24、Docker网络:IPv6使用与故障排查

Docker网络:IPv6使用与故障排查

1. NDP代理与IPv6子网

NDP代理类似于代理ARP,主机在响应邻居发现请求时提供自己的MAC地址。例如:

2003:ab11::c000:242:ac11:2 dev eth0 lladdr 00:0c:29:7f:3d:64 REACHABLE

通过查看邻居表和接口信息,可以发现邻居表中的MAC地址实际上是每个主机的eth0 MAC地址:

user@docker1:~$ ip link show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast 
state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:29:50:b8:cc brd ff:ff:ff:ff:ff:ff

这种方法在无法向外部网络通告Docker IPv6子网的情况下效果较好,但它依赖于为每个要代理的IPv6地址设置单独的代理条目,每创建一个容器都需要生成一个额外的IPv6代理地址。

2. 用户定义网络与IPv6

用户定义网络可以像使用IPv4一样利用IPv6寻址,网络相关参数同时适用于IPv4和IPv6。以下是定义一个同时具有IPv4和IPv6寻址的用户定义网络的步骤:
- 准备工作 :使用单个Docker主机,假设Docker已安装并处于默认配置,使用用户定义网络的IPv6寻址时,不需要使用 --ipv6 服务级参数启用Docker服务。
- 定义网络

user@docker1:~$ docker network create -d bridge \
--subnet 2003:ab11:0:0:c000::/66 --subnet 192.168.127.0/24 \
--ipv6 ipv6_bridge

这里需要注意:
- --subnet 参数定义了两次,分别定义了IPv4子网和IPv6子网。
- --ipv6 选项用于启用该网络的IPv6功能,如果不定义此选项,主机的网关接口将不会被定义。
- 启动容器

user@docker1:~$ docker run -d --name=web1 --net=ipv6_bridge \
--ip 192.168.127.10 --ip6 2003:ab11::c000:0:0:10 \
jonlangemak/web_server_1

通过 --ip --ip6 参数分别为容器指定了IPv4和IPv6地址。
- 检查网络信息

user@docker1:~$ docker network inspect ipv6_bridge
[
    {
        "Name": "ipv6_bridge",
        "Id": "0c6e760998ea6c5b99ba39f3c7ce63b113dab2276645e5fb7a2207f06273401a",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.127.0/24"
                },
                {
                    "Subnet": "2003:ab11:0:0:c000::/66"
                }
            ]
        },
        "Containers": {
            "38e7ac1a0d0ce849a782c5045caf770c3310aca42e069e02a55d0c4a601e6b5a": {
                "Name": "web1",
                "EndpointID": "a80ac4b00d34d462ed98084a238980b3a75093591630b5832f105d400fabb4bb",
                "MacAddress": "02:42:c0:a8:7f:0a",
                "IPv4Address": "192.168.127.10/24",
                "IPv6Address": "2003:ab11::c000:0:0:10/66"
            }
        },
        "Options": {
            "com.docker.network.enable_ipv6": "true"
        }
    }
]
  • 检查主机网络配置
user@docker1:~$ ip addr show
…<Additional output removed for brevity>… 
9: br-0b2efacf6f85: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc 
noqueue state UP group default
    link/ether 02:42:09:bc:9f:77 brd ff:ff:ff:ff:ff:ff
    inet 192.168.127.1/24 scope global br-0b2efacf6f85
       valid_lft forever preferred_lft forever
    inet6 2003:ab11::c000:0:0:1/66 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::42:9ff:febc:9f77/64 scope link
       valid_lft forever preferred_lft forever
    inet6 fe80::1/64 scope link
       valid_lft forever preferred_lft forever
…<Additional output removed for brevity>…
  • 检查容器网络配置
