Skip to main content

Windows Worker Nodes

Purpose: For platform engineers, shows how to add Windows Server nodes using the opencenter-windows Ansible collection.

Informational Only

Windows worker nodes are not part of the GA support boundary for openCenter 2026.01.0. This page is retained for historical and exploratory use.

Architecture​

Windows worker nodes extend an existing openCenter Kubernetes cluster to run Windows container workloads. Key design decisions:

  • Workers only — Kubernetes does not support Windows control plane nodes. The control plane is always Linux.
  • ContainerD runtime — Docker/dockershim was removed in K8s v1.24. ContainerD is the supported runtime.
  • NSSM for kubelet — Windows has no systemd. NSSM (Non-Sucking Service Manager) wraps kubelet as a Windows service.
  • BGP routing — Windows RemoteAccess features installed for Calico pod networking via BGP (idle if using other CNI).
  • SSH connectivity — SSH is the recommended connection method (OpenSSH Server on Windows).
  • Push-based Ansible — Windows node lifecycle differs from Linux; push-based Ansible suits Windows better than GitOps pull.

The collection does NOT handle: CNI plugin installation, kube-proxy config, Windows patching, certificate rotation, or node draining.

Prerequisites​

  • A running openCenter Kubernetes cluster with Linux control plane nodes
  • Windows Server 2019 or 2022 VMs with OpenSSH Server enabled
  • Ansible 2.14+ with the ansible.windows collection
  • Administrator credentials on Windows nodes
  • Network connectivity: Windows node → control plane (port 6443), control plane → Windows node (port 10250)
  • oc_controlplane_nodes inventory group defined (for join token generation)

Steps​

1. Install the Ansible collection​

ansible-galaxy collection install opencenter-cloud.opencenter_windows_workers

Or build from source:

git clone https://github.com/opencenter-cloud/opencenter-windows.git
cd opencenter-windows
ansible-galaxy collection build
ansible-galaxy collection install opencenter-cloud-opencenter_windows_workers-*.tar.gz

2. Prepare the inventory​

Create an inventory file listing your Windows nodes. SSH is the recommended connection:

# windows-inventory.ini
[windows_workers]
win-worker-01 ansible_host=192.168.1.30
win-worker-02 ansible_host=192.168.1.31

[windows_workers:vars]
ansible_connection=ssh
ansible_shell_type=powershell
ansible_user=Administrator

[oc_controlplane_nodes]
cp-01 ansible_host=192.168.1.10
cp-02 ansible_host=192.168.1.11
cp-03 ansible_host=192.168.1.12

3. Create the playbook​

# windows-workers.yml
---
- name: Setup Windows Kubernetes Workers
hosts: windows_workers
vars:
containerd_version: "1.7.13"
crictl_version: "1.29.0"
kube_version: "1.29.0"
k8s_internal_ip: "192.168.1.20" # Control plane API endpoint or LB VIP
roles:
- opencenter-cloud.opencenter_windows_workers.win-containerd
- opencenter-cloud.opencenter_windows_workers.win-kubeadm

4. Run the playbook​

ansible-playbook -i windows-inventory.ini windows-workers.yml

The roles execute in order:

  1. win-containerd — Checks for pending reboots, installs Containers/Hyper-V features, downloads and installs ContainerD, registers it as a Windows service, installs crictl for debugging.
  2. win-kubeadm — Validates ContainerD is running, downloads kubelet/kubeadm, registers kubelet via NSSM, opens firewall port 10250, installs BGP routing features, generates join token from control plane, joins the node.

Expect 10–20 minutes per node. Up to 4 reboots may occur (pending reboot, feature installs, routing features, PATH update).

To rejoin a node after token expiration:

ansible-playbook -i windows-inventory.ini windows-workers.yml --tags join

5. Verify the nodes joined​

kubectl get nodes -o wide

Windows nodes appear with OS-Image: Windows Server 2022 and status Ready.

6. Apply a Windows node taint (optional)​

To prevent Linux workloads from scheduling on Windows nodes:

kubectl taint nodes win-worker-01 os=windows:NoSchedule
kubectl taint nodes win-worker-02 os=windows:NoSchedule

Windows workloads should include a matching toleration and nodeSelector:

spec:
nodeSelector:
kubernetes.io/os: windows
tolerations:
- key: os
value: windows
effect: NoSchedule

Variables Reference​

VariableDefaultRequiredRole
containerd_version—Yeswin-containerd
crictl_version—Yeswin-containerd
kube_version—Yeswin-kubeadm
k8s_internal_ip—Yeswin-kubeadm
skip_hypervisor_support_checkfalseNowin-containerd
cni_bin_pathc:/opt/cni/binNowin-containerd
cni_config_pathc:/etc/cni/net.dNowin-containerd
containerd_pathC:\Program Files\containerdNowin-containerd
hostname_override{{ ansible_hostname }}Nowin-kubeadm
kubernetes_pathC:\kNowin-kubeadm
kubelet_log_pathC:\var\log\kubeletNowin-kubeadm
nssm_install_directoryC:\Program Files\nssmNowin-kubeadm

Set skip_hypervisor_support_check: true when running on VMs without nested virtualization (uses process-isolated containers instead of Hyper-V isolation).

Verification​

# Node status
kubectl get nodes -l kubernetes.io/os=windows

# Run a test Windows pod
kubectl run win-test --image=mcr.microsoft.com/windows/nanoserver:ltsc2022 \
--overrides='{"spec":{"nodeSelector":{"kubernetes.io/os":"windows"}}}' \
--command -- ping -t localhost

kubectl get pod win-test -w
# Should reach Running state

# Cleanup
kubectl delete pod win-test

Troubleshooting​

SymptomLikely causeFix
kubeadm join fails with timeoutControl plane IP unreachableVerify: Test-NetConnection -ComputerName <CP_IP> -Port 6443
Node shows NotReadyContainerD service not runningOn Windows: Get-Service containerd, Start-Service containerd
SSH connection refusedOpenSSH Server not installedInstall: Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Calico pods not runningBGP configuration mismatchVerify calico_version matches the Linux cluster's Calico version
Windows pod stuck in ContainerCreatingMissing container base imagePull: crictl pull mcr.microsoft.com/windows/nanoserver:ltsc2022
Kubelet not startingNSSM not registeredRun: nssm install kubelet "C:\k\StartKubelet.ps1"