本章介绍如何将现有IPv4 VPC
转变为具有 IPv6 地址空间的双栈 VPC,并在该 VPC 中部署支持 IPv6 的EKS集群。
默认情况下,K8s向pod和service分配IPv4地址,EKS上可以配置向pod和service分配IPv6地址。
但是EKS上只支持single stack
, 要么只用IPv6, 要么只用IPv4(实际上官方k8s可以dual stack, 但是EKS上不行)
在创建EKS的集群的时候,指定IP类型,在创建完成后不能再进行更改。
EKS所在VPC既要有IPv4 CIDR,也要绑定IPv6 CIDR。所有节点既分配 ipv6地址,也分配了ipv4地址。EC2级别不能关闭IPv4
创建EKS IPv6集群时,所在IPv6子网必须要开启auto assign IPv6
(注意默认这个设置是关闭的)
子网所在的路由表必须有对IPv6地址的路由;安全组必须允许IPv6地址
Pod与外界公网交流时,用的是自己的IPv6地址,而不是node的,它是走IGW或EIGW(egress only)出去的
通过Pod所在实例的NAT,IPv6 Pod可以与IPv4的地址进行访问
我们先使用eksctl创建一个IPv6的EKS集群,它会自动创建一个新的VPC,并配置好VPC的ipv6配置
创建ipv6-cluster.yaml
,kubernetesNetworkConfig
部分定义了使用IPv6:
cat >ipv6-cluster.yaml <<EOF
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: ipv6-cluster
region: us-east-2
version: "1.28"
kubernetesNetworkConfig:
ipFamily: IPv6
addons:
- name: vpc-cni
version: latest
- name: coredns
version: latest
- name: kube-proxy
version: latest
iam:
withOIDC: true
managedNodeGroups:
- name: ng-1
instanceType: t3.large
EOF
创建集群:
eksctl create cluster -f ipv6-cluster.yaml
创建完成后,查询pod,上面分配了IPv6地址:
kubectl get pods -n kube-system -o wide
查看service,上面也分配了IPv6地址:
kubectl get services -n kube-system -o wide
查看集群,它的Cluster IP address family
是IPv6
:
从上面的页面打开任意子网,上面分配了IPv6 CIDR
,并且开启了Auto-assign IPv6 address
:
查看子网的路由表,有一条到::0
的路由,指向IGW:
查看EKS的addon,VPC CNI上绑定了一个role,role上的policy具有AssignIPv6Addresses
的权限:
上一节创建eks集群时,vpc内的配置由eksctl自动处理。如果想在已有vpc中创建IPv6 EKS集群,需要提前对vpc进行一些配置,包括:
::0
的路由进入vpc页面,选择VPC ,从右上角的“操作”菜单中,选择“Edit CIDR”:
单击IPv6 CIDR 下的Add new IPv6 CIDR:
然后选择Amazon provided IPv6 CIDR block:
添加完成后,新的IPv6段会显示出来:
我们将现有的 IPv4 子网设置为双栈,使其同时具有 IPv4 CIDR 和 IPv6 CIDR,并将使用它来启动支持 IPv6 的EKS 集群。
Edit IPv6 CIDRs
:在编辑 IPv6 CIDR页面上,添加一个IPv6子网:
后面的单位是18.4Q,其实等于2^64
:
Q是科学计数法:
再次点击子网的Edit subnet settings
:
启用自动分配IPv6地址以及DNS64
:
对于另外几个子网,重复上面的过程:
在给vpc添加完IPv6 CIDR后,会自动添加一个local路由,这样vpc下的实例之间能用ipv6地址进行通讯:
但此时IPv6还没有到公网的路由,需要进行手动添加:
这里以给public子网添加IGW为例,打开子网使用的route table:
编辑路由表,添加一条::0
的路由:
参考: https://docs.aws.amazon.com/vpc/latest/userguide/vpc-migrate-ipv6.html
使用eksctl创建新的IPv6, 里面指定了使用已有VPC:
cat >ipv6-cluster2.yaml <<EOF
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: ipv6-cluster
region: us-west-2
version: "1.28"
vpc:
subnets:
public:
us-west-2a:
id: subnet-3221874a
us-west-2b:
id: subnet-22ff3c68
us-west-2c:
id: subnet-2ab30377
kubernetesNetworkConfig:
ipFamily: IPv6
addons:
- name: vpc-cni
version: latest
- name: coredns
version: latest
- name: kube-proxy
version: latest
iam:
withOIDC: true
managedNodeGroups:
- name: ng-1
instanceType: t3.large
EOF
创建集群:
eksctl create cluster -f ipv6-cluster2.yaml
查看pod上是否具有IPv6地址:
kubectl get pods -n kube-system -o wide
查看service上是否具有IPv6地址:
kubectl get services -n kube-system -o wide
接下来创建AWS Load balancer controller
,并部署一个service暴露EKS应用。
AWS Load balancer controller根据子网的标签来找到它,所以提前要给几个子网打上以下标签:
kubernetes.io/role/elb=1
eksctl utils associate-iam-oidc-provider --cluster ipv6-cluster --region $AWS_REGION --approve # 开启OIDC provider
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.5.4/docs/install/iam_policy.json
aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy2 \
--policy-document file://iam_policy.json # 创建policy
eksctl create iamserviceaccount \
--cluster=ipv6-cluster \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--role-name AmazonEKSLoadBalancerControllerRole2 \
--region=$AWS_REGION \
--attach-policy-arn=arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy2 \
--approve
使用helm安装aws load balancer controller
:
helm repo add eks https://aws.github.io/eks-charts
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=ipv6-cluster \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller \
--set createIngressClassResource=true
查看aws-load-balancer-controller
状态:
kubectl get pods -A -o wide
部署game 2048测试应用:
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/examples/2048/2048_full_dualstack.yaml
上述命令将在双栈模式下配置ALB。ALB 将接受来自支持 IPv4 和 IPv6 的客户端的传入连接请求。当将注释service.beta.kubernetes.io/aws-load-balancer-ip-address-type: Dualstack
添加后,EKS IPv6 集群会在双栈模式下配置 ALB 和 NLB :
几分钟后,使用以下命令验证是否已创建alb:
kubectl get ingress/ingress-2048 -n game-2048
创建出来的ALB是dual stack模式,解析出来同时具有ipv6和ipv4 地址:
在本部分中,我们将验证从 IPv4客户端 到IPv6 EKS 集群上的应用程序的连接。
ALB启用了dual stack模式,它允许 IPv4 和 IPv6 客户端进行连接。
获取上一步的ALB DNS地址,在浏览器中访问:
验证ALB是否可以解析为 A 和 AAAA DNS 记录:
$ dig k8s-game2048-ingress2-xxxxxxxxx-yyyyyyyyyy.us-west-2.elb.amazonaws.com +short
$ dig k8s-game2048-ingress2-xxxxxxxxx-yyyyyyyyyy.us-west-2.elb.amazonaws.com AAAA +short
在本部分中,我们将验证从 EKS Pod 到 Internet 上的 IPv4 / IPv6 的连接。
运行以下命令创建一个新的 pod,该 pod 允许执行 curl 命令并打开 pod 的 shell 终端。
kubectl run mycurlpod --image=curlimages/curl -i --tty -- sh
在 Pod 终端上,运行以下命令来测试与 Internet 上的 IPv4 公共端点的连接:
curl 'https://api.ipify.org?format=json'
预期回应:
kongpingfan:~/environment/eksctl $ kubectl run mycurlpod --image=curlimages/curl -i --tty -- sh
If you don't see a command prompt, try pressing enter.
~ $ curl 'https://api.ipify.org?format=json'
{"ip":"54.202.37.175"}~ $
通过Pod所在实例的NAT,IPv6 Pod可以与IPv4的地址进行访问
这个返回的IP实际上是Pod所在EC2的IP:
Pod与外界公网交流时,用的是自己的IPv6地址,它是走IGW或EIGW(egress only)
出去的
上面两个url:
api.ipify.org
ip.gs
一个走ipv4,另一个走ipv6, 这是因为两个URL对IPv6的支持不一样:
在本部分中,我们将验证 EKS Pod 之间通过 IPv6 地址的连接。
我们将在 EKS Pod 上部署一个前端(一个将代理用户请求的 nginx)和一个后端应用程序(一个用于返回hello world的简单微服务),并测试它们之间的连接。为简单起见,我们将在此场景中在两个 pod 之间执行 ping6 测试
运行以下命令来创建后端 Pod 和后端服务:
kubectl apply -f https://k8s.io/examples/service/access/backend-deployment.yaml
kubectl apply -f https://k8s.io/examples/service/access/backend-service.yaml
接下来,运行以下命令来验证服务是否已成功创建。注意到分配给服务的CLUSTER-IP将是 IPv6 地址。
kubectl get svc hello
现在我们将创建前端,它接受用户请求并将其代理到后端服务:
kubectl apply -f https://k8s.io/examples/service/access/frontend-deployment.yaml
kubectl apply -f https://k8s.io/examples/service/access/frontend-service.yaml
运行以下命令并从输出中复制任意一个 IPv6 地址。
kubectl describe svc hello
接下来,我们需要进入前端pod的bash终端:
kubectl exec -it frontend-<podname> -- /bin/bash
从前端 pod 的 bash 终端,运行 ping6 命令。在以下命令中使用上一步查到的 IPv6 地址:
ping6 <IPV6ADDRESS>
会看到来自后端 Pod 的成功 ping 响应,这验证了 Pod 之间通过 IPv6 地址进行的通信。