我该如何通过 Amazon EKS 使用多个 CIDR 范围?
上次更新日期:2022 年 12 月 27 日
我想通过 Amazon Elastic Kubernetes Service(Amazon EKS)使用多个 CIDR 范围以解决我的容器组(pod)遇到的问题。例如,如何通过添加到我的 Amazon Virtual Private Cloud (Amazon VPC) 的不同 CIDR 范围运行 Pod? 此外,当子网的 IP 地址耗尽时,如何为它增加更多 IP 地址? 最后,我要如何确保在工作线程节点上运行的 Pod 有不同的 IP 范围?
简短描述
在您完成解决方法部分的步骤前,确保您有以下各项:
- 处于运行状态的 Amazon EKS 集群
- 可访问版本号不低于 1.16.284 的 AWS 命令行界面 (AWS CLI) 的权限
- 可管理 Amazon VPC 的 AWS Identity and Access Management (IAM) 权限
- kubectl 和创建自定义资源及编辑 DaemonsSet 的权限
- 系统上已安装的 jq 版本(来自 jq 网站)
- 带有 Bash shell 的基于 Unix 的系统
请记住:
- 在创建集群之前或之后,您可以将私有(RFC 1918)和公有(非 RFC 1918)CIDR 数据块关联到您的 VPC。
- 在运营商级网络地址转换(NATI)的情况下,100.64.0.0/10 是专用网络范围。此专用网络范围用于共享地址空间,以实现服务提供商与其订阅者之间的通信。您的 NAT 网关必须在路由表中被配置为用于容器组(pod)和互联网之间的通信。AWS Fargate 集群不支持 Daemonsets。要将辅助 CIDR 范围添加到 Fargate 配置文件,使用 VPC 的辅助 CIDR 数据块中的子网。然后,标记新子网后再将子网添加到您的 Fargate 配置文件。
重要提示:在某些情况下,创建集群后,Amazon EKS 无法与通过添加到 VPC 的其他 CIDR 数据块在子网中启动的节点进行通信。向现有集群添加 CIDR 数据块所导致的更新范围可能需要长达 5 小时才能显示。
解决方法
注意:如果在运行 AWS CLI 命令时收到错误,请确保您使用的是最新版本的 AWS CLI。
在以下解决方案中,您首先需要设置 VPC。然后,配置 CNI 插件以使用新的 CIDR 范围。
添加额外的 CIDR 范围以扩展您的 VPC 网络
1. 查找您的 VPC。
如果您的 VPC 有标签,运行以下命令来查找您的 VPC:
VPC_ID=$(aws ec2 describe-vpcs --filters Name=tag:Name,Values=yourVPCName | jq -r '.Vpcs[].VpcId')
如果您的 VPC 没有标签,则运行以下命令以列出 AWS 区域中的全部 VPC:
aws ec2 describe-vpcs --filters | jq -r '.Vpcs[].VpcId'
2. 要将您的 VPC 附加到 VPC_ID 变量,运行以下命令:
export VPC_ID=vpc-xxxxxxxxxxxx
3. 要将范围为 100.64.0.0/16 的额外 CIDR 块关联到 VPC,运行以下命令:
aws ec2 associate-vpc-cidr-block --vpc-id $VPC_ID --cidr-block 100.64.0.0/16
使用新的 CIDR 范围创建子网
1. 要列出您的 AWS 区域中的全部可用区,运行以下命令:
aws ec2 describe-availability-zones --region us-east-1 --query 'AvailabilityZones[*].ZoneName'
注:将 us-east-1 替换为您的 AWS 区域。
2. 选择您想要添加子网的可用区,然后将这些可用区分配给变量。例如:
export AZ1=us-east-1a
export AZ2=us-east-1b
export AZ3=us-east-1c
注意:您可以通过创建更多变量来添加更多可用区。
3. 要在 VPC 下使用新的 CIDR 范围创建新子网,运行以下命令:
CUST_SNET1=$(aws ec2 create-subnet --cidr-block 100.64.0.0/19 --vpc-id $VPC_ID --availability-zone $AZ1 | jq -r .Subnet.SubnetId)
CUST_SNET2=$(aws ec2 create-subnet --cidr-block 100.64.32.0/19 --vpc-id $VPC_ID --availability-zone $AZ2 | jq -r .Subnet.SubnetId)
CUST_SNET3=$(aws ec2 create-subnet --cidr-block 100.64.64.0/19 --vpc-id $VPC_ID --availability-zone $AZ3 | jq -r .Subnet.SubnetId)
为新子网贴标签
对于在 Kubernetes 1.18 及更早版本上运行的集群,您必须为全部子网贴标签,以便 Amazon EKS 可以发现这些子网。
注意:从 Kubernetes 版本 1.19 开始,Amazon EKS 支持自动发现子网,而不需要任何 kubernetes.io 标签。有关更多信息,请参阅 Kubernetes GitHub 站点上的变更日志。
1. (可选)通过设置键值对为您的子网添加名称标签。例如:
aws ec2 create-tags --resources $CUST_SNET1 --tags Key=Name,Value=SubnetA
aws ec2 create-tags --resources $CUST_SNET2 --tags Key=Name,Value=SubnetB
aws ec2 create-tags --resources $CUST_SNET3 --tags Key=Name,Value=SubnetC
2. 对于 Kubernetes 1.18 及更低版本上运行的集群,请贴标签以方便 Amazon EKS 发现子网。例如:
aws ec2 create-tags --resources $CUST_SNET1 --tags Key=kubernetes.io/cluster/yourClusterName,Value=shared
aws ec2 create-tags --resources $CUST_SNET2 --tags Key=kubernetes.io/cluster/yourClusterName,Value=shared
aws ec2 create-tags --resources $CUST_SNET3 --tags Key=kubernetes.io/cluster/yourClusterName,Value=shared
注意:将 yourClusterName 替换为您的 Amazon EKS 集群的名称。
如果您计划使用弹性负载均衡,则考虑添加其他标签。
将您的新子网关联到路由表
1. 要列出 VPC 下方的完整路由表,运行以下命令:
aws ec2 describe-route-tables --filters Name=vpc-id,Values=$VPC_ID |jq -r '.RouteTables[].RouteTableId'
2. 对于要与子网关联的路由表,请运行以下命令以导出到变量。然后,用步骤 1 中的值替换 rtb-xxxxxxxxx:
export RTASSOC_ID=rtb-xxxxxxxxx
3. 将路由表关联到所有新子网。例如:
aws ec2 associate-route-table --route-table-id $RTASSOC_ID --subnet-id $CUST_SNET1
aws ec2 associate-route-table --route-table-id $RTASSOC_ID --subnet-id $CUST_SNET2
aws ec2 associate-route-table --route-table-id $RTASSOC_ID --subnet-id $CUST_SNET3
有关更多信息,请参阅路由。
配置 CNI 插件以使用新的 CIDR 范围
1. 确保集群中正在运行 vpc-cni 插件的最新推荐版本。
要验证集群中正在运行的版本,请运行以下命令:
kubectl describe daemonset aws-node --namespace kube-system | grep Image | cut -d "/" -f 2<br>
要查看 vpc-cni 的最新推荐版本,并在需要时更新插件,请参阅 Updating the Amazon VPC CNI plugin for Kubernetes add-on(更新适用于 Kubernetes 附加组件的 Amazon VPC CNI 插件)。
2. 要打开 CNI 插件的自定义网络配置,运行以下命令:
kubectl set env daemonset aws-node -n kube-system AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG=true
3. 要添加 ENIConfig 标签以便于识别您的工作线程节点,运行以下命令:
kubectl set env daemonset aws-node -n kube-system ENI_CONFIG_LABEL_DEF=failure-domain.beta.kubernetes.io/zone
4. 要为所有子网和可用区创建 ENIConfig 自定义资源,运行以下命令:
cat <<EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
name: $AZ1
spec:
subnet: $CUST_SNET1
EOF
cat <<EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
name: $AZ2
spec:
subnet: $CUST_SNET2
EOF
cat <<EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
name: $AZ3
spec:
subnet: $CUST_SNET3
EOF
注意:ENIConfig 必须与您的 Worker 节点的可用区匹配。
5. 启动新的 Worker 节点。
注意:此步骤允许 CNI 插件(ipamd)从新的 CIDR 范围中为新的 Worker 节点分配 IP 地址。
当您使用自定义联网时,主网络接口不会用于容器组(pod)置放。在这种情况下,您必须首先使用以下公式更新 max-pods:
maxPods = (number of interfaces - 1) * (max IPv4 addresses per interface - 1) + 2
- 对于自我管理的节点组,请按照启动自我管理的 Amazon Linux 节点中的说明部署节点组。不要指定您在已部署的 ENIConfig 资源中使用的子网。相反,请为 BootstrapArguments 参数指定以下文本:
--use-max-pods false --kubelet-extra-args '--max-pods=<20>'
- 对于托管节点组,如果不使用启动模板,或者使用未指定 AMI ID 的启动模板,则托管节点组会自动计算 Amazon EKS 建议的最大容器组(pod)值。按照创建托管节点组中的步骤进行操作。或者,使用 Amazon EKS CLI 创建托管节点组:
aws eks create-nodegroup --cluster-name <sample-cluster-name> --nodegroup-name <sample-nodegroup-name> --subnets <subnet-123 subnet-456> --node-role <arn:aws:iam::123456789012:role/SampleNodeRole>
注意:对于子网字段,请勿指定您在 ENIConfig 资源中指定的子网。可以根据需要指定更多选项。
- 对于托管节点组,如果使用指定 AMI ID 的启动模板,请在启动模板中提供“--max-pods=
” 附加参数作为用户数据。在启动模板中,指定 Amazon EKS 优化的 AMI ID,或基于 Amazon EKS 优化的 AMI 构建的自定义 AMI。然后,使用启动模板部署节点组,并在启动模板中提供以下用户数据:
#!/bin/bash
/etc/eks/bootstrap.sh <my-cluster-name> --kubelet-extra-args <'--max-pods=20'>
6. 创建节点组后,记下子网的安全组,并将该安全组应用于关联的 ENIConfig。
将以下示例中的 sg-xxxxxxxxxxxx 替换为您的安全组:
cat <<EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
name: $AZ1
spec:
securityGroups:
- sg-xxxxxxxxxxxx
subnet: $CUST_SNET1
EOF
cat <<EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
name: $AZ2
spec:
securityGroups:
- sg-xxxxxxxxxxxx
subnet: $CUST_SNET2
EOF
cat <<EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
name: $AZ3
spec:
securityGroups:
- sg-xxxxxxxxxxxx
subnet: $CUST_SNET3
EOF
7. 终止旧的 Worker 节点。然后,通过启动新部署来测试配置。添加了 10 个新的容器组(pod),并且为新的 Worker 节点安排了新的 CIDR 范围:
kubectl create deployment nginx-test --image=nginx --replicas=10
kubectl get pods -o wide --selector=app=nginx-test