Azure / azure-functions-docker

This repo contains the base Docker images for working with azure functions
MIT License
269 stars 118 forks source link

Azure Function within Docker container - No job functions found #642

Open CAJTechnologyLimited opened 2 years ago

CAJTechnologyLimited commented 2 years ago

Hoping someone can help me! Appreciate this is close to the following issue previous raised: https://github.com/Azure/azure-functions-docker/issues/128 Unfortunately the above link didnt solve my problem.

I added docker to an existing azure function that I had previously built. This was done via the docker support functionality within visual studio. The created dockerfile runs perfectly fine within visual studio. Having looked at what commands VS runs these are significantly different to what I am expecting to run. One to build the docker image and two to spin up the container.

Dockerfile:

FROM mcr.microsoft.com/azure-functions/dotnet:3.0 AS base
WORKDIR /home/site/wwwroot
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:3.1 AS build
WORKDIR /src
COPY ["NuGet.config", "."]
COPY ["XXXX/XXXX.csproj", "XXXX/"]
RUN dotnet restore "XXXX/XXXX.csproj"
COPY . .
WORKDIR "/src/XXXX"
RUN dotnet build "XXXX.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "XXXX.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /home/site/wwwroot
COPY --from=publish /app/publish .
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
    AzureFunctionsJobHost__Logging__Console__IsEnabled=true

Therefore I am looking to one run the following Build command:

docker build -f Dockerfile . -t newtest

This on face value looks like it has succeeded. Here is the output of the above:

[+] Building 68.8s (19/19) FINISHED
 => [internal] load build definition from Dockerfile                                                                                                   0.0s
 => => transferring dockerfile: 906B                                                                                                                   0.0s
 => [internal] load .dockerignore                                                                                                                      0.0s
 => => transferring context: 2B                                                                                                                        0.0s
 => [internal] load metadata for mcr.microsoft.com/dotnet/sdk:3.1                                                                                      0.2s
 => [internal] load metadata for mcr.microsoft.com/azure-functions/dotnet:3.0                                                                          0.2s
 => [base 1/2] FROM mcr.microsoft.com/azure-functions/dotnet:3.0@sha256:3ce9888785b6ad4a4a219e2c5beaf32add1ec6a2c8514f88a596bbcaa58f1312               0.0s
 => [internal] load build context                                                                                                                      0.1s
 => => transferring context: 166.44kB                                                                                                                  0.0s
 => [build 1/8] FROM mcr.microsoft.com/dotnet/sdk:3.1@sha256:2db1d2c81c51ce4a5b0ed41d439839ee3a1c90b415c3e03ca987478cef7a1371                         22.9s
 => => resolve mcr.microsoft.com/dotnet/sdk:3.1@sha256:2db1d2c81c51ce4a5b0ed41d439839ee3a1c90b415c3e03ca987478cef7a1371                                0.0s
 => => sha256:61441cac53211e0132831cf4977286fce5b9d8c50d1df80763b148211c4dda2e 6.43kB / 6.43kB                                                         0.0s
 => => sha256:ba3959e1529771ae9fb5393fc19cd8b236814c45043e81fb64f1c7a0ca8066a8 13.70MB / 13.70MB                                                       2.5s
 => => sha256:449df86cd0f646dbe9e8eb3b22b5ca3f19827797edc58bc8c8d34493194676cf 13.23MB / 13.23MB                                                       2.5s
 => => sha256:c6d947c32e6215ba4f98050e9f7b7925fb9c72c244fca5b2e40eb4d5ac51aeaa 1.80kB / 1.80kB                                                         0.0s
 => => sha256:2641eac4b740ed8558510f7dfd06fa8c52c0c0a64934d5cc0faeb00e420538f6 124.17MB / 124.17MB                                                     8.3s
 => => sha256:2db1d2c81c51ce4a5b0ed41d439839ee3a1c90b415c3e03ca987478cef7a1371 2.17kB / 2.17kB                                                         0.0s
 => => extracting sha256:ba3959e1529771ae9fb5393fc19cd8b236814c45043e81fb64f1c7a0ca8066a8                                                              0.7s
 => => extracting sha256:2641eac4b740ed8558510f7dfd06fa8c52c0c0a64934d5cc0faeb00e420538f6                                                             12.6s
 => => extracting sha256:449df86cd0f646dbe9e8eb3b22b5ca3f19827797edc58bc8c8d34493194676cf                                                              0.9s
 => [build 2/8] WORKDIR /src                                                                                                                           0.8s
 => [build 3/8] COPY [NuGet.config, .]                                                                                                                 0.1s
 => [build 4/8] COPY [XXXX.csproj, XXXX/]                                          0.1s
 => [build 5/8] RUN dotnet restore "XXXX/XXXX.csproj"                             27.8s
 => [build 6/8] COPY . .                                                                                                                               0.4s
 => [build 7/8] WORKDIR /src/XXXX                                                                                    0.0s
 => [build 8/8] RUN dotnet build "XXXX.csproj" -c Release -o /app/build                                              8.9s
 => [publish 1/1] RUN dotnet publish "XXXX.csproj" -c Release -o /app/publish                                        6.9s
 => CACHED [base 2/2] WORKDIR /home/site/wwwroot                                                                                                       0.0s
 => CACHED [final 1/2] WORKDIR /home/site/wwwroot                                                                                                      0.0s
 => [final 2/2] COPY --from=publish /app/publish .                                                                                                     0.1s
 => exporting to image                                                                                                                                 0.3s
 => => exporting layers                                                                                                                                0.2s
 => => writing image sha256:a30d6d99db2ced202d31789daabd319174659b2337b42a2963b74ca3b9082757                                                           0.0s
 => => naming to docker.io/library/newtest

