最近遇到个业务问题,在linux中docker run 启动容器时,我们可以通过-p,然后绑定host与容器的端口,实现端口映射,但如果不用这个实现端口映射,我们有没有其他的解决方案了呢?

答案,有。

在host设置iptables规则实现nat网络地址转换,也可以实现外部来的访问请求,通过网络地址转换,进而访问到docker容器的服务。

具体可以描述为:我们有个web server,开始是直接host运行,每次安装server服务都得考虑环境的问题,现在随着容器技术的应用,环境问题就解决了,反正服务我运行在容器中,而容器是隔离的。一般测试的时候,为了方便可以直接在启动容器服务的时候,直接-p host_port:container_port指定端口进行映射,但正式上线的时候,我们通常会通过iptables实现。

docker容器的ip我们指定(此处不展开),也可以通过docker inspect container_name|ID查看得到。

先来看看iptables的具体设置:

# 1.设置目标地址转换,本地的网络服务开放给外部网络访问
iptables -t nat -A PREROUTING -i ens33 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.168.123.xx:8000

# 2.过滤允许docker 特定ip:port
iptables -t filter -A DOCKER -d 192.168.123.xx -p tcp -m tcp --dport 8000 -j ACCEPT

我们在路由前设置nat表规则,通过ens33网卡进入,使用tcp协议,对于来自host端口8080 的访问,通过目标网络地址转换(DNAT),将其转发到192.168.123.xx:8000。

通过这一步,我们就实现了网络地址转发,下面对DOCKER chain设置filter规则。

DOCKER 链:仅处理从宿主机到docker0的IP数据包

filter表中,对DOCKER 链追加规则,对于访问192.168.123.xx:8000的tcp请求,对应动作:ACCEPT

通过以上设置,1.设置目标地址转换,2.DOCKER 链接受访问指定ip:port,这样,我们就顺利实现外部访问host的docker容器某服务了。

docker容器与宿主机之间的nat设置

总体来说,实现宿主机与主机之间的nat设置,分两种:1.允许外部网络访问容器内部服务,2.允许容器内部向其他docker容器访问

1.允许外部网络访问容器内部服务

# iptables 设置PREROUTING规则
iptables -t nat  -A PREROUTING -i ens33 -dport 80 -p tcp -j DNAT --to-destination 192.168.123.xx:90
# host 0.0.0.0:80 >> 192.168.123.xx:90

# iptables 设置DOCKER filter过滤规则
iptables -t filter -A DOCKER -d 192.168.123.xx -dport 90 -p tcp -j ACCEPT
# 处理宿主机到docker0网卡的数据包,允许访问192.168.123.xx:90

2.允许容器内部向其他docker容器访问

# 实现172.18.0.0/16网段的容器间的网络访问,MASQUERADE 相当于动态SNAT,用于ADSL
iptables -t nat -A POSTROUTING -s 172.18.0.0/16 -j MASQUERADE

扩展

iptables实现NAT

如何用iptables实现NAT

基于iptables的Docker网络隔离