Windows Containers
- Hybrid Cluster Support: Kubernetes supports running both Linux and Windows containers within the same cluster. The control plane always runs on Linux, while worker nodes can be either Linux or Windows Server.
- OS Version Dependency: Windows containers have a strict dependency on the host kernel version. A container built for Windows Server 2022 LTSC requires a Windows Server 2022 host. This is fundamentally different from Linux containers, which share a kernel ABI that is backward-compatible across versions.
- Node Affinity Required: To ensure Windows containers only schedule on Windows nodes, explicit
nodeSelector(usingkubernetes.io/os: windows) or taints and tolerations must be configured. Without these, the scheduler may attempt to place Windows pods on Linux nodes, causing failures. - Legacy Workload Modernization: This feature is crucial for enterprises modernizing legacy
.NET Framework 4.x, IIS, or Windows service applications without rewriting them for Linux. It enables a single orchestration platform for mixed-OS environments. - Known Limitations: Windows containers cannot run in privileged mode, do not support host networking, and have limited support for certain Kubernetes features. Understanding these constraints is essential before planning a hybrid cluster.
Not everything runs on Linux. Many enterprises still rely on .NET Framework 4.8, legacy IIS-hosted applications, or Windows services that cannot be ported to .NET (Core/5+) without significant rewriting. Kubernetes supports hybrid clusters where the control plane runs on Linux and some worker nodes run Windows Server, allowing both Linux and Windows workloads to be orchestrated from a single platform.
1. Hybrid Node Architecture
In a hybrid Kubernetes cluster, the control plane components (kube-apiserver, kube-controller-manager, kube-scheduler, etcd) always run on Linux. Windows support is limited to worker nodes. The kubelet and kube-proxy run natively on Windows, and container workloads use the Windows container runtime (containerd on Windows).
This architecture means you need at least one Linux node in every cluster (for the control plane and system components like CoreDNS and the CNI plugin DaemonSets), plus one or more Windows nodes for Windows workloads.
2. Windows Container Types
Windows Server Core
A larger image (~3.1 GB compressed) that includes most of the Windows Server APIs. Use this for applications that depend on the full .NET Framework, IIS, PowerShell, or Win32 APIs. Most legacy application migrations target Server Core.
Nano Server
A minimal image (~100 MB compressed) designed for applications built with .NET (Core/5+) or other lightweight runtimes. Nano Server has no GUI components, no MSI support, and no 32-bit application support. Use it for modern .NET applications that do not need legacy Windows APIs.
Windows Server Base Image Compatibility
The container base image OS version must match the host OS version. This is called process isolation mode. Hyper-V isolation (available on Windows 10/11 but not commonly used in Kubernetes) relaxes this requirement by running each container in a lightweight VM.
| Host OS | Compatible Base Images |
|---|---|
| Windows Server 2022 LTSC | ltsc2022 tagged images |
| Windows Server 2019 LTSC | ltsc2019 tagged images |
If you run a mixed fleet with both Windows Server 2019 and 2022 nodes, you need separate node pools and nodeSelectors to match containers to compatible hosts.
3. Key Limitations vs. Linux Containers
Understanding what Windows containers cannot do is critical for architecture decisions:
- No privileged containers: Windows does not support the
privileged: truesecurity context. DaemonSets that require privileged access (like some monitoring agents or CNI plugins) need Windows-native alternatives. - No host networking:
hostNetwork: trueis not supported on Windows. Pods always use container networking. - No shared process namespace:
shareProcessNamespace: trueis not available. Ephemeral containers with--targetfor process namespace sharing do not work on Windows nodes. - Single container runtime: Only containerd is supported as the container runtime on Windows nodes. Docker (dockershim) support was removed.
- No Linux-specific security features: Seccomp, AppArmor, SELinux, and user namespaces are not available on Windows nodes.
- Limited volume types: Some volume types (like
hostPathvolumes with Linux-specific paths) do not translate to Windows. Windows supports emptyDir, hostPath (with Windows paths), and CSI-based persistent volumes. - No IPv6-only networking: Windows containers support IPv4 and dual-stack but not IPv6-only configurations.
4. Scheduling: Node Selectors and Taints
You must ensure Windows pods land on Windows nodes and Linux pods land on Linux nodes. Without explicit scheduling constraints, the default scheduler makes no OS distinction.
NodeSelector (Minimum Required)
# .NET Framework application targeting Windows nodes
apiVersion: apps/v1
kind: Deployment
metadata:
name: legacy-billing-app
namespace: billing
spec:
replicas: 3
selector:
matchLabels:
app: legacy-billing
template:
metadata:
labels:
app: legacy-billing
spec:
nodeSelector:
kubernetes.io/os: windows # Required: schedule on Windows nodes
node.kubernetes.io/windows-build: "10.0.20348" # Optional: target specific build
containers:
- name: billing
image: myregistry.io/billing-app:v4.8-ltsc2022
ports:
- containerPort: 80
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2"
memory: "4Gi"
Taints and Tolerations (Recommended)
Tainting Windows nodes prevents Linux pods from accidentally scheduling there. This is the recommended practice for hybrid clusters.
# Taint applied to Windows nodes (via kubelet configuration or manually)
# kubectl taint nodes win-node-1 os=windows:NoSchedule
# Windows pods must tolerate the taint
apiVersion: apps/v1
kind: Deployment
metadata:
name: iis-webapp
namespace: web
spec:
replicas: 2
selector:
matchLabels:
app: iis-webapp
template:
metadata:
labels:
app: iis-webapp
spec:
nodeSelector:
kubernetes.io/os: windows
tolerations:
- key: "os"
operator: "Equal"
value: "windows"
effect: "NoSchedule"
containers:
- name: iis
image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022
ports:
- containerPort: 80
5. .NET Workload Examples
.NET Framework 4.8 (Windows-Only)
Legacy .NET Framework applications must run on Windows Server Core. They are typically deployed as IIS-hosted web applications.
# Classic ASP.NET Web API on .NET Framework 4.8
apiVersion: apps/v1
kind: Deployment
metadata:
name: dotnet-framework-api
spec:
replicas: 2
selector:
matchLabels:
app: dotnet-framework-api
template:
metadata:
labels:
app: dotnet-framework-api
spec:
nodeSelector:
kubernetes.io/os: windows
containers:
- name: api
image: myregistry.io/legacy-api:4.8.1-ltsc2022
ports:
- containerPort: 80
env:
- name: ASPNET_ENVIRONMENT
value: "Production"
readinessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 30 # Windows containers take longer to start
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 60 # Allow extra time for IIS warm-up
periodSeconds: 15
.NET 8+ (Cross-Platform)
Modern .NET applications (5, 6, 7, 8+) can run on either Linux or Windows. For these, prefer Linux containers unless you have a specific Windows dependency (COM objects, Windows Registry, etc.).
6. Windows Container Networking
Windows uses the Host Networking Service (HNS) instead of the Linux networking stack. Most modern CNI plugins support Windows:
- Calico: Supports Windows with BGP and VXLAN networking modes. The Calico node agent runs as a Windows service.
- Antrea: Full Windows support with Open vSwitch (OVS). Provides NetworkPolicy enforcement on Windows nodes.
- Azure CNI: Native support for Windows on AKS clusters.
- Flannel: VXLAN overlay networking with Windows support.
Key networking differences on Windows:
- No iptables: Windows uses HNS and the Virtual Filtering Platform (VFP) instead of iptables for packet routing.
- kube-proxy: Runs on Windows and uses either userspace or kernelspace mode (WinDSR for Direct Server Return).
- DNS: Windows containers use the same CoreDNS-based cluster DNS as Linux pods. Pod DNS resolution works identically.
7. Group Managed Service Accounts (gMSA)
Many Windows enterprise applications authenticate to SQL Server, file shares, or other services using Active Directory (AD). gMSA allows Windows containers to assume an AD identity without embedding credentials in the container.
# gMSA credential spec (stored as a Kubernetes resource)
apiVersion: windows.k8s.io/v1
kind: GMSACredentialSpec
metadata:
name: billing-gmsa
credspec:
ActiveDirectoryConfig:
GroupManagedServiceAccounts:
- Name: billing-svc # AD account name
Scope: CORP.EXAMPLE.COM # AD domain
HostAccountConfig:
PortableCcgVersion: "1"
PluginGUID: "{859E1386-BDB4-49E8-85C7-3070B13920E1}"
PluginInput: "ObjectGuid=a69a...;DomainName=CORP.EXAMPLE.COM"
---
# Pod referencing the gMSA credential spec
apiVersion: v1
kind: Pod
metadata:
name: billing-worker
spec:
nodeSelector:
kubernetes.io/os: windows
securityContext:
windowsOptions:
gmsaCredentialSpecName: billing-gmsa # Reference the credential spec
containers:
- name: worker
image: myregistry.io/billing-worker:v2.1-ltsc2022
Setting up gMSA requires joining Windows nodes to the AD domain and configuring the gMSA webhook admission controller. The credential spec is validated at admission time, and the kubelet configures the container's identity at startup.
8. Storage on Windows Nodes
Windows nodes support the following volume types:
- emptyDir: Works identically to Linux, using the node's local storage.
- hostPath: Supported but uses Windows paths (for example,
C:\data). - CSI volumes: The CSI driver interface works on Windows. Azure Disk, Azure File, AWS EBS, and SMB/CIFS CSI drivers support Windows nodes.
- ConfigMap and Secret: Mounted as files in the container, but Windows does not support symbolic links in the same way as Linux. Files are copied rather than symlinked.
# PersistentVolumeClaim for a Windows workload using SMB
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: billing-data
spec:
accessModes:
- ReadWriteMany # SMB supports RWX
storageClassName: smb-csi
resources:
requests:
storage: 50Gi
9. Operational Considerations
Image Size and Pull Times
Windows container images are significantly larger than Linux equivalents. A Windows Server Core image starts at ~3 GB. This affects node startup time, pod scheduling latency, and registry bandwidth. Pre-pulling images on Windows nodes is strongly recommended.
Node Provisioning
Windows nodes typically take longer to provision and join a cluster than Linux nodes. Allow extra time in autoscaling configurations and cluster provisioning pipelines.
Monitoring and Logging
Standard Kubernetes monitoring tools (Prometheus, Grafana) work with Windows nodes, but some exporters need Windows-specific builds. The windows-exporter (formerly wmi-exporter) provides Windows-specific metrics. Fluentd and Fluent Bit have Windows builds for log collection.
Common Pitfalls
- Forgetting nodeSelector: Without
kubernetes.io/os: windows, Windows pods may be scheduled on Linux nodes and fail with cryptic image pull errors (since Windows images cannot run on Linux). - OS version mismatch: Deploying an
ltsc2019image to a Windows Server 2022 node fails. Always tag images with the target OS version and use nodeSelectors to match. - Expecting Linux-equivalent features: Privileged containers, host networking, and security profiles are not available. Plan architecture accordingly.
- Underestimating image sizes: A 3 GB image pull over a slow network can cause pod startup timeouts. Configure appropriate
imagePullPolicyand consider pre-pulling images via DaemonSets. - Ignoring Windows update cycles: Windows Server nodes need regular patching. Plan maintenance windows and use MachineDeployment rolling updates (via CAPI or managed Kubernetes) to rotate nodes with updated OS versions.
- Not testing gMSA in staging: AD integration is complex and brittle. Always validate gMSA configurations in a staging environment before deploying to production.
What's Next?
- Set up a hybrid cluster using your cloud provider's managed Kubernetes service (AKS, EKS, or GKE) with Windows node pools.
- Evaluate Calico or Antrea for CNI plugin support on Windows with NetworkPolicy enforcement.
- Implement gMSA for Windows workloads that require Active Directory authentication.
- Plan an image optimization strategy using multi-stage builds to minimize Windows container image sizes.
- Explore HostProcess containers (Windows privileged containers, GA in Kubernetes 1.26) for node-level operations like log collection and monitoring agents on Windows nodes.
- Review Microsoft's Windows container documentation for the latest base image versions and compatibility matrices.