Docker容器间互联

允许所有容器互联

默认情况下,同一宿主机下的所有Docker容器相互之间是能够进行网络访问的。

例如,分别启动两个Nginx容器,然后通过其中任意一个Nginx(IP地址:172.17.0.2)可以访问到另一个Nginx(IP地址:172.17.0.3):

  1. # 启动两个 Nginx 容器 nginx_server1、nginx_server2
  2. [root@localhost dockerfiles]# docker run -it -d --name nginx_server1 centos_nginx:1.0 /bin/bash
  3. cac8a92bef84bb2c172548f79810f56d6f431151bc37480ae22f2613de31e477
  4. [root@localhost dockerfiles]# docker run -it -d --name nginx_server2 centos_nginx:1.0 /bin/bash
  5. 7ea4342b91b7cc3bed2b900bf4c8b814d6f587a596ad05738f0002d5b4c9bb68

登录其中一个 Nginx 容器,可以访问到另外一个。

  1. [root@cac8a92bef84 /]# ifconfig
  2. eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
  3. inet 172.17.0.2 netmask 255.255.0.0 broadcast 0.0.0.0
  4. inet6 fe80::42:acff:fe11:2 prefixlen 64 scopeid 0x20<link>
  5. ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
  6. RX packets 213 bytes 328347 (320.6 KiB)
  7. RX errors 0 dropped 0 overruns 0 frame 0
  8. TX packets 208 bytes 16152 (15.7 KiB)
  9. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
  10. lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
  11. inet 127.0.0.1 netmask 255.0.0.0
  12. inet6 ::1 prefixlen 128 scopeid 0x10<host>
  13. loop txqueuelen 1000 (Local Loopback)
  14. RX packets 0 bytes 0 (0.0 B)
  15. RX errors 0 dropped 0 overruns 0 frame 0
  16. TX packets 0 bytes 0 (0.0 B)
  17. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
  18. [root@cac8a92bef84 /]# curl 172.17.0.3
  19. <!DOCTYPE html>
  20. <html>
  21. <head>
  22. <title>Welcome to nginx!</title>
  23. <style>
  24. body {
  25. width: 35em;
  26. margin: 0 auto;
  27. font-family: Tahoma, Verdana, Arial, sans-serif;
  28. }
  29. </style>
  30. </head>
  31. <body>
  32. <h1>Welcome to nginx!</h1>
  33. <p>If you see this page, the nginx web server is successfully installed and
  34. working. Further configuration is required.</p>
  35. <p>For online documentation and support please refer to
  36. <a href="http://nginx.org/">nginx.org</a>.<br/>
  37. Commercial support is available at
  38. <a href="http://nginx.com/">nginx.com</a>.</p>
  39. <p><em>Thank you for using nginx.</em></p>
  40. </body>
  41. </html>

通过别名连接容器

在前面的例子中,nginx_server1是通过IP地址来访问的nginx_server2。但是,Docker容器的IP地址是在启动的时候自动分配的,即便是同一个容器在重启时,其IP地址也往往会发生变化。因此,通过IP地址来实现Docker容器之间的相互访问其实并不可靠。

为了解决这一问题,Docker为我们提供了另外一种容器互联方式:通过别名互联。

通过别名互联需要借助 docker run 命令的 —link 参数:

  1. docker run --link [container_name]:[alias] [image] [command]

接下来,我们再启动一个 Nginx 容器命名为 nginx_server3, 并让其连接到 nginx_server2,且为 nginx_server2 指定一个别名为 ng2 。这样一来,nginx_server3 就可以通过 ng2 来访问 nginx_server2 了。

  1. [root@localhost dockerfiles]# docker run -it -d --link nginx_server2:ng2 --name nginx_server3 centos_nginx:1.0 /bin/bash
  2. 5942fb62e2d3be6b78722b1826a633094f39aeb208d31417344bf9aa5a577128
  3. [root@localhost dockerfiles]# docker attach 5942fb62e2d3be6b78722b1826a633094f39aeb208d31417344bf9aa5a577128
  4. [root@5942fb62e2d3 /]# curl ng2
  5. <!DOCTYPE html>
  6. <html>
  7. <head>
  8. <title>Welcome to nginx!</title>
  9. <style>
  10. body {
  11. width: 35em;
  12. margin: 0 auto;
  13. font-family: Tahoma, Verdana, Arial, sans-serif;
  14. }
  15. </style>
  16. </head>
  17. <body>
  18. <h1>Welcome to nginx!</h1>
  19. <p>If you see this page, the nginx web server is successfully installed and
  20. working. Further configuration is required.</p>
  21. <p>For online documentation and support please refer to
  22. <a href="http://nginx.org/">nginx.org</a>.<br/>
  23. Commercial support is available at
  24. <a href="http://nginx.com/">nginx.com</a>.</p>
  25. <p><em>Thank you for using nginx.</em></p>
  26. </body>
  27. </html>

值得注意的是,此时 nginx_server3 依然可以正常访问宿主机上启动的其他容器。

