在当今的技术环境下,越来越多的客户选择使用 Amazon Elastic Kubernetes Service(EKS)来部署和管理容器化的应用程序。在某些场景下,需要 Pod 有公网 IP 地址直接对外提供服务,例如在游戏场景中,游戏服、战斗服通过公网 IP 直接对外连接玩家;在电商平台独立站中,也可以满足独立站对于独享公网 IP 的需求。
对于部署在 Pod 中的应用,为 Pod 自动添加公网 IP 地址(EIP),就可以直接通过 Pod 的公网 IP 访问应用程序。本文实现了一个 Elastic IP Controller,您就可以通过注解的方式自动地将 EIP 附加到 Pod 上。
方案总览
解决方案通过以下步骤为 Pod 处理 EIP:
- Informers 通过 List 和 Watch 监听 Pod 事件
- Controller 将获取的事件中对应的 Pod key 推送到 WorkQueue
- Worker 从 WorkQueue 中获取到 Pod key 并从 Indexer 中获取到 Pod 的相关信息
- 根据 Pod 的注解信息,Worker 使用 AWS SDK 为 Pod 分配并关联 EIP 或将 EIP 分离并释放
先决条件
部署指南
创建 EKS 集群
设置当前账户和区域。
export ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account)
export AWS_REGION=<your-region>
注意:使用您的 EKS 集群所在区域进行替换<your-region>。
此命令将同时创建一个名为 main 的节点组,该节点组包含两个 m5.large 类型的实例,并将其部署到公共子网中。
cat << EOF > eip-demo-cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: eip-controller-demo
region: ${AWS_REGION}
version: "1.27"
iam:
withOIDC: true
managedNodeGroups:
- name: main
instanceType: m5.large
desiredCapacity: 2
privateNetworking: false
EOF
eksctl create cluster -f eip-demo-cluster.yaml
kubectl get nodes
构建镜像并推送到 Amazon Elastic Container Registry
创建 ECR 仓库并登录。
aws ecr create-repository --repository-name aws-pod-eip-controller \
--region ${AWS_REGION}
aws ecr get-login-password --region ${AWS_REGION} \
| docker login --username AWS \
--password-stdin ${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com
下载示例 Pod EIP controller 代码,构建镜像并推送到 ECR。
git clone https://github.com/aws-samples/aws-pod-eip-controller.git
cd aws-pod-eip-controller
git fetch
git switch blog
docker buildx build \
--tag ${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/aws-pod-eip-controller:latest \
--platform linux/amd64,linux/arm64 \
--push .
部署 Pod EIP Controller
创建控制器所需的 IAM 策略。
cat << EOF > iam-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ec2:AllocateAddress",
"ec2:AssociateAddress",
"ec2:CreateTags",
"ec2:ReleaseAddress",
"ec2:DisassociateAddress",
"ec2:DeleteTags",
"ec2:DescribeAddresses",
"ec2:DescribeNetworkInterfaces"
],
"Resource": "*"
}
]
}
EOF
aws iam create-policy \
--policy-name AWSPodEIPControllerIAMPolicy \
--policy-document file://iam-policy.json
创建一个 IAM 角色和 Kubernetes 服务账户供控制器使用。
eksctl create iamserviceaccount \
--cluster=eip-controller-demo \
--namespace=kube-system \
--name=aws-pod-eip-controller \
--attach-policy-arn=arn:aws:iam::${ACCOUNT_ID}:policy/AWSPodEIPControllerIAMPolicy \
--override-existing-serviceaccounts \
--region ${AWS_REGION} \
--approve
运行以下命令在您的环境中部署 Pod EIP controller。
cat << EOF > myvals.yaml
image: ${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/aws-pod-eip-controller
serviceAccountName: aws-pod-eip-controller
logLevel: DEBUG
clusterName: eip-controller-demo
vpcID: ""
region: ""
# set to empty string to watch all namespaces
watchNamespace: nginx-demo-ns
createServiceAccount: false
resyncPeriod: 0
EOF
helm install aws-pod-eip-controller charts/aws-pod-eip-controller \
-f myvals.yaml \
-n kube-system
kubectl get deployment -n kube-system
注意:具体配置参数可以在项目 aws-samples/aws-pod-eip-controller 中查看。
这条命令将在 kube-system 命名空间中创建 aws-pod-eip-controller 部署。
使用示例
运行以下命令在您的环境中部署 nginx 应用。
cat << EOF > nginx.demo.yaml
---
apiVersion: v1
kind: Namespace
metadata:
name: nginx-demo-ns
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-user
namespace: nginx-demo-ns
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: nginx-demo-ns
name: app-nginx-demo
labels:
app.kubernetes.io/name: app-nginx-demo
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: app-nginx-demo
template:
metadata:
labels:
app: app-nginx-demo
annotations:
aws-samples.github.com/aws-pod-eip-controller-type: auto
spec:
serviceAccountName: nginx-user
containers:
- image: nginx:1.20
imagePullPolicy: Always
name: nginx
ports:
- containerPort: 80
protocol: TCP
EOF
kubectl apply -f nginx.demo.yaml
运行以下命令查看 Pod 的名字。
kubectl get pods -n nginx-demo-ns
运行以下命令查看附加的弹性 IP。
kubectl get pods <your-pod-name> \
-o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,PODIP:.status.podIP,EIP:.metadata.labels.aws-pod-eip-controller-public-ip \
-n nginx-demo-ns \
-w
注意:需要将您实际的 nginx 的 Pod 的名称进行替换<your-pod-name>。
注意: 在这个 EIP 所在的安全组中,添加 80 端口的访问规则将允许您通过 EIP 访问 Pod。
清理环境
为避免收费,请删除您的 AWS 资源。
kubectl delete -f nginx.demo.yaml
注意:删除该部署的同时也会让控制器释放关联的弹性 IP。
eksctl delete cluster -f eip-demo-cluster.yaml
aws iam delete-policy \
--policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/AWSPodEIPControllerIAMPolicy
aws ecr delete-repository \
--repository-name aws-pod-eip-controller \
--region ${AWS_REGION} \
--force
注意:在 eip-demo-cluster.yaml 所在的文件夹中执行命令。
结论
在这篇文章中,您在 EKS 集群中部署了 EIP 控制器。通过监听 Pod 的创建和删除事件,它会为带有特定注释的 Pod 关联和取消关联 EIP。这简化了应用程序访问,Pod 可以直接通过 EIP 访问,而无需额外的负载均衡器或 Ingress 控制器。它实现了自动化操作,注释和控制器方法完全自动化了 EIP 的分配和释放过程,无需人工干预。
本篇作者