Finally! AMIRITE? Now that we’ve spun our solr and sql containers up, it’s time to move to the big guns: The CM Server. I’m not going to cover the CD Server, as it’s fairly similar. XP topology is also not very far deviant from the concepts you’ve conquered so far. Let’s get to it. The good news is, we’ve create all the base images for the CM image. Woot! Let’s look at that Dockerfile though, and see whats’ going on. It’s a bit to take in:

# escape=` ARG BASE_IMAGE ARG ASSETS_IMAGE FROM $ASSETS_IMAGE as assets FROM $BASE_IMAGE as build SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] ARG ASSETS_USE_WDP ARG SC_ROLE_CONFIG_DIRECTORY COPY --from=assets ["${ASSETS_USE_WDP}", "C:\\temp\\packages\\"] # expand selected wdp and copy to install into the webroot RUN Expand-Archive -Path 'C:\\temp\\packages\\*.zip' -DestinationPath 'C:\\temp'; ` Copy-Item -Path 'C:\\temp\\Content\\Website\\*' -Destination 'C:\\inetpub\\wwwroot' -Recurse -Force; # copy patches COPY --from=assets ["c:\\patches\\", "c:\\patches\\"] # apply patches RUN Get-ChildItem -Path 'C:\\patches' -Exclude ".gitkeep" | Copy-Item -Destination 'C:\\inetpub\\wwwroot' -Recurse -Force; # configure wwwroot RUN Copy-Item -Path 'C:\\inetpub\\wwwroot\\App_Config\\Include\\Examples\\Sitecore.Owin.Authentication.IdentityServer.Disabler.config.example' -Destination 'C:\\inetpub\\wwwroot\\App_Config\\Include\\Sitecore.Owin.Authentication.IdentityServer.Disabler.config'; ` Copy-Item -Path 'C:\\inetpub\\wwwroot\\App_Config\\Include\\Examples\\Sitecore.LoadBalancing.config.example' -Destination 'C:\\inetpub\\wwwroot\\App_Config\\Include\\Sitecore.LoadBalancing.config'; ` New-Item -Path 'C:\\inetpub\\wwwroot\\upload' -ItemType Directory | Out-Null; ` New-Item -Path 'C:\\inetpub\\wwwroot\\sitecore\\shell\\override' -ItemType Directory | Out-Null; ` Remove-Item -Path 'C:\\inetpub\\wwwroot\\App_Data\\logs' -Force -Recurse; # copy tools and transforms COPY --from=assets ["C:\\install\\tools\\", "C:\\inetpub\\wwwroot\\temp\\install\\tools\\"] COPY ${SC_ROLE_CONFIG_DIRECTORY} C:\\inetpub\\wwwroot\\ # find transform files and do transformation RUN $xdts = (Get-ChildItem -Path 'C:\\inetpub\\wwwroot\\*.config.xdt'), (Get-ChildItem -Path 'C:\\inetpub\\wwwroot\\App_Config\\*.config.xdt' -Recurse); ` $xdts | ForEach-Object { & 'C:\\inetpub\\wwwroot\\temp\\install\\tools\\scripts\\Invoke-XdtTransform.ps1' -Path $_.FullName.Replace('.xdt', '') -XdtPath $_.FullName -XdtDllPath 'C:\\inetpub\\wwwroot\\temp\\install\\tools\\bin\\Microsoft.Web.XmlTransform.dll'; }; ` $xdts | ForEach-Object { Remove-Item -Path $_.FullName; }; # add config patches COPY .\config\*.config C:\\inetpub\\wwwroot\\App_Config\\Include\\ # add installers COPY --from=assets ["C:\\install\\setup\\", "C:\\inetpub\\wwwroot\\temp\\install\\setup\\"] FROM $BASE_IMAGE SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] ARG SC_ROLE_DEFINE COPY --from=build ["C:\\inetpub\\wwwroot\\", "C:\\inetpub\\wwwroot\\"] RUN $env:INSTALL_TEMP = 'C:\\inetpub\\wwwroot\\temp\\install'; ` $env:IIS_SITE_PATH = 'IIS:\Sites\Default Web Site'; ` $env:IIS_SITE_HOMEDIR_PATH = 'C:\\inetpub\\wwwroot'; ` $env:IIS_APPPOOL_IDENTITY = 'IIS AppPool\DefaultAppPool'; ` # install dependencies Start-Process msiexec.exe -ArgumentList '/i', (Join-Path $env:INSTALL_TEMP '\\setup\\urlrewrite.msi'), '/quiet', '/norestart' -NoNewWindow -Wait; ` Start-Process (Join-Path $env:INSTALL_TEMP '\\setup\\vc_redist.exe') -ArgumentList '/install', '/passive', '/norestart' -NoNewWindow -Wait; ` # install tools Copy-Item -Path (Join-Path $env:INSTALL_TEMP '\\tools') -Destination 'C:\\tools' -Recurse -Force; ` setx /M PATH $($env:PATH + ';C:\tools\scripts;C:\tools\bin') | Out-Null; ` # configure Windows to disable DNS caching Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name 'ServerPriorityTimeLimit' -Value 0 -Type DWord; ` # configure app pool group memberships Add-LocalGroupMember -Group 'Performance Monitor Users' -Member $env:IIS_APPPOOL_IDENTITY; ` # configure app pool filesystem permissions $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($env:IIS_APPPOOL_IDENTITY, 'FullControl', @('ContainerInherit', 'ObjectInherit'), 'None', 'Allow'); ` $acl = Get-Acl -Path $env:IIS_SITE_HOMEDIR_PATH; ` $acl.SetAccessRule($rule); ` $acl | Set-Acl -Path $env:IIS_SITE_HOMEDIR_PATH; ` # configure role Import-Module WebAdministration; ` Set-WebConfigurationProperty -PSPath $env:IIS_SITE_PATH -Filter '/appSettings/add[@key=\"role:define\"]' -Name 'value' -Value $env:SC_ROLE_DEFINE; ` # delete temporary files Remove-Item -Path $env:INSTALL_TEMP -Force -Recurse;

