亚马逊AWS官方博客

无缝升级,连接未来互联网:探索云原生 Amazon EKS IPv6 实现

IPv6 简介

IPv6 是 Internet Protocol version 6(互联网协议第六版)的缩写,是互联网协议(IP)的一种协议版本,它是 IPv4 的下一代协议。对比 IPv4,IPv6 增加了地址空间,它可以支持更多的互联设备,同时提供更高效的路由和网络安全功能。IPv6 还提供了一些其他的特性,如对流媒体和 VoIP 通信的支持、对 QoS 的改进、对多播和任播的更好支持、支持更多的路由器层级等等。因此,IPv6 被视为下一代互联网协议,以满足未来的互联设备和应用程序的需求。

对于企业来说,向 IPv6 迁移能有效解决以下几个主要问题:

  • 地址空间不足:IPv4 的地址空间是有限的,很多企业已经用尽了它们的 IPv4 地址,需要更多的 IP 地址来满足未来业务增长的需求。IPv6 提供了一个庞大的地址空间,为企业提供足够的地址,能够满足企业未来业务需求。
  • 安全性:IPv6 提供了更好的安全性,如通过 IPSec 提供的端到端加密和认证,对 DDoS(分布式拒绝服务攻击)更好的防御能力。
  • 设备支持:许多新设备和技术(如 IoT、云计算、5G 等)需要 IPv6 支持才能正常工作。如企业不迁移至 IPv6,它们将无法使用这些新设备和技术,进而影响其业务发展和竞争力。
  • 全球化:IPv6 是一种全球化协议,这意味着它可以为全球范围内的企业和用户提供服务。在全球化经济中,IPv6 的使用已经成为了企业间交流和合作的必要条件。

我们建议企业尽早考虑向 IPv6 迁移,以便充分利用 IPv6 带来的好处,保障业务的未来发展。

IPv6 基础知识

IPv6 与 IPv4 最大的区别在于 IP 地址。 IPv6 由 128 位二进制数字组成,相比 IPv4 的 32 位地址空间,IPv6 的地址空间大很多,使得 IPv6 可以为更多的设备分配唯一的 IP 地址。

在 IPv6 地址表示层面,IPv6 地址每 16 位用一个冒号分隔,共有 8 组。例如:2001:0db8:85a3:0000:0000:8a2e:0370:7334。IPv6 地址的数量极其庞大,为 2 的 128 次方,形象来说,地球上每一平方米,都可以有 10 的 26 次方个地址。

IPv6 主要地址类型

IPv6 地址分为三大类:单播地址(用于点对点通信)、多播地址(用于向多个目的地址传输数据)和任播地址(用于向同一组内的某个地址传输数据)。IPv6 地址的分配由 IANA(The Internet Assigned Numbers Authority,互联网数字分配机构)管理,并由 RIR(Regional Internet Registry,地区性管理机构)、LIR(本地 Internet 注册管理机构)和 ISP(互联网服务提供商)逐层分配最终到设备。

IPv6 地址,按用途又有如下几种常见地址段:

用途 表示 说明
本机地址 ::1/128 类似 127.0.0.1
单播地址 2000::/3 IPv6 公网地址
Link-Local 地址 fe80::/3 类型 169.254.0.0/16
局域网地址 fc00::/7 用于本地局域网
多播地址 ff00::/7 用于广播、组播等

什么是 Amazon EKS

Amazon EKS(Elastic Kubernetes Service)是一项由亚马逊云科技提供的托管式 Kubernetes 服务,旨在简化 Kubernetes 集群的部署、管理和扩展。Amazon EKS 允许用户轻松地在亚马逊云科技上创建和管理 Kubernetes 集群,无需管理自己的 Kubernetes 控制平面或节点。

使用 Amazon EKS,用户可以快速构建和部署高度可用、弹性和安全的应用程序,Amazon EKS 负责处理 Kubernetes 集群中的所有基础架构细节,包括控制平面、节点、存储和网络。同时,Amazon EKS 还提供了一些高级功能,例如自动缩放、负载均衡、安全性和监控,帮助用户轻松构建可靠和可扩展的应用程序。

