在云原生网络向纯 IPv6 演进的过程中,许多 K8s 集群已采用 IPv6,但大量存量服务仍只支持 IPv4。当 Pod 仅有 IPv6、外部依赖仅监听 IPv4 时,便出现协议不兼容问题。本文通过一台双栈服务器部署 Nginx 反向代理,使纯 IPv6 Pod 经 IPv6 入口接入,再由 Nginx 以 IPv4 对外通信。
1、场景与痛点
- Pod(纯 IPv6) ──✗──> 外部服务(纯 IPv4)
- IPv6 与 IPv4 是两套完全独立的协议栈,彼此无法直接通信
1.1 需求拆解
- Pod 侧:使用 IPv6 地址访问,无需感知外部是 IPv4
- 外部服务侧:看到的来源是 IPv4 地址(白名单/安全策略要求)
- 方案约束:不改造 K8s 网络插件,不引入复杂的 NAT64/DNS64 基础设施
2、架构设计
2.1、核心思路
- **核心思路:**用双栈 Nginx 做"协议翻译",引入一台同时拥有 IPv6 和 IPv4 地址的服务器,部署 Nginx 作为反向代理
Pod (IPv6) → Nginx (IPv6 入口) → Nginx (IPv4 出口) → 外部服务 (IPv4)
Nginx 在这里扮演了协议网关的角色:
-
**入站:**监听 IPv6 端口,接收来自 Pod 的请求
-
**出站:**绑定指定 IPv4 地址,转发请求到外部服务
2.2、完整数据流
┌───────────────────────────────────────────────────────
│ K8s 集群(纯 IPv6 网络平面)
│
│ ┌──────────┐
│ │ Pod │ 访问 https://registry6.abcd.com:5000/yunmassms/
│ │ (IPv6) │ ─────────────────────────┐
│ └──────────┘ │
│ │ │
│ ┌──────▼────────┐ │
│ │ Worker Node │ /etc/hosts 映射 │
│ │ (IPv6 路由) │ 域名 → Nginx IPv6 地址 │
│ └──────┬────────┘ │
└────────┼─────────────────────────┼────────────────────
│ IPv6 (:5000) │
▼ │
┌──────────────────────────────────┼────────────────────
│ Nginx 代理服务器(双栈) │
│ │
│ IPv6 入口: 2408:8608:c000:1202::71 :5000 │
│ IPv4 出口: 192.201.5.166 ──────────────── ─┘
│ ▼
│ ┌─────────────────────────────────────────────────────
│ │ Nginx 核心动作:
│ │ ① 接收 IPv6 请求
│ │ ② proxy_bind 绑定 IPv4 出口
│ │ ③ proxy_pass 转发到外部 IPv4 服务
│ │ ④ 外部服务看到来源 = 192.201.5.166 (IPv4)
│ └─────────────────────────────────────────────────────
└─────────────────────┬─────────────────────────────────
│ IPv4
▼
┌───────────────────────────────────────────────────────
│ 外部服务(IPv4 Only)
│ abcd.bcactc.cn → 143.254.24.66:443
│ 视角:请求来自 192.201.5.166
└────────────────────────────────────────────────────────
3、实施步骤
3.1、确认双栈服务器网络就绪
# 登录 Nginx 服务器,分别验证 IPv6 入站和 IPv4 出站能力
# 验证 IPv6 地址已配置
ip -6 addr show | grep "2408:8608:c000:1202::71"
# 验证 IPv4 出口地址存在
ip -4 addr show | grep "192.201.5.166"
# 验证 IPv4 能连通外部服务
curl -v https://143.254.24.66:443/ -H "Host: abcd.bcactc.cn" --resolve abcd.bcactc.cn:443:143.254.24.66
3.2、编写 Nginx 反向代理配置
# /usr/local/nginx/conf/conf.d/ipv6-to-ipv4-proxy.conf
server {
# 仅监听 IPv6 的 5000 端口
listen [::]:5000 ssl;
# SSL 证书(Pod 端 HTTPS 访问需要)
# ssl_certificate /etc/nginx/certs/registry6.abcd.com.crt;
# ssl_certificate_key /etc/nginx/certs/registry6.abcd.com.key;
server_name registry6.abcd.com;
location /abcd/ {
# ===== 转发目标(外部 IPv4 服务,直接用 IP 避免 DNS 解析)=====
proxy_pass https://143.254.24.66:443/;
# ===== SSL/TLS 设置 =====
proxy_ssl_server_name on;
proxy_ssl_name abcd.bcactc.cn;
proxy_ssl_verify off; # 测试阶段关闭,生产建议开启
# ===== 核心:绑定 IPv4 出口地址 =====
# 外部服务将看到此 IP 作为请求来源
proxy_bind 192.201.5.166;
# ===== 请求头 =====
proxy_set_header Host abcd.bcactc.cn;
proxy_set_header Authorization $http_authorization;
# 关键:只传公网 nginx 服务器的 IPv4,不透传 Pod 的 IPv6
proxy_set_header X-Real-IP 209.232.13.17;
proxy_set_header X-Forwarded-For 209.232.13.17;
proxy_set_header X-Forwarded-Proto https;
# ===== 超时控制 =====
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}
# 配置要点
## listen [::]:5000:只接受 IPv6 连接,确保 Pod 的 IPv6 流量能进入
## proxy_pass:直连外部服务 IP,绕过 DNS(避免 IPv6 DNS 解析失败)
## proxy_bind 192.201.5.166:强制 Nginx 用指定 IPv4 发起出站连接
## proxy_set_header X-Real-IP:外部服务获取到的 "客户端 IP ",填公网 IPv4
## proxy_ssl_name:SNI 扩展,告知后端服务器正确的域名
3.3、校验并加载 Nginx 配置
# 语法检查
nginx -t
# 重载配置(不中断现有连接)
nginx -s reload
# 确认监听状态
ss -tlnp | grep 5000
# 预期输出包含 :::5000
3.4、配置 K8s Worker 节点 hosts 映射
# 编辑 hosts 文件
cat >> /etc/hosts << 'EOF'
2408:8608:c000:1202::71 registry6.abcd.com
EOF
# 验证解析
getent hosts registry6.abcd.com
# 应输出: 2408:8608:c000:1202::71 registry6.abcd.com
3.5、Pod 内验证访问
# 基础连通性
curl -v https://registry6.abcd.com:5000/abcd/mscore/app/common
# 如果证书未配置,可临时跳过验证
curl -k https://registry6.abcd.com:5000/abcd/mscore/app/common
# 成功时,外部服务日志中应显示请求来源为 192.201.5.166(IPv4)
4、生产环境增强建议
- SSL 证书 :为
registry6.abcd.com配置有效证书,Pod 端无需-k跳过验证 - proxy_ssl_verify:开启后端证书校验,防止中间人攻击
- 高可用:部署多台 Nginx + Keepalived,避免单点故障
- 日志 :记录
$proxy_protocol_addr和$remote_addr便于审计