
你跑了一个Nginx容器,-p 8080:80,以为能从宿主机IP的8080端口访问。结果访问不了。你检查了防火墙,检查了安全组,都没问题。那么问题出在Docker网络上。
Docker容器默认跑在一个虚拟网桥里,IP是172.17.x.x,和宿主机不在同一个网络。你想让容器直接用宿主机的网络,不想做端口映射。或者你想让两个容器之间通信,不想暴露端口给宿主机。
Docker提供了几种网络模式,各有用处。今天把它们聊透。
先看一个数据
在一次技术社区调查中,超过40%的Docker初学者曾因网络模式选错而导致服务无法访问。其中最常见的问题是:容器之间访问不了、端口映射不生效、宿主机网络不通。选择正确的网络模式,能避免90%的容器网络问题。
Docker网络模式概览
| 模式 | 说明 | 适用场景 |
|---|---|---|
bridge | 默认模式,容器通过虚拟网桥与宿主机通信,端口需映射 | 单机多容器通信 |
host | 容器直接使用宿主机网络栈,无端口映射 | 追求性能、需要直接使用宿主机端口 |
none | 无网络,只有loopback | 不需要网络的离线任务 |
container | 共享另一个容器的网络栈 | 调试、代理模式 |
overlay | 跨主机容器通信(Swarm/K8s) | 多机集群 |
日常最常用的是bridge和host。none用得少,但特定场景有用。container比较小众,今天主要聊前三者。
bridge模式:默认的选择
Docker安装后,会在宿主机创建一个虚拟网桥docker0,默认IP段172.17.0.0/16。每个新容器自动分配到172.17.x.x的IP。
如果什么都不配,容器内跑Nginx监听80端口,外面访问不了。你需要用-p 8080:80把宿主机的8080端口映射到容器的80端口。外部请求到达宿主机8080端口,Docker通过NAT转发到容器的80端口。
优点:隔离性好,容器有自己的网络命名空间,端口不会冲突。
缺点:端口映射有轻微性能损耗。
适用场景:大部分单机部署场景。
容器间通信:同一宿主机上的两个bridge容器,可以用--link或自定义网络,直接通过容器名互访。
host模式:性能优先
host模式下,容器直接使用宿主机的网络栈。没有网络隔离,没有端口映射。你在容器里监听80端口,就等于在宿主机上监听80端口。
优点:
- 性能好:没有NAT转换,网络延迟低,吞吐量高
- 端口直用:不需要
-p映射,容器端口自动暴露
缺点:
- 端口冲突:宿主机80端口被一个容器占了,其他容器就不能用host模式绑定80
- 安全性差:容器网络隔离被打破
适用场景:
- 追求极致网络性能(如网关、负载均衡器)
- 需要容器直接使用宿主机特定端口(如DHCP、VPN服务)
- 调试时临时用,方便看端口
启动命令:docker run --network host nginx
启动后访问宿主机IP直接看到Nginx页面,没有-p参数。
none模式:无网络
none模式下,容器只有lo环回接口,没有外部网络。用docker run --network none启动,容器内部ip a只能看到lo。
适用场景:
- 离线批量任务,不需要网络
- 生成静态文件、数据预处理
- 安全性要求极高,不允许任何网络访问的计算任务
实际例子:一个离线PDF生成容器,只读取输入文件、输出PDF,不访问任何外部服务。没必要给它网络,用none模式更安全。
注意:启动后docker exec -it 容器名 bash,测试ping google.com会失败。如果后面的任务需要网络,不要用none。
自定义bridge网络
Docker默认的bridge网络不支持容器名解析(需要--link,已废弃)。更好的做法:创建自定义bridge网络。
bash
docker network create mynet
运行容器时指定网络:
bash
docker run --network mynet --name app1 nginx docker run --network mynet --name app2 nginx
在app2容器里,可以直接ping app1,不需要--link。Docker内置DNS会自动解析。
适用场景:
- 多个容器需要互相通信
- 微服务架构
三种模式对比
| 特性 | bridge | host | none |
|---|---|---|---|
| 网络隔离 | 有 | 无 | 完全隔离 |
| 端口映射 | 需要 | 不需要 | 无端口 |
| 性能 | 中等(有NAT损耗) | 最高 | 不适用 |
| 容器间互访 | 可通过自定义网络 | 直接共享宿主机 | 不能 |
| 适用场景 | 大多数场景 | 高性能/特殊端口场景 | 离线任务 |
真实案例
一个日志收集服务,使用Filebeat容器收集宿主机日志。Filebeat需要访问宿主机网络栈来监听日志文件。如果用bridge模式,需要映射端口且容器内看到的网络是隔离的,不方便。改用host模式后,Filebeat直接读取宿主机的/var/log目录和网络流量,配置简单,性能好。
另一个案例是数据库容器(MySQL)。用bridge模式,映射3306端口到宿主机,外部应用通过宿主机IP:3306连接。这是标准做法。
常见问题
Q:bridge模式下容器ping不通外网?
A:检查宿主机IP转发是否开启sysctl net.ipv4.ip_forward,应该是1。Docker一般会自动配好。
Q:host模式下容器里看到的是宿主机IP?
A:是的。hostname也和宿主机一样。
Q:--network=container:另一个容器名有什么用?
A:共享另一个容器的网络栈。可用于调试(用busybox容器连到应用容器的网络,排查端口)。或代理模式。
Q:怎么查看容器当前网络模式?
A:docker inspect 容器名 | grep -A 10 NetworkSettings,看NetworkMode字段。
最后一句
Docker网络模式的选型原则:默认用bridge,端口不够用或要极致性能用host。不需要网络的任务用none。
大多数时候,你只需要记住:-p映射端口时用bridge,直接跑服务时考虑host。但注意host模式会打破容器和宿主机之间的网络隔离边界。
下次容器网络不通,先检查网络模式。很可能你用了host模式但以为自己在bridge,或者反过来。
把网络模式搞对,容器跑起来才不闹脾气。




