In the previous post, you probably ran the following and had no idea what you were doing. If you did, shhhh and move along…

docker image build --build-arg BUILD_IMAGE=mcr.microsoft.com/windows/servercore:1903 --build-arg BASE_IMAGE=mcr.microsoft.com/windows/nanoserver:1903 --tag sitecore-assets:9.2.0-nanoserver-1903 --isolation 'hyperv' .

Some of this is pretty intuitive. Such as the “docker” part. “image” just means you’re working with Images. “build” does what you think. You are building an image with docker. I’m not making it up, folks.

Now things get a little trickier, you notice we are passing the following options:

  • Two Build-Args (You can have as many as you want)
  • One Tag
  • One Isolation level

We’ll talk about Build Args in a sec. Focusing on the Tag Option, that essentially allows you to reference the image later for builds. It’s nothing fancy except it names the repository first, then the image name second. In the example, the repository is “sitecore-assets” and the image is “9.2.0-nanoserver-1903”. Next is the Isolation. This for windows should always be set to “hyperv” because someone who knows a lot more about this said so, and I’m not inclined to argue much with them.

Looking at build-args now, to make sense of them, we’ll want to pop open the Dockerfile itself. The one sitting in \windows\9.2.0\sitecore-assets. When we do open this up, we see the following

# escape=`
ARG BUILD_IMAGE
ARG BASE_IMAGE

FROM $BUILD_IMAGE as build

SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

# download remote assets
RUN New-Item -Path 'C:\\downloads' -ItemType 'Directory' -Force | Out-Null; `
    & curl.exe -sS -L -o c:\\downloads\\nuget.exe https://dist.nuget.org/win-x86-commandline/v5.2.0/nuget.exe; `
    & curl.exe -sS -L -o C:\\downloads\\urlrewrite.msi https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_en-US.msi; `
    & curl.exe -sS -L -o C:\\downloads\\vc_redist.exe https://aka.ms/vs/15/release/VC_redist.x64.exe; `
    & curl.exe -sS -L -o C:\\downloads\\7z-installer.exe https://www.7-zip.org/a/7z1900-x64.exe;

# copy local assets
COPY *.zip C:\\downloads\\
COPY patches\\ c:\\patches\\

# install 7zip
RUN New-Item -Path 'C:\\install\\tools\\bin\\7zip' -ItemType 'Directory' -Force | Out-Null; `
    & 'C:\\downloads\\7z-installer.exe' /S /D='C:\\install\\tools\\bin\\7zip\\';

# verify assets
RUN Get-ChildItem -Path 'C:\\downloads\\*.zip' | ForEach-Object { & 'C:\\install\\tools\\bin\\7zip\\7z.exe' t $_.FullName -r }

# install nuget
RUN Move-Item -Path 'C:\\downloads\\nuget.exe' -Destination 'C:\\install\\tools\\bin' -Force;

# install microsoft xdt assembly
RUN & 'C:\\install\\tools\\bin\\nuget.exe' install 'Microsoft.Web.Xdt' -Version '3.0.0' -OutputDirectory 'C:\\install'; `
    Copy-Item -Path 'C:\\install\\Microsoft.Web.Xdt*\\lib\\netstandard2.0\\*.dll' -Destination 'C:\\install\\tools\\bin'; `
    Remove-Item -Path (Get-Item -Path 'C:\\install\\Microsoft.Web.Xdt*\\').FullName -Recurse -Force;

# extract assets, skip wdps, move already extracted wdps
RUN $zips = Get-ChildItem -Path 'C:\\downloads\\*.zip' -Exclude '*.scwdp.zip'; `
    $zips | ForEach-Object { Expand-Archive -Path $_.FullName -DestinationPath 'C:\\packages' -Force; }; `
    $zips | ForEach-Object { Remove-Item -Path $_.FullName -Force; }; `
    $zips = Get-ChildItem -Path 'C:\\downloads\\*.zip' -Exclude '*Configuration files*.zip'; `
    $zips | ForEach-Object { Move-Item -Path $_.FullName -Destination 'C:\\packages'; };

# move installers
RUN New-Item -Path 'C:\\install\\setup' -ItemType 'Directory' -Force | Out-Null; `
    Get-ChildItem 'C:\\downloads\\*.*' -Include '*.exe', '*.msi' | Move-Item -Destination 'C:\\install\\setup';

# add tools folder
COPY tools C:\\install\\tools

FROM $BASE_IMAGE

COPY --from=build ["C:\\install\\", "C:\\install\\"]
COPY --from=build ["C:\\packages\\", "C:\\packages\\"]
COPY --from=build ["C:\\patches\\", "C:\\patches\\"]

It’s a bit much, yeah. Let’s eat the elephant one bite at a time, though.

# escape=`

This simply changes the escape character from back slack to back tick. Keep it spicy, guys.

ARG BUILD_IMAGE
ARG BASE_IMAGE

