为Pod挂载独立公网EIP

重要

本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。

在Kubernetes集群中,Pod的IP地址一般是私网的IP地址。但在某些场景下,Pod可能需要一个独立的公网IP地址,使得Pod可以独立地与外部网络通信,不受其他Pod流量的干扰。阿里云的Terway和ack-extend-network-controller组件均支持将弹性公网IP(Elastic IP Address,简称EIP)直接关联到特定的Pod上,从而使得该Pod拥有独立的公网出口。

前提条件

已创建ACK托管集群ACK专有版集群,且集群网络插件为Terway。具体操作,请参见创建ACK托管集群创建ACK专有集群。关于Terway网络模式的更多信息,请参见使用Terway网络插件

重要

自2023年11月起,Terway停止EIP功能更新,并在v1.7.0版本中正式移除。推荐您使用ack-extend-network-controller组件为Pod挂载独立公网EIP。详细信息,请参见将EIP功能从Terway迁移至ack-extend-network-controller

使用限制

  • 此功能仅支持普通ECS节点,不支持ECI实例。

  • 在使用EIP之前,请了解EIP的使用限制,请参见使用限制

费用说明

启用Terway和ack-extend-network-controller插件不会产生额外的费用,但使用云产品资源可能会产生费用。关于ACK的云产品资源计费信息,请参见云产品资源计费

背景信息

一般情况下,Terway网络模式中的Pod访问公网的流量是通过主机SNAT(Source Network Address Translation)或者外部SNAT通过EIP实现的,对于Pod的公网入口流量一般是通过LoadBalancer类型的Service流入。然而,在某些场景中,Pod可能需要独立的公网地址,例如:

  • Pod的对外映射端口是随机的,一般常见于UDP(User Datagram Protocol)的游戏服务器或电话会议等。例如RTSP协议,对不同的客户端使用不同的端口。

  • Pod访问公网流量存在争抢,Pod需要独立的公网出口。

步骤一:配置挂载EIP所需的RAM权限

ack-extend-network-controller

  • ACK托管集群ACK专有版集群授予RAM权限

    1. 创建自定义权限策略,策略内容如下。具体操作,请参见步骤一:创建自定义权限策略

           {
            "Effect": "Allow",
            "Action": [
              "vpc:DescribeVSwitches",
              "vpc:AllocateEipAddress",
              "vpc:AllocateEipAddressPro",
              "vpc:DescribeEipAddresses",
              "vpc:AssociateEipAddress",
              "vpc:UnassociateEipAddress",
              "vpc:ReleaseEipAddress",
              "vpc:AddCommonBandwidthPackageIp",
              "vpc:RemoveCommonBandwidthPackageIp",
              "vpc:TagResources",
              "ecs:DescribeNetworkInterfaces"
            ],
            "Resource": [
              "*"
            ],
            "Condition": {}
          }
    2. 为集群的Worker RAM角色授权。具体操作,请参见步骤二:为集群的Worker RAM角色授权

  • ACK Serverless集群授予RAM权限

    对于ACK Serverless集群,请为RAM用户生成访问密钥(AccessKey)。具体操作,请参见创建RAM用户创建自定义权限策略

Terway

