在 Azure Kubernetes 服务 (AKS) 中使用实例级公共 IP

AKS 节点无需使用自身的公共 IP 地址进行通信。 但某些方案可能需要节点池中的节点收到专用公共 IP 地址。 一个常见的场景是游戏工作负载,在这种情况下,游戏主机需要与云端虚拟机建立直接连接,以尽量减少网络跳数。 可通过使用节点公共 IP 在 AKS 上实现此方案。

首先,创建一个新的资源组。

az group create --name <resourceGroup> --location <region>

创建新的 AKS 群集并为节点附加公共 IP。 节点池中的每个节点都将收到唯一的公共 IP。 可以通过查看虚拟机规模集实例来验证这一点。

az aks create \
    --resource-group <resourceGroup> \
    --name <aksClusterName> \
    --location <region> \
    --enable-node-public-ip \
    --generate-ssh-keys

对于现有 AKS 群集,还可以添加新的节点池,并为节点附加公共 IP。

az aks nodepool add --resource-group <resourceGroup> --cluster-name <aksClusterName> --name <newNodePool> --enable-node-public-ip

使用公共 IP 前缀

使用公共 IP 前缀有很多好处。 在创建新群集或添加节点池时,通过 --node-public-ip-prefix-id 标志传递资源 ID,AKS 支持为节点使用来自现有公共 IP 前缀的地址。

首先,使用 az network public-ip prefix create 创建公共 IP 前缀:

az network public-ip prefix create --length 28 --location <region> --name <publicIPPrefixName> --resource-group <resourceGroup>

查看输出,并注意前缀为 id:

{
  ...
  "id": "/subscriptions/<subscription-id>/resourceGroups/<resourceGroup>/providers/Microsoft.Network/publicIPPrefixes/<publicIPPrefixName>",
  ...
}

最后,在创建新群集或添加新的节点池时,使用标志 --node-public-ip-prefix-id 并传入前缀的资源 ID:

az aks create \
    --resource-group <resourceGroup> \
    --name <aksClusterName> \
    --location <region> \
    --enable-node-public-ip \
    --node-public-ip-prefix-id /subscriptions/<subscription-id>/resourceGroups/<resourceGroup>/providers/Microsoft.Network/publicIPPrefixes/<publicIPPrefixName> \
    --generate-ssh-keys

使用双堆栈公共 IP 前缀(预览版)

可以使用双堆栈群集上的公共 IP 前缀将 IPv4 和 IPv6 公共 IP 地址分配给节点池中的每个节点。 此功能适用于需要通过 IPv4 和 IPv6 建立直接入站或出站连接的工作负荷,也适用于在需要符合 IPv6 要求的环境中运行的应用程序。

有两种受支持的配置:

  • 使用您自己的 IPv4 和 IPv6 前缀。 每个节点从 IPv4 前缀接收一个 IPv4 地址,并从 IPv6 前缀接收一个 IPv6 地址。 当这两个地址都需要来自你控制的地址范围(例如,当防火墙或合作伙伴服务只允许来自你的前缀的流量时)时,请使用此配置。
  • 仅支持自备 IPv6 前缀。 每个节点从 IPv6 前缀接收一个 IPv6 地址,Azure自动分配 IPv4 地址。 仅当 IPv6 地址需要来自所控制的范围时,请使用此配置。 由于节点池不使用 IPv4 前缀中的地址,因此 IPv4 前缀的大小不会限制节点池可缩放到的节点数。

重要

AKS 预览功能以自助且需主动选择加入的方式提供。 预览功能是“按现状”和“按可用”提供的,不包括在服务级别协议和有限保证中。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:

要求

