Docker网络

定义:Docker网络是Docker提供的一种用于在容器和容器之间、容器和外部网络之间提供网络功能的方式。Docker网络提供了容器间的安全、私有通信。

功能:容器间的互联和通信以及端口映射,容器IP变动时候可以通过服务名直接网络通信而不受到影响。

基本命令

1
2
3
4
5
6
7
8
Commands:
connect Connect a container to a network #链接容器到指定网络
create Create a network #创建一个docker网络
disconnect Disconnect a container from a network #从某个网络中将指定容器移除
inspect Display detailed information on one or more networks #显示某个网络的详细信息
ls List networks #显示已经存在的docker网络
prune Remove all unused networks #移除掉未使用的网络
rm Remove one or more networks #移除某个或多个指定的网络

上述的部分命令包含子命令。可以通过–help查看

网络模式

通过使用docker network ls可以看到docker自动创建的三个网络分别是一下:

1
2
3
4
bridge模式:使用--network  bridge指定,默认使用docker0
host模式:使用--network host指定
none模式:使用--network none指定
container模式:使用--network container:NAME或者容器ID指定 #该模式不是docker创建的需要自己指定。

bridge模式:为每个容器分配和设置IP等,并将容器链接到docker0的虚拟网桥上。

host模式:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。

none模式:容器有独立的 Network namespace,但并没有对其进行任何网络设置,如分配 veth pair 和网桥连接,IP 等。几乎不使用这个。

container模式:新建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP,端口范围等。

用的最多的就是bridge和host两种网络模式,在创建docker网络时默认模式是bridge模式。

docker容器内部的IP有可能是会发生变动的。

案例说明

本章案例均使用typecho镜像来说明网络的各个模式,也可以使用别的镜像,只是恰巧在本地有一个typecho的镜像。

bridge模式

概述

Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。

1
2
3
4
5
6
7
8
[root@localhost ~]# docker network inspect ed17f204c15f | grep bridge
"Name": "bridge",
"Driver": "bridge",
"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"

1、Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

2、docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址

3、网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。

  • 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
  • 每个容器实例内部也有一块网卡,每个接口叫eth0;
  • docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。

通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。

image-20250126171338154

案例

启动一个typecho的容器实例名为typecho-network-bridege.

在宿主机上ip addr来查看网络信息,可以看到如下信息,这是因为启动了一个typecho的docker容器示例,他的网络模式就是bridge模式。

image-20250126163040695

进入到typecho容器示例内部查看网络情况如下。

image-20250126163146075

可以看出docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。

host模式

概述

直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。

容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。

image-20250126170923629

案例

重新启动一个typecho的容器实例名为typecho-network-host.

1
2
3
4
5
6
docker run -d \
--name=typecho-network-host \
--network host \
-e PHP_TZ=Asia/Shanghai \
-e PHP_MAX_EXECUTION_TIME=600 \
-p 80:80 80x86/typecho:latest

当执行完毕使会出现以下waring

WARNING: Published ports are discarded when using host network mode

这是因为在host模式下,使用的是宿主机的网络配置信息,不需要在指定端口映射。

通过inspect来查看容器的网络信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@localhost ~]# docker inspect typecho-network-host | tail -n 20
"host": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"MacAddress": "",
"NetworkID": "42171acac1d2c2f82078b43c5831b55097c9e05866efa09b434465619fff667d",
"EndpointID": "dd109dbcbd74ff5c8883f680eed40562389975e76c72b6c26a93cfb7806a5344",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DriverOpts": null,
"DNSNames": null
}
}
}
}
]

进入容器内部查看网络信息,可以发现,容器的网络信息和本地的信息一致。

此处由于网络信息较长,省略。

http://宿主机IP:80/

在CentOS里面用默认的火狐浏览器访问容器内的typecho服务看到访问成功,因为此时容器的IP借用主机的,所以容器共享宿主机网络IP,这样的好处是外部主机与容器可以直接通信。

none模式

该模式使用的很少。

概述

在none模式下,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo需要我们自己为Docker容器添加网卡、配置IP等。

禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)

案例

以none模式启动一个typecho容器实例,实例名称为typecho-network-none.

1
2
3
4
5
6
docker run -d \
--name=typecho-network-none \
--network none \
-e PHP_TZ=Asia/Shanghai \
-e PHP_MAX_EXECUTION_TIME=600 \
-p 80:80 80x86/typecho:latest

在容器外部查看容器的网络信息如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@localhost ~]# docker inspect typecho-network-none | tail -n 20
"none": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"MacAddress": "",
"NetworkID": "7de51d8a81dd5910dedcc7c7bb79b79172f71097f3c66e812bb4d81d65f7fc7c",
"EndpointID": "951841256eb35c74e6d0bf82da2e3fcaf4f13acf1fe899d1e0cc5b8c0e8ed6ff",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DriverOpts": null,
"DNSNames": null
}
}
}
}
]