Terway为Pod配置EIP需要EIP相关的权限来申请和配置EIP,所以需要部署额外的配置和权限。

  • ACK托管集群或者2020年6月及之后创建的ACK集群基础版授予RAM权限

    1. 创建自定义权限策略,策略内容如下。具体操作,请参见步骤一:创建自定义权限策略

           {
            "Effect": "Allow",
            "Action": [
              "vpc:DescribeVSwitches",
              "vpc:AllocateEipAddress",
              "vpc:DescribeEipAddresses",
              "vpc:AssociateEipAddress",
              "vpc:UnassociateEipAddress",
              "vpc:ReleaseEipAddress",
              "vpc:AddCommonBandwidthPackageIp",
              "vpc:RemoveCommonBandwidthPackageIp"
            ],
            "Resource": [
              "*"
            ],
            "Condition": {}
          }
    2. 为集群的Worker RAM角色授权。具体操作,请参见步骤二:为集群的Worker RAM角色授权

  • ACK专有版集群或者2020年06月之前创建的ACK托管集群授予RAM权限

    1. 创建自定义权限策略,策略内容如下。具体操作,请参见步骤一:创建自定义权限策略

           {
            "Effect": "Allow",
            "Action": [
              "vpc:DescribeVSwitches",
              "vpc:AllocateEipAddress",
              "vpc:DescribeEipAddresses",
              "vpc:AssociateEipAddress",
              "vpc:UnassociateEipAddress",
              "vpc:ReleaseEipAddress",
              "vpc:AddCommonBandwidthPackageIp",
              "vpc:RemoveCommonBandwidthPackageIp"
            ],
            "Resource": [
              "*"
            ],
            "Condition": {}
          }
    2. RAM角色AliyunCSManagedNetworkRole页面的权限策略页签,单击新增授权,然后单击自定义策略,将上一步创建的自定义权限策略选中。

    3. 单击确定

    4. 单击完成

步骤二:为集群安装或升级插件

警告

您不能同时启用ack-extend-network-controller与Terway的EIP配置能力,否则可能会使EIP资源重复分配,从而导致EIP绑定失败。推荐您使用ack-extend-network-controller插件。

插件对比

对比项

ack-extend-network-controller

Terway

支持的集群类型

  • ACK托管集群

  • ACK专有集群

  • ACK Serverless集群

  • ACK托管集群

  • ACK专有集群

固定EIP

支持

不支持

配置阶段

Pod IP分配后,控制器将为Pod分配、绑定EIP地址。

在CNI执行过程中分配、绑定EIP地址。

支持版本

插件版本为v0.2.0及以上。

Terway插件版本大于等于v1.0.10.280-gdc2cb6c-aliyun,小于v1.7.0。

安装或升级插件

如果使用ack-extend-network-controller插件,请在ACK应用市场中安装ack-extend-network-controller插件,并开启EIP控制器;如果使用Terway网络插件,请将Terway升级至v1.0.10.280-gdc2cb6c-aliyun及以上版本。

安装ack-extend-network-controller

  1. 登录容器服务管理控制台,在左侧导航栏选择市场 > 应用市场

  2. 应用市场页面的搜索栏中输入ack-extend-network-controller,然后单击目标应用。

  3. 在应用详情页面,单击右上角的一键部署

  4. 创建面板中,选择集群和命名空间,然后单击下一步

    1. 在参数配置页面,选择版本号并设置相应的参数,然后单击确定

      参数说明如下所示:

      配置参数

      类型

      必填

      描述

      clusterID

      string

      集群ID。

      regionID

      string

      集群可用区ID。

      enableControllers

      []string

      配置eip以启用EIP功能。

      networkController.vpcid

      string

      集群所在VPC ID。

      networkController.eipController.maxConcurrentReconciles

      int

      EIP控制器并发数量。

      networkController.eipController.garbageCollectionPeriodInMinutes

      int

      EIP控制器清理固定EIP的周期。

      customStatefulWorkloadKinds

      []string

      自定义有状态控制器Kind。

      credential.accessKey

      string

      挂载EIP所需权限账户的AK。

      若使用步骤一为集群的Worker RAM角色授权,此处无需配置。

      重要

      此配置会将敏感信息存储到Kubernetes Secret中,不推荐使用。

      credential.accessSecret

      string

      挂载EIP所需权限账户的SK。

      若使用步骤一为集群的Worker RAM角色授权,此处无需配置。

      重要

      此配置会将敏感信息存储到Kubernetes Secret中,不推荐使用。

      参数示例如下:

      clusterID: "c11ba338192xxxxxxx"  
      regionID: "cn-hangzhou"      
      vpcID: "vpc-bp1rkq0zxxxxxx" 
      enableControllers:
        - eip              
      
      networkController:
        eipController:
          maxConcurrentReconciles: 1   
          garbageCollectionPeriodInMinutes: 1  
        customStatefulWorkloadKinds:           
        - foo
      
      credential:                             
        accessKey: ""
        accessSecret: ""

