一、问题概述
在CentOS 7环境中,部署Docker容器并做端口映射后,宿主机firewalld防火墙未放行对应端口,外网却可直接访问容器服务。该问题并非程序Bug,是Docker与firewalld底层运行机制冲突导致,目前CentOS7+firewalld+Docker组合仍会复现此问题。
二、底层核心原理
2.1 防火墙底层逻辑
CentOS 7中firewalld仅是上层可视化管理工具,底层依旧依赖iptables实现防火墙规则;firewalld仅管控自身定义的public、trusted等区域链规则。
2.2 Docker网络规则机制
Docker守护进程默认会直接操作宿主机iptables的nat表、filter表,自主添加端口转发、流量放行规则,且Docker生成的iptables规则不在firewalld管控的区域链范围内。
2.3 流量通行路径
外网流量→宿主机网卡→Docker自建iptables放行规则→转发至容器,流量全程不经过firewalld过滤链,因此防火墙无法拦截容器访问流量。
2.4 误区澄清
- 启动顺序无影响:Docker启动后会主动刷新iptables规则,不受firewalld启动先后顺序干扰;
- 无关容器内部防火墙:容器默认无独立防火墙,内部iptables为空,问题仅存在于宿主机网络规则层面。
三、老旧修复方案(原博主方案,不推荐)
3.1 修复思路
给Docker守护进程添加启动参数
--iptables=false,禁止Docker修改宿主机iptables,强制容器流量经过firewalld过滤。3.2 操作步骤
- 新建/编辑配置文件
/etc/default/docker,写入配置:DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4 --iptables=false"; - 修改docker服务文件
/usr/lib/systemd/system/docker.service,添加配置依赖:EnvironmentFile=-/etc/default/docker,并在ExecStart末尾追加$DOCKER_OPTS; - 执行命令重载配置并重启Docker: # 重载系统配置
systemctl daemon-reload# 重启Docker服务service docker restart - 手动在firewalld放行端口,才可正常访问容器服务。
3.3 方案优缺点
优点
可实现firewalld管控容器端口,未放行端口则无法访问容器,达到基础防护效果。
缺点(重大缺陷)
- 参数
--iptables=false会导致Docker端口映射异常、网桥通信故障,容器间网络互通容易出错; /etc/default/docker为老旧配置文件,新版docker-ce不默认识别;- 硬编码修改docker.service文件,Docker版本升级后配置会被覆盖丢失。
四、官方推荐现代修复方案
4.1 方案A(优先推荐:网桥托管法)
修复思路
不关闭Docker的iptables权限,将Docker默认网桥docker0纳入firewalld信任区域,让容器流量强制经过防火墙过滤,兼顾网络稳定性与安全管控。
执行命令
# 将docker0网桥加入信任区域,永久生效
firewall-cmd --permanent --add-interface=docker0 --zone=trusted
# 重载防火墙规则
firewall-cmd --reload实现效果
Docker可正常修改iptables、维持原生网络特性,外网访问容器必须在firewalld放行对应端口,防火墙管控生效。
4.2 方案B(禁用Docker iptables:现代标准写法)
修复思路
沿用关闭Docker iptables的核心思路,采用官方通用配置文件,替代老旧修改方式,稳定性更强。
操作步骤
- 编辑Docker官方配置文件
/etc/docker/daemon.json,写入JSON配置:{"iptables": false} - 重载配置并重启Docker:
systemctl daemon-reloadsystemctl restart docker
五、总结
- 问题本质:Docker直改底层iptables,流量绕过firewalld过滤链,并非系统漏洞;
- 老旧方案:原理可行,但配置方式过时、易引发网络故障,生产环境禁止使用;
- 最优方案:优先使用firewalld信任docker0网桥;若需禁用Docker iptables,统一修改daemon.json配置,规避老旧BUG。
