跳到主要内容

Pod 绑 EIP

腾讯云容器服务 TKE 支持为 Pod 绑定 EIP,参考官方文档 Pod 直接绑定弹性公网 IP 使用说明

本文用更通俗的语言描述下在 TKE 环境如何为 Pod 绑定 EIP。

EIP 授权

集群中的 ipamd 组件通过调用相关云 API 为 Pod 分配 EIP,需要 ipamd 有相关的权限,具体授权方法:

  1. 角色列表 页面找到 IPAMDofTKE_QCSRole 这个角色,点进去。
  2. 点击关联策略:
  3. 选择 QcloudAccessForIPAMDRoleInQcloudAllocateEIP 进行关联:

标准集群与 Serverless 集群

TKE 的集群有标准集群与 Serverless 集群之分,两种类型集群为 Pod 配置 EIP 方式是不一样的。

Serverless 集群的能力现已与融入到标准集群中,未来将不存在 Serverless 集群类型。

注意
  1. 如果您使用标准集群,不管 Pod 在超级节点与否,统一都使用标准集群写法即可。
  2. 如果您的存量 Serverless 集群需使用 EIP,查看 YAML 示例时注意选择 Serverless 集群版本的写法。

如何为 Pod 绑 EIP ?

为 Pod 加 eip-attributes 注解以声明需要绑定 EIP,值为 JSON 格式,填写创建 EIP 接口的相关的参数,详细参数列表可参考 这里

YAML 写法示例:

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
annotations:
tke.cloud.tencent.com/networks: "tke-route-eni" # 如果集群网络是 GlobalRouter + VPC-CNI 混用,用此注解需要显式指定 Pod 使用 VPC-CNI
# 指定 EIP 属性,具体字段参考 CLB 的 AllocateAddresses 接口文档:https://cloud.tencent.com/document/api/215/16699#2.-.E8.BE.93.E5.85.A5.E5.8F.82.E6.95.B0
tke.cloud.tencent.com/eip-attributes: '{"Bandwidth":"100", "ISP":"BGP", "InternetMaxBandwidthOut":50, "InternetChargeType":"TRAFFIC_POSTPAID_BY_HOUR"}'
spec:
containers:
- name: nginx
image: nginx:latest
resources: # 声明 EIP 资源,用于调度 (节点能绑定的 EIP 数量有限)
limits:
tke.cloud.tencent.com/eni-ip: "1"
tke.cloud.tencent.com/eip: "1"
requests:
tke.cloud.tencent.com/eni-ip: "1"
tke.cloud.tencent.com/eip: "1"

如果是 TKE 标准集群,要求 Pod 使用 VPC-CNI 网络模式(参考这里的前提条件和限制)。

如何保留 EIP ?

如果希望 Pod 重建后能复用重建之前的 EIP,需要在创建集群的时候启用 固定 Pod IP 并设置 IP 回收策略:

Pod 被删除后 EIP 会被释放,EIP 在未绑定状态下会产生费用(在和Pod绑定时EIP不计费),这个 IP 回收策略 配置的是 EIP 回收的时间阈值,EIP 在未绑定状态超过该时间阈值就会被销毁,避免因某些问题导致 EIP 长时间处于未绑定状态而产生更多额外费用。

那如何声明让 Pod 保留 EIP 呢?

首先需要使用 StatefulSet 部署或其它第三方有状态工作负载(如 OpenKruiseAdvanced StatefulSetOpenKruiseGameGameServerSet)。

为什么要用有状态工作负载才可以?因为有状态工作负载的 Pod 名称有序号,可通过 Pod 名称与 EIP 的关联关系实现固定 EIP,无状态的 Pod 就无法实现了。

下面是保留 EIP 的 YAML 示例:

apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
serviceName: ""
template:
metadata:
annotations:
tke.cloud.tencent.com/networks: "tke-route-eni" # 如果集群网络是 GlobalRouter + VPC-CNI 混用,用此注解需要显式指定 Pod 使用 VPC-CNI
# 指定 EIP 属性,具体字段参考 CLB 的 AllocateAddresses 接口文档:https://cloud.tencent.com/document/api/215/16699#2.-.E8.BE.93.E5.85.A5.E5.8F.82.E6.95.B0
tke.cloud.tencent.com/eip-attributes: '{"Bandwidth":"100", "ISP":"BGP", "InternetMaxBandwidthOut":50, "InternetChargeType":"TRAFFIC_POSTPAID_BY_HOUR"}'
tke.cloud.tencent.com/eip-claim-delete-policy: "Never"
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
resources:
limits:
tke.cloud.tencent.com/eni-ip: "1"
tke.cloud.tencent.com/eip: "1"
requests:
tke.cloud.tencent.com/eni-ip: "1"
tke.cloud.tencent.com/eip: "1"

如何在容器内获取自身公网 IP ?

可以利用 K8S 的 Downward API ,将 Pod 上的一些字段注入到环境变量或挂载到文件,Pod 的 EIP 信息最终会写到 Pod 的 tke.cloud.tencent.com/eip-public-ip 这个 annotation 上,但不会 Pod 创建时就写上,是在启动过程写上去的,所以如果注入到环境变量最终会为空,挂载到文件就没问题,以下是使用方法:

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
annotations:
tke.cloud.tencent.com/networks: "tke-route-eni" # 如果集群网络是 GlobalRouter + VPC-CNI 混用,用此注解需要显式指定 Pod 使用 VPC-CNI
# 指定 EIP 属性,具体字段参考 CLB 的 AllocateAddresses 接口文档:https://cloud.tencent.com/document/api/215/16699#2.-.E8.BE.93.E5.85.A5.E5.8F.82.E6.95.B0
tke.cloud.tencent.com/eip-attributes: '{"Bandwidth":"100", "ISP":"BGP", "InternetMaxBandwidthOut":50, "InternetChargeType":"TRAFFIC_POSTPAID_BY_HOUR"}'
spec:
containers:
- name: nginx
image: nginx:latest
resources: # 声明 EIP 资源,用于调度 (节点能绑定的 EIP 数量有限)
limits:
tke.cloud.tencent.com/eni-ip: "1"
tke.cloud.tencent.com/eip: "1"
requests:
tke.cloud.tencent.com/eni-ip: "1"
tke.cloud.tencent.com/eip: "1"
command:
- sleep
- infinity
volumeMounts:
- mountPath: /etc/podinfo # 容器内读取 /etc/podinfo/eip 可获取当前 Pod EIP 信息
name: podinfo
volumes:
- name: podinfo
downwardAPI:
items:
- path: "eip" # 关键
fieldRef:
fieldPath: metadata.annotations['tke.cloud.tencent.com/eip-public-ip']

容器内进程启动时可以读取 /etc/podinfo/eip 中的内容来获取 EIP。

常见问题:EIP 分配失败

Pod EIP 分配失败,tke.cloud.tencent.com/eip-public-ip 注解没有被自动打上,Pod 内无法通过 Downward API 获取自身 EIP。

Pod 事件报错:

  Warning  FailedAllocateEIP  4m58s  tke-eni-ipamd      Failed to create eip: failed to allocate eip: [TencentCloudSDKError] Code=UnauthorizedOperation, Message="[request id:********-****-****-****-************]you are not authorized to perform operation (cvm:AllocateAddresses)\nresource (qcs::cvm:ap-guangzhou:uin\/1000******04:eip\/*) has no permission\n"., RequestId=********-****-****-****-************

原因是没正确为 ipamd 组件授权,需按照 EIP 授权 步骤进行操作。

参考资料