你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

在 Azure Kubernetes 服务 (AKS) 中配置 Azure CNI 覆盖网络

传统的 Azure 容器网络接口 (CNI) 为每个 Pod 分配一个 VNet IP 地址。 它从每个节点上预留的一组 IP 或为 Pod 保留的单独子网中分配此 IP 地址。 这种方法需要规划 IP 地址,并可能导致地址耗尽,从而难以随着应用程序需求的增长而扩展集群。

使用 Azure CNI 覆盖时,群集节点将部署到 Azure 虚拟网络 (VNet) 子网中。 Pod 是从专用 CIDR 分配的 IP 地址,这在逻辑上与托管节点的 VNet 不同。 群集中的 Pod 和节点流量使用覆盖网络。 网络地址转换 (NAT) 使用节点的 IP 地址访问群集外部的资源。 此解决方案可节省大量 VNet IP 地址,从而能够将群集扩展到非常大的规模。 额外的优点是,可以在不同的 AKS 群集中重复使用专用 CIDR,这样做可扩展 Azure Kubernetes 服务 (AKS) 中容器化应用程序的可用 IP 空间。

覆盖网络概述

在覆盖网络中,只有 Kubernetes 群集节点从子网获取 IP。 Pod 从群集创建时提供的专用 CIDR 接收 IP。 每个节点获取一个从同一 CIDR 中划分出来的 /24 地址空间。 横向扩展群集时创建的额外节点会自动从同一 CIDR 获得 /24 地址空间。 Azure CNI 从此 /24 空间将 IP 分配到 Pod。

在 Azure 网络堆栈中为 Pod 的专用 CIDR 空间创建单独的路由域,这将创建一个覆盖网络,用于 Pod 之间的直接通信。 无需在群集子网上预配自定义路由,也无需使用封装方法在 Pod 之间通过隧道传输流量,这在 Pod 之间提供了与 VNet 中的 VM 相当的连接性能。 Pod 中运行的工作负载甚至不知道正在进行网络地址操作。

示意图显示两个节点,上面三个 Pod 都在覆盖网络中运行。到集群外部终结点的 Pod 流量通过 NAT 进行路由。

通过 NAT,使用节点 IP 与群集外部的终结点(如本地和对等互连 VNet)进行通信。 Azure CNI 将流量的源 IP(Pod 的覆盖 IP)转换为 VM 的主 IP 地址,从而使 Azure 网络堆栈能够将流量路由到目标。 群集外部的终结点无法直接连接到 Pod。 必须将 Pod 的应用程序发布为 Kubernetes 负载均衡器服务,使其可在 VNet 上访问。

可以使用标准 SKU 负载均衡器托管 NAT 网关为覆盖 Pod 提供到 Internet 的出站(出口)连接。 还可以通过使用群集子网上的用户定义路由将出口流量定向到防火墙来控制出口流量。

可以使用入口控制器(如 Nginx 或 HTTP 应用程序路由)配置与群集的入口连接。 无法使用 Azure 应用网关配置入口连接。 有关详细信息,请参阅 Azure CNI 覆盖的限制

Kubenet 和 Azure CNI 覆盖之间的区别

与 Azure CNI 覆盖一样,Kubenet 从逻辑上与 VNet 不同的地址空间向 Pod 分配 IP 地址,但具有缩放和其他限制。 下表提供了 Kubenet 和 Azure CNI 覆盖之间的详细对比。 如果不希望由于 IP 不足而将 VNet IP 地址分配给 Pod,建议使用 Azure CNI 覆盖。

区域 Azure CNI 覆盖 Kubenet
群集缩放 5000 个节点,每节点 250 个 Pod 400 个节点,每节点 250 个 Pod
网络配置 简单 - Pod 网络不需要额外配置 复杂 - Pod 网络需要群集子网上的路由表和 UDR
Pod 连接性能 与 VNet 中的 VM 相当的性能 额外的跃点会增加延迟
Kubernetes 网络策略 Azure 网络策略、Calico、Cilium Calico
支持的 OS 平台 Linux 和 Windows Server 2022,2019 仅限 Linux

