容器之间的互联

在同一个宿主机上的容器之间可以通过端口映射的方式经过宿主机中转进行互相访问

也可以直接通过宿主机的docker0网桥进行互相访问

直接互联

  • 启动两个Nginx容器
  1. [root@server ~]# docker run -d -it --name nginx-1 nginx
  2. [root@server ~]# docker run -d -it --name nginx-2 nginx
  • 安装相关工具包,用来查看IP地址并且进行互ping测试
  1. root@root@1bc3c795b000:/# apt update
  2. root@root@1bc3c795b000:/# apt install net-tools -y
  3. root@root@1bc3c795b000:/# apt install iputils-ping -y
  4. root@root@1bc3c795b000:/# apt install procps -y
  • 查看各自的IP地址
  1. # nginx-1
  2. root@1bc3c795b000:/# ifconfig # 172.17.0.2
  3. # nginx-2
  4. root@4e305588f142:/# ifconfig # 172.17.0.3
  • 直接互ping是可以连通的
  1. root@1bc3c795b000:/# ping 172.17.0.3 -c 2
  2. PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
  3. 64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.072 ms
  4. 64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.204 ms
  5. --- 172.17.0.3 ping statistics ---
  6. 2 packets transmitted, 2 received, 0% packet loss, time 1002ms
  7. rtt min/avg/max/mdev = 0.072/0.138/0.204/0.066 ms

名称互联

  • 启动两个Nginx容器
  1. [root@server ~]# docker run -d -it --name nginx-1 nginx
  2. [root@server ~]# docker run -d -it --name nginx-2 --link nginx-1 nginx
  • 查看nginx-2容器的hosts文件,发现已经实现了主机名解析
  1. [root@server ~]# docker exec -it nginx-2 bash
  2. root@7385ecc0af3a:/# cat /etc/hosts
  3. 127.0.0.1 localhost
  4. ::1 localhost ip6-localhost ip6-loopback
  5. fe00::0 ip6-localnet
  6. ff00::0 ip6-mcastprefix
  7. ff02::1 ip6-allnodes
  8. ff02::2 ip6-allrouters
  9. 172.17.0.2 nginx-1 8cfad88ba05a # 容器nginx-1
  10. 172.17.0.3 7385ecc0af3a
  • 因此直接进行ping主机名也是可以通的
  1. root@7385ecc0af3a:/# ping nginx-1 -c 2
  2. PING nginx-1 (172.17.0.2) 56(84) bytes of data.
  3. 64 bytes from nginx-1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.180 ms
  4. 64 bytes from nginx-1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.100 ms
  5. --- nginx-1 ping statistics ---
  6. 2 packets transmitted, 2 received, 0% packet loss, time 1000ms
  7. rtt min/avg/max/mdev = 0.100/0.140/0.180/0.040 ms

别名互联

自定义的容器名称可能后期会发生变化,那么一旦发生变化也会带来一些影响,这个时候如果每次都更改名称又比较麻烦,这个时候可以使用定义别名的方式解决,即容器名称可以随意更改,只要不更改别名即可

  • 启动两个Nginx容器
  1. [root@server ~]# docker run -d -it --name nginx-1 nginx
  2. [root@server ~]# docker run -d -it --name nginx-2 --link nginx-1:web1 nginx
  • 查看nginx-2容器的hosts文件,发现已经实现了主机名解析,同时别名也进行了解析
  1. [root@server ~]# docker exec -it nginx-2 bash
  2. root@1241479e8e4f:/# cat /etc/hosts
  3. 127.0.0.1 localhost
  4. ::1 localhost ip6-localhost ip6-loopback
  5. fe00::0 ip6-localnet
  6. ff00::0 ip6-mcastprefix
  7. ff02::1 ip6-allnodes
  8. ff02::2 ip6-allrouters
  9. 172.17.0.2 web1 1e96a855597b nginx-1
  10. 172.17.0.3 1241479e8e4f
  • 直接进行ping别名同样是可以通的
  1. root@1241479e8e4f:/# ping web1 -c 2
  2. PING web1 (172.17.0.2) 56(84) bytes of data.
  3. 64 bytes from web1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.075 ms
  4. 64 bytes from web1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.085 ms
  5. --- web1 ping statistics ---
  6. 2 packets transmitted, 2 received, 0% packet loss, time 1000ms
  7. rtt min/avg/max/mdev = 0.075/0.080/0.085/0.005 ms

