一、docker0 是 Docker 网络的核心
先把环境弄干净,删掉所有容器和镜像再开始,开一台新机器也行:
docker rm -f `docker ps -aq`
docker rmi -f `docker images -aq`
# 这一步不知道为什么把docker的配置也删了,pull加速都拉不了了
# 只能重新配置一下了(更详细的在前面的笔记)
sudo tee /etc/docker/daemon.json <<EOF
{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://mirror.ccs.tencentyun.com",
"https://docker.m.daocloud.io"
]
}
EOF
清干净之后看网卡,一共三块:
ubuntu@VM-0-9-ubuntu:~$ 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 noprefixroute
valid_lft forever preferred_lft forever
# 腾讯云内网地址
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 52:54:00:af:79:fb brd ff:ff:ff:ff:ff:ff
altname enp2s1
altname ens1
inet 172.16.0.9/20 metric 100 brd 172.16.15.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:feaf:79fb/64 scope link
valid_lft forever preferred_lft forever
# docker的网卡
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 62:b1:8b:b3:a1:39 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::60b1:8bff:feb3:a139/64 scope link
valid_lft forever preferred_lft forever
lo 是本机回环,eth0 是云服务器的内网网卡,docker0 才是 Docker 自己的网卡 —— 地址是 172.17.0.1/16,它就是这个内网的网关。
二、容器 IP、veth-pair 和 docker0 转发
随便起一个容器:
docker run -d -P --name tomcat01 tomcat
# 查看容器内部网络地址,直接追加 ip addr 即可
# 之前写镜像就提到可以追加命令
三种查法:
# 方法1:查看 hosts 文件
docker exec tomcat01 cat /etc/hosts
# 方法2:来看内网 IP(缺少命令,看下面的方式安装)
docker exec -it tomcat01 ip addr
root@d84972560009:/usr/local/tomcat# 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
# 容器启动时会得到一个 eth0@if140 地址IP,这是 docker 分配的
2: eth0@if140: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 92:d3:f5:3f:b3:d0 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
# 方法3:用 inspect 从外面看(最准),在network块
docker inspect tomcat01 | grep IPAddress
# 直接 inspect 看
"NetworkSettings": {
"SandboxID": "b0abb8543d11e213fb421d73f85134395b40d1f88c148002525d6a466739ce05",
"SandboxKey": "/var/run/docker/netns/b0abb8543d11",
"Ports": {
"8080/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "32768"
},
{
"HostIp": "::",
"HostPort": "32768"
}
]
},
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"DriverOpts": null,
"GwPriority": 0,
"NetworkID": "d18bbcfbe97438fc79c2ae24c7e92f0d72082b0a7d7e4c6b747e21a1d1d353c8",
"EndpointID": "a8570c4216ea15d1b53ca3b40617f6fb485b9d9cbe1b71ebbad3197efa58aebb",
"Gateway": "172.17.0.1",
# 容器内部地址
"IPAddress": "172.17.0.2",
"MacAddress": "92:d3:f5:3f:b3:d0",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DNSNames": null
}
}
},
注意 -P 是大写,表示随机映射端口,inspect 出来的 HostPort: 32768 就是随机分到的那个。
tomcat 这种精简镜像里默认没有 ip addr,得进去装。按发行版选对应的包管理器:
# 基于 Debian(apt 包管理器)的容器
docker exec -it tomcat01 bash
apt update
apt install iproute2 -y
ip addr
# 基于 CentOS/RHEL(yum 包管理器)的容器
docker exec -it tomcat01 bash
yum install -y iproute
ip addr
# 基于 Alpine(apk 包管理器)的容器
docker exec -it tomcat01 sh
apk add iproute2
ip addr
想 ping 也一样,apt install iputils-ping -y 装完才有:
# 发现 ping 命令没有,安装
apt install iputils-ping -y
# 发现能 ping 通
root@d84972560009:/usr/local/tomcat# 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.021 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.034 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.032 ms
宿主机和容器是通的。那么容器之间能不能通?
每安装一个 docker 容器,docker 就会给容器分配 IP,而 docker 产生的网卡是桥接模式,使用 veth-pair 技术。
再看一次宿主机的网卡,容器的对端也冒出来了:
root@VM-0-9-ubuntu:~# 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 noprefixroute
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 52:54:00:af:79:fb brd ff:ff:ff:ff:ff:ff
altname enp2s1
altname ens1
inet 172.16.0.9/20 metric 100 brd 172.16.15.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:feaf:79fb/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 62:b1:8b:b3:a1:39 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::60b1:8bff:feb3:a139/64 scope link
valid_lft forever preferred_lft forever
140: veth4543c38@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether ce:c1:e7:39:b2:2f brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::ccc1:e7ff:fe39:b22f/64 scope link
valid_lft forever preferred_lft forever
再起一个容器,宿主机上就又多一块:
ip addr
# 又多了一个
140: veth4543c38@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether ce:c1:e7:39:b2:2f brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::ccc1:e7ff:fe39:b22f/64 scope link
valid_lft forever preferred_lft forever
141: vethcc477c1@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 6e:7b:eb:15:4a:97 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::6c7b:ebff:fe15:4a97/64 scope link
valid_lft forever preferred_lft forever
# 看里面
apt update && apt install -y iproute2
root@1fa8ebedc8fb:/usr/local/tomcat# 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
# 这个数字对应容器外面的 141 那块网卡
2: eth0@if141: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 52:bb:99:c3:57:4f 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
# 测试两个tomcat互通
apt install iputils-ping -y
# 用02 ping 01
root@1fa8ebedc8fb:/usr/local/tomcat# 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.062 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.044 ms
通。docker 给容器分配的 IP 都是同网段的,所以容器之间默认互联不用额外配置。
这里的关键是 veth-pair:
- 容器带来的网卡都是一对,容器内是一个
eth0@if[编号],容器外面对应的编号又是一块网卡 - veth-pair 就是一对虚拟设备接口,它们成对出现,一端连着协议栈,一端彼此相连;正因为这个特性,它可以充当桥梁,专门连接虚拟网络设备
- 容器内外的区别就是:容器内的网卡有容器内网的 IPv4 地址,容器外那块只有 IPv6 的 link 地址。只要删掉容器,这一对 veth-pair 就没了