IP 地址规划

  • 群集节点:设置 AKS 群集时,请确保 VNet 子网有足够的增长空间,以便于将来缩放。 可以将每个节点池分配到专用子网。 /24 子网最多可容纳 251 个节点,因为前三个 IP 地址保留用于管理任务。
  • Pod:覆盖解决方案从群集创建期间指定的专用 CIDR 为每个节点上的 Pod 分配 /24 地址空间。 /24 大小是固定的,不能增减。 最多可在一个节点上运行 250 个 Pod。 规划 Pod 地址空间时,请确保专用 CIDR 足够大,以便为新节点提供 /24 地址空间来支持将来的群集扩展。
    • 规划 Pod 的 IP 地址空间时,请考虑以下因素:
      • 同一 Pod CIDR 空间可用于同一 VNet 中的多个独立 AKS 群集。
      • Pod CIDR 空间不得与群集子网范围重叠。
      • Pod CIDR 空间不得与直接连接的网络重叠(如 VNet 对等互连、ExpressRoute 或 VPN)。 如果外部流量在 podCIDR 范围内具有源 IP,则需要通过 SNAT 转换为非重叠 IP 才能与群集通信。
  • Kubernetes 服务地址范围:服务地址 CIDR 的大小取决于计划创建的群集服务的数量。 它必须小于 /12。 此范围不应与对等互连 VNet 和本地网络中使用的 Pod CIDR 范围、群集子网范围和 IP 范围重叠。
  • Kubernetes DNS 服务 IP 地址:这是 Kubernetes 服务地址范围内的 IP 地址,将由群集服务发现使用。 不要使用地址范围中的第一个 IP 地址,因为此地址用于 kubernetes.default.svc.cluster.local 地址。

网络安全组

未封装使用 Azure CNI 覆盖的 Pod 到 Pod 流量,并应用了子网网络安全组规则。 如果子网 NSG 包含会影响 Pod CIDR 流量的拒绝规则,请确保以下规则到位,以确保除了满足所有 AKS 出口要求之外,群集的功能可以正常运行:

  • 所有端口和协议上从节点 CIDR 到节点 CIDR 的流量
  • 所有端口和协议上从节点 CIDR 到 Pod CIDR 的流量(服务流量路由所需的)
  • 所有端口和协议上从 Pod CIDR 到 Pod CIDR 的流量(Pod 到 Pod 和 Pod 到服务流量所需的,包括 DNS)

从 Pod 到 Pod CIDR 块外部的任何目标的流量将利用 SNAT 将源 IP 设置为运行 Pod 的节点的 IP。

如果要限制群集中工作负载之间的流量,建议使用网络策略

每个节点的最大 Pod 数

可以在创建群集时或添加新节点池时配置每个节点的最大 Pod 数。 Azure CNI 覆盖的默认值为 250。 可以在 Azure CNI 覆盖中指定的最大值为 250,最小值为 10。 在节点池创建期间配置的每个节点值的最大 Pod 数值仅适用于该节点池中的节点。

选择要使用的网络模型

Azure CNI 为 Pod 提供了两个 IP 寻址选项:将 VNet IP 分配到 Pod 的传统配置,以及覆盖网络。 选择用于 AKS 群集的选项时,需要在灵活性与高级配置需求之间进行平衡。 如果每种网络模型似乎都很合适,以下考虑因素可帮助你做出决策:

在以下情况下使用覆盖网络:

  • 希望扩展到大量 Pod,但 VNet 中的 IP 地址空间有限。
  • 大部分 Pod 通信在群集中进行。
  • 不需要高级 AKS 功能,例如虚拟节点。

