IT技术博客大学习 共学习 共进步

Ack集群Pod独占EIP实践

山山仙人博客 2026-06-03 09:03:23 累计浏览 2 次
本机暂存

1. 背景

某线上应用部署在ack集群内,用于根据用户定义的http请求项配置,周期性检查http接口的请求响应状态,接口地址为内网或公网,当接口地址为公网时,频繁出现请求超时的报警错误。经过排查发现,在公网请求发生超时的时刻,集群vpc NAT带宽达到上限200Mbps,也就是25MB/s

原图已失效

分析:由于集群占用vpcvpc内所有ip(node和pod的ip)都属于vpc内各子网地址,这些地址出公网的请求共用vpc绑定的公网NAT,在某时刻子网ip请求公网使用的EIP是随机的,无法控制,会产生和其他ip同时请求公网使用同一个EIP的情况,由此发生了带宽内拥挤,超限的情况,因此上述超时报警其实是客户端带宽不够产生的误报

2. 解决方案

为了避免发生上述情况,解决办法是避免这些特定的pod请求公网时和其他ip发生公网带宽的争抢,走独立的公网出口,有以下两种方案:

  • 方案一

将这些pod调度到特定的子网nodenodeippodip会使用特定的子网,这个特定的子网由于在特定的vSwitch虚拟交换机下,因此可以为这个子网单独指定路由条目,也就是将请求公网地址的请求的下一跳路由到特定的公网NAT,特定的公网NAT使用特定的EIP且不和其他子网共用

  • 方案二

ack集群的网络使用的是阿里云Terway,在此前提下,阿里云提供了为Terway网络中的Pod挂载独立的公网EIP的解决方案,具体可以查看文档说明,简单来说就是阿里云提供了集群内的控制器,实现了通过k8s原生的声明式配置,调用EIP产品相关api动态为pod绑定EIP的功能

3. 方案选取和实现

方案一,改动较大,需要将pod调度到特定的node上,且需要人工维护路由条目,维护性较差;
方案二,更为直接,在安装控制器插件后,通过给pod添加特定注解实现目的,主要分为两种方式:

  • 一种是根据声明式配置动态随机购买EIP
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"  # 自动创建并绑定EIP
        k8s.aliyun.com/eip-bandwidth: "200"  # EIP峰值带宽
        k8s.aliyun.com/eip-internet-charge-type: "PayByTraffic" # EIP的计量方式
        k8s.aliyun.com/eip-instance-charge-type: "PostPaid"  # EIP的计费方式
        k8s.aliyun.com/eip-name: "app-eip"  # EIP名称
        k8s.aliyun.com/eip-description: "app-eip"  # EIP描述
  • 一种是先购买EIP,pod注解中声明EIP的id
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-eip-instanceid: eip-2zeXXXXXx  # EIP ID

3.1 配置RAM策略并安装插件

按照文档操作,配置挂载EIP所需的RAM权限
安装插件ack-extend-network-controller,安装时启用插件pod eip的能力,一键安装即可

原图已失效

3.2 购买EIP

由于业务目前只有1pod,为了后续排查方便,选择通过先购买EIP再根据EIP id绑定的方式
购买EIP,按量付费,带宽上限为200Mbps

原图已失效

3.3 为pod添加注解

deploymentyaml中为pod添加注解,根据EIP id绑定这个EIP即可

spec:
  template:
    metadata:
      annotations:
        k8s.aliyun.com/pod-eip-instanceid: eip-xxx

绑定后效果

  • 集群cr

控制器会自动创建一个和pod名称相同的PodEIPcr,从这个crstatus中可以看到和上面购买的EIP相关的信息

~ kubectl get pods -o wide|grep app
app-79dcf755fb-ks2ld                                       1/1     Running             0                47h     10.245.36.4      ack-010245035222packets-spot       <none>           1/1
~ kubectl get podeips app-79dcf755fb-ks2ld -o yaml
apiVersion: alibabacloud.com/v1beta1
kind: PodEIP
metadata:
  creationTimestamp: "2024-04-01T07:55:46Z"
  finalizers:
  - podeip-controller.alibabacloud.com/finalizer
  generation: 1
  name: app-79dcf755fb-ks2ld
  namespace: dev
  resourceVersion: "2389078403"
  uid: 292773d3-80b4-4c88-b0ef-17f011a1530e
spec:
  allocationID: eip-xxxxx
  allocationType:
    releaseStrategy: Follow
    type: Static
