通过配置注解为Pod挂载EIP

ACS集群中,PodIP地址默认是私有IP地址。但在某些场景(多租户隔离或安全隔离场景等)下,Pod可能需要一个独立的公网IP地址,使得Pod可以独立地与外部网络通信。本文介绍如何通过配置注解为ACS集群中的Pod挂载独立的EIP。

背景信息

一般情况下,Pod访问公网的流量是通过公网NAT网关的方式实现,详情请参见为集群开启公网访问能力。对于Pod的公网入口流量,一般是通过LoadBalancer类型的Service流入。在一些特殊场景中Pod需要独立的公网地址,例如:

  • 动态端口需求:如UDP游戏服务器或RTSP协议需为不同客户端分配随机端口,配置独立IP以避免端口冲突。

  • 避免SNAT限制:Pod调用外部服务时,若服务要求固定IP白名单,共享SNAT的出口IP会被封禁。

  • 直接IP标识需求:需通过独立IP与外部系统建立端到端连接(如实时通信协议)。

使用限制

  • 在使用弹性公网IP(Elastic IP Address,简称EIP)前,请先了解EIP使用限制

  • 如果您使用自动分配EIP能力,在Pod重建、CNI执行失败等情况下,可能会反复申请、释放EIP资源,这种情况下,可能会触发EIP使用限制。如果您想避免这种情况,可以通过配置Pod Annotationnetwork.alibabacloud.com/allocated-eip-idPod指定EIP。

操作流程

Pod挂载EIP,需要为集群安装ack-extend-network-controller组件,您可以在组件管理中进行安装。具体的步骤流程如下:

image

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

说明

开始安装前,请确认是否已经通过Helm或者ACK应用市场安装过组件。如有请先卸载。

  1. 登录容器计算服务控制台,在左侧导航栏选择集群列表

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择运维管理组件管理

  3. 在页面搜索框中搜索ack-extend-network-controller,在结果中单击组件卡片右下角的安装

    image

  4. 根据以下内容,在弹出框中进行配置。完成后单击确定

    参数名称

    功能说明

    enableControllers

    配置启用功能:

    • eip:启用EIP功能。

    • ipv6gw: 启用IPv6功能。

    • natgw:启用DNAT网关功能。

    eipipv6gw功能默认勾选,可以直接启用,无需配置 RAM 权限。

    使用natgw需配置RAM权限,请按照配置DNAT所需的RAM权限进行配置。

    natGwPool

    DNAT配置。

    customStatefulWorkloadKinds

    自定义有状态容器类型。默认支持K8s StatefulSet和直接创建的Pod。若您有其他容器类型需要使用EIP,请单击+ 添加

步骤二:启用EIP功能

ACS支持使用Annotation的方式启用EIP功能,通过指定Pod中的annotations可以创建或者关联EIPPod中。关于启用EIP功能注解的详细内容,请参见启用EIPAnnotation介绍

说明

您可以按需选择自动分配EIP或者指定EIP实例的方式。这两种方式除了使用的Annotation不同之外,在EIP回收策略上也有不同。对于指定EIP实例的方式,删除Pod不会释放EIP实例,而自动分配EIP的方式则默认释放EIP实例。EIP回收策略的详细信息,请参见设置EIP回收策略的Annotation介绍

自动分配EIP

  1. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 无状态

  2. 在页面右上方,单击使用YAML创建资源

  3. 使用如下YAML示例创建一个名为example的无状态工作负载。

    展开查看Deployment YAML

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example
      labels:
        app: example
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: example
      template:
        metadata:
          labels:
            app: example
          annotations:
            network.alibabacloud.com/pod-with-eip: "true"
            network.alibabacloud.com/eip-bandwidth: "5"
        spec:
          containers:
          - name: example
            image: registry.cn-hangzhou.aliyuncs.com/acs-sample/nginx:latest
            ports:
            - containerPort: 80

    其中的annotations部分表示为每个Pod自动分配一个EIP实例,并且实例带宽为5 Mbps。

  4. 创建成功后,进入名为exampleDeployment。点击Pod名称(例如:example-78d17b7xxx-adxxx)进入Pod详情页面,在页面注解部分查看创建出的EIP信息。您也可以点击编辑,在Pod YAML中查看创建出的EIP信息。

    展开查看Pod YAML

    apiVersion: v1
    kind: Pod
    metadata:
      annotations:
        ...
        network.alibabacloud.com/allocated-eip-id: eip-xxxxx0y884ucrevoxxxxx
        network.alibabacloud.com/allocated-eipAddress: xxx.xxx.xxx.xxx
        network.alibabacloud.com/allocated-eni-id: eni-xxxxx563trofuhaxxxxx
        network.alibabacloud.com/eip-bandwidth: '5'
        network.alibabacloud.com/pod-with-eip: 'true'
        ...
      labels:
        alibabacloud.com/compute-class: general-purpose
        app: example
      name: example-78d17b7xxx-adxxx
      namespace: default
    spec:
      ...
  5. 完成示例后,删除名为exampleDeployment。由于在没有指定Pod EIP实例ID的情况下,Pod EIP的默认回收策略是跟随Pod生命周期。因此当Pod被删除后,EIP会自动释放。

