Docker 网络模式:bridge 和 host 怎么选
Docker 的 bridge、host、none 三种网络模式到底什么区别?小够用大白话讲清原理、怎么选,以及端口映射时最容易踩的坑。
我是小够。Docker 玩到一定程度,都会遇到网络问题:容器之间怎么互通?端口怎么映射?bridge 和 host 选哪个?今天把 Docker 的网络模式一次讲明白。
先理解:容器网络在解决什么
每个 Docker 容器都是一座孤岛,网络模式决定的是:孤岛和外界怎么连。三种主流模式,bridge、host、none,覆盖 99% 的场景。
bridge:默认模式,大多数时候用它
docker run 不指定网络,默认就是 bridge。原理:Docker 在宿主机上建一座虚拟网桥(docker0),每个容器接一根虚拟网线到桥上,容器之间通过内网 IP 互通,访问外网走 NAT 出去。
特点:
- 容器有独立的内网 IP(一般是 172.17.x.x),互相隔离。
- 外界访问容器里的服务,要做端口映射:
-p 8080:80,意思是宿主机的 8080 端口转发到容器的 80 端口。 - 容器之间想互通,用容器名当主机名就行(同一自定义网络下),不用记 IP。
docker run -d -p 8080:80 --name myweb nginx
这行命令:后台跑个 nginx,宿主机 8080 端口映射到容器 80 端口,浏览器打开 服务器IP:8080 就能看到页面。
什么时候用 bridge:默认就用它。跑网站、跑应用、跑数据库,bridge 加端口映射,够用了。
host:和宿主机共用网络
--network host,容器直接用宿主机的网络栈,没有隔离:容器里开 80 端口,就是宿主机的 80 端口,不用映射。
特点:
- 性能最好:少了一层 NAT 转发,延迟最低,吞吐最高。
- 端口直接暴露:容器开什么端口,宿主机就开什么端口,省了映射的麻烦,也少了映射的困惑。
- 容易冲突:两个容器都想用 80 端口,直接打架。端口规划得自己做好。
- 隔离性差:容器能看到宿主机的网络,安全性比 bridge 低一档。
什么时候用 host:对网络性能敏感的(比如 DNS 服务、高并发网关)、端口特别多的(映射写到手酸)、或者某些必须用宿主机网络的特殊软件。普通网站、应用,老老实实 bridge。
none:没有网络,特殊场景
--network none,容器没有网卡,只能用回环地址自己跟自己玩。听起来没用,但有些场景要的就是隔离:跑一次性计算任务、处理敏感数据、不需要任何网络的批处理。用得少,知道有这个选项就行。
怎么选:一张决策表
| 场景 | 选哪个 |
|---|---|
| 默认,不知道选啥 | bridge |
| 跑网站、API、数据库 | bridge + 端口映射 |
| 对延迟敏感、高并发 | host |
| 端口多到映射写不完 | host |
| 完全不需要网络 | none |
| 多容器互相调用 | 自定义 bridge 网络(docker compose 默认就是) |
新手记住一句就行:默认 bridge,性能不够再 host。别一上来就 host,端口冲突和安全问题够你喝一壶。
最容易踩的坑:端口映射的 0.0.0.0
跑容器时 -p 8080:80,默认绑定的是 0.0.0.0:8080,意思是所有网卡、公网可访问。本意只想内网用的数据库,一个 -p 3306:3306 就暴露到公网了,扫描器分分钟找上门。
两个习惯:
- 只映射必须公开的端口,数据库、管理后台这类,能不映射就不映射,容器之间内网互通就行。
- 公网暴露的端口,配合 UFW 防火墙收紧(本系列第一篇讲过),该限 IP 的限 IP。
docker compose:多容器的正确姿势
容器一多,docker run 参数写到崩溃,换 docker compose。一个 compose.yaml 把几个容器、网络、端口映射写在一起,一键起停:
services:
web:
image: nginx
ports:
- "8080:80"
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: example
compose 默认给这些容器建一个自定义 bridge 网络,容器之间用服务名(web、db)直接互通,不用记 IP,不用手动映射内部端口。这是生产环境的标准姿势,早用早省心。
自定义网络:生产环境标配
默认的 bridge(docker0)有个缺点:容器重启 IP 会变,靠 IP 互通不靠谱。生产环境都用自定义 bridge 网络:
docker network create mynet
docker run -d --network mynet --name web nginx
docker run -d --network mynet --name db mysql:8
同一自定义网络下,容器之间用容器名当主机名直接互通,web 连 db 就写 db:3306,IP 变了也不怕。docker compose 默认就是这么干的,所以前面说 compose 是标准姿势。
容器互通的三种方式
- 容器名互通(推荐):同一自定义网络,用服务名直连,最省心。
- 端口映射经宿主机:A 容器映射到宿主机端口,B 容器连宿主机 IP 加端口。绕远,能用但不优雅。
- 共享网络栈:
--network container:web,两个容器共用一套网络,localhost 互通。适合边车(sidecar)模式,比如主应用加日志收集。
第一种覆盖 90% 的场景,记住它就行。
overlay:多机器才用得上
单机玩 Docker,bridge 加自定义网络走天下。overlay 是给多台机器(Swarm / 跨主机)准备的,容器跨宿主机互通。个人用户基本用不上,知道有这个概念,面试…看文档时不懵就行。
实战:WordPress 的网络长什么样
services:
wordpress:
image: wordpress
ports:
- "8080:80"
networks:
- wpnet
db:
image: mysql:8
networks:
- wpnet
networks:
wpnet:
wordpress 和 db 都在 wpnet 里,wordpress 连数据库写 db:3306。db 没有 ports 映射,外界连不进来,只能 wordpress 连,安全。8080 映射出来给访客。这就是典型的「前端暴露、后端内网」结构,举一反三,什么应用都这么搭。
排错:容器连不上怎么办
按这个顺序查:
- 在不在一个网络:
docker network inspect看两个容器是不是同一网络,不在就连不上。 - 端口对不对:容器内服务监听的是哪个端口,映射的是哪个,别搞混。服务监听 8080,你映射 80,转了个寂寞。
- 服务起来没:
docker logs看容器日志,服务没启动,网络再通也没用。 - 防火墙:宿主机 UFW 没放行映射的端口,公网进不来。内网互通不受 UFW 影响,别背锅给防火墙。
- DNS:自定义网络下容器名解析不了,检查网络模式对不对,默认 bridge 下容器名是解析不了的,必须自定义网络。
IPv6 与 Docker:一句话
宿主机有 IPv6,容器默认拿不到,要额外配置。个人用户先别折腾,IPv4 够用。等哪天 IPv6 真成刚需了,再回头看文档,官方文档写得很清楚。
生产环境 checklist
容器上生产前,对着过一遍:
- 只映射了必须公开的端口
- 数据库、管理后台没暴露公网
- 用了自定义网络,服务名互通
- 重要数据挂了 volume,重建容器不丢数据
- 设了 restart: always,机器重启容器自启
- 日志有轮转,别让 json 日志吃掉硬盘
最后一条展开说一句:Docker 默认日志不轮转,跑半年的容器,日志几个 G 很常见。compose 里加个 logging 配置,或者定期清,别等硬盘满了才想起来。
小够的唠叨
Docker 网络看着复杂,其实就三句话:默认 bridge 够用,端口映射想清楚,数据库别暴露公网。网络模式选错了,最多是性能差一点、麻烦一点;端口暴露错了,是安全问题。分清主次,别在 bridge 和 host 的选择上纠结半天,转头把数据库端口映射到了公网。compose 用起来,自定义网络是标配,这两样掌握了,Docker 网络这关就算过了。以后看到容器连不通,先想网络模式,再想端口映射,最后看防火墙,这个排查顺序能解决九成问题。剩下一成,日志里找答案,社区里问,别自己闷头试到半夜,效率最高,身体也重要,真的。