Docker 和 Kubernetes 中的 IPv6:容器网络指南
为容器化应用配置 IPv6。涵盖 Docker 守护程序设置、Kubernetes 双栈、CNI 插件和服务暴露。
容器网络默认为 IPv4。如果你在 2024 年运行生产工作负载,这就是一个问题。
TL;DR - 快速摘要
要点:
- Docker 和 Kubernetes 默认仅支持 IPv4;IPv6 需要显式配置
- Docker 需要 daemon.json 更改和带有
--ipv6标志的自定义网络 - Kubernetes 1.23+ 支持稳定的双栈,pod 和 service 都支持 IPv6
- CNI 插件(Calico、Cilium、Flannel)处理双栈的方式不同
跳转至: Docker 配置 | Kubernetes 双栈 | CNI 插件 | 测试
为什么容器需要 IPv6#
你的容器可能仅支持 IPv4,而互联网的其他部分正在转向 IPv6。移动网络、ISP 和云提供商都是 IPv6 优先。如果你的容器化服务不支持 IPv6,你就会通过 NAT64 网关增加延迟,或者更糟——完全错过客户。
容器编排平台(Docker、Kubernetes、ECS、Nomad)是在 IPv4 时代构建的。IPv6 支持是后来作为附加功能添加的。默认设置仍然假定仅支持 IPv4 网络。
启用 IPv6 并不难,但需要在多个层面进行显式配置:守护程序、网络、容器和服务。缺少一个层次,你就会出现神秘故障的部分连接。
Docker IPv6 配置#
Docker 守护程序默认不启用 IPv6。你需要在 /etc/docker/daemon.json 中配置它。
守护程序配置#
创建或修改 /etc/docker/daemon.json:
{
"ipv6": true,
"fixed-cidr-v6": "fd00::/80",
"experimental": false,
"ip6tables": true
}细分说明:
"ipv6": true启用 IPv6 支持"fixed-cidr-v6"设置容器的子网(使用 ULA 或 GUA 前缀)"ip6tables": true启用 IPv6 防火墙规则(Docker 20.10+)
对于具有全局可路由地址的生产环境,使用提供商分配的前缀:
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:1234::/64"
}重启 Docker 以应用更改:
sudo systemctl restart docker验证 IPv6 已启用:
docker network inspect bridge | grep IPv6你应该看到 "EnableIPv6": true。
默认桥接网络#
即使在守护程序配置后,默认桥接网络也不会自动获得 IPv6。创建自定义网络:
docker network create --ipv6 \
--subnet=172.20.0.0/16 \
--subnet=fd00:dead:beef::/48 \
mynetwork在此网络上运行容器:
docker run -d --network mynetwork nginx容器现在接收 IPv4 和 IPv6 地址。
用户定义的网络#
用户定义的桥接网络支持双栈:
docker network create --ipv6 \
--subnet=10.1.0.0/24 \
--gateway=10.1.0.1 \
--subnet=fd00:cafe::/64 \
--gateway=fd00:cafe::1 \
appnetwork此网络上的容器可以通过 IPv6 通信:
# 终端 1
docker run -it --rm --network appnetwork --name container1 alpine sh
# 终端 2
docker run -it --rm --network appnetwork alpine sh
ping6 container1当启用 IPv6 时,Docker 的嵌入式 DNS 解析器返回容器名称的 AAAA 记录。
IPv6 NAT 和路由#
默认情况下,Docker 对 IPv4 使用 NAT,但可能不对 IPv6 进行 NAT。这取决于你的 fixed-cidr-v6 配置。
使用 ULA 前缀(fd00::/8),你需要 NAT 进行互联网访问:
# 启用 IPv6 转发
sudo sysctl -w net.ipv6.conf.all.forwarding=1
# 添加伪装规则
sudo ip6tables -t nat -A POSTROUTING -s fd00::/80 ! -o docker0 -j MASQUERADE使用 GUA 前缀(全局可路由),直接路由而不使用 NAT:
# 为容器子网添加路由
sudo ip -6 route add 2001:db8:1234::/64 via <docker-host-ipv6>配置上游路由器将容器子网路由到 Docker 主机。
Docker Compose IPv6#
Docker Compose 需要在网络定义中显式配置 IPv6。
示例 docker-compose.yml:
version: '3.8'
services:
web:
image: nginx
networks:
- frontend
ports:
- "80:80"
- "[::]:8080:80" # 显式绑定 IPv6
app:
image: myapp:latest
networks:
- frontend
- backend
db:
image: postgres:14
networks:
- backend
environment:
POSTGRES_HOST_AUTH_METHOD: trust
networks:
frontend:
enable_ipv6: true
ipam:
config:
- subnet: 172.20.0.0/16
gateway: 172.20.0.1
- subnet: fd00:1::/64
gateway: fd00:1::1
backend:
enable_ipv6: true
ipam:
config:
- subnet: 172.21.0.0/16
- subnet: fd00:2::/64每个网络都需要 enable_ipv6: true 标志。IPAM(IP 地址管理)配置分配 IPv4 和 IPv6 子网。
IPv6 的端口绑定语法:
ports:
- "80:80" # IPv4 和 IPv6
- "0.0.0.0:8080:80" # 仅 IPv4
- "[::]:8081:80" # 仅 IPv6
- "127.0.0.1:8082:80" # IPv4 本地主机
- "[::1]:8083:80" # IPv6 本地主机启动服务:
docker-compose up -d验证容器具有 IPv6:
docker-compose exec web ip -6 addr showKubernetes 双栈#
Kubernetes 从版本 1.21(测试版)和 1.23(稳定版)开始支持双栈网络。
先决条件#
- Kubernetes 1.23 或更高版本
- 支持双栈的 CNI 插件(Calico、Cilium、Flannel、Weave)
- 具有双栈模式的 kube-proxy
- 云提供商支持(用于 LoadBalancer 服务)
启用双栈#
对于新集群,在初始化期间启用双栈。使用 kubeadm:
# kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
networking:
podSubnet: "10.244.0.0/16,fd00:10:244::/56"
serviceSubnet: "10.96.0.0/16,fd00:10:96::/112"初始化集群:
kubeadm init --config kubeadm-config.yaml对于托管 Kubernetes(EKS、GKE、AKS),在集群创建期间启用双栈:
# EKS
eksctl create cluster \
--name mycluster \
--ip-family ipv4,ipv6
# GKE
gcloud container clusters create mycluster \
--enable-ip-alias \
--stack-type=IPV4_IPV6
# AKS
az aks create \
--resource-group myResourceGroup \
--name mycluster \
--network-plugin azure \
--ip-families IPv4,IPv6验证双栈已启用:
kubectl get nodes -o jsonpath='{.items[*].spec.podCIDRs}'你应该看到 IPv4 和 IPv6 CIDR。
Pod 网络#
Pod 自动从两个系列接收地址。在大多数情况下不需要特殊配置。
示例 pod:
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: nginx
image: nginx部署并检查地址:
kubectl apply -f pod.yaml
kubectl get pod test-pod -o jsonpath='{.status.podIPs}'输出显示 IPv4 和 IPv6:
[{"ip":"10.244.1.5"},{"ip":"fd00:10:244:1::5"}]Pod 内的应用程序应该绑定到 ::(所有地址)或特别绑定到 0.0.0.0:
# Python 示例 - 绑定到 IPv4 和 IPv6
import socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
sock.bind(("::", 8080))
sock.listen(5)或者分别绑定到 0.0.0.0 用于 IPv4 和 :: 用于 IPv6。
服务配置#
服务可以是仅 IPv4、仅 IPv6 或双栈。使用 ipFamilyPolicy 和 ipFamilies 字段控制这一点。
双栈服务(双栈集群中的默认值):
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ipFamilyPolicy: RequireDualStack
ipFamilies:
- IPv4
- IPv6
selector:
app: myapp
ports:
- port: 80
targetPort: 8080仅 IPv4 服务:
apiVersion: v1
kind: Service
metadata:
name: myservice-v4
spec:
ipFamilyPolicy: SingleStack
ipFamilies:
- IPv4
selector:
app: myapp
ports:
- port: 80仅 IPv6 服务:
apiVersion: v1
kind: Service
metadata:
name: myservice-v6
spec:
ipFamilyPolicy: SingleStack
ipFamilies:
- IPv6
selector:
app: myapp
ports:
- port: 80检查服务 IP:
kubectl get svc myservice -o jsonpath='{.spec.clusterIPs}'输出:
["10.96.100.5","fd00:10:96::a5"]LoadBalancer 服务#
LoadBalancer 服务使用双栈前端配置云负载均衡器(如果云提供商支持)。
apiVersion: v1
kind: Service
metadata:
name: web-lb
spec:
type: LoadBalancer
ipFamilyPolicy: RequireDualStack
ipFamilies:
- IPv4
- IPv6
selector:
app: web
ports:
- port: 80
targetPort: 8080检查外部 IP:
kubectl get svc web-lb输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
web-lb LoadBalancer 10.96.100.10 203.0.113.10,2001:db8:1234::10 80:30123/TCP并非所有云提供商都支持双栈负载均衡器。验证平台的支持。
Ingress 控制器#
Ingress 对 IPv6 的支持取决于控制器实现。
支持 IPv6 的流行控制器:
- nginx-ingress:支持双栈,监听 IPv4 和 IPv6
- Traefik:完全双栈支持
- HAProxy Ingress:支持 IPv6
- Contour:支持双栈
为双栈配置 nginx-ingress:
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
type: LoadBalancer
ipFamilyPolicy: RequireDualStack
ipFamilies:
- IPv4
- IPv6
selector:
app.kubernetes.io/name: ingress-nginx
ports:
- name: http
port: 80
targetPort: http
- name: https
port: 443
targetPort: https如果控制器支持,Ingress 资源不需要特殊的 IPv6 配置——它们会自动工作。
网络策略#
NetworkPolicy 资源支持 IPv6 CIDR 块:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ipv6
spec:
podSelector:
matchLabels:
app: myapp
ingress:
- from:
- ipBlock:
cidr: 2001:db8::/32
- ipBlock:
cidr: fd00::/8
egress:
- to:
- ipBlock:
cidr: ::/0
except:
- fc00::/7 # 阻止 ULAIPv4 和 IPv6 规则可以在同一策略中共存。
CNI 插件注意事项#
不同的 CNI 插件以不同方式处理双栈。
Calico#
Calico 通过 IP 池支持双栈:
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: ipv4-pool
spec:
cidr: 10.244.0.0/16
ipipMode: Never
natOutgoing: true
nodeSelector: all()
---
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: ipv6-pool
spec:
cidr: fd00:10:244::/56
natOutgoing: false
nodeSelector: all()在 Calico 中启用 IPv6:
kubectl set env daemonset/calico-node -n kube-system IP6=autodetect
kubectl set env daemonset/calico-node -n kube-system FELIX_IPV6SUPPORT=trueCilium#
Cilium 具有原生双栈支持。在安装期间启用:
helm install cilium cilium/cilium \
--namespace kube-system \
--set ipv4.enabled=true \
--set ipv6.enabled=true \
--set tunnel=disabled \
--set autoDirectNodeRoutes=trueFlannel#
Flannel 需要在 DaemonSet 配置中使用双栈模式:
apiVersion: v1
kind: ConfigMap
metadata:
name: kube-flannel-cfg
namespace: kube-system
data:
net-conf.json: |
{
"Network": "10.244.0.0/16",
"IPv6Network": "fd00:10:244::/56",
"Backend": {
"Type": "vxlan"
}
}Weave#
Weave 支持两种 IPAM 模式的双栈:
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')&env.IPALLOC_RANGE=10.244.0.0/16&env.IPALLOC_RANGE=fd00:10:244::/56"常见陷阱#
应用程序绑定#
应用程序必须显式监听 IPv6 地址。绑定到 0.0.0.0 只监听 IPv4。
错误:
server.bind(("0.0.0.0", 8080)) # 仅 IPv4正确:
server.bind(("::", 8080)) # IPv6(如果 IPV6_V6ONLY=0 则包括 IPv4)许多语言默认为仅 IPv4。检查框架文档。
DNS 解析#
双栈环境中的 DNS 查询返回 A 和 AAAA 记录。应用程序应该尝试两者,优先选择 IPv6。
一些较旧的库只查询 A 记录。更新依赖项或显式配置 DNS 解析。
防火墙规则#
容器防火墙(iptables/ip6tables)需要两个系列的规则。如果配置正确,Docker 和 Kubernetes 会自动处理这一点,但自定义规则可能会阻止 IPv6。
验证 IPv6 防火墙规则:
sudo ip6tables -L -n -v外部连接#
具有 IPv6 的容器需要正确路由到外部网络。如果主机没有 IPv6 连接,容器也不会有。
首先测试主机 IPv6:
ping6 google.com如果失败,在排查容器之前修复主机网络。
StatefulSet 无头服务#
具有无头服务的 StatefulSet 为 pod DNS 名称返回 IPv4 和 IPv6 地址:
nslookup web-0.myservice.default.svc.cluster.local连接到 StatefulSet pod 的应用程序必须优雅地处理多个地址。
测试双栈部署#
部署测试应用程序:
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app
spec:
replicas: 2
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: test-svc
spec:
type: LoadBalancer
ipFamilyPolicy: RequireDualStack
ipFamilies:
- IPv4
- IPv6
selector:
app: test
ports:
- port: 80应用并测试:
kubectl apply -f test-app.yaml
# 获取服务 IP
kubectl get svc test-svc
# 测试 IPv4
curl http://<ipv4-external-ip>
# 测试 IPv6
curl -6 http://[<ipv6-external-ip>]从 pod 内部测试双栈连接:
kubectl run -it --rm debug --image=alpine --restart=Never -- sh
# Pod 内部
apk add curl bind-tools
nslookup test-svc
curl -4 http://test-svc # IPv4
curl -6 http://test-svc # IPv6生产注意事项#
- 在可观测性工具中监控两个地址系列
- 测试一个系列不可用时的故障转移行为
- 为 IPv4 和 IPv6 配置健康检查
- 记录网络拓扑,包括 IPv6 前缀
- 规划 IP 地址分配以避免冲突
- 在 CI/CD 流水线中启用 IPv6进行测试
- 培训团队进行双栈故障排除
相关文章#
- 开发人员的 IPv6 - 应用层 IPv6 实现
- AWS、Azure 和 GCP 中的 IPv6 - 云平台 IPv6 配置
- 在网络上启用 IPv6 - 基础架构范围的 IPv6 部署