如需更新ack-extend-network-controller插件的版本和参数,请参见修改Helm Chart

升级Terway

请确认您的集群插件为Terway,并将Terway插件(terway-eni或terway-eniip)升级到支持EIP功能的版本。关于升级Terway插件的具体步骤,请参见管理组件

说明

Terway插件版本大于等于v1.0.10.280-gdc2cb6c-aliyun,小于v1.7.0。关于Terway插件版本信息,请参见Terway

步骤三:启用EIP功能

启用EIP的Annotation介绍

ACK支持使用Annotation(注解)的方式启用EIP功能,您可以按需选择自动分配EIP或为Pod设置固定EIP。

自动分配EIP

重要

使用自动分配EIP功能时,可能会在Pod重建、CNI执行失败等情况下出现反复申请、释放EIP资源的情况。如果您想避免这种情况,可以选择指定EIP实例的方式。

Pod Annotations

value

k8s.aliyun.com/pod-with-eip

是否自动创建并绑定EIP。取值:

  • true:自动创建并绑定EIP。

  • false:不自动创建并绑定EIP。

k8s.aliyun.com/eci-with-eip(兼容)

k8s.aliyun.com/eip-bandwidth

EIP峰值带宽。单位:Mbps。更多信息,请参见申请EIP

k8s.aliyun.com/eip-internet-charge-type

EIP的计量方式。取值:

  • PayByTraffic:按使用流量计费。

  • PayByBandwidth:按带宽计费。

更多信息,请参见申请EIP

说明
  • 默认选择PayByTraffic。

k8s.aliyun.com/eip-charge-type(兼容)

k8s.aliyun.com/eip-instance-charge-type

EIP的计费方式,取值:

  • PrePaid:包年包月。

  • PostPaid:按量计费。

更多信息,请参见申请EIP

说明

此Annotation仅在ack-extend-network-controller中支持。

k8s.aliyun.com/eip-common-bandwidth-package-id

绑定已有的共享带宽包。

说明

使用此Annotation,需要terway插件版本为v1.2.3及以上;对ack-extend-network-controller插件版本无限制。

k8s.aliyun.com/eip-isp

EIP的线路类型。取值:

  • BGP:BGP(多线)线路。

  • BGP_PRO:BGP(多线)精品线路。

更多信息,请参见申请EIP

说明

使用此Annotation,需要terway插件版本为v1.2.3及以上;对ack-extend-network-controller插件版本无限制。

k8s.aliyun.com/eip-public-ip-address-pool-id

EIP地址池。关于EIP地址池的使用限制、使用步骤等,请参见创建和管理IP地址池

说明

此Annotation仅在ack-extend-network-controller中支持。

k8s.aliyun.com/eip-resource-group-id

EIP资源组。更多信息,请参见申请EIP

说明

此Annotation仅ack-extend-network-controller插件版本为v0.4.0及以上支持使用。

k8s.aliyun.com/eip-name

EIP名称。更多信息,请参见申请EIP

说明

此Annotation仅ack-extend-network-controller插件版本为v0.6.0及以上支持使用。

k8s.aliyun.com/eip-description

EIP描述。更多信息,请参见申请EIP

说明

此Annotation仅ack-extend-network-controller插件版本为v0.6.0及以上支持使用。

k8s.aliyun.com/eip-security-protection-types

EIP安全防护级别,支持高防EIP(DDoS防护增强EIP)。若配置多个,请通过,分隔。更多信息,请参见申请EIP

说明

此Annotation仅ack-extend-network-controller插件版本为v0.9.0及以上支持使用。

指定EIP实例

您可以通过指定EIP实例ID的方式绑定已有的EIP。Pod Annotation不会对EIP实例配置进行修改,仅将EIP绑定到指定的Pod。

重要

此功能不适用于多副本类型的控制器,请确保EIP实例只有一个Pod引用。建议您仅在有状态应用Statefulset中使用。

Pod Annotations

value

