One of the most anticipated announcements in the Docker space when it comes to building images is Multi-Stage builds because of the huge benefits it gives to CI/CD pipelines in DevOps. Before this announcement, building software in a container usually involved creating a container with all the SDK’s and compilers in the container, uploading code into the container, compiling it, creating a drop, then building another container with just the runtime that sucks in the compiled code to run. This pattern required an external tool and storage to build the container image so it was more burdensome.

Multi-Stage builds on Docker though provide a mechanism for moving the output of a build from a builder container into another container that can be used for running. Consider the following the example. This Dockerfile builds a .NET core app in one container then packages it in another.

FROM microsoft/dotnet:1.1.2-sdk-jessie
COPY /myapp /myapp
RUN dotnet restore ./myapp && 
    dotnet build -c release ./myapp && 
    dotnet publish -c release -o pubdir ./myapp

#Final Build
FROM microsoft/dotnet:1.1.2-runtime
COPY --from=0 /myapp/pubdir /myapp
ENTRYPOINT ["dotnet", "/myapp/myapp.dll"]

This file has two FROM instructions, which in a traditional Dockerfile only one is a allowed. The first one in the file Dockerfile points to an image on Docker Hub for .NET Core on Linux with the SDK already installed. This instructions are quite simple: upload the code and compile it. In classic Dockerfiles, additional steps would be required to move the binaries out of the build container into a share to be picked up.

Notice the COPY the command after the second FROM. This copy now has a parameter, –from= that allows artifacts to be copied out of a builder container into the respective container. The integer refers to a 0-based array, with 0 referring to the first container being used in the Dockerfile.

Chaining build containers with the final container as the final artifact allows users to implement better CI and CD with Docker without having to use external tools to have separate build/test and deployment containers.

Here’s a working example using the above Dockerfile.