user@docker1:~$ docker exec web1 ip route
default via 192.168.127.1 dev eth0
192.168.127.0/24 dev eth0  proto kernel  scope link  src 192.168.127.10
user@docker1:~$ docker exec web1 ip -6 route
2003:ab11:0:0:c000::/66 dev eth0  proto kernel  metric 256
fe80::/64 dev eth0  proto kernel  metric 256
default via 2003:ab11::c000:0:0:1 dev eth0  metric 1024

用户定义网络不支持主机防火墙集成以支持出站伪装或入站端口发布,IPv6在主机内外的连接与docker0桥接器一样,需要原生路由IPv6流量。此外,启动第二个容器时,嵌入式DNS对IPv4和IPv6寻址都有效:

user@docker1:~$ docker run -d --name=web2 --net=ipv6_bridge \
jonlangemak/web_server_1
user@docker1:~$
user@docker1:~$ docker exec -it web2 ping web1 -c 2
PING web1 (192.168.127.10): 48 data bytes
56 bytes from 192.168.127.10: icmp_seq=0 ttl=64 time=0.113 ms
56 bytes from 192.168.127.10: icmp_seq=1 ttl=64 time=0.111 ms
--- web1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.111/0.112/0.113/0.000 ms
user@docker1:~$ 
user@docker1:~$ docker exec -it web2 ping6 web1 -c 2
PING web1 (2003:ab11::c000:0:0:10): 48 data bytes
56 bytes from web1.ipv6_bridge: icmp_seq=0 ttl=64 time=0.113 ms
56 bytes from web1.ipv6_bridge: icmp_seq=1 ttl=64 time=0.127 ms
--- web1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.113/0.120/0.127/0.000 ms
3. 使用tcpdump验证网络路径

tcpdump是一个强大的故障排除工具,可用于捕获主机上一个或多个接口的网络流量。以下是使用tcpdump验证容器网络流量的步骤:
- 准备工作 :使用单个Docker主机,假设Docker已安装并处于默认配置,需要root权限来检查和更改主机的网络和防火墙配置,需要安装tcpdump:

sudo apt-get install tcpdump
  • 启动容器
user@docker1:~$ docker run -dP --name web1 jonlangemak/web_server_1
ea32565ece0c0c22eace935113b6697bebe837f0b5ddf31724f371220792fb15
  • 检查发布端口
user@docker1:~$ docker port web1
80/tcp -> 0.0.0.0:32768
  • 捕获入站流量
user@docker1:~$ sudo tcpdump -qnn -i eth0 dst port 32768
tcpdump: verbose output suppressed, use -v or -vv for full protocol 
decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
15:46:07.629747 IP 10.20.30.41.55939 > 10.10.10.101.32768: tcp 0
15:46:07.629997 IP 10.20.30.41.55940 > 10.10.10.101.32768: tcp 0
15:46:07.630257 IP 10.20.30.41.55939 > 10.10.10.101.32768: tcp 0

使用的参数说明:
- q :使tcpdump安静,不生成过多输出。
- nn :不尝试将IP解析为DNS名称。
- i :指定要捕获的接口。
- dst port :过滤目标端口为32768的流量。
- 捕获docker0桥接器上的流量

user@docker1:~$ sudo tcpdump -qnn -i docker0
tcpdump: verbose output suppressed, use -v or -vv for full protocol 
decode
listening on docker0, link-type EN10MB (Ethernet), capture size 65535 
bytes
16:34:54.193822 IP 10.20.30.41.53846 > 172.17.0.2.80: tcp 0
16:34:54.193848 IP 10.20.30.41.53847 > 172.17.0.2.80: tcp 0
16:34:54.193913 IP 172.17.0.2.80 > 10.20.30.41.53846: tcp 0
16:34:54.193940 IP 172.17.0.2.80 > 10.20.30.41.53847: tcp 0

如果有多个容器在docker0桥上运行,可以指定IP地址进行过滤:

