Azure App Service on Linux has several prefabricated Docker images that support applications written in languages such as .NET core, PHP, and Node.js. App Service also supports using your own Docker image to spin up a container for your application. A useful configuration feature of App Service on Linux is the Startup File configuration that you can set as part of configuring the runtime stack. The value that you specify for the configuration overrides the CMD
instruction of the Dockerfile that creates the runtime of the application. If you are not aware of this configuration option, we will soon deploy an application that uses this configuration option soon, so keep reading.
The Docker documentation states that if your Dockerfile has both CMD
and ENTRYPOINT
instructions, then CMD
arguments are appended to the end of the command generated by the ENTRYPOINT
instruction. A necessary condition for this feature to work is that you must use the exec
form of the ENTRYPOINT
instruction in your Dockerfile. In simple terms, assume that your Dockerfile has the following instructions.
ENTRYPOINT["sed","-i","s/Windows/Linux/g"]
CMD["file-to-update"]
When the Docker daemon executes the instructions of the previous code listing, it will generate and run the command sed -i 's/Windows/Linux/g' file-to-update
by combining the arguments of the ENTRYPOINT
and CMD
instructions in the container. In general, we specify the command that will launch the application process as arguments of the ENTRYPOINT
instruction.
If you combine this feature of Docker with the ability to override CMD
instruction in App Service for Linux, you can enable the scenario of passing command-line arguments to a containerized ASP.NET Core web application. Also, you can change the runtime arguments of a live app and affect the web application immediately. Although I will only discuss this feature in the context of Azure App Service, you can use the same approach with Kubernetes and Docker Compose.
To demonstrate the concept, I created a simple ASP.NET Core MVC web application that paints the homepage with the color that it receives from a command-line argument.
Source Code
You can download the source code of the sample application code from GitHub.
The structure of the project is straightforward. The solution Colors contains a single project named ColoredWeb which is an ASP.NET Core MVC web application. The application contains a Dockerfile which mostly contains standard instructions except for the ENTRYPOINT
and CMD
instructions that supply command line parameters to the application.
Command Line Arguments to The Application
To understand how we can instruct Docker to pass arguments to the application, let’s explore the Dockerfile of the ColoredWeb project.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["ColoredWeb/ColoredWeb.csproj", "ColoredWeb/"]
RUN dotnet restore "ColoredWeb/ColoredWeb.csproj"
COPY . .
WORKDIR "/src/ColoredWeb"
RUN dotnet build "ColoredWeb.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "ColoredWeb.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ColoredWeb.dll"]
CMD ["Color=Blue"]
I want to draw your attention to the last two instructions of the Dockerfile. With the combination of the ENTRYPOINT
and CMD
instructions, Docker will try to launch the application with the following command.
dotnet ColoredWeb.dll Color=Blue
In the previous command, note that we assigned the value Blue to the key Color, which is a command-line argument passed to the ColoredWeb executable. The ConfigureAppConfiguration
extension method in the class Program
adds the command line to the application configurations. You can pass more than one argument to the applications as well.
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) => { config.AddCommandLine(args); })
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
}
If you try to debug the application in local Docker container and navigate to the home page, you will see that it is painted in color red rather than blue.
The application picks the default color because Visual Studio executes a command like the following to launch the container in debug mode.
docker run -dt -v "C:\Users\rahul\vsdbg\vs2017u5:/remote_debugger:rw" `
-v "D:\Projects\PaintMe\ColoredWeb:/app" `
-v "D:\Projects\PaintMe:/src"`
-v "C:\Users\rahul\AppData\Roaming\Microsoft\UserSecrets:/root/.microsoft/usersecrets:ro"`
-v "C:\Users\rahul\AppData\Roaming\ASP.NET\Https:/root/.aspnet/https:ro"`
-v "C:\Users\rahul\.nuget\packages\:/root/.nuget/fallbackpackages2"`
-v "C:\Program Files\dotnet\sdk\NuGetFallbackFolder:/root/.nuget/fallbackpackages"`
-e "DOTNET_USE_POLLING_FILE_WATCHER=1" -e "ASPNETCORE_ENVIRONMENT=Development"`
-e "ASPNETCORE_URLS=https://+:443;http://+:80"`
-e "NUGET_PACKAGES=/root/.nuget/fallbackpackages2" -e "NUGET_FALLBACK_PACKAGES=/root/.nuget/fallbackpackages;/root/.nuget/fallbackpackages2"`
-P --name ColoredWeb --entrypoint tail coloredweb:dev -f /dev/null
In the previous command, you can see that Visual Studio overrides both the ENTRYPOINT
and CMD
instructions with the tail -f /dev/null
command. Hence, Docker does not execute the ENTRYPOINT
and CMD
instructions of the Dockerfile. However, you can build the container image yourself (docker build
) and execute it (docker run
) to make the application execute expectedly.
Let’s now switch to Azure App Service. I have published the image of the ColoredWeb application to my DockerHub repository here. Let’s now use this image for creating an Azure App Service.
Create Azure App Service
Although you may (and should) use the Azure CLI to create and configure your application, I will walk you through the steps to set up the application on the Azure portal as it is more visually intuitive than the CLI.
On the Azure portal, create a new Azure App Service. In the first step of the wizard, select Docker Container as the mode of publishing the application and set the language toggle to Linux. Select a name and an appropriate App Service Plan that suits your requirements.
In the next step of the wizard, select Docker Hub as the source of the application image. Since I have hosted the image of the application in public Docker repository, select the value Public in the Access Type dropdown. Next, in the Image and tag field, enter the name and tag of the image, rahulrai/coloredweb:latest. Finally, in the Startup Command field, enter the value Color=Yellow, which will override the CMD
instruction specified in the Dockerfile of the application.
Click the Review + Create button that will take you to the last step of the wizard. Click on the Create button to create the application. After the application is ready, navigate to the URL of the application, which will render as follows.
You can change the command line arguments of the application on the fly which will trigger a rolling update of the application. To change the command line arguments, navigate to the Container Settings blade of the application. In the following image, I demonstrate how to change the command line argument from Yellow to Red.
I hope you found this exercise interesting and discovered another way to configure your web applications on Azure. You can reach out to me on Twitter @rahulrai_in to share your feedback.