简介

在 IPv4 地址日渐稀缺的大环境下,对如何给网站启用 IPv6 支持感兴趣的人增多,在本文中,我以作者自己运营的站点为例,讲解给网站启用 IPv6 支持的做法之一。

背景

IPv6 的前身是 IPv4, IPv4 也就是通常人们俗称的“IP 协议”,IP 是 Internet Protocol 的全称,字面意思也就是“互联网协议”,实现了互联网协议的计算机、网络设备连接起来,构成了全球的互联网。当互联网上的一台主机 A 想要和另一台主机 B 通信,它只需要知道主机 B 的 IP 地址(不指定 IPv6 则默认为 IPv4 地址),互联网中的网络设备(计算机和计算机网卡、路由器、交换机、调制解调器、卫星和基站等)会将从 A 发出的 packet 层层转发,最终转发给 B(假定 B 的 IP 地址是 publicly routable 的)。

IP 协议(IPv4 协议)定义了 IP Packet 的头部(IP Header),IP Header 有两个字段被叫做 “IP 地址“,分别是 offset 12(十进制,下同)和 offset 16, 其中 offset 12 表示源地址,类似于信件的”发件人“一栏,offset 16 表示目的地址,类似于信件的“收件人”一栏。网络设备(主要是路由器,也有三层交换机),查看 IP Header 的目的地址字段,来决定如何转发 IP Packet.

IANA 及其分支机构负责 IP 地址的划分、分配(通过发布公告、制定标准以及划分自治域等手段)。可分配的公网 IPv4 地址的长度是 4 个字节,总共只有不到 2^32 个(“不到”是因为要减去各种保留地址),因此,随着联网设备的爆炸式增多,很快可划分的 IPv4 地址就接近枯竭,这也导致了 IPv4 地址的最终用户(应用开发者,网站管理员等)获取 IPv4 地址的成本增多。

IPv6 被设计出来,解决的其中一个问题,就是公网 “IPv4 地址不够用“的问题。

解决思路

作为一个应用开发者或者网站管理员,给自己开发的 App 或者网站启用 IPv6 支持的一个直接的办法(步骤)是:

  1. 向自己的云服务商或者电信服务提供商索要~~(或者购买)~~ 至少一个 internet routable 的 IPv6 地址;
  2. 配置应用的软件栈,主要是 web server, 使得它监听来自 IPv6 互联网的流量;
  3. 配置域名的 AAAA 记录,使得你的应用的最终用户所使用的设备,能够得知如何以 IPv6 的方式访问你的服务。

上述步骤可以使得你的应用原生支持 IPv6.

然而,考虑到此网站的具体情况,步骤 2 执行起来比较麻烦:因为需要对 Kubernetes 的许多组件 (components,例如 kube-proxy, kubelet, kube-api-server) 和插件 (CNI plugin, DNS plugin),以及控制器(Ingress Controller) 进行修改,才能使得部署在集群内的工作负载 (Workloads)能够和外部进行 IPv6 通信!对于多节点集群,这些事情还要在多个节点上重复一遍(考虑到我的集群中的节点并非是标准化配置的,因此脚本方法“应该”行不通)。

因此,我采取了另辟蹊径的举措:通过一台中转机器,来实现网站的 IPv6 可访问性。具体来说:

  1. 配置域名的 AAAA 记录,使它指向一台同时支持 IPv6 和 IPv4 的机器(这台机器其实还是集群内的一个节点,只不过负责转发的进程运行在集群外);简称它为“转发机”或者”中转机器“;
  2. 转发机负责绑定、监听 IPv6 协议族(AF_INET6),端口为 http 或者 https 的套接字,对收到的流量以自己的名义转发给集群内的 web server 工作负载;(SNAT)
  3. 集群内的 web server 工作负载对请求进行处理,处理完毕后,将响应内容发回给转发机(而不是最终、真实 client),转发机再将响应内容发回给 client.(DNAT)

其中 2, 3 构成了一个 1 对 1 NAT 的过程,转发机总会将从一个固定 socket 上收到的流量转发给另一个固定的服务。

并且在 2, 3 中,客户以 IPv6 的方式和转发机通信(客户甚至可以是 IPv6 only 的),转发机以 IPv4 的方式,和集群内的 web 工作负载通信。