user@docker1:~$ sudo tcpdump -qnn -i docker0 dst 172.17.0.2
tcpdump: verbose output suppressed, use -v or -vv for full protocol 
decode
listening on docker0, link-type EN10MB (Ethernet), capture size 65535 
bytes
16:42:22.332555 IP 10.20.30.41.53878 > 172.17.0.2.80: tcp 0
16:42:22.332940 IP 10.20.30.41.53878 > 172.17.0.2.80: tcp 0
  • 关联容器MAC地址和接口
user@docker1:~$ sudo tcpdump -qnne -i docker0 host 172.17.0.2
tcpdump: verbose output suppressed, use -v or -vv for full protocol 
decode
listening on docker0, link-type EN10MB (Ethernet), capture size 65535 
bytes
16:59:33.334941 02:42:ab:27:0e:3e > 02:42:ac:11:00:02, IPv4, length 66: 
10.20.30.41.57260 > 172.17.0.2.80: tcp 0
16:59:33.335012 02:42:ac:11:00:02 > 02:42:ab:27:0e:3e, IPv4, length 66: 
172.17.0.2.80 > 10.20.30.41.57260: tcp 0

通过 e 参数显示每个帧的源和目标MAC地址,然后通过 ip link show dev docker0 查看docker0桥的MAC地址,再使用 bridge fdb show | grep 02:42:ac:11:00:02 找到容器MAC地址对应的接口:

user@docker1:~$ bridge fdb show | grep 02:42:ac:11:00:02
02:42:ac:11:00:02 dev vetha431055

最后在该接口上进行捕获验证:

user@docker1:~$ sudo tcpdump -qnn -i vetha431055
tcpdump: WARNING: vetha431055: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol 
decode
listening on vetha431055, link-type EN10MB (Ethernet), capture size 65535 
bytes
21:01:24.503939 IP 10.20.30.41.58035 > 172.17.0.2.80: tcp 0
21:01:24.503990 IP 172.17.0.2.80 > 10.20.30.41.58035: tcp 0
4. 验证VETH对

VETH对是Docker中连接容器网络命名空间和默认网络命名空间的重要组件。以下是验证VETH对的步骤:
- 准备工作 :使用单个Docker主机,假设Docker已安装并处于默认配置,需要root权限来检查和更改主机的网络和防火墙配置。
- 从主机端开始匹配

user@docker1:~$ ip -d link show
…<Additional output removed for brevity>… 
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue 
state UP mode DEFAULT group default
    link/ether 02:42:ab:27:0e:3e brd ff:ff:ff:ff:ff:ff promiscuity 0
    bridge
6: vetha431055@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc 
noqueue master docker0 state UP mode DEFAULT group default
    link/ether 82:69:cb:b6:9a:db brd ff:ff:ff:ff:ff:ff promiscuity 1
    veth
- `-d`参数显示接口的详细信息,确认该接口是VETH对。
- VETH对命名遵循`<end1>@<end2>`命名约定,这里`vetha431055`是本地接口,`if5`是另一端。
- 使用`ethtool`命令确认另一端的接口索引:
user@docker1:~$ sudo ethtool -S vetha431055
NIC statistics:
     peer_ifindex: 5
- 使用`xargs`命令查找具有该接口索引的容器:
docker ps -q | xargs --verb -I {} docker exec {} ip link | grep ^5:

输出示例:

user@docker1:~$ docker ps -q | xargs --verb -I {} docker exec {} ip link 
| grep ^5:
docker exec 4b521df22184 ip link
docker exec 772e12b15c92 ip link
docker exec d8f3e7936690 ip link
docker exec a2e3201278e2 ip link
docker exec f9216233ba56 ip link
docker exec ea32565ece0c ip link
5: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue 
state UP
  • 从容器端开始匹配
user@docker1:~$ docker exec web1 ip -d link show dev eth0
5: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue 
state UP

容器端接口命名告诉我们主机端匹配接口的索引。

总结

本文介绍了Docker网络中NDP代理、用户定义网络与IPv6的使用,以及使用tcpdump验证网络路径和验证VETH对的方法。通过这些方法,可以更好地配置和排查Docker网络问题。

