默认 bridge 网络里,容器重启就换 IP,也没法用
--ip指定地址,容器之间只能靠 IP 或--link互访。这篇把docker network的七条子命令、--network的五个取值、以及自建网桥怎么定网段、怎么给容器钉死地址一次讲完,最后用resolv.conf里的127.0.0.11说清容器 DNS 到底谁在管。
本文概要:
| 项目 | 内容 |
|---|---|
| 文章主题 | docker network 七条子命令的用法、五种网络模式的取舍、自建网桥与固定 IP / DNS 的配置方法 |
| 所属类别 | 云计算 → 容器技术 → Docker 网络 |
| 知识关键字 | docker network · --subnet · --ip-range · --gateway · --ip · 127.0.0.11 · --dns-search · brctl · --network=host |
主线一句:要固定地址或按名字互访,就得自己建网络。第一章看清 Docker 自带的网,第二章比五种模式的差异。第三章动手建网桥,第四章讲连接与清理,第五章解决地址与解析。
一、先看清 Docker 自带了哪几张网
1.1 ls 用法速查表
| 参数 | 含义 | 英文原意 |
|---|---|---|
ls / list |
列出所有网络 | list,列出 |
-q / --quiet |
只输出网络 ID | quiet,安静 |
-f / --filter |
按条件过滤,如 driver=bridge |
filter,过滤 |
--no-trunc |
ID 不截断,方便贴进工单 | no truncation,不截断 |
--format |
用 Go 模板自定义输出列 | format,格式化 |
bash
[root@docker ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
6b2167212b5b bridge bridge local
f2b4b4381ebe host host local
215052afe287 none null local
三张网开箱即用:bridge 是默认网桥,host 直接用宿主网络栈,none 什么都不接。DRIVER 列写 null 是因为 none 网络压根没有驱动。
1.2 inspect 用法速查表
| 参数 | 含义 | 英文原意 |
|---|---|---|
inspect |
查看网络详情,可同时看多个 | inspect,检查 |
-f / --format |
用 Go 模板只取某个字段 | format,格式化 |
-v / --verbose |
输出诊断用的额外信息 | verbose,详细 |
bash
[root@docker ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "6b2167212b5b9f7b0dd52099b5a611a509efcb8284c3596e6d14b5c1b95e73a4",
"Driver": "bridge",
"IPAM": {
"Config": [
{ "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" }
]
},
"Containers": {
"aa0545bd0ff5...": {
"Name": "myweb",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.3/16"
}
},
"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"
}
}
]
Options 里的六个键决定这张网的行为,改之前先弄清各自管什么:
| 键 | 作用 |
|---|---|
com.docker.network.bridge.default_bridge |
是否作为默认网桥,true 时新容器不指定网络就连它 |
com.docker.network.bridge.enable_icc |
容器间是否允许互访,关掉等于同网段隔离 |
com.docker.network.bridge.enable_ip_masquerade |
是否做出站 SNAT,关掉容器上不了外网 |
com.docker.network.bridge.host_binding_ipv4 |
-p 发布端口默认绑定到哪个地址 |
com.docker.network.bridge.name |
宿主机上这块网桥叫什么名字 |
com.docker.network.driver.mtu |
最大传输单元,跨 VXLAN 时要调小 |
二、五种网络模式怎么选
--network 一共五个取值,选错就是「明明配了却不通」的根源。
| 取值 | 网络栈 | 出网 | 能否 --ip |
典型用途 |
|---|---|---|---|---|
none |
只有 lo,没有网卡 |
不能 | 不能 | 只算数不算网络的离线任务 |
bridge(默认) |
接 docker0,走 NAT | 能 | 不能 | 单机实验、临时容器 |
| 自定义网络 | 接自建网桥,带内嵌 DNS | 能 | 能 (需先有 --subnet) |
多容器协作、需要名字互访 |
container:名字 |
与另一个容器共用 | 跟随对方 | 不能 | 边车容器,共用对方的网络命名空间 |
host |
直接用宿主网卡 | 能 | 不适用 | 追求性能、端口不冲突的场景 |

