How to Deploy Windows Containers with Docker on Windows Server 2025

Windows Server 2025 supports two distinct container isolation modes — process isolation and Hyper-V isolation — giving operators fine-grained control over the security boundary between containers and the host. Process-isolated containers share the host kernel directly, offering near-bare-metal density and performance, while Hyper-V isolated containers run each container inside a lightweight virtual machine for stronger workload separation. Understanding when to use each mode, how to author Windows-specific Dockerfiles, and how to configure Windows container networking are the core skills this tutorial addresses. By the end you will be able to build a custom IIS container image, publish it on different network configurations, and manage Windows-specific volume mounts.

Prerequisites

  • Docker Engine installed and running on Windows Server 2025 (see the installation guide)
  • At least one Windows base image pulled locally (e.g., mcr.microsoft.com/windows/servercore:ltsc2022)
  • PowerShell 5.1 or later running as Administrator
  • Hyper-V role enabled for Hyper-V isolation testing
  • Basic familiarity with Dockerfile syntax
  • Internet access to pull images from the Microsoft Container Registry (MCR)

Step 1: Understand Windows Container Isolation Modes

The key differentiator of Windows containers versus Linux containers is the isolation model. Process isolation (also called Windows Server Containers) is the default on Windows Server 2025 and runs the container’s processes directly on the host kernel. Hyper-V isolation wraps each container in a thin Hyper-V partition, so a kernel vulnerability in the container cannot reach the host. Use process isolation for internal workloads where density matters; use Hyper-V isolation for multi-tenant workloads or when running containers from untrusted sources.

# Run a container with explicit process isolation (default on Server 2025)
docker run --rm --isolation=process `
    mcr.microsoft.com/windows/servercore:ltsc2022 `
    powershell -Command "[System.Environment]::OSVersion.Version"

# Run the same image with Hyper-V isolation
# Requires Hyper-V role: Install-WindowsFeature -Name Hyper-V -IncludeManagementTools
docker run --rm --isolation=hyperv `
    mcr.microsoft.com/windows/servercore:ltsc2022 `
    powershell -Command "[System.Environment]::OSVersion.Version"

# Inspect the isolation mode of a running container
docker inspect  --format "{{.HostConfig.Isolation}}"

Step 2: Choose the Right Windows Base Image

Microsoft publishes three principal base image families on MCR, each with a different size and API surface. Select the smallest image that satisfies your application’s requirements to minimise attack surface and pull time.

  • nanoserver — smallest footprint (~100 MB), no PowerShell, no .NET Framework, ideal for .NET 8+ and Go applications
  • servercore — full .NET Framework support, PowerShell, most Win32 APIs, ~3 GB on disk
  • windows — full Windows including Desktop Experience APIs, use only when servercore is insufficient
# Pull all three base image families
docker pull mcr.microsoft.com/windows/nanoserver:ltsc2022
docker pull mcr.microsoft.com/windows/servercore:ltsc2022
docker pull mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022

# Compare compressed sizes
docker images mcr.microsoft.com/windows/nanoserver
docker images mcr.microsoft.com/windows/servercore
docker images mcr.microsoft.com/windows/servercore/iis

Step 3: Build a Custom Windows Container Image with a Dockerfile

Create a Dockerfile that starts from the Windows Server Core image, installs a custom application, and sets the container entry point. The following example installs Python 3 into a Server Core container — a common base for Windows-native automation agents.

# Create a build context directory
New-Item -ItemType Directory -Path C:DockerBuildspython-agent -Force
Set-Location C:DockerBuildspython-agent

# Write the Dockerfile
@'
# escape=`
FROM mcr.microsoft.com/windows/servercore:ltsc2022

LABEL maintainer="[email protected]"
LABEL version="1.0"

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