若要将双堆栈公共 IP 前缀与节点公共 IP 配合使用,请确保满足以下先决条件:

  • 群集配置为具有 IPv4 和 IPv6 IP 系列的双堆栈群集。 两种配置都需要双栈集群,包括仅限 IPv6 的前缀配置。
  • 群集使用具有覆盖网络的 Azure CNI。
  • 你创建了计划与 AKS 群集在同一订阅和区域中使用的公共 IP 前缀。 根据所选的配置,需要一个 IPv4 前缀和一个 IPv6 前缀,或者一个 IPv6 前缀。
  • 每个公共 IP 前缀都使用标准 SKU,且未关联到负载均衡器。
  • AKS 群集标识有权管理公共 IP 前缀。 如果前缀位于其他资源组中,请将该资源组上的网络参与者角色分配给群集标识。

注册预览功能

适用于节点公共 IP 的双堆栈(IPv4 和 IPv6)公共 IP 前缀支持当前处于预览阶段。 在使用此功能之前,必须先安装或更新Azure CLI扩展并在订阅中注册NodePublicIPv6PrefixPreview功能标志。

安装或更新 aks-preview 扩展:

az extension add --name aks-preview --upgrade

注册所需的预览功能:

az feature register --namespace Microsoft.ContainerService --name NodePublicIPv6PrefixPreview

完成功能注册可能需要几分钟时间。 若要检查注册状态,请运行:

az feature show --namespace Microsoft.ContainerService --name NodePublicIPv6PrefixPreview --query "properties.state"

等待该特性报告为 已注册 状态后,再继续。

注册功能标志后,请刷新资源提供程序,以确保更改已生效:

az provider register --namespace Microsoft.ContainerService

注册完成后,可以创建或更新群集,以对节点公共 IP 使用双堆栈公共 IP 前缀。

创建公共 IP 前缀

使用Azure CLI为 IPv4 和 IPv6 创建公共 IP 前缀。 如果计划使用仅限 IPv6 的前缀配置,请仅创建 IPv6 前缀。

对于 IPv4:

az network public-ip prefix create \
  --resource-group <resourceGroup> \
  --name <ipv4PrefixName> \
  --location <region> \
  --length 28 \
  --sku Standard \
  --version IPv4

对于 IPv6:

az network public-ip prefix create \
  --resource-group <resourceGroup> \
  --name <ipv6PrefixName> \
  --location <region> \
  --length 124 \
  --sku Standard \
  --version IPv6

创建前缀后,请记下每个前缀的资源 ID。

创建具有双堆栈节点公共 IP 前缀的新群集

创建新的 AKS 群集时,使用 --node-public-ip-prefix-ids 参数同时指定 IPv4 和公共 IP 前缀。

az aks create \
  --resource-group <resourceGroup> \
  --name <aksClusterName> \
  --location <region> \
  --enable-node-public-ip \
  --ip-families IPv4,IPv6 \
  --network-plugin azure \
  --network-plugin-mode overlay \
  --node-public-ip-prefix-ids "<ipv4PrefixResourceId>,<ipv6PrefixResourceId>" \
  --generate-ssh-keys

该 --node-public-ip-prefix-ids 参数接受以逗号分隔的公共 IP 前缀资源 ID 列表。 该列表最多可以包含一个 IPv4 前缀和一个 IPv6 前缀。 顺序并不重要,因为 AKS 从每个引用的前缀中确定 IP 版本。

添加具有双堆栈节点公共 IP 前缀的节点池

还可以将具有双堆栈节点公共 IP 前缀的节点池添加到现有的双堆栈群集。

az aks nodepool add \
  --resource-group <resourceGroup> \
  --cluster-name <aksClusterName> \
  --name <nodePoolName> \
  --enable-node-public-ip \
  --node-public-ip-prefix-ids "<ipv4PrefixResourceId>,<ipv6PrefixResourceId>"

使用仅限 IPv6 的公共 IP 前缀

如果只需要 IPv6 地址来自所控制的前缀,请指定单个 IPv6 前缀。 每个节点从前缀接收 IPv6 地址,Azure自动分配 IPv4 地址。 节点池仍需要双堆栈群集。

