AWS上进行Docker IPv6改造总结

说明:

  • CentOS7 + AWS Linux 系统环境
  • AWS 提供的是 IPv6 + IPv4 双栈方案
  • 可以适配 AWS Auto Scaling 自动缩放场景

AWS 实例 IPv6 配置

AWS IPv6 迁移文档

无需特别配置

  • Amazon Linux 2016.09.0 以上
  • Windows Server 2008 R2 以上

CentOS7.5

  • 通过cloud-init
  • 如果希望不重启系统,可以参照里面修改 /etc/sysconfig/network-scripts/ifcfg-eth0 部分,再 sudo service network restart

Docker IPv6 支持

默认是没有开启 IPv6支持的
!! 注意:以下命令会覆盖配置,如果 /etc/docker/daemon.json 有其他配置项,请手动修改

1
2
3
4
5
6
7
8
cat << EOF | sudo tee /etc/docker/daemon.json
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:1::/64"
}
EOF

sudo service docker restart

Docker 官方文档 >>

此时宿主机的ipv6转发会开启 = 1

1
2
sysctl net.ipv6.conf.default.forwarding
sysctl net.ipv6.conf.all.forwarding

Docker IPv6 NAT 连接外网问题

测试:ping6 yryz.net 可以解析到ipv6地址,但是ping不通。

docker run --rm -it alpine sh -c "ip a && ping6 yryz.net -c 3"

目前测试环境docker 18.06.1-ce 没有为ipv6实现像ipv4那样自动添加相关NAT配置,我们需要手动来解决。可能社区也不鼓励大家用NAT吧,目前过渡阶段和安全考虑,我们还是暂时用NAT来达到和之前的网络模型一致。

小知识:

SNAT 和 DNAT 是 iptables 中使用 NAT 规则相关的的两个重要概念。如上图所示,如果内网主机访问外网而经过路由时,源 IP 会发生改变,这种变更行为就是 SNAT;反之,当外网的数据经过路由发往内网主机时,数据包中的目的 IP (路由器上的公网 IP) 将修改为内网 IP,这种变更行为就是 DNAT 。

与 SNAT 和 DNAT所对应的两个链分别是 POSTROUTING和PREROUTING 。
MASQUERADE,地址伪装,算是SNAT中的一种特例,可以实现自动化的SNAT 解决像 AWS Auto Scaling 自动缩放场景 中事先不知道接口IP情况很好用。

配置 ip6tables:

1
2
sudo ip6tables -t nat -I POSTROUTING -j MASQUERADE
sudo service ip6tables save

ip6tables -t nat -I POSTROUTING -s 2001:db8:1::1/64 -j MASQUERADE -o eth0

解决ip6tables持久化重启加载
如果CentOS7、Amazon Linux不生效,需要禁用firewalld,安装iptables

1
2
3
4
5
6
sudo systemctl disable firewalld
sudo yum install iptables-services -y
sudo systemctl enable iptables
sudo systemctl enable ip6tables
sudo systemctl start iptables
sudo systemctl start ip6tables

注意:因为docker自动添加了iptables规则,重启iptables后需要重新docker,否则服务不可用。

检查是否生效
sudo ip6tables -L -t nat

1
2
3
4
5
6
7
8
9
10
11
12
Chain PREROUTING (policy ACCEPT)
target prot opt source destination

Chain INPUT (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all anywhere anywhere

Docker 容器网络测试

docker run --rm -it alpine sh -c "ip a && ping6 yryz.net -c 3"

容器中测试

docker-compose IPv6 支持

用 docker-compose 编排的容器,默认会创建一个Network,没有使用docker默认的。所以需要手动指定IPv6子网配置。

注意docker-compose 2.1修复了ipv6的一个bug

参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: '2.1'

services:
app:
image: busybox
command: sh -c 'ifconfig && ping6 -c 3 yryz.net'
networks:
app_net:
ipv4_address: 172.16.238.10
ipv6_address: 2001:3984:3989::10

networks:
app_net:
enable_ipv6: true
driver: bridge
ipam:
driver: default
config:
- subnet: 172.16.238.0/24
gateway: 172.16.238.1
- subnet: 2001:3984:3989::/64
gateway: 2001:3984:3989::1

上面的配置都不用,机器支持IPv6 docker-compose就直接能支持了
docker-compose测试

其他问题

IPv6路由被docker删除的问题

docker-compose 创建自定义网络后,启动容器会导致主机无法访问外网IPv6地址(注意eth0同网段IP地址不受影响)
默认IPv6路由不明原因被docker删除,暂时手动添加解决(参考,ip可以在service network restart通过 ip -6 route | grep default 获取
ip -6 route add default via fe80::45b:91ff:fed9:2a6b dev eth0

AWS AutoScaling

需要将子网设置为在实例创建时自动分配IPv6地址

8fab91bf6442d16da856869ba390a6c8

https://docs.aws.amazon.com/vpc/latest/userguide/vpc-subnets-commands-example-ipv6.html

或直接
aws ec2 modify-subnet-attribute --subnet-id ${subnet_id} --assign-ipv6-address-on-creation

AWS ELB启用IPv6

AWS ELB IPv4+IPv6双栈方案