在 Kubernetes 中运行 Windows 容器指南

本页提供了一些步骤的演练,您可以按照这些步骤使用 Kubernetes 运行 Windows 容器。本页还重点介绍了 Kubernetes 中一些特定于 Windows 的功能。

需要注意的是,在 Kubernetes 上创建和部署服务和工作负载的方式对于 Linux 和 Windows 容器基本相同。与集群交互的 kubectl 命令 是相同的。本页中的示例旨在帮助您快速开始使用 Windows 容器。

目标

配置一个示例部署,以在 Windows 节点上运行 Windows 容器。

开始之前

您应该已经可以访问一个 Kubernetes 集群,其中包含一个运行 Windows Server 的工作节点。

入门:部署 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
  1. 检查所有节点是否健康

    kubectl get nodes
    
  2. 部署服务并观察 Pod 更新

    kubectl apply -f win-webserver.yaml
    kubectl get pods -o wide -w
    

    当服务正确部署后,两个 Pod 都将标记为就绪。要退出监视命令,请按 Ctrl+C。

  3. 检查部署是否成功。要验证

    • 从 Linux 控制平面节点列出的多个 Pod,使用 kubectl get pods
    • 节点到 Pod 之间的跨网络通信,curl 从 Linux 控制平面节点的 Pod IP 的端口 80 以检查 Web 服务器响应
    • Pod 到 Pod 之间的通信,使用 kubectl exec 在 Pod 之间(如果您有多个 Windows 节点,则跨主机)执行 ping
    • 服务到 Pod 之间的通信,curl 从 Linux 控制平面节点和单个 Pod 中的虚拟服务 IP(在 kubectl get services 中看到)
    • 服务发现,curl 使用 Kubernetes 默认 DNS 后缀 的服务名称
    • 入站连接,curl 从 Linux 控制平面节点或集群外部的机器上的 NodePort
    • 出站连接,使用 kubectl exec 从 Pod 内部 curl 外部 IP

可观察性

从工作负载中捕获日志

日志是可观察性的重要组成部分;它们使用户能够深入了解工作负载的操作方面,并且是解决问题的关键要素。由于 Windows 容器和 Windows 容器中的工作负载的行为与 Linux 容器不同,因此用户很难收集日志,这限制了操作可见性。例如,Windows 工作负载通常配置为记录到 ETW(Windows 事件跟踪)或将条目推送到应用程序事件日志。LogMonitor 是 Microsoft 的一个开源工具,是监视 Windows 容器内配置的日志源的推荐方式。LogMonitor 支持监视事件日志、ETW 提供程序和自定义应用程序日志,并将它们管道传输到 STDOUT,以便 kubectl logs <pod> 使用。

按照 LogMonitor GitHub 页面上的说明将它的二进制文件和配置文件复制到所有容器中,并为 LogMonitor 添加必要的入口点,以将您的日志推送到 STDOUT。

配置容器用户

使用可配置的容器用户名

可以将 Windows 容器配置为使用与镜像默认值不同的用户名运行其入口点和进程。在此处详细了解

使用组托管服务帐户管理工作负载标识

可以将 Windows 容器工作负载配置为使用组托管服务帐户 (GMSA)。组托管服务帐户是一种特定类型的 Active Directory 帐户,它提供自动密码管理、简化的服务主体名称 (SPN) 管理以及将管理委派给多个服务器上的其他管理员的能力。使用 GMSA 配置的容器可以访问外部 Active Directory 域资源,同时携带使用 GMSA 配置的标识。在此处详细了解为 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.31 的 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.31 的最佳实践是使用 nodeSelector

但是,在许多情况下,用户已经拥有大量用于 Linux 容器的现有部署,以及社区 Helm 图表等现成的配置生态系统,以及使用运算符等进行的编程 Pod 生成情况。在这些情况下,您可能不愿意进行配置更改,以将 nodeSelector 字段添加到所有 Pod 和 Pod 模板中。另一种方法是使用污点。由于 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 201910.0.17763
Windows Server 202210.0.20348

使用 RuntimeClass 简化

RuntimeClass 可用于简化使用污点和容忍度的方法。集群管理员可以创建一个 RuntimeClass 对象,用于封装这些污点和容忍度。

  1. 将此文件保存到 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"
    
  2. 以集群管理员身份运行 kubectl create -f runtimeClasses.yml

  3. 根据需要将 runtimeClassName: windows-2019 添加到 Pod 规范

    例如

    ---
    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
    
最后修改时间:2023 年 5 月 24 日下午 10:55 PST:修复 windows 用户指南中的步骤缩进 (#41283) (f0e755caae)