如果 IPv4 前缀的大小会限制节点池可扩展到何种程度,请使用此配置。 由于节点池不会从前缀中提取 IPv4 地址,因此只有 IPv6 前缀的容量会限制节点计数。

使用仅限 IPv6 的节点公共 IP 前缀创建新群集:

az aks create \
  --resource-group <resourceGroup> \
  --name <aksClusterName> \
  --location <region> \
  --enable-node-public-ip \
  --ip-families IPv4,IPv6 \
  --network-plugin azure \
  --network-plugin-mode overlay \
  --node-public-ip-prefix-ids "<ipv6PrefixResourceId>" \
  --generate-ssh-keys

将具有仅限 IPv6 的节点公共 IP 前缀的节点池添加到现有的双堆栈群集:

az aks nodepool add \
  --resource-group <resourceGroup> \
  --cluster-name <aksClusterName> \
  --name <nodePoolName> \
  --enable-node-public-ip \
  --node-public-ip-prefix-ids "<ipv6PrefixResourceId>"

由于Azure自动分配 IPv4 地址,因此每个节点的 IPv4 地址不可预测,并且无法提前将其添加到允许列表中。 因此,不能在使用 API 服务器授权 IP 范围的群集上使用仅限 IPv6 的公共 IP 前缀。 请改用 专用群集 ,或在列表中包括 IPv4 前缀。

验证节点公共 IP 前缀配置

使用 az aks nodepool show 命令确认节点池使用哪些前缀:

az aks nodepool show \
  --resource-group <resourceGroup> \
  --cluster-name <aksClusterName> \
  --name <nodePoolName> \
  --query "networkProfile.nodePublicIPPrefixIDs"

列出节点通过 az vmss list-instance-public-ips 命令获取的公共 IP 地址。 使用 节点资源组:

az vmss list-instance-public-ips \
  --resource-group <MC_resourceGroup_aksClusterName_region> \
  --name <virtualMachineScaleSetName> \
  --query "[].{name:name, ipAddress:ipAddress, version:publicIPAddressVersion}" \
  --output table

对于仅限 IPv6 的前缀,每个节点都有一个来自你的前缀的 IPv6 地址,以及 Azure 托管地址池中的一个 IPv4 地址。

局限性

以下限制适用于用于节点公共 IP 的公共 IP 前缀。

前缀列表:

  • 前缀列表最多可以包含一个 IPv4 前缀和一个 IPv6 前缀。 拒绝同一 IP 版本的两个前缀。
  • 指定前缀时,必须在节点池上启用节点公共 IP。
  • 不能在同一命令中使用 --node-public-ip-prefix-ids 和 --node-public-ip-prefix-id 参数。
  • 节点公共 IP 配置是不可变的。 若要更改公共 IP 前缀,必须创建新的节点池并迁移工作负载。

前缀资源:

  • 每个前缀都必须使用标准 SKU。 不支持基本和标准 V2 前缀。
  • 每个前缀必须位于与 AKS 群集相同的订阅和同一区域。
  • 不能使用已与负载均衡器关联的前缀。
  • 如果节点池使用可用性区域,则每个前缀的区域必须涵盖节点池的区域。 区域冗余前缀(未分配到任何区域)适用于任何节点池。

容量和规模:

  • 每个前缀必须有足够的地址用于节点池的节点计数,因为每个节点都使用你提供的每个前缀中的一个地址。
  • 支持群集自动缩放程序,但请确保配置的最大节点计数不超过提供的每个前缀中的可用 IP 地址数。 如果使用仅 IPv6 前缀,则只有 IPv6 前缀会限制节点计数,因为Azure自动分配 IPv4 地址。