在以下情况下使用传统 VNet 选项:

  • 有可用的 IP 地址空间。
  • 大部分 Pod 通信是与群集外部的资源进行的。
  • 群集外部的资源需要直接到达 Pod。
  • 需要 AKS 高级功能,例如虚拟节点。

Azure CNI 覆盖限制

Azure CNI 覆盖具有以下限制:

  • 不能将应用程序网关用作覆盖群集的入口控制器 (AGIC)。
  • 虚拟机可用性集 (VMAS) 不支持覆盖。
  • 不能在节点池中使用 DCsv2 系列虚拟机。 为了满足机密计算要求,请考虑改用 DCasv5 或 DCadsv5 系列机密 VM
  • 如果使用自己的子网来部署群集,则子网、VNET 和包含 VNET 的资源组的名称不得超过 63 个字符。 这是因为这些名称将用作 AKS 工作器节点中的标签,因此会受到 Kubernetes 标签语法规则的约束。

设置覆盖群集

注意

必须具有 CLI 版本 2.48.0 或更高版本才能使用 --network-plugin-mode 参数。 对于 Windows,必须安装最新的 aks-preview Azure CLI 扩展,并按照以下说明进行操作。

通过 az aks create 命令使用 Azure CNI 覆盖创建群集。 请确保使用参数 --network-plugin-mode 指定覆盖群集。 如果未指定 Pod CIDR,AKS 会分配一个默认空间:viz. 10.244.0.0/16

clusterName="myOverlayCluster"
resourceGroup="myResourceGroup"
location="westcentralus"

az aks create -n $clusterName -g $resourceGroup \
  --location $location \
  --network-plugin azure \
  --network-plugin-mode overlay \
  --pod-cidr 192.168.0.0/16

将新节点池添加到专用子网

使用 Azure CNI 覆盖创建群集后,可以创建另一个节点池,并将节点分配给同一 VNet 的新子网。 如果要控制同一 VNET 或对等 VNet 中目标的主机入口或出口 IP,此方法非常有用。

clusterName="myOverlayCluster"
resourceGroup="myResourceGroup"
location="westcentralus"
nodepoolName="newpool1"
subscriptionId=$(az account show --query id -o tsv)
vnetName="yourVnetName"
subnetName="yourNewSubnetName"
subnetResourceId="/subscriptions/$subscriptionId/resourceGroups/$resourceGroup/providers/Microsoft.Network/virtualNetworks/$vnetName/subnets/$subnetName"
az aks nodepool add  -g $resourceGroup --cluster-name $clusterName \
  --name $nodepoolName --node-count 1 \
  --mode system --vnet-subnet-id $subnetResourceId

将现有群集升级到 CNI 覆盖层

注意

如果群集满足以下条件,则可以将现有 Azure CNI 群集更新为覆盖层:

  • 群集使用 Kubernetes 版本 1.22+。
  • 请勿使用动态 Pod IP 分配功能。
  • 请勿启用网络策略。 可以在升级前卸载网络策略引擎,请参阅卸载 Azure 网络策略管理器或 Calico
  • 请勿使用将 docker 作为容器运行时的任何 Windows 节点池。

注意

由于 ARM 尚不支持路由域,因此基于 ARM 的 (ARM64) 处理器节点尚不支持 CNI 覆盖。

注意

将现有群集升级到 CNI 覆盖是一个不可逆的过程。

警告

在低于 Windows OS 内部版本 20348.1668 的版本中,围绕 Windows 覆盖 Pod 的限制错误地对来自主机网络 Pod 的数据包执行 SNAT,这对升级到覆盖层的群集具有更不利的影响。 若要避免此问题,请使用大于或等于 20348.1668 的 Windows OS 内部版本

警告

