在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。
使用限制
在使用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权限
创建自定义权限策略,策略内容如下。具体操作,请参见步骤一:创建自定义权限策略。
{ "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": {} }
为集群的Worker RAM角色授权。具体操作,请参见步骤二:为集群的Worker RAM角色授权。
为ACK Serverless集群授予RAM权限
对于ACK Serverless集群,请为RAM用户生成访问密钥(AccessKey)。具体操作,请参见创建RAM用户、创建自定义权限策略。
Terway
Terway为Pod配置EIP需要EIP相关的权限来申请和配置EIP,所以需要部署额外的配置和权限。
为ACK托管集群或者2020年6月及之后创建的ACK集群基础版授予RAM权限
创建自定义权限策略,策略内容如下。具体操作,请参见步骤一:创建自定义权限策略。
{ "Effect": "Allow", "Action": [ "vpc:DescribeVSwitches", "vpc:AllocateEipAddress", "vpc:DescribeEipAddresses", "vpc:AssociateEipAddress", "vpc:UnassociateEipAddress", "vpc:ReleaseEipAddress", "vpc:AddCommonBandwidthPackageIp", "vpc:RemoveCommonBandwidthPackageIp" ], "Resource": [ "*" ], "Condition": {} }
为集群的Worker RAM角色授权。具体操作,请参见步骤二:为集群的Worker RAM角色授权。
为ACK专有版集群或者2020年06月之前创建的ACK托管集群授予RAM权限
创建自定义权限策略,策略内容如下。具体操作,请参见步骤一:创建自定义权限策略。
{ "Effect": "Allow", "Action": [ "vpc:DescribeVSwitches", "vpc:AllocateEipAddress", "vpc:DescribeEipAddresses", "vpc:AssociateEipAddress", "vpc:UnassociateEipAddress", "vpc:ReleaseEipAddress", "vpc:AddCommonBandwidthPackageIp", "vpc:RemoveCommonBandwidthPackageIp" ], "Resource": [ "*" ], "Condition": {} }
在RAM角色AliyunCSManagedNetworkRole页面的权限策略页签,单击新增授权,然后单击自定义策略,将上一步创建的自定义权限策略选中。
单击确定。
单击完成。
步骤二:为集群安装或升级插件
您不能同时启用ack-extend-network-controller与Terway的EIP配置能力,否则可能会使EIP资源重复分配,从而导致EIP绑定失败。推荐您使用ack-extend-network-controller插件。
插件对比
对比项 | ack-extend-network-controller | Terway |
支持的集群类型 |
|
|
固定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
登录容器服务管理控制台,在左侧导航栏选择 。
在应用市场页面的搜索栏中输入
ack-extend-network-controller
,然后单击目标应用。在应用详情页面,单击右上角的一键部署。
在创建面板中,选择集群和命名空间,然后单击下一步。
在参数配置页面,选择版本号并设置相应的参数,然后单击确定。
参数说明如下所示:
配置参数
类型
必填
描述
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。
enableVirtualNode
bool
否
是否支持ECI虚拟节点。
重要启用此配置后,控制器将为ECI实例的Pod分配EIP,您配置的Pod annotation不能和ECI所支持EIP功能相同,请谨慎使用。
enableRRSA
bool
否
通过RRSA方式进行鉴权。
说明ack-extend-network-controller插件版本为v0.10.0及以上支持。
仅支持ack-pod-identity-webhook注入方式配置RRSA,请为kube-system namesapce 配置对应label。配置内容请参考通过RRSA配置ServiceAccount的RAM权限实现Pod权限隔离。
rrsaRoleName
string
否
角色名称。
说明ack-extend-network-controller插件版本为v0.10.0及以上支持。
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 |
network.alibabacloud.com/pod-with-eip k8s.aliyun.com/pod-with-eip | 是否自动创建并绑定EIP。取值:
|
k8s.aliyun.com/eci-with-eip(兼容) | |
network.alibabacloud.com/eip-bandwidth k8s.aliyun.com/eip-bandwidth | EIP峰值带宽。单位:Mbps。更多信息,请参见申请EIP。 |
network.alibabacloud.com/eip-internet-charge-type k8s.aliyun.com/eip-internet-charge-type | EIP的计量方式。取值:
更多信息,请参见申请EIP。 说明
|
k8s.aliyun.com/eip-charge-type(兼容) | |
network.alibabacloud.com/eip-instance-charge-type k8s.aliyun.com/eip-instance-charge-type | EIP的计费方式,取值:
更多信息,请参见申请EIP。 说明 此Annotation仅在ack-extend-network-controller中支持。 |
network.alibabacloud.com/eip-common-bandwidth-package-id k8s.aliyun.com/eip-common-bandwidth-package-id | 绑定已有的共享带宽包。 说明 使用此Annotation,需要terway插件版本为v1.2.3及以上;对ack-extend-network-controller插件版本无限制。 |
network.alibabacloud.com/eip-isp k8s.aliyun.com/eip-isp | EIP的线路类型。取值:
更多信息,请参见申请EIP。 说明 使用此Annotation,需要terway插件版本为v1.2.3及以上;对ack-extend-network-controller插件版本无限制。 |
network.alibabacloud.com/eip-public-ip-address-pool-id k8s.aliyun.com/eip-public-ip-address-pool-id | EIP地址池。关于EIP地址池的使用限制、使用步骤等,请参见创建和管理IP地址池。 说明 此Annotation仅在ack-extend-network-controller中支持。 |
network.alibabacloud.com/eip-resource-group-id k8s.aliyun.com/eip-resource-group-id | EIP资源组。更多信息,请参见申请EIP。 说明 此Annotation仅ack-extend-network-controller插件版本为v0.4.0及以上支持使用。 |
network.alibabacloud.com/eip-name k8s.aliyun.com/eip-name | EIP名称。更多信息,请参见申请EIP。 说明 此Annotation仅ack-extend-network-controller插件版本为v0.6.0及以上支持使用。 |
network.alibabacloud.com/eip-description k8s.aliyun.com/eip-description | EIP描述。更多信息,请参见申请EIP。 说明 此Annotation仅ack-extend-network-controller插件版本为v0.6.0及以上支持使用。 |
network.alibabacloud.com/eip-security-protection-types k8s.aliyun.com/eip-security-protection-types | EIP安全防护级别,支持高防EIP(DDoS防护增强EIP)。若配置多个,请通过 说明 此Annotation仅ack-extend-network-controller插件版本为v0.9.0及以上支持使用。 |
指定EIP实例
您可以通过指定EIP实例ID的方式绑定已有的EIP。Pod Annotation不会对EIP实例配置进行修改,仅将EIP绑定到指定的Pod。
此功能不适用于多副本类型的控制器,请确保EIP实例只有一个Pod引用。建议您仅在有状态应用Statefulet中使用。
Pod Annotations | value |
network.alibabacloud.com/pod-eip-instanceid 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 |
network.alibabacloud.com/pod-eip-release-strategy k8s.aliyun.com/pod-eip-release-strategy | 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的详细信息,请参见下文常见问题。
创建应用,并为指定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。
验证配置。
当Pod变成Running状态之后,可以观察部署后的Pod中Annotations k8s.aliyun.com/allocated-eipAddress的值来查看它分配到的关联EIP地址,通过该EIP即可访问到Pod。
在Terway中启用
部署Terway配置以支持EIP功能。
执行以下命令修改Terway的配置ConfigMap。
kubectl edit cm eni-config -n kube-system
在eni_conf中增加以下内容。
"enable_eip_pool": "true"
说明如果您希望在指定EIP的时候能够强制解绑之前的实例,还需要在eni_conf中增加参数"allow_eip_rob": "true"。
修改完成后,按Esc键,输入:wq!并按Enter键,保存修改后的配置文件并退出编辑模式。
执行以下命令重建Terway实例。
kubectl delete pod -n kube-system -l app=terway-eniip # 如果您安装的是terway-eni组件,请将terway-eniip换成terway-eni。
通过Annotation为Pod创建和关联EIP。
通过指定Pod中的Annotation可以创建或关联EIP到此Pod中。EIP的使用限制,请参见使用限制。
根据不同场景,配置注解方式如下:
k8s.aliyun.com/pod-with-eip: "true"
:为目标Pod分配一个独立的公网EIP。k8s.aliyun.com/eip-bandwidth: "5"
:指定EIP的带宽,默认带宽为5 Mbps(与EIP的默认值保持一致)。由于单个EIP不支持关联多个Pod,所以不适用于Deployment和StatefulSet等场景。
默认情况下,如果EIP已经绑定了实例,则会创建EIP失败。如果希望解绑之前的实例再绑定新的实例,需要在上述修改ConfigMap中配置"allow_eip_rob": "true"。
指定EIP实例ID的场景只能用于单个副本实例的情况。例如,Deployment不能超过1个Replicas。
验证配置。
当Pod变成Running状态之后,可以观察部署完后的Pod中Annotations network.alibabacloud.com/allocated-eipAddress的值来查看它分配到的关联EIP地址,通过该EIP即可访问到Pod。
自动分配EIP场景
添加以下注解,为Pod自动分配EIP,并指定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:
network.alibabacloud.com/pod-with-eip: "true" # 为Nginx容器自动分配公网EIP地址。
network.alibabacloud.com/eip-bandwidth: "5" # 指定EIP的带宽,默认带宽为5 Mbps(与EIP的默认值保持一致)。
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
指定EIP场景
添加以下注解,为Pod指定EIP实例ID:
k8s.aliyun.com/pod-eip-instanceid: "<youreipInstanceId>"
常见问题
为什么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:
network.alibabacloud.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