Multi-stage Docker builds with .NET

A colleague of mine recently pointed out an article by Travis Reeder regarding the new multi-stage docker builds for Go images:

I didn’t even know about this upcoming feature so I decided to try it out on using a simple .NET app on CoreCLR. The steps outlined in this article runs a trivial ‘hello world’ .NET app from source by first building it with the coreCLR SDK image and then with multi-stage builds.

Multi-stage build was very recently added into docker 17.06.0-dev so the steps below outline how to set that version up and then run the images.

The following steps assume you’ve installed docker 17.06.0-dev daemon and aliased docker cli to that same version (yeah, i know, running as root):

Now for the fun part.

Given the simple hello world .NET app, lets build it inside a container:

console.csproj

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
</Project>

Program.cs

using System;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}

Create these files in a directory and setup a Dockerfile to build the app from the SDK:

Dockerfile

FROM microsoft/dotnet:1.1.1-sdk
ADD . /app
WORKDIR /app
RUN dotnet restore
RUN dotnet publish -c Release
ENTRYPOINT ["dotnet", "bin/Release/netcoreapp1.1/console.dll"]

All good…

Now, setup the Dockerfile for multi-stage build by first instructing the build from the SDK and then apply the output packaged .dll to the smaller runtime image only

Dockerfile

# build stage
FROM microsoft/dotnet:1.1.1-sdk AS build-env
ADD . /app
WORKDIR /app
RUN dotnet restore
RUN dotnet publish -c Release
# final stage
FROM microsoft/dotnet:1.1.1-runtime
WORKDIR /app
COPY --from=build-env /app /app/
ENTRYPOINT ["dotnet", "bin/Release/netcoreapp1.1/console.dll"]

Both images now will run the helloworld but note the difference in images (252M vs 879M)!

Note: i would’ve ran through these images using Alpine for coreCLR but its not available yet)