如果使用自定义 azure-ip-masq-agent 配置来包含不应从 Pod SNAT 数据包的其他 IP 范围,则升级到 Azure CNI 覆盖可能会中断到这些范围的连接。 群集节点外部的任何内容都无法访问覆盖空间中的 Pod IP。 此外,对于足够旧的群集,可能还有旧版 azure-ip-masq-agent 的 ConfigMap。 如果这个名为 azure-ip-masq-agent-config 的 ConfigMap 存在并且不是有意放置的,则应在运行 update 命令之前将其删除。 如果不使用自定义 ip-masq-agent 配置,则应仅存在与 Azure ip-masq-agent ConfigMaps 相关的 azure-ip-masq-agent-config-reconciled ConfigMap,并且这会在升级过程中自动更新。

升级过程将触发每个节点池同时重新映像。 不支持单独将每个节点池升级到覆盖层。 群集网络的任何中断都类似于节点映像升级或 Kubernetes 版本升级,其中节点池中的每个节点都会重新映像。

Azure CNI 群集升级

使用 az aks update 命令更新现有 Azure CNI 群集以使用覆盖。

clusterName="myOverlayCluster"
resourceGroup="myResourceGroup"
location="westcentralus"

az aks update --name $clusterName \
--resource-group $resourceGroup \
--network-plugin-mode overlay \
--pod-cidr 192.168.0.0/16

从旧 CNI 升级时需要 --pod-cidr 参数,因为 Pod 需要从与现有节点子网不重叠的新覆盖空间获取 IP。 Pod CIDR 也不能与节点池的任何 VNet 地址重叠。 例如,如果 VNet 地址为 10.0.0.0/8,节点位于子网 10.240.0.0/16 中,则 --pod-cidr 不能与 10.0.0.0/8 或群集上的现有服务 CIDR 重叠。

Kubenet 群集升级

使用 az aks update 命令更新现有 Kubenet 群集以使用 Azure CNI 覆盖。

clusterName="myOverlayCluster"
resourceGroup="myResourceGroup"
location="westcentralus"

az aks update --name $clusterName \
--resource-group $resourceGroup \
--network-plugin azure \
--network-plugin-mode overlay 

由于群集已在对不与 VNet IP 空间重叠的 Pod 使用专用 CIDR,因此无需指定 --pod-cidr 参数,并且 Pod CIDR 将保持不变。

注意

从 Kubenet 升级到 CNI 覆盖时,Pod 路由不再需要使用路由表。 如果群集使用的是客户提供的路由表,则迁移操作期间会自动删除用于将 Pod 流量定向到正确节点的路由。 如果群集使用的是托管路由表(路由表由 AKS 创建并驻留在节点资源组中),则会将路由表作为迁移的一部分删除。

双栈网络

在使用覆盖网络和双堆栈 Azure 虚拟网络时,可以在双堆栈模式下部署 AKS 群集。 在此配置中,节点从 Azure 虚拟网络子网接收 IPv4 和 IPv6 地址。 Pod 接收从逻辑上不同的地址空间到节点的 Azure 虚拟网络子网的 IPv4 和 IPv6 地址。 然后配置网络地址转换 (NAT),以便 Pod 可以访问 Azure 虚拟网络上的资源。 流量的源 IP 地址是 NAT 到同一系列的节点主 IP 地址(从 IPv4 到 IPv4 和从 IPv6 到 IPv6)。

先决条件

  • 必须安装 Azure CLI 2.48.0 或更高版本。
  • Kubernetes 版本 1.26.3 或更高版本。

限制

双堆栈网络不支持以下功能:

  • Windows 节点池
  • Azure 网络策略
  • Calico 网络策略
  • NAT 网关
  • 虚拟节点加载项

部署双堆栈 AKS 群集

