Windows Server 2016 | Containers
Why Containers ?
- For packaging and running applications across diverse environments on-prem or cloud
- lightweight, isolated environment — easy to develop, deploy and manage.
- quick start/stop
- useful for utilizing your infrastructure
Virtual Machine with Containers (Process Isolation)
Windows containers running on Windows Server default to running with process isolation.
- Process Isolation — This is the “traditional isolation” for containers. Containers instances run with isolation provided through namespace, resource control and process isolation technologies. Containers share same kernel with host as well as with each other (same as how linux containers run).
docker run -it --isolation=process mcr.microsoft.com/windows/servercore:ltsc2016 cmd

Hyper-V Isolation for Containers
- Hyper-V Isolation — This isolation mode offers enhanced security and broader compatibility between host and container versions. Each container runs inside of a highly optimized virtual machine and effectively gets its own kernel which provides hardware level isolation between each container as well as the container host.
docker run -it --isolation=hyperv mcr.microsoft.com/windows/servercore:ltsc2016 cmd

Windows Base Images
For most users, Windows Server Core and Nanoserver will be the most appropriate image to use.
- full .NET framework? target Windows Server Core.
- .NET Core? target Nanoserver.

Explore Docker Hub for official images for Windows.
Windows Server Core vs Nanoserver
Windows Server Core
and Nanoserver
are the most common base images to target. The key difference between these images is that Nanoserver has a significantly smaller API surface. PowerShell, WMI, and the Windows servicing stack are absent from the Nanoserver image.
Matching container host version with container image versions
- Because Windows Server containers and the underlying host share a single kernel, the container’s base image OS version must match that of the host.
- The Windows operating system has four levels of versioning: major, minor, build and revision. for Eg: 10.0.14393.4225 would have a major version of 10, a minor version of 0, a build number of 14393, and a revision number of 4225
Build number (new release of Windows)
Windows Server containers are blocked from starting when the build number between the container host and the container image are different.
For example, when the container host is version 10.0.14393.* (Windows Server 2016) and container image is version 10.0.16299.* (Windows Server version 1709), the container won’t start.
Revision number (patching)
Windows Server containers currently don’t support scenarios where Windows Server 2016-based containers run in a system where the revision numbers of the container host and the container image are different. For example, if the container host is version 10.0.14393.1914 (Windows Server 2016 with KB4051033 applied) and the container image is version 10.0.14393.1944 (Windows Server 2016 with KB4053579 applied), then the image might not start.
You must know which version you need to use for your container.
If you want Windows Server 2016 as your container OS and want to have the latest patches for it, you should use the tag ltsc2016
when specifying which version of the base OS container images you want :
mcr.microsoft.com/windows/servercore:ltsc2016
If you want a specific patch of Windows Server 2016, you can specify the KB number in the tag.
mcr.microsoft.com/windows/servercore:ltsc2016-KB4053579
You can also specify the exact patches you need with the schema we have used previously, by specifying the OS version in the tag
mcr.microsoft.com/windows/servercore:10.0.14393.1944
Microsoft recommends you keep your systems (host and container) up-to-date with the latest patches and updates to stay secure.
With Hyper-V isolation you can have different OS versions in the container host and image.
Containerization Decision Tree

Build Your own Custom Windows Container Images using Dockerfile | Example : Install IIS
# Sample Dockerfile# Indicates that the windowsservercore image will be used as the base image.FROM mcr.microsoft.com/windows/servercore:ltsc2016# Metadata indicating an image maintainer.LABEL maintainer="ashish.sbaghel@outlook.com"# Uses dism.exe to install the IIS role.RUN dism.exe /online /enable-feature /all /featurename:iis-webserver /NoRestart# Creates an HTML file and adds content to this file.RUN echo "Hello World - Dockerfile" > c:\inetpub\wwwroot\index.html# Sets a command or process that will run each time a container is run from the new image.
CMD [ "cmd" ]
docker build | docker run
# Build
docker build -t test-iis:001-ltsc2016 .# Run Container
docker run --name test-iis -it -p 7070:80 test-iis:001-ltsc2016
Containerize an aspnetcore application
Code can be found in following github repository -
https://github.com/mechdeveloper/aspnetcore-sample-windowscontainer-ltsc2016
Create aspnetcore web app
Run following command to create your app:
dotnet new webApp -o myWebApp --no-https

Build your own Custom Windows Container images | dotnet SDK
FROM mcr.microsoft.com/windows/servercore:ltsc2016SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1' -OutFile 'dotnet-install.ps1'; \
./dotnet-install.ps1 -Channel 5.0 \
$newPath = ('{0};{1}' -f 'C:\\Users\\ContainerAdministrator\\AppData\\Local\\Microsoft\\dotnet', $env:PATH); \
setx /M PATH "$newPath";CMD ["dotnet"]
docker build | docker run
# Build
docker build `
-t ashishbagheldocker/windows/baseimages/dotnet:sdk-5.0-servercore-ltsc2016 .# Run / Test
docker run ashishbagheldocker/windows/baseimages/dotnet:sdk-5.0-servercore-ltsc2016
Build your own Custom Windows Container images | aspnetcore Runtime
FROM mcr.microsoft.com/windows/servercore:ltsc2016SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]ENV ASPNETCORE_URLS http://+:80RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1' -OutFile 'dotnet-install.ps1'; \
./dotnet-install.ps1 .\dotnet-install.ps1 -Runtime aspnetcore -Version 5.0.0 \
$newPath = ('{0};{1}' -f 'C:\\Users\\ContainerAdministrator\\AppData\\Local\\Microsoft\\dotnet', $env:PATH); \
setx /M PATH "$newPath";CMD ["dotnet"]
docker build | docker run
# Build
docker build `
-t ashishbagheldocker/windows/baseimages/aspnetcore:runtime-5.0.0-servercore-ltsc2016# Run / Test
docker run ashishbagheldocker/windows/baseimages/aspnetcore:runtime-5.0.0-servercore-ltsc2016
Build your aspnetcore web application as a docker image using multi stage `Dockerfile`
- use sdk image to build and publish your aspnetcore app
- use runtime image to run your compiled aspnetcore app
# first stage : use sdk image to build
FROM ashishbagheldocker/windows/baseimages/dotnet:sdk-5.0-servercore-ltsc2016 AS build-envWORKDIR /app# copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore# copy and publish app and libraries
COPY . ./
RUN dotnet publish -c Release -o out --no-restore# final stage/image : use runtime image
FROM ashishbagheldocker/windows/baseimages/aspnetcore:runtime-5.0.0-servercore-ltsc2016
WORKDIR /app
COPY --from=build-env /app/out .ENTRYPOINT ["dotnet", "myWebApp.dll"]
docker build
docker build -t aspnetcore-sampleapp:v0.0.1 .
For additional examples of Dockerfiles for Windows, see the Dockerfile for Windows repository.
Deploy using `docker-compose.yml`
version: "3.7"
services:
webapp:
image: aspnetcore-sampleapp:v0.0.1
ports:
- mode: host
target: 80
published: 8080
deploy:
mode: global
endpoint_mode: dnsrr
networks:
- web_netnetworks:
web_net:
docker stack deploy
docker stack deploy --compose-file docker-compose.yml stack- aspnetcoreapp
Source/Reference:
- Docker: https://docs.docker.com/get-started/
- Windows Containers: https://docs.microsoft.com/en-us/virtualization/windowscontainers/