功能兼容性:

  • 不能在使用 API 服务器授权 IP 范围的群集上使用仅限 IPv6 的公共 IP 前缀,因为Azure自动分配节点的 IPv4 地址,并且不能提前将其添加到允许列表。 请改用 API Server VNet 集成或专用群集,或在列表中包括 IPv4 前缀。
  • 为每个节点分配一个 IPv6 公共 IP 地址。
  • AKS 自动或节点自动预配不支持此功能。
  • 不支持多 NIC 节点池。

找到节点的公共 IP

可以通过多种方式找到节点的公共 IP:

重要

节点资源组包含节点及其公共 IP。 执行命令时,使用节点资源组查找节点的公共 IP。

az vmss list-instance-public-ips --resource-group <MC_region_aksClusterName_region> --name <virtualMachineScaleSetName>

在节点公共 IP 上使用公共 IP 标记

在节点的公共 IP 上可以使用公共 IP 标签,以利用 Azure 路由首选项功能,该功能在指定区域中可用。

要求

  • 需要 AKS 版本 1.29 或更高版本。

使用路由首选项 Internet 创建新群集

az aks create \
    --name <aksClusterName> \
    --location <region> \
    --resource-group <resourceGroup> \
    --enable-node-public-ip \
    --node-public-ip-tags RoutingPreference=Internet \
    --generate-ssh-keys

添加具有路由首选项 Internet 的节点池

az aks nodepool add --cluster-name <aksClusterName> \
  --name <nodePoolName> \
  --location <region> \
  --resource-group <resourceGroup> \
  --enable-node-public-ip \
  --node-public-ip-tags RoutingPreference=Internet

允许主机端口连接并将节点池添加到应用程序安全组

对于利用节点公共 IP 并在其主机地址上托管服务的 AKS 节点,需要为其添加 NSG 规则以允许流量。 在节点池配置中添加所需的端口会在群集网络安全组中创建相应的允许规则。

如果使用自带虚拟网络的群集所在的子网上已配置网络安全组,则必须向该网络安全组添加一条允许规则。 可以通过将该节点池添加到应用程序安全组 (ASG) 中,将此限制为特定节点池中的节点。 如果指定了允许的主机端口,则默认情况下会在托管资源组中创建托管 ASG。 还可以通过在节点池参数中指定 NSG 的资源 ID,将节点添加到一个或多个自定义 ASG。

主机端口规范格式

指定允许的端口列表时,请使用逗号分隔列表,其中包含采用 port/protocol 或 startPort-endPort/protocol 格式的条目。

示例:

  • 80/tcp
  • 80/tcp,443/tcp
  • 53/udp,80/tcp
  • 50000-60000/tcp

要求

  • 需要 AKS 版本 1.29 或更高版本。

使用允许的端口和应用程序安全组创建新群集

az aks create \
    --resource-group <resourceGroup> \
    --name <aksClusterName> \
    --nodepool-name <nodePoolName> \
    --nodepool-allowed-host-ports 80/tcp,443/tcp,53/udp,40000-60000/tcp,40000-50000/udp\
    --nodepool-asg-ids "<asgId>,<asgId>" \
    --generate-ssh-keys

添加具有允许的端口和应用程序安全组的新节点池

az aks nodepool add \
  --resource-group <resourceGroup> \
  --cluster-name <aksClusterName> \
  --name <nodePoolName> \
  --allowed-host-ports 80/tcp,443/tcp,53/udp,40000-60000/tcp,40000-50000/udp \
  --asg-ids "<asgId>,<asgId>"

更新节点池允许的端口和应用程序安全组

az aks nodepool update \
  --resource-group <resourceGroup> \
  --cluster-name <aksClusterName> \
  --name <nodePoolName> \
  --allowed-host-ports 80/tcp,443/tcp,53/udp,40000-60000/tcp,40000-50000/udp \
  --asg-ids "<asgId>,<asgId>"

为 Pod 工作负载自动分配主机端口(预览版)

