Docker commands look almost identical for Linux and Windows containers, but the runtime model is different. A container image must match the active engine:
Linux image → Linux kernel → Docker Linux engine (usually WSL2 on Windows)
Windows image → Windows kernel → Docker Windows engine
Docker Desktop can switch between its Linux and Windows engines, but it does not run both engines simultaneously. If you need both at once, one practical development setup is Docker Desktop for Windows containers plus a separate Podman machine or Docker Engine in WSL for Linux containers.
Sources:
- Docker:
docker container run - Microsoft: Windows container isolation modes
- Microsoft: Windows container version compatibility
- Docker: Windows permission requirements
- Microsoft: Windows container security
docker desktop engine ls
docker desktop engine use windows
docker info --format 'Server OS={{.OSType}} Architecture={{.Architecture}}'Expected:
Server OS=windows Architecture=x86_64
Switch back to Docker's Linux engine later with:
docker desktop engine use linuxWindows container through Docker Desktop:
docker run --rm --isolation=hyperv `
mcr.microsoft.com/windows/nanoserver:ltsc2022 `
cmd.exe /C "echo Hello from Windows!"Linux container through a separate Podman engine:
podman run --rm docker.io/library/alpine echo "Hello from Linux!"--rm deletes the stopped container automatically. The downloaded image stays
cached for later runs.
Yes, Windows containers can run both Windows PowerShell 5.1 (powershell.exe)
and modern PowerShell 7 (pwsh). The executable available depends on the image.
Windows Server Core includes powershell.exe:
docker run --rm -it --isolation=hyperv `
mcr.microsoft.com/windows/servercore:ltsc2022 `
powershell.exe -NoLogo -NoProfileInside the container:
$PSVersionTable
Write-Output 'Hello from Windows PowerShell'
exitFor a non-interactive command:
docker run --rm --isolation=hyperv `
mcr.microsoft.com/windows/servercore:ltsc2022 `
powershell.exe -NoLogo -NoProfile `
-Command "Write-Output 'Hello from Windows PowerShell'; Get-Host | Select-Object Version"Microsoft's maintained .NET SDK images include PowerShell 7. Use an explicit Windows Server Core tag while Docker is running its Windows engine:
docker run --rm -it --isolation=hyperv `
mcr.microsoft.com/dotnet/sdk:8.0-windowsservercore-ltsc2022 `
pwsh -NoLogoInside the container:
$PSVersionTable
Write-Output 'Hello from PowerShell 7'
exitOr run one command without opening an interactive shell:
docker run --rm --isolation=hyperv `
mcr.microsoft.com/dotnet/sdk:8.0-windowsservercore-ltsc2022 `
pwsh -NoLogo `
-Command "Write-Output 'Hello from pwsh'; Get-Host | Select-Object Version"The plain Nano Server image used in the earlier hello-world example does not include PowerShell, WMI, or the Windows servicing stack. Its smaller footprint is intentional.
Choose the image according to the workload:
| Requirement | Suggested image |
|---|---|
| Small modern application with no shell dependency | Nano Server |
| Built-in Windows PowerShell 5.1 or traditional Windows APIs | Server Core |
| PowerShell 7 plus the .NET SDK | .NET SDK Windows Server Core image |
Server Core and .NET SDK images are substantially larger than Nano Server. For production, build a purpose-specific image containing only the runtime and modules the application requires.
References:
Windows containers support two isolation implementations:
| Mode | Kernel | Strengths | Trade-offs |
|---|---|---|---|
process |
Shared with the Windows host | Fast startup and lower overhead | Host/image kernel compatibility matters; weaker boundary |
hyperv |
A lightweight private kernel per container | Stronger boundary and broader image compatibility | More startup time and memory |
default |
Host policy | Convenient | Behavior changes by host type |
Windows 10/11 normally defaults to Hyper-V isolation. Windows Server normally defaults to process isolation.
docker run --rm --isolation=hyperv IMAGE COMMAND
docker run --rm --isolation=process IMAGE COMMAND
docker run --rm --isolation=default IMAGE COMMANDUse Hyper-V isolation by default on a development workstation:
docker run --rm --isolation=hyperv `
mcr.microsoft.com/windows/nanoserver:ltsc2022 cmd.exe /C verThe version printed by ver is the container image's Windows kernel version.
With Hyper-V isolation, that kernel can differ from the Windows 11 host.
Use process isolation only when:
- the host and image versions are compatible;
- lower overhead is important; or
- a supported host-device class must be shared with the container.
Process isolation on Windows 10/11 is intended for development and testing. Use Windows Server and an appropriate support model for production workloads.
Windows containers do not use Linux UID/GID permissions or Linux capabilities. They use Windows accounts, access-control lists, tokens, and service identities.
Common built-in identities are:
ContainerUser: restricted; preferred for normal application execution.ContainerAdministrator: administrator inside the container; useful while installing or configuring software, but avoid it for routine execution.
Select the runtime identity with --user:
docker run --rm --user ContainerUser `
mcr.microsoft.com/windows/nanoserver:ltsc2022 whoamiOr make it part of the image:
FROM mcr.microsoft.com/windows/nanoserver:ltsc2022
COPY app.exe C:\app\app.exe
USER ContainerUser
ENTRYPOINT ["C:\\app\\app.exe"]Nano Server commonly defaults to ContainerUser; Server Core commonly defaults
to ContainerAdministrator. Check the image instead of assuming:
docker run --rm IMAGE whoamiThe Windows Docker engine is a privileged host service. A trusted user who can
fully control that engine can generally obtain administrator-equivalent control
of the host. Membership in the local docker-users group should therefore be
treated as privileged access.
Hyper-V isolation strengthens the boundary between the workload and host, but it does not make unsafe mounts, credentials, or Docker daemon access harmless.
Windows containers can use a Group Managed Service Account through a credential specification:
docker run --security-opt "credentialspec=file://webapp.json" IMAGEThis is an Active Directory deployment feature, not a substitute for
ContainerUser in a simple local container.
--name NAME stable container name
--rm remove the container when it exits
-d run in the background
-it interactive terminal
--restart POLICY restart behavior for a long-running service
--isolation=hyperv|process|default
--user ContainerUser|ContainerAdministrator
--security-opt credentialspec=file://SPEC.json
--memory 1GB
--cpus 2
--cpu-percent 50
--cpu-shares 7500
--storage-opt size=30GB
--io-maxbandwidth BYTES_PER_SECOND
--io-maxiops OPERATIONS_PER_SECOND
Example:
docker run --rm --isolation=hyperv --memory 1GB --cpus 2 `
mcr.microsoft.com/windows/nanoserver:ltsc2022 cmd.exe /C ver-e NAME=VALUE
--env-file PATH
--hostname NAME
--label KEY=VALUE
Windows images do not automatically inherit arbitrary host environment variables. Pass required values explicitly, and do not put secrets directly in commands that may be saved in shell history.
-p HOST_PORT:CONTAINER_PORT
--network NETWORK
--dns ADDRESS
--add-host NAME:ADDRESS
Example with IIS:
docker run -d --name windows-iis --isolation=hyperv -p 8080:80 `
mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022Open http://localhost:8080. The IIS/Server Core image is much larger than
Nano Server.
Windows paths are used for both source and destination:
New-Item C:\ContainerData -ItemType Directory -Force
docker run --rm --isolation=hyperv `
--mount 'type=bind,source=C:\ContainerData,target=C:\data' `
mcr.microsoft.com/windows/nanoserver:ltsc2022 `
cmd.exe /C "echo persistent data>C:\data\hello.txt"
Get-Content C:\ContainerData\hello.txtFor a read-only mount:
-v C:\ContainerData:C:\data:roWindows ACLs still matter. Do not mount sensitive locations such as the entire
host C:\ drive into an untrusted container.
Supported Windows device classes can be exposed only to process-isolated containers:
docker run --isolation=process `
--device=class/DEVICE-INTERFACE-CLASS-GUID IMAGEHyper-V-isolated Windows containers do not support this device-sharing model.
These Linux-oriented options depend on Linux kernel facilities and generally do not apply to Windows containers:
--privileged
--cap-add / --cap-drop
--pid=host
--tmpfs
--device=/dev/...
Linux UID/GID mappings
SELinux/AppArmor labels
seccomp profiles
Windows uses Hyper-V or process isolation, Windows access tokens, ACLs, job objects, and device-interface classes instead.
Other visible differences include:
| Linux container | Windows container |
|---|---|
Usually sh or bash |
Usually cmd.exe or PowerShell when included |
Paths such as /app/data |
Paths such as C:\app\data |
| UID/GID and capabilities | Windows users, groups, tokens, and ACLs |
| Linux base images | Nano Server, Server Core, or Windows images |
| Generally small base images | Windows base images are usually much larger |
Show the active engine:
docker info --format '{{.OSType}}'Inspect a running container's isolation and user configuration:
docker inspect --format `
'Isolation={{.HostConfig.Isolation}} User={{.Config.User}}' CONTAINERList Windows containers by isolation mode:
docker ps --filter isolation=hyperv
docker ps --filter isolation=processShow every flag supported by the installed CLI:
docker run --helpCommon failures:
| Error | Likely cause |
|---|---|
no matching manifest for linux/amd64 |
Linux engine selected for a Windows image |
image operating system "windows" cannot be used |
Wrong engine selected |
| OS version incompatibility | Use Hyper-V isolation or a compatible image tag |
| Access denied on a bind mount | Host/container ACL mismatch |
--device rejected |
Device sharing requires process isolation |
For local Windows-container development:
- Prefer
--isolation=hyperv. - Run the application as
ContainerUserwhere possible. - Give the container explicit CPU and memory limits when it is long-running.
- Mount only the exact host directories required.
- Treat
docker-usersmembership and Docker daemon access as privileged. - Rebuild from Microsoft’s updated base images instead of patching a running Windows container like a normal VM.