进入容器实例内部查看网络信息,可以看到容器的网络就只有一个lo。

1
2
3
4
5
6
7
8
[root@localhost ~]# docker exec -it typecho-network-none /bin/sh
/app # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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

container模式

概述

新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。

image-20250127105346005

案例

本案例使用ubuntu的镜像演示,由于typecho镜像在启动两个容器实例的时候会导致端口冲突。

以bridge模式启动一个ubuntu容器实例,实例名称为ubuntu-o。执行以下命令会打开一个连接ubuntu-o容器的伪终端。不要关闭。

1
docker run -it --name=ubuntu-o  ubuntu:latest /bin/bash

A:查看ubuntu-o容器的网络信息,在连接ubuntu-o的伪终端中,输入ip addr命令发现无法找到命令。执行以下命令

1
2
apt-get update
apt-get install -y iproute2

在伪终端中输入ip addr内容如下。

以下内容会根据你的系统变化。

1
2
3
4
5
6
7
8
9
10
11
root@d184d4bdf3d1:/# 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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
14: eth0@if15: <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

再启动一个ubuntu容器实例,实例名字为ubuntu-w,使用container网络模式,ubuntu-o和实例共享网络信息。执行以下命令会打开一个连接ubuntu-w容器的伪终端。不要关闭。

1
docker run -it --name=ubuntu-w --network container:ubuntu-o  ubuntu:latest /bin/bash

查看容器是否成功启动

1
2
3
4
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3bee535ca29b ubuntu:latest "/bin/bash" 9 seconds ago Up 8 seconds ubuntu-w
d184d4bdf3d1 ubuntu:latest "/bin/bash" 7 minutes ago Up 7 minutes ubuntu-o

在ubuntu-w伪终端界面查看网络信息,若出现上无法找到命令的话就执行A处的步骤。ubuntu-w容器的网络信息如下

1
2
3
4
5
6
7
8
9
10
11
root@d184d4bdf3d1:/# 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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
14: eth0@if15: <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

会发现ubuntu-w的网络信息和ubuntu-o的一样,是因为,ubuntu-w共享了ubuntu-o的网络。

若ubuntu-o容器实例停止运行,ubuntu-w的网络将丢失共享的网络配置剩下本地网络的回环地址配置信息。

自定义网络

概述

允许自定义容器之间的网络通信规则。自定义网络可以帮助你更好地控制容器的网络环境,例如隔离网络、创建私有网络等。

由于bridge模式在容器重启时可能会导致容器的网络配置IP信息发生变化,所以自定义网络可以使网络内的容器直接使用服务名通信。就解决了容器重启发生IP变化的问题。

案例

本案例只演示使用自定义网络后,网络内的容器可以直接调用的情况,由于不使用自定义网络只能通过IP通信这里不演示。

本案例同样使用ubuntu的镜像。

创建一个自定义的docker网络,网络名字为docker-study-network-custom,命令如下

1
2
3
4
5
6
7
8
9
[root@localhost ~]# docker network create docker-study-network-custom
eea315734dc40c83f9c1d39fb0272f7a82d8be7db461cc7eb89fd5fe5ba5712f
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
71eeefc97021 blinko-network bridge local
ed17f204c15f bridge bridge local
eea315734dc4 docker-study-network-custom bridge local
42171acac1d2 host host local
7de51d8a81dd none null local

创建两个ubuntu的实例,实例名分别为ubuntu-1,ubuntu-2。

1
2
docker run -it --name=ubuntu-1 --network  docker-study-network-custom  ubuntu:latest /bin/bash
docker run -it --name=ubuntu-2 --network docker-study-network-custom ubuntu:latest /bin/bash

在ubuntu-2内ping ubuntu-1。

若提示ping命令不存在,在ubuntu-2的容器内执行以下命令

apt-get update

apt-get install iputils-ping

1
2
3
4
5
6
7
8
9
root@1631df68cf4d:/# ping ubuntu-1
PING ubuntu-1 (172.19.0.2) 56(84) bytes of data.
64 bytes from ubuntu-1.docker-study-network-custom (172.19.0.2): icmp_seq=1 ttl=64 time=0.075 ms
64 bytes from ubuntu-1.docker-study-network-custom (172.19.0.2): icmp_seq=2 ttl=64 time=0.108 ms
64 bytes from ubuntu-1.docker-study-network-custom (172.19.0.2): icmp_seq=3 ttl=64 time=0.045 ms
^C
--- ubuntu-1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 0.045/0.076/0.108/0.025 ms

同样也可以直接ping ip地址。但是容器重启IP可能会发生变化,所以自定义网络解决了容器重启发生IP变化容器连通的问题。