共计 6282 个字符,预计需要花费 16 分钟才能阅读完成。
本篇接着上篇:【Docker0 网络及原理探索】,持续深刻探索容器网络通信原理,通过学习 Docker 网路驱动模型,更好地解决容器间的通信问题🎉🎉
1、Docker 的网络驱动模型
1.1、Docker 的网络驱动模型分类:
bridge
:Docker 中默认的网络驱动模型,在启动容器时如果不指定则默认为此驱动类型;host
:突破 Docker 容器与宿主机之间的网络隔离,间接应用宿主机的网络环境,该模型仅实用于 Docker17.6 及以上版本;overlay
:能够连贯多个 docker 守护过程或者满足集群服务之间的通信;实用于不同宿主机上的 docker 容器之间的通信;macvlan
:能够为 docker 容器调配MAC
地址,使其像实在的物理机一样运行;none
:即禁用了网络驱动,须要本人手动自定义网络驱动配置;plugins
:应用第三方网络驱动插件;
1.2、Docker 网络模式
- 查看 docker 网络
docker network ls
[root@--- ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
feafa30d4051 bridge bridge local
e8bf4fced9e2 host host local
6263db0933b9 none null local
[root@--- ~]#
Docker 内置这三个网络,运行容器时,你能够应用该 --network
标记来指定容器应连贯到哪些网络。
该 bridge
网络代表 docker0
所有 Docker 装置中存在的网络。除非你应用 docker run --network=<NETWORK>
选项指定,否则 Docker 守护程序默认将容器连贯到此网络。
咱们在应用 docker run
创立 Docker 容器时,能够用 --net
选项指定容器的网络模式,Docker 能够有以下 4 种网络模式:
host 模式
:应用--net=host
指定。none 模式
:应用--net=none
指定。bridge 模式
:应用--net=bridge
指定,默认设置。container 模式
:应用--net=container:NAME_or_ID
指定。
docker run -it -P --name tomcat01 --net=bridge tomcat # 默认设置
docker run -it -P --name tomcat02 --net=none tomcat
# ...
2、容器通信问题
- 因为不同容器通过
veth pair
连贯在虚构网桥docker0
上,所以容器之间能够通过IP
相互通信,然而无奈通过容器名进行通信。docker0 不反对容器名连贯拜访 - 默认网桥
bridge
上的容器只能通过 IP 互连,无奈通过DNS
解析名称或别名。如果咱们在 container1 中部署了 Web 服务,在 container2 中部署了 mysql,container1 中的 Web 服务往往须要连贯 container2 的 mysql,这是只能靠 IP 进行连贯,然而 docker 也无奈保障容器重启后的 IP 地址不变,所以更好的形式是通过别名进行互联,在网络中退出 DNS 服务器,将容器名与 IP 地址进行匹配,省去了手动批改 Web 服务中连贯 mysql 的 IP 的过程。
为了实现不同容器 通过容器名或别名的互连,docker 提供了以下几种:👇
- 在启动 docker 容器时退出
--link
参数,然而目前曾经被废除,废除的次要起因是须要在连贯的两个容器上都创立 –link 选项,当互连的容器数量较多时,操作的复杂度会显著减少; - 启动 docker 容器后进入容器并批改
/etc/hosts
配置文件(本地 DNS 解析),毛病是手动配置较为繁冗; - 用户 自定义 bridge 网桥 ,这是目前解决此类问题的次要办法,提供更好的隔离成果和更好的互通性(更好的隔离成果是针对外界网络,而更好的互通性则是指同一
bridge
下的不同容器之间),用户自定义 bridge 在容器之间提供了主动 DNS 解析。
容器在默认状况下以隔离形式运行,它们齐全不晓得同一计算机上有其余过程或容器。那么,如何使容器可能彼此通信?答案就是网络连接。如果两个容器在同一网络上,那么它们可彼此通信。如果没在同一网络上,则没法通信。
3、容器之间通信的次要形式总结
3.1、通过容器 ip 拜访
容器重启后,ip 会发生变化。通过容器 ip 拜访不是一个好的计划。
3.2、通过宿主机的 ip:port 拜访
通过宿主机的 ip:port
拜访,只能依附监听在暴露出的端口的过程来进行无限的通信。
3.3、通过 --link
建设连贯(官网不举荐应用)
原理剖析:
- 运行容器时,指定参数 link,使得源容器与被链接的容器能够进行互相通信,并且承受的容器能够取得源容器的一些数据,比方:环境变量。
- 与
/etc/hosts
中的主机条目不同,如果重新启动源容器,则不会自动更新存储在环境变量中的 IP 地址。咱们倡议应用主机条目/etc/hosts
来解析链接容器的 IP 地址。 - 除了环境变量之外,Docker 还将源容器的主机条目增加到
/etc/hosts
文件中。(实质上就是通过--link
参数,主动的给容器增加hosts
配置)
--link
建设连贯步骤:✨
- 启动 tomcat01,tomcat02
docker run -it -P --name tomcat01 tomcat
docker run -it -P --name tomcat02 tomcat
--link
通过配置/etc/hosts
实现连贯- 通过
link
建设连贯的容器,被链接的容器能 ping 通源容器,反过来不行。- 被链接容器会继承源容器的环境变量信息
- 建设
link
连贯
tomcat02
容器 link 到 tomcat03
上
docker run -it -P --name tomcat03 --link tomcat02 tomcat
- 查看 tomcat03 hosts 配置
[root@--- ~]# docker exec -it tomcat03 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.3 tomcat02 099602f3ff7f #✨--link 命令配置生成的条目✨
172.17.0.4 a20a10b7e728
[root@--- ~]#
3.4、🧨通过 User-defined networks(举荐)
用户自定义网桥步骤:✨
- 创立用户自定义 bridge 网桥
[root@--- ~]# docker network create test-network
799426d70aa28b73b4a777c85b338186eafadd1558b13c43e07a9fd9a8b545e7
[root@iZm5e23n3ueobwkjtfartxZ ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
feafa30d4051 bridge bridge local
e8bf4fced9e2 host host local
6263db0933b9 none null local
799426d70aa2 test-network bridge local #✨创立的桥接网络✨
删除网桥:
docker network rm test-network
-
把之前启动的 mysql01,centos01,centos02 容器退出到自定义 bridge 网桥中:
connect
docker network connect test-network mysql01 docker network connect test-network centos01 docker network connect test-network centos02
- 查看自定义 bridge 网桥信息
docker network inspect 799426d70aa2
[
{
"Name": "test-network",
"Id": "799426d70aa28b73b4a777c85b338186eafadd1558b13c43e07a9fd9a8b545e7",
"Created": "2021-10-03T20:30:03.325679562+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16", #✨test-network 的子网✨
"Gateway": "172.18.0.1" #✨test-network 的网关✨
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {"29298987c51b777b546bf6626560020ce235e390e1d7fcfe188c6db228ca4edf": {"Name":"mysql01","EndpointID":"a69560a1872a25af042c74132df5dcade6e0e93faf9102185c1de19f6c8b3b36","MacAddress":"02:42:ac:12:00:02","IPv4Address":"172.18.0.2/16", #✨mysql01 容器的 IP,与之前不同✨"IPv6Address":""},
"cb1922b95b9316d129b54f3545fad9729092926e10a1d5517f8928db42706151": {
"Name": "centos01",
"EndpointID": "f0cf5feb77ec23526fe5cee217dba9271125b9b4106c81bc7d58253ac48a4caf",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16", #✨centos01 容器的 IP,与之前不同✨
"IPv6Address": ""},"cc6f510b9765ba018dbafd416c9774ddf5fd3ff55fa992827f55516e8dc70b6a": {"Name":"centos02","EndpointID":"6c88540d719014e441d3119c4388e62d311b07acf009106e16aa66d7ebaf5763","MacAddress":"02:42:ac:12:00:04","IPv4Address":"172.18.0.4/16", #✨centos02 容器的 IP,与之前不同✨"IPv6Address":""}
},
"Options": {},
"Labels": {}}
]
- 通过容器名或别名互连通信
进入 centos01 容器,ping centos02
, ping mysql01
能够发现 centos01 能够和 centos02、mysql01 容器之间能够通信
docker exec -it cb1922b95b93 /bin/bash👈
[root@cb1922b95b93 /]# ping centos02👈
PING centos02 (172.18.0.4) 56(84) bytes of data.
64 bytes from centos02.test-network (172.18.0.4): icmp_seq=1 ttl=64 time=0.118 ms
64 bytes from centos02.test-network (172.18.0.4): icmp_seq=2 ttl=64 time=0.113 ms
...
ping mysql01👈
PING mysql01 (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql01.test-network (172.18.0.2): icmp_seq=1 ttl=64 time=0.107 ms
64 bytes from mysql01.test-network (172.18.0.2): icmp_seq=2 ttl=64 time=0.103 ms
...
- 断开网络
因为咱们的容器依然连贯着默认 bridge 网桥 docker0,而当初咱们曾经不须要它,所以应该将容器与 docker0 的连贯断开,执行以下操作disconnect
:
docker network disconnect bridge mysql01
docker network disconnect bridge centos01
docker network disconnect bridge centos02
- 查看默认 bridge 网桥 docker0 的容器网络配置
docker network inspect feafa30d4051👈
[
{
"Name": "bridge",
"Id": "feafa30d4051f24353508959bd420fd163ad0c98d6b30ec8ff13b59a59552bb1",
"Created": "2021-09-26T15:10:27.167774553+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {}, #✨之前的容器服务,曾经从默认网桥中移除✨"Options": {"com.docker.network.bridge.default_bridge":"true","com.docker.network.bridge.enable_icc":"true","com.docker.network.bridge.enable_ip_masquerade":"true","com.docker.network.bridge.host_binding_ipv4":"0.0.0.0","com.docker.network.bridge.name":"docker0","com.docker.network.driver.mtu":"1500"},"Labels": {}}
]
最初
理解了 Docker 网络、容器通信之后,对持续学习服务网格(Service Mesh
)与 Kubernetes
的服务发现有很大帮忙。很多的我的项目架构也都是从网络通信角度进行的层级、模块划分(比方:网路拓扑图、终极零碎架构异地多活)。对于网络,学完之后你会发现很多货色都串一块了,超级有意思😊
微信公众号:【看见另一种可能】
🌹 继续更文,关注我,你会发现一个虚浮致力的宝藏程序员😊,让咱们一起学习,独特成长吧。
🎉 喜爱的小伙伴记得点赞关注珍藏哟,回看不迷路 😉
🎁 欢送大家评论交换, 蟹蟹😊