Docker网络详解
Docker网络详解
Docker0网络
准备工作:清空所有的容器,清空所有的镜像
docker rm -f $(docker ps -a -q) # 删除所有容器 docker rmi -f $(docker images -qa) # 删除全部镜像
本地干净的网络
[root@kuangshenlinux ~]# ip addr # 本地回环网络 1: lo: 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 # 网卡地址 wifi 2: enp0s3: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 08:00:27:e0:aa:73 brd ff:ff:ff:ff:ff:ff inet 192.168.0.111/24 brd 192.168.0.255 scope global noprefixroute enp0s3 valid_lft forever preferred_lft forever inet6 fe80::3202:526:12cb:70ec/64 scope link noprefixroute valid_lft forever preferred_lft forever # docker 0 ,docker创建的网络 3: docker0: mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:f8:9d:a8:42 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
1、微服务这么多,访问怎么解决? (容器名)
2、docker每启动一个容器,就会给他分配一个ip。docker0是docker默认给的。我们不指定网络的情况下,创建容器都在docker0中,未来开发,我们要自定义网络。
[root@kuangshenlinux ~]# docker run -itd --name web01 centos Unable to find image 'centos:latest' locally latest: Pulling from library/centos a1d0c7532777: Already exists Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177 Status: Downloaded newer image for centos:latest 53231c3adf0423ed2d0577ead987507c12978416349a51445d663c9536c9b4ff # docker每启动一个容器,就会给他分配一个ip。这个ip就是归docker0 管理 [root@kuangshenlinux ~]# docker exec -it web01 ip addr 1: lo: 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 4: eth0@if5: 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到容器里面 [root@kuangshenlinux ~]# ping 172.17.0.2 PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data. 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.058 ms
分析原理
1、本来有三个网络,启动容器后,多了一个,这个网络和容器内部的网络是配对的。
# 再次启动一个容器查看 [root@kuangshenlinux ~]# docker exec -it web02 ip addr 1: lo: 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 6: eth0@if7: 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@kuangshenlinux ~]# ip addr .... 3: docker0: mtu 1500 qdisc noqueue state UP group default link/ether 02:42:f8:9d:a8:42 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:f8ff:fe9d:a842/64 scope link valid_lft forever preferred_lft forever 5: veth3b4847e@if4: mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 0e:58:71:93:42:18 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::c58:71ff:fe93:4218/64 scope link valid_lft forever preferred_lft forever 7: veth13568df@if6: mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 9a:3c:71:70:e2:a0 brd ff:ff:ff:ff:ff:ff link-netnsid 1 inet6 fe80::983c:71ff:fe70:e2a0/64 scope link valid_lft forever preferred_lft forever # 总结观察: 1、web1 -- linux 主机 5: veth3b4847e@if4: 4: eth0@if5 2、web2 -- linux 主机 7: veth13568df@if6: 6: eth0@if7 # 只要启动一个容器,默认就会分配一对网卡。 # 虚拟接口 # veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。 # 就好比一个桥梁,可以连通容器内外。
# 测试容器之间的访问,ip访问没有问题 [root@kuangshenlinux ~]# docker exec -it web02 ping 172.17.0.2 PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data. 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.058 ms 64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.064 ms ^C --- 172.17.0.2 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 0.058/0.061/0.064/0.003 ms [root@kuangshenlinux ~]# docker exec -it web01 ping 172.17.0.3 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.043 ms 64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.071 ms 64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.092 ms ^C --- 172.17.0.3 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2005ms rtt min/avg/max/mdev = 0.043/0.068/0.092/0.022 ms
小结
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。
–link
mysql: 服务名地址链接 ip会变化
[root@kuangshenlinux ~]# docker exec -it web02 ping web01 ping: web01: Name or service not known # 但是可以通过 --link在启动容器的时候连接到另一个容器网络中,可以通过域名ping了 [root@kuangshenlinux ~]# docker run -itd --name web03 --link web02 centos 6f67f9f7407edb8c48ce2d3ca413aef414a2a8628080fd69605e4ce2c3bea6ab [root@kuangshenlinux ~]# docker exec -it web03 ping web02 PING web02 (172.17.0.3) 56(84) bytes of data. 64 bytes from web02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.062 ms 64 bytes from web02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.064 ms 64 bytes from web02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.064 ms ^C --- web02 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2005ms rtt min/avg/max/mdev = 0.062/0.063/0.064/0.006 ms # 但是反向也ping不通。 [root@kuangshenlinux ~]# docker exec -it web02 ping web03 ping: web03: Name or service not known # 底层原理 域名: --link hosts 添加了一条记录 172.17.0.3 web02 [root@kuangshenlinux ~]# docker exec -it web03 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 web02 325795bd6df8 172.17.0.4 6f67f9f7407e [root@kuangshenlinux ~]#
–link是以前的方法,不方便了。
自定义网络
[root@kuangshenlinux ~]# docker network --help Usage: docker network COMMAND Manage networks Commands: connect Connect a container to a network create Create a network disconnect Disconnect a container from a network inspect Display detailed information on one or more networks ls List networks prune Remove all unused networks rm Remove one or more networks Run 'docker network COMMAND --help' for more information on a command. # 查看所有的网络 [root@kuangshenlinux ~]# docker network ls NETWORK ID NAME DRIVER SCOPE defce6912c4a bridge bridge local e6e26ff63dfe host host local 8a592709b443 none null local
所有网络模式
网络模式 | 配置 | 说明 |
---|---|---|
bridge模式 | –net=bridge | 默认值,在Docker网桥docker0上为容器创建新的网络栈 |
none模式 | –net=none | 不配置网络,用户可以稍后进入容器,自行配置 |
container模式 | –net=container:name/id | 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。 |
host模式 | –net=host | 容器和宿主机共享Network namespace |
用户自定义 | –net=自定义网络 | 用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定义的网络 |
[root@kuangshenlinux ~]# docker network inspect bridge [ { "Name": "bridge", "Id": "defce6912c4ae8b16d6f02a6eee0650c79c7d39cba26597de32648f936c0cd43", "Created": "2023-12-12T19:57:25.572880728+08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { // 网络配置: config配置,子网网段 255*255. 65534 个地址 "Subnet": "172.17.0.0/16", // docker0 网关地址 "Gateway": "172.17.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, // 在这个网络下的容器地址。Name就是容器的名字 "Containers": { "325795bd6df82e6ef18ff027f43a189c4ef886a25b95fdc9c5793bc9d7827179": { "Name": "web02", "EndpointID": "9ab43d4cd786b8c79d78fd3bf3f05c6dfbd6f1665ca5bc9e74646f1d6f758508", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", "IPv6Address": "" }, "53231c3adf0423ed2d0577ead987507c12978416349a51445d663c9536c9b4ff": { "Name": "web01", "EndpointID": "b891d5b8213b8241b5438c60afc08054c0c4c48490a3715f21fe5591b28b65fc", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", "IPv6Address": "" }, "6f67f9f7407edb8c48ce2d3ca413aef414a2a8628080fd69605e4ce2c3bea6ab": { "Name": "web03", "EndpointID": "651e2d1b9dcd72fc7339c687904cf763aaa524bd79cc5945888dfec8829a62b6", "MacAddress": "02:42:ac:11:00:04", "IPv4Address": "172.17.0.4/16", "IPv6Address": "" } }, "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": {} } ]
自定义一个网络
[root@kuangshenlinux ~]# docker run -itd --name web01 --net bridge centos 552223f74f163f94238bf536040aa0c683b1ab0fbfbcabdd1ed28644e40f1b9f # docker0网络的特点 1.它是默认的 2.域名访问不通 3.--link 域名通了,但是删了又不行
create命令创建一个新的网络
[root@kuangshenlinux ~]# docker network create \ --driver bridge \ --subnet 192.169.0.0/16 \ --gateway 192.169.0.1 \ mynet d37ec2853507c3e6159db06e4c8a33e39a45edff4ac69949c96f981d7aca9a79 [root@kuangshenlinux ~]# docker network ls NETWORK ID NAME DRIVER SCOPE defce6912c4a bridge bridge local e6e26ff63dfe host host local d37ec2853507 mynet bridge local 8a592709b443 none null local
使用的逻辑
# 未来可以通过网络来隔离项目 docker network create \ --driver bridge \ --subnet 192.169.0.0/16 \ --gateway 192.169.0.1 \ kuangstudynet mysql redis web admin mq # 部署集群挽环境,也可以这样定义网络 mysql 3-5个容器 docker network create \ --driver bridge \ --subnet 192.169.0.0/16 \ --gateway 192.169.0.1 \ mysqlnet --net mysqlnet
# 启动两个服务在自己的网络下。 --net mynet [root@kuangshenlinux ~]# docker run -itd --name wen01-net --net mynet centos e16726178e4ee3b61b0dc47f16d112ba0426bcf040b84949811ebc8607d94555 [root@kuangshenlinux ~]# docker run -itd --name wen02-net --net mynet centos 17fae7a2c0bb66c2834ad7d3dc338c0a5707aea5caf4337138f15c6f2079713e # 测试互相ping,可以使用域名ping通了 [root@kuangshenlinux ~]# docker exec -it wen01-net ping 192.169.0.3 PING 192.169.0.3 (192.169.0.3) 56(84) bytes of data. 64 bytes from 192.169.0.3: icmp_seq=1 ttl=64 time=0.063 ms 64 bytes from 192.169.0.3: icmp_seq=2 ttl=64 time=0.091 ms 64 bytes from 192.169.0.3: icmp_seq=3 ttl=64 time=0.066 ms ^C --- 192.169.0.3 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2001ms rtt min/avg/max/mdev = 0.063/0.073/0.091/0.014 ms [root@kuangshenlinux ~]# docker exec -it wen01-net ping wen02-net PING wen02-net (192.169.0.3) 56(84) bytes of data. 64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=1 ttl=64 time=0.041 ms 64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=2 ttl=64 time=0.064 ms 64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=3 ttl=64 time=0.106 ms 64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=4 ttl=64 time=0.088 ms ^C --- wen02-net ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3007ms rtt min/avg/max/mdev = 0.041/0.074/0.106/0.026 ms [root@kuangshenlinux ~]# docker exec -it wen02-net ping wen01-net PING wen01-net (192.169.0.2) 56(84) bytes of data. 64 bytes from wen01-net.mynet (192.169.0.2): icmp_seq=1 ttl=64 time=0.052 ms 64 bytes from wen01-net.mynet (192.169.0.2): icmp_seq=2 ttl=64 time=0.092 ms ^C --- wen01-net ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1002ms rtt min/avg/max/mdev = 0.052/0.072/0.092/0.020 ms # 未来在项目中,直接使用容器名来连接服务,ip无论怎么变,都不会发生变化 docker run -itd --name mysql --net mynet mysql mysql:3306/rbms
网络连通
由于我们现在是跨网络的,容器之间无法访问
[root@kuangshenlinux ~]# docker exec -it web01 ping wen01-net ping: wen01-net: Name or service not known [root@kuangshenlinux ~]# docker exec -it web01 ping 192.169.0.2
docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离:
大家公司项目部署的业务都非常多,假设我们有一个商城,我们会有订单业务(操作不同数据),会有订单业务购物车业务(操作不同缓存)。如果在一个网络下,有的程序猿的恶意代码就不能防止了,所以我们就在部署的时候网络隔离,创建两个桥接网卡,比如订单业务(里面的数据库,redis,mq,全部业务 都在order-net网络下)其他业务在其他网络。
那关键的问题来了,如何让 web-net-01 访问 web01?
[root@kuangshenlinux ~]# docker network connect --help Usage: docker network connect [OPTIONS] NETWORK CONTAINER Connect a container to a network # 第一个参数 网络 # 第二个参数 容器 [root@kuangshenlinux ~]# docker network connect mynet web01 [root@kuangshenlinux ~]# docker network inspect mynet [ { "Name": "mynet", "Id": "d37ec2853507c3e6159db06e4c8a33e39a45edff4ac69949c96f981d7aca9a79", "Created": "2023-12-12T20:34:57.1073687+08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "192.169.0.0/16", "Gateway": "192.169.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "17fae7a2c0bb66c2834ad7d3dc338c0a5707aea5caf4337138f15c6f2079713e": { "Name": "wen02-net", "EndpointID": "cd4963c8bc9e64182fffc5f7b202495c3c2b28d46da8e17d73d3a94359fd7c1d", "MacAddress": "02:42:c0:a9:00:03", "IPv4Address": "192.169.0.3/16", "IPv6Address": "" }, # web01 这个容器进入了 mynet 网络 "552223f74f163f94238bf536040aa0c683b1ab0fbfbcabdd1ed28644e40f1b9f": { "Name": "web01", "EndpointID": "d684b0ab3142219939957cbbd47a4a254d2459cbcac6fe9f9ae5aed0b7f32370", "MacAddress": "02:42:c0:a9:00:04", "IPv4Address": "192.169.0.4/16", "IPv6Address": "" }, "e16726178e4ee3b61b0dc47f16d112ba0426bcf040b84949811ebc8607d94555": { "Name": "wen01-net", "EndpointID": "574b3b469f3c2f2f5c21725b720adeaa8640a47618f1d7d7ad8f279343f54c2b", "MacAddress": "02:42:c0:a9:00:02", "IPv4Address": "192.169.0.2/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ]
[root@kuangshenlinux ~]# docker network inspect bridge [ { "Name": "bridge", "Id": "defce6912c4ae8b16d6f02a6eee0650c79c7d39cba26597de32648f936c0cd43", "Created": "2023-12-12T19:57:25.572880728+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": { "26b67bff513034805ec998da0d36ff3b22eb27d2d5f93709f81adc7cc642d935": { "Name": "web02", "EndpointID": "db5229124ae6aee60f2fadd30c59fa0ec38dbde2a6ea325e50a943af9c97618c", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", "IPv6Address": "" }, // web01 依旧存在 "552223f74f163f94238bf536040aa0c683b1ab0fbfbcabdd1ed28644e40f1b9f": { "Name": "web01", "EndpointID": "d114e6a65bb580713542121454c5e5c9bb3d1151959cf40ec1e2c80e416240bb", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", "IPv6Address": "" } }, "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": {} } ]
连接之后,web01这个容器拥有了两个ip。一个容器是可以有多个ip的。
#通过连接之后,网络就完全可以打通了 [root@kuangshenlinux ~]# docker exec -it web01 ping wen02-net PING wen02-net (192.169.0.3) 56(84) bytes of data. 64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=1 ttl=64 time=0.047 ms 64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=2 ttl=64 time=0.064 ms 64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=3 ttl=64 time=0.140 ms 64 bytes from wen02-net.mynet (192.169.0.3): icmp_seq=4 ttl=64 time=0.069 ms ^C --- wen02-net ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3014ms rtt min/avg/max/mdev = 0.047/0.080/0.140/0.035 ms [root@kuangshenlinux ~]# docker exec -it web02-net ping wen01 Error response from daemon: No such container: web02-net [root@kuangshenlinux ~]# docker exec -it wen02-net ping web01 PING web01 (192.169.0.4) 56(84) bytes of data. 64 bytes from web01.mynet (192.169.0.4): icmp_seq=1 ttl=64 time=0.031 ms 64 bytes from web01.mynet (192.169.0.4): icmp_seq=2 ttl=64 time=0.063 ms 64 bytes from web01.mynet (192.169.0.4): icmp_seq=3 ttl=64 time=0.092 ms ^C --- web01 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2001ms rtt min/avg/max/mdev = 0.031/0.062/0.092/0.024 ms
结论:如果要跨网络操作别人,就需要使用 docker network connect [OPTIONS] NETWORK CONTAINER 连接。