学习自b站狂神说Docker: https://www.bilibili.com/video/BV1og4y1q7M4/?spm_id_from=333.337.search-card.all.click
Docker网络
原理
- 每启动一个容器,docker就会给容器分配一个地址,只要安装docker就会有一个默认网卡docker0(桥接模式),使用的技术是evth-pair技术
- 容器带来的网卡都是一对的,evth-pair就是一对虚拟设备接口,成对出现,一端连着协议,一端彼此相连(利用他充当桥梁,连接各种虚拟网络设备)
- 容器需要重复下载操作,可commit做一个自己的镜像(省去下载)
测试
# 获取ip地址 lo是本地回环地址 eth0是阿里云的内网地址 Docker0是Docker生成的地址(路由器)172.17.0.1
[root@localhost ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
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: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:83:43:d8 brd ff:ff:ff:ff:ff:ff
inet 192.168.44.128/24 brd 192.168.44.255 scope global ens32
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe83:43d8/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:6a:af:7b:cc 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
# 三种网络代表三种不同的环境
实现容器间的访问
# 查看容器内部的网络地址
[root@localhost ~]# docker run -d -P --name tomcat01 tomcat
#tomcat容器可能没有ip addr命令 需进入容器手动安装
root@2e1f28f3c6d5:/usr/local/tomcat# apt update #更新apt依赖
root@2e1f28f3c6d5:/usr/local/tomcat# apt install -y iproute2 #安装ipaddr
root@2e1f28f3c6d5:/usr/local/tomcat# apt install -y net-tools #安装ifconfig
root@2e1f28f3c6d5:/usr/local/tomcat# apt install -y iputils-ping #安装ping
# 启动tomcat不进命令行看ip(精简命令) ip addr 容器启动会获得docker分配的ip地址 eth0@if9
[root@localhost ~]# docker exec -it tomcat1 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
8: eth0@if9: <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
# linux可以ping通容器内部 eth0@if9 172.17.0.2
[root@localhost ~]# 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.092 ms
# 启动容器后,再次执行ip addr会发现多出一个网卡 容器 8: eth0@if9 网卡 9: veth86be480@if8
[root@localhost ~]# ip addr
//......
9: veth86be480@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 8e:44:40:04:e1:b3 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::8c44:40ff:fe04:e1b3/64 scope link
valid_lft forever preferred_lft forever
# 再启动一个容器测试,每启动一个容器,网卡就多一对 容器内也增加了 12: eth0@if13:
[root@localhost ~]# ip addr
//......
13: veth2a0e0b8@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 0e:dd:58:44:0b:5e brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::cdd:58ff:fe44:b5e/64 scope link
valid_lft forever preferred_lft forever
# 在容器1可以ping通容器2
[root@localhost ~]# docker exec -it tomcat2 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
12: eth0@if13: <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@localhost ~]# docker exec -it tomcat1 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=35.1 ms
结论:容器1和2是公用的一个路由器(docker0),所有的容器不指定网络的情况下都是docker0,docker会给我们的容器分配一个默认的可用ip(有65535个)
小结
Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥docker0,核心是使用了Linux的虚拟化网络技术,在容器内和docker0分别创建了虚拟网卡,通过evth-pair进行连接,Docker中所有的网络接口都是虚拟的(虚拟的网络效率高,类似内网传递)
若删除一个容器
# 删除容器的同时对应的一对网卡也会被删除
[root@localhost ~]# docker rm -f tomcat1
[root@localhost ~]# ip addr
docker每次启动会重新分配ip,ip会崩但服务名不变,服务名不变,项目就不需要重启,(数据库会宕机重启后IP就换掉了)需要做到通过名字访问容器,完成高可用。
–link
# 两个容器之间直接通过服务名ping不通(可解决)
[root@localhost ~]# docker exec -it tomcat1 ping tomcat2
ping: tomcat2: Name or service not known
# --link可实现 以服务名完成网络通信
[root@localhost ~]# docker run -d -P --name tomcat3 --link tomcat2 tomcat
# 3可ping通2,但2不能ping3(反向不通)
[root@localhost ~]# docker exec -it tomcat3 ping tomcat2
PING tomcat2 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat2 (172.17.0.3): icmp_seq=1 ttl=64 time=0.054 ms
[root@localhost ~]# docker exec -it tomcat2 ping tomcat3
ping: tomcat3: Name or service not known
# 查看当前网络配置(bridge是docker0)
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
503e09d0e453 bridge bridge local
22f671f332f6 host host local
5f4d28c03a21 none null local
# 查看对应网卡的具体信息,启动服务,不指定ip,就会随机分配一个ip
[root@localhost ~]# docker network inspect 503e09d0e453
[
{
"Name": "bridge",
"Id": "503e09d0e4539a7a786e67516e80c5de902b1ce90bdec51002f008304de6891c",
"Created": "2023-10-24T09:03:06.242436289+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" Docker0
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": { 启动的容器
"19a1a4b71bc42464865e6d67274527d5ae8fcaa0ad7fa293e146c88ec4e9fe68": {
"Name": "tomcat3",
"EndpointID": "5fd50887709fec04a7e5501c19b8d6bb6898c4ff4c8faf03e7b6b125fd3a6f82",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
},
"4200b69eb015a7503699eede4f4dd8c564b49136a73804da5cd516862f04e29d": {
"Name": "tomcat2",
"EndpointID": "6b29c3d57349dffcaed1c9bec1671d8923991b7e35a085840b29052011ac68f9",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"76342dafbaa1702a9d8b8ee5ab9444ccdf59f0328f2e33e1deca97451f2dc4b5": {
"Name": "tomcat1",
"EndpointID": "d70da230988aa9e961d835cd7e397a8a7feaa872aac499aec0c413dbe5a94fc3",
"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": {}
}
]
# 查看tomcat2的详细信息
[root@localhost ~]# docker inspect 4200b69eb015
//......
"NetworkSettings": { 网络设置
"Bridge": "",
"SandboxID": "f089fd4fff3bd78be835064252c0743204387eb4c62ac2bb6ebba9c36f2aa265",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"8080/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "32768"
},
{
"HostIp": "::",
"HostPort": "32768"
}
]
},
//......
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "503e09d0e4539a7a786e67516e80c5de902b1ce90bdec51002f008304de6891c",
"EndpointID": "6b29c3d57349dffcaed1c9bec1671d8923991b7e35a085840b29052011ac68f9",
"Gateway": "172.17.0.1", 网关
"IPAddress": "172.17.0.3", ip地址
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
# 原理其实是容器3在本地配置了容器2的配置,进入容器查看,linux下/etc/hosts文件是配置本地绑定的(破解软件,若配置了 127.0.0.1 www.baidu.com则请求百度会走到127)
[root@localhost ~]# docker exec -it tomcat3 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 tomcat2 4200b69eb015 #容器内写死,访问容器2,走到172.17.0.3
172.17.0.4 19a1a4b71bc4
–link在hosts配置中增加了一个映射172.17.0.3 tomcat2 4200b69eb015(单向的,需两边都配置),目前不建议使用了,有局限性
docker0不支持容器名连接访问,域名不能访问,–link可以打通连接(网络默认就是他)
自定义网络-容器互联
# 移除网卡
[root@localhost ~]# docker network rm mynet
# 查看所有的docker网络
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
503e09d0e453 bridge bridge local
22f671f332f6 host host local
5f4d28c03a21 none null local
# 网络模式
bridge:桥接模式(默认,自己创建也用这个)(1,2不能直接访问,但1可以通过3访问2)
none:不配置网络
host:和宿主机共享网络
container:容器网络连通(用得少)(直接互联但局限性很大)
测试
# 通过docker network --help命令查看帮助文档
#直接启动的命令有默认的隐藏项--net bridge,这个就是docker0(bridge是他的名字)
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
# 通过create创建自定义网络,桥接模式,子网掩码,网关(从哪里出去),名字
# --driver bridge 默认,不写也是他
# --subnet 192.168.0.0/16 是192.168.0.2到192.168.255.255
# --gateway 192.168.0.1 网关 从这出去
[root@localhost ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
41fd8e2a01d879385326e021f32a0aadfe3bb4ca5afb15b534895d4257e7ab9d
# 查看创建的网络
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
503e09d0e453 bridge bridge local
22f671f332f6 host host local
41fd8e2a01d8 mynet bridge local
5f4d28c03a21 none null local
# 查看网络详细信息
[root@localhost ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "41fd8e2a01d879385326e021f32a0aadfe3bb4ca5afb15b534895d4257e7ab9d",
"Created": "2023-10-24T10:40:57.415257632+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@localhost ~]# docker run -d -P --name tomcat-net01 --net mynet tomcat2:1.0
ae072824e82d4718c678cdf65d4500b9e0c5e5ca01a986f46d05d31744898aa1
[root@localhost ~]# docker run -d -P --name tomcat-net02 --net mynet tomcat2:1.0
ee998de82b55e24497d4c531a2788e3ca0c268acf7a3582ea941970e35d7bd10
# 网络内创建容器后的具体信息,是我们预先分配的ip
[root@localhost ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "41fd8e2a01d879385326e021f32a0aadfe3bb4ca5afb15b534895d4257e7ab9d",
"Created": "2023-10-24T10:40:57.415257632+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": { 出现了我们创建的容器
"ae072824e82d4718c678cdf65d4500b9e0c5e5ca01a986f46d05d31744898aa1": {
"Name": "tomcat-net01",
"EndpointID": "64c71d020f0d40b0229d71eeec8054e73652073d0418d045545e8f7c8bb85642",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
"ee998de82b55e24497d4c531a2788e3ca0c268acf7a3582ea941970e35d7bd10": {
"Name": "tomcat-net02",
"EndpointID": "e452021914e0c10e0243aa1a7bf4289791be6a89b46f0a7eec5bc42857e2fd49",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
# 自定义网络容器不配置--link也可以ping通(ip和服务名),docker0的缺点被修复
[root@localhost ~]# docker exec -it tomcat-net01 ping 192.168.0.3
PING 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=6.87 ms
[root@localhost ~]# docker exec -it tomcat-net01 ping tomcat-net02
PING tomcat-net02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.097 ms
自定义网络docker已经维护好对应的关系,推荐使用。
好处:不同的网络间是隔离的(有自己的子网),互不影响(可以打通)
redis集群与mysql集群-不同的集群使用不同的网络,保证集群是安全和健康的
网络连通-跨网络操作
# 不同网络的容器间不能够直接ping通(192.168.0.3与172.17.0.3)
[root@localhost ~]# docker run -d -P --name tomcat05 tomcat2:1.0
476d764c4f0429482c10aa353aa01ecd05ecccac8f16d9bd48c76092dc6427d5
[root@localhost ~]# docker exec -it tomcat05 ping tomcat-net01
ping: tomcat-net01: Name or service not known
# docker network connect 打通tomcat05-mynet
# 连通就是将tomcat05放到了mynet网络下(一个容器2个ip)
[root@localhost ~]# docker network connect mynet tomcat05
[root@localhost ~]# docker network inspect mynet
//......
"Containers": {
"476d764c4f0429482c10aa353aa01ecd05ecccac8f16d9bd48c76092dc6427d5": {
"Name": "tomcat05", 容器05放到了mynet网络中
"EndpointID": "6bfb6ba5241b0a1c23cbc80352f178c87241eb8610cb15868acc0d87bca89cef",
"MacAddress": "02:42:c0:a8:00:04",
"IPv4Address": "192.168.0.4/16",
"IPv6Address": ""
},
"ae072824e82d4718c678cdf65d4500b9e0c5e5ca01a986f46d05d31744898aa1": {
"Name": "tomcat-net01",
"EndpointID": "64c71d020f0d40b0229d71eeec8054e73652073d0418d045545e8f7c8bb85642",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
"ee998de82b55e24497d4c531a2788e3ca0c268acf7a3582ea941970e35d7bd10": {
"Name": "tomcat-net02",
"EndpointID": "e452021914e0c10e0243aa1a7bf4289791be6a89b46f0a7eec5bc42857e2fd49",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
//......
]
# 再次尝试ping操作,可以ping通,但05同网络下的其他容器是不通的
[root@localhost ~]# docker exec -it tomcat05 ping tomcat-net01
PING tomcat-net01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.116 ms