OpenStack、Docker 容器之间连接、OVS 之间,用的都是 veth-pair 技术。
想找到配对的另一头也简单:进容器看 eth0@if141 里 if 后面的数字,对应宿主机上的那块 141: vethcc477c1@if2。
docker0 就像网关、路由器,容器之间不是直连,是 docker0 转发连接的。docker0 是 docker 的网卡,docker 的内网和 Linux 服务器对应的公网是一回事。

分配的 IP 直接看 CIDR 表示法就知道上限了:
172.17.0.3/16
172.17.0.0---172.17.255.255
可分配IP:2^16-2(广播地址和回环地址)
一个网段能塞 6 万多个容器,不用深究,知道大概就行。
往外走的时候靠 NAT:
# NAT 核心作用就是:让多个设备共享一个公网 IP 上网
# 实现:把内网 IP(私有地址)替换成外网 IP(公网地址)
容器A(172.17.0.2)
│
▼
┌───────┐
│docker0│ ← 网桥(只负责内部连接)
└───┬───┘
│
▼
Linux内核路由 + NAT ← 这里做地址转换
│
▼
物理网卡(eth0) ← 带着公网 IP 发出数据
删除容器的时候,一对 veth-pair 会一起消失:
# 删除容器一对veth-pair都会消失
# 查看删除前 tomcat02 的信息
2: eth0@if141: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 52:bb:99:c3:57:4f 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
141: vethcc477c1@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 6e:7b:eb:15:4a:97 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::6c7b:ebff:fe15:4a97/64 scope link
valid_lft forever preferred_lft forever
docker rm -f tomcat02
# 此时少了 02 的一对网卡,只剩 01 的 140 那块
一个小结:
- docker 用桥接方式连接容器,docker0 是网桥,对应外部的物理网卡
- 一个物理网卡可以创建多个虚拟网卡(或虚拟接口),每个虚拟网卡有自己的 IP,共享同一个物理网卡收发数据
- docker 中的所有网络接口都是虚拟的,因为虚拟接口转发效率高,内网传递文件非常快

