docker容器互联

docker容器互联

Docker 提供了几种网络模式,以便容器之间进行通信,每种模式都适用于不同的场景和需求。以下是 Docker 的主要网络模式(本章节介绍前四种):

  1. 桥接模式(Bridge)
    • 默认情况下,Docker 容器采用桥接模式。每个容器都连接到 Docker 守护程序管理的一个虚拟网络桥接中。
    • 桥接模式允许容器之间相互通信,并且它们可以通过容器的 IP 地址或容器名称进行访问。
    • Docker 容器可以连接到多个桥接网络,但每个容器只能连接到一个桥接网络。
  2. 主机模式(Host)
    • 使用主机模式时,容器将直接使用宿主机的网络命名空间,而不是创建自己的网络命名空间。
    • 这意味着容器可以直接访问宿主机上的网络接口,并且它们的网络性能可能更高,但也增加了安全风险。
  3. 无网络模式(None)
    • 在无网络模式下,Docker 容器不会连接到任何网络,即使容器内部运行的服务也无法通过网络访问。
    • 这种模式通常用于特殊情况,比如只需要容器执行计算任务,而不需要网络连接的情况。
  4. 容器模式(Container)
    • 容器模式是一种特殊的网络模式,它允许将一个容器直接连接到另一个容器的网络命名空间,实现容器之间的直接通信,而无需通过网络端口。
    • 在容器模式下,两个容器可以直接使用 localhost 来互相访问,就好像它们在同一台计算机上运行一样。
    • 这种模式通常用于需要在多个容器之间建立特定的网络通信,例如容器化的应用程序架构中的微服务间通信。
  5. 覆盖网络模式(Overlay)
    • 覆盖网络模式允许在不同 Docker 宿主机上的容器进行通信,实现跨主机的容器网络。
    • 这种模式通常与 Docker Swarm 或 Kubernetes 等容器编排工具一起使用,以构建跨主机的容器集群。
  6. Macvlan 模式
    • Macvlan 模式允许 Docker 容器拥有与宿主机相同的 MAC 地址,并且可以在局域网中像物理主机一样工作。
    • 这种模式通常用于需要容器与局域网中其他设备直接通信的场景。
  7. 网络插件模式(Network plugins)
    • Docker 支持通过网络插件扩展其网络功能,使得可以集成各种第三方网络解决方案。
    • 这些插件可以提供各种网络功能,如软件定义网络(SDN)、安全性增强、性能优化等。

指定docker的网络模式使用--net进行指定。

在安装docker时,会生成一个docker0的虚拟网桥

[root@docker-master ~]# ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:b3:80:76 brd ff:ff:ff:ff:ff:ff
    inet 192.168.132.167/24 brd 192.168.132.255 scope global noprefixroute dynamic ens33
       valid_lft 1207sec preferred_lft 1207sec
    inet6 fe80::d906:bfb6:efc2:b001/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:59:41:ad:ec brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:59ff:fe41:adec/64 scope link 
       valid_lft forever preferred_lft forever

每运行一个docker容器,都会生成一个veth设备对,veth的一个接口在容器内,一个接口在物理机上

[root@docker-master ~]# ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:b3:80:76 brd ff:ff:ff:ff:ff:ff
    inet 192.168.132.167/24 brd 192.168.132.255 scope global noprefixroute dynamic ens33
       valid_lft 1060sec preferred_lft 1060sec
    inet6 fe80::d906:bfb6:efc2:b001/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:59:41:ad:ec brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:59ff:fe41:adec/64 scope link 
       valid_lft forever preferred_lft forever
107: vethbf84b03@if106: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether de:aa:a7:13:ae:cd brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::dcaa:a7ff:fe13:aecd/64 scope link 
       valid_lft forever preferred_lft forever

安装网桥管理工具,查看网桥对应的接口,可以观察到docker0的网桥设备有interfaces(接口)选项,每一个接口表示一个启动的docker容器

[root@docker-master ~]# yum -y install bridge-utils.x86_64
[root@docker-master ~]# brctl show
bridge name bridge id       STP enabled interfaces
docker0     8000.02425941adec   no      vethbf84b03
docker容器互联

创建net-docker目录,切换到目录内,编写dockerfile(此centos镜像已经重新封装仓库源),随后构建镜像

