一、问题背景
在 CentOS Stream 10 上安装 Docker 后,发现 Docker 服务可以正常启动,但是部分 Docker 容器无法访问外网。
例如:
docker exec alpine1 ping -c 3 8.8.8.8
出现:
3 packets transmitted, 0 packets received, 100% packet loss
而新创建的默认 bridge 网络容器却可以正常访问:
docker run -d --name alpine-test alpine sleep 3600
docker exec alpine-test ping -c 3 8.8.8.8
结果:
3 packets transmitted, 3 packets received, 0% packet loss
说明 Docker 本身、宿主机网络以及 NAT 基本正常,问题集中在原来的 Docker 自定义网络。
二、排查 iptables 的 addrtype 模块
首先检查:
sudo modprobe xt_addrtype
提示:
modprobe: FATAL: Module xt_addrtype not found
继续检查:
sudo iptables -m addrtype --help
出现:
Warning: Extension addrtype revision 0 not supported, missing kernel module?
再检查:
sudo modinfo xt_addrtype
结果:
modinfo: ERROR: Module xt_addrtype not found.
确认当前内核:
uname -r
例如:
6.12.0-254.el10.x86_64
三、确认 xt_addrtype 属于哪个软件包
使用 DNF 查询:
dnf provides '*/xt_addrtype.ko*'
发现:
kernel-modules-extra-6.12.0-254.el10.x86_64
也就是说,xt_addrtype 并不在当前已经安装的基础内核模块中,而是在:
kernel-modules-extra
四、安装 kernel-modules-extra
直接安装与当前内核版本对应的软件包:
sudo dnf install kernel-modules-extra-$(uname -r)
安装完成后检查:
find /lib/modules/$(uname -r) -type f | grep xt_addrtype
应该能够看到:
/lib/modules/6.12.0-254.el10.x86_64/kernel/net/netfilter/xt_addrtype.ko.xz
然后加载模块:
sudo modprobe xt_addrtype
确认:
lsmod | grep xt_addrtype
正常结果类似:
xt_addrtype 12288 0
至此,xt_addrtype 内核模块缺失问题解决。
五、重启 Docker
重新加载模块后重启 Docker:
sudo systemctl reset-failed docker
sudo systemctl restart docker
sudo systemctl status docker --no-pager -l
确认:
Active: active (running)
说明 Docker 服务正常。
六、重新创建 Docker 测试容器
为了排除原有容器网络配置问题,建议重新创建两个测试容器。
先删除旧容器:
docker rm -f alpine1 alpine2 2>/dev/null
删除旧的自定义网络:
docker network rm ssc_net 2>/dev/null
重新创建网络:
docker network create --driver bridge ssc_net
创建两个 Alpine 容器:
docker run -d \
--name alpine1 \
--network ssc_net \
alpine sleep 3600
docker run -d \
--name alpine2 \
--network ssc_net \
alpine sleep 3600
查看:
docker ps
应该看到:
alpine1
alpine2
七、检查容器网络
查看 alpine1:
docker exec alpine1 ip addr
docker exec alpine1 ip route
正常情况下:
inet 172.18.0.2/16
default via 172.18.0.1 dev eth0
alpine2 通常会获得:
172.18.0.3/16
测试 Docker 网关:
docker exec alpine1 ping -c 3 172.18.0.1
测试外网:
docker exec alpine1 ping -c 3 8.8.8.8
然后测试第二个容器:
docker exec alpine2 ping -c 3 8.8.8.8
如果均出现:
3 packets transmitted, 3 packets received, 0% packet loss
说明 Docker 自定义 bridge 网络已经恢复正常。
八、进一步测试 DNS 和 HTTP
测试 DNS:
docker exec alpine1 ping -c 3 www.baidu.com
或者:
docker exec alpine1 nslookup www.baidu.com
测试 HTTP/HTTPS:
docker exec alpine1 wget -O- -T 5 https://www.baidu.com
如果能够正常返回百度网页 HTML,说明:
容器
↓
Docker bridge
↓
Docker NAT
↓
宿主机
↓
外网
整条网络链路已经正常。
九、问题原因总结
本次问题的核心不是 Docker 服务本身,也不是宿主机无法联网,而是:
CentOS Stream 10
↓
当前内核 6.12.0-254.el10
↓
缺少 kernel-modules-extra
↓
缺少 xt_addrtype.ko
↓
iptables addrtype 模块无法加载
↓
Docker 网络相关规则无法正常工作
通过安装:
kernel-modules-extra-$(uname -r)
即可获得:
xt_addrtype.ko.xz
然后:
sudo modprobe xt_addrtype
即可加载。
十、完整解决命令
如果遇到同样的问题,可以直接按照下面的顺序执行:
# 1. 查看当前内核
uname -r
# 2. 安装额外内核模块
sudo dnf install kernel-modules-extra-$(uname -r)
# 3. 加载 xt_addrtype
sudo modprobe xt_addrtype
# 4. 确认模块
lsmod | grep xt_addrtype
# 5. 重启 Docker
sudo systemctl reset-failed docker
sudo systemctl restart docker
# 6. 删除旧测试容器和网络
docker rm -f alpine1 alpine2 2>/dev/null
docker network rm ssc_net 2>/dev/null
# 7. 创建新的 Docker 网络
docker network create --driver bridge ssc_net
# 8. 创建测试容器
docker run -d --name alpine1 --network ssc_net alpine sleep 3600
docker run -d --name alpine2 --network ssc_net alpine sleep 3600
# 9. 测试外网
docker exec alpine1 ping -c 3 8.8.8.8
docker exec alpine2 ping -c 3 8.8.8.8
# 10. 测试 HTTPS
docker exec alpine1 wget -O- -T 5 https://www.baidu.com
总结
CentOS Stream 10 上 Docker 网络异常时,如果发现:
modprobe xt_addrtype
提示:
Module xt_addrtype not found
首先不要急着修改 Docker 的 NAT 规则。
先检查:
dnf provides '*/xt_addrtype.ko*'
如果发现该模块属于:
kernel-modules-extra
直接安装:
sudo dnf install kernel-modules-extra-$(uname -r)
再执行:
sudo modprobe xt_addrtype
最后重新创建 Docker 网络和容器进行测试。
关键点:内核版本和 kernel-modules-extra 必须匹配。
例如当前内核:
6.12.0-254.el10.x86_64
就应该安装:
kernel-modules-extra-6.12.0-254.el10.x86_64
而不是随便安装其他版本。