Docker 网络原理
容器是绝对独立的环境,相当于一个小型的 Linux 零碎,外界无奈间接拜访,那他是怎么做的呢,这里咱们先理解下 Linux veth pair。
1. Linux veth pair
veth pair 是成对呈现的一种虚构网络设备接口,一端连着网络协议栈,一端彼此相连。如下图所示:
veth pair将两个网络veth0和veth1连通。
2. 了解Docker0
咱们先查看本地ip
这里咱们剖析可得,有三个网络:
lo 127.0.0.1 # 本机回环地址eth0 172.31.179.120 # 阿里云的公有IP(如果你是虚拟机就是虚拟机的ip)docker0 172.17.0.1 # docker网桥
lo和eth0在咱们的虚拟机启动的时候就会创立,然而docker0在咱们装置了docker的时候就会创立。docker0用来和虚拟机之间通信。
问题:Docker 是如何解决容器网络拜访的?咱们先启动一个 tomcat 容器来阐明。
[root@jiangnan tomcat1]# docker pull tomcat[root@jiangnan tomcat1]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEtomcat latest fb5657adc892 2 months ago 680MB[root@jiangnan tomcat1]# docker run -d -p 8081:8080 --name tomcat01 tomcat914a7d82b017f63f81c6eba49af5471441f1946c9d45509b69ab2c50c2713b6f[root@jiangnan tomcat1]#
这里启动了tomcat01,咱们再来查看网络
发现:咱们后面查看的时候还是三组网卡,当启动了一个tomcat容器之后,多了一组网卡201: vethad33778@if200,而且还是成对的。同样咱们再来启动一个tomcat02会又多出一对网卡。
进入了 tomcat01 容器内能够看到 tomcat01 对应的 ip 地址为:172.17.0.2
在宿主机上也可ping通。
阐明:tomcat02对应的ip为172.17.0.3,也能够ping通。
论断:咱们每启动一个容器,就会多出一对网卡,同时他们被连贯到docker0上,而docker0又和虚拟机之间连通。
也能够通过inspect查看。
[root@jiangnan tomcat1]# docker network lsNETWORK ID NAME DRIVER SCOPE4d3e75606593 bridge bridge local # 这个就是docker08e92ee24e5f6 host host locale85ffb1f2cc3 none null local[root@jiangnan tomcat1]# docker inspect 4d3e75606593"IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" # 网关 } ] },"Containers": { # 容器 "15910ee083965d60c46bf9b3b292570fef9b8925905aa4df90c6d48142bb2eee": { "Name": "tomcat01", "EndpointID": "9c7a5ab65f1fc91b1d92ad61dec9b2f518f67f69f662522483dca789616f42aa", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", "IPv6Address": "" }, "6c9a6a5d8eca9ad52926008c7b30516d23293ff8ad1f38947957d571431d5297": { "Name": "tomcat02", "EndpointID": "f83c1e643236cd65f50fba03929ca14d5df8d135b1f6cb8adf203cf96084f7aa", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", "IPv6Address": "" } },
咱们能够形象为这样一个网络模型。
在这里,咱们能够看到Docker0相当于一个路由器的作用,任何一个容器启动默认都是docker0网络。
docker默认会给容器调配一个可用ip,并把它同docke0相连。应用到的就是veth pair技术。
3. 容器互联–Link
在网络模型图中能够看出,容器和容器之间不能间接连通。
后面咱们启动的两个 tomcat 对应的 hosts 如下:
[root@jiangnan tomcat1]# docker exec -it tomcat01 cat /etc/hosts127.0.0.1 localhost::1 localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters172.17.0.2 3ecb3204e2dcroot@3ecb3204e2dc:/usr/local/tomcat#
[root@jiangnan tomcat1]# docker exec -it tomcat02 cat /etc/hosts127.0.0.1 localhost::1 localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters172.17.0.3 6c9a6a5d8eca[root@jiangnan tomcat1]#
发现:他们的 hosts 中只有各自的ip地址。
然而在理论的工作中,容器应用的是虚构ip,每次启动ip都会变动,思考一个场景,咱们编写一个微服务,数据库连贯地址原来是应用ip的,如果ip变动就不行了,那咱们能不能应用服务名拜访呢?咱们在启动一个tomcat03,应用—link绑定到tomcat02上。而后看它的hosts是什么样的。
[root@jiangnan tomcat1]# docker run -d -p 8083:8080 --name tomcat03 --link tomcat02 tomcatdb75c42f7f7f609218deb290d3e923e3c7da6bcf8c0b38cde27962fb2b9e9a54[root@jiangnan tomcat1]# docker exec -it tomcat03 cat /etc/hosts127.0.0.1 localhost::1 localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters172.17.0.3 tomcat02 e4060ea4ee28 # 发现tomcat2间接被写在这里172.17.0.4 db75c42f7f7froot@db75c42f7f7f:/usr/local/tomcat#
发现:应用了–link,岂但有了本人的ip,而且还有了tomcat02的服务名。然而tomcat02中并没有tomcat03的,因为–link是单向的。
这样就实现了容器和容器之间的连通。不须要通过ip地址连通,而是通过服务名就能够。
然而应用—link的办法过期了,咱们个别应用自定义网络。
4.自定义网络(举荐)
docker0的特点:
- 它是默认的
- 域名拜访不通
- –link 域名通了,然而删了又不行
docker为咱们提供了三种网络模式
[root@jiangnan tomcat1]# docker network lsNETWORK ID NAME DRIVER SCOPE4d3e75606593 bridge bridge local8e92ee24e5f6 host host locale85ffb1f2cc3 none null local[root@jiangnan tomcat1]#
这其中默认应用的是 bridge,也就是咱们的docker0网卡。
在咱们启动容器的时候,实际上是如下命令
[root@jiangnan tomcat1]# docker run -d -P --name tomcat01 --net bridge tomcat
这个—net是默认的,所以被省略了。
上面咱们自定义一个网络 mynet。
# 自定义创立的默认default "bridge"[root@jiangnan tomcat1]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet3136d64109c6f285bc69d3ee4be901524292d0e5ddd9e414d49197dfa6c19ba1[root@jiangnan tomcat1]# docker network lsNETWORK ID NAME DRIVER SCOPE4d3e75606593 bridge bridge local8e92ee24e5f6 host host local3136d64109c6 mynet bridge local # 多了一个mynete85ffb1f2cc3 none null local[root@jiangnan tomcat1]# docker network inspect mynet[ { "Name": "mynet", "Id": "3136d64109c6f285bc69d3ee4be901524292d0e5ddd9e414d49197dfa6c19ba1", "Created": "2022-02-27T14:15:44.676693958+08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "192.168.0.0/16", # 子网地址 "Gateway": "192.168.0.1" # 网关 } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": {}, "Labels": {} }][root@jiangnan tomcat1]#
查看网络
[root@jiangnan tomcat1]# docker inspect mynet[ { "Name": "mynet", "Id": "3136d64109c6f285bc69d3ee4be901524292d0e5ddd9e414d49197dfa6c19ba1", "Created": "2022-02-27T14:15:44.676693958+08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "192.168.0.0/16", "Gateway": "192.168.0.1" }] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "31f12c9332e8b4b6e66619dc988533f2863b80e71dbf490c8313694637814ca1": { "Name": "tomcat-net-02", "EndpointID": "1c0e9dbffff295f2326bfd1e2847c0f1d9136ff00519101bb11d922e7da4f818", "MacAddress": "02:42:c0:a8:00:03", "IPv4Address": "192.168.0.3/16", "IPv6Address": "" }, "675439c851dc29355c03f82bb163f9e5a326e230447d86d40d53ff08766cfd06": { "Name": "tomcat-net-01", "EndpointID": "2653da0a25d166f0d7222235e85d8231d9424e19949b6e6b7cfa1a3eddcc462b", "MacAddress": "02:42:c0:a8:00:02", "IPv4Address": "192.168.0.2/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} }][root@jiangnan tomcat1]#
# 咱们来测试ping容器名和ip试试,都能够ping通[root@jiangnan ~]# docker exec -it tomcat-net-01 ping 192.168.0.3PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.093 ms[root@jiangnan ~]# docker exec -it tomcat-net-01 ping tomcat-net-02PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.063 ms64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.066 ms
发现:不必—link也能够间接通过服务名ping通了。
5.网络连通
docker0和自定义网络必定不通,咱们应用自定义网络的益处就是网络隔离。然而在理论的工作中,比方咱们部署了mysql应用了一个网段。部署了tomcat应用了另一个网段,两个网段之间必定是不能互相连通的,然而tomcat和mysql又须要互相连通,咱们就要应用网络连通。原理图如下:
网络连通就是将一个容器和一个网段之间的连通。
比方我后面应用的默认docker0的tomcat01,须要连贯到mynet网络。
# docker network connect 网络 容器[root@jiangnan tomcat1]# docker network connect mynet tomcat01[root@jiangnan tomcat1]# docker network inspect mynet[ { "Name": "mynet", "Id": "3136d64109c6f285bc69d3ee4be901524292d0e5ddd9e414d49197dfa6c19ba1", "Created": "2022-02-27T14:15:44.676693958+08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "192.168.0.0/16", "Gateway": "192.168.0.1" }] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "2e709013935463c29caf28771bb49925fee4e02842459b339d7dd1ad5dedf9b7": { "Name": "tomcat-net-01", "EndpointID": "9f3a46bad37ade7935e283715caa5699e9a7e22175b592f4a4792a37c351d969", "MacAddress": "02:42:c0:a8:00:02", "IPv4Address": "192.168.0.2/16", "IPv6Address": "" }, "5c0c544f2507d9f5f456feceddbd853ebccc07cea8c39c8479693731e480bf55": { "Name": "tomcat01", "EndpointID": "d05abb2d31af4067c5a45f299ce7b4401b1fa81638a44b6c09f3de7f8f4221fe", "MacAddress": "02:42:c0:a8:00:04", "IPv4Address": "192.168.0.4/16", "IPv6Address": "" }, "d6066db5fdd0b508514107a896ed20b639eaa47dbd97a025ad0c52250766c8a4": { "Name": "tomcat-net-02", "EndpointID": "3a5f6f2a07d900303382b290825c9f52640689c859608c741c7c7d81031e107e", "MacAddress": "02:42:c0:a8:00:03", "IPv4Address": "192.168.0.3/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} }][root@jiangnan tomcat1]#
通过这种形式间接将tomcat01加到了mynet网络中。
6.总结
- veth pair是成对呈现的一种虚构网络设备接口,一端连着网络协议栈,一端彼此相连。
- docker中默认应用docker0网络。
- docker0相当于一个路由器的作用,任何一个容器启动默认都是docker0网络。
- docker0是容器和虚拟机之间通信的桥梁。
- 举荐应用自定义网络,更好实现应用服务名的连通形式,防止ip扭转的难堪。
- 网络之间不能间接连通,网络连通是将一个容器和一个网络之间的连通,实现跨网络操作。