Dockerfile I use for ASP.NET Core web applications. This is suitable for both F# and C# apps. Below I detail some design decisions and Docker best practices.
FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build WORKDIR /app # Copy source code and compile COPY ./ ./ RUN dotnet restore RUN dotnet publish --configuration Release -o bin # Build runtime image FROM mcr.microsoft.com/dotnet/aspnet:5.0-alpine AS runtime LABEL com.org.author=foo LABEL com.org.component=bar-api WORKDIR /app COPY --from=build /app/bin . HEALTHCHECK --interval=5s --timeout=10s --retries=1 CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1 ENTRYPOINT ["dotnet", "bar-api.App.dll"]
Build the testing image
docker build -t bar-api .
docker run -it --rm -p 5000:80 --name local-bar-api-test bar-api
Docker Base Images
dotnet/aspnet:5.0-alpine for fast, secure, and reproducible images. Some key considerations:
dotnet/images are published by Microsoft. We trust they know what they’re doing.
- The application is compiled within the
dotnet/sdkimage. The resulting binaries are copied to the
dotnet/aspnetimage which has the minimal set of libraries required to serve the application.
- Alpine Linux gives us security and a small resulting Docker image. Docker image size is important for storage costs as well as speed of execution of our deployment pipelines.
- If your application is being developed within an organisation with a private Docker Registry then use it. ie replace
- New versions of
dotnet/aspnetare published whenever the underlying Alpine or .NET 5 framework version changes. I find this is a good balance of security and reproducibility but if you need absolute reproducibility of the docker images then consider pinning to a specific version.
HEALTHCHECK provides a basic indicator to the container orchestrator about the status of the container. Container orchestrators provide different capabilities; Kubernetes offers Liveness, Readiness, and Startup checks for you to configure independent of the
Dockerfile. This allows you to differentiate between failure modes of:
- The container failed to start due to some static reason such as a typo in the configuration. Restarting the container won’t fix the problem.
- The container has a memory leak and has now stopped serving requests. If the orchestrator restarts the container the problem will be fixed.
- A critical downstream dependency of the container is down. Don’t route it traffic until the dependency comes back up.
Kubernetes is complex and the orchestrator you use may not have those features. Whether you use Kubernetes or not, keep it simple and configure the
HEALTHCHECK to be able to check that the ASP.NET Core web server is running without error. Add a
/ping endpoint to your REST API and hard code it to return an HTTP 200. When the container starts Docker (or the orchestrator) runs the
HEALTHCHECK and sets the container status to Healthy once it confirms the endpoint is accessible.
HEALTHCHECK --interval=5s --timeout=10s --retries=1 CMD wget --no-verbose --tries=1 --spider http://localhost/ping || exit 1
wgetis preferred to
curlas it comes packaged with Alpine Linux.
- Although we expect a
GET /pingto return nearly instantly be aware of the startup time of the ASP.NET Core server. Factor this in to the