前尘往事:
Docker 真香定律:Windows 开发者如何用容器偷懒高效工作
Docker 进阶指南-Windows版:从镜像定制到容器编排,手把手带你玩转 Docker 实战
零、前言
如果你已经跟着前几篇文章跑起来了 Flask 应用和 Redis 容器,可能已经用到过 docker network create my-network 这样的命令。你是否有这样的疑问:
- 为什么容器之间可以通过容器名互相访问?
- 默认的
bridge网络和自定义网络有什么区别? - 容器怎么访问宿主机的服务?
- 多个宿主机上的容器能互相通信吗?
这篇指南将为你揭开 Docker 网络的神秘面纱,通过几个实战场景,逐步掌握 Docker 网络的使用。
一、Docker 网络模型简介
Docker 在安装时会创建三种默认网络,你可以用 docker network ls 查看:
powershell
docker network ls
输出:
NETWORK ID NAME DRIVER SCOPE
e3f5e6f8b9a7 bridge bridge local
2b3c4d5e6f7g host host local
7a8b9c0d1e2f none null local
- bridge :默认网络。每个容器启动时如果不指定网络,就会加入这个网络。容器之间可以通过 IP 通信,但不能通过容器名通信。
- host:容器直接使用宿主机的网络栈,没有网络隔离。
- none:容器没有网络接口,完全隔离。
实际开发中,我们最常用的是自定义 bridge 网络。它比默认 bridge 功能更强,容器之间可以通过容器名互相发现,还能自定义 IP 地址范围。
二、Docker 网络驱动简介
Docker 支持多种网络驱动,最常用的有:
| 驱动 | 说明 | 适用场景 |
|---|---|---|
| bridge | 默认驱动,在单机上的容器间通信 | 单机开发、测试 |
| host | 容器共享宿主机网络栈 | 性能要求高,不想有额外网络开销的场景 |
| overlay | 跨多台 Docker 主机的容器通信 | 多机集群(Swarm 或 Kubernetes) |
| macvlan | 为容器分配 MAC 地址,使其像物理设备一样接入网络 | 需要容器直接出现在物理网络中的场景 |
| none | 禁用网络 | 隔离容器 |
本篇文章重点讲解 bridge 和 host 驱动,以及如何创建和使用自定义 bridge 网络。
三、实战:创建自定义网络
我们从一个最简单的场景开始:两个容器需要在同一个网络中,通过容器名互相访问。
3.1 创建自定义网络
powershell
docker network create my-net
查看创建的网络:
powershell
docker network ls