表里五行下面各跑一遍:none 与默认 bridge 在 2.1,host 在 2.2,container 在 2.3,自定义网络在 2.4。每节都以一条能验证的判读收尾。
2.1 两种省事的模式:none 与 bridge
bash
# none:容器里只有环回口,适合纯计算
[root@docker ~]# docker container run -it --network=none busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue
inet 127.0.0.1/8 scope host lo
/ # ping -c 1 10.1.8.130
ping: connect: Network is unreachable
ip a 里只有 lo 一行、ping 直接报「网络不可达」,这就是 none 的判读方式:没有网卡、没有路由、没有 DNS。
默认 bridge 的演示贯穿第三、四章(bridge2、nettest 都在用它),这里只补一条它最常被踩的限制:
bash
# 默认 bridge 上想固定地址,直接报错
[root@docker ~]# docker run --rm --network=bridge --ip 172.17.0.50 busybox
docker: Error response from daemon: user specified IP address is supported only when connecting to networks with user configured subnets.
读这句报错:user configured subnets 就是「创建网络时自己写的 --subnet」,默认 bridge 的网段是 Docker 启动时定的,不算用户配置。
2.2 host:直接借用宿主机的网卡
bash
# 想让容器直接监听宿主机的 80,就这么写
[root@docker ~]# docker run -d --name webhost --network=host -p 8080:80 httpd
WARNING: Published ports are discarded when using host network mode
9c1b0e5a5f2d...
第一行输出就是 host 模式最重要的提示:容器没有自己的 IP,-p 无处可映射,被丢弃并告警。所以验证不查端口,改查网卡和宿主 IP:
bash
# 容器里看到的网卡,和宿主机上的一模一样
[root@docker ~]# docker exec webhost ip -4 -br a
lo UNKNOWN 127.0.0.1/8
enp0s3 UP 10.1.8.130/24
docker0 DOWN 172.17.0.1/16
# 端口映射表是空的:它压根没有独立的端口
[root@docker ~]# docker port webhost
# 直接访问宿主 IP 的 80,命中的就是容器里的 httpd
[root@docker ~]# curl -s -o /dev/null -w '%{http_code}\n' http://10.1.8.130
200
判读三件事:ip -br a 里出现了宿主机网卡和 docker0 网桥(这些本来是宿主机的)、docker port 输出为空、访问宿主 IP 就能拿到服务。
代价也在这里:容器监听的 80 就是宿主机的 80,这个端口被占时容器直接起不来。反过来容器占了端口,宿主自己的服务也起不来。
省掉 NAT 与 docker-proxy 换来的是性能,付出的是零网络隔离。从网络角度看,它跟直接装在宿主机上的 httpd 没区别,只适合端口不冲突又要低延迟的场景。
2.3 container:借用另一个容器的网络栈
bash
# 先起一个业务容器当「宿主」,80 发布到宿主 8080
[root@docker ~]# docker run -d --name web1 -p 8080:80 httpd
3f5a7c9e1d84...
# 再起一个旁路容器,网络栈直接借用 web1 的
[root@docker ~]# docker run --rm -it --network=container:web1 busybox
/ # ip -4 -br a
lo UNKNOWN 127.0.0.1/8
eth0 UP 172.17.0.2/16
/ # wget -qO- 127.0.0.1
<html><body><h1>It works!</h1></body></html>
ip 里只有一张 eth0,地址是 172.17.0.2(web1 的地址);wget 127.0.0.1 又直接拿到了 web1 的首页。这两条就是判读:新容器的网卡、IP、路由全归对方管 ,两者通过 lo 环回口直接通信。
文件系统、进程列表、资源限制仍归自己。所以典型用法是「旁路工具」:业务镜像不装 tcpdump,另起 nicolaka/netshoot 容器借它的网卡抓包,抓完一删,业务镜像干干净净。
端口同样不归自己管:-p 写了也不生效,要对外提供服务得在对方容器上发布。对方容器一停,旁路容器立刻失去网络。
2.4 自定义网络:建一次,固定地址和名字解析一起拿到
bash
# 自建一张带网段的网络
[root@docker ~]# docker network create appnet --subnet=172.20.0.0/16 --gateway=172.20.0.1
8f2c41d7a9e3...
# app1 用 --ip 钉死地址
[root@docker ~]# docker run -d --name app1 --network=appnet --ip 172.20.0.10 busybox sleep 3600
# app2 不指定,从网段里自动分配
[root@docker ~]# docker run -d --name app2 --network=appnet busybox sleep 3600
# 直接用容器名 ping,不用查 IP
[root@docker ~]# docker exec app2 ping -c 1 app1
PING app1 (172.20.0.10): 56 data bytes
64 bytes from 172.20.0.10: seq=0 ttl=64 time=0.083 ms
# 收尾:把这几个演示容器清掉
[root@docker ~]# docker rm -f webhost web1 app1 app2
ping app1 不用 IP 就能通,靠的是自定义网络内嵌的 127.0.0.11 DNS;--ip 172.20.0.10 能生效,靠的是创建时写了 --subnet。这两件事在默认 bridge 上都做不到------这就是表里只有这一行敢同时写两个「能」的原因。
建网与接容器的完整参数在第三章,--ip、--hostname、--dns-search 的细节在第五章。
三、动手建一个自己的网桥
3.1 create 用法速查表
| 参数 | 含义 | 英文原意 |
|---|---|---|
create NETWORK |
新建一个网络,位置参数是网络名 | create,创建 |
-d / --driver |
网络驱动,默认 bridge |
driver,驱动 |
--subnet |
网段,CIDR 写法,决定掩码与可用地址范围 | subnet,子网 |
--ip-range |
从子网里再切一段专供容器分配 | IP range,地址范围 |
--gateway |
网关地址,不写就取网段第一个可用地址 | gateway,网关 |
-o / --opt |
驱动选项,如 com.docker.network.bridge.name |
option,选项 |
--internal |
禁止访问外网,只做内部互通 | internal,内部 |
--attachable |
允许非 Swarm 容器手动接入 | attachable,可附加 |
bash
# 网段 172.28.0.0/16,但容器地址只从 172.28.5.0/24 里取,网关 .5.254,宿主网桥名叫 docker1
[root@docker ~]# docker network create bridge2 --driver=bridge --subnet=172.28.0.0/16 --ip-range=172.28.5.0/24 --gateway=172.28.5.254 -o com.docker.network.bridge.name=docker1
0b2ea4cd10682eeb974bd761fb0c57c798e69f53748b714a64ff71172a2f56f4
三件事一起发生了:网络对象叫 bridge2,宿主机上多了一块叫 docker1 的网桥,网段是 172.28.0.0/16。
bash
[root@docker ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
6b2167212b5b bridge bridge local
0b2ea4cd1068 bridge2 bridge local
f2b4b4381ebe host host local
215052afe287 none null local
# 三个地址参数最终落在 IPAM.Config 里,一项不少
[root@docker ~]# docker network inspect bridge2 -f '{{json .IPAM.Config}}'
[{"Subnet":"172.28.0.0/16","IPRange":"172.28.5.0/24","Gateway":"172.28.5.254"}]
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242038dc579 no veth01fd766
docker1 8000.02420bed0c44 no
[root@docker ~]# ip addr show docker1
13: docker1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 state DOWN
inet 172.28.5.254/16 brd 172.28.255.255 scope global docker1
NO-CARRIER 与 DOWN 是正常的:网桥建好了但还没容器接进来,等第一个容器接入就会自动 UP。
3.2 把容器接到新网桥上
bash
# --network 指向刚建的网络,容器就落到 docker1 上
[root@docker ~]# docker container run --rm -it --network=bridge2 busybox
/ # ip a
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500
inet 172.28.5.0/16 brd 172.28.255.255 scope global eth0
/ # route -n
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.28.5.254 0.0.0.0 UG 0 0 0 eth0
172.28.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
网关正是创建时写的 172.28.5.254,掩码来自 --subnet 的 /16,地址 .5.0 来自 --ip-range。三个参数各管一段,一个 --subnet 定不死地址。
3.3 Docker 建容器时到底做了四步
- 创建一对虚拟网卡,一半放宿主机、一半放新容器的网络命名空间。
- 宿主机那一半接到默认
docker0或--network指定的网桥上,名字以veth开头。 - 容器那一半改名成
eth0,只在容器命名空间里可见。 - 从网桥的地址范围里取一个空闲地址给
eth0,网关指向网桥自己的内部接口地址。
第 4 步里「网桥自己的地址」不一定是 docker0:本节的例子就是 docker1 的 172.28.5.254。

四、把容器接上或摘下
4.1 disconnect 用法速查表
| 参数 | 含义 | 英文原意 |
|---|---|---|
disconnect NETWORK CONTAINER |
把容器从网络上摘下 | disconnect,断开 |
-f / --force |
容器在跑也强行断开 | force,强制 |
bash
[root@docker ~]# docker container run -d -p 5000:5000 --name nettest registry
[root@docker ~]# docker container ls
CONTAINER ID IMAGE STATUS PORTS NAMES
1f3d9c8a7b21 registry Up 2 seconds 0.0.0.0:5000->5000/tcp nettest
# 断开默认 bridge,端口发布跟着失效
[root@docker ~]# docker network disconnect bridge nettest
[root@docker ~]# docker container ls
CONTAINER ID IMAGE STATUS PORTS NAMES
1f3d9c8a7b21 registry Up 8 seconds nettest
PORTS 列空掉就是断开的证据:容器还在跑,但已经没有网卡承载这条映射,外部立刻访问不到。
4.2 connect 用法速查表
| 参数 | 含义 | 英文原意 |
|---|---|---|
connect NETWORK CONTAINER |
把容器接到网络上,一个容器可接多张 | connect,连接 |
--ip |
指定 IPv4 地址,要求该网络创建时写过 --subnet |
IP address,IP 地址 |
--ip6 |
指定 IPv6 地址 | IPv6 address |
--alias |
给容器在这张网络上加个别名 | alias,别名 |
--link |
顺带连向另一个容器,同 run 的 --link |
link,链接 |
--driver-opt |
传给驱动的选项 | driver option |
--link-local-ip |
指定链路本地地址 | link-local IP |
bash
# 接回默认 bridge,端口映射自动恢复
[root@docker ~]# docker network connect bridge nettest
[root@docker ~]# docker container ls
CONTAINER ID IMAGE STATUS PORTS NAMES
1f3d9c8a7b21 registry Up 20 seconds 0.0.0.0:5000->5000/tcp nettest
一个容器可以同时接多张网,用 docker network connect 再挂一张即可,适合「管理网 + 业务网」分离的部署。
4.3 rm 与 prune 用法速查表
| 参数 | 含义 | 英文原意 |
|---|---|---|
rm NETWORK |
删除一个或多个网络 | remove,移除 |
prune |
删除所有没被容器使用的网络 | prune,修剪 |
--filter |
按条件删,如 until=<时间戳> |
filter,过滤 |
-f / --force |
跳过交互确认 | force,强制 |
bash
[root@docker ~]# docker network rm bridge2
bridge2
[root@docker ~]# docker network prune
WARNING! This will remove all custom networks not used by at least one container.
Are you sure you want to continue? [y/N] y
prune 只清「自定义」网络,bridge、host、none 三张内置网不会被删。
五、固定地址与容器 DNS
5.1 网络相关参数速查表
| 参数 | 含义 | 英文原意 |
|---|---|---|
--network |
指定容器接入的网络 | network,网络 |
--ip |
指定容器地址,仅在自定义网络可用 | IP address,IP 地址 |
--hostname |
设置容器主机名 | host name,主机名 |
--dns |
追加一个 DNS 服务器地址 | DNS server |
--dns-search |
追加搜索域,短名字自动补全后缀 | DNS search,搜索域 |
bash
# 先把网建好,再用 --ip 钉死地址
[root@docker ~]# docker network create bridge2 --driver=bridge --subnet=172.28.0.0/16 --ip-range=172.28.5.0/24 --gateway=172.28.5.254 -o com.docker.network.bridge.name=docker1
0e3a48a34bf3453a0c0e2963cc86389e8a237a22de94a0f93206d7746cf74026
[root@docker ~]# docker container run --rm -it --dns-search redhat.fun --hostname myhost --ip 172.28.5.100 --network bridge2 busybox
/ # ip a show eth0
21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500
inet 172.28.5.100/16 brd 172.28.255.255 scope global eth0
/ # cat /etc/resolv.conf
search redhat.fun
nameserver 127.0.0.11
options ndots:0
/ # ping -c 2 zhb
PING zhb (117.88.5.0): 56 data bytes
64 bytes from 117.88.5.0: seq=0 ttl=127 time=4.810 ms
三条配置各生效在不同的文件里,别指望它们互相关联:
| 配置 | 落到哪 | 效果 |
|---|---|---|
--ip 172.28.5.100 |
容器 eth0 的地址 |
重建容器还是这个地址,前提是网络没重建 |
--hostname myhost |
容器的主机名(hostname 命令可见) |
容器内提示符与日志里显示的名字 |
--dns-search redhat.fun |
/etc/resolv.conf 的 search 行 |
ping zhb 自动补成 zhb.redhat.fun |
nameserver 127.0.0.11 是 Docker 塞进自定义网络的内嵌 DNS。ping zhb 先由它补全域名,再把外部查询转给宿主 DNS 解析。
⚠️ 注意 :
--ip有两个硬前提------网络必须是自定义的,且创建时写过--subnet。默认bridge上加--ip直接报错,因为它的子网是 Docker 启动时定死的,不允许单容器改。
5.2 默认 bridge 与自定义网络的 DNS 差别
| 对比项 | 默认 bridge |
自定义网络 |
|---|---|---|
/etc/resolv.conf 里的 DNS |
宿主机的 DNS(如 10.1.8.2) |
127.0.0.11 内嵌 DNS |
| 容器名能否解析 | 不能,只能靠 IP 或 --link |
能,容器名与别名都进 DNS |
能否 --ip |
不能 | 能(需 --subnet) |
能否 --hostname 生效 |
只改宿主名,不参与解析 | 只改宿主名,不参与解析 |
官方对默认网络的原话很直接:默认 bridge 上的容器只能通过 IP 互访 ,--link 是补丁式的 legacy 方案;自定义网络才有自动的服务发现。这也是多容器项目一律自建网络的原因。
附:命令英文全称速查表
| 命令 / 缩写 | 英文全称 / 原意 | 作用 |
|---|---|---|
network |
network | 网络子命令入口 |
ls |
list | 列出网络 |
inspect |
inspect | 查看网络详情 |
create |
create | 创建网络 |
connect |
connect | 把容器接入网络 |
disconnect |
disconnect | 把容器从网络摘下 |
rm |
remove | 删除网络 |
prune |
prune | 清理未使用的网络 |
subnet |
sub-network | 子网,决定掩码与网段 |
gateway |
gateway | 网关地址 |
brctl |
bridge control | 查看与管理 Linux 网桥 |
veth |
virtual Ethernet | 成对出现的虚拟网卡 |
DNS |
Domain Name System | 域名系统,把名字换成 IP |
📚 参考资料(官方文档)
- bridge 网络驱动与自定义网络:https://docs.docker.com/engine/network/drivers/bridge/
docker network create参数全解:https://docs.docker.com/reference/cli/docker/network/create/docker run的--network与--ip:https://docs.docker.com/reference/cli/docker/container/run/#networknone网络驱动:https://docs.docker.com/engine/network/drivers/none/
总结 :Docker 自带的三张网只够跑单机小实验------默认
bridge不能指定 IP、不带名字解析,host没有隔离,none干脆没网卡。要固定地址、要按名字互访,就自己docker network create一个带--subnet的网络,容器用--network接进去,用--ip钉地址,DNS 交给127.0.0.11的内嵌服务。记住一句:--ip只在自定义网络里有效,而自定义网络必须先有--subnet。
📚 同系列 · Docker 从镜像到容器(其余篇目见博客主页)
- 上一篇:《容器端口映射完还是连不上?-p 四种写法、DNAT 原理与 WordPress 实战》
- 相关篇:《容器一删数据就没?Docker 数据卷三种挂载与 volume 命令避坑指南》
- 相关篇:《容器退出就没了?Docker 容器生命周期管理:13 条命令 + 自愈策略》
💬 你在 --ip 上报过 user specified IP address is supported only when connecting to networks with user configured subnets 吗?把你建网络的完整命令贴出来,一起看是哪一段缺了。
