配置Docker daemon为--iptables=true和--userland-proxy=false后,如何实现容器通过主机转发端口互通?
刚好碰到过类似的场景,当你把Docker daemon配置成--iptables=true和--userland-proxy=false后,容器没法通过主机IP访问本地转发端口确实是Docker的默认行为——因为禁用userland-proxy后,Docker依赖iptables做端口转发,但默认的FORWARD链规则会阻止docker0接口上的回环流量(容器→主机→容器的路径)。下面给你几个不需要每次启动容器手动改iptables的持久化方案:
方案1:添加持久化的iptables FORWARD规则
这是最直接的解决办法,我们需要允许docker0接口内部的双向转发流量:
临时测试(重启后失效):
先执行这条命令验证是否解决问题:iptables -A FORWARD -i docker0 -o docker0 -j ACCEPT测试容器能否通过主机IP访问对方的转发端口,如果可行,再做持久化。
持久化规则(CentOS/RHEL系):
把规则保存到iptables配置文件:iptables-save > /etc/sysconfig/iptables或者创建自定义规则文件,通过
iptables-restore加载(比如在/etc/rc.d/rc.local中添加加载命令)。持久化规则(Debian/Ubuntu系):
安装netfilter-persistent工具:apt-get install netfilter-persistent netfilter-persistent save这样规则会在系统重启后自动加载。
方案2:通过systemd服务自动添加规则
如果不想手动维护iptables配置,可以修改Docker的systemd服务文件,让Docker启动前自动添加这条规则:
- 编辑Docker的systemd服务文件:
vi /usr/lib/systemd/system/docker.service - 在
ExecStart行之前添加以下内容:ExecStartPre=/sbin/iptables -A FORWARD -i docker0 -o docker0 -j ACCEPT - 重新加载systemd配置并重启Docker:
这样每次Docker启动都会自动配置好这条规则,一劳永逸。systemctl daemon-reload systemctl restart docker
额外说明:为什么会出现这个问题?
当禁用userland-proxy后,Docker会把端口转发规则写入iptables的DOCKER链,但默认的FORWARD链策略是拒绝未明确允许的流量。容器尝试通过主机IP访问转发端口时,流量会从docker0接口进入主机,再从docker0接口回到另一个容器,这条路径的流量默认被FORWARD链阻止,所以我们需要手动添加规则允许它。
你的环境信息:
[root@AppServer ~]# docker version
Client:
Version: 18.03.1-ol
API version: 1.37
Go version: go1.9.4
Git commit: 0d51d18
Built: Wed Aug 22 21:59:42 2018
OS/Arch: linux/amd64
Experimental: false
Orchestrator: swarmServer:
Engine:
Version: 18.03.1-ol
API version: 1.37 (minimum version 1.12)
Go version: go1.9.4
Git commit: 0d51d18
Built: Wed Aug 22 22:03:05 2018
OS/Arch: linux/amd64
Experimental: false
[root@AppServer ~]#
内容的提问来源于stack exchange,提问作者Ram




