Introduction to Kubernetes on Windows Server 2019
Kubernetes is the industry-standard container orchestration platform that automates deployment, scaling, and management of containerized applications. Windows Server 2019 can participate in Kubernetes clusters as a worker node, running Windows containers alongside Linux-based control plane components. As of Kubernetes 1.14 and later, Windows worker nodes are officially supported, enabling organizations to run both Linux and Windows workloads in the same Kubernetes cluster. The control plane components including the API server, etcd, scheduler, and controller manager must run on Linux nodes. Windows Server 2019 nodes run the kubelet, kube-proxy, and a container runtime such as containerd to execute Windows container workloads.
Prerequisites and Architecture Overview
A typical hybrid Kubernetes cluster for Windows Server 2019 workloads requires at least one Linux master node running the Kubernetes control plane, and one or more Windows Server 2019 worker nodes. For production, use three Linux master nodes for high availability. The Linux master can run Ubuntu 20.04, CentOS 8, or similar. The Windows worker nodes run Windows Server 2019. All nodes must have static IP addresses, network connectivity to each other, and unique hostnames. Disable Windows Firewall or configure it to allow Kubernetes traffic on ports 6443, 10250, 10251, 10252, and 2379-2380. Disable IPv6 if not in use.
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
New-NetFirewallRule -DisplayName "Kubernetes API" -Direction Inbound -Protocol TCP -LocalPort 6443 -Action Allow
New-NetFirewallRule -DisplayName "Kubelet" -Direction Inbound -Protocol TCP -LocalPort 10250 -Action Allow
Preparing Windows Server 2019 as a Kubernetes Worker Node
Prepare the Windows Server 2019 node by enabling the Containers feature and ensuring the system meets Kubernetes requirements:
Install-WindowsFeature Containers -Restart
Get-ComputerInfo | Select-Object OsName, OsVersion
hostname
Disable Windows Defender real-time monitoring temporarily during installation to avoid performance issues (re-enable in production):
Set-MpPreference -DisableRealtimeMonitoring $true
Set a unique hostname for the node:
Rename-Computer -NewName "k8s-win-worker01" -Restart
Installing containerd on Windows Server 2019
Containerd is the recommended container runtime for Kubernetes on Windows Server 2019, replacing Docker for Kubernetes workloads. Install containerd:
$Version = "1.7.0"
curl.exe -L "https://github.com/containerd/containerd/releases/download/v${Version}/containerd-${Version}-windows-amd64.tar.gz" -o containerd.tar.gz
tar.exe -xvf containerd.tar.gz -C "C:Program Files"
mkdir C:Programdatacontainerdstate
mkdir C:Programdatacontainerdroot
containerd.exe config default | Out-File C:Programdatacontainerdconfig.toml
Register and start the containerd service:
& "C:Program Filesbincontainerd.exe" --register-service
Start-Service containerd
Set-Service containerd -StartupType Automatic
containerd --version
Installing crictl for containerd
crictl is the command-line interface for CRI-compatible container runtimes and is used by Kubernetes to manage containers and images through the CRI interface:
$Version = "v1.26.0"
curl.exe -L "https://github.com/kubernetes-sigs/cri-tools/releases/download/${Version}/crictl-${Version}-windows-amd64.tar.gz" -o crictl.tar.gz
tar.exe -xvf crictl.tar.gz -C "C:Windowssystem32"
crictl --version
Configure crictl to use the containerd socket:
$config = @"
runtime-endpoint: npipe:////./pipe/containerd-containerd
image-endpoint: npipe:////./pipe/containerd-containerd
timeout: 10
"@
$config | Out-File -FilePath "C:ProgramDatacrictl.yaml" -Encoding ascii
Installing kubelet and kube-proxy
Download and install the Kubernetes node components. Choose a Kubernetes version compatible with your control plane:
$KubeVersion = "v1.27.0"
$KubePath = "C:k"
mkdir $KubePath
curl.exe -L "https://dl.k8s.io/${KubeVersion}/bin/windows/amd64/kubelet.exe" -o "$KubePathkubelet.exe"
curl.exe -L "https://dl.k8s.io/${KubeVersion}/bin/windows/amd64/kube-proxy.exe" -o "$KubePathkube-proxy.exe"
curl.exe -L "https://dl.k8s.io/${KubeVersion}/bin/windows/amd64/kubectl.exe" -o "$KubePathkubectl.exe"
$env:PATH = "$env:PATH;C:k"
[Environment]::SetEnvironmentVariable("PATH", $env:PATH, "Machine")
Joining the Windows Node to the Kubernetes Cluster
Copy the kubeconfig file from the Linux master node to the Windows node. This file contains the cluster API server address and credentials. Store it at C:kconfig:
# From the Linux master, copy the join token
kubeadm token create --print-join-command
# This outputs a command like:
# kubeadm join 192.168.1.10:6443 --token xxx --discovery-token-ca-cert-hash sha256:yyy
On Windows Server 2019, use the SIG Windows tooling to join the node to the cluster. Download and run the sig-windows-tools:
curl.exe -L "https://github.com/kubernetes-sigs/sig-windows-tools/releases/latest/download/PrepareNode.ps1" -o PrepareNode.ps1
.PrepareNode.ps1 -KubernetesVersion "v1.27.0"
kubeadm join 192.168.1.10:6443 --token your_token_here --discovery-token-ca-cert-hash sha256:your_hash_here
Verify the Windows node joined the cluster from the Linux master:
kubectl get nodes -o wide
kubectl describe node k8s-win-worker01
Installing a CNI Plugin for Windows
A Container Network Interface (CNI) plugin is required for pod networking. For Windows nodes, Flannel with the vxlan backend or Calico are commonly used. Install Flannel’s Windows-compatible overlay network. From the Linux master, apply the Flannel manifest for hybrid Windows/Linux clusters:
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/sig-windows-tools/master/hostprocess/flannel/flanneld.yml
On the Windows node, verify the CNI is functioning:
ls C:kcniconfig
ipconfig | findstr "vEthernet"
Deploying Windows Workloads
Deploy Windows containers to the Windows worker node using node selectors to ensure Windows pods are scheduled on Windows nodes. Create a deployment manifest for a Windows IIS application:
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: iis-deployment
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: iis
template:
metadata:
labels:
app: iis
spec:
nodeSelector:
kubernetes.io/os: windows
containers:
- name: iis
image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: iis-service
spec:
selector:
app: iis
ports:
- port: 80
targetPort: 80
type: LoadBalancer
EOF
Verify deployment status:
kubectl get pods -o wide
kubectl get deployments
kubectl get services
kubectl describe pod -l app=iis
Troubleshooting Windows Kubernetes Nodes
Check kubelet and kube-proxy status on Windows worker nodes:
Get-Service kubelet, kube-proxy, containerd | Select-Object Name, Status
Get-WinEvent -LogName System -Source kubelet -MaxEvents 20 | Format-List TimeCreated, Message
kubectl logs -n kube-system -l component=kube-proxy
kubectl describe node k8s-win-worker01 | findstr -i "taints|conditions"
Common issues include pod networking failures from incorrect CNI configuration, certificate mismatch errors from clock skew (sync time with w32tm), and image pull failures. Check the kubelet logs:
Get-WinEvent -LogName "System" -MaxEvents 50 | Where-Object {$_.ProviderName -eq "kubelet"} | Format-List