Each week I'll look at one Dockerfile in detail, showing you what it does and how it works. This is #5 in the series.
Last week I covered a simple .NET Core Hello World app, where the Dockerfile had the steps to compile and package the app from source. That approach used Microsoft's .NET Core image with the SDK installed, so the final application image contained the SDK and the app source code - which isn't needed to run the app.
This week I'll show a different approach - compiling the app outside of Docker and then packaging the published output in the Dockerfile. The final application image uses Microsoft's .NET Core image with just the runtime installed, so the SDK and source code aren't part of the package.
The Dockerfile for this approach is in Dockerfile.slim, and it's very simple:
FROM microsoft/dotnet:1.1-runtime-nanoserver WORKDIR /dotnetapp COPY ./src/bin/Debug/netcoreapp1.1/publish . CMD ["dotnet", "HelloWorld.NetCore.dll"]
FROMuses a version of the microsoft/dotnet image which has the .NET Core 1.1 runtime installed, but not the SDK. It's an image based on Nano Server so it runs as a Docker Windows container
WORKDIRcreates a directory at
C:\dotnetappand sets that as the current working directory for the image
COPYcopies the published application from the local machine into the Docker image
CMDspecifies the command to run to start the app.
You can't build your own Docker image just by running
docker image build with this version, you need to publish the application first. There's a build script which does all the steps:
dotnet restore src dotnet publish src docker image build --file Dockerfile.slim --tag dockeronwindows/ch02-dotnet-helloworld:slim .
- the Dockerfile isn't called
Dockerfile, so the build command uses the
--fileargument to specify the source file name
dockeronwindows/ch02-dotnet-helloworld:slim image packages the published app binaries on top of an image that has the .NET Core runtime but not the SDK. That makes for a much smaller image - 1.15GB compared to 1.68GB for last week's version.
The drawback is that you need to have the right version of the .NET SDK installed on your dev machine to publish the app. You need the SDK on your build agent for the CI process too, and you also need to keep the toolchain in sync between the build server(s) and all the dev environments.
Well, first you need to install the .NET Core SDK. Then you run
build.ps1 to publish the app and then build the Docker image:
Then you can run the container. I've pushed a public image on Docker Hub, in the dockeronwindows organization, so you don't need to build it yourself, just run:
docker container run dockeronwindows/ch02-dotnet-helloworld:slim
Packaging the app in an image with the .NET runtime but not the SDK makes for a smaller image, which is faster to push and pull. More importantly, it has a smaller surface area for attackers, and less software to be patched.
Next week is the final take on the .NET Core Hello World app running in a Docker Windows container. Dockerfile.multistage uses Docker multi-stage builds to combine the best of the two other approaches. The app is compiled and published using Docker, so you don't need the .NET Core SDK installed to build the app, but the final image uses the minimal runtime base image.