Docker 网络
什么是子网掩码?
用来判断两台计算机的 IP 地址是否属于同一个网络段的判断。如果两台计算机处于同一个网络字段上,则这两台计算机就可以直接进行通信交流。
将计算机的IP地址和子网掩码都转化为二进制,进行AND运算,得出结果相同的话,则说明两台计算机处在同一个网络段,可以直接通信。
IP 地址在设计时就考虑到地址分配的层次特点,将每个 IP地址都分割成网络号和主机号两部分,以便于 IP地址的寻址操作。
IP 地址的网络号和主机号各是多少位呢?如果不指定,就不知道哪些位是网络号、哪些是主机号,这就需要通过子网掩码来实现。
什么是网关?
通常指默认网关,比如通过子网掩码判断出两台计算机处于不同的网络字段,两台计算机就不能直接进行通信,为了能进行通信,这个时候网关就出现了,可以将不同网络频段的两台计算机联系在一起,从而进行通信。
网关实质上是一个网络通向其他网络的IP地址。比如有网络A和网络B,网络A的IP地址范围为“192.168.1.1192.168.1.254”,子网掩码为255.255.255.0;网络B的IP地址范围为“192.168.2.1192.168.2.254”,子网掩码为255.255.255.0。在没有路由器的情况下,两个网络之间是不能进行TCP/IP通信的,即使是两个网络连接在同一台交换机(或集线器)上,TCP/IP协议也会根据子网掩码(255.255.255.0)判定两个网络中的主机处在不同的网络里。而要实现这两个网络之间的通信,则必须通过网关。如果网络A中的主机发现数据包的目标主机不在本地网络中,就把数据包转发给它自己的网关,再由网关转发给网络B的网关,网络B的网关再转发给网络B的某个主机。网络B向网络A转发数据包的过程也是如此 所以说,只有设置好网关的IP地址,TCP/IP协议才能实现不同网络之间的相互通信。那么这个IP地址是哪台机器的IP地址呢?网关的IP地址是具有路由功能的设备的IP地址,具有路由功能的设备有路由器、启用了路由协议的服务器(实质上相当于一台路由器)、代理服务器(也相当于一台路由器)。
一文搞懂网络知识,IP、子网掩码、网关、DNS、端口号 - 知乎 (zhihu.com)
IP地址、子网掩码、网关的概念 - 知乎 (zhihu.com)
vmware虚拟机虚拟网卡作用_岁月的拓荒者的博客-CSDN博客
清空镜像和容器
# 删除所有容器
$ docker rm -f $(docker ps -aq)
# 删除所有镜像
$ docker rmi -f $(docker images -aq)
1、理解 Docker0
【计算机网络】你真的认识 ip addr 命令的输出内容吗?_见见大魔王的博客-CSDN博客
三个网络
Docker 如何处理容器网络访问的?
测试
# 启动一个 Tomcat 容器
[root@localhost /]$ docker run -d -P --name tomcat_01 tomcat:7.0
# 查看容器内部的网络信息 ip addr
# 发现容器启动时会得到一个 eth0@if7 的 IP网卡,docker 分配的!
[root@localhost /]$ docker exec -it tomcat_01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> 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: <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 通这个容器内的 IP (docke0: 172.17.0.1)
[root@localhost /]$ ping -c3 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.068 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.053 ms
原理
Docker 网络模式详解及容器间网络通信 - 知乎 (zhihu.com)
1、Docker就会给新启动的Docker容器分配一个IP,只要安装了Docker就会有一个 Docker0 的虚拟网卡(bridge 网络模式),使用是的 evth-pair 技术!
再次使用 ip addr
命令:发现多了一个 vethd562aef@if6
虚拟网卡。
2、再启动一个容器,发现又多了一对网卡
Docker 守护进程创建了一个虚拟以太网桥 docker0
,新建的容器会自动桥接到这个接口,附加在其上的任何网卡之间都能自动转发数据包。
守护进程会创建一对对等虚拟设备接口 veth pair
,将其中一个接口设置为容器的 eth0
接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似 vethxxx
这样的名字命名。同时,守护进程还会从网桥 docker0
的私有地址空间中分配一个 IP 地址和子网给该容器,并设置 docker0 的 IP 地址为容器的默认网关。
OpenStack,Docker容器之间的连接,OVS的连接,都是使用 eveth-pair 技术的!
3、测试容器 tomcat_01 是否够用 ping 通 tomcat_02
# 可以 ping 通
[root@localhost /]$ docker exec -it tomcat_01 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.201 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.034 ms
4、删除 tomcat_01 容器
只要容器删除后,对应的一对网桥就没了
2、–link
思考一个场景,我们编写一个微服务,数据库连接地址 (datasource=ip:port/xxxx) 是使用 ip 的,如果 ip 变化就连不到了,那我们能不能使用服务名访问呢?实现高可用!
如:jdbc:mysql://mysql:3306,这样的话哪怕 mysql 重启,我们也不需要修改配置了!docker提供了 --link的操作!
(springcloud feign 通过服务名调用)
这种方式官方已不推荐使用,并且在未来版本可能会被移除 Legacy container links | Docker Documentation
docker run --link
可以用来连接两个容器,使得源容器(被链接的容器)和接收容器(主动去链接的容器)之间可以互相通信,并且接收容器可以获取源容器的一些数据,如源容器的环境变量。
[root@localhost ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d219082f82b7 tomcat:7.0 "catalina.sh run" 32 seconds ago Up 28 seconds 0.0.0.0:49153->8080/tcp tomcat_01
eac028266f7a tomcat:7.0 "catalina.sh run" 4 days ago Up 2 seconds 0.0.0.0:49154->8080/tcp tomcat_02
[root@localhost ~]$ docker exec -it tomcat_02 ping tomcat_01
ping: tomcat_01: No address associated with hostname
# 如何解决
[root@localhost ~]$ docker run -d -P --name tomcat_03 --link tomcat_02 tomcat:7.0
b887a2fe4fae5e968ed3aa7cca3e2ee28a46e529fc7a5677a1ccb73433aba1d4
[root@localhost ~]$ docker exec -it tomcat_03 ping tomcat_02
PING tomcat_02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat_02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.130 ms
64 bytes from tomcat_02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.141 ms
# 反向不能 ping 通
[root@localhost ~]$ docker exec -it tomcat_02 ping tomcat_03
ping: tomcat_03: No address associated with hostname
docker network
[root@localhost ~]$ 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@localhost ~]$ docker network ls
NETWORK ID NAME DRIVER SCOPE
6563b3632046 bridge bridge local # docker0
7c554362cbe4 host host local
8bfc4929b49e none null local
[root@localhost ~]$ docker network inspect 6563b3632046
[
{
"Name": "bridge",
"Id": "6563b3632046a5e5c450beb51bb2809729729acd10df165e1525795fc78c8c9d",
"Created": "2022-07-13T21:36:06.791064532+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": {
"b887a2fe4fae5e968ed3aa7cca3e2ee28a46e529fc7a5677a1ccb73433aba1d4": {
"Name": "tomcat_03",
"EndpointID": "7756d3303230523f56ee475c70386a6df2a2460383f134c1dd48dfd6cd915e2a",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
},
"d219082f82b7c6e4a15661911263edbef83ee38966313ac8a888209aa71d293f": {
"Name": "tomcat_01",
"EndpointID": "1491bdebda43b92c4b82fb5d5683af937dca60a8343fb0f28a3f8ae947327dc6",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"eac028266f7a89bc1b013ddce9900015f24bc710df6e1bbc30325bb0292d137f": {
"Name": "tomcat_02",
"EndpointID": "eb4efed4bad97c379f394f3f0aa73140184ff9fbd512df5de0876965ccc51f8f",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/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": {}
}
]
docker inspect
其实tomcat03就是在本地配置了tomcat02的配置
[root@localhost ~]$ docker inspect tomcat_03 | grep Links -C 10
.....
"Links": [
"/tomcat_02:/tomcat_03/tomcat_02"
],
.....
查看 tomcat_03 下 host 配置文件:
[root@localhost ~]$ docker exec -it tomcat_03 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 tomcat_02 eac028266f7a # 配置了一个 hosts 地址
172.17.0.4 b887a2fe4fae
# --link的时候,直接把需要link的主机的域名和ip直接配置到了hosts文件中
本质: --link 就是我们在 host 文件中增加了一个 172.17.0.3 tomcat_02 eac028266f7a
的配置。
不建议使用原因
docker0问题:不支持容器名连接访问!
3、Docker 网络模式
查看所有的docker网络
# docker network --help
docker network ls
3.1、网络模式
网络模式 | 配置 | 说明 |
---|---|---|
bridge模式 | –net=bridge | 为每一个容器分配、设置IP等,并将容器连接到一个 docker0 虚拟网桥。(默认模式) |
none模式 | –net=none | 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接,IP等。 |
container模式 | –net=container:name/id | 新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。 |
host模式 | –net=host | 容器将不会虚拟出自己的网卡,配置自己的P等,而是使用宿主机的 IP和端口。 |
用户自定义 | –net=自定义网络 | 用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定义的网络(一般用bridge模式) |
1)bridge 网络模式
在该模式中,Docker 守护进程创建了一个虚拟以太网桥 docker0
,新建的容器会自动桥接到这个接口,附加在其上的任何网卡之间都能自动转发数据包。
2)host 网络模式
- 采用 host 网络模式的 Docker Container,可以直接使用宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换;
- host 网络模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性。
3)none 网络模式
none 网络模式即不为 Docker Container 创建任何的网络环境,容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源。
4)container 网络模式
处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用 localhost 高效快速通信。
Container 网络模式即新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样两个容器除了网络方面相同之外,其他的如文件系统、进程列表等还是隔离的。
5)自定义网络
虽然 Docker 提供的默认网络使用比较简单,但是为了保证各容器中应用的安全性,在实际开发中更推荐使用自定义的网络进行容器管理,以及启用容器名称到 IP 地址的自动 DNS 解析。
从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过容器名称通信。方法很简单,只要在创建容器时使用 --name
为容器命名即可。
但是使用 Docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。
4、自定义网络
# 删除所有容器
[root@localhost ~]$ docker rm -f $(docker ps -aq)
# 不配置网络时,也就相当于使用默认值: --net bridge 使用的是 docker0
[root@localhost ~]$ docker run -d -P --name tomcat_01 --net bridge tomcat:7.0
# docker0 网络的特点:默认的、域名访问不通、--link 打通连接
自定义网络测试
[root@localhost ~]$ docker network create --help
Usage: docker network create [OPTIONS] NETWORK
Create a network
Options:
--attachable Enable manual container attachment
--aux-address map Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
--config-from string The network from which to copy the configuration
--config-only Create a configuration only network
-d, --driver string Driver to manage the Network (default "bridge")
--gateway strings IPv4 or IPv6 Gateway for the master subnet
--ingress Create swarm routing-mesh network
--internal Restrict external access to the network
--ip-range strings Allocate container ip from a sub-range
--ipam-driver string IP Address Management Driver (default "default")
--ipam-opt map Set IPAM driver specific options (default map[])
--ipv6 Enable IPv6 networking
--label list Set metadata on a network
-o, --opt map Set driver specific options (default map[])
--scope string Control the network's scope
--subnet strings Subnet in CIDR format that represents a network segment
自定义创建一个网络:
# 自定义创建一个网络
# --driver bridge 桥接模式
# --subnet 192.168.0.0/16 子网
# --gateway 192.168.0.1 网关
[root@localhost ~]$ docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
ec7457772ed8fde0da37b31d6108e34e2ed38633f3c90fe2a33d7eadb947c0b0
[root@localhost ~]$ docker network ls
NETWORK ID NAME DRIVER SCOPE
6563b3632046 bridge bridge local
7c554362cbe4 host host local
ec7457772ed8 mynet bridge local
8bfc4929b49e none null local
# 查看自己创建的网络信息
[root@localhost ~]$ docker network inspect mynet
[
{
"Name": "mynet",
"Id": "ec7457772ed8fde0da37b31d6108e34e2ed38633f3c90fe2a33d7eadb947c0b0",
"Created": "2022-07-13T23:21:35.730196203+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-net-01 --net mynet tomcat:7.0
e78f5e6d47285c1bcee60b7e4ab6eff6b8e093f7e53233599108e89bc9adc1a5
[root@localhost ~]$ docker run -d -P --name tomcat-net-02 --net mynet tomcat:7.0
2433c5af82baa0b149a98a688f32c9345acd97cfaa85d91d3e13547aeec74a54
# 再次查看自己创建的网络信息
[root@localhost ~]$ docker network inspect mynet
默认时是ping不通容器名的,使用自定义网络再来测试能否ping通容器:
[root@localhost ~]$ docker exec -it tomcat-net-01 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=0.156 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.064 ms
# 现在不使用 --link 也能 ping 通容器名了
[root@localhost ~]$ docker exec -it tomcat-net-01 ping tomcat-net-02
PING 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.152 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.061 ms
总结
我们自定义的网络docker都已经帮我们维护好了对应的关系。所以我们平时这样使用网络,不使用 –-link
也能使用容器名 ping 通.
好处: 不同的集群使用不同网段的网络,保证集群是安全和健康的!如redis集群、mysql集群等。
5、网络连通
测试
[root@localhost ~]$ docker run -d -P --name tomcat-01 tomcat:7.0
04f6ce534f7e07d82149c58b04ee3f2b05d98ccd34e02eb29337c6194fa50bc5
[root@localhost ~]$ docker run -d -P --name tomcat-02 tomcat:7.0
797f01a03d11acf8301d16af562704480c8496dd0610678d79cb33ae5e92c4ce
# 查看容器
[root@localhost ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
797f01a03d11 tomcat:7.0 "catalina.sh run" 3 minutes ago Up 3 minutes 0.0.0.0:49160->8080/tcp tomcat-02
04f6ce534f7e tomcat:7.0 "catalina.sh run" 3 minutes ago Up 3 minutes 0.0.0.0:49159->8080/tcp tomcat-01
2433c5af82ba tomcat:7.0 "catalina.sh run" 23 minutes ago Up 23 minutes 0.0.0.0:49158->8080/tcp tomcat-net-02
e78f5e6d4728 tomcat:7.0 "catalina.sh run" 23 minutes ago Up 23 minutes 0.0.0.0:49157->8080/tcp tomcat-net-01
ping 不通:
[root@localhost ~]$ docker exec -it tomcat-01 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
命令
[root@localhost ~]$ docker network --help
Usage: docker network COMMAND
Commands:
connect Connect a container to a network
[root@localhost ~]$ docker network connect --help
Usage: docker network connect [OPTIONS] NETWORK CONTAINER
Connect a container to a network
Options:
--alias strings Add network-scoped alias for the container
--driver-opt strings driver options for the network
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--link list Add link to another container
--link-local-ip strings Add a link-local address for the container
测试 : 打通 tomcat-01
到 mynet
[root@localhost ~]$ docker network connect mynet tomcat-01
[root@localhost ~]$ docker network inspect mynet
# 连通之后就是将 tomcat-01 放到了 mynet 之下
# 一个容器两个ip地址,类似于阿里云服务一个公网ip,一个私网ip
测试能否 ping 通:
# tomcat-01 可以ping通
[root@localhost ~]$ docker exec -it tomcat-01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.285 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.060 ms
# tomcat-02 ping不通
[root@localhost ~]$ docker exec -it tomcat-02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
结论:如果要跨网络操作别人,就需要使用 docker network connect [OPTIONS] NETWORK CONTAINER
连通!