创建容器后手动映射端口

[TOC]

一般我们在创建容器的时候都可以-p指定多个端口或者-P 指定随机端口,但是比较麻烦的是我们在创建了容器之后又想映射多一个或者多个端口,但是这时候docker 又没有支持的命令进行操作。

那首先就需要先了解docker 端口映射是怎么一个工作原理了。

一般情况下,容器是可以访问外网,而外部网络是不能访问到容器的。

容器访问外部实现

容器所有到外部网络的连接,源地址都会被NAT成本地系统的IP地址。这是使用iptables的源地址转换实现的。

查看宿主机的NAT表

iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0           ADDRTYPE match dst-type LOCAL 

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0           
MASQUERADE  tcp  --  172.17.0.6           172.17.0.6          tcp dpt:8080 
……

可以看到上面的iptables的规则把所有源地址在172.17.0.0/16 网段,目标地址为其他网段(外部网络)的流量都进行了转换(伪装)从宿主机的网卡发出。MASQUERADE 跟传统 SNAT 的好处是它能动态从网卡获取地址。

外部网络访问容器的实现

iptables -t nat -nL
Chain DOCKER (2 references)
target     prot opt source               destination         
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:58080 to:172.17.0.6:8080 
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:50443 to:172.17.0.6:443 
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:5080 to:172.17.0.6:80 
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:5022 to:172.17.0.6:22 

以上的端口转换是在创建容器时指定的:

docker run -t -p 5122:22 -p 5180:80 -p 18080:8080 -p 51443:443 --name nagios centos:6.2 /bin/bash

使用-p 命令来进行端口映射,在这里可以看出,当外部访问宿主机与容器所映射的端口时,iptables 的NAT表会对目的端口进行转换,转换为相应的容器的ip:port

通过修改宿主机防火墙配置允许外部网络访问容器

iptables -t nat -I DOCKER 1 -p tcp --dport 123 -j DNAT --to-destination 172.17.0.6:123
iptables -I DOCKER 4 -p tcp -d 172.17.0.6 --dport 123 -j ACCEPT

经过上面的分析我们知道了外部网络是如何访问带容器内部的。
因此我们需要添加DNAT规则以及允许访问宿主机的容器IP和端口。

测试
在容器中用nc监听一个端口

while true; do ( echo "HTTP/1.0 200 Ok"; echo; echo "Hello World" ) | nc -l 123; done

然后添加了上面两条防火墙规则后,再去测试能否连通宿主机的123端口

telnet 192.168.15.226 123
Trying 192.168.15.226...
Connected to 192.168.15.226.
Escape character is '^]'.
HTTP/1.0 200 Ok

Hello World
Connection closed by foreign host.

验证了是可以通的。

你可能感兴趣的:(创建容器后手动映射端口)