顺带一个实际的问题:写微服务的时候数据库地址写成 数据库url=ip:端口,IP 一变地址就失效了(docker 每次重启会重新分配 IP)。Spring Cloud 里用服务名(feign 那种写法)就能绕开这个坑,只看服务名不看 IP,数据库 IP 换了也不影响访问。这就是为什么后面要用自定义网络。
三、四种网络模式
docker0 和 veth-pair 是底层原理,实际用的时候是在启动容器时选一种网络模式。它要解决的就是这几件事:容器之间互联通信、宿主机外面能访问进来(端口映射),以及容器 IP 变动的时候还能用服务名找到对方:

1. 三大主流模式
先认模式,日常用得最多的就是 bridge:

指定方式就是在 docker run 的时候加 --network:

bridge 是默认模式,前面那张 docker0 网桥就是它。名字不用刻意记,docker network inspect bridge 里的 com.docker.network.bridge.name 就写着 docker0,宿主机上 ifconfig 也能查到这块网卡:

容器进出的流量都从这张网桥过:容器里是一块 eth0,宿主机上是一对 veth,最后接到宿主机的物理网卡:

原理不复杂:容器网卡和宿主机上的 veth 成对出现、一对一匹配,同一个网桥下面的容器互相可达:

想验证的话,起两个 tomcat 看网卡最直观:
# 启动两个web服务,这个镜像是安装了ip命令的
docker run -d -p 8082:8080 --name tomcat82 tomcat:with-ip
docker run -d -p 8081:8080 --name tomcat81 tomcat:with-ip
# 宿主机上 ip addr 能看到两块 veth
117: veth01fed78@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 22:7f:88:72:5c:15 brd ff:ff:ff:ff:ff:ff link-netnsid 0
118: vethc9b94bd@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether e6:ec:df:1e:b0:82 brd ff:ff:ff:ff:ff:ff link-netnsid 1
宿主机上的 veth 和容器里的 eth0 是一对一对上的:

容器里一般没有 ip addr 这类命令,装完再打包成镜像就顺手了:
docker commit -a "zzz" -m "添加 iproute2" tomcat81 tomcat:with-ip
默认的 bridge 网络里,容器之间直接用 IP 是通的,问题是 IP 是动态的:

通是通,但下次重建容器 IP 就变了,所以还是得靠名字 —— 这就是后面要用自定义网络的原因。
host 模式不虚拟自己的网卡,直接用宿主机的 IP 和端口,和宿主机共用同一个 Network Namespace:

docker run -d -p 8083:8080 --network host --name tomcat83 tomcat:with-ip
# 启动时有一个警告:启动发布的端口是不被推荐的
# 因为端口号会以主机端口为主,指定了端口映射语法没问题但是不生效
# 所以一般不写 -p
WARNING: Published ports are discarded when using host network mode
那句 WARNING: Published ports are discarded when using host network mode 就是答案:端口以宿主机为准,-p 写了也不生效,所以干脆不写,浏览器直接访问 IP:8080。进容器看 ip addr,和宿主机是一模一样的(Gateway、IPAddress 都是空的)。
none 模式的容器只有一块 lo,docker 不给它做任何网络配置,得自己配,日常基本用不上:

2. container 模式(了解)
除了三大模式,还有一种是借用别人的网络:新容器不建自己的网卡、不配自己的 IP,直接和指定容器共享 IP 和端口范围:


docker run -d -p 8085:8080 --name tomcat85 billygoo/tomcat8-jdk8
docker run -d -p 8086:8080 --network container:tomcat85 --name tomcat86 billygoo/tomcat8-jdk8

这条命令会直接失败:

原因就是端口冲突:既然网络是跟别人共用的,那端口也是同一套,再写 -p 就等于和别人抢端口,docker 直接拒绝。所以容器的两个 8080 是没法共存的,tomcat 不适合这么玩。
换个干净的镜像试就清楚了:
docker run -it --name alpine1 alpine /bin/sh
docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh

两个容器里的 eth0@if16、IP、MAC 完全一样:

