在 Kubernetes 中运行 Windows 容器的指南
此页面提供了一些步骤的演练,你可以按照这些步骤使用 Kubernetes 运行 Windows 容器。 此页面还重点介绍了 Kubernetes 中一些特定于 Windows 的功能。
需要注意的是,在 Kubernetes 上创建和部署服务和工作负载对于 Linux 和 Windows 容器的行为方式基本相同。 与集群交互的 kubectl 命令 是相同的。 此页面中的示例旨在快速启动你使用 Windows 容器的体验。
目标
配置一个示例部署,以便在 Windows 节点上运行 Windows 容器。
开始之前
你应已可以访问包含运行 Windows Server 的工作节点的 Kubernetes 集群。
入门:部署 Windows 工作负载
下面的示例 YAML 文件部署一个在 Windows 容器内运行的简单 Web 服务器应用程序。
创建一个名为 win-webserver.yaml 的清单,其内容如下
---
apiVersion: v1
kind: Service
metadata:
name: win-webserver
labels:
app: win-webserver
spec:
ports:
# the port that this service should serve on
- port: 80
targetPort: 80
selector:
app: win-webserver
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: win-webserver
name: win-webserver
spec:
replicas: 2
selector:
matchLabels:
app: win-webserver
template:
metadata:
labels:
app: win-webserver
name: win-webserver
spec:
containers:
- name: windowswebserver
image: mcr.microsoft.com/windows/servercore:ltsc2019
command:
- powershell.exe
- -command
- "<#code used from https://gist.github.com/19WAS85/5424431#> ; $$listener = New-Object System.Net.HttpListener ; $$listener.Prefixes.Add('http://*:80/') ; $$listener.Start() ; $$callerCounts = @{} ; Write-Host('Listening at http://*:80/') ; while ($$listener.IsListening) { ;$$context = $$listener.GetContext() ;$$requestUrl = $$context.Request.Url ;$$clientIP = $$context.Request.RemoteEndPoint.Address ;$$response = $$context.Response ;Write-Host '' ;Write-Host('> {0}' -f $$requestUrl) ; ;$$count = 1 ;$$k=$$callerCounts.Get_Item($$clientIP) ;if ($$k -ne $$null) { $$count += $$k } ;$$callerCounts.Set_Item($$clientIP, $$count) ;$$ip=(Get-NetAdapter | Get-NetIpAddress); $$header='<html><body><H1>Windows Container Web Server</H1>' ;$$callerCountsString='' ;$$callerCounts.Keys | % { $$callerCountsString+='<p>IP {0} callerCount {1} ' -f $$ip[1].IPAddress,$$callerCounts.Item($$_) } ;$$footer='</body></html>' ;$$content='{0}{1}{2}' -f $$header,$$callerCountsString,$$footer ;Write-Output $$content ;$$buffer = [System.Text.Encoding]::UTF8.GetBytes($$content) ;$$response.ContentLength64 = $$buffer.Length ;$$response.OutputStream.Write($$buffer, 0, $$buffer.Length) ;$$response.Close() ;$$responseStatus = $$response.StatusCode ;Write-Host('< {0}' -f $$responseStatus) } ; "
nodeSelector:
kubernetes.io/os: windows
注意
也支持端口映射,但为简单起见,此示例将容器的 80 端口直接暴露给服务。检查所有节点是否健康
kubectl get nodes部署服务并观察 Pod 更新
kubectl apply -f win-webserver.yaml kubectl get pods -o wide -w当服务正确部署后,两个 Pod 都标记为就绪。 要退出 watch 命令,请按 Ctrl+C。
检查部署是否成功。 要验证
- 从 Linux 控制平面节点列出的几个 Pod,使用
kubectl get pods - 跨网络的节点到 Pod 通信,从 Linux 控制平面节点
curl你 Pod 的 IP 的 80 端口,以检查 Web 服务器响应 - Pod 到 Pod 通信,使用
kubectl exec在 Pod 之间(以及跨主机,如果你有多个 Windows 节点)进行 ping 操作 - 服务到 Pod 通信,从 Linux 控制平面节点和各个 Pod
curl虚拟服务 IP(在kubectl get services下看到) - 服务发现,使用 Kubernetes 默认 DNS 后缀
curl服务名称 - 入站连接,从 Linux 控制平面节点或集群外部的机器
curlNodePort - 出站连接,使用
kubectl exec从 Pod 内部curl外部 IP
- 从 Linux 控制平面节点列出的几个 Pod,使用
注意
由于 Windows 网络堆栈的当前平台限制,Windows 容器主机无法访问在其上调度的服务的 IP。 只有 Windows Pod 能够访问服务 IP。可观测性
从工作负载捕获日志
日志是可观测性的一个重要元素;它们使使用者能够深入了解工作负载的操作方面,并且是解决问题的关键要素。 由于 Windows 容器和 Windows 容器内部的工作负载的行为方式与 Linux 容器不同,因此用户很难收集日志,从而限制了操作可见性。 例如,Windows 工作负载通常配置为记录到 ETW(Windows 事件跟踪),或将条目推送到应用程序事件日志中。 Microsoft 的开源工具 LogMonitor 是监控 Windows 容器内部配置的日志源的推荐方式。 LogMonitor 支持监控事件日志、ETW 提供程序和自定义应用程序日志,将它们通过管道传输到 STDOUT 以供 kubectl logs <pod> 使用。
按照 LogMonitor GitHub 页面中的说明将二进制文件和配置文件复制到所有容器,并添加必要的入口点,以便 LogMonitor 将日志推送到 STDOUT。
配置容器用户
使用可配置的容器用户名
可以将 Windows 容器配置为使用与镜像默认值不同的用户名来运行其入口点和进程。 在 此处了解更多信息。
使用组托管服务帐户管理工作负载标识
可以将 Windows 容器工作负载配置为使用组托管服务帐户 (GMSA)。 组托管服务帐户是一种特定类型的 Active Directory 帐户,提供自动密码管理、简化的服务主体名称 (SPN) 管理以及将管理委派给多台服务器上的其他管理员的能力。 配置有 GMSA 的容器可以使用 GMSA 配置的标识来访问外部 Active Directory 域资源。 在此处 了解有关为 Windows 容器配置和使用 GMSA 的更多信息。
污点和容忍度
用户需要使用 污点 和节点选择器的某种组合,以便将 Linux 和 Windows 工作负载调度到各自特定于操作系统的节点。 建议的方法概述如下,其主要目标之一是此方法不应破坏现有 Linux 工作负载的兼容性。
你可以(并且应该)为每个 Pod 设置 .spec.os.name,以指示该 Pod 中容器设计用于的操作系统。 对于运行 Linux 容器的 Pod,请将 .spec.os.name 设置为 linux。 对于运行 Windows 容器的 Pod,请将 .spec.os.name 设置为 windows。
调度程序在将 Pod 分配给节点时不会使用 .spec.os.name 的值。 你应该使用正常的 Kubernetes 机制来将 Pod 分配给节点,以确保集群的控制平面将 Pod 放置到运行相应操作系统的节点上。
.spec.os.name 值对 Windows Pod 的调度没有影响,因此仍然需要污点和容忍度(或节点选择器)来确保 Windows Pod 落在适当的 Windows 节点上。
确保特定于操作系统的的工作负载落在适当的容器主机上
用户可以使用污点和容忍度来确保 Windows 容器可以调度到适当的主机上。 所有运行 Kubernetes 1.32 的 Kubernetes 节点都具有以下默认标签
- kubernetes.io/os = [windows|linux]
- kubernetes.io/arch = [amd64|arm64|...]
如果 Pod 规范未指定 nodeSelector,例如 "kubernetes.io/os": windows,则 Pod 可能被调度到任何主机上,无论是 Windows 还是 Linux。 这可能会有问题,因为 Windows 容器只能在 Windows 上运行,而 Linux 容器只能在 Linux 上运行。 Kubernetes 1.32 的最佳做法是使用 nodeSelector。
但是,在许多情况下,用户有大量预先存在的 Linux 容器部署,以及现成的配置生态系统,例如社区 Helm Chart 以及编程 Pod 生成案例,例如使用操作器。 在这些情况下,你可能会犹豫是否要进行配置更改,以将 nodeSelector 字段添加到所有 Pod 和 Pod 模板中。 另一种方法是使用污点。 由于 kubelet 可以在注册期间设置污点,因此可以很容易地修改 kubelet 以便仅在 Windows 上运行时自动添加污点。
例如:--register-with-taints='os=windows:NoSchedule'
通过向所有 Windows 节点添加污点,不会在它们上调度任何内容(包括现有的 Linux Pod)。 为了使 Windows Pod 能够调度到 Windows 节点上,它既需要 nodeSelector 又需要适当的匹配容忍度来选择 Windows。
nodeSelector:
kubernetes.io/os: windows
node.kubernetes.io/windows-build: '10.0.17763'
tolerations:
- key: "os"
operator: "Equal"
value: "windows"
effect: "NoSchedule"
在同一集群中处理多个 Windows 版本
每个 Pod 使用的 Windows Server 版本必须与节点版本匹配。 如果你想在同一集群中使用多个 Windows Server 版本,则应设置额外的节点标签和 nodeSelector 字段。
Kubernetes 会自动添加一个标签 node.kubernetes.io/windows-build 以简化此过程。
此标签反映了需要匹配的 Windows 主版本号、次版本号和内部版本号以确保兼容性。以下是每个 Windows Server 版本使用的值
| 产品名称 | 版本 |
|---|---|
| Windows Server 2019 | 10.0.17763 |
| Windows Server 2022 | 10.0.20348 |
使用 RuntimeClass 简化
RuntimeClass 可用于简化使用污点(taints)和容忍(tolerations)的过程。集群管理员可以创建一个 RuntimeClass 对象,用于封装这些污点和容忍。
将此文件保存为
runtimeClasses.yml。它包括适用于 Windows 操作系统、架构和版本的适当nodeSelector。--- apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: name: windows-2019 handler: example-container-runtime-handler scheduling: nodeSelector: kubernetes.io/os: 'windows' kubernetes.io/arch: 'amd64' node.kubernetes.io/windows-build: '10.0.17763' tolerations: - effect: NoSchedule key: os operator: Equal value: "windows"以集群管理员身份运行
kubectl create -f runtimeClasses.yml在 Pod 规约中酌情添加
runtimeClassName: windows-2019例如
--- apiVersion: apps/v1 kind: Deployment metadata: name: iis-2019 labels: app: iis-2019 spec: replicas: 1 template: metadata: name: iis-2019 labels: app: iis-2019 spec: runtimeClassName: windows-2019 containers: - name: iis image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019 resources: limits: cpu: 1 memory: 800Mi requests: cpu: .1 memory: 300Mi ports: - containerPort: 80 selector: matchLabels: app: iis-2019 --- apiVersion: v1 kind: Service metadata: name: iis spec: type: LoadBalancer ports: - protocol: TCP port: 80 selector: app: iis-2019