So woof. There’s a lot to have in there. One thing you WON’T notice is SIF. These Dockerfiles are sans-SIF (like the font, right?) which, honestly is just a reduction of complexity and a pretty good idea, if you ask me. With this Dockerfile, let’s setup our instance of Sitecore!

docker image build --build-arg BASE_IMAGE=mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-1903 --build-arg ASSETS_IMAGE=sitecore-assets:9.2.0-nanoserver-1903 --build-arg ASSETS_USE_WDP='C:\\packages\\Sitecore 9.2.0 rev. 002893 (XM) (OnPrem)_cm.scwdp.zip' --build-arg SC_ROLE_CONFIG_DIRECTORY='\\config\\cm' --build-arg SC_ROLE_DEFINE='ContentManagement, Indexing' --isolation 'hyperv' --tag sitecore-xm-cm:9.2.0-windowsservercore-1903 .\windows\9.2.x\sitecore-xm\

This looks a little more like Sitecore. We see the path to the WDP (which is now in the Assets Image. We see our config to change the role (CM vs CD here) and we see the Role Define which will be used to transform the web.config as it moves into the Image. Here’s our new Image list:

This feels fresh.

Let’s go ahead and spin our container up and check it out:

docker run -d --publish 44000:80 --mount type=bind,source=C:/Dev/docker/sitecore/dummy/cm,target=C:/inetpub/wwwroot/App_Data/logs --mount type=bind,source=C:/Dev/docker/sitecore/dummy,target=C:/license --name sitecore_cm_920 sitecore-xm-cm:9.2.0-windowsservercore-1903

A quick thing to point out here: For simplicity, the license file is kept OUTSIDE the container, which means you’re going to need a secondary mount. That’s fine, you can have as many as you want to. Just make sure you license file is in the source folder.

Let’s run it! Open up your browser and visit http://localhost:44000 ahhhh what. It isn’t working???

Well this isn’t good. But it isn’t unexpected, either.

Unfortunately, containers a, by nature, isolated. That’s cool though, we can fix that. What we need to do is, is create a network for them to talk over. If you run the following command, you’ll see what networks are there out of the box:

docker network ls

Out of the box networks

We see four out of the box. We could attempt to attach our containers directly to the ‘nat’ network, but that wouldn’t entirely fix our issue. We really want to be able to name our containers on the network. That’s pretty easy once we have a network. So let’s make one and call it something logical:

docker network create -d nat sc_920

All that does is make a new network of type ‘nat’, and name it. We should see this now in our network list:

Oh hi there, new network

Cool cool cool. Let’s put our containers on that network now:

docker network connect --alias sql sc_920 sql_xm_920 docker network connect --alias solr sc_920 solr_xm_920 docker network connect --alias cm sc_920 sitecore_cm_920

The important thing here comes in the alias option. We’re able to name the container on the network, and when we request http://solr:8983, it’ll find our solr_xm_920 container. Pretty neat? Let’s refresh that browser:

SUCCESS! We now have Sitecore running in a docker container, connected to solr in a docker container as well as sql in a docker container. All running in an isolated network. Nice work!

Can we make this easier? It’s a little laborious spinning all the containers up, adding to network, validating the shares, etc. Let’s call our friend Docker Compose for some assistance. He’s hanging out in Part 9: Compose all the Things.

The TL;DR Code

#build our image docker image build --build-arg BASE_IMAGE=mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-1903 --build-arg ASSETS_IMAGE=sitecore-assets:9.2.0-nanoserver-1903 --build-arg ASSETS_USE_WDP='C:\\packages\\Sitecore 9.2.0 rev. 002893 (XM) (OnPrem)_cm.scwdp.zip' --build-arg SC_ROLE_CONFIG_DIRECTORY='\\config\\cm' --build-arg SC_ROLE_DEFINE='ContentManagement, Indexing' --isolation 'hyperv' --tag sitecore-xm-cm:9.2.0-windowsservercore-1903 .\windows\9.2.x\sitecore-xm\ #create the container docker run -d --publish 44000:80 --mount type=bind,source=C:/Dev/docker/sitecore/dummy/cm,target=C:/inetpub/wwwroot/App_Data/logs --mount type=bind,source=C:/Dev/docker/sitecore/dummy,target=C:/license --name sitecore_cm_920 sitecore-xm-cm:9.2.0-windowsservercore-1903 #create a network docker network create -d nat sc_920 #add containers to the network docker network connect --alias sql sc_920 sql_xm_920 docker network connect --alias solr sc_920 solr_xm_920 docker network connect --alias cm sc_920 sitecore_cm_920

[rcblock id=”669″]