在节点上配置公共 IP 时,可以利用主机端口允许 Pod 直接接收流量,而无需配置负载均衡器服务。 这在游戏等场景中特别有用,在这些场景中,节点 IP 和端口的临时性质不成问题,因为已知主机名中的配对服务可以提供要在连接时使用的正确主机和端口。 但是,由于主机上只有一个进程可以侦听同一端口,因此将应用程序与主机端口配合使用可能会导致计划出现问题。 为了避免此问题,AKS 允许系统在计划时动态分配可用端口,从而防止冲突。

警告

群集上设置的默认 NSG 规则会阻止 Pod 主机端口流量。 此功能应与在节点池上允许使用主机端口结合使用,以使流量能够通过。

重要

AKS 预览功能以自助且需主动选择加入的方式提供。 预览功能是“按现状”和“按可用”提供的,不包括在服务级别协议和有限保证中。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:

要求

  • 需要 AKS 版本 1.29 或更高版本。

注册“PodHostPortAutoAssignPreview”功能标志

使用 PodHostPortAutoAssignPreview 命令注册 功能标志,如以下示例所示:

az feature register --namespace "Microsoft.ContainerService" --name "PodHostPortAutoAssignPreview"

状态需要几分钟才会显示为已注册。 使用 az feature show 命令验证注册状态:

az feature show --namespace "Microsoft.ContainerService" --name "PodHostPortAutoAssignPreview"

当状态反映为“已注册”时,使用 az provider register 命令刷新 Microsoft.ContainerService 资源提供程序的注册:

az provider register --namespace Microsoft.ContainerService

自动为 Pod 分配主机端口

触发主机端口自动分配的方法是:部署一个未指定任何主机端口的工作负载,并添加 kubernetes.azure.com/assign-hostports-for-containerports 注解,其中包含需要分配主机端口的端口列表。 该注释的值应指定为逗号分隔的条目列表,例如 port/protocol,其中 port 是 Pod 规范中定义的单个端口号,protocol 为 tcp 或 udp。

端口将从范围 40000-59999 分配,并且在整个群集中是唯一的。 分配的端口还将添加到 Pod 内的环境变量中,以便应用程序可以确定分配了哪些端口。 环境变量名称将采用以下格式(示例如下):<deployment name>_PORT_<port number>_<protocol>_HOSTPORT,例如 mydeployment_PORT_8080_TCP_HOSTPORT: 41932。

下面是一个示例 echoserver 部署,显示了端口 8080 和 8443 的主机端口映射:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: echoserver-hostport
  labels:
    app: echoserver-hostport
spec:
  replicas: 3
  selector:
    matchLabels:
      app: echoserver-hostport
  template:
    metadata:
      annotations:
        kubernetes.azure.com/assign-hostports-for-containerports: 8080/tcp,8443/tcp
      labels:
        app: echoserver-hostport
    spec:
      nodeSelector:
        kubernetes.io/os: linux
      containers:
        - name: echoserver-hostport
          image: k8sgcr.azk8s.cn/echoserver:1.10
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
            - name: https
              containerPort: 8443
              protocol: TCP

应用该部署时,hostPort 条目将出现在各个 Pod 的 YAML 中:

$ kubectl describe pod echoserver-hostport-75dc8d8855-4gjfc
<cut for brevity>
Containers:
  echoserver-hostport:
    Container ID:   containerd://d0b75198afe0612091f412ee7cf7473f26c80660143a96b459b3e699ebaee54c
    Image:          k8sgcr.azk8s.cn/echoserver:1.10
    Image ID:       k8sgcr.azk8s.cn/echoserver@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229                                                                                                      Ports:          8080/TCP, 8443/TCP
    Host Ports:     46645/TCP, 49482/TCP
    State:          Running
      Started:      Thu, 12 Jan 2023 18:02:50 +0000
    Ready:          True
    Restart Count:  0
    Environment:
      echoserver-hostport_PORT_8443_TCP_HOSTPORT:  49482
      echoserver-hostport_PORT_8080_TCP_HOSTPORT:  46645

后续步骤