使用了 —link 参数启动的 Docker容器 其环境变量中会被添加上一些以别名开头的配置项。

  1. [root@5942fb62e2d3 /]# env
  2. HOSTNAME=5942fb62e2d3
  3. TERM=xterm
  4. NG2_PORT_80_TCP_PORT=80
  5. NG2_NAME=/nginx_server3/ng2
  6. NG2_PORT_80_TCP=tcp://172.17.0.3:80
  7. NG2_PORT_80_TCP_PROTO=tcp
  8. PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
  9. PWD=/
  10. SHLVL=1
  11. HOME=/root
  12. NG2_PORT_80_TCP_ADDR=172.17.0.3
  13. NG2_PORT=tcp://172.17.0.3:80
  14. _=/usr/bin/env

同时,在 /etc/hosts 配置文件中也会添加上该别名的地址映射。

  1. 127.0.0.1 localhost
  2. 172.17.0.3 ng2 7ea4342b91b7 nginx_server2

禁止所有容器互联

默认情况下,Docker允许位于同一宿主机下的容器之间进行相互访问。如果要改变这一默认配置,需要修改 /etc/docker/daemon.json,添加 icc = false 项。

  1. {
  2. "icc": false,
  3. "registry-mirrors": ["https://registry.docker-cn.com","http://hub-mirror.c.163.com"]
  4. }

修改完成后,保存文件并重启 docker 守护进程。

  1. systemctl restart docker

允许指定容器互联

出于安全考虑,我们将Docker的 icc 选项设置为 false ,这样可以禁止所有容器间的相互访问。这时,如果我们需要指定某些容器之间可以进行相互访问,需要做如下配置:

  • 将Docker的 icc 选项设置为 false ,默认情况下,禁止所有容器互联;
  • 将Docker的 iptables 选项设置为 true(默认值,可以不设置) ,启用自定义的iptable规则;
  • 通过 docker run 命令的 —link 参数指定需要进行访问的容器;

在前面的示例中,当我们将Docker的 icc 选项设置为 false 后,nginx_server1 和 nginx_server2 将禁止访问任何其他容器,仅有 nginx_server3 可以访问 nginx_server2 。此时查看 iptables 规则列表,Docker规则链中仅存在一组nginx_server3 和nginx_server2 之间的规则 。

  1. [root@localhost dockerfiles]# iptables -L -n
  2. Chain FORWARD (policy DROP)
  3. target prot opt source destination
  4. DOCKER-ISOLATION all -- 0.0.0.0/0 0.0.0.0/0
  5. DOCKER all -- 0.0.0.0/0 0.0.0.0/0
  6. ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
  7. ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
  8. ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
  9. ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
  10. Chain DOCKER (1 references)
  11. target prot opt source destination
  12. ACCEPT tcp -- 172.17.0.4 172.17.0.3 tcp dpt:80
  13. ACCEPT tcp -- 172.17.0.3 172.17.0.4 tcp spt:80

外网访问容器

ip-forward

ip-forward 是 Linux 系统自带的一个配置项,用来决定是否允许系统进行流量转发。在 Docker 中也有一个 ip-forward 选项,其默认值为 true ,这样 Docker 守护进程就会在启动时自动将系统的 ip-forward 参数设置为 1,即允许系统进行流量转发。

  1. # Docker 启动后查看系统 ip-forward 配置
  2. [root@localhost ~]# sysctl net.ipv4.conf.all.forwarding
  3. net.ipv4.conf.all.forwarding = 1

端口映射

在系统允许流量转发的情况下,想要从外网访问容器还需要设置好宿主机和容器之间的端口映射。

  1. [root@localhost dockerfiles]# docker run -it -d -p 8080:80 --name nginx_server4 centos_nginx:1.0 /bin/bash
  2. 6a1bae73f56ae16e0d07d8daa2efb142728f0499418ced125122980757a48154
  3. [root@localhost dockerfiles]# docker attach nginx_server4
  4. [root@6a1bae73f56a /]# nginx
  5. [root@6a1bae73f56a /]# [root@localhost dockerfiles]# docker port nginx_server4
  6. 80/tcp -> 0.0.0.0:8080

在这里,外面将Nginx容器的80端口映射到了宿主机的8080端口,这样外网就可以通过 http://宿主机IP:8080/ 来访问 nginx 容器了。

iptables

再查看 iptables ,发现Docker规则链中多了一条规则。

  1. [root@localhost ~]# iptables -t filter -L -n
  2. Chain DOCKER (1 references)
  3. target prot opt source destination
  4. ACCEPT tcp -- 172.17.0.4 172.17.0.3 tcp dpt:80
  5. ACCEPT tcp -- 172.17.0.3 172.17.0.4 tcp spt:80
  6. # 多的那条规则是我
  7. ACCEPT tcp -- 0.0.0.0/0 172.17.0.5 tcp dpt:80

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BlbmdqdW5sZWU_size_16_color_FFFFFF_t_70

由此可知,外网访问容器是借助 iptables 规则来实现的。既然如此,我们也可以通过自己动手添加 iptables 规则来禁止指定的主机来访问容器。

  1. # 禁止主机 172.16.80.47 访问 容器 172.17.0.5 的 80 端口
  2. [root@localhost dockerfiles]# iptables -I DOCKER -s 172.16.80.47 -d 172.17.0.5 -p TCP --dport 80 -j DROP

发表评论

表情:
评论列表 (有 0 条评论,67人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Docker——端口映射与容器互联

    端口映射实现容器访问 1. 从外部访问容器应用: 在启动容器的时候,如果不指定对应参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的。 当容器中运行一些网络

    相关 Docker 容器互联

    随着 Docker 网络的完善,强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 `--link` 参数。