[root@docker-master ~]# cd net-docker/
[root@docker-master net-docker]# cat dockerfile 
FROM centos-repo
RUN yum -y install wget
RUN yum -y install nginx
EXPOSE 80
CMD  /bin/bash
[root@docker-master net-docker]# docker build -t="inter-image" .

基于构建的镜像创建容器test1,进入容器内部查看IP地址,并启动nginx服务

[root@docker-master ~]# docker run -itd --name test1 inter-image
[root@docker-master ~]# docker exec -it test1 /bin/bash
[root@c4296967265c /]# ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
116: eth0@if117: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
[root@c4296967265c /]# /usr/sbin/nginx  

基于构建的镜像创建容器test2,进入容器内部查看IP地址,使用ping命令检查与容器test1的连通性,并查看test1容器内nginx网页的内容

[root@docker-master ~]# docker run -itd --name test2 inter-image
00be6e2e7592b858ad5a7b71b198f2a87b41e2a79d7597b6f77147146ce35fc9
[root@docker-master ~]# docker exec -it test2 /bin/bash
[root@00be6e2e7592 /]# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
118: eth0@if119: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
[root@00be6e2e7592 ~]# ping 172.17.0.3 -c 2
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.095 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.089 ms

--- 172.17.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.089/0.092/0.095/0.003 ms
[root@00be6e2e7592 /]# curl 172.17.0.3
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
...省略部分输出...
docker link设置网络别名

Docker Link 允许在容器之间创建连接,以便它们可以相互通信。在连接的同时,Docker 允许为每个连接设置网络别名,这样容器可以使用更友好的名称来引用连接的容器。以下是 Docker Link 设置网络别名的应用场景:

  1. 微服务架构

    • 在微服务架构中,不同的服务可能部署在不同的容器中。使用 Docker Link 设置网络别名,可以使服务之间的通信更直观。
    • 例如,一个 Web 服务可能需要连接到一个数据库服务。通过为数据库容器设置网络别名,Web 服务可以简单地使用别名来连接数据库,而不需要记住容器的 ID 或 IP 地址。
  2. 容器化的应用程序部署

    • 当你将应用程序拆分为多个容器时,这些容器之间需要通信。使用 Docker Link 设置网络别名,可以简化容器之间的通信。
    • 比如,一个应用程序可能包括一个前端容器、一个后端容器和一个数据库容器。通过为这些容器设置网络别名,可以更轻松地实现它们之间的通信。
  3. 测试和开发环境

    • 在测试和开发环境中,经常需要在本地运行多个容器来模拟生产环境。使用 Docker Link 设置网络别名,可以帮助简化容器之间的通信。
    • 例如,你可能在本地运行一个 Web 服务器容器和一个模拟的数据库容器。通过设置网络别名,你可以在配置 Web 服务器时使用更简洁的名称来引用数据库容器。
  4. 跨容器通信

    • 有时,不同容器之间需要相互通信,但它们可能属于不同的应用程序或服务。在这种情况下,使用 Docker Link 设置网络别名可以使通信更简单。
    • 例如,一个日志收集容器可能需要连接到多个应用程序容器来收集日志。通过为这些应用程序容器设置网络别名,日志收集容器可以更容易地与它们通信。

总的来说,Docker Link 设置网络别名的主要应用场景是简化容器之间的通信,并使通信更直观和易于管理。

格式:

docker run --link=[CONTAINER_NAME]:[ALIAS] [IMAGE][COMMAND]

启动一个test4容器,

[root@docker-master ~]# docker run -itd --name test4 --privileged=true inter-image
e52bb2ca7312f83259c0f6be9b58a05d5a0a574b4f14aabc2925a0dd878ee777
参数 解释
--privileged=true 使得容器拥有主机上的 root 权限

启动一个test3容器,链接test4容器的别名为webtest

[root@docker-master ~]# docker run -itd --link=test4:webtest --name test3 inter-image
b8e879d4bef68946f0c8c551b9b3514890b761da0aebcf19db05355bf8d70c8f

进入test3容器内部,尝试通过别名访问test4容器,可以观察到别名被写入了/etc/hosts文件