流程图

graph TD;
    A[准备工作] --> B[定义用户网络];
    B --> C[启动容器];
    C --> D[检查网络信息];
    D --> E[检查主机网络配置];
    E --> F[检查容器网络配置];
    G[准备工作] --> H[启动容器];
    H --> I[检查发布端口];
    I --> J[捕获入站流量];
    J --> K[捕获docker0桥流量];
    K --> L[关联容器MAC和接口];
    M[准备工作] --> N[从主机端匹配VETH对];
    N --> O[从容器端匹配VETH对];

表格

操作 命令示例 说明
定义用户网络 docker network create -d bridge --subnet 2003:ab11:0:0:c000::/66 --subnet 192.168.127.0/24 --ipv6 ipv6_bridge 同时定义IPv4和IPv6子网,启用IPv6功能
启动容器 docker run -d --name=web1 --net=ipv6_bridge --ip 192.168.127.10 --ip6 2003:ab11::c000:0:0:10 jonlangemak/web_server_1 指定容器所属网络和IPv4、IPv6地址
捕获入站流量 sudo tcpdump -qnn -i eth0 dst port 32768 过滤目标端口为32768的入站流量
捕获docker0桥流量 sudo tcpdump -qnn -i docker0 捕获docker0桥上的所有流量
关联容器MAC和接口 bridge fdb show | grep 02:42:ac:11:00:02 根据容器MAC地址找到对应的接口
从主机端匹配VETH对 docker ps -q | xargs --verb -I {} docker exec {} ip link | grep ^5: 查找具有指定接口索引的容器
从容器端匹配VETH对 docker exec web1 ip -d link show dev eth0 查看容器端接口信息
5. 验证发布端口和出站伪装

在 Docker 网络中,验证发布端口和出站伪装是确保容器网络正常工作的重要环节。以下是验证的步骤:

  • 准备工作 :使用单个 Docker 主机,确保 Docker 已安装并处于默认配置,需要 root 权限来检查和更改主机的网络和防火墙配置。
  • 启动容器并发布端口
user@docker1:~$ docker run -dP --name web1 jonlangemak/web_server_1
ea32565ece0c0c22eace935113b6697bebe837f0b5ddf31724f371220792fb15

这里使用 -dP 参数, -d 表示容器在后台运行, -P 表示将容器内暴露的端口随机映射到主机的端口。
- 查看发布端口

user@docker1:~$ docker port web1
80/tcp -> 0.0.0.0:32768

可以看到容器内的 80 端口被映射到了主机的 32768 端口。
- 验证入站流量 :可以使用前面提到的 tcpdump 工具来验证入站流量是否能到达主机的映射端口。

user@docker1:~$ sudo tcpdump -qnn -i eth0 dst port 32768
  • 验证出站伪装 :当容器访问外部网络时,容器的流量会通过主机的 IP 地址进行出站伪装。可以在容器内访问外部网络资源,然后在主机上使用 tcpdump 查看流量是否以主机的 IP 地址发出。例如,在容器内执行 ping 命令:
user@docker1:~$ docker exec web1 ping 8.8.8.8 -c 2

同时在主机上捕获流量:

user@docker1:~$ sudo tcpdump -qnn -i eth0 src host 主机IP地址

这里的 主机IP地址 是 Docker 主机的实际 IP 地址。

6. 验证名称解析

在 Docker 网络中,名称解析是让容器能够通过名称相互访问的关键。以下是验证名称解析的方法:

  • 准备工作 :使用单个 Docker 主机,确保 Docker 已安装并处于默认配置,启动多个容器并连接到同一个用户定义网络。
user@docker1:~$ docker network create -d bridge my_network
user@docker1:~$ docker run -d --name=web1 --net=my_network jonlangemak/web_server_1
user@docker1:~$ docker run -d --name=web2 --net=my_network jonlangemak/web_server_1
  • 在容器内进行名称解析测试 :在 web2 容器内尝试通过名称访问 web1 容器。
