Kubernetes 对 Windows 的支持

    若要在 Kubernetes 中启用对 Windows 容器的编排,只需在现有的 Linux 集群中 包含 Windows 节点。在 Kubernetes 上调度 中的 Windows 容器与调用基于 Linux 的容器一样简单、一样容易。

    为了运行 Windows 容器,你的 Kubernetes 集群必须包含多个操作系统,控制面 节点运行 Linux,工作节点则可以根据负载需要运行 Windows 或 Linux。 Windows Server 2019 是唯一被支持的 Windows 操作系统,在 Windows 上启用 Kubernetes 节点 支持(包括 kubelet, 、 以及 kube-proxy)。关于 Windows 发行版渠道的详细讨论,可参见 Microsoft 文档

    Windows 操作系统版本支持

    参考下面的表格,了解 Kubernetes 中支持的 Windows 操作系统。 同一个异构的 Kubernetes 集群中可以同时包含 Windows 和 Linux 工作节点。 Windows 容器仅能调度到 Windows 节点,Linux 容器则只能调度到 Linux 节点。

    关于不同的 Windows Server 版本的服务渠道,包括其支持模式等相关信息可以在 找到。

    我们并不指望所有 Windows 客户都为其应用频繁地更新操作系统。 对应用的更新是向集群中引入新代码的根本原因。 对于想要更新运行于 Kubernetes 之上的容器中操作系统的客户,我们会在添加对新 操作系统版本的支持时提供指南和分步的操作指令。 该指南会包含与集群节点一起来升级用户应用的建议升级步骤。 Windows 节点遵从 Kubernetes 版本偏差策略(节点到控制面的 版本控制),与 Linux 节点的现行策略相同。

    Windows Server 主机操作系统会受 授权策略控制。Windows 容器镜像则遵从 Windows 容器的补充授权条款 约定。

    带进程隔离的 Windows 容器受一些严格的兼容性规则约束, 。 一旦我们在 Kubernetes 中支持带 Hyper-V 隔离的 Windows 容器, 这一约束和兼容性规则也会发生改变。

    计算

    从 API 和 kubectl 的角度,Windows 容器的表现在很大程度上与基于 Linux 的容器 是相同的。不过也有一些与关键功能相关的差别值得注意,这些差别列举于 局限性小节中。

    关键性的 Kubernetes 元素在 Windows 下与其在 Linux 下工作方式相同。我们在本节中 讨论一些关键性的负载支撑组件及其在 Windows 中的映射。

    • Pod 是 Kubernetes 中最基本的构造模块,是 Kubernetes 对象模型中你可以创建或部署的 最小、最简单元。你不可以在同一 Pod 中部署 Windows 和 Linux 容器。 Pod 中的所有容器都会被调度到同一节点(Node),而每个节点代表的是一种特定的平台 和体系结构。Windows 容器支持 Pod 的以下能力、属性和事件:

      • 在带进程隔离和卷共享支持的 Pod 中运行一个或多个容器
      • Pod 状态字段
      • 就绪态(Readiness)和活跃性(Liveness)探针
      • postStart 和 preStop 容器生命周期事件
      • ConfigMap、Secrets:用作环境变量或卷
      • emptyDir 卷
      • 从宿主系统挂载命名管道
      • 资源限制
    • 控制器(Controllers)

      Kubernetes 控制器处理 Pod 的期望状态。Windows 容器支持以下负载控制器:

      • ReplicaSet
      • ReplicationController
      • Deployment
      • StatefulSet
      • DaemonSet
      • Job
      • CronJob
    • Kubernetes Service 是一种抽象对象,用来定义 Pod 的一个逻辑集合及用来访问这些 Pod 的策略。Service 有时也称作微服务(Micro-service)。你可以使用服务来实现 跨操作系统的连接。在 Windows 系统中,服务可以使用下面的类型、属性和能力:

      • Service 环境变量
      • NodePort
      • ClusterIP
      • LoadBalancer
      • ExternalName
      • 无头(Headless)服务

    Pods、控制器和服务是在 Kubernetes 上管理 Windows 负载的关键元素。 不过,在一个动态的云原生环境中,这些元素本身还不足以用来正确管理 Windows 负载的生命周期。我们为此添加了如下功能特性:

    • Pod 和容器的度量(Metrics)
    • 对水平 Pod 自动扩展的支持
    • 对 kubectl exec 命令的支持
    • 资源配额
    • 调度器抢占

    容器运行时

    Docker EE

    FEATURE STATE:

    Docker EE-basic 19.03+ 是建议所有 Windows Server 版本采用的容器运行时。 该容器运行时能够与 kubelet 中的 dockershim 代码协同工作。

    CRI-ContainerD

    FEATURE STATE: Kubernetes v1.19 [beta]

    注意: 在 ContainerD 上使用 GMSA 访问 Windows 网络共享资源时,有一个 已知的局限, 需要内核补丁来解决。 你可以在关注 来跟进相关的更新。

    ContainerD 1.4.0-beta.2+ 也可在 Windows Kubernetes 节点上用作容器运行时。

    在 Windows 对 ContainerD 的最初支持是在 Kubernetes v1.18 加入的。 Windows 上 ContainerD 的进展可以在 跟进。

    你可以进一步了解如何在 Windows 上安装 ContainerD.

    持久性存储

    使用 Kubernetes ,对数据持久性和 Pod 卷 共享有需求的复杂应用也可以部署到 Kubernetes 上。 管理与特定存储后端或协议相关的持久卷时,相关的操作包括:对卷的配备(Provisioning)、 去配(De-provisioning)和调整大小,将卷挂接到 Kubernetes 节点或从节点上解除挂接, 将卷挂载到需要持久数据的 Pod 中的某容器或从容器上卸载。 负责实现为特定存储后端或协议实现卷管理动作的代码以 Kubernetes 卷 插件的形式发布。 Windows 支持以下大类的 Kubernetes 卷插件:

    树内卷插件

    与树内卷插件(In-Tree Volume Plugin)相关的代码都作为核心 Kubernetes 代码基 的一部分发布。树内卷插件的部署不需要安装额外的脚本,也不需要额外部署独立的 容器化插件组件。这些插件可以处理:对应存储后端上存储卷的配备、去配和尺寸更改, 将卷挂接到 Kubernetes 或从其上解挂,以及将卷挂载到 Pod 中各个容器上或从其上 卸载。以下树内插件支持 Windows 节点:

    FlexVolume 插件

    FlexVolume 插件相关的代码是作为 树外(Out-of-tree)脚本或可执行文件来发布的,因此需要在宿主系统上直接部署。 FlexVolume 插件处理将卷挂接到 Kubernetes 节点或从其上解挂、将卷挂载到 Pod 中 各个容器上或从其上卸载等操作。对于与 FlexVolume 插件相关联的持久卷的配备和 去配操作,可以通过外部的配置程序来处理。这类配置程序通常与 FlexVolume 插件 相分离。下面的 FlexVolume 可以以 PowerShell 脚本的形式部署到宿主系统上,支持 Windows 节点:

    CSI 插件

    FEATURE STATE: Kubernetes v1.16 [alpha]

    CSI 插件相关联的代码作为 树外脚本和可执行文件来发布且通常发布为容器镜像形式,并使用 DaemonSet 和 StatefulSet 这类标准的 Kubernetes 构造体来部署。 CSI 插件处理 Kubernetes 中的很多卷管理操作:对卷的配备、去配和调整大小, 将卷挂接到 Kubernetes 节点或从节点上解除挂接,将卷挂载到需要持久数据的 Pod 中的某容器或从容器上卸载,使用快照和克隆来备份或恢复持久数据。 CSI 插件通常包含节点插件(以 DaemonSet 形式运行于各节点上)和控制器插件。

    CSI 节点插件(尤其是那些通过块设备或者共享文件系统形式来提供持久卷的插件) 需要执行很多特权级操作,例如扫描磁盘设备、挂载文件系统等等。 这些操作在不同的宿主操作系统上差别较大。对于 Linux 工作节点而言,容器化的 CSI 节点插件通常部署为特权级的容器。对于 Windows 工作节点而言,容器化的 CSI 节点插件的特权操作通过 来支持;csi-proxy 是一个社区管理的、独立的可执行文件,需要预安装在每个 Windows 节点之上。请参考你要部署的 CSI 插件的部署指南以进一步了解其细节。

    联网

    Windows 容器的联网是通过 CNI 插件 来暴露出来的。Windows 容器的联网行为与虚拟机的联网行为类似。 每个容器有一块虚拟的网络适配器(vNIC)连接到 Hyper-V 的虚拟交换机(vSwitch)。 宿主的联网服务(Host Networking Service,HNS)和宿主计算服务(Host Compute Service,HCS)协同工作,创建容器并将容器的虚拟网卡连接到网络上。 HCS 负责管理容器,HNS 则负责管理网络资源,例如:

    • 虚拟网络(包括创建 vSwitch)
    • 端点(Endpoint)/ vNIC
    • 名字空间(Namespace)
    • 策略(报文封装、负载均衡规则、访问控制列表、网络地址转译规则等等)

    支持的服务规约类型如下:

    • NodePort
    • ClusterIP
    • LoadBalancer
    • ExternalName
    网络模式

    Windows 支持五种不同的网络驱动/模式:二层桥接(L2bridge)、二层隧道(L2tunnel)、 覆盖网络(Overlay)、透明网络(Transparent)和网络地址转译(NAT)。 在一个包含 Windows 和 Linux 工作节点的异构集群中,你需要选择一种对 Windows 和 Linux 兼容的联网方案。下面是 Windows 上支持的一些树外插件及何时使用某种 CNI 插件的建议:

    如前所述, CNI meta 插件 在 Windows 上也是 的,方法是通过 VXLAN 网络后端alpha 阶段 :委托给 win-overlay)和 (稳定版本;委托给 win-bridge 实现)。 此插件支持将操作委托给所引用的 CNI 插件(win-overlay、win-bridge)之一, 从而能够与 Windows 上的 Flannel 守护进程(Flanneld)一同工作,自动为节点 分配子网租期,创建 HNS 网络。 该插件读入其自身的配置文件(cni.conf),并将其与 FlannelD 所生成的 subnet.env 文件中的环境变量整合,之后将其操作委托给所引用的 CNI 插件之一以完成网络发现, 并将包含节点所被分配的子网信息的正确配置发送给 IPAM 插件(例如 host-local)。

    对于节点、Pod 和服务对象,可针对 TCP/UDP 流量支持以下网络数据流:

    • Pod -> Pod (IP 寻址)
    • Pod -> Pod (名字寻址)
    • Pod -> 服务(集群 IP)
    • Pod -> 服务(部分限定域名,仅适用于名称中不包含“.”的情形)
    • Pod -> 服务(全限定域名)
    • Pod -> 集群外部(IP 寻址)
    • Pod -> 集群外部(DNS 寻址)
    • Pod -> 节点
    IP 地址管理(IPAM)

    Windows 上支持以下 IPAM 选项:

    • host-local
    • HNS IPAM (Inbox 平台 IPAM,未指定 IPAM 时的默认设置)
    • (仅适用于 azure-cni )
    负载均衡与服务

    在 Windows 系统上,你可以使用以下配置来设定服务和负载均衡行为:

    IPv4/IPv6 双栈支持

    你可以通过使用 IPv6DualStack 特性门控 来为 l2bridge 网络启用 IPv4/IPv6 双栈联网支持。 进一步的细节可参见。

    对 Windows 而言,在 Kubernetes 中使用 IPv6 需要 Windows Server vNext Insider Preview Build 19603 或更高版本。

    目前 Windows 上的覆盖网络(VXLAN)还不支持双协议栈联网。

    局限性

    控制面

    在 Kubernetes 架构和节点阵列中仅支持将 Windows 作为工作节点使用。 这意味着 Kubernetes 集群必须总是包含 Linux 主控节点,零个或者多个 Linux 工作节点以及零个或者多个 Windows 工作节点。

    计算

    资源管理与进程隔离

    Linux 上使用 Linux 控制组(CGroups)作为 Pod 的边界,以实现资源控制。 容器都创建于这一边界之内,从而实现网络、进程和文件系统的隔离。 控制组 CGroups API 可用来收集 CPU、I/O 和内存的统计信息。 与此相比,Windows 为每个容器创建一个带有系统名字空间过滤设置的 Job 对象, 以容纳容器中的所有进程并提供其与宿主系统间的逻辑隔离。 没有现成的名字空间过滤设置是无法运行 Windows 容器的。 这也意味着,系统特权无法在宿主环境中评估,因而 Windows 上也就不存在特权容器。 归咎于独立存在的安全账号管理器(Security Account Manager,SAM),容器也不能 获得宿主系统上的任何身份标识。

    操作系统限制
    功能特性限制
    • 终止宽限期(Termination Grace Period):未实现
    • 单文件映射:将用 CRI-ContainerD 来实现
    • 终止消息(Termination message):将用 CRI-ContainerD 来实现
    • 特权容器:Windows 容器当前不支持
    • 巨页(Huge Pages):Windows 容器当前不支持
    • 现有的节点问题探测器(Node Problem Detector)仅适用于 Linux,且要求使用特权容器。 一般而言,我们不设想此探测器能用于 Windows 节点,因为 Windows 不支持特权容器。
    • 并非支持共享名字空间的所有功能特性(参见 API 节以了解详细信息)
    内存预留与处理

    Windows 不像 Linux 一样有一个内存耗尽(Out-of-memory)进程杀手(Process Killer)机制。Windows 总是将用户态的内存分配视为虚拟请求,页面文件(Pagefile) 是必需的。这一差异的直接结果是 Windows 不会像 Linux 那样出现内存耗尽的状况, 系统会将进程内存页面写入磁盘而不会因内存耗尽而终止进程。 当内存被过量使用且所有物理内存都被用光时,系统的换页行为会导致性能下降。

    通过一个两步的过程是有可能将内存用量限制在一个合理的范围的。 首先,使用 kubelet 参数 --kubelet-reserve 与/或 --system-reserve 来划分节点上的内存用量(各容器之外)。 这样做会减少节点可分配内存 (NodeAllocatable)。 在你部署工作负载时,对容器使用资源限制(必须仅设置 limits 或者让 limits 等于 requests 值)。这也会从 NodeAllocatable 中耗掉部分内存量,从而避免在节点 负荷已满时调度器继续向节点添加 Pods。

    避免过量分配的最佳实践是为 kubelet 配置至少 2 GB 的系统预留内存,以供 Windows、Docker 和 Kubernetes 进程使用。

    参数的不同行为描述如下:

    • --kubelet-reserve--system-reserve--eviction-hard 标志会更新节点可分配内存量
    • 未实现通过使用 --enforce-node-allocable 来完成的 Pod 驱逐
    • 未实现通过使用 --eviction-hard--eviction-soft 来完成的 Pod 驱逐
    • MemoryPressure 状况未实现
    • kubelet 不会采取措施来执行基于 OOM 的驱逐动作
    • Windows 节点上运行的 kubelet 没有内存约束。 --kubelet-reserve--system-reserve 不会为 kubelet 或宿主系统上运行 的进程设限。这意味着 kubelet 或宿主系统上的进程可能导致内存资源紧张, 而这一情况既不受节点可分配量影响,也不会被调度器感知。

    存储

    Windows 上包含一个分层的文件系统来挂载容器的分层,并会基于 NTFS 来创建一个 拷贝文件系统。容器中的所有文件路径都仅在该容器的上下文内完成解析。

    • 卷挂载仅可针对容器中的目录进行,不可针对独立的文件
    • 卷挂载无法将文件或目录投射回宿主文件系统
    • 不支持只读文件系统,因为 Windows 注册表和 SAM 数据库总是需要写访问权限。 不过,Windows 支持只读的卷。
    • 不支持卷的用户掩码和访问许可,因为宿主与容器之间并不共享 SAM,二者之间不存在 映射关系。所有访问许可都是在容器上下文中解析的。

    因此,Windows 节点上不支持以下存储功能:

    • 卷的子路径挂载;只能在 Windows 容器上挂载整个卷。
    • 为 Secret 执行子路径挂载
    • 宿主挂载投射
    • 默认访问模式(因为该特性依赖 UID/GID)
    • 只读的根文件系统;映射的卷仍然支持 readOnly
    • 块设备映射
    • 将内存作为存储介质
    • 类似 UUID/GUID、每用户不同的 Linux 文件系统访问许可等文件系统特性
    • 基于 NFS 的存储和卷支持
    • 扩充已挂载卷(resizefs)

    联网

    Windows 容器联网与 Linux 联网有着非常重要的差别。 中包含额外的细节和背景信息。

    Windows 宿主联网服务和虚拟交换机实现了名字空间隔离,可以根据需要为 Pod 或容器 创建虚拟的网络接口(NICs)。不过,很多类似 DNS、路由、度量值之类的配置数据都 保存在 Windows 注册表数据库中而不是像 Linux 一样保存在 /etc/... 文件中。 Windows 为容器提供的注册表与宿主系统的注册表是分离的,因此类似于将 /etc/resolv.conf 文件从宿主系统映射到容器中的做法不会产生与 Linux 系统相同的效果。 这些信息必须在容器内部使用 Windows API 来配置。 因此,CNI 实现需要调用 HNS,而不是依赖文件映射来将网络细节传递到 Pod 或容器中。

    Windows 节点不支持以下联网功能:

    • Windows Pod 不能使用宿主网络模式
    • 从节点本地访问 NodePort 会失败(但从其他节点或外部客户端可访问)
    • Windows Server 的未来版本中会支持从节点访问服务的 VIPs
    • kube-proxy 的覆盖网络支持是 Alpha 特性。此外,它要求在 Windows Server 2019 上安装 KB4482887 补丁
    • 本地流量策略和 DSR(保留目标地址)模式
    • 连接到 l2bridge、l2tunnel 或覆盖网络的 Windows 容器不支持使用 IPv6 协议栈通信。 要使得这些网络驱动能够支持 IPv6 地址需要在 Windows 平台上开展大量的工作, 还需要在 Kubernetes 侧修改 kubelet、kube-proxy 以及 CNI 插件。
    • 通过 win-overlay、win-bridge 和 Azure-CNI 插件使用 ICMP 协议向集群外通信。 尤其是,Windows 数据面() 不支持转换 ICMP 报文。这意味着:
      • 指向同一网络内目标地址的 ICMP 报文(例如 Pod 之间的 ping 通信)是可以工作的,没有局限性
      • TCP/UDP 报文可以正常工作,没有局限性
      • 指向远程网络的 ICMP 报文(例如,从 Pod 中 ping 外部互联网的通信)无法被转换, 因此也无法被路由回到其源点。
      • 由于 TCP/UDP 包仍可被转换,用户可以将 ping <目标> 操作替换为 curl <目标> 以便能够调试与外部世界的网络连接。

    Kubernetes v1.15 中添加了以下功能特性:

    • kubectl port-forward
    CNI 插件
    • Windows 参考网络插件 win-bridge 和 win-overlay 当前未实现 CNI spec v0.4.0, 原因是缺少检查用(CHECK)的实现。

    • Windows 上的 Flannel VXLAN CNI 有以下局限性:

      1. 其设计上不支持从节点到 Pod 的连接。 只有在 Flannel v0.12.0 或更高版本后才有可能访问本地 Pods。
      2. 我们被限制只能使用 VNI 4096 和 UDP 端口 4789。 VNI 的限制正在被解决,会在将来的版本中消失(开源的 Flannel 更改)。 参见官方的 后端文档以了解关于这些参数的详细信息。
    DNS
    • 不支持 DNS 的 ClusterFirstWithHostNet 配置。Windows 将所有包含 “.” 的名字 视为全限定域名(FQDN),因而不会对其执行部分限定域名(PQDN)解析。
    • 在 Linux 上,你可以有一个 DNS 后缀列表供解析部分限定域名时使用。 在 Windows 上,我们只有一个 DNS 后缀,即与该 Pod 名字空间相关联的 DNS 后缀(例如 mydns.svc.cluster.local)。 Windows 可以解析全限定域名、或者恰好可用该后缀来解析的服务名称。 例如,在 default 名字空间中生成的 Pod 会获得 DNS 后缀 default.svc.cluster.local。在 Windows Pod 中,你可以解析 kubernetes.default.svc.cluster.localkubernetes,但无法解析二者 之间的形式,如 kubernetes.defaultkubernetes.default.svc
    • 在 Windows 上,可以使用的 DNS 解析程序有很多。由于这些解析程序彼此之间 会有轻微的行为差别,建议使用 Resolve-DNSName 工具来完成名字查询解析。
    IPv6

    Windows 上的 Kubernetes 不支持单协议栈的“只用 IPv6”联网选项。 不过,系统支持在 IPv4/IPv6 双协议栈的 Pod 和节点上运行单协议家族的服务。 更多细节可参阅 IPv4/IPv6 双协议栈联网一节。

    会话亲和性

    不支持使用 service.spec.sessionAffinityConfig.clientIP.timeoutSeconds 来为 Windows 服务设置最大会话粘滞时间。

    安全性

    Secret 以明文形式写入节点的卷中(而不是像 Linux 那样写入内存或 tmpfs 中)。 这意味着客户必须做以下两件事:

    1. 使用文件访问控制列表来保护 Secret 文件所在的位置
    2. 使用 来执行卷层面的加密

    Windows 上目前不支持 RunAsUser。 一种替代方案是在为容器打包时创建本地账号。 将来的版本中可能会添加对 RunAsUser 的支持。

    不支持特定于 Linux 的 Pod 安全上下文特权,例如 SELinux、AppArmor、Seccomp、 权能字(POSIX 权能字)等等。

    此外,如前所述,Windows 不支持特权容器。

    API

    对 Windows 而言,大多数 Kubernetes API 的工作方式没有变化。 一些不易察觉的差别通常体现在 OS 和容器运行时上的不同。 在某些场合,负载 API (如 Pod 或 Container)的某些属性在设计时假定其 在 Linux 上实现,因此会无法在 Windows 上运行。

    在较高层面,不同的 OS 概念有:

    • 身份标识 - Linux 使用证书类型来表示用户 ID(UID)和组 ID(GID)。用户和组名 没有特定标准,它们仅是 /etc/groups/etc/passwd 中的别名表项,会映射回 UID+GID。Windows 使用一个更大的二进制安全标识符(SID),保存在 Windows 安全访问管理器(Security Access Manager,SAM)数据库中。此数据库并不在宿主系统 与容器间,或者任意两个容器之间共享。
    • 文件许可 - Windows 使用基于 SID 的访问控制列表,而不是基于 UID+GID 的访问权限位掩码。
    • 文件路径 - Windows 上的习惯是使用 \ 而非 /。Go 语言的 IO 库通常能够同时接受二者, 并做出正确判断。不过当你在指定要在容器内解析的路径或命令行时,可能需要使用 \
    • 信号 - Windows 交互式应用以不同方式来处理终止事件,并可实现以下方式之一或组合:
      • UI 线程处理包含 WM_CLOSE 在内的良定的消息
      • 控制台应用使用控制处理程序来处理 Ctrl-C 或 Ctrl-Break
      • 服务会注册服务控制处理程序,接受 SERVICE_CONTROL_STOP 控制代码

    退出代码遵从相同的习惯,0 表示成功,非 0 值表示失败。 特定的错误代码在 Windows 和 Linux 上可能会不同。不过,从 Kubernetes 组件 (kubelet、kube-proxy)所返回的退出代码是没有变化的。

    V1.Container
    • v1.Container.ResourceRequirements.limits.cpuv1.Container.ResourceRequirements.limits.memory - Windows 不对 CPU 分配设置硬性的限制。与之相反,Windows 使用一个份额(share)系统。 基于毫核(millicores)的现有字段值会被缩放为相对的份额值,供 Windows 调度器使用。 参见 和 Microsoft 文档中关于资源控制的部分

      • Windows 容器运行时中没有实现巨页支持,因此相关特性不可用。 巨页支持需要 而这一特性无法在容器级别配置。
    • v1.Container.ResourceRequirements.requests.cpuv1.Container.ResourceRequirements.requests.memory - 请求 值会从节点可分配资源中扣除,从而可用来避免节点上的资源过量分配。 但是,它们无法用来在一个已经过量分配的节点上提供资源保障。 如果操作员希望彻底避免过量分配,作为最佳实践,他们就需要为所有容器设置资源请求值。

    • v1.Container.SecurityContext.allowPrivilegeEscalation - 在 Windows 上无法实现,对应的权能 无一可在 Windows 上生效。

    • v1.Container.SecurityContext.Capabilities - Windows 上未实现 POSIX 权能机制

    • v1.Container.SecurityContext.privileged - Windows 不支持特权容器

    • v1.Container.SecurityContext.procMount - Windows 不包含 /proc 文件系统

    • v1.Container.SecurityContext.readOnlyRootFilesystem - 在 Windows 上无法实现, 要在容器内使用注册表或运行系统进程就必需写访问权限。

    • v1.Container.SecurityContext.runAsGroup - 在 Windows 上无法实现,没有 GID 支持

    • v1.Container.SecurityContext.runAsNonRoot - Windows 上没有 root 用户。 与之最接近的等价用户是 ContainerAdministrator,而该身份标识在节点上并不存在。

    • v1.Container.SecurityContext.runAsUser - 在 Windows 上无法实现,因为没有作为整数支持的 GID。

    • v1.Container.SecurityContext.seLinuxOptions - 在 Windows 上无法实现,因为没有 SELinux

    • V1.Container.terminationMessagePath - 因为 Windows 不支持单个文件的映射,这一功能 在 Windows 上也受限。默认值 /dev/termination-log 在 Windows 上也无法使用因为 对应路径在 Windows 上不存在。

    V1.Pod
    • v1.Pod.hostIPCv1.Pod.hostPID - Windows 不支持共享宿主系统的名字空间
    • v1.Pod.hostNetwork - Windows 操作系统不支持共享宿主网络
    • v1.Pod.dnsPolicy - 不支持 ,因为 Windows 不支持宿主网络
    • v1.Pod.podSecurityContext - 参见下面的 v1.PodSecurityContext
    • v1.Pod.shareProcessNamespace - 此为 Beta 特性且依赖于 Windows 上未实现的 Linux 名字空间。Windows 无法共享进程名字空间或者容器的根文件系统。只能共享网络。
    • v1.Pod.terminationGracePeriodSeconds - 这一特性未在 Windows 版本的 Docker 中完全实现。 参见问题报告。 目前实现的行为是向 ENTRYPOINT 进程发送 CTRL_SHUTDOWN_EVENT 时间,之后 Windows 默认 等待 5 秒钟,并最终使用正常的 Windows 关机行为关闭所有进程。 这里的 5 秒钟默认值实际上保存在 的 Windows 注册表中,因此可以在构造容器时重载。
    • v1.Pod.volumeDevices - 此为 Beta 特性且未在 Windows 上实现。Windows 无法挂接 原生的块设备到 Pod 中。
    • v1.Pod.volumes - emptyDirsecretconfigMaphostPath 都可正常工作且在 TestGrid 中测试。
      • v1.emptyDir.volumeSource - Windows 上节点的默认介质是磁盘。不支持将内存作为介质, 因为 Windows 不支持内置的 RAM 磁盘。
    • v1.VolumeMount.mountPropagation - Windows 上不支持挂载传播。
    V1.PodSecurityContext

    PodSecurityContext 的所有选项在 Windows 上都无法工作。这些选项列在下面仅供参考。

    • v1.PodSecurityContext.seLinuxOptions - Windows 上无 SELinux
    • v1.PodSecurityContext.runAsUser - 提供 UID;Windows 不支持
    • v1.PodSecurityContext.runAsGroup - 提供 GID;Windows 不支持
    • v1.PodSecurityContext.runAsNonRoot - Windows 上没有 root 用户 最接近的等价账号是 ContainerAdministrator,而该身份标识在节点上不存在
    • v1.PodSecurityContext.supplementalGroups - 提供 GID;Windows 不支持
    • v1.PodSecurityContext.sysctls - 这些是 Linux sysctl 接口的一部分;Windows 上 没有等价机制。

    对你的 Kubernetes 集群进行排查的主要帮助信息来源应该是 这份文档。 该文档中包含了一些额外的、特定于 Windows 系统的故障排查帮助信息。 Kubernetes 中日志是故障排查的一个重要元素。确保你在尝试从其他贡献者那里获得 故障排查帮助时提供日志信息。 你可以按照 SIG-Windows 所给的指令来操作。

    1. 我怎样知道 start.ps1 是否已成功完成?

      你应该能看到节点上运行的 kubelet、kube-proxy 和(如果你选择 Flannel 作为联网方案)flanneld 宿主代理进程,它们的运行日志显示在不同的 PowerShell 窗口中。此外,你的 Windows 节点应该在你的 Kubernetes 集群 列举为 “Ready” 节点。

    2. 我可以将 Kubernetes 节点进程配置为服务运行在后台么?

      kubelet 和 kube-proxy 都已经被配置为以本地 Windows 服务运行, 并且在出现失效事件(例如进程意外结束)时通过自动重启服务来提供一定的弹性。 你有两种办法将这些节点组件配置为服务。

      1. 以本地 Windows 服务的形式

        Kubelet 和 kube-proxy 可以用 sc.exe 以本地 Windows 服务的形式运行:

      1. 使用 nssm.exe

        你也总是可以使用替代的服务管理器,例如nssm.exe,来为你在后台运行 这些进程(flanneldkubeletkube-proxy)。你可以使用这一 , 利用 nssm.exekubeletkube-proxyflanneld.exe 注册为要在后台运行的 Windows 服务。

        1. register-svc.ps1 -NetworkMode <网络模式> -ManagementIP <Windows 节点 IP> -ClusterCIDR <集群子网> -KubeDnsServiceIP <kube-dns 服务 IP> -LogDir <日志目录>
        2. # NetworkMode = 网络模式 l2bridge(flannel host-gw,也是默认值)或 overlay(flannel vxlan)选做网络方案
        3. # ManagementIP = 分配给 Windows 节点的 IP 地址。你可以使用 ipconfig 得到此值
        4. # ClusterCIDR = 集群子网范围(默认值为 10.244.0.0/16)
        5. # KubeDnsServiceIP = Kubernetes DNS 服务 IP(默认值为 10.96.0.10)
        6. # LogDir = kubelet 和 kube-proxy 的日志会被重定向到这一目录中的对应输出文件,默认值为 `C:\k`。
        1. # 注册 flanneld.exe
        2. nssm install flanneld C:\flannel\flanneld.exe
        3. nssm set flanneld AppParameters --kubeconfig-file=c:\k\config --iface=<ManagementIP> --ip-masq=1 --kube-subnet-mgr=1
        4. nssm set flanneld AppEnvironmentExtra NODE_NAME=<主机名>
        5. nssm set flanneld AppDirectory C:\flannel
        6. nssm start flanneld
        7. # 注册 kubelet.exe
        8. # Microsoft 在 mcr.microsoft.com/k8s/core/pause:1.2.0 发布其 pause 基础设施容器
        9. nssm install kubelet C:\k\kubelet.exe
        10. nssm set kubelet AppParameters --hostname-override=<hostname> --v=6 --pod-infra-container-image=mcr.microsoft.com/k8s/core/pause:1.2.0 --resolv-conf="" --allow-privileged=true --enable-debugging-handlers --cluster-dns=<DNS 服务 IP> --cluster-domain=cluster.local --kubeconfig=c:\k\config --hairpin-mode=promiscuous-bridge --image-pull-progress-deadline=20m --cgroups-per-qos=false --log-dir=<log directory> --logtostderr=false --enforce-node-allocatable="" --network-plugin=cni --cni-bin-dir=c:\k\cni --cni-conf-dir=c:\k\cni\config
        11. nssm set kubelet AppDirectory C:\k
        12. nssm start kubelet
        13. # 注册 kube-proxy.exe (l2bridge / host-gw)
        14. nssm install kube-proxy C:\k\kube-proxy.exe
        15. nssm set kube-proxy AppDirectory c:\k
        16. nssm set kube-proxy AppParameters --v=4 --proxy-mode=kernelspace --hostname-override=<主机名>--kubeconfig=c:\k\config --enable-dsr=false --log-dir=<日志目录> --logtostderr=false
        17. nssm.exe set kube-proxy AppEnvironmentExtra KUBE_NETWORK=cbr0
        18. nssm set kube-proxy DependOnService kubelet
        19. nssm start kube-proxy
        20. # 注册 kube-proxy.exe (overlay / vxlan)
        21. nssm install kube-proxy C:\k\kube-proxy.exe
        22. nssm set kube-proxy AppParameters --v=4 --proxy-mode=kernelspace --feature-gates="WinOverlay=true" --hostname-override=<主机名> --kubeconfig=c:\k\config --network-name=vxlan0 --source-vip=<源端 VIP> --enable-dsr=false --log-dir=<日志目录> --logtostderr=false
        23. nssm set kube-proxy DependOnService kubelet
        24. nssm start kube-proxy

        作为初始的故障排查操作,你可以使用在 nssm.exe 中使用下面的标志 以便将标准输出和标准错误输出重定向到一个输出文件:

        1. nssm set <服务名称> AppStdout C:\k\mysvc.log
        2. nssm set <服务名称> AppStderr C:\k\mysvc.log

        要了解更多的细节,可参见官方的 文档。

    3. 我的 Windows Pods 无发连接网络

      如果你在使用虚拟机,请确保 VM 网络适配器均已开启 MAC 侦听(Spoofing)。

    4. 我的 Windows Pods 无法 ping 外部资源

      Windows Pods 目前没有为 ICMP 协议提供出站规则。不过 TCP/UDP 是支持的。 尝试与集群外资源连接时,可以将 ping <IP> 命令替换为对应的 curl <IP> 命令。

      如果你还遇到问题,很可能你在 cni.conf 中的网络配置值得额外的注意。你总是可以编辑这一静态文件。 配置的更新会应用到所有新创建的 Kubernetes 资源上。

      Kubernetes 网络的需求之一(参见) 是集群内部无需网络地址转译(NAT)即可实现通信。为了符合这一要求,对所有我们不希望出站时发生 NAT 的通信都存在一个 ExceptionList。 然而这也意味着你需要将你要查询的外部 IP 从 ExceptionList 中移除。 只有这时,从你的 Windows Pod 发起的网络请求才会被正确地通过 SNAT 转换以接收到 来自外部世界的响应。 就此而言,你在 cni.conf 中的 ExceptionList 应该看起来像这样:

    5. 我的 Windows 节点无法访问 NodePort 服务

      从节点自身发起的本地 NodePort 请求会失败。这是一个已知的局限。 NodePort 服务的访问从其他节点或者外部客户端都可正常进行。

    6. 容器的 vNICs 和 HNS 端点被删除了

      这一问题可能因为 hostname-override 参数未能传递给 而导致。 解决这一问题时,用户需要按如下方式将主机名传递给 kube-proxy:

      1. C:\k\kube-proxy.exe --hostname-override=$(hostname)
    7. 使用 Flannel 时,我的节点在重新加入集群时遇到问题

      无论何时,当一个之前被删除的节点被重新添加到集群时,flannelD 都会将为节点分配 一个新的 Pod 子网。 用户需要将将下面路径中的老的 Pod 子网配置文件删除:

      1. Remove-Item C:\k\SourceVip.json
      2. Remove-Item C:\k\SourceVipRequest.json
    8. 在启动了 start.ps1 之后,flanneld 一直停滞在 “Waiting for the Network to be created” 状态

      关于这一正在被分析的问题有很多的报告; 最可能的一种原因是关于何时设置 Flannel 网络的管理 IP 的时间问题。 一种解决办法是重新启动 start.ps1 或者按如下方式手动重启之:

      1. PS C:> [Environment]::SetEnvironmentVariable("NODE_NAME", "<Windows 工作节点主机名>")
      2. PS C:> C:\flannel\flanneld.exe --kubeconfig-file=c:\k\config --iface=<Windows 工作节点 IP> --ip-masq=1 --kube-subnet-mgr=1
    9. 我的 Windows Pods 无法启动,因为缺少 /run/flannel/subnet.env 文件

      这表明 Flannel 网络未能正确启动。你可以尝试重启 flanneld.exe 或者将文件手动地 从 Kubernetes 主控节点的 /run/flannel/subnet.env 路径复制到 Windows 工作 节点的 C:\run\flannel\subnet.env 路径,并将 FLANNEL_SUBNET 行改为一个 不同的数值。例如,如果期望节点子网为 10.244.4.1/24

    10. 我的 Windows 节点无法使用服务 IP 访问我的服务

      这是 Windows 上当前网络协议栈的一个已知的限制。 Windows Pods 能够访问服务 IP。

    11. 启动 kubelet 时找不到网络适配器

      Windows 网络堆栈需要一个虚拟的适配器,这样 Kubernetes 网络才能工作。 如果下面的命令(在管理员 Shell 中)没有任何返回结果,证明虚拟网络创建 (kubelet 正常工作的必要前提之一)失败了:

      1. Get-HnsNetwork | ? Name -ieq "cbr0"
      2. Get-NetAdapter | ? Name -Like "vEthernet (Ethernet*"

      当宿主系统的网络适配器名称不是 “Ethernet” 时,通常值得更改 start.ps1 脚本中的 参数来重试。否则可以查验 start-kubelet.ps1 的输出,看看是否在虚拟网络创建 过程中报告了其他错误。

    12. 我的 Pods 停滞在 “Container Creating” 状态或者反复重启

      检查你的 pause 镜像是与你的 OS 版本兼容的。 这里的指令 假定你的 OS 和容器版本都是 1803。如果你安装的是更新版本的 Windows,比如说 某个 Insider 构造版本,你需要相应地调整要使用的镜像。 请参照 Microsoft 的 了解镜像。不管怎样,pause 镜像的 Dockerfile 和示例服务都期望镜像的标签 为 :latest

      从 Kubernetes v1.14 版本起,Microsoft 开始在 mcr.microsoft.com/k8s/core/pause:1.2.0 发布其 pause 基础设施容器。

    13. DNS 解析无法正常工作

      参阅 Windows 上 DNS 相关的局限 节。

    14. kubectl port-forward 失败,错误信息为 “unable to do port forwarding: wincat not found”

      此功能是在 Kubernetes v1.15 中实现的,pause 基础设施容器为 mcr.microsoft.com/k8s/core/pause:1.2.0。 请确保你使用的是这些版本或者更新版本。 如果你想要自行构造你自己的 pause 基础设施容器,要确保其中包含了

    15. 我的 Kubernetes 安装失败,因为我的 Windows Server 节点在防火墙后面

      如果你处于防火墙之后,那么必须定义如下 PowerShell 环境变量:

      ```

    1. [Environment]::SetEnvironmentVariable("HTTP_PROXY", "http://proxy.example.com:80/", [EnvironmentVariableTarget]::Machine)
    2. [Environment]::SetEnvironmentVariable("HTTPS_PROXY", "http://proxy.example.com:443/", [EnvironmentVariableTarget]::Machine)
    3. ```
    1. pause 容器是什么?

      在一个 Kubernetes Pod 中,一个基础设施容器,或称 “pause” 容器,会被首先创建出来, 用以托管容器端点。属于同一 Pod 的容器,包括基础设施容器和工作容器,会共享相同的 网络名字空间和端点(相同的 IP 和端口空间)。我们需要 pause 容器来工作容器崩溃或 重启的状况,以确保不会丢失任何网络配置。

      “pause” (基础设施)镜像托管在 Microsoft Container Registry (MCR) 上。 你可以使用 docker pull mcr.microsoft.com/k8s/core/pause:1.2.0 来访问它。 要了解进一步的细节,可参阅 DOCKERFILE

    如果以上步骤未能解决你遇到的问题,你可以通过以下方式获得在 Kubernetes 中的 Windows 节点上运行 Windows 容器的帮助:

    如果你遇到看起来像是软件缺陷的问题,或者你想要提起某种功能需求,请使用 GitHub 问题跟踪系统。 你可以在 上发起 Issue 并将其指派给 SIG-Windows。你应该首先搜索 Issue 列表,看看是否 该 Issue 以前曾经被报告过,以评论形式将你在该 Issue 上的体验追加进去,并附上 额外的日志信息。SIG-Windows Slack 频道也是一个获得初步支持的好渠道,可以在 生成新的 Ticket 之前对一些想法进行故障分析。

    在登记软件缺陷时,请给出如何重现该问题的详细信息,例如:

    • Kubernetes 版本:kubectl 版本
    • 环境细节:云平台、OS 版本、网络选型和配置情况以及 Docker 版本
    • 重现该问题的详细步骤
    • 相关的日志
    • 通过为该 Issue 添加 /sig windows 评论为其添加 sig/windows 标签, 进而引起 SIG-Windows 成员的注意。

    在我们的未来蓝图中包含很多功能特性(要实现)。下面是一个浓缩的简要列表,不过我们 鼓励你查看我们的 并 通过贡献的方式 帮助我们把 Windows 支持做得更好。

    Hyper-V 隔离

    要满足 Kubernetes 中 Windows 容器的如下用例,需要利用 Hyper-V 隔离:

    • 在 Pod 之间实施基于监管程序(Hypervisor)的隔离,以增强安全性
    • 出于向后兼容需要,允许添加运行新 Windows Server 版本的节点时不必重新创建容器
    • 为 Pod 设置特定的 CPU/NUMA 配置
    • 实施内存隔离与预留

    现有的 Hyper-V 隔离支持是添加自 v1.10 版本的实验性功能特性,会在未来版本中弃用, 向前文所提到的 CRI-ContainerD 和 RuntimeClass 特性倾斜。 要使用当前的功能特性并创建 Hyper-V 隔离的容器,需要在启动 kubelet 时设置特性门控 HyperVContainer=true,同时为 Pod 添加注解 experimental.windows.kubernetes.io/isolation-type=hyperv。 在实验性实现版本中,此功能特性限制每个 Pod 中只能包含一个容器。

    1. apiVersion: apps/v1
    2. kind: Deployment
    3. metadata:
    4. name: iis
    5. spec:
    6. selector:
    7. matchLabels:
    8. app: iis
    9. replicas: 3
    10. template:
    11. metadata:
    12. labels:
    13. app: iis
    14. annotations:
    15. experimental.windows.kubernetes.io/isolation-type: hyperv
    16. spec:
    17. containers:
    18. - name: iis
    19. image: microsoft/iis
    20. ports:
    21. - containerPort: 80

    kubeadm 已经成为用户部署 Kubernetes 集群的事实标准。 kubeadm 对 Windows 节点的支持目前还在开发过程中,不过你可以阅读相关的 。 我们也在投入资源到 Cluster API,以确保 Windows 节点被正确配置。

    若干其他关键功能

    • 为组管理的服务账号(Group Managed Service Accounts,GMSA)提供 Beta 支持
    • 实现更多的存储插件