Docker启动报错-iptables failed问题解析与处理

剖析Docker与nftables冲突的根源

Docker启动报错-iptables failed问题解析与处理
Photo by insung yoon / Unsplash

一、Bug出现

某天,docker容器运行异常,日志中出现Failed to resolve 'www.baidu.com'的错误,也许是容器内的DNS解析配置问题。

二、寻找线索

2.1 逐步排查

想起该服务器刚安装了fail2ban以防被暴力破解,并启动了nftables作为防火墙。将以上两个服务关闭,接着修改docker-compose.yml,指定DNS地址,执行docker compose up -d进行更新容器,但报出了以下异常:

Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint {container_name} (c7d6d789c8164855cc0b99cdb91af8a21587284d7f316752baada0b7315fb9be): Unable to enable DNAT rule:  (iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 8080 -j DNAT --to-destination 172.19.0.6:8080 ! -i br-da87abf7e60c: iptables: No chain/target/match by that name.
 (exit status 1))

可看到末尾 iptables: No chain/target/match by that name ,通常意味着 Docker 在尝试配置网络(比如设置端口映射)时,发现系统防火墙 (iptables) 的规则链丢失或损坏了。这通常发生在重启了系统防火墙、或者系统上 iptables 与 nftables 有冲突的情况下。

2.2 原因分析

  • 问题本质:

Docker默认使用iptables来管理容器网络,它并不直接支持nftables。当安装nftables后,系统很可能将默认的防火墙后端切换到了nftables,导致Docker找不到它所需的传统iptables链,从而报错。

  • 检查iptables中Docker链是否存在
# 查看 nat 表中是否有 DOCKER 链
sudo iptables -t nat -L | grep -i docker

# 查看 filter 表中是否有 DOCKER 链
sudo iptables -t filter -L | grep -i docker

如果命令没有输出,说明链丢失了。

2.3 如何解决

🛠️ 方案一:让Docker通过兼容层使用nftables(推荐)

可以让系统通过一个兼容层(iptables-nft),无需卸载nftables,将Docker的iptables指令“翻译”给nftables执行。

操作步骤如下:

  1. 检查当前iptables模式:确认系统是否正在使用nftables作为后端。
sudo iptables --version

输出中如果包含nf_tables,例如iptables v1.8.10 (nf_tables),说明已经处于兼容模式。但为了确保Docker正常工作,可以强制指定使用iptables-nft

  1. 切换iptables到nft后端:使用update-alternatives命令,将系统的iptables切换为使用nftables后端的版本。
sudo update-alternatives --set iptables /usr/sbin/iptables-nft
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-nft
  1. 重启Docker服务:让Docker重新初始化网络,并自动通过新的兼容层在nftables中创建所需的规则。
sudo systemctl restart docker

🛠️ 方案二:彻底禁用Docker的iptables管理(备选)

如果希望由自己通过nftables来管理服务器的防火墙规则, 不希望Docker自动干预,可以选择这个方案,会关闭Docker自动操作防火墙的能力。

# 编辑daemon.json文件
sudo tee /etc/docker/daemon.json <<EOF
{
  "iptables": false
}
EOF

# 重启Docker服务
sudo systemctl restart docker

⚠️手动配置 nftables(如果需要):采用此方案后,Docker 容器的端口映射 (-p 参数) 将不会自动工作。需要手动编写 nftables 规则来实现端口转发和网络地址转换(NAT)。这是一个更高级的选项,需要对 nftables 有较深的了解 。

三、验证

  • 再次尝试更新容器:docker compose up -d
  • 查看nftables的规则集,应该可以看到Docker自动创建的ip filterip nat等表。
sudo nft list ruleset

在输出中,应该能找到 chain DOCKER 和 chain DOCKER-USER 等内容 。