status:
  eipAddress: 101.xxx.xxx.5
  internetChargeType: PayByTraffic
  isp: BGP
  name: app独享
  networkInterfaceID: eni-2zexxxxxxxqvrrpxxx
  podLastSeen: "2024-04-01T07:39:39Z"
  privateIPAddress: 10.xxx.36.4
  resourceGroupID: rg-xxxxx5afyhf3xky
  status: InUse
  • EIP绑定情况,与从集群查看cr得到的状态一致
原图已失效

3.4 其他说明

以上实现了pod绑定特定EIP的功能,在此条件下,pod请求公网时会固定为此eip出公网,为了保障配置的稳定,经过测试,上面提到此业务pod只有一个副本,且通过deployment管理,属于无状态应用,只做上面为pod添加注解的方式会有以下问题

3.4.1 如何控制当pod状态变为ready后才绑定EIP?

控制器会在Pod IP分配后,为Pod配置EIP地址,Pod Ready状态可能早于EIP绑定成功时间。解决办法是为pod添加就绪前的检测

  • 一种方式是为Pod配置Readiness gates
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,在init container中检查EIP是否已经分配成功
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

3.4.2 如何控制pod更新时,EIP始终只绑定了一个pod?

pod如果发生了滚动更新,且pod在配置有探针的情况下,可以保障始终只有一个pod接收流量,但是无法保证EIP的正常绑定,因为发布过程中有两个pod同时绑定了这个EIP,新pod启动后,老的pod下线调用了解绑EIP的动作,EIP绑定是需要调用接口到vpc去绑定,只有绑定了这个EIP pod的后续探针才会ready。在新pod滚动更新的过程中,会重新绑定EIP,但是旧pod的回收,又会卸载绑定这个EIP

这里EIP当做了创建pod所需的基础资源,实际上EIP并不是pod运行所必须的,解决办法:

  • A. 修改控制器实现支持在pod滚动更新结束后才将新的pod ipEIP绑定(下述C可以避免此问题)

  • B. 将pod的滚动更新模式修改为销毁重建Recreate,这样会损失一定流量

  • C. 控制器支持有状态应用的pod在一定时间内发生更新后仍然使用之前的EIP,因此把poddeployment改为statefulset,并声明pod在更新过程中仍然使用之前的EIP即可(固定EIP可以保证Pod重建后依然使用之前的EIP地址。该策略可与自动分配EIP能力结合,用于有状态应用的固定EIP

      annotations:
        k8s.aliyun.com/pod-with-eip: "true"
        k8s.aliyun.com/pod-eip-release-strategy: "10m"

结合现状,业务pod如果支持多副本模式,可以切换到statefulset并创建2个副本,有状态应用的滚动更新本身就是副本销毁和重新创建,在多副本的情况下不会有流量丢失。目前只有一个(暂不支持多副本模式),且可以接受在升级的过程中丢失一定的流量,在不改变原有的无状态应用属性的情况下,选择的解决办法为B

最终配置如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  strategy:
    type: Recreate
  template:
    metadata:
      annotations:
        k8s.aliyun.com/pod-eip-instanceid: eip-XXXXXXXlus72fax
    spec:
      readinessGates:
      - conditionType: "k8s.aliyun.com/eip"

3.4.3 pod绑定EIP后pod本身监听的端口是否也就通过EIP暴露?

pod由于没有通过NAT请求公网,是EIPPod IP(ecs 弹性辅助网卡)直接绑定,因此默认情况下,通过pod ip(vpc内网):端口可以直接访问到pod暴露的接口,通过eip(公网):端口也可以访问到,但是由于EIP绑定的是ecs的弹性辅助网卡,因此和ecs共用了一个安全组,ecs是集群node,只开放了集群子网间互通,因此这个问题已经规避

建议继续学习

  1. 大公司与风险管理 (累计阅读 5,242)
  2. Kubernetes – Google分布式容器技术初体验 (累计阅读 4,900)
  3. Twitter新员工的入职过程是怎样的? (累计阅读 4,541)
  4. “集群和负载均衡”的通俗版解释 (累计阅读 4,440)
  5. 云计算的技术架构与实现分析 (累计阅读 4,160)
  6. 中大型移动互联网公司技术架构选择 (累计阅读 4,061)
  7. 如何对待开发团队中那个拖后腿的人? (累计阅读 3,861)
  8. 互联网产业链分析【图】 (累计阅读 3,281)
  9. 70 后都跑哪去了? (累计阅读 3,201)
  10. 今年,我们二十七八岁 (累计阅读 3,181)