最近遇到个业务问题,在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