Docker 网络详解(十一)
这篇文章介绍了Docker网络的五种类型:基础网络类型(bridge、host和none)和由基础网络类型派生的网络类型(container和custom)。网络命名空间是Linux内核提供的一种用于隔离不同容器间网络资源的重要功能。veth-pair则用于解决不同网络命名空间之间的通信,它是一种虚拟网络设备对,就像两块有网线连接的网卡。Docker使用虚拟网络设备对来实现不同容器间的通信。
docker安装并启动服务后,会在宿主机中添加一个虚拟网卡。 在Docker服务启动前,使用
ifconfig
或ip addr
查看网卡信息:
• lo
:本机回环网络网卡
使用 systemctl start docker
启动Docker服务后,会多出一个 docker0
网卡。
Docker容器的网络隔离,是通过Linux内核特性 namespace
和 cgroup
实现的。
Docker 基础网络类型一共有三种(bridge
、host
和 none
),还有两种由基础网络类型派生的网络类型(container
和 custom
)。本文详细讲解这五种网络类型。
查看 docker 网络:
bash[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
b3f041e614ec bridge bridge local
d039b1004b4b host host local
8f512acdd2f6 none null local
网络模式说明:
网络模式 | 配置 | 说明 |
---|---|---|
host | --network=host | 容器不会创建自己的网卡,配置 IP 等,而是使用宿主机的 IP 和端口 |
none | --network=none | 容器关闭网络功能,不进行任何网路设置 |
bridge | --network=bridge | 为每个容器分配 IP 。并将容器连接到 docker0 虚拟网桥上,这种模式是默认模式 |
container | --network=container | 容器不会创建自己的网卡和IP,而是和一个指定的容器共享 IP 和端口 |
custom | --network=new_bridge | 为每个容器分配 IP 。并将容器连接到自定义的虚拟网桥上 |
操作 | 命令 | 描述 |
---|---|---|
添加 Docker 网络 | docker network create xxx | 添加名为 xxx 的网络 |
删除 Docker 网络 | docker network rm xxx | 删除名为 xxx 的网络 |
查看网络元数据 | docker network inspect xxx | 查看名为 xxx 的网络信息 |
删除所有无效的网络 | docker network prune | 删除所有无效的网络 |
Network Namespace 是 linux 内核提供的用于实现网络虚拟化的重要功能,是 Linux 内核用来隔离不同容器间的网络资源(每个 Docker 容器都拥有一个独立的网络命名空间),网络命名空间主要隔离的资源包括:
网络空间结构如下图所示,当系统中拥有 2 个网络命名空间:
由于不同的网络命名空间之间是相互隔离的,所以不同的网络命名空间之间并不能直接通信。 就好比两台电脑,如果没有任何网线连接,它们之间是不能通信的。所以,Linux 内核提供了 虚拟网络设备对(veth) 这个功能,用于解决不同网络命名空间之间的通信。
虚拟网络设备对(veth-pair)用于解决不同网络命名空间之间的通信,可以将其看成是两块有网线连接的网卡。只要将其中一块网卡放置到网络命名空间A,另外一块网卡放置到网络命名空间B,那么两个不同的网络命名空间就能够通信,如下图所示:
如上图所示,veth0 与 veth1 组成一个虚拟网络设备对。虚拟网络设备对就像管道一样,只要向其中一端发送数据,就可以从另外一端接收到数据。
Docker 就是使用 虚拟网络设备对 来实现不同容器之间的通信,其原理如下图:
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。
Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
查看 docker0 网桥:
bash# 查看 bridge 所有信息
docker network inspect bridge
# 查看 bridge com.docker.network.bridge.name": "docker0" 的名称
docker network inspect bridge | grep name
#查看所有网络接口信息
ip a
查看 docker0 详细:
bash[root@VM-8-17-centos ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "b3f041e614ec48f5ffabb446a425f905ac689c7c8bd70fe4f4802eab5b54cfd2",
"Created": "2023-10-24T00:00:01.550434451+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,
"Containers": {
"4cd859c037b8c925ba1ca6b99918537d30617155a7ba8706b0f4c8bd2b0d2525": {
"Name": "stoic_euler",
"EndpointID": "9752c42f4d838457a46360079c4285ad22c6b61d7ee979188d5a5554bea69e2e",
"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": {}
}
]
查看连接到 docker0 的虚拟网络设备对(veth-pair):
bash[root@VM-8-17-centos ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02429137dd65 no veth348e53d
注意:每启动一个容器,就会生成一个 veth-pair 。
如果没有 brctl 这个命令,可以通过以下命令进行安装:
bashyum install -y bridge-utils
在 host 模式下,容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。
结构如下图所示:
查看该网络模式配置:
bash[root@VM-8-17-centos ~]# docker network inspect host
[
{
"Name": "host",
"Id": "d039b1004b4b2695c40287b25da6f6d8b4d91e7ae42b54920a7559826fa5263a",
"Created": "2023-08-31T08:36:22.077011441+08:00",
"Scope": "local",
"Driver": "host",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": []
},
"Internal": false,
"Attachable": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过–network=none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。
结构如下图所示:
查看该网络模式配置:
bash[root@VM-8-17-centos ~]# docker network inspect none
[
{
"Name": "none",
"Id": "8f512acdd2f6b6558cd327c2254ce027869dd3aecdf345e3cda1dc6ce39a283c",
"Created": "2023-08-31T08:36:22.070115953+08:00",
"Scope": "local",
"Driver": "null",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": []
},
"Internal": false,
"Attachable": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
Bridge 模式是 docker 的默认网络模式,不写 --network
参数,就是 bridge 网桥模式。
当 Docker 进程启动时,会在主机上创建一个名为 docker0
的虚拟网桥,此主机上启动的Docker容器默认都会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
从 docker0子网中分配一个IP给容器使用,并设置 docker0
的IP地址为容器的默认网关。在主机上创建一对虚拟网卡 veth pair
设备,Docker 将 veth pair
设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以 vethxxx
这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过 brctl show
命令查看。
结构如下图所示:
查看该网络模式配置:
bash[root@VM-8-17-centos ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "b3f041e614ec48f5ffabb446a425f905ac689c7c8bd70fe4f4802eab5b54cfd2",
"Created": "2023-10-24T00:00:01.550434451+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,
"Containers": {
"4cd859c037b8c925ba1ca6b99918537d30617155a7ba8706b0f4c8bd2b0d2525": {
"Name": "stoic_euler",
"EndpointID": "9752c42f4d838457a46360079c4285ad22c6b61d7ee979188d5a5554bea69e2e",
"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": {}
}
]
Container 模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
结构如下图所示:
在以上示例中,Docker 2
容器可以通过--network=container:Docker 1
参数,指定自己的网络和一个容器 Docker 1
共享 IP 和端口。
示例:
bashdocker run -it --name docker1 nginx:latest /bin/bash
# 指定和 docker1 容器共享网络
docker run -it --name docker2 --network=container:docker1 nginx:latest /bin/bash
此时使用 ip addr
查看两台容器的网络,会发现两台容器的eth0
网卡内的IP等信息完全相同。
如果关掉了alpine1
容器,因为alpine2
的网络使用的alpine1
共享网络,所以关掉alpin1
后,alpine2
的eth0
网卡也随之消失了。
Custom 模式用于自定义 docker 网络。
结构如下图所示:
如上图所示,新建自定义网桥 custom ,指定网络(192.168.10.0/24)和网关(192.168.10.1)。
bash# 新建自定义网络
docker network create --driver bridge --subnet 192.168.10.0/24 --gateway 192.168.10.1 Custom
# 查看自定义网络,查看定义网络
docker network ls
NETWORK ID NAME DRIVER SCOPE
994c4bd64f70 bridge bridge local
9eeb43076ad2 host host local
24cd1b0769bd Custom bridge local
ad2da4225045 none null local
# 查看自定义网桥 IP 地址
[root@localhost ~]# ip addr
316: br-24cd1b0769bd: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:cb:b3:6c:a3 brd ff:ff:ff:ff:ff:ff
inet 192.168.10.1/24 brd 192.168.10.255 scope global br-24cd1b0769bd
valid_lft forever preferred_lft forever
在没有使用 connect 命令的情况下,不同网络间的容器是无法进行网络连接的。
如下图所示:container1 和 container2,使用不同的网络,所以无法联通。
bash# 创建容器
docker run -it --name container1 centosjava:latest /bin/bash
# 查看容器 IP
[root@0fa776c5eb80 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.3 netmask 255.255.0.0 broadcast 0.0.0.0
inet6 fe80::42:acff:fe11:3 prefixlen 64 scopeid 0x20<link>
ether 02:42:ac:11:00:03 txqueuelen 0 (Ethernet)
RX packets 23 bytes 1830 (1.7 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 22 bytes 1860 (1.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
bash# 创建容器
docker run -it --name container2 --network Custom centosjava:latest /bin/bash
# 查看容器 IP
[root@a42c80a672cd local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.10.2 netmask 255.255.255.0 broadcast 0.0.0.0
inet6 fe80::42:c0ff:fea8:a02 prefixlen 64 scopeid 0x20<link>
ether 02:42:c0:a8:0a:02 txqueuelen 0 (Ethernet)
RX packets 47 bytes 2950 (2.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 526 bytes 50020 (48.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ping
测试可以
直接 ping容器名
,不需要ping IP地址 因为我们是自定义网络
bash# 容器 container1 ping container2 ,不通
[root@41eea42d9980 /]# ping 192.168.10.2
PING 192.168.10.2 (192.168.10.2) 56(84) bytes of data.
# 容器 container2 ping container1 ,不通
[root@7279af38152a /]# ping 172.17.0.8
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
bashdocker network connect Custom container1 docker network connect bridge container2
bash# 容器 container1 ping container2 ,通
[root@41eea42d9980 /]# ping 192.168.10.2
PING 192.168.10.2 (192.168.10.2) 56(84) bytes of data.
64 bytes from 192.168.10.2: icmp_seq=123 ttl=64 time=0.087 ms
64 bytes from 192.168.10.2: icmp_seq=124 ttl=64 time=0.085 ms
# 容器 container2 ping container1 ,通
[root@7279af38152a /]# 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=229 ttl=64 time=0.090 ms
64 bytes from 172.17.0.3: icmp_seq=230 ttl=64 time=0.077 ms
通过以上实战说明,docker 不同网络之间互联需要使用 connect 命令进行网络发布!!!
本文作者:LiuXueChao
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!