构建云原生 IPv6 Amazon EKS

作为亚马逊云科技云原生服务,Amazon EKS 已经能够全面支持 IPv6。

创建支持 IPv6 的 VPC

要构建支持 IPv6 的 EKS 集群,我们首先需要确保我们的 VPC 支持 IPv6。在 Amazon Web Service 上,我们可以通过开源工具来实现 Amazon CloudFormation 一键部署 IPv6 VPC, 也可以通过以下步骤配置支持 IPv6 的 VPC:

  • 为 VPC 添加 IPv6 地址段。Amazon Web Service 为客户 VPC 免费提供了 /56 的 IPv6 地址段,它包含 2 的 72 次方个 IPv6 地址,我们可以直接,快速地获取海量 IPv6 地址。

  • 创建 IPv6 子网:在 VPC 中创建一个或多个 IPv6 子网。可以在控制台中选择“子网”服务,然后点击“创建子网”按钮。在创建子网的页面中,选择 IPv6 CIDR 块并分配给子网,然后完成子网的创建。

  • 配置 IPv6 公有路由表:在 VPC 中配置 IPv6 公有路由表,以指定 IPv6 流量的路由规则。可以在控制台中选择“路由表”服务,然后创建一个新的 IPv6 路由表。并将 IPv6 子网关联到 IPv6 路由表,最后添加一条::/0 指向 Internet Gateway 的默认路由。

  • 配置私有子网 Egress Only Gateway 及 IPv6 私有路由表:Egress Only Gateway 是专门用于处理 IPv6 出向流量的,它允许绑定 IPv6 地址的 EC2 实例通过 Egress Only Gateway 安全地访问互联网,同时防止来自互联网的 IPv6 流量进入 VPC。它的作用类似 IPv4 私有子网中的 NAT Gateway(但并不执行 NAT)。我们只需要在 VPC 中创建一个 Egress Only Gateay,并与我们的 IPv6 VPC 进行关联即可。

  • 之后创建一个新的 IPv6 路由表。将 IPv6 子网关联到 IPv6 路由表并添加 IPv6 路由规则,设置 IPv6 的默认路由(::/0)指向新建的 Egress Only Gateway。

  • 配置 IPv6 安全组:在 VPC 中配置 IPv6 安全组以控制 IPv6 流量的进出规则。可以在 VPC 控制台中选择“安全组”,然后创建一个新的 IPv6 安全组。然后,将 IPv6 安全组关联到相应的 IPv6 实例或资源上。

完成相关配置后,我们可以在 VPC 公有、私有子网创建 EC2 资源,检查 IPv6 网络是否配置成功。最简单的办法是通过 ping6,其功能与 IPv4 的 ping 命令类似:

$ ping6 www.amazon.com
PING www.amazon.com(2600:9000:221a:fa00:7:49a5:5fd2:8621 (2600:9000:221a:fa00:7:49a5:5fd2:8621)) 56 data bytes
64 bytes from 2600:9000:221a:fa00:7:49a5:5fd2:8621 (2600:9000:221a:fa00:7:49a5:5fd2:8621): icmp_seq=1 ttl=45 time=2.07 ms
64 bytes from 2600:9000:221a:fa00:7:49a5:5fd2:8621 (2600:9000:221a:fa00:7:49a5:5fd2:8621): icmp_seq=2 ttl=45 time=2.06 ms
64 bytes from 2600:9000:221a:fa00:7:49a5:5fd2:8621 (2600:9000:221a:fa00:7:49a5:5fd2:8621): icmp_seq=3 ttl=45 time=2.07 ms
64 bytes from 2600:9000:221a:fa00:7:49a5:5fd2:8621 (2600:9000:221a:fa00:7:49a5:5fd2:8621): icmp_seq=4 ttl=45 time=2.06 ms
^C
--- www.amazon.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 2.055/2.062/2.071/0.006 ms