After the build succeeds the next command I am running is:

Command

docker run -it --rm -p "5500:80" newtest

Output

warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Overriding address(es) 'http://+:80'. Binding to endpoints defined in UseKestrel() instead.
info: Host.Triggers.Warmup[0]
      Initializing Warmup Extension.
info: Host.Startup[503]
      Initializing Host. OperationId: '2984e8f7-610d-4934-93d9-4c506cf9f56d'.
info: Host.Startup[504]
      Host initialization: ConsecutiveErrors=0, StartupCount=1, OperationId=2984e8f7-610d-4934-93d9-4c506cf9f56d
info: Microsoft.Azure.WebJobs.Hosting.OptionsLoggingService[0]
      LoggerFilterOptions
      {
        "MinLevel": "None",
        "Rules": [
          {
            "ProviderName": null,
            "CategoryName": null,
            "LogLevel": null,
            "Filter": "<AddFilter>b__0"
          },
          {
            "ProviderName": "Microsoft.Azure.WebJobs.Script.WebHost.Diagnostics.SystemLoggerProvider",
            "CategoryName": null,
            "LogLevel": "None",
            "Filter": null
          },
          {
            "ProviderName": "Microsoft.Azure.WebJobs.Script.WebHost.Diagnostics.SystemLoggerProvider",
            "CategoryName": null,
            "LogLevel": null,
            "Filter": "<AddFilter>b__0"
          }
        ]
      }
info: Microsoft.Azure.WebJobs.Hosting.OptionsLoggingService[0]
      ConcurrencyOptions
      {
        "DynamicConcurrencyEnabled": false,
        "MaximumFunctionConcurrency": 500,
        "CPUThreshold": 0.8,
        "SnapshotPersistenceEnabled": true
      }
info: Microsoft.Azure.WebJobs.Hosting.OptionsLoggingService[0]
      FunctionResultAggregatorOptions
      {
        "BatchSize": 1000,
        "FlushTimeout": "00:00:30",
        "IsEnabled": true
      }
info: Microsoft.Azure.WebJobs.Hosting.OptionsLoggingService[0]
      SingletonOptions
      {
        "LockPeriod": "00:00:15",
        "ListenerLockPeriod": "00:01:00",
        "LockAcquisitionTimeout": "10675199.02:48:05.4775807",
        "LockAcquisitionPollingInterval": "00:00:05",
        "ListenerLockRecoveryPollingInterval": "00:01:00"
      }
info: Microsoft.Azure.WebJobs.Hosting.JobHostService[0]
      Starting JobHost
info: Host.Startup[401]
      Starting Host (HostId=02519606f196-2137340777, InstanceId=f51daae3-b514-4d9a-8516-fb8c1e9c30da, Version=3.4.2.0, ProcessId=1, AppDomainId=1, InDebugMode=False, InDiagnosticMode=False, FunctionsExtensionVersion=(null))
info: Host.Startup[314]
      Loading functions metadata
info: Host.Startup[315]
      0 functions loaded
info: Host.Startup[0]
      Generating 0 job function(s)
warn: Host.Startup[0]
      No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
info: Microsoft.Azure.WebJobs.Hosting.OptionsLoggingService[0]
      HttpOptions
      {
        "DynamicThrottlesEnabled": false,
        "EnableChunkedRequestBinding": false,
        "MaxConcurrentRequests": -1,
        "MaxOutstandingRequests": -1,
        "RoutePrefix": "api"
      }
info: Microsoft.Azure.WebJobs.Script.WebHost.WebScriptHostHttpRoutesManager[0]
      Initializing function HTTP routes
      No HTTP routes mapped

info: Host.Startup[412]
      Host initialized (39ms)
info: Host.Startup[413]
      Host started (49ms)
info: Host.Startup[0]
      Job host started
Hosting environment: Production
Content root path: /azure-functions-host
Now listening on: http://[::]:80
Application started. Press Ctrl+C to shut down.
info: Host.General[337]
      Host lock lease acquired by instance ID '00000000000000000000000086D15900'.
^CApplication is shutting down...
info: Microsoft.Azure.WebJobs.Hosting.JobHostService[0]
      Stopping JobHost