3.2 运行两个容器并加入网络
powershell
docker run -d --name redis-0331 --network my-net-0331 redis
docker run -d --name app-0331 --network my-net-0331 -p 5000:5000 flask-app-0331
注:
flask-app-0331是制作的镜像,可参考 Docker 真香定律:Windows 开发者如何用容器高效工作 这篇文章如何制作镜像。
现在,在 app-0331 容器内部,可以通过 redis-0331 这个主机名访问 Redis 容器。进入 app 容器测试:
powershell
PS D:\> docker exec -it app-0331 bash
root@df63769307b6:/app# getent hosts redis-0331
172.20.0.2 redis-0331
root@df63769307b6:/app#
容器名解析成功。
3.3 检查网络详情
powershell
docker network inspect my-net-0331
输出会显示这个网络下所有容器的名称、IP 地址等信息。你会看到容器名被自动解析为 IP。
json
PS D:\> docker network inspect my-net-0331
[
{
"Name": "my-net-0331",
"Id": "218584c3e80f6942c8c6321e96445bf56de2558cc539f22afbaccfa8ab3d8b62",
"Created": "2026-03-31T12:24:38.165057052Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv4": true,
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.0.0/16",
"Gateway": "172.20.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Options": {
"com.docker.network.enable_ipv4": "true",
"com.docker.network.enable_ipv6": "false"
},
"Labels": {},
"Containers": {
"3a65f9dddb9a00beb57510e4d69b419eaef670017f1aa09599385b9b04497ec7": {
"Name": "redis-0331",
"EndpointID": "8f47cc159861daeb59d685fb1a21afcae77c98e06b7d723726ac9bbcb5d56b6b",
"MacAddress": "3a:23:84:e0:75:89",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
},
"df63769307b65d20e79e234cd8c850cfe7dd7d60c7c94200a6d207c66f5a829d": {
"Name": "app-0331",
"EndpointID": "bc62eb76e80b6becaed2ced109153a9b6e66a3daff5b50e4237c3f949fa1830c",
"MacAddress": "fe:37:13:6b:65:75",
"IPv4Address": "172.20.0.3/16",
"IPv6Address": ""
}
},
"Status": {
"IPAM": {
"Subnets": {
"172.20.0.0/16": {
"IPsInUse": 5,
"DynamicIPsAvailable": 65531
}
}
}
}
}
]
3.4 优势总结
- 使用自定义网络后,容器之间可以通过容器名直接通信,无需知道 IP。
- 网络内的容器可以互相访问,但外部无法直接访问(除非通过端口映射
-p)。 - 网络可以被多个容器共享,并且支持动态添加/移除容器。
四、网络连接与断开
有时你需要让一个已经运行的容器加入某个网络,或者从网络中移除。
4.1 将容器连接到已有网络
powershell
docker network connect my-net-0331 my-container
4.2 断开连接
powershell
docker network disconnect my-net my-container
4.3 实战:把 Redis 容器连接到两个网络
假设你已经有一个 Redis 容器运行在 my-net 中,现在需要它也能被另一个网络 other-net 中的容器访问:
powershell
docker network create other-net
docker network connect other-net redis
现在 redis 容器同时属于两个网络,两个网络内的容器都可以通过 redis 这个名字访问它。这在微服务架构中很常见。
五、容器如何访问宿主机服务?
有时候容器需要访问宿主机上运行的服务(比如一个本地的 MySQL 数据库,没有容器化)。默认情况下,容器内的 localhost 指的是容器自身,不是宿主机。
解决方案:
- 在 Linux 上,使用
host.docker.internal这个特殊域名。 - 在 Windows / macOS 上,Docker Desktop 也支持
host.docker.internal。
例如,如果你的宿主机上运行着 MySQL 并监听 3306 端口,在容器内可以这样连接:
python
import mysql.connector
conn = mysql.connector.connect(
host="host.docker.internal",
port=3306,
user="root",
password="secret"
)
注意 :在 Linux 上,如果使用 --network host 模式,容器可以直接使用 localhost 访问宿主机,但会失去网络隔离。通常推荐使用 host.docker.internal。
六、端口映射深入理解
我们经常用 -p 8080:80 把容器的 80 端口映射到宿主机的 8080。这个映射其实是在 宿主机网络命名空间 和 容器网络命名空间 之间建立了一个转发规则。
6.1 原理
- 当外部访问宿主机的 8080 端口时,请求被转发到容器的 80 端口。
- 容器内部不需要做任何特殊配置,它仍然认为自己在监听 80 端口。
- 一个容器可以映射多个端口:
-p 8080:80 -p 8443:443。
6.2 查看端口映射
powershell
docker port 容器名
输出类似:
80/tcp -> 0.0.0.0:8080
powershell
PS D:\> docker port app-0331
5000/tcp -> 0.0.0.0:5000
5000/tcp -> [::]:5000
6.3 绑定到特定 IP
默认端口映射会监听宿主机的所有 IP 地址。如果只想让本机访问,可以绑定到 127.0.0.1:
powershell
docker run -p 127.0.0.1:8080:80 ...
这样只有本机可以访问,局域网其他机器无法访问。
七、host 网络模式
如果你希望容器与宿主机共享网络栈(没有网络隔离),可以使用 --network host。
powershell
docker run --network host nginx
此时容器内的 localhost 就是宿主机的 localhost,容器不需要 -p 映射端口,因为它的网络直接就是宿主机的网络。
适用场景:
- 性能要求极高,不想经过 Docker 的网络虚拟化。
- 需要监听大量端口,不想一个一个映射。
- 容器需要访问宿主机的某些服务,且
host.docker.internal无法使用(比如某些 Linux 环境)。
缺点:
- 容器之间网络隔离消失,容易冲突。
- 容器与宿主机共享端口空间,如果宿主机上某个端口被占用,容器也无法启动。
八、none 网络模式
完全禁用网络。容器只能通过 --network none 启动,这样的容器没有网络接口,无法对外通信。
powershell
docker run --network none busybox ip addr
只看到 lo 回环接口。
适用场景:极度安全的场景,容器不需要任何网络访问,比如只做离线计算的容器。
九、跨主机通信简介
单机 Docker 的网络很简单,但生产环境往往需要多台机器上的容器互相通信。这需要用到 overlay 网络驱动。
9.1 Overlay 网络基础
- 需要 Docker Swarm 或 Kubernetes 等编排工具。
- 通过 VXLAN 等隧道技术,让不同主机上的容器感觉像在同一个二层网络中。
- 容器之间可以通过服务名互相发现(内置 DNS)。
9.2 简单示例(使用 Docker Swarm)
powershell
# 初始化 Swarm
docker swarm init
# 创建 overlay 网络
docker network create -d overlay my-overlay
# 在不同节点上部署服务,服务会加入该网络
docker service create --name web --network my-overlay --replicas 3 nginx
Swarm 会自动处理服务发现和负载均衡。对于普通开发者,了解 overlay 的存在即可,深入使用通常结合生产环境。
十、常见网络问题与排查
10.1 容器无法访问外网
检查 Docker 守护进程是否配置了 DNS。默认容器使用宿主机的 DNS 配置。如果宿主机 DNS 有问题,可以启动容器时指定:
powershell
docker run --dns 8.8.8.8 ...
10.2 端口映射不生效
- 确认宿主机防火墙是否允许该端口。
- 确认没有其他程序占用该端口(可以用
netstat -ano | findstr :8080查看)。 - 检查容器是否确实在监听正确的端口(
docker logs查看日志)。
10.3 容器之间 ping 不通
- 确认两个容器在同一个自定义网络中(不是默认 bridge)。
- 尝试用 IP 而不是容器名测试,排除 DNS 问题。
- 检查容器内是否有防火墙规则(通常没有)。
10.4 如何修改已运行容器的网络?
不能直接修改,需要先停止、删除,然后重新创建时指定网络。但可以通过 docker network connect 将容器加入额外网络(前提是容器启动时已经有一个网络)。
10.5 删除网络失败
如果网络正在被容器使用,无法删除。需要先断开所有容器:
powershell
docker network disconnect 网络名 容器名
docker network rm 网络名
十一、小结
- 始终使用自定义网络,而不是默认 bridge。这样容器名解析、网络隔离、动态连接都更灵活。
- 合理规划网络:不同项目使用不同的网络,避免服务发现混乱。
- 开发时使用
--network host要谨慎,容易忽略环境差异。 - 端口映射尽量绑定到
127.0.0.1,除非需要对外暴露。 - 定期清理无用网络 :
docker network prune会删除所有未使用的网络。
别忘了点赞、收藏、转发 哦!