创建支持 IPv6 的 Amazon EKS 集群

创建 EKS 集群的方式很多,我们这里推荐使用`eksctl`。`eksctl`是一款命令行工具,它可以帮助用户快速创建和配置 EKS 集群,并提供了一些内置的默认值和最佳实践。具体安装、使用文档,可以参考 eksctl 官方网站 https://eksctl.io/

  • 准备工作
  • 创建 EKS 集群配置文件 `testeks.yaml`。相关配置项参考文件注释
1.	# refer https://eksctl.io/usage/vpc-ip-family/?h=ipv6
2.	apiVersion: eksctl.io/v1alpha5
3.	kind: ClusterConfig
4.	
5.	metadata:
6.	  name: testeks-ipv6
7.	  region: ap-northeast-1
8.	  version: "1.24"
9.	
10.	# 指定 EKS 支持 IPv6
11.	kubernetesNetworkConfig:
12.	  ipFamily: IPv6
13.	
14.	# IPv6 需要启用 OIDC
15.	iam:
16.	  withOIDC: true
17.	
18.	# IPv6 要求安装这些插件,我们还可以指定版本
19.	addons:
20.	  - name: vpc-cni
21.	  - name: coredns
22.	  - name: kube-proxy
23.	
24.	# 指定之前创建的 IPv6 VPC,子网选择之前创建的 IPv6 子网
25.	vpc:
26.	  subnets:
27.	    public:
28.	      ap-northeast-1c: {id: subnet-111111111111}
29.	      ap-northeast-1a: {id: subnet-222222222222}
30.	      ap-northeast-1d: {id: subnet-333333333333}
31.	    private:
32.	      ap-northeast-1c: {id: subnet-444444444444}
33.	      ap-northeast-1a: {id: subnet-555555555555}
34.	      ap-northeast-1d: {id: subnet-666666666666}
35.	
36.	#nodeGroups:  非托管集群暂不支持 IPv6
37.	managedNodeGroups:
38.	  - name: ng-test
39.	    instanceType: m6a.large
40.	    desiredCapacity: 1
41.	    volumeSize: 50
42.	    volumeType: gp3
43.	    privateNetworking: true
44.	    ssh:
45.	        publicKeyPath: ~/.ssh/id_rsa.pub
46.	    labels:
47.	        role: workers
48.	        clusterName: testeks-ipv6
49.	        clusterNg: ng-test
  • 创建支持 IPv6 的 EKS 集群
$eksctl create cluster -f testeks.yaml

创建支持 IPv6 的 Amazon EKS 应用

我们编写了一个简单的微服务,提供 echo 服务,用于进行 Demo 演示。具体的架构如下:

可以参考下面 deployments.yaml,通过`kubectl apply -f deployments.yaml`来创建 Frontend 及 Backend 应用 Deployment:

1.	apiVersion: apps/v1
2.	kind: Deployment
3.	metadata:
4.	  name: flask-frontend
5.	  labels:
6.	    app: flask-frontend
7.	  namespace: default
8.	spec:
9.	  replicas: 1
10.	  selector:
11.	    matchLabels:
12.	      app: flask-frontend
13.	  strategy:
14.	    rollingUpdate:
15.	      maxSurge: 25%
16.	      maxUnavailable: 25%
17.	    type: RollingUpdate
18.	  template:
19.	    metadata:
20.	      labels:
21.	        app: flask-frontend
22.	    spec:
23.	      containers:
24.	      - image: kealiu/flaskecho:lastest
25.	        imagePullPolicy: Always
26.	        name: flask-frontend
27.	        env: 
28.	        - name: SERVER_NAME
29.	          value: "frontend"
30.	        - name: UPSTREAM
31.	          value: "http://flask-backend/"
32.	        ports:
33.	        - containerPort: 5000
34.	          protocol: TCP
35.	 
36.	---
37.	apiVersion: apps/v1
38.	kind: Deployment
39.	metadata:
40.	  name: flask-backend
41.	  labels:
42.	    app: flask-backend
43.	  namespace: default
44.	spec:
45.	  replicas: 1
46.	  selector:
47.	    matchLabels:
48.	      app: flask-backend
49.	  strategy:
50.	    rollingUpdate:
51.	      maxSurge: 25%
52.	      maxUnavailable: 25%
53.	    type: RollingUpdate
54.	  template:
55.	    metadata:
56.	      labels:
57.	        app: flask-backend
58.	    spec:
59.	      containers:
60.	      - image: kealiu/flaskecho:lastest
61.	        imagePullPolicy: Always
62.	        name: flask-backend
63.	        env:
64.	        - name: SERVER_NAME
65.	          value: "backend"
66.	        ports:
67.	        - containerPort: 5000
68.	          protocol: TCP

