azuredockerazure-functionshttp-status-code-404httpresponse

Azure function HTTP Request 404 when published to Azure through Docker and Visual Studio


I'm attempting to learn some more about Azure Functions 2.0 and Docker containers to publish to my Azure instance. I followed to tutorial below with the only difference being that I published with docker to a container registry in azure using visual studio 2019.

https://learn.microsoft.com/en-us/azure/azure-functions/functions-create-your-first-function-visual-studio

This all worked correctly and I was able to start my container and visit the site. However, in the example you can visit /api/function1 and get a response. This works on my localhost but on the live site it returns a 404. It seems that /api/function1 is not reachable after being published.

The app itself returns this when visiting the IP itself so I know it is working. Do I need to do something else in Azure to expose my APIs?

Azure screenshot working default page

My container log only shows this.

Hosting environment: Production
Content root path: C:\
Now listening on: http://[::]:80
Application started. Press Ctrl+C to shut down.

I grabbed my dockerfile from here

https://github.com/Azure/azure-functions-docker/blob/master/host/2.0/nanoserver-1809/Dockerfile

# escape=`

# Installer image
FROM mcr.microsoft.com/windows/servercore:1809 AS installer-env

SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

# Retrieve .NET Core SDK
ENV DOTNET_SDK_VERSION 2.2.402

RUN Invoke-WebRequest -OutFile dotnet.zip https://dotnetcli.blob.core.windows.net/dotnet/Sdk/$Env:DOTNET_SDK_VERSION/dotnet-sdk-$Env:DOTNET_SDK_VERSION-win-x64.zip; `
    $dotnet_sha512 = '0fa3bf476b560c8fc70749df37a41580f5b97334b7a1f19d66e32096d055043f4d7ad2828f994306e0a24c62a3030358bcc4579d2d8d439d90f36fecfb2666f6'; `
    if ((Get-FileHash dotnet.zip -Algorithm sha512).Hash -ne $dotnet_sha512) { `
        Write-Host 'CHECKSUM VERIFICATION FAILED!'; `
        exit 1; `
    }; `
    `
    Expand-Archive dotnet.zip -DestinationPath dotnet; `
    Remove-Item -Force dotnet.zip

ENV ASPNETCORE_URLS=http://+:80 `
    DOTNET_RUNNING_IN_CONTAINER=true `
    DOTNET_USE_POLLING_FILE_WATCHER=true `
    NUGET_XMLDOC_MODE=skip `
    PublishWithAspNetCoreTargetManifest=false `
    HOST_COMMIT=69f124faed40d20d9d8e5b8d51f305d249b21512 `
    BUILD_NUMBER=12858

RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; `
    Invoke-WebRequest -OutFile host.zip https://github.com/Azure/azure-functions-host/archive/$Env:HOST_COMMIT.zip; `
    Expand-Archive host.zip .; `
    cd azure-functions-host-$Env:HOST_COMMIT; `
    /dotnet/dotnet publish /p:BuildNumber=$Env:BUILD_NUMBER /p:CommitHash=$Env:HOST_COMMIT src\WebJobs.Script.WebHost\WebJobs.Script.WebHost.csproj --output C:\runtime


# Runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2.7-nanoserver-1809

COPY --from=installer-env ["C:\\runtime", "C:\\runtime"]

ENV AzureWebJobsScriptRoot=C:\approot `
    WEBSITE_HOSTNAME=localhost:80

CMD ["dotnet", "C:\\runtime\\Microsoft.Azure.WebJobs.Script.WebHost.dll"]

Here's my function1 code for my azure function

public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string productid = req.Query["productid"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            productid = productid ?? data?.product;

            Product newProduct = new Product()
            {
                ProductNumber = 0,
                ProductName = "Unknown",
                ProductCost = 0
            };
            if (Convert.ToInt32(productid) ==1)
            {
                newProduct = new Product()
                {
                    ProductCost = 100,
                    ProductName = "Lime Tree",
                    ProductNumber = 1
                };
            }
            else if(Convert.ToInt32(productid) == 2) 
            {
                newProduct = new Product()
                {
                    ProductCost = 500,
                    ProductName = "Lemon Tree",
                    ProductNumber = 2
                };
            }
            return productid != null
                ? (ActionResult)new JsonResult(newProduct)
                : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
        }

Here's a photo of my container running with my image.

Container image

I'm new to this so any advice would be helpful for sure!

Thanks!


Solution

  • @silent's answer was correct - Linux containers are the way to go for Azure Functions. My environment wasn't set up correctly for Linux containers but once I got a correct environment this worked out of the box.

    Here's my latest DockerFile for another project that uses Linux Containers

    See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

    FROM mcr.microsoft.com/azure-functions/dotnet:2.0 AS base
    WORKDIR /app
    EXPOSE 80
    
    FROM mcr.microsoft.com/dotnet/core/sdk:3.0 AS build
    WORKDIR /src
    COPY ["FunctionTestAppLinux/FunctionTestAppLinux.csproj", "FunctionTestAppLinux/"]
    RUN dotnet restore "FunctionTestAppLinux/FunctionTestAppLinux.csproj"
    COPY . .
    WORKDIR "/src/FunctionTestAppLinux"
    RUN dotnet build "FunctionTestAppLinux.csproj" -c Release -o /app/build
    
    FROM build AS publish
    RUN dotnet publish "FunctionTestAppLinux.csproj" -c Release -o /app/publish
    
    FROM base AS final
    WORKDIR /app
    COPY --from=publish /app/publish .
    ENV AzureWebJobsScriptRoot=/app