k8s.aliyun.com/pod-eip-instanceid

使用指定的EIP,请填写EIP实例ID,例如:eip-bp14qxxxxxxx

重要

请避免将相同EIP实例分配到不同名称的Pod上。EIP控制器会在Pod退出后处理EIP解绑,在此期间,您不能在新容器内使用相同的EIP实例。您可以通过检查和Pod同名的Pod EIP资源是否存在,来判断Pod和EIP解绑是否完成。

k8s.aliyun.com/eci-eip-instanceid(兼容)

设置EIP回收策略的Annotation介绍

固定EIP可以保证Pod重建后依然使用之前的EIP地址。该策略可与自动分配EIP能力结合,用于有状态应用的固定EIP。

重要
  • 此能力仅在ack-extend-network-controller中支持,且仅适用于有状态类型的副本控制器,您无法为无状态类型的控制器使用。

  • 指定EIP实例ID,不会释放EIP实例。

Pod Annotation

value

k8s.aliyun.com/pod-eip-release-strategy

Pod EIP的回收策略。取值:

  • Follow:默认值,跟随Pod生命周期。

  • Never:不删除Pod EIP。当不需要时需要手动删除这个Pod EIP。

可直接配置过期时间,例如:5m30s,表示Pod删除5.5分钟后删除Pod EIP。支持Go类型时间表达式。

在ack-extend-network-controller或Terway集群中启用EIP

在ack-extend-network-controller中启用

说明

ack-extend-network-controller需要访问阿里云OpenAPI来创建资源,您需要在RAM中配置相应的权限。然后再在应用市场中安装ack-extend-network-controller,并通过Annotation为指定Pod创建和关联EIP。

通过Annotation为指定Pod创建和关联EIP