在 Amazon EKS 中创建 IPv6 services

同样,参考下面 services.yaml, 通过`kubectl apply -f services.yaml`来创建 Frontend 及 Backend services:

1.	apiVersion: v1
2.	kind: Service
3.	metadata:
4.	  name: flask-frontend
5.	spec:
6.	  selector:
7.	    app: flask-frontend
8.	  ports:
9.	   -  protocol: TCP
10.	      port: 80
11.	      targetPort: 5000
12.	
13.	---
14.	apiVersion: v1
15.	kind: Service
16.	metadata:
17.	  name: flask-backend
18.	spec:
19.	  selector:
20.	    app: flask-backend
21.	  ports:
22.	   -  protocol: TCP
23.	      port: 80
24.	      targetPort: 5000

在 Amazon EKS 中创建 IPv6 ingress

参考下面 ingress.yaml,通过`kubectl apply -f ingress.yaml`来创建 Ingress,并将 Frontend 服务暴露到公网,供最终用户访问。注意下面 yaml 中的 annotation,需要指定 ELB 的`ip-address-type`类型为`dualstack`,并且`target-type`为 ip。

1.	apiVersion: networking.k8s.io/v1
2.	kind: Ingress
3.	metadata:
4.	    name: ipv6ingress
5.	    annotations:
6.	        alb.ingress.kubernetes.io/ip-address-type: dualstack
7.	        alb.ingress.kubernetes.io/scheme: internet-facing
8.	        alb.ingress.kubernetes.io/target-type: ip
9.	
10.	spec:
11.	    ingressClassName: alb
12.	    rules:
13.	    - http:
14.	        paths:
15.	        - path: /
16.	          pathType: Prefix
17.	          backend:
18.	            service:
19.	              name: flask-frontend
20.	              port:
21.	                number: 80

验证 IPv6 外部访问

  • 通过 kubectl 获取访问地址
$ kubectl get ing 
NAME          CLASS   HOSTS   ADDRESS                                                                       PORTS   AGE
ipv6ingress   alb     *       k8s-default-ipv6ingr-someid1234.region-1.elb.amazonaws.com   80      21h

其中 ADDRESS 项正式外部访问域名,我们可以通过`ping6`确定其是否支持 IPv6。

  • 通过命令行访问

通过 curl 命令,可以访问并确定是否为 IPv6。