These look sneakily like the Args passed in. HRM! Sure enough, the values from the command line are mapped into here. You can reference them later with a dollar sign, such as $BUILD_IMAGE

FROM $BUILD_IMAGE as build

FROM is a fun one. This guy actually sets a new build stage. Anything run after this is run on that build stage.

SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

SHELL does kinda what you think. Commands run after this will use whatever shell is defined here. We like PowerShell, though. From the bottom of our hearts.

RUN New-Item -Path 'C:\\downloads' -ItemType 'Directory' -Force | Out-Null; `
    & curl.exe -sS -L -o c:\\downloads\\nuget.exe https://dist.nuget.org/win-x86-commandline/v5.2.0/nuget.exe; `
    & curl.exe -sS -L -o C:\\downloads\\urlrewrite.msi https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_en-US.msi; `
    & curl.exe -sS -L -o C:\\downloads\\vc_redist.exe https://aka.ms/vs/15/release/VC_redist.x64.exe; `
    & curl.exe -sS -L -o C:\\downloads\\7z-installer.exe https://www.7-zip.org/a/7z1900-x64.exe;

RUN does kinda what you think. It executes something in the shell (which is now PowerShell. So it creates a new folder first in the C drive of the Image. Then it uses curl.exe (we love curl, too) to download some files into that directory. Nothing crazy so far, right?

This post is getting pretty intense. Time to:

OK, back on track:

COPY *.zip C:\\downloads\\
COPY patches\\ c:\\patches\\

COPY here is also pretty straight forward. All those zip files we had next to the docker file? They are going in the Image’s C:\downloads now. Same with the folder we had in the local file system called patches. Copy can reference the host’s file system, or even another Image’s file system.

RUN New-Item -Path 'C:\\install\\tools\\bin\\7zip' -ItemType 'Directory' -Force | Out-Null; `
    & 'C:\\downloads\\7z-installer.exe' /S /D='C:\\install\\tools\\bin\\7zip\\';

Another RUN, this time to install 7-Zip.

RUN Get-ChildItem -Path 'C:\\downloads\\*.zip' | ForEach-Object { & 'C:\\install\\tools\\bin\\7zip\\7z.exe' t $_.FullName -r }

# install nuget
RUN Move-Item -Path 'C:\\downloads\\nuget.exe' -Destination 'C:\\install\\tools\\bin' -Force;

# install microsoft xdt assembly
RUN & 'C:\\install\\tools\\bin\\nuget.exe' install 'Microsoft.Web.Xdt' -Version '3.0.0' -OutputDirectory 'C:\\install'; `
    Copy-Item -Path 'C:\\install\\Microsoft.Web.Xdt*\\lib\\netstandard2.0\\*.dll' -Destination 'C:\\install\\tools\\bin'; `
    Remove-Item -Path (Get-Item -Path 'C:\\install\\Microsoft.Web.Xdt*\\').FullName -Recurse -Force;

# extract assets, skip wdps, move already extracted wdps
RUN $zips = Get-ChildItem -Path 'C:\\downloads\\*.zip' -Exclude '*.scwdp.zip'; `
    $zips | ForEach-Object { Expand-Archive -Path $_.FullName -DestinationPath 'C:\\packages' -Force; }; `
    $zips | ForEach-Object { Remove-Item -Path $_.FullName -Force; }; `
    $zips = Get-ChildItem -Path 'C:\\downloads\\*.zip' -Exclude '*Configuration files*.zip'; `
    $zips | ForEach-Object { Move-Item -Path $_.FullName -Destination 'C:\\packages'; };

# move installers
RUN New-Item -Path 'C:\\install\\setup' -ItemType 'Directory' -Force | Out-Null; `
    Get-ChildItem 'C:\\downloads\\*.*' -Include '*.exe', '*.msi' | Move-Item -Destination 'C:\\install\\setup';

More of the RUN command, just setting up some plumbing and installing utilities that we’ll need later. Again, since we’re layering, all this will be available to downstream images, and we don’t have to jack with it again.

COPY tools C:\\install\\tools

Another simple COPY command to drop off some tools

FROM $BASE_IMAGE

If you remember from earlier, this is going to pop another Image out and the subsequent commands will run against that. All the previous commands are being run against the BUILD Image, which was from servercore. Now we’re running an new internal image from nanocore. I’m assuming this was for some space savings…

COPY --from=build ["C:\\install\\", "C:\\install\\"]
COPY --from=build ["C:\\packages\\", "C:\\packages\\"]
COPY --from=build ["C:\\patches\\", "C:\\patches\\"]

Ah, ha. So what we see here is that the COPY command is grabbing files from the build image (servercore) and copying them over to nancore. Again, hypothesizing this is for space constraints.

If you want to read through all the commands, you can head over to the build reference site.

Now that we understand the basics of a Dockerfile, let’s try to spin up a solr server. Try that out in Part 6: Simply Solr.


This is a post in the “Yet Another Sitecore Docker Series.” Other Posts include