通过指定Pod中的Annotation可以创建或关联EIP到此Pod中。关于Annotation的详细信息,请参见下文常见问题

  1. 创建应用,并为指定Pod创建和关联EIP。

    无状态应用

    使用如下示例创建一个Deployment控制器,为每个Pod自动分配一个EIP实例,实例带宽为5 Mbps。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example
      labels:
        app: example
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: example
      template:
        metadata:
          labels:
            app: example
          annotations:
            k8s.aliyun.com/pod-with-eip: "true"
            k8s.aliyun.com/eip-bandwidth: "5"
        spec:
          readinessGates:
          - conditionType: "k8s.aliyun.com/eip"
          containers:
          - name: example
            image: nginx

    Pod创建成功后,执行以下命令,访问Pod同名的资源podeips.alibabacloud.com,跟踪分配的EIP信息。

    kubectl get podeip -n <namespace> <podname>  -o yaml

    预期输出:

    apiVersion: alibabacloud.com/v1beta1
    kind: PodEIP
    metadata:
      creationTimestamp: "2023-12-15T04:25:37Z"
      finalizers:
      - podeip-controller.alibabacloud.com/finalizer
      generation: 1
      name: example-xxx
      namespace: default
      resourceVersion: "222800"
      uid: 43xxx-f1xx-4xxx-b3xx-969faxxx
    spec:
      allocationID: eip-2ze2qe8zsxxx
      allocationType:
        releaseStrategy: Follow
        type: Auto
    status:
      eipAddress: 39.102.XX.XX
      internetChargeType: PayByTraffic
      isp: BGP
      networkInterfaceID: eni-2zeagv8f3xxxx
      podLastSeen: "2023-12-15T05:18:47Z"
      privateIPAddress: 192.168.XX.XX
      resourceGroupID: rg-acfmwxxxxxsq
      status: InUse

    有状态应用

    使用如下示例创建一个StatefulSet资源,创建两个Pod,并为每个Pod自动分配一个EIP实例,并设置回收策略为Pod删除10分钟后删除PodEIP。

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: example
      labels:
        app: example
    spec:
      serviceName: "example"
      replicas: 2
      selector:
        matchLabels:
          app: example
      template:
        metadata:
          labels:
            app: example
          annotations:
            k8s.aliyun.com/pod-with-eip: "true"
            k8s.aliyun.com/pod-eip-release-strategy: "10m"
        spec:
          containers:
          - name: example
            image: nginx

    Pod创建成功后,执行以下命令访问Pod同名的资源podeips.alibabacloud.com,跟踪分配的EIP信息。

    kubectl get podeip -n <namespace> -o yaml

    预期输出:

    apiVersion: v1
    items:
    - apiVersion: alibabacloud.com/v1beta1
      kind: PodEIP
      metadata:
        creationTimestamp: "2023-12-15T03:28:01Z"
        finalizers
        - podeip-controller.alibabacloud.com/finalizer
        generation: 1
        name: example-0
        namespace: default
        resourceVersion: "227221"
        uid: 79954xx-17xx-4dxx-b7xx-15b84xxx
      spec:
        allocationID: eip-2ze08metxxx
        allocationType:
          releaseAfter: 10m
          releaseStrategy: TTL
          type: Auto
      status:
        eipAddress: 39.105.XX.XX
        internetChargeType: PayByTraffic
        isp: BGP
        networkInterfaceID: eni-2ze4tkg4xxx
        podLastSeen: "2023-12-15T05:31:34Z"
        privateIPAddress: 192.168.XX.XX
        resourceGroupID: rg-acfmwxxx
        status: InUse
    - apiVersion: alibabacloud.com/v1beta1
      kind: PodEIP
      metadata:
        creationTimestamp: "2023-12-15T03:28:03Z"
        finalizers:
        - podeip-controller.alibabacloud.com/finalizer
        generation: 1
        name: example-1
        namespace: default
        resourceVersion: "227222"
        uid: 1339xxxe7-97xx-46xx-9bxx-537690xxx
      spec:
        allocationID: eip-2zetwhffqxxx
        allocationType:
          releaseAfter: 10m
          releaseStrategy: TTL
          type: Auto
      status:
        eipAddress: 39.105.XX.XX
        internetChargeType: PayByTraffic
        isp: BGP
        networkInterfaceID: eni-2zeagv8f3wxxx
        podLastSeen: "2023-12-15T05:31:34Z"
        privateIPAddress: 192.168.XX.XX
        resourceGroupID: rg-acfmwqnwxxx
        status: InUse
    - apiVersion: alibabacloud.com/v1beta1
      kind: PodEIP
      metadata:
        creationTimestamp: "2023-12-15T04:25:37Z"
        finalizers:
        - podeip-controller.alibabacloud.com/finalizer
        generation: 1
        name: example-5bxxx-9xx
        namespace: default
        resourceVersion: "227220"
        uid: 43cdfxxx-f1xx-42xx-b3xx-969fxxx
      spec:
        allocationID: eip-2ze2qe8zsmnxxx
        allocationType:
          releaseStrategy: Follow
          type: Auto
      status:
        eipAddress: 39.102.XX.XX
        internetChargeType: PayByTraffic
        isp: BGP
        networkInterfaceID: eni-2zeagv8f3wxxx
        podLastSeen: "2023-12-15T05:31:34Z"
        privateIPAddress: 192.168.XX.XX
        publicIpAddressPoolID: pippool-2ze498cxxx
        resourceGroupID: rg-acfmwqnxxx
        status: InUse
    kind: List
    metadata:
      resourceVersion: ""

    此有状态应用的Pod删除后,PodEIP CR会保留10分钟后再删除,在此期间创建的同名称Pod,将继续使用相应的EIP。

  2. 验证配置。

    当Pod变成Running状态之后,可以观察部署后的Pod中Annotations k8s.aliyun.com/allocated-eipAddress的值来查看它分配到的关联EIP地址,通过该EIP即可访问到Pod。

    image.png

