Introduction to Windows Server 2019 Containers
Windows Server 2019 includes native support for containerization, enabling organizations to run applications in isolated, lightweight environments called containers. Unlike virtual machines, containers share the host OS kernel but maintain isolation through namespaces and resource controls. Windows Server 2019 supports two container isolation types: process isolation and Hyper-V isolation. Process isolation uses Windows kernel namespaces for lightweight isolation where all containers share the host kernel. Hyper-V isolation runs each container in a lightweight utility VM providing stronger isolation suitable for multi-tenant environments or running untrusted code. Windows Server 2019 also supports Linux containers in Hyper-V isolation mode through the Linux Containers on Windows (LCOW) feature.
Prerequisites for Windows Containers
Windows Server 2019 must be running with at least 4 GB of RAM and adequate disk space for container images, which can be 5-10 GB each. The server must have internet access to pull container images from Docker Hub or Microsoft Container Registry, or an internal registry must be available. Hyper-V isolation requires the Hyper-V role installed and the CPU must support hardware virtualization. Verify hardware virtualization support:
Get-ComputerInfo -Property HyperV*
systeminfo | findstr /i "hyper-v"
Installing the Containers Feature
Enable the Containers feature on Windows Server 2019. This feature is required for running both process-isolated and Hyper-V-isolated Windows containers:
Install-WindowsFeature Containers -Restart
If Hyper-V isolation is needed, also install the Hyper-V role:
Install-WindowsFeature Hyper-V -IncludeManagementTools -Restart
Verify the Containers feature is installed:
Get-WindowsFeature Containers, Hyper-V | Select-Object Name, InstallState
Installing Docker on Windows Server 2019
Docker is the container runtime for Windows Server 2019. Install the Docker Engine using PowerShell from the PowerShell Gallery:
Install-Module -Name DockerMsftProvider -Repository PSGallery -Force
Install-Package -Name docker -ProviderName DockerMsftProvider -Force -RequiredVersion 20.10.9
Restart-Computer -Force
After restart, verify Docker installation and service status:
docker version
docker info
Get-Service docker | Select-Object Status, DisplayName
Pulling Windows Container Base Images
Microsoft provides several Windows container base images from the Microsoft Container Registry (mcr.microsoft.com). The primary base images for Windows Server 2019 containers are Windows Server Core (a large image with most Win32 APIs), Nano Server (a minimal image with limited APIs, optimized for .NET Core), and the Windows image (the full Windows base). Pull the Windows Server Core image matching your host OS version:
docker pull mcr.microsoft.com/windows/servercore:ltsc2019
docker pull mcr.microsoft.com/windows/nanoserver:1809
docker pull mcr.microsoft.com/windows:1809
List downloaded images:
docker images
The first pull takes time as the images are several gigabytes. Subsequent pulls of images based on the same layers are fast.
Running Your First Windows Container
Run a basic Windows container to verify the environment is working correctly. Run an interactive PowerShell session in a Server Core container:
docker run -it mcr.microsoft.com/windows/servercore:ltsc2019 powershell
Inside the container, run commands to verify the isolated environment:
hostname
ipconfig
Get-Process
exit
Run a detached container and inspect it:
docker run -d --name web01 -p 80:80 mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
docker ps
docker inspect web01
docker logs web01
Creating a Custom Windows Container Image
Build custom container images using a Dockerfile. Create a directory for the build context and write a Dockerfile to containerize a sample ASP.NET application:
mkdir C:DockerBuildWebApp
cd C:DockerBuildWebApp
Create the Dockerfile with the following content:
FROM mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
RUN Remove-Item -Recurse C:inetpubwwwroot*
COPY index.html C:inetpubwwwroot
EXPOSE 80
CMD ["ping", "-t", "localhost"]
Create a sample index.html and build the image:
echo "Hello from Windows Container
" > C:DockerBuildWebAppindex.html
docker build -t contoso/webapp:1.0 C:DockerBuildWebApp
docker run -d --name webapp -p 8080:80 contoso/webapp:1.0
Configuring Container Networking
Windows containers support several network modes. NAT is the default, where containers get private IP addresses and the host performs NAT for outbound traffic. Transparent mode connects containers directly to the physical network. Overlay networking connects containers across multiple hosts using a virtual network. Configure a custom NAT network:
docker network create -d nat --subnet=172.20.0.0/16 --gateway=172.20.0.1 CorpNAT
docker run -d --network CorpNAT --name db01 mcr.microsoft.com/windows/servercore:ltsc2019
For transparent networking where containers get IP addresses directly from your network:
docker network create -d transparent --subnet=192.168.1.0/24 --gateway=192.168.1.1 CorpTransparent
Inspect network configuration:
docker network ls
docker network inspect CorpNAT
Configuring Container Storage
Containers have ephemeral storage by default, meaning data written inside a container is lost when the container is removed. Use volumes or bind mounts to persist data. Create a Docker volume and mount it into a container:
docker volume create AppData
docker run -d --name sqlcontainer -v AppData:C:SQLData -e sa_password=P@ssw0rd! -e ACCEPT_EULA=Y mcr.microsoft.com/mssql/server:2019-latest
Use a bind mount to map a host directory into a container:
docker run -d --name webserver -v C:WebContent:C:inetpubwwwroot -p 80:80 mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
Using Hyper-V Isolation
Run containers with Hyper-V isolation for stronger security boundaries. This is required when the container image OS version does not match the host OS version, or for running multiple container OS versions on the same host:
docker run -it --isolation=hyperv mcr.microsoft.com/windows/servercore:ltsc2019 powershell
docker run -d --isolation=hyperv --name hyperv-web -p 8081:80 mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
Verify isolation type of running containers:
docker inspect hyperv-web --format "{{.HostConfig.Isolation}}"
Managing Container Resources
Control CPU and memory resources allocated to containers to prevent resource contention. Limit a container to 2 CPU cores and 2 GB of RAM:
docker run -d --name limited-app --cpus="2.0" --memory="2g" --memory-swap="4g" mcr.microsoft.com/windows/servercore:ltsc2019
Monitor resource usage of running containers:
docker stats
docker stats --no-stream --format "table {{.Name}}t{{.CPUPerc}}t{{.MemUsage}}"
Setting Up a Private Container Registry
Run a private Docker registry on your network to host custom images without relying on Docker Hub. Deploy the registry container:
docker run -d -p 5000:5000 --restart always --name registry -v C:RegistryData:/var/lib/registry registry:2
Tag and push a local image to the private registry:
docker tag contoso/webapp:1.0 localhost:5000/contoso/webapp:1.0
docker push localhost:5000/contoso/webapp:1.0
docker pull localhost:5000/contoso/webapp:1.0
Windows Server 2019 containers provide a powerful way to deploy and manage applications with consistent environments, reduced conflicts, and faster startup times compared to traditional virtual machines.