在下面指定的环境中,IPv4 像猫一样呼噜呼噜地叫,但 IPv6 会在短时间后消失 - 也就是说,即使主机也无法通过 Docker 网络通过 IPv6 到达其容器。我是否遗漏了什么?
编辑#1
用全局变量替换了 64:ff9b::,但问题仍然存在。主机失去了与直接连接的 Docker 容器的 IPv6(而非 IPv4)连接。首先是“无到主机的路由”,然后是超时。
剧本.yml
---
- hosts: all
become: yes
become_method: sudo
tasks:
- import_tasks: tasks/firewall.yml
- import_tasks: tasks/router.yml
- import_tasks: tasks/docker.yml
- name: /usr/local/docker-services
file:
path: /usr/local/docker-services
owner: root
group: root
mode: '0700'
state: directory
- name: nginx-site.conf
copy:
dest: /usr/local/docker-services/nginx-site.conf
owner: root
group: root
mode: '0666'
src: files/nginx-site.conf
- name: docker-compose.yml
copy:
dest: /usr/local/docker-services/docker-compose.yml
owner: root
group: root
mode: '0666'
content: |
version: '2.4'
networks:
ext-nginx:
internal: true
enable_ipv6: true
driver_opts:
com.docker.network.bridge.name: docker1
ipam:
config:
- subnet: 192.168.234.0/30
gateway: 192.168.234.1
- subnet: 64:ff9b::192.168.234.0/126
gateway: 64:ff9b::192.168.234.1
services:
nginx:
container_name: nginx
image: nginx
restart: always
logging:
options:
labels: container
labels:
container: nginx
networks:
ext-nginx:
ipv4_address: 192.168.234.2
ipv6_address: 64:ff9b::192.168.234.2
priority: 1
volumes:
- type: bind
source: /usr/local/docker-services/nginx-site.conf
target: /etc/nginx/conf.d/default.conf
read_only: true
register: docker_compose_yml
- name: docker-compose.service
copy:
dest: /etc/systemd/system/docker-compose.service
owner: root
group: root
mode: '0644'
src: files/docker-compose.service
register: docker_compose_service
- name: systemctl daemon-reload
when: docker_compose_service.changed
systemd:
daemon_reload: yes
- name: systemctl stop docker-compose.service
when: >-
docker_compose_service.changed
or docker_compose_yml.changed
service:
name: docker-compose
state: stopped
- name: systemctl start docker-compose.service
service:
name: docker-compose
state: started
enabled: yes
任务/防火墙.yml
---
- name: Firewall rules applicator
apt:
name: iptables-persistent
- name: Firewall rules file
loop: [4, 6]
copy:
dest: '/etc/iptables/rules.v{{ item }}'
owner: root
group: root
mode: '0644'
src: 'files/firewall/rules.v{{ item }}'
register: firewall_file
- name: Apply firewall rules
when: 'firewall_file.results[0].changed or firewall_file.results[1].changed'
service:
name: netfilter-persistent
state: restarted
任务/路由器.yml
---
- name: net.ipv4.ip_forward
sysctl:
name: net.ipv4.ip_forward
value: '1'
- name: net.ipv6.conf.all.forwarding
sysctl:
name: net.ipv6.conf.all.forwarding
value: '1'
任务/docker.yml
---
- name: apt-transport-https
apt:
name: apt-transport-https
- name: Docker apt key
apt_key:
url: https://download.docker.com/linux/debian/gpg
- name: Docker apt repo
apt_repository:
filename: docker
repo: >
deb https://download.docker.com/linux/debian
{{ ansible_lsb.codename }} stable
- name: /etc/docker
file:
path: /etc/docker
owner: root
group: root
mode: '0755'
state: directory
- name: /etc/docker/daemon.json
copy:
dest: /etc/docker/daemon.json
owner: root
group: root
mode: '0644'
content: '{"iptables":false}'
- name: Docker
apt:
name: docker-ce
- name: Docker compose
apt:
name: docker-compose
文件/防火墙/规则.v4
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -d 127.0.0.0/8 ! -i lo -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -o docker1 -d 192.168.234.2/32 -p tcp -m tcp --dport 80 -j ACCEPT
-A FORWARD -i docker1 -o eth0 -j ACCEPT
-A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -i eth0 -d 78.47.124.58 -p tcp -m tcp --dport 80 -j DNAT --to 192.168.234.2
-A POSTROUTING -o eth0 ! -s 78.47.124.58 -j MASQUERADE
COMMIT
文件/防火墙/规则.v6
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -d ::1/128 ! -i lo -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -o docker1 -d 64:ff9b::192.168.234.2 -p tcp -m tcp --dport 80 -j ACCEPT
-A FORWARD -i docker1 -o eth0 -j ACCEPT
-A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -i eth0 -d 2a01:4f8:c0c:3bc1::/64 -p tcp -m tcp --dport 80 -j DNAT --to 64:ff9b::192.168.234.2
-A POSTROUTING -o eth0 ! -s 2a01:4f8:c0c:3bc1::/64 -j MASQUERADE
COMMIT
文件/nginx-site.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
文件/docker-compose.service
[Unit]
Requires=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/usr/local/docker-services
ExecStart=/usr/bin/docker-compose up -d --force-recreate
ExecStop=/usr/bin/docker-compose down
[Install]
WantedBy=multi-user.target
答案1
我猜你的 IPv6 防火墙规则正在阻止NDP(邻居发现协议)数据包,从而阻止您的主机正确解析容器的链路层地址。
在 IPv4 堆栈中,链路层(以太网)地址的解析由ARP(地址解析协议),它使用链路层地址作为数据包目的地。当主机发出 ARP 请求或未经请求的 ARP 通告时,这些数据包将直接转发到广播链路层地址(FF:FF:FF:FF:FF:FF
以太网协议中),因此不受过滤iptables
。
在 IPv6 堆栈中,链路层地址的解析由 NDP(邻居发现协议)处理。与 ARP 不同,NDP 数据包实际上是转发到 IPv6 地址的 ICMPv6 数据包,因此需要进行ip6tables
过滤。
我相信,根据我的经验和Arch Linux Wiki 文章,CONNTRACK 模块不是为了跟踪 ICMPv6 NDP 数据包并将回复数据包标记为已确立的或者有关的files/firewall/rules.v6
。我的建议是在文件中明确允许此类流量:
(新规则)
-A INPUT -i docker1 -p ipv6-icmp -m icmp6 --icmpv6-type 133 -m comment --comment router-solicitation -j ACCEPT
-A INPUT -i eth0 -p ipv6-icmp -m icmp6 --icmpv6-type 134 -m comment --comment router-advertisement -j ACCEPT
-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 135 -m comment --comment neighbor-solicitation -j ACCEPT
-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 136 -m comment --comment neighbor-advertisement -j ACCEPT
(完整文件)
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -d ::1/128 ! -i lo -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i docker1 -p ipv6-icmp -m icmp6 --icmpv6-type 133 -m comment --comment router-solicitation -j ACCEPT
-A INPUT -i eth0 -p ipv6-icmp -m icmp6 --icmpv6-type 134 -m comment --comment router-advertisement -j ACCEPT
-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 135 -m comment --comment neighbor-solicitation -j ACCEPT
-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 136 -m comment --comment neighbor-advertisement -j ACCEPT
-A FORWARD -o docker1 -d 64:ff9b::192.168.234.2 -p tcp -m tcp --dport 80 -j ACCEPT
-A FORWARD -i docker1 -o eth0 -j ACCEPT
-A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -i eth0 -d 2a01:4f8:c0c:3bc1::/64 -p tcp -m tcp --dport 80 -j DNAT --to 64:ff9b::192.168.234.2
-A POSTROUTING -o eth0 ! -s 2a01:4f8:c0c:3bc1::/64 -j MASQUERADE
COMMIT