Docker网络

网络模式介绍

Docker网络模式 配置 说明
none模式 —network none 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接,配置IP等
container模式 —network container:容器名/ID 容器和另外一个容器共享Network namespace;kubernetes中的pod就是多个容器共享一个Network namespace
host模式 —network host 容器和宿主机共享Network namespace
bridge模式 —network bridge 默认模式,容器与宿主机桥接

None模式

  • 使用None模式后,docker容器不会进行任何网络配置,没有网卡没有IP也没有路由,因此默认无法与外界进行通信,需要手动添加网卡配置IP等,因此极少使用这种模式

Docker网络管理 - 图1

启动一个none网络模式的容器,可以看到没有IP地址,只有一个环回接口

  1. [root@server ~]# docker run -d --name web1 --network none nginx:v1
  2. 3d6e13c3bd8bbad49a2689c184bc530629071413a5e78e5d68c5cff9abaf9de5
  3. [root@server ~]# docker exec -it web1 bash
  4. [root@3d6e13c3bd8b /]# ip a
  5. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  6. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  7. inet 127.0.0.1/8 scope host lo
  8. valid_lft forever preferred_lft forever

Container模式

  • Container模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享

  • 新创建的容器不会创建自己的网卡,配置自己的IP,而是和指定的容器共享一个IP、端口范围

  • 两个容器除了网络方面不是隔离的,其他方面如文件系统、进程列表等还是隔离的

Docker网络管理 - 图2

启动一个默认模式的容器,一个container模式的容器

  1. [root@server ~]# docker run -d --name web1 nginx:v1
  2. [root@server ~]# docker run -d -it --name web2 --network container:web1 centos:7

进入两个容器查看各自的IP地址,发现IP地址是一样的,暴露的端口也是一样的,而他们的主机名也是一模一样

  1. [root@server ~]# docker exec -it web1 bash
  2. [root@b30a2eb148c5 /]# ip a
  3. # eth0:172.17.0.2
  4. [root@b30a2eb148c5 /]# ss -tnl
  5. State Recv-Q Send-Q Local Address:Port Peer Address:Port
  6. LISTEN 0 128 *:80 *:*
  7. [root@server ~]# docker exec -it web2 bash
  8. [root@b30a2eb148c5 /]# ip a
  9. # eth0:172.17.0.2
  10. [root@b30a2eb148c5 /]# ss -tnl
  11. State Recv-Q Send-Q Local Address:Port Peer Address:Port
  12. LISTEN 0 128 *:80 *:*

Host模式

  • 如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace

  • 容器不会虚拟出自己的网卡,配置自己的IP等,而是直接使用宿主机的IP和端口

  • 使用host模式的容器可以直接使用宿主机的IP地址和外界进行通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT

  • host模式的优点就是网络性能很好,但是对于宿主机和容器之间的网络隔离性来说不是很友好

Docker网络管理 - 图3

启动两个host模式的容器

  1. [root@server ~]# docker run -d -it --name web1 --network host centos:7
  2. [root@server ~]# docker run -d -it --name web2 --network host centos:7

