Pod 绑 EIP
腾讯云容器服务 TKE 支持为 Pod 绑定 EIP,参考官方文档 Pod 直接绑定弹性公网 IP 使用说明。
本文用更通俗的语言描述下在 TKE 环境如何为 Pod 绑定 EIP。
EIP 授权
集群中的 ipamd 组件通过调用相关云 API 为 Pod 分配 EIP,需要 ipamd 有相关的权限,具体授权方法:
- 在 角色列表 页面找到
IPAMDofTKE_QCSRole
这个角色,点进去。 - 点击关联策略:
- 选择
QcloudAccessForIPAMDRoleInQcloudAllocateEIP
进行关联:
标准集群与 Serverless 集群
TKE 的集群有标准集群与 Serverless 集群之分,两种类型集群为 Pod 配置 EIP 方式是不一样的。
Serverless 集群的能力现已与融入到标准集群中,未来将不存在 Serverless 集群类型。
- 如果您使用标准集群,不管 Pod 在超级节点与否,统一都使用标准集群写法即可。
- 如果您的存量 Serverless 集群需使用 EIP,查看 YAML 示例时注意选择 Serverless 集群版本的写法。
如何为 Pod 绑 EIP ?
为 Pod 加 eip-attributes
注解以声明需要绑定 EIP,值为 JSON 格式,填写创建 EIP 接口的相关的参数,详细参数列表可参考 这里 。
YAML 写法示例:
- 标准集群写法
- Serverless 集群写法
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"
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
annotations:
# 指定 EIP 属性,具体字段参考 CLB 的 AllocateAddresses 接口文档:https://cloud.tencent.com/document/api/215/16699#2.-.E8.BE.93.E5.85.A5.E5.8F.82.E6.95.B0
eks.tke.cloud.tencent.com/eip-attributes: '{"Bandwidth":"100", "ISP":"BGP", "InternetMaxBandwidthOut":50, "InternetChargeType":"TRAFFIC_POSTPAID_BY_HOUR"}'
spec:
containers:
- name: nginx
image: nginx:latest
如果是 TKE 标准集群,要求 Pod 使用
VPC-CNI
网络模式(参考这里的前提条件和限制)。
如何保留 EIP ?
如果希望 Pod 重建后能复用重建之前的 EIP,需要在创建集群的时候启用 固定 Pod IP
并设置 IP 回收策略
:
Pod 被删除后 EIP 会被释放,EIP 在未绑定状态下会产生费用(在和Pod绑定时EIP不计费),这个 IP 回收策略
配置的是 EIP 回收的时间阈值,EIP 在未绑定状态超过该时间阈值就会被销毁,避免因某些问题导致 EIP 长时间处于未绑定状态而产生更多额外费用。
那如何声明让 Pod 保留 EIP 呢?
首先需要使用 StatefulSet
部署或其它第三方有状态工作负载(如 OpenKruise
的 Advanced StatefulSet
、OpenKruiseGame
的 GameServerSet
)。
为什么要用有状态工作负载才可以?因为有状态工作负载的 Pod 名称有序号,可通过 Pod 名称与 EIP 的关联关系实现固定 EIP,无状态的 Pod 就无法实现了。
下面是保留 EIP 的 YAML 示例:
- 标准集群写法
- Serverless 集群写法
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"
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"}'
eks.tke.cloud.tencent.com/eip-claim-delete-policy: "Never" # 声明要保留 EIP(Pod 重建后保持 EIP 不变),仅支持有状态工作负载,如 StatefulSet
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 创建时 就写上,是在启动过程写上去的,所以如果注入到环境变量最终会为空,挂载到文件就没问题,以下是使用方法:
- 标准集群写法
- Serverless 集群写法
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']
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
annotations:
eks.tke.cloud.tencent.com/eip-attributes: '{"InternetMaxBandwidthOut":100, "InternetChargeType":"TRAFFIC_POSTPAID_BY_HOUR"}'
spec:
containers:
- name: nginx
image: nginx:latest
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['eks.tke.cloud.tencent.com/eip-attributes']
容器内进程启动时可以读取 /etc/podinfo/eip
中的内容来获取 EIP。