Building Docker Images for .NET Core Applications
In this tutorial, We focus on how to use .NET Core on Docker. First, we explore the different Docker images offered and maintained by Microsoft, and use cases. We then learn how to build and dockerize an ASP.NET Core app.
During the course of this tutorial, you learn:
- Learn about Microsoft .NET Core Docker images
- Get an ASP.NET Core sample app to Dockerize
- Run the ASP.NET sample app locally
- Build and run the sample with Docker for Linux containers
- Build and run the sample with Docker for Windows containers
Docker Image Optimizations
When building Docker images for developers, we focused on three main scenarios:
- Images used to develop .NET Core apps
- Images used to build .NET Core apps
- Images used to run .NET Core apps
Why three images? When developing, building, and running containerized applications, we have different priorities.
Development: The priority focuses on quickly iterate changes, and the ability to debug the changes. The size of the image isn't as important, rather can you make changes to your code and see them quickly?
Build: This image contains everything needed to compile your app, which includes the compiler and any other dependencies to optimize the binaries. You use the build image to create the assets you place into a production image. The build image would be used for continuous integration, or in a build environment. This approach allows a build agent to compile and build the application (with all the required dependencies) in a build image instance. Your build agent only needs to know how to run this Docker image.
Production: How fast you can deploy and start your image? This image is small so network performance from your Docker Registry to your Docker hosts is optimized. The contents are ready to run enabling the fastest time from Docker run to processing results. Dynamic code compilation isn't needed in the Docker model. The content you place in this image would be limited to the binaries and content needed to run the application.
For example, the
dotnet publishoutput contains:
- the compiled binaries
- .js and .css files
The reason to include the
dotnet publish command output in your production image is to keep its size to a minimum.
Some .NET Core images share layers between different tags so downloading the latest tag is a relatively lightweight process. If you already have an older version on your machine, this architecture decreases the needed disk space.
When multiple applications use common images on the same machine, memory is shared between the common images. The images must be the same to be shared.
Docker image variations
To achieve the goals above, we provide image variants under
microsoft/dotnet:2.1-sdk) This image contains the .NET Core SDK, which includes the .NET Core and Command Line Tools (CLI). This image maps to the development scenario. You use this image for local development, debugging, and unit testing. This image can also be used for your build scenarios. Using
microsoft/dotnet:sdkalways gives you the latest version.
If you are unsure about your needs, you want to use the
microsoft/dotnet:<version>-sdk image. As the "de facto" image, it's designed to be used as a throw away container (mount your source code and start the container to start your app), and as the base image to build other images from.
microsoft/dotnet:<version>-runtime: This image contains the .NET Core (runtime and libraries) and is optimized for running .NET Core apps in production.
In addition to the optimized scenarios of development, build and production, we provide additional images:
microsoft/dotnet:<version>-runtime-deps: The runtime-deps image contains the operating system with all of the native dependencies needed by .NET Core. This image is for self-contained applications.
Latest versions of each variant:
microsoft/dotnet:latest(alias for the SDK image)
Samples to explore
This ASP.NET Core Docker sample demonstrates a best practice pattern for building Docker images for ASP.NET Core apps for production. The sample works with both Linux and Windows containers.
This .NET Core Docker sample demonstrates a best practice pattern for building Docker images for .NET Core apps for production.
Your first ASP.NET Core Docker app
For this tutorial, lets use an ASP.NET Core Docker sample application for the app we want to dockerize. This ASP.NET Core Docker sample application demonstrates a best practice pattern for building Docker images for ASP.NET Core apps for production. The sample works with both Linux and Windows containers.
The sample Dockerfile creates an ASP.NET Core application Docker image based off of the ASP.NET Core Runtime Docker base image.
It uses the Docker multi-stage build feature to:
- build the sample in a container based on the larger ASP.NET Core Build Docker base image
- copies the final build result into a Docker image based on the smaller ASP.NET Core Docker Runtime base image
The build image contains required tools to build applications while the runtime image does not.
To build and run, install the following items:
.NET Core 2.1 SDK
Install .NET Core SDK 2.1.
Install your favorite code editor, if you haven't already.
Need to install a code editor? Try Visual Studio!
Installing Docker Client
Install Docker 18.03 or later of the Docker client.
The Docker client can be installed in:
Installing Git for sample repository
- Install git if you wish to clone the repository.
Getting the sample application
The easiest way to get the sample is by cloning the .NET Core Docker repository with git, using the following instructions:
git clone https://github.com/dotnet/dotnet-docker
You can also download the repository (it is small) as a zip from the .NET Core Docker repository.
Run the ASP.NET app locally
For a reference point, before we containerize the application, first run the application locally.
You can build and run the application locally with the .NET Core 2.1 SDK using the following commands (The instructions assume the root of the repository):
cd dotnet-docker cd samples cd aspnetapp // solution scope where the dockerfile is located cd aspnetapp // project scope dotnet run
After the application starts, visit http://localhost:5000 in your web browser.
Build and run the sample with Docker for Linux containers
You can build and run the sample in Docker using Linux containers using the following commands (The instructions assume the root of the repository):
cd dotnet-docker cd samples cd aspnetapp // solution scope where the dockerfile is located docker build -t aspnetapp . docker run -it --rm -p 5000:80 --name aspnetcore_sample aspnetapp
docker run '-p' argument maps port 5000 on your local machine to port 80 in the container (the port mapping form is
host:container). For more information, see the docker run reference on command-line parameters.
After the application starts, visit http://localhost:5000 in your web browser.
Build and run the sample with Docker for Windows containers
You can build and run the sample in Docker using Windows containers using the following commands (The instructions assume the root of the repository):
cd dotnet-docker cd samples cd aspnetapp // solution scope where the dockerfile is located docker build -t aspnetapp . docker run -it --rm --name aspnetcore_sample aspnetapp
You must navigate to the container IP address (as opposed to http://localhost) in your browser directly when using Windows containers. You can get the IP address of your container with the following steps:
- Open up another command prompt.
docker psto see your running containers. The "aspnetcore_sample" container should be there.
docker exec aspnetcore_sample ipconfig.
- Copy the container IP address and paste into your browser (for example, 172.29.245.43).
Docker exec supports identifying containers with name or hash. The name (aspnetcore_sample) is used in our example.
See the following example of how to get the IP address of a running Windows container.
docker exec aspnetcore_sample ipconfig Windows IP Configuration Ethernet adapter Ethernet: Connection-specific DNS Suffix . : contoso.com Link-local IPv6 Address . . . . . : fe80::1967:6598:124:cfa3%4 IPv4 Address. . . . . . . . . . . : 172.29.245.43 Subnet Mask . . . . . . . . . . . : 255.255.240.0 Default Gateway . . . . . . . . . : 172.29.240.1
Docker exec runs a new command in a running container. For more information, see the docker exec reference on command-line parameters.
You can produce an application that is ready to deploy to production locally using the dotnet publish command.
dotnet publish -c Release -o published
The -c Release argument builds the application in release mode (the default is debug mode). For more information, see the dotnet run reference on command-line parameters.
You can run the application on Windows using the following command.
You can run the application on Linux or macOS using the following command.
Docker Images used in this sample
The following Docker images are used in this sample's dockerfile.
Congratulations! you have just:
- Learned about Microsoft .NET Core Docker images
- Got an ASP.NET Core sample app to Dockerize
- Ran the ASP.NET sample app locally
- Built and ran the sample with Docker for Linux containers
- Built and ran the sample with Docker for Windows containers
Here are some next steps you can take:
- Working with Visual Studio Docker Tools
- Deploying Docker Images from the Azure Container Registry to Azure Container Instances
- Debugging with Visual Studio Code
- Getting hands on with Visual Studio for Mac, containers, and serverless code in the cloud
- Getting Started with Docker and Visual Studio for Mac Lab
If you do not have an Azure subscription, sign up today for a free 30-day account and get $200 in Azure Credits to try out any combination of Azure services.