那故障也就好理解了:共享源一停,借用方就只剩一块 lo 网卡,网络全没了。
四、--link:已经过时的老办法
这是比较老的技术了,但可以学一下,知道它为什么被淘汰。
# 直接按名字 ping 是不通的
# (原笔记这里把容器名写成了 tomcat 02,中间多一个空格,报的是 No such container,跟网络无关)
docker exec -it tomcat03 ping tomcat02
# 让两个网络连接就可以了
# 启动三个tomcat
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b9594c12916a tomcat "catalina.sh run" About a minute ago Up About a minute 0.0.0.0:32770->8080/tcp, [::]:32770->8080/tcp tomcat02
d84972560009 tomcat "catalina.sh run" 2 days ago Up 2 days 0.0.0.0:32768->8080/tcp, [::]:32768->8080/tcp tomcat01
# 想让03 ping 通02
# 使用 --link 启动
root@VM-0-9-ubuntu:~# docker run -P -d --name tomcat03 --link tomcat02 tomcat
WARNING: Links on the default bridge network are deprecated and will be removed in a future release. Use a custom network instead.
f4d53196405c4f745e9c4b04737c4091256837550ad67cd41ddeca2d63d54eae
# 此时再 ping(ping 命令在 Tomcat 容器里默认没有安装进去安装就行)
# docker exec 是在一个已经运行的容器里执行一条命令
# docker exec [选项] 容器名 命令 [参数...]
root@VM-0-9-ubuntu:~# docker exec -it tomcat03 ping tomcat02
OCI runtime exec failed: exec failed: unable to start container process: exec: "ping": executable file not found in $PATH
# 安装 ping
apt update && apt install iputils-ping -y
# 再测试
root@VM-0-9-ubuntu:~# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.040 ms
docker 自己也给了警告:--link 已经过时了,以后会被移除,建议用自定义网络代替。
--link 不方便的地方在于它是单向的:上面 03 到 02 可以通,02 到 03 就不行,因为 02 启动时没配 link。看配置文件就明白了:
# 也可以看容器的本地绑定文件
root@VM-0-9-ubuntu:~# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00:: ip6-localnet
ff00:: ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
# 直接写死了请求02的地址,ping容器名和ID都可以
172.17.0.3 tomcat02 b9594c12916a
# 下面是03的IP
172.17.0.4 f4d53196405c
# 02是没有的
root@VM-0-9-ubuntu:~# docker exec -it tomcat02 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00:: ip6-localnet
ff00:: ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 b9594c12916a
--link 本质上就是往对方的 /etc/hosts 里写死一条 IP 记录。既然是写死的,重启 docker 让 IP 变了就全乱套了,所以现在不用它了。(想看 link 配置就 docker inspect tomcat03 | grep Link,02 那边是 null。)
五、自定义网络
先看现在有哪些网络:
# 看所有网卡
# 平时都看桥接网卡的东西,不看别的
root@VM-0-9-ubuntu:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
d18bbcfbe974 bridge bridge local
5f8c65dbe6a5 host host local
0ace46ca89cf none null local
四种网络模式前面已经一种一种过了一遍,这里直接看自定义网络。
看具体某个网络,docker network inspect 后面跟的是网络名或网络 ID,不是容器 ID:
docker network inspect d18bbcfbe974
root@VM-0-9-ubuntu:~# docker network inspect d18bbcfbe974
[
{
"Name": "bridge",
"Id": "d18bbcfbe97438fc79c2ae24c7e92f0d72082b0a7d7e4c6b747e21a1d1d353c8",
"Created": "2026-08-02T16:40:39.066550227+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv4": true,
"EnableIPv6": false,
"IPAM": {
# 这里是docker0
"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,
"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": {},
# 容器部分
"Containers": {
"b9594c12916a7613ad93945068d8cf066af6e36a84021ebde7d265dc3e5031ec": {
"Name": "tomcat02",
"EndpointID": "7e9e2f499ea32e6366d20013e6b5566b14dc938d436c5fbf031fa43c1025172e",
"MacAddress": "4e:9e:25:32:29:7c",
# 下面是 docker 随机分配的IP
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"d8497256000951bb607f74a7e8da25ddf2a2634b66cbd3370e7eb7b9031644d5": {
"Name": "tomcat01",
"EndpointID": "a8570c4216ea15d1b53ca3b40617f6fb485b9d9cbe1b71ebbad3197efa58aebb",
"MacAddress": "92:d3:f5:3f:b3:d0",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"f4d53196405c4f745e9c4b04737c4091256837550ad67cd41ddeca2d63d54eae": {
"Name": "tomcat03",
"EndpointID": "58030c137ffd0ccf1024cbe22db4bc6d1ffc6f7a40fe19061f6e318d24c8073b",
"MacAddress": "02:f7:af:47:b7:3b",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
}
},
"Status": {
"IPAM": {
"Subnets": {
"172.17.0.0/16": {
"IPsInUse": 6,
"DynamicIPsAvailable": 65530
}
}
}
}
}
]
创建自定义网络先看参数,不知道就 --help:
root@VM-0-9-ubuntu:~# 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 ipSlice IPv4 or IPv6 Gateway for the master subnet (default [])
--ingress Create swarm routing-mesh network
--internal Restrict external access to the network
--ip-range ipNetSlice Allocate container ip from a sub-range (default [])
--ipam-driver string IP Address Management Driver (default "default")
--ipam-opt map Set IPAM driver specific options (default map[])
--ipv4 Enable or disable IPv4 address assignment (default true)
--ipv6 Enable or disable IPv6 address assignment
--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
这里有个容易混的地方:--net bridge 是启动容器时指定的模式,--driver bridge 是创建网络时用的参数。
下面自己建一个,参数依次是驱动模式、子网(CIDR 表示法)、网关:
docker network create \
--driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 \
mynet # 子网的名字
# 查看网络
root@VM-0-9-ubuntu:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
d18bbcfbe974 bridge bridge local
5f8c65dbe6a5 host host local
36ca4c8c9a09 mynet bridge local
0ace46ca89cf none null local
# docker inspect [网络名]
root@VM-0-9-ubuntu:~# docker inspect mynet
[
{
"Name": "mynet",
"Id": "36ca4c8c9a09eeb1e2d4b641a9b51ae9c69e9a057d4326f3b37875f1b099a296",
"Created": "2026-08-05T09:28:43.060157867+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv4": true,
"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,
"Options": {},
"Labels": {},
"Containers": {},
"Status": {
"IPAM": {
"Subnets": {
"192.168.0.0/16": {
"IPsInUse": 3,
"DynamicIPsAvailable": 65533
}
}
}
}
}
]
到这儿自己的网络就建好了。往里跑两个容器:
docker run -d -P --name tomcat01 --net mynet tomcat
docker run -d -P --name tomcat02 --net mynet tomcat
# 查看inspect的容器部分
# 用到了自己创建的子网IP,2和3,1是网关
"Containers": {
"3c0f5e37a82f11fea4ade117d465627574c6e2bfb816bc7d2d28ba91eaa63100": {
"Name": "tomcat01",
"EndpointID": "f26efa1880b0de9f1609f1b114f1dae6da7a018355f927c2a303d9b82576005f",
"MacAddress": "82:96:fd:c3:ba:66",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
"6f0a0cee653c0eb9d0a7669af37fb7245cdc7863510729701937f4a1f8a89dbe": {
"Name": "tomcat02",
"EndpointID": "35ba3cda62ffbe3b7eba0d306d182e74099b780d59eb7b83798b3d3a9dd16b00",
"MacAddress": "d2:eb:e7:cd:10:8c",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
}
},
测互通 —— 不用 --link 就能通,这是自定义网络最香的地方:
apt update && apt install -y iputils-ping
root@VM-0-9-ubuntu:~# docker exec -it tomcat01 bash
root@3c0f5e37a82f:/usr/local/tomcat# 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.074 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.062 ms
(原笔记这一段两次 ping 的输出对不上,一次 ping .3 却回了 .2 的结果,属于贴错;以能 ping 通 .3 的这次为准。)
自定义的网络 docker 已经帮我们维护好了对应的关系,平时大都使用自定义网络而不是 docker0。 不同的集群用不同的网络,可以保证集群彼此隔离、互不打扰,比如 redis 一套、mysql 一套;当然需要的时候也能打通。

换到自定义网络之后,容器里装个 ping 就能直接用服务名互 ping:

原因就是自定义网络本身就维护好了主机名和 IP 的对应关系,容器 IP 变了也不影响调用:

六、跨网段连通
现在手上有两个网络了:docker0(172.17 网段)和 mynet(192.168 网段),各跑着容器。同一网段内畅通没问题,不同网段按计网的规矩就是 ping 不通:

先在 docker0 网段里起两个:
# 在docker0网段创建
root@VM-0-9-ubuntu:~# docker run -d -P --name tomcat01-d0 tomcat
9227203fcc9c1e05874024db920e7ca3f4734ad80634b95d0ae907b2ee136e60
root@VM-0-9-ubuntu:~# docker run -d -P --name tomcat02-d0 tomcat
3dd00dc3dc9dc0e3f0593446214efc00d4d11ad28c3e5a436cb31e4caccbf1e6
root@VM-0-9-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3dd00dc3dc9d tomcat "catalina.sh run" 2 seconds ago Up 1 second 0.0.0.0:32777->8080/tcp, [::]:32777->8080/tcp tomcat02-d0
9227203fcc9c tomcat "catalina.sh run" 5 seconds ago Up 5 seconds 0.0.0.0:32776->8080/tcp, [::]:32776->8080/tcp tomcat01-d0
6f0a0cee653c tomcat "catalina.sh run" 28 minutes ago Up 28 minutes 0.0.0.0:32775->8080/tcp, [::]:32775->8080/tcp tomcat02
3c0f5e37a82f tomcat "catalina.sh run" 29 minutes ago Up 29 minutes 0.0.0.0:32774->8080/tcp, [::]:32774->8080/tcp tomcat01
# 这里卡住了,并不通
root@VM-0-9-ubuntu:~# docker exec -it tomcat01-d0 ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
# 看网段(docker0的默认网段名字叫bridge)
docker inspect bridge
# 容器部分里 172 网段和 192 网段不同,所以 ping 失败
打通的办法是用 docker network connect,相当于给这个容器在另一个网段里再加一个 IP:
# docker network connect [网络名] [容器名]
# 如同给网段新增容器
docker network connect mynet tomcat01-d0
连上之后再看 mynet 的容器列表,tomcat01-d0 就多了一个 192.168.0.4 的地址:
"Containers": {
# 直接加入了容器,实现一个容器两个地址,也算是暴力打通了
"9227203fcc9c1e05874024db920e7ca3f4734ad80634b95d0ae907b2ee136e60": {
"Name": "tomcat01-d0",
"EndpointID": "4dc6ac32e8d5b1c2a48c4ccd8aabfff17da0789758118a4d5836615544e27ddc",
"MacAddress": "e2:5f:63:b5:c0:8d",
"IPv4Address": "192.168.0.4/16",
"IPv6Address": ""
}
},
再测就通了,而且因为是自定义网络,直接用容器名就能 ping 到:
# 测试连通性
root@VM-0-9-ubuntu:~# docker exec -it tomcat01-d0 ping tomcat02
PING tomcat02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.057 ms
^C
--- tomcat02 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1023ms
rtt min/avg/max/mdev = 0.057/0.059/0.062/0.002 ms
跨网络操作就用 docker network connect。

docker network 这套子命令不长,常用的就这几个:
docker network --help
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
它和系统自带的 netstat 容易混,放一张表对比:
| 对比 | netstat | docker network |
|---|---|---|
| 来源 | Linux 系统自带 | Docker 提供 |
| 作用对象 | 宿主机网卡、端口、连接 | Docker 网桥、容器网络 |
| 能看到什么 | 哪个端口被占用、TCP 连接 | 有哪些 Docker 网络、哪个容器连到哪个网桥 |
| 示例输出 | netstat -tlnp 看 80 端口被谁占 | docker network ls 看网络列表 |
七、关于跨主机通信
上面聊的都是单机上的网络:docker0、自定义网桥、docker network connect,全在同一台宿主机里。跨主机要另外的驱动,比如 overlay(Swarm/K8s 那套)或者 macvlan,我这边的笔记还没做到,先留个位置。
最后两条收尾的:
docker network prune可以删掉所有没被使用的网络,测试完清场很方便;但正在被容器用着的网络不会动,删不掉是正常的。- 笔记里原来还留了一个 Redis 集群部署的位置,那是利用 Docker 网络部署多节点集群的典型场景,备注是"这个集群不是哨兵模式,是分片"。等 Redis 那部分补上了再回来写。