--- title: Kubernetes 对 Windows 的支持 content_type: concept weight: 65 --- 在很多组织中,其服务和应用的很大比例是 Windows 应用。 [Windows 容器](https://aka.ms/windowscontainers)提供了一种对进程和包依赖关系 进行封装的现代方式,这使得用户更容易采用 DevOps 实践,令 Windows 应用同样遵从 云原生模式。 Kubernetes 已经成为事实上的标准容器编排器,Kubernetes 1.14 发行版本中包含了将 Windows 容器调度到 Kubernetes 集群中 Windows 节点上的生产级支持,从而使得巨大 的 Windows 应用生态圈能够充分利用 Kubernetes 的能力。 对于同时投入基于 Windows 应用和 Linux 应用的组织而言,他们不必寻找不同的编排系统 来管理其工作负载,其跨部署的运维效率得以大幅提升,而不必关心所用操作系统。 ## kubernetes 中的 Windows 容器 {#windows-containers-in-kubernetes} 若要在 Kubernetes 中启用对 Windows 容器的编排,可以在现有的 Linux 集群中 包含 Windows 节点。在 Kubernetes 上调度 {{< glossary_tooltip text="Pods" term_id="pod" >}} 中的 Windows 容器与调用基于 Linux 的容器类似。 为了运行 Windows 容器,你的 Kubernetes 集群必须包含多个操作系统,控制面 节点运行 Linux,工作节点则可以根据负载需要运行 Windows 或 Linux。 Windows Server 2019 是唯一被支持的 Windows 操作系统,在 Windows 上启用 [Kubernetes 节点](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture/architecture.md#the-kubernetes-node) 支持(包括 kubelet, [容器运行时](https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/containerd)、 以及 kube-proxy)。关于 Windows 发行版渠道的详细讨论,可参见 [Microsoft 文档](https://docs.microsoft.com/en-us/windows-server/get-started-19/servicing-channels-19)。 {{< note >}} Kubernetes 控制面,包括[主控组件](/zh/docs/concepts/overview/components/), 继续在 Linux 上运行。 目前没有支持完全是 Windows 节点的 Kubernetes 集群的计划。 {{< /note >}} {{< note >}} 在本文中,当我们讨论 Windows 容器时,我们所指的是具有进程隔离能力的 Windows 容器。具有 [Hyper-V 隔离能力](https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/hyperv-container) 的 Windows 容器计划在将来发行版本中推出。 {{< /note >}} ## 支持的功能与局限性 {#supported-functionality-and-limitations} ### 支持的功能 {#supported-functionality} #### Windows 操作系统版本支持 {#windows-os-version-support} 参考下面的表格,了解 Kubernetes 中支持的 Windows 操作系统。 同一个异构的 Kubernetes 集群中可以同时包含 Windows 和 Linux 工作节点。 Windows 容器仅能调度到 Windows 节点,Linux 容器则只能调度到 Linux 节点。 | Kubernetes 版本 | Windows Server LTSC 版本 | Windows Server SAC 版本 | | --- | --- | --- | --- | | *Kubernetes v1.19* | Windows Server 2019 | Windows Server ver 1909, Windows Server ver 2004 | | *Kubernetes v1.20* | Windows Server 2019 | Windows Server ver 1909, Windows Server ver 2004 | | *Kubernetes v1.21* | Windows Server 2019 | Windows Server ver 2004, Windows Server ver 20H2 | 关于不同的 Windows Server 版本的服务渠道,包括其支持模式等相关信息可以在 [Windows Server servicing channels](https://docs.microsoft.com/en-us/windows-server/get-started-19/servicing-channels-19) 找到。 我们并不指望所有 Windows 客户都为其应用频繁地更新操作系统。 对应用的更新是向集群中引入新代码的根本原因。 对于想要更新运行于 Kubernetes 之上的容器中操作系统的客户,我们会在添加对新 操作系统版本的支持时提供指南和分步的操作指令。 该指南会包含与集群节点一起来升级用户应用的建议升级步骤。 Windows 节点遵从 Kubernetes [版本偏差策略](/zh/docs/setup/release/version-skew-policy/)(节点到控制面的 版本控制),与 Linux 节点的现行策略相同。 Windows Server 主机操作系统会受 [Windows Server](https://www.microsoft.com/en-us/cloud-platform/windows-server-pricing) 授权策略控制。Windows 容器镜像则遵从 [Windows 容器的补充授权条款](https://docs.microsoft.com/en-us/virtualization/windowscontainers/images-eula) 约定。 带进程隔离的 Windows 容器受一些严格的兼容性规则约束, [其中宿主 OS 版本必须与容器基准镜像的 OS 版本相同](https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility)。 一旦我们在 Kubernetes 中支持带 Hyper-V 隔离的 Windows 容器, 这一约束和兼容性规则也会发生改变。 #### Pause 镜像 {#pause-image} Microsoft 在 `mcr.microsoft.com/oss/kubernetes/pause:3.4.1` 处维护 一个 pause 基础设施容器镜像。 #### 计算 {#compute} 从 API 和 kubectl 的角度,Windows 容器的表现在很大程度上与基于 Linux 的容器 是相同的。不过也有一些与关键功能相关的差别值得注意,这些差别列举于 [局限性](#limitations)小节中。 关键性的 Kubernetes 元素在 Windows 下与其在 Linux 下工作方式相同。我们在本节中 讨论一些关键性的负载支撑组件及其在 Windows 中的映射。 * [Pods](/zh/docs/concepts/workloads/pods/) Pod 是 Kubernetes 中最基本的构造模块,是 Kubernetes 对象模型中你可以创建或部署的 最小、最简单元。你不可以在同一 Pod 中部署 Windows 和 Linux 容器。 Pod 中的所有容器都会被调度到同一节点(Node),而每个节点代表的是一种特定的平台 和体系结构。Windows 容器支持 Pod 的以下能力、属性和事件: * 在带进程隔离和卷共享支持的 Pod 中运行一个或多个容器 * Pod 状态字段 * 就绪态(Readiness)和活跃性(Liveness)探针 * postStart 和 preStop 容器生命周期事件 * ConfigMap、Secrets:用作环境变量或卷 * emptyDir 卷 * 从宿主系统挂载命名管道 * 资源限制 * [控制器(Controllers)](/zh/docs/concepts/workloads/controllers/) Kubernetes 控制器处理 Pod 的期望状态。Windows 容器支持以下负载控制器: * ReplicaSet * ReplicationController * Deployment * StatefulSet * DaemonSet * Job * CronJob * [服务(Services)](/zh/docs/concepts/services-networking/service/) Kubernetes Service 是一种抽象对象,用来定义 Pod 的一个逻辑集合及用来访问这些 Pod 的策略。Service 有时也称作微服务(Micro-service)。你可以使用服务来实现 跨操作系统的连接。在 Windows 系统中,服务可以使用下面的类型、属性和能力: * Service 环境变量 * NodePort * ClusterIP * LoadBalancer * ExternalName * 无头(Headless)服务 Pods、控制器和服务是在 Kubernetes 上管理 Windows 负载的关键元素。 不过,在一个动态的云原生环境中,这些元素本身还不足以用来正确管理 Windows 负载的生命周期。我们为此添加了如下功能特性: * Pod 和容器的度量(Metrics) * 对水平 Pod 自动扩展的支持 * 对 kubectl exec 命令的支持 * 资源配额 * 调度器抢占 #### 容器运行时 {#container-runtime} ##### Docker EE {{< feature-state for_k8s_version="v1.14" state="stable" >}} Docker EE-basic 19.03+ 是建议所有 Windows Server 版本采用的容器运行时。 该容器运行时能够与 kubelet 中的 dockershim 代码协同工作。 ##### CRI-ContainerD {{< feature-state for_k8s_version="v1.20" state="stable" >}} {{< glossary_tooltip term_id="containerd" text="ContainerD" >}} 1.4.0+ 也可作为 Windows Kubernetes 节点上的容器运行时。 #### 持久性存储 {#persistent-storage} 使用 Kubernetes [卷](/zh/docs/concepts/storage/volumes/),对数据持久性和 Pod 卷 共享有需求的复杂应用也可以部署到 Kubernetes 上。 管理与特定存储后端或协议相关的持久卷时,相关的操作包括:对卷的配备(Provisioning)、 去配(De-provisioning)和调整大小,将卷挂接到 Kubernetes 节点或从节点上解除挂接, 将卷挂载到需要持久数据的 Pod 中的某容器或从容器上卸载。 负责实现为特定存储后端或协议实现卷管理动作的代码以 Kubernetes 卷 [插件](/zh/docs/concepts/storage/volumes/#types-of-volumes)的形式发布。 Windows 支持以下大类的 Kubernetes 卷插件: ##### 树内卷插件 {#in-tree-volume-plugins} 与树内卷插件(In-Tree Volume Plugin)相关的代码都作为核心 Kubernetes 代码基 的一部分发布。树内卷插件的部署不需要安装额外的脚本,也不需要额外部署独立的 容器化插件组件。这些插件可以处理:对应存储后端上存储卷的配备、去配和尺寸更改, 将卷挂接到 Kubernetes 或从其上解挂,以及将卷挂载到 Pod 中各个容器上或从其上 卸载。以下树内插件支持 Windows 节点: * [awsElasticBlockStore](/zh/docs/concepts/storage/volumes/#awselasticblockstore) * [azureDisk](/zh/docs/concepts/storage/volumes/#azuredisk) * [azureFile](/zh/docs/concepts/storage/volumes/#azurefile) * [gcePersistentDisk](/zh/docs/concepts/storage/volumes/#gcepersistentdisk) * [vsphereVolume](/zh/docs/concepts/storage/volumes/#vspherevolume) ##### FlexVolume 插件 {#flexvolume-plugins} 与 [FlexVolume](/zh/docs/concepts/storage/volumes/#flexVolume) 插件相关的代码是作为 树外(Out-of-tree)脚本或可执行文件来发布的,因此需要在宿主系统上直接部署。 FlexVolume 插件处理将卷挂接到 Kubernetes 节点或从其上解挂、将卷挂载到 Pod 中 各个容器上或从其上卸载等操作。对于与 FlexVolume 插件相关联的持久卷的配备和 去配操作,可以通过外部的配置程序来处理。这类配置程序通常与 FlexVolume 插件 相分离。下面的 FlexVolume [插件](https://github.com/Microsoft/K8s-Storage-Plugins/tree/master/flexvolume/windows) 可以以 PowerShell 脚本的形式部署到宿主系统上,支持 Windows 节点: * [SMB](https://github.com/microsoft/K8s-Storage-Plugins/tree/master/flexvolume/windows/plugins/microsoft.com~smb.cmd) * [iSCSI](https://github.com/microsoft/K8s-Storage-Plugins/tree/master/flexvolume/windows/plugins/microsoft.com~iscsi.cmd) ##### CSI 插件 {#csi-plugins} {{< feature-state for_k8s_version="v1.19" state="beta" >}} 与 {{< glossary_tooltip text="CSI" term_id="csi" >}} 插件相关联的代码作为 树外脚本和可执行文件来发布且通常发布为容器镜像形式,并使用 DaemonSet 和 StatefulSet 这类标准的 Kubernetes 构造体来部署。 CSI 插件处理 Kubernetes 中的很多卷管理操作:对卷的配备、去配和调整大小, 将卷挂接到 Kubernetes 节点或从节点上解除挂接,将卷挂载到需要持久数据的 Pod 中的某容器或从容器上卸载,使用快照和克隆来备份或恢复持久数据。 CSI 插件通常包含节点插件(以 DaemonSet 形式运行于各节点上)和控制器插件。 CSI 节点插件(尤其是那些通过块设备或者共享文件系统形式来提供持久卷的插件) 需要执行很多特权级操作,例如扫描磁盘设备、挂载文件系统等等。 这些操作在不同的宿主操作系统上差别较大。对于 Linux 工作节点而言,容器化的 CSI 节点插件通常部署为特权级的容器。对于 Windows 工作节点而言,容器化的 CSI 节点插件的特权操作通过 [csi-proxy](https://github.com/kubernetes-csi/csi-proxy) 来支持;csi-proxy 是一个社区管理的、独立的可执行文件,需要预安装在每个 Windows 节点之上。请参考你要部署的 CSI 插件的部署指南以进一步了解其细节。 #### 联网 {#networking} Windows 容器的联网是通过 [CNI 插件](/zh/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/) 来暴露出来的。Windows 容器的联网行为与虚拟机的联网行为类似。 每个容器有一块虚拟的网络适配器(vNIC)连接到 Hyper-V 的虚拟交换机(vSwitch)。 宿主的联网服务(Host Networking Service,HNS)和宿主计算服务(Host Compute Service,HCS)协同工作,创建容器并将容器的虚拟网卡连接到网络上。 HCS 负责管理容器,HNS 则负责管理网络资源,例如: * 虚拟网络(包括创建 vSwitch) * 端点(Endpoint)/ vNIC * 名字空间(Namespace) * 策略(报文封装、负载均衡规则、访问控制列表、网络地址转译规则等等) 支持的服务规约类型如下: * NodePort * ClusterIP * LoadBalancer * ExternalName ##### 网络模式 {#network-modes} Windows 支持五种不同的网络驱动/模式:二层桥接(L2bridge)、二层隧道(L2tunnel)、 覆盖网络(Overlay)、透明网络(Transparent)和网络地址转译(NAT)。 在一个包含 Windows 和 Linux 工作节点的异构集群中,你需要选择一种对 Windows 和 Linux 兼容的联网方案。下面是 Windows 上支持的一些树外插件及何时使用某种 CNI 插件的建议:
| 网络驱动 | 描述 | 容器报文更改 | 网络插件 | 网络插件特点 |
|---|---|---|---|---|
| L2bridge | 容器挂接到外部 vSwitch 上。容器挂接到下层网络之上,但由于容器的 MAC 地址在入站和出站时被重写,物理网络不需要这些地址。 | MAC 地址被重写为宿主系统的 MAC 地址,IP 地址也可能依据 HNS OutboundNAT 策略重写为宿主的 IP 地址。 | win-bridge、 Azure-CNI、 Flannel 宿主网关(host-gateway)使用 win-bridge | win-bridge 使用二层桥接(L2bridge)网络模式,将容器连接到下层宿主系统上, 从而提供最佳性能。需要用户定义的路由(User-Defined Routes,UDR)才能 实现节点间的连接。 |
| L2Tunnel | 这是二层桥接的一种特殊情形,但仅被用于 Azure 上。 所有报文都被发送到虚拟化环境中的宿主机上并根据 SDN 策略进行处理。 | MAC 地址被改写,IP 地址在下层网络上可见。 | Azure-CNI | Azure-CNI 使得容器能够与 Azure vNET 集成,并允许容器利用 [Azure 虚拟网络](https://azure.microsoft.com/en-us/services/virtual-network/) 所提供的功能特性集合。例如,可以安全地连接到 Azure 服务上或者使用 Azure NSG。 你可以参考 [azure-cni](https://docs.microsoft.com/en-us/azure/aks/concepts-network#azure-cni-advanced-networking) 所提供的一些示例。 |
| 覆盖网络(Kubernetes 中为 Windows 提供的覆盖网络支持处于 *alpha* 阶段) | 每个容器会获得一个连接到外部 vSwitch 的虚拟网卡(vNIC)。 每个覆盖网络都有自己的、通过定制 IP 前缀来定义的 IP 子网。 覆盖网络驱动使用 VxLAN 封装。 | 封装于外层包头内。 | Win-overlay、 Flannel VXLAN(使用 win-overlay) | 当(比如出于安全原因)期望虚拟容器网络与下层宿主网络隔离时, 应该使用 win-overlay。如果你的数据中心可用 IP 地址受限, 覆盖网络允许你在不同的网络中复用 IP 地址(每个覆盖网络有不同的 VNID 标签)。 这一选项要求在 Windows Server 2009 上安装 [KB4489899](https://support.microsoft.com/help/4489899) 补丁。 |
| 透明网络([ovn-kubernetes](https://github.com/openvswitch/ovn-kubernetes) 的特殊用例) | 需要一个外部 vSwitch。容器挂接到某外部 vSwitch 上,该 vSwitch 通过逻辑网络(逻辑交换机和路由器)允许 Pod 间通信。 |
报文或者通过 [GENEVE](https://datatracker.ietf.org/doc/draft-gross-geneve/) 来封装,
或者通过 [STT](https://datatracker.ietf.org/doc/draft-davie-stt/) 隧道来封装,
以便能够到达不在同一宿主系统上的每个 Pod。 报文通过 OVN 网络控制器所提供的隧道元数据信息来判定是转发还是丢弃。 北-南向通信通过 NAT 网络地址转译来实现。 |
ovn-kubernetes | [通过 Ansible 来部署](https://github.com/openvswitch/ovn-kubernetes/tree/master/contrib)。 所发布的 ACL 可以通过 Kubernetes 策略来应用实施。支持 IPAM 。 负载均衡能力不依赖 kube-proxy。 网络地址转译(NAT)也不需要 iptables 或 netsh。 |
| NAT(未在 Kubernetes 中使用) | 容器获得一个连接到某内部 vSwitch 的 vNIC 接口。 DNS/DHCP 服务通过名为 [WinNAT](https://blogs.technet.microsoft.com/virtualization/2016/05/25/windows-nat-winnat-capabilities-and-limitations/) 的内部组件来提供。 | MAC 地址和 IP 地址都被重写为宿主系统的 MAC 地址和 IP 地址。 | nat | 列在此表中仅出于完整性考虑 |
| 功能特性 | 描述 | 所支持的 Kubernetes 版本 | 所支持的 Windows OS 版本 | 如何启用 |
|---|---|---|---|---|
| 会话亲和性 | 确保来自特定客户的连接每次都被交给同一 Pod。 | v1.20+ | [Windows Server vNext Insider Preview Build 19551](https://blogs.windows.com/windowsexperience/2020/01/28/announcing-windows-server-vnext-insider-preview-build-19551/) 或更高版本 |
将 service.spec.sessionAffinitys 设置为 "ClientIP"
|
| 直接服务器返回(DSR) | 这是一种负载均衡模式,IP 地址的修正和负载均衡地址转译(LBNAT) 直接在容器的 vSwitch 端口上处理;服务流量到达时,其源端 IP 地址 设置为来源 Pod 的 IP。 | v1.20+ | Windows Server 2019 | 为 kube-proxy 设置标志:`--feature-gates="WinDSR=true" --enable-dsr=true` |
| 保留目标地址 | 对服务流量略过 DNAT 步骤,这样就可以在到达后端 Pod 的报文中保留目标服务的 虚拟 IP 地址。还要禁止节点之间的转发。 | v1.20+ | Windows Server 1903 或更高版本 | 在服务注解中设置 `"preserve-destination": "true"` 并启用 kube-proxy 中的 DSR 标志。 |
| IPv4/IPv6 双栈网络 | 在集群内外同时支持原生的 IPv4-到-IPv4 和 IPv6-到-IPv6 通信。 | v1.19+ | Windows Server 2004 或更高版本 | 参见 [IPv4/IPv6 双栈网络](#ipv4ipv6-dual-stack) |
| 保留客户端 IP | 确保入站流量的源 IP 地址被保留。同样要禁止节点之间的转发。 | v1.20+ | Windows Server 2019 或更高版本 |
将 service.spec.externalTrafficPolicy 设置为 "Local",
并在 kube-proxy 上启用 DSR。
|