info: Host.Startup[0]

As you can see the output above shows: info: Host.Startup[315] 0 functions loaded info: Host.Startup[0] Generating 0 job function(s) warn: Host.Startup[0] No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).

I cant for the life of me figure out why no job functions are being found, considering running it via VS produces in successful build & run. I even tested via consuming the expected endpoints successfully.

Apologies if I havent produced every log available, im a newbie when it comes to docker and containerisation, hence trying to get it working with an existing application

sergevm commented 2 years ago

Experiencing the same issue here ... Deploying a container to a private container registry on Azure. The app service hosting the functions is connected to the deployed container via the linuxFxVersion setting on the app service. The docker logs via Kudu show that the container is pulled successfully. No functions shown in the portal after this, and a call to the HttpTrigger enabled function returns a 404.

Clearly this implies that the runtime is not picking up the functions. Does this have to do anything with the version of the functions runtime? I don't think so, because when I pull the deployed to my local machine, and call the HttpTrigger endpoint, then it runs just fine.

nerddtvg commented 2 years ago

I found the culprit to be the persistent shared storage. If you are using WEBSITES_ENABLE_APP_SERVICE_STORAGE set to true, this will mount over the /home directory of the container prior to execution. This effectively hides the app and files from the container runtime.

https://learn.microsoft.com/en-us/azure/app-service/configure-custom-container?pivots=container-linux#use-persistent-shared-storage

Additionally, any contents inside the /home directory of the container are overwritten by any existing files already present on the persistent storage when the container starts.

There appears to be no easy way to change this in Azure. The startup code specifically finds if the container is running in Azure (identifies if there is the environment variable WEBSITE_INSTANCE_ID), and then sets the path to /home/site/wwwroot assuming that the environment variable HOME is unset or set to /home. Despite the property being called IsAppServiceEnvironment, it's referring to Azure App Services as a whole and not just App Service Environment hosted applications.

https://github.com/Azure/azure-functions-host/blob/2c95cfe1354c3743f387cadcd03f4144dffe184d/src/WebJobs.Script/Description/DotNet/FunctionAssemblyLoadContext.cs#L590-L600

The environment variable AzureWebJobsScriptRoot is ignored in Azure App Services.

More information:

https://stackoverflow.com/questions/66179732/containerizing-an-azure-function-changing-azurewebjobsscriptroot-variable-from

prabhurajshell commented 1 year ago

@nerddtvg @sergevm @CAJTechnologyLimited I'm facing the same issue with custom docker image on node platform. Did any of you find a fix or workaround for this?

nerddtvg commented 1 year ago

I'm facing the same issue with custom docker image on node platform. Did any of you find a fix or workaround for this?

@prabhurajshell The only solution I have is from my comment above to not use WEBSITES_ENABLE_APP_SERVICE_STORAGE.

prabhurajshell commented 1 year ago

@nerddtvg Thank you, setting WEBSITES_ENABLE_APP_SERVICE_STORAGE as false worked for me. Are there any downsides to performance if we are not using the persistent storage?

svickers commented 1 year ago

We were having a problem with the exact same symptoms but the fix turned out to be different than the WEBSITES_ENABLE_APP_SERVICE_STORAGE. We were upgrading an existing functions 3 to run on the 4 framework and everything was working fine running the container locally but refused to recognize any functions in azure. Turns out the issue was the path we were using in the docker build command.

Previously the devops pipeline would run the equivalent of this command, within the project directory: docker build -f Dockerfile . and the build step within the dockerfile looked like:

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["myproject.csproj", "myproject/"]
RUN dotnet restore "myproject/myproject.csproj"
COPY . .
WORKDIR "/src/myproject"
RUN dotnet build "myproject.csproj" -c Release -o /app/build

The trick turns out to be running the build from one directory up at the solution level... Command updated to: docker build -f myproject/Dockerfile . and build step changed to:

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["myproject/myproject.csproj", "myproject/"]
RUN dotnet restore "myproject/myproject.csproj"
COPY . .
WORKDIR "/src/myproject"
RUN dotnet build "myproject.csproj" -c Release -o /app/build

Not sure why it was different between v3 and v4, or why it worked locally, but there it is.

Christopher-Flanagan commented 1 year ago

Our team also ran into this issue. We resolved it by setting WEBSITES_ENABLE_APP_SERVICE_STORAGE to false.

This triggered a different issue related to the permissions for the following directory /home/LogFiles/Application/Functions/Host. If you run into this verify that this directory exists inside your container and that the access level for /home and subfolders is open to non-root users

axl8652 commented 1 year ago

Upgrading the function runtime worked for me, Dockerfile: FROM mcr.microsoft.com/azure-functions/node:4-nightly-node18 ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ AzureFunctionsJobHostLoggingConsole__IsEnabled=true COPY . /home/site/wwwroot RUN cd /home/site/wwwroot && \ npm install && \ npm run build