映射容器端口到宿主主机的实现

默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。

容器访问外部实现

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

查看主机的 NAT 规则。

  1. $ sudo iptables -t nat -nL
  2. ...
  3. Chain POSTROUTING (policy ACCEPT)
  4. target prot opt source destination
  5. MASQUERADE all --172.17.0.0/16!172.17.0.0/16
  6. ...

其中,上述规则将所有源地址在 172.17.0.0/16 网段,目标地址为其他网段(外部网络)的流量动态伪装为从系统网卡发出。MASQUERADE 跟传统 SNAT 的好处是它能动态从网卡获取地址。

外部访问容器实现

容器允许外部访问,可以在 docker run 时候通过 -p-P 参数来启用。

不管用那种办法,其实也是在本地的 iptable 的 nat 表中添加相应的规则。

使用 -P 时:

  1. $ iptables -t nat -nL
  2. ...
  3. Chain DOCKER (2 references)
  4. target prot opt source destination
  5. DNAT tcp --0.0.0.0/00.0.0.0/0 tcp dpt:49153 to:172.17.0.2:80

使用 -p 80:80 时:

  1. $ iptables -t nat -nL
  2. Chain DOCKER (2 references)
  3. target prot opt source destination
  4. DNAT tcp --0.0.0.0/00.0.0.0/0 tcp dpt:80 to:172.17.0.2:80

注意:

  • 这里的规则映射了 0.0.0.0,意味着将接受主机来自所有接口的流量。用户可以通过 -p IP:host_port:container_port-p IP::port 来指定允许访问容器的主机上的 IP、接口等,以制定更严格的规则。

  • 如果希望永久绑定到某个固定的 IP 地址,可以在 Docker 配置文件 /etc/docker/daemon.json 中添加如下内容。

  1. {
  2. "ip":"0.0.0.0"
  3. }