把 Windows Server 纳入 Kubernetes 集群,最大的坑往往不是 join 命令本身,而是前置组件没有按 Windows 的方式准备好。Linux 节点一条 kubeadm join 可以完成的工作,在 Windows 上必须先把 containerd、kubelet、kube-proxy 和网络插件都配置到位,否则节点会反复 NotReady,Pod 也调度不上去。本文以 Windows Server 2022 和较新的 Kubernetes 版本为例,完整说明从系统准备到节点加入、再到网络排错的过程。

一、安装前的版本匹配与系统准备
Windows 节点只能作为 Kubernetes 工作节点,不能充当控制平面节点。安装前要先确认 Windows Server 版本、容器基础镜像版本和 Kubernetes 版本之间的关系。Windows 容器对主机内核版本很敏感,Windows Server 2022 主机通常只能运行对应 LTSC2022 标签的容器镜像,如果镜像标签和主机版本不一致,容器可能会一直无法启动。
系统准备的第一步是启用容器功能,管理员可以在 PowerShell 中执行 Install-WindowsFeature Containers,完成后重启服务器。接着需要创建几个固定目录:C:\k 用来存放 kubelet、kube-proxy、kubeadm 等可执行文件,C:\var\lib\kubelet 存放 kubelet 运行数据,C:\etc\kubernetes 存放 kubeconfig 文件,C:\var\log\kubelet 存放 kubelet 日志。还要确认防火墙不会拦截节点间的 VXLAN 端口 UDP 4789 以及 kubelet 端口 TCP 10250。
如果之前安装过 Docker Desktop、Docker EE 或其他容器运行时,建议先卸载,避免和 containerd 争抢 Windows 容器功能。Windows Server 自带的 Containers 功能只需要启用一次,后续由 containerd 管理容器生命周期。系统盘建议保留足够空间,因为 Windows 基础镜像体积通常比 Linux 镜像大得多,单个 servercore 镜像就可能超过 4GB。
二、安装 containerd 并注册 Windows 服务
Windows 节点推荐使用 containerd 作为容器运行时。先在 GitHub 或镜像站下载 Windows amd64 版本的 containerd 压缩包,解压到 C:\Program Files\containerd。注意目录名不要随意更改,因为后续 kubelet 的 CRI 套接字路径会依赖 containerd 服务。
$containerdVersion = "1.7.20" $url = "https://github.com/containerd/containerd/releases/download/v$containerdVersion/containerd-$containerdVersion-windows-amd64.tar.gz" Invoke-WebRequest -Uri $url -OutFile C:\containerd.tar.gz tar -xzf C:\containerd.tar.gz -C "C:\Program Files\containerd" containerd.exe config default | Out-File "C:\Program Files\containerd\config.toml" -Encoding ascii containerd.exe --register-service Start-Service containerd
上面的命令不仅解压了二进制文件,还生成默认配置文件并注册了 containerd 服务。默认配置中 pause 镜像通常指向 registry.k8s.io/pause:3.8 或类似地址,如果集群无法访问该地址,需要把 C:\Program Files\containerd\config.toml 中的 sandbox_image 改成可访问的镜像地址,例如 mcr.microsoft.com/oss/kubernetes/pause:3.9。
执行 Get-Service containerd 应该能看到服务状态为 Running。如果启动失败,可以使用 containerd.exe --log-level debug 前台运行观察输出,也可以查看 Windows 事件日志。另一个常见问题是 C:\Program Files\containerd 没有加入系统 PATH,但这不影响服务运行,只有在手动执行 containerd 命令时才需要切换到该目录。
三、下载 Kubernetes 组件并准备 kubelet
接下来需要准备 kubeadm、kubelet 和 kube-proxy 三个可执行文件。它们可以从 Kubernetes 官方下载地址获取,版本号要和 Linux 控制平面保持一致或略低一个小版本。下面示例假设 Kubernetes 版本为 v1.29.0,目录统一放到 C:\k。
$K8S_VERSION = "v1.29.0" $baseUrl = "https://dl.k8s.io/$K8S_VERSION/bin/windows/amd64" New-Item -ItemType Directory -Force C:\k Invoke-WebRequest -Uri "$baseUrl/kubeadm.exe" -OutFile C:\k\kubeadm.exe Invoke-WebRequest -Uri "$baseUrl/kubelet.exe" -OutFile C:\k\kubelet.exe Invoke-WebRequest -Uri "$baseUrl/kube-proxy.exe" -OutFile C:\k\kube-proxy.exe
这些文件下载后并不会自动注册为 Windows 服务。kubeadm join 执行时会读取 token 和 CA 证书信息,为 kubelet 生成 C:\etc\kubernetes\kubelet.conf 和 C:\var\lib\kubelet\kubeadm-flags.env 等配置文件。为了让 kubelet 以 Windows 服务方式常驻运行,可以使用 sc.exe 创建服务,启动命令中要指定 --windows-service 参数。
手动创建服务时,推荐把二进制路径写成 C:\k\kubelet.exe,并设置启动类型为自动。kube-proxy 服务也需要类似处理,但 kube-proxy 通常依赖 kubeadm 生成的 C:\etc\kubernetes\kube-proxy.conf。为了减少手动配置出错,生产环境建议使用 Kubernetes 社区提供的 PrepareNode.ps1 脚本自动完成下载和服务注册,但理解这些目录和参数对后续排错仍然有帮助。
四、获取 join 令牌并在 Windows 节点执行加入
在 Linux 控制节点上执行 kubeadm token create --print-join-command 可以生成加入命令。直接复制这条命令到 Windows 节点执行通常会失败,因为命令中的 CRI socket 仍是 Linux 默认的 unix:///var/run/containerd/containerd.sock。Windows 节点必须显式追加 --cri-socket "npipe:////./pipe/containerd-containerd" 参数。
kubeadm.exe join 172.16.10.10:6443 ` --token abcdef.0123456789abcdef ` --discovery-token-ca-cert-hash sha256:<cert-hash> ` --cri-socket "npipe:////./pipe/containerd-containerd" ` --node-name win-node-01
代码中的 token 和 cert-hash 需要替换成控制节点实际生成的字符串。PowerShell 换行符使用反引号,如果在 cmd 中执行则使用 ^ 换行。节点名称建议显式指定,避免使用 Windows 主机名时出现 DNS 解析不一致的问题。
加入命令执行完成后,回到控制节点运行 kubectl get nodes。新节点可能先显示 NotReady,这是正常的,因为 kubelet 需要拉取 pause 镜像并初始化网络。几分钟后如果没有变成 Ready,就要到 Windows 节点查看 C:\var\log\kubelet\kubelet.log 或运行 Get-Service kubelet 检查服务状态。日志中如果出现 sandbox image pull failed,基本可以确定是 pause 镜像地址无法访问。
五、配置 CNI 网络和设置 OS 调度标签
Windows 节点加入集群后,还需要确保 CNI 插件支持 Windows 数据面。Calico 是混合集群中比较常见的选择,它的 Windows 版本会以 DaemonSet 形式运行在带 kubernetes.io/os=windows 标签的节点上。需要先在 Linux 控制平面部署 Calico 控制器和 CRD,然后安装 calico-node-windows,并确认 VXLAN 端口 UDP 4789 在节点防火墙中已放行。
如果集群中既有 Linux 节点又有 Windows 节点,一定要给所有工作负载明确声明 OS 标签。否则 Kubernetes 可能把 Linux 容器 Pod 调度到 Windows 节点,导致容器创建失败。下面是一个 Windows Pod 的调度示例:
apiVersion: v1
kind: Pod
metadata:
name: windows-test
spec:
nodeSelector:
kubernetes.io/os: windows
containers:
- name: iis
image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022
对于已有的 Linux Deployment,建议在 spec.template.spec 中加上 nodeSelector: kubernetes.io/os: linux,或使用 nodeAffinity 限制调度范围。这样混合集群的调度行为才可预期。
常见的 NotReady 问题主要集中在三个地方:pause 镜像拉取失败、containerd 服务未启动、CNI 插件没有在 Windows 节点上运行。可以分别用 kubectl describe node、Get-Service containerd 和 kubectl get pods -n kube-system -o wide 来定位。确认节点 Ready 后再部署 Windows 业务 Pod,能减少很多无效等待。
KubernetesWindows Server节点加入修改时间:2026-09-30 16:51:09