To get started, you need Docker version 17.05.0-ce-rc1 or better. At the time of this writing I needed to install Docker for Windows Edge channel to make it work. Want to know which version you are running? run on the command line the following command: docker version or Docker –version
As you can find in my previous post, you can create a docker image, using your standard website publishing flow using web deploy. The docker file to make this work for the MVC musicstore sample is as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
FROM microsoft/aspnet
RUN mkdir c:install
ADD WebDeploy_2_10_amd64_en-US.msi /install/WebDeploy_2_10_amd64_en-US.msi
WORKDIR /install
RUN msiexec.exe /i c:installWebDeploy_2_10_amd64_en-US.msi /qn
RUN mkdir c:MvcMusicstore
WORKDIR /MvcMusicStore
ADD fixAcls.ps1 /MvcMusicStore/fixAcls.ps1
ADD MvcMusicstore.zip /MvcMusicStore/MvcMusicStore.zip
ADD MvcMusicStore.deploy.cmd /MvcMusicStore/MvcMusicStore.deploy.cmd
ADD MvcMusicStore.SetParameters.xml /MvcMusicStore/MvcMusicStore.SetParameters.xml
RUN MvcMusicStore.deploy.cmd, /Y
RUN powershell.exe -executionpolicy bypass .fixAcls.ps1
RUN MvcMusicStore.deploy.cmd, /Y
EXPOSE 80
|
Now with multi staged builds we will create a temporary image that does all the heavy lifting of installing the website using web deploy, but we will create a second stage where we create the actual image that we need. This image does not contain all the install files, webdeploy, the zip files, etc. We don’t need webdeploy when we run the website, so we are better of having a image that is clean and only contains the deployed files. this is not only better for image size, it also reduced your attac surface, which is a good practice if it comes to security as well!
The way we create a second stage is by adding the AS keyword at your first FROM statement. You can now create multiple FROM statements in your Dockerfile and only the last FROM is the actual image you want to create and publish. You can in your dockerfile now refer to any of the itnermediate stages by using the COPY keyword and there pass in the flag –from=[nameofstage]. So we can copy resutls from previous stages into our final image. See below the altered dockerbuild file that has two stages:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
##First Stage that deploys the website and upacks the files and structure on disk
FROM microsoft/aspnet AS temp
RUN mkdir c:install
ADD WebDeploy_2_10_amd64_en-US.msi /install/WebDeploy_2_10_amd64_en-US.msi
WORKDIR /install
RUN msiexec.exe /i c:installWebDeploy_2_10_amd64_en-US.msi /qn
RUN mkdir c:MvcMusicstore
WORKDIR /MvcMusicStore
ADD fixAcls.ps1 /MvcMusicStore/fixAcls.ps1
ADD MvcMusicstore.zip /MvcMusicStore/MvcMusicStore.zip
ADD MvcMusicStore.deploy.cmd /MvcMusicStore/MvcMusicStore.deploy.cmd
ADD MvcMusicStore.SetParameters.xml /MvcMusicStore/MvcMusicStore.SetParameters.xml
RUN MvcMusicStore.deploy.cmd, /Y
RUN powershell.exe -executionpolicy bypass .fixAcls.ps1
RUN MvcMusicStore.deploy.cmd, /Y
##second stage that creates the final image and only contains final results
FROM microsoft/aspnet AS final
COPY –from=temp c:/inetpub/wwwroot c:/inetpub/wwwroot
EXPOSE 80
|
This now results in a bare minimum image that has microsoft/aspnet base image that is created by microsoft, and only contains files we need at runtime, that come from the previous step.
This simple example, only works of course if you install at the default website with default settings of the website and application pool. In case you still need to make changes, then you need to run the IIS commands to change the app pool settings in the final stage. But as you can see the result is a much cleaner and smaller image.
If you compare the two images then you see the image size differs with 315MB!
Also, the number of layers is drastically reduced. If you compare the image details, using Docker image inspect command you will see the number of layers for the first single stage build containers is 20 and for the multistage build the number of layers is only 5!
So multi stage builds are a big improvement if it comes to building efficient images. for me this will definitely be the way I build my images in the future!