docker 容器之间通信
简介
我们安装Docker后,它会自动创建三个网络,bridge(创建容器默认连接到此网络)、 none 、host。
- host:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
- None:该模式关闭了容器的网络功能,相当于一个回环网络。
- Bridge:此模式会为每一个容器分配、设置IP等,并将容器连接到一个叫docker0的虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。
关于上述提到的三个网络解释如下:
- Host:相当于Vmware中的桥接模式,与宿主机在同一个网络中,但没有独立的IP地址。众所周知,Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。基于Host模式启动的容器,在容器内执行ifconfig时,看到的都是宿主机上的信息。该模式不够灵活,容易出现端口冲突问题。
- None:该模式将容器放置在它自己的网络栈中,但是并不进行任何配置。实际上,该模式关闭了容器的网络功能,类似于会换地址,在以下两种情况下是有用的:容器并不需要网络(例如只需要写磁盘卷的批处理任务)。
- overlay:顾名思义:覆盖,但它又不是覆盖,它的作用就是在容器原有的网络基础之上,再添加一块网卡,并为其分配一个IP地址,可以将所有的docker容器关联到同一个局域网中,适用于容器与容器是跨主机进行通信的场景。
- Bridge:相当于Vmware中的NAT模式,容器使用独立的network Namespace,并且连接到docker0虚拟网卡(默认模式)。通过docker网桥以及IPtables nat表配置与宿主机通信;Bridge模式是Docker默认的网络设置,此模式会为每一个容器分配一个Network nameSpace、设置IP等,并将一个主机上的Docker容器连接到一个虚拟网桥docker0上。
Bridge如图:
网络模式使用总结
上面讲了关于docker的网络模式,主要关于以哪种方式让服务器内部的容器与公网进行通信。
1、假如使用的是默认的桥接网络模式,启动容器的时候需要使用参数-p 宿主机端口:容器端口设置端口的映射。
2、假如使用的是host主机模式,因为使用的是宿主机的ip与端口,那就直接可以与公网通信。
相关命令
查看docker创建的网络
#执行该命令查看docker创建的网络
docker network ls
创建新网络
docker network create <network-name>
将容器连接到网络
docker run --net=<network-name> ...
或者将已存在容器加入新的网络
docker network connect <network-name> <container-name>
按名称ping容器
docker exec -ti <container-name-A> ping <container-name-B>
Ps:需要注意的是,如果容器没有指定名称(–name),那么就只能用id
启动容器并指定模式
默认是Bridge
在容器启动命令时用参数--net=host指定当前容器网络模式
如:
docker run -itd --net=host centos:7 /bin/bash
查看容器元信息
docker inspect 容器ID
docker网络连接命令介绍
docker network connect 命令是用于将docker容器连接到某个网络中,或者与其他容器建联,容器可以使用容器名或者容器ID。
用法
docker network connect [OPTIONS] NETWORK CONTAINER
选项
名称,简写 | 默认 | 说明 |
---|---|---|
--alias |
为容器添加网络范围的别名 | |
--ip |
指定IP地址 | |
--ip6 |
指定IPv6地址 | |
--link |
添加链接到另一个容器 | |
--link-local-ip |
添加容器的链接本地地址 |
相关命令
命令名称 | 说明 |
---|---|
docker network connect | 将容器连接到网络 |
docker network create | 创建一个网络 |
docker network disconnect | 断开容器的网络 |
docker network inspect | 显示一个或多个网络的详细信息 |
docker network ls | 列出网络 |
docker network prune | 删除所有未使用的网络 |
docker network rm | 删除一个或多个网络 |
docker默认Bridge内部通信
在实际的项目环境中,肯定会存在多个服务间通信的情况。也就是多个容器之间通信。
那么该如何通信呢?
它们都是通过默认的bridge
进行通信的。
启动两个centos7
docker run -itd --name centos1 centos:7
docker run -itd --name centos2 centos:7
查看两个容器的元信息
主要是看虚拟ip
该命令会返回所有元信息
docker inspect 5c266f40400e
可以使用过滤并一次查询两个ip
docker inspect --format '{{ .NetworkSettings.IPAddress }}' 容器id1 容器id2
[root@localhost ~]# docker inspect --format '{{ .NetworkSettings.IPAddress }}' 5c266f40400e 861e6b2f0566
172.18.0.2
172.18.0.3
可以看到两个容器虚拟ip分别为172.18.0.2
172.18.0.3
宿主机ping容器
[root@localhost ~]# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.079 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.077 ms
64 bytes from 172.18.0.2: icmp_seq=3 ttl=64 time=0.054 ms
^C
--- 172.18.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.054/0.070/0.079/0.011 ms
[root@localhost ~]# ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.053 ms
64 bytes from 172.18.0.3: icmp_seq=2 ttl=64 time=0.052 ms
64 bytes from 172.18.0.3: icmp_seq=3 ttl=64 time=0.041 ms
^C
--- 172.18.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.041/0.048/0.053/0.009 ms
可以看到两个都可以ping通
容器间互ping
开两个ssh窗口
容器1
#进入容器
docker exec -it 5c266f40400e
[root@5c266f40400e /]# ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.072 ms
64 bytes from 172.18.0.3: icmp_seq=2 ttl=64 time=0.052 ms
^C
--- 172.18.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.052/0.062/0.072/0.010 ms
[root@5c266f40400e /]# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.032 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.032 ms
^C
--- 172.18.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.032/0.032/0.032/0.000 m
容器2
#进入容器
docker exec -it 861e6b2f0566 /bin/bash
[root@861e6b2f0566 /]# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.058 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.068 ms
^C
--- 172.18.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.058/0.063/0.068/0.005 ms
[root@861e6b2f0566 /]# ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.032 ms
64 bytes from 172.18.0.3: icmp_seq=2 ttl=64 time=0.022 ms
^C
--- 172.18.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.022/0.027/0.032/0.005 ms
总结
经过上面的测试你会发现宿主机,容器,容器和容器根据虚拟ip连通完全没有问题
缺点
在docker中容器间直接通过ip进行服务访问是存在弊端的。假如上面例子中某个centos容器突然挂掉重启也失败,只能重新run一个。这时ip可能会发生变化,那就需要进去直接修改相关配置信息,就很不友好。
解决办法
因此Docker也提供了基于容器名来与其它容器通信。
docker基于容器名通信
容器之间若要通过容器名之间进行网络通信,需要保证两个容器在同一交换机下,且是在非默认的名为bridge
的交换机下.
所以在创建容器之前,需要新建一个交换机,网络创建前,可以使用docker network ls
查看当前的交换机.。
创建网络交换机
docker network create myNerwork
启动两个容器并指定网络
docker run -itd --name centos3 --network=myNerwork centos:7
docker run -itd --name centos4 --network=myNerwork centos:7
进入网络交换机中查看网络信息
docker network inspect myNerwork
#返回
[
{
"Name": "myNerwork",
"Id": "c4fc8902df6c6343c56fe7966d4454cf0cee43a8ce9c843bbe1613b3232de98f",
"Created": "2021-01-06T16:35:32.8229922+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"04e723114d3fd9f92b50f37b960db168ffe7eb16302e36b257dcc52a78585caf": {
"Name": "centos4",
"EndpointID": "38002e89da4897edf1a27ebf57cf8723950a2e7c0e260c19fb99b8deb66ecc54",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"5f7d789b38691678e0b9f0226b23f9839d9eb2ad4ece436d3e5db9d650ba5e3c": {
"Name": "centos3",
"EndpointID": "647a516fa3d579ee2f7031a3e0c06f2c29d50e9ca94696957d5ad5b8a60d6724",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
发现两个容器都已经在新的网络中了
测试容器使用容器名互ping
分别进入两个容器
容器1
docker exec -it 5f7d789b3869 /bin/bash
[root@5f7d789b3869 /]# ping centos4
PING centos4 (172.17.0.3) 56(84) bytes of data.
64 bytes from centos4.myNerwork (172.17.0.3): icmp_seq=1 ttl=64 time=0.064 ms
64 bytes from centos4.myNerwork (172.17.0.3): icmp_seq=2 ttl=64 time=0.091 ms
64 bytes from centos4.myNerwork (172.17.0.3): icmp_seq=3 ttl=64 time=0.050 ms
64 bytes from centos4.myNerwork (172.17.0.3): icmp_seq=4 ttl=64 time=0.065 ms
64 bytes from centos4.myNerwork (172.17.0.3): icmp_seq=5 ttl=64 time=0.048 ms
^C
--- centos4 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 3999ms
rtt min/avg/max/mdev = 0.048/0.063/0.091/0.017 ms
没啥问题
容器2
docker exec -it centos4 /bin/bash
[root@04e723114d3f /]# ping centos3
PING centos3 (172.17.0.2) 56(84) bytes of data.
64 bytes from centos3.myNerwork (172.17.0.2): icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from centos3.myNerwork (172.17.0.2): icmp_seq=2 ttl=64 time=0.066 ms
64 bytes from centos3.myNerwork (172.17.0.2): icmp_seq=3 ttl=64 time=0.094 ms
64 bytes from centos3.myNerwork (172.17.0.2): icmp_seq=4 ttl=64 time=0.084 ms
^C
--- centos3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 0.044/0.072/0.094/0.019 ms
没啥问题