指定EIP实例

  1. 准备示例使用的EIP实例,请先申请EIP

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 >有状态

  3. 在页面右上方,单击使用YAML创建资源

  4. 使用如下YAML示例创建一个名为example的有状态工作负载。

    展开查看StatefulSet YAML

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      labels:
        app: example
      name: example
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: example
      template:
        metadata:
          labels:
            app: example
          annotations:
            network.alibabacloud.com/pod-eip-instanceid: eip-xxxxx66wjkj16lf9xxxxx
        spec:
          containers:
          - name: example
            image: registry.cn-hangzhou.aliyuncs.com/acs-sample/nginx:latest
            ports:
            - containerPort: 80

    其中的annotations部分表示为Pod指定一个实例IDeip-xxxxx66wjkj16lf9xxxxxEIP实例,该实例ID需要替换成实际的值。

  5. 创建成功后,进入名为exampleStatefulSet。点击Pod名称(例如:example-0)进入Pod详情页面,在页面右侧注解部分查看已绑定的EIP实例信息。您也可以点击编辑,在Pod YAML中查看已绑定的EIP实例信息。

    展开查看Pod YAML

    apiVersion: v1
    kind: Pod
    metadata:
      annotations:
        ...
        network.alibabacloud.com/allocated-eip-id: eip-xxxxx66wjkj16lf9xxxxx
        network.alibabacloud.com/allocated-eipAddress: xxx.xxx.xxx.xxx
        network.alibabacloud.com/allocated-eni-id: eni-xxxxx612ub33hunxxxxx
        network.alibabacloud.com/pod-eip-instanceid: eip-xxxxx66wjkj16lf9xxxxx
        ...
      labels:
        alibabacloud.com/compute-class: general-purpose
        app: example
      name: example-0
      namespace: default
    spec:
      ...
  6. 完成示例后,删除名为exampleStatefulSet。由于在指定Pod EIP实例ID的情况下,Pod EIP的回收策略是不释放EIP实例。因此当Pod被删除后,EIP不会自动释放。

相关操作

控制器会在Pod IP分配后,为Pod配置EIP地址,在这个过程中Pod可能在EIP绑定成功前进入Ready状态。您可以尝试使用以下方式来解决这类问题,确保Pod在进入服务可用状态之前已完成EIP的绑定,避免可能出现的服务中断或者连接超时等情况。

使用Readiness gates检查EIP绑定状态

当在Pod中配置readinessGates,并且绑定EIP成功后,控制器会设置Podconditions。在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
...

使用initContainers检查EIP绑定状态

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

apiVersion: v1
kind: Pod
metadata:
  name: example
  annotations:
    network.alibabacloud.com/pod-with-eip: "true"
spec:
  containers:
  - name: example
    image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init
    image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/busybox:1.28
    command: ['timeout', '-t' ,'60', 'sh','-c', "until grep -E '^k8s.aliyun.com\\/pod-ips=\\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

配置DNAT所需的RAM权限

DNAT功能依赖于ack-extend-network-controller访问阿里云OpenAPI来创建资源,您需要在RAM中配置相应的权限。

  1. 登录RAM控制台在左侧导航栏中单击权限策略,单击创建权限策略

  2. 创建权限策略页面单击脚本编辑,将以下内容粘贴至代码区域的Statement中,单击确定,配置策略名称DNAT-Policy,再次单击确定

    {
          "Effect": "Allow",
          "Action": [
            "ecs:DescribeNetworkInterfaces",
            "vpc:DescribeNatGateways",
            "vpc:DescribeForwardTableEntries",
            "vpc:CreateForwardEntry",
            "vpc:DescribeEipAddresses",
            "vpc:DeleteForwardEntry",
            "vpc:DescribeRouteTableList",
            "vpc:DescribeRouteEntryList"
          ],
          "Resource": [
            "*"
          ],
          "Condition": {}
        }
  3. 单击左侧导航栏中的角色,在搜索栏中搜索AliyunCCNECRole,在操作列单击新增授权

  4. 权限策略部分的搜索栏中搜索并勾选DNAT-Policy,单击确认新增授权