进入容器内部(看似没进入,实则已经进去了,因为主机名是一样的

  1. [root@server ~]# docker exec -it web1 bash
  2. [root@server /]#

查看网络配置信息,可以发现和宿主机上的网络配置信息一模一样

  1. # 宿主机
  2. [root@server ~]# ip a
  3. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  4. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  5. inet 127.0.0.1/8 scope host lo
  6. valid_lft forever preferred_lft forever
  7. inet6 ::1/128 scope host
  8. valid_lft forever preferred_lft forever
  9. 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  10. link/ether 00:0c:29:31:70:df brd ff:ff:ff:ff:ff:ff
  11. inet 192.168.31.99/24 brd 192.168.31.255 scope global noprefixroute ens33
  12. valid_lft forever preferred_lft forever
  13. inet6 fe80::ea13:321a:474b:f3ea/64 scope link noprefixroute
  14. valid_lft forever preferred_lft forever
  15. 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
  16. link/ether 02:42:37:35:35:d7 brd ff:ff:ff:ff:ff:ff
  17. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  18. valid_lft forever preferred_lft forever
  19. inet6 fe80::42:37ff:fe35:35d7/64 scope link
  20. valid_lft forever preferred_lft forever
  21. # 容器web1或者web2
  22. [root@server /]# ip a
  23. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  24. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  25. inet 127.0.0.1/8 scope host lo
  26. valid_lft forever preferred_lft forever
  27. inet6 ::1/128 scope host
  28. valid_lft forever preferred_lft forever
  29. 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  30. link/ether 00:0c:29:31:70:df brd ff:ff:ff:ff:ff:ff
  31. inet 192.168.31.99/24 brd 192.168.31.255 scope global noprefixroute ens33
  32. valid_lft forever preferred_lft forever
  33. inet6 fe80::ea13:321a:474b:f3ea/64 scope link noprefixroute
  34. valid_lft forever preferred_lft forever
  35. 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
  36. link/ether 02:42:37:35:35:d7 brd ff:ff:ff:ff:ff:ff
  37. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  38. valid_lft forever preferred_lft forever
  39. inet6 fe80::42:37ff:fe35:35d7/64 scope link
  40. valid_lft forever preferred_lft forever

包括端口信息也是一模一样

Docker网络管理 - 图4

Bridge模式

  • 当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上,虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中
  • 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关,然后在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中,可以通过brctl show命令查看

Docker网络管理 - 图5

  • bridge模式是docker的默认网络模式,容器启动时不写—network参数就是bridge模式
  • 使用docker run -p端口映射时,底层工作的是iptables,它实现了端口转发功能,可以通过iptables -t nat -vnL进行查看,当docker服务启动的时候,就会自动在iptables中新增一个自定义链Chain DOCKER

Docker网络管理 - 图6

注意点:

有时候docker服务在运行的时候,会发现防火墙没关,此时就会使用systemctl stop firewalld关闭防火墙,那么此时iptables中的DOCKER链就也会被清空,那么端口映射就会出错了!此时的解决办法是重启docker服务systemctl restart docker,那么DOCKER链就又会自动回来了

自定义网络

可以使用docker命令来创建自定义网络,自定义网络可以自定义IP地址范围和网关等信息

  • 创建一个网络
  1. [root@server ~]# docker network create -d bridge --subnet 10.10.0.0/16 --gateway 10.10.0.1 my-net
  2. 6a1eaa02a995581fda7939222fac54740877e35688b1ffd9f98e42fb624e3d25
  3. [root@server ~]# docker network list
  4. NETWORK ID NAME DRIVER SCOPE
  5. bda7c30ac2ac bridge bridge local
  6. 8d5ae5100941 host host local
  7. 6a1eaa02a995 my-net bridge local
  8. f8073bd77b21 none null local

Docker网络管理 - 图7

  • 使用自定义的网络创建容器
  1. [root@server ~]# docker run -d -it --name web1 --network my-net nginx:v1
  2. 4ffa06be05c8c356cfce5be166d4b62371f916afc443316d88b9ddb11057e7bb
  • 进入容器查看网络配置
  1. [root@server ~]# docker exec -it web1 bash
  2. [root@4ffa06be05c8 /]# ip a
  3. # eth0:10.10.0.2
  4. [root@4ffa06be05c8 /]# ping baidu.com -c 2
  5. # 能ping通
  • 查看iptables的nat表
  1. [root@server ~]# iptables -t nat -vnL

Docker网络管理 - 图8