在Terway中启用

  1. 部署Terway配置以支持EIP功能。

    1. 执行以下命令修改Terway的配置ConfigMap。

      kubectl edit cm eni-config -n kube-system
    2. eni_conf中增加以下内容。

      "enable_eip_pool": "true"
      说明

      如果您希望在指定EIP的时候能够强制解绑之前的实例,还需要在eni_conf中增加参数"allow_eip_rob": "true"

    3. 修改完成后,按Esc键,输入:wq!并按Enter键,保存修改后的配置文件并退出编辑模式。

    4. 执行以下命令重建Terway实例。

      kubectl delete pod -n kube-system -l app=terway-eniip # 如果您安装的是terway-eni组件,请将terway-eniip换成terway-eni。
  2. 通过Annotation为Pod创建和关联EIP。

    通过指定Pod中的Annotation可以创建或关联EIP到此Pod中。EIP的使用限制,请参见使用限制

    根据不同场景,配置注解方式如下:

  3. 自动分配EIP场景

    添加以下注解,为Pod自动分配EIP,并指定EIP的带宽。

    • k8s.aliyun.com/pod-with-eip: "true":为目标Pod分配一个独立的公网EIP。

    • k8s.aliyun.com/eip-bandwidth: "5":指定EIP的带宽,默认带宽为5 Mbps(与EIP的默认值保持一致)。

    示例YAML如下。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment-basic
      labels:
        app: nginx
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          annotations:
            k8s.aliyun.com/pod-with-eip: "true" # 为Nginx容器自动分配公网EIP地址。
            k8s.aliyun.com/eip-bandwidth: "5"   # 指定EIP的带宽,默认带宽为5 Mbps(与EIP的默认值保持一致)。
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx

    指定EIP场景

    重要
    • 由于单个EIP不支持关联多个Pod,所以不适用于Deployment和StatefulSet等场景。

    • 默认情况下,如果EIP已经绑定了实例,则会创建EIP失败。如果希望解绑之前的实例再绑定新的实例,需要在上述修改ConfigMap中配置"allow_eip_rob": "true"

    • 指定EIP实例ID的场景只能用于单个副本实例的情况。例如,Deployment不能超过1个Replicas。

    添加以下注解,为Pod指定EIP实例ID:

    k8s.aliyun.com/pod-eip-instanceid: "<youreipInstanceId>"
  4. 验证配置。

    当Pod变成Running状态之后,可以观察部署完后的Pod中Annotations k8s.aliyun.com/allocated-eipAddress的值来查看它分配到的关联EIP地址,通过该EIP即可访问到Pod。

常见问题

为什么Pod会变为Ready状态?

控制器会在Pod IP分配后,为Pod配置EIP地址,Pod Ready状态可能早于EIP绑定成功时间。您可以尝试使用下面的方式来控制Pod Ready状态。

为Pod配置Readiness gates

说明

为Pod配置Readiness gates仅在ack-extend-network-controller中支持。

当在Pod中配置完readinessGates,并且绑定EIP成功后,控制器会设置Pod conditions。在EIP未绑定前,Pod不会处于Ready状态。

kind: Pod
...
spec:
  readinessGates:
  - conditionType: "k8s.aliyun.com/eip"
status:
  conditions:
  - lastProbeTime: "2022-12-12T03:45:48Z"
    lastTransitionTime: "2022-12-12T03:45:48Z"
    reason: Associate eip succeed
    status: "True"
    type: k8s.aliyun.com/eip
...

为Pod配置init Container

为Pod配置init Container,在init Container中检查EIP是否已经分配成功。您可以参考以下示例配置init Container。

apiVersion: v1
kind: Pod
metadata:
  name: example
  annotations:
    k8s.aliyun.com/pod-with-eip: "true"
spec:
  containers:
  - name: example
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init
    image: busybox:1.28
    command: ['timeout', '-t' ,'60', 'sh','-c', "until grep -E '^k8s.aliyun.com\\/allocated-eipAddress=\\S?[0-9]+\\S?' /etc/podinfo/annotations; do echo waiting for annotations; sleep 2; done"]
    volumeMounts:
      - name: podinfo
        mountPath: /etc/podinfo
  volumes:
    - name: podinfo
      downwardAPI:
        items:
          - path: "labels"
            fieldRef:
              fieldPath: metadata.labels
          - path: "annotations"
            fieldRef:
              fieldPath: metadata.annotations