# Install Python 3.12
RUN Invoke-WebRequest -Uri https://www.python.org/ftp/python/3.12.3/python-3.12.3-amd64.exe `
        -OutFile C:python-installer.exe; `
    Start-Process -FilePath C:python-installer.exe `
        -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' `
        -Wait; `
    Remove-Item C:python-installer.exe

# Create app directory
RUN New-Item -ItemType Directory -Force -Path C:app

WORKDIR C:app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8080

CMD ["python", "server.py"]
'@ | Set-Content -Path Dockerfile -Encoding UTF8

# Build the image
docker build -t python-agent:1.0 -f Dockerfile .

# Verify the build
docker images python-agent

Step 4: Run IIS in a Windows Container

The Microsoft IIS image is one of the most common Windows container workloads. It extends Server Core with IIS already installed and configured. Override the default site content by copying your web files into C:inetpubwwwroot at build time.

# Create an IIS application image
New-Item -ItemType Directory -Path C:DockerBuildsiis-app -Force
Set-Location C:DockerBuildsiis-app

# Simple HTML page for testing
@'

IIS on Windows Server 2025 Container

'@ | Set-Content -Path index.html -Encoding UTF8 # Dockerfile for IIS @' FROM mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022 SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"] # Remove default IIS site content RUN Remove-Item -Recurse -Force C:inetpubwwwroot* # Copy application files COPY index.html C:inetpubwwwroot EXPOSE 80 # IIS service is started by the base image entrypoint (ServiceMonitor.exe) '@ | Set-Content -Path Dockerfile -Encoding UTF8 docker build -t iis-app:1.0 . # Run the IIS container publishing port 80 docker run -d --name iis-site --isolation=process -p 8080:80 iis-app:1.0 # Test connectivity Invoke-WebRequest -Uri http://localhost:8080 -UseBasicParsing # View IIS container logs docker logs iis-site

Step 5: Use Volume Mounts on Windows

Volume mounts on Windows containers use Windows-style paths and must be mapped to Windows paths inside the container. Unlike Linux, you cannot mount directly into the middle of a read-only layer; instead, mount to a directory that does not conflict with image content.

# Create a host directory to mount
New-Item -ItemType Directory -Path D:ContainerDatalogs -Force

# Bind mount a host directory into the container
docker run -d --name iis-logged --isolation=process `
    -p 8081:80 `
    -v "D:ContainerDatalogs:C:inetpublogsLogFiles" `
    iis-app:1.0

# Create and use a named Docker volume (managed by Docker)
docker volume create iis-content

docker run -d --name iis-vol --isolation=process `
    -p 8082:80 `
    -v iis-content:C:inetpubwwwroot `
    mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022

# Inspect the volume
docker volume inspect iis-content

# List files written to the named volume from outside the container
docker run --rm --isolation=process `
    -v iis-content:C:data `
    mcr.microsoft.com/windows/servercore:ltsc2022 `
    powershell -Command "Get-ChildItem C:data"

Step 6: Configure Windows Container Networking

Docker on Windows Server 2025 supports several network drivers. NAT is the default and provides outbound internet access via the host IP. Transparent mode places the container directly on the physical network with its own IP from the DHCP server or a static assignment. Overlay networking spans multiple Docker hosts and requires Docker Swarm.

# List existing Docker networks
docker network ls

# Inspect the default NAT network
docker network inspect nat

# Create a transparent network (container gets a physical network IP)
docker network create -d transparent `
    --subnet=10.0.0.0/24 `
    --gateway=10.0.0.1 `
    TransparentNet

# Run a container on the transparent network with a static IP
docker run -d --name iis-transparent --isolation=process `
    --network TransparentNet `
    --ip 10.0.0.50 `
    -p 80:80 `
    iis-app:1.0

# Create a custom NAT network with a specific subnet
docker network create `
    --driver nat `
    --subnet 172.20.0.0/16 `
    --gateway 172.20.0.1 `
    AppNet

# Connect a running container to an additional network
docker network connect AppNet iis-site

# Inspect container network settings
docker inspect iis-site --format "{{json .NetworkSettings.Networks}}"

Conclusion

Windows Server 2025 containers provide a powerful path to packaging and deploying Windows applications with the same toolchain used for Linux container workloads. This tutorial covered the two isolation modes and when to use each, the three base image families and their trade-offs, authoring production Dockerfiles for Server Core and IIS, Windows-specific volume mount syntax, and the NAT and transparent network drivers. With these building blocks in place, the next steps are automating image builds in a CI/CD pipeline, publishing images to a private Azure Container Registry or on-premises Harbor instance, and composing multi-container Windows applications with Docker Compose.