[root@docker-master ~]# docker exec -it test3 /bin/bash
[root@d0bedb636425 /]# cat /etc/hosts
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.5  webtest 5c5695889e6f test4
172.17.0.6  d0bedb636425
[root@d0bedb636425 /]# ping webtest -c 2
PING webtest (172.17.0.5) 56(84) bytes of data.
64 bytes from webtest (172.17.0.5): icmp_seq=1 ttl=64 time=0.250 ms
64 bytes from webtest (172.17.0.5): icmp_seq=2 ttl=64 time=0.091 ms

--- webtest ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.091/0.170/0.250/0.080 ms

测试更换test4的IP地址后,是否仍能通过别名进行通信,如果直接使用ifconfig命令进行修改,会产生无法联通的提示。

尝试直接删除test4容器,先创建test5容器(占用IP地址),再创建test4容器。但是此时进入test3容器内部会提示报错

[root@docker-master ~]# docker exec -it test3 /bin/bash
Error response from daemon: Cannot link to a non running container: /test4 AS /test3/webtest

处理方法:重启docker服务,首先重启test4容器,再启动test3容器,注意顺序不能颠倒,否则报错

[root@docker-master ~]# docker start test3
Error response from daemon: Cannot link to a non running container: /test4 AS /test3/webtest
[root@docker-master ~]# docker start test4
test4
[root@docker-master ~]# docker start test3
test3

进入test3容器内部,再次使用ping命令测试连通性,可以注意到IP地址发生了改变,但是别名依然能正常使用

[root@docker-master ~]# docker exec -it test3 /bin/bash
[root@d0bedb636425 /]# ping webtest -c 2
PING webtest (172.17.0.2) 56(84) bytes of data.
64 bytes from webtest (172.17.0.2): icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from webtest (172.17.0.2): icmp_seq=2 ttl=64 time=0.060 ms

--- webtest ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.060/0.065/0.070/0.005 ms
容器的四种网络模式解析和效果展示

none模式:创建的容器没有网络地址,只有环回接口

[root@docker-master ~]# docker run -itd --net none --name none centos
098d50ed6c33d500cb4ca006d73ff843f7d18da7424d782459235c1d74a7ca89
[root@docker-master ~]# docker exec none ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever

container模式:指定其和已经存在的某个容器共享一个 Network Namespace。假设新建容器共享test4容器,因此就不会拥有自己独立的 IP,而是共享test4容器的 IP 172.17.0.2,端口范围等网络资源,两个容器的进程通过 lo 网卡设备通信。

创建连接到test4容器网络命名空间的容器

[root@docker-master ~]# docker run -itd --net container:test4 --name container centos
f00422cc99484ad767b5bfedb8d9edc93799b8cda909d06490ee1afb3a357c82

查看container容器的IP地址

[root@docker-master ~]# docker exec container ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
142: eth0@if143: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

使用ping命令测试与容器test3的连通性(test3容器的IP为172.17.0.3/16)

[root@docker-master ~]# docker exec container ping 172.17.0.3 -c 1
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.308 ms

--- 172.17.0.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.308/0.308/0.308/0.000 ms

bridge模式:容器启动后通过 DHCP 获取IP地址

[root@docker-master ~]# docker run -it --net bridge --name bridge centos
[root@92936020c12c /]# ip address show | grep eth0
148: eth0@if149: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0

host模式:容器共享宿主机的网络

观察到,进入容器内,主机名、网络结构都与宿主机相同

[root@docker-master ~]# docker run -itd --net host --name host centos
aca03def6fe2ecb02daa4dda580f60065b6d53fe9f2a3c356a2343185058b6c3
[root@docker-master ~]# docker exec -it host /bin/bash
[root@docker-master /]# ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:b3:80:76 brd ff:ff:ff:ff:ff:ff
    inet 192.168.132.167/24 brd 192.168.132.255 scope global dynamic noprefixroute ens33
       valid_lft 1753sec preferred_lft 1753sec
    inet6 fe80::d906:bfb6:efc2:b001/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:59:41:ad:ec brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:59ff:fe41:adec/64 scope link 
       valid_lft forever preferred_lft forever
143: veth1aab036@if142: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 02:4e:7e:c2:ce:99 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::4e:7eff:fec2:ce99/64 scope link 
       valid_lft forever preferred_lft forever
145: vethd082e8b@if144: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 2a:3b:74:93:36:16 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::283b:74ff:fe93:3616/64 scope link 
       valid_lft forever preferred_lft forever