容器 IP 每次重建都变?docker network 五种模式与自定义网桥固定地址

默认 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 建容器时到底做了四步

  1. 创建一对虚拟网卡,一半放宿主机、一半放新容器的网络命名空间。
  2. 宿主机那一半接到默认 docker0 或 --network 指定的网桥上,名字以 veth 开头。
  3. 容器那一半改名成 eth0,只在容器命名空间里可见。
  4. 从网桥的地址范围里取一个空闲地址给 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

📚 参考资料(官方文档)

总结 :Docker 自带的三张网只够跑单机小实验------默认 bridge 不能指定 IP、不带名字解析,host 没有隔离,none 干脆没网卡。要固定地址、要按名字互访,就自己 docker network create 一个带 --subnet 的网络,容器用 --network 接进去,用 --ip 钉地址,DNS 交给 127.0.0.11 的内嵌服务。记住一句:--ip 只在自定义网络里有效,而自定义网络必须先有 --subnet。


📚 同系列 · Docker 从镜像到容器(其余篇目见博客主页)

blog.csdn.net/nbsxl

  • 上一篇:《容器端口映射完还是连不上?-p 四种写法、DNAT 原理与 WordPress 实战》
  • 相关篇:《容器一删数据就没?Docker 数据卷三种挂载与 volume 命令避坑指南》
  • 相关篇:《容器退出就没了?Docker 容器生命周期管理:13 条命令 + 自愈策略》

💬 你在 --ip 上报过 user specified IP address is supported only when connecting to networks with user configured subnets 吗?把你建网络的完整命令贴出来,一起看是哪一段缺了。

相关推荐
火云代理1 小时前
同一个网站,有的网络能打开、有的打不开?认识 IPv4 与 IPv6 的访问差异
服务器·网络·网络协议·tcp/ip·测试工具·php·状态模式
坤坤子吖2 小时前
Linux网络编程:TCP 粘包与半包问题,如何正确处理 TCP 流式数据?
linux·服务器·网络·笔记·网络协议·学习
打工仔折腾 AI4 小时前
Changedetection.io 网页变动监控:Docker 部署、通知配置与公网暴露实践
运维·人工智能·后端·python·docker·容器·性能优化
火云代理4 小时前
Python 使用代理 IP 前,先弄清 Requests 的配置来源与验证方法
网络·python·网络协议·tcp/ip·ip
如夏倾城5 小时前
QUIC——HTTP/3 的唯一底层传输协议 及 0-RTT恢复
网络·网络协议·tcp/ip·安全·http
科研邪修法6 小时前
培训PDF保护配置:把需求转换成可验收权限
linux·服务器·网络
xbzb9 小时前
自建镜像仓库:registry 一条命令 + harbor 部署、授权、跨库同步与卸载
docker·harbor·镜像·仓库·同步·registry
略懂而已1 天前
安装SSL后网站速度变慢?
网络·网络协议·ssl