user@docker1:~$ docker exec -it web2 ping web1 -c 2

如果名称解析正常,应该能够看到 ping 命令成功响应。

PING web1 (172.x.x.x): 48 data bytes
56 bytes from 172.x.x.x: icmp_seq=0 ttl=64 time=0.113 ms
56 bytes from 172.x.x.x: icmp_seq=1 ttl=64 time=0.111 ms
--- web1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.111/0.112/0.113/0.000 ms
  • 检查容器的 DNS 配置 :可以查看容器的 /etc/resolv.conf 文件,确认 DNS 配置是否正确。
user@docker1:~$ docker exec web2 cat /etc/resolv.conf
7. 构建测试容器

构建测试容器可以帮助我们更好地验证 Docker 网络的各项功能。以下是构建测试容器的步骤:

  • 创建 Dockerfile :创建一个名为 Dockerfile 的文件,内容如下:
FROM alpine:latest
RUN apk add --no-cache iputils ping curl
CMD ["sh"]

这里使用 alpine 作为基础镜像,安装 ping curl 工具,方便后续进行网络测试。
- 构建镜像 :在包含 Dockerfile 的目录下执行以下命令构建镜像。

user@docker1:~$ docker build -t test_container .
  • 运行测试容器
user@docker1:~$ docker run -it --net=my_network test_container

在测试容器内可以使用 ping curl 等工具进行网络测试。例如:

/ # ping web1
/ # curl http://web1
8. 重置本地 Docker 网络数据库

当 Docker 网络出现问题时,重置本地 Docker 网络数据库可能会解决问题。以下是重置的步骤:

  • 停止 Docker 服务
user@docker1:~$ sudo systemctl stop docker
  • 删除 Docker 网络配置文件
user@docker1:~$ sudo rm -rf /var/lib/docker/network
  • 重启 Docker 服务
user@docker1:~$ sudo systemctl start docker

总结

本文详细介绍了 Docker 网络中多个方面的操作和验证方法,包括 NDP 代理、用户定义网络与 IPv6 的使用、使用 tcpdump 验证网络路径、验证 VETH 对、验证发布端口和出站伪装、验证名称解析、构建测试容器以及重置本地 Docker 网络数据库。掌握这些方法可以帮助我们更好地配置和排查 Docker 网络问题,确保容器网络的稳定运行。

流程图

graph TD;
    A[启动容器并发布端口] --> B[查看发布端口];
    B --> C[验证入站流量];
    B --> D[验证出站伪装];
    E[创建用户定义网络并启动多个容器] --> F[在容器内进行名称解析测试];
    F --> G[检查容器的DNS配置];
    H[创建Dockerfile] --> I[构建镜像];
    I --> J[运行测试容器];
    K[停止Docker服务] --> L[删除网络配置文件];
    L --> M[重启Docker服务];

表格

操作 命令示例 说明
启动容器并发布端口 docker run -dP --name web1 jonlangemak/web_server_1 容器在后台运行并随机映射端口
验证入站流量 sudo tcpdump -qnn -i eth0 dst port 32768 检查入站流量是否到达映射端口
验证出站伪装 sudo tcpdump -qnn -i eth0 src host 主机IP地址 检查容器流量是否以主机IP发出
名称解析测试 docker exec -it web2 ping web1 -c 2 测试容器间名称解析
检查 DNS 配置 docker exec web2 cat /etc/resolv.conf 查看容器 DNS 配置
构建镜像 docker build -t test_container . 使用 Dockerfile 构建镜像
运行测试容器 docker run -it --net=my_network test_container 运行测试容器进行网络测试
停止 Docker 服务 sudo systemctl stop docker 停止 Docker 服务
删除网络配置文件 sudo rm -rf /var/lib/docker/network 删除 Docker 网络配置文件
重启 Docker 服务 sudo systemctl start docker 重启 Docker 服务
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值