提供了下列属性来支持双堆栈群集:

  • --ip-families:采用要在群集上启用的 IP 系列列表,以逗号分隔。
    • 仅支持 ipv4ipv4,ipv6
  • --pod-cidrs:采用 CIDR 表示法 IP 范围的逗号分隔列表,从中分配 Pod IP。
    • 此列表中范围的计数和顺序必须与提供给 --ip-families 的值匹配。
    • 如果未提供值,则使用默认值 10.244.0.0/16,fd12:3456:789a::/64
  • --service-cidrs:采用 CIDR 表示法 IP 范围的逗号分隔列表,从中分配服务 IP。
    • 此列表中范围的计数和顺序必须与提供给 --ip-families 的值匹配。
    • 如果未提供值,则使用默认值 10.0.0.0/16,fd12:3456:789a:1::/108
    • 分配给 --service-cidrs 的 IPv6 子网不能大于 /108。

创建双堆栈 AKS 群集

  1. 使用 [az group create][az-group-create] 命令为群集创建 Azure 资源组。

    az group create -l <region> -n <resourceGroupName>
    
  2. 使用 --ip-families 参数设置为 ipv4,ipv6az aks create 命令创建双堆栈 AKS 群集。

    az aks create -l <region> -g <resourceGroupName> -n <clusterName> \
      --network-plugin azure \
      --network-plugin-mode overlay \
      --ip-families ipv4,ipv6
    

创建示例工作负载

创建群集后,便可部署工作负载。 本文将指导你完成 NGINX Web 服务器的示例工作负载部署。

部署 NGINX Web 服务器

对于 AKS 群集中的入口,建议使用应用程序路由加载项。 有关应用程序路由加载项的详细信息以及如何使用加载项部署应用程序的示例,请参阅“托管 NGINX 入口与应用程序路由加载项”

通过 LoadBalancer 类型服务公开工作负载

重要

目前,AKS 中的 IPv6 服务有两个限制。

  • Azure 负载均衡器将运行状况探测从链接本地地址发送到 IPv6 目标。 在 Azure Linux 节点池中,此流量无法路由到 Pod,因此流向使用 externalTrafficPolicy: Cluster 部署的 IPv6 服务的流量会失败。 必须使用 externalTrafficPolicy: Local 部署 IPv6 服务,以使 kube-proxy 响应节点上的探测。
  • 在 Kubernetes 版本 1.27 之前,只有服务的第一个 IP 地址将预配到负载均衡器,因此双堆栈服务只会获得第一个列出的 IP 系列的公共 IP。 要为单个部署提供双堆栈服务,请创建两个面向同一选择器的服务:一个针对 IPv4,一个针对 IPv6。 这不再是 kubernetes 1.27 或更高版本中的限制。
  1. 使用 kubectl expose deployment nginx 命令公开 NGINX 部署。

    kubectl expose deployment nginx --name=nginx-ipv4 --port=80 --type=LoadBalancer'
    kubectl expose deployment nginx --name=nginx-ipv6 --port=80 --type=LoadBalancer --overrides='{"spec":{"ipFamilies": ["IPv6"]}}'
    

    你会收到一个输出,显示服务已公开。

    service/nginx-ipv4 exposed
    service/nginx-ipv6 exposed
    
  2. 公开部署并完全预配 LoadBalancer 服务后,使用 kubectl get services 命令获取服务的 IP 地址。

    kubectl get services
    
    NAME         TYPE           CLUSTER-IP               EXTERNAL-IP         PORT(S)        AGE
    nginx-ipv4   LoadBalancer   10.0.88.78               20.46.24.24         80:30652/TCP   97s
    nginx-ipv6   LoadBalancer   fd12:3456:789a:1::981a   2603:1030:8:5::2d   80:32002/TCP   63s
    
  3. 在支持 IPv6 的主机中通过命令行 Web 请求来验证功能。 Azure Cloud Shell 不支持 IPv6。

    SERVICE_IP=$(kubectl get services nginx-ipv6 -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    curl -s "http://[${SERVICE_IP}]" | head -n5
    
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
    

后续步骤

若要了解如何将 AKS 与自己的容器网络接口 (CNI) 插件配合使用,请参阅引入自己的容器网络接口 (CNI) 插件