$ curl -vvv http://k8s-default-ipv6ingr-11111111.region-1.elb.amazonaws.com 
*   Trying 2406::1111:1111:1111:1111:80...
* TCP_NODELAY set
* Connected to k8s-default-ipv6ingr-11111111.region-1.elb.amazonaws.com (2406::1111:1111:1111:1111) port 80 (#0)
> GET / HTTP/1.1
> Host: k8s-default-ipv6ingr-11111111.region-1.elb.amazonaws.com
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 23 Feb 2023 07:56:15 GMT
< Content-Type: application/json
< Content-Length: 122
< Connection: keep-alive
< Server: Werkzeug/2.2.2 Python/3.8.16
< 
{"message":["{\"message\":[\"Requested by frontend , serviced by backend\"]}\n","Requested by _ , serviced by frontend"]}
* Connection #0 to host k8s-default-ipv6ingr-11111111.region-1.elb.amazonaws.com  left intact
  • 通过浏览器访问

通过浏览器提供的调试模式,我们可以看到连接的是否为 IPv6 地址。

深入了解 Amazon EKS IPv6 网络实现

上面我们通过动手实践,了解如何部署一个真正的 IPv6 云原生服务,接下来让我们深入到 EKS 内部,了解 Amazon EKS 中 IPv6 网络实现。

Amazon EKS Pod 内部网络结构

  • EKS 会为 EC2 Node 节点分配 IPv6 prefix(默认为/80 的地址段),该 EC2 Node 中的 Pod 都将由该 Node 自行进一步分配 IPv6 地址。
  • Pod 内部,其实是 IPv6&IPv4 DualStackIP 地址
    • IPv6 地址是默认地址,在能使用 IPv6 的情况下,pod 都将优先使用该地址。该地址由 EC2 Node 节点中的 CNI 插件自动分配。
    • IPv4 地址是 Local Only 地址,默认为 254.0.0/16 中分配。该地址仅在 EC2 Node 中生效,用于特定情况下,需要使用 IPv4 地址时使用。EC2 Node 会对 169.254.0.0/16 的出向请求进行 NAT,最终以 EC2 Node 的私有地址出网。

一个典型的 Pod IP 地址信息如下:

1.	$ kubectl get nodes
2.	NAME                                              STATUS   ROLES    AGE   VERSION
3.	ip-172-31-1-2.region-1.compute.internal   Ready    <none>   19d   v1.24.9-eks-49d8fe8
4.	$ ssh ec2-user@ ip-172-31-1-2.region-1.compute.internal
5.	........... <ssh into EKS work node> ..............
6.	
7.	root@flask-frontend-5dbd654f4d-gp99l:/app# ifconfig 
8.	.............
9.	eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
10.	        inet6 2406:1:1:1:1::6  prefixlen 128  scopeid 0x0<global>
11.	        inet6 fe80::888a:c7ff:feda:91b6  prefixlen 64  scopeid 0x20<link>
12.	        ether 8a:8a:c7:da:91:b6  txqueuelen 0  (Ethernet)
13.	...........
14.	v4if0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
15.	        inet 169.254.172.12  netmask 255.255.252.0  broadcast 169.254.175.255
16.	...............

我们可以用下面的 IP 地址及网络流量图来进一步理解,图中 IPv6 及 IPv4 地址均为演示用,不代表真实地址:

Amazon EKS Pod 之间访问

Pod 之间的访问总是使用 IPv6 地址,进行点到点通信。如下图:

Amazon EKS Pod 访问 Amazon EKS 控制平面

EKS 控制平面由 Amazon 托管维护,它通过跨账号共享 ENI 方式,将 EKS 控制平面的 ENI 部署到用户 VPC,实现 EKS 控制平面对用户 VPC 的直接访问。但是,用户并不能直接访问 EKS 控制平面,必须要通过 EKS 暴露的 Cluster Endpoint 进行访问。由于 EKS Cluster Endpoint 是通过域名访问,当前该域名并未设置 IPv6 解析结果,所以无论是 Public Endpoint 还是 Private VPC Endpoint 的域名解析都将返回 IPv4 地址(启用 DNS64 的将返回 64:ff9b::/56 的地址)。

Amazon EKS 控制平面对外通信分两部分:

  1. EKS 控制平面主动访问 Node/Pod。 这种情况下,EKS 控制平面直接通过跨账号 ENI 访问 Node/Pod。这部分与 VPC 设定一致。IPv6 的情况下,也将直接支持 IPv6,优先使用 IPv6 进行访问(如`kubectl logs`命令, EKS 控制平面将主动连接 Node 节点的 kubelet)。
  2. Node/Pod 主动访问 EKS 控制平面。前面提到,EKS Cluster Endpoint 暂未支持 IPv6 解析,我们仍需使用 IPv4 进行访问。Node 会直接通过 IPv4 地址访问,Node 中的 Pod 会通过 254.0.0/16 的 IPv4 地址,在本 Node 进行 NAT,最终实现 IPv4 地址访问 EKS Cluster Endpoint。在启用 DNS64 的情况下,将通过 NAT64 访问(参考后文外部 IPv4 访问介绍)。

整体流程如下图所示:

Amazon EKS Pod 访问 Internet

支持 IPv6 的 Internet 访问

对于支持 IPv6 的外部网站,Pod 将通过 Egress Only Gateway 进行直接访问。

仅支持 IPv4 的 Internet 访问

对于 IPv4 地址的访问,我们推荐使用的 DNS64 & NAT64 方案。 该方案中,所有仅 IPv4 记录的解析结果,都将映射为 64:ff9b::/96 中的地址段。通过将 64:ff9b::/96 地址段路由到支持 NAT64 的 IPv6 转 IPv4 NAT gateway,实现最终以 IPv4 的方式访问互联网。

如果是直接 IPv4 地址访问,我们也可以自行将目标 IPv4 地址映射到 64:ff9b::/96 ,再通过该 IPv6 地址进行访问。

在 Amazon VPC 中,如何支持 DNS64&NAT64? 具体来说,我们需要做如下配置:

  • Amazon VPC NAT Gateway 默认支持 NAT64,无需进行任何设置。
  • 对于 DNS64,需要在 VPC Subnet 设置中启用 DNS64。每个需要启用 DNS64 的 Subnet 都需要单独设置。

  • 配置 Subnet 路由表,将 64:ff9b::/96 段的流量路由到 NAT Gateway。

Pod 访问外部 IPv4 地址的步骤如下。如果是直接 IPv4 访问,则没有 DNS64 解析过程,可以由应用自行将 IPv4 地址映射到 64:ff9b::/96 后按 IPv6 进行访问。

总结

Internet 向 IPv6 演进是未来的必然趋势,一边是 IPv4 地址已经枯竭,一边是层出不穷的新业务对 IP 地址数量需求越来越多。本文介绍了 Amazon EKS 云原生场景下,我们如何实现在亚马逊云科技基础设施中使用 IPv6,并进行了具体的 Demo 演示。同时,为了让大家进一步了解 IPv6 在 EKS 环境中是如何运行的,本文还对 EKS IPv6 路由机制及网络流量进行了分析介绍。

参考文档

  1. IPv6 部署情况:https://en.wikipedia.org/wiki/IPv6_deployment
  2. IPv6 地址技术说明:https://en.wikipedia.org/wiki/IPv6_address
  3. Amazon IPv6 VPC 文档:https://docs.aws.amazon.com/vpc/latest/userguide/get-started-ipv6.html
  4. Amazon EKS 文档:https://docs.aws.amazon.com/eks/index.html
  5. eksctl 官方文档:https://eksctl.io/
  6. Amazon EKS 地址分配 Prefix:https://aws.github.io/aws-eks-best-practices/networking/prefix-mode/
  7. Amazon Loadbalancer Controller 文档:https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/aws-load-balancer-controller.html
  8. DNS64 解释&实现:https://docs.aws.amazon.com/vpc/latest/userguide/nat-gateway-nat64-dns64.html

本篇作者

刘科

西云数据解决方案架构师,15+年 IT 研发、管理经验,曾就职于知名通信设备厂商、头部互联网企业,有丰富、广泛的系统架构与研发管理经验。擅长帮助企业打造完善研发 Devops 体系,构建网络与安全体系,帮助企业业务产品项目落地。

戴涛

西云数据解决方案架构师,14+年 IT 专业服务经验,云计算项目经验丰富,擅长容器/云原生领域。