4、Docker网络与存储:Docker网络模式(bridge、host、none、overlay)、数据卷(Volume)与绑定挂载、多容器通信(Docker Compose)
聊到容器化部署,网络和存储是绕不开的两座大山。很多新手刚接触 Docker 时,总觉得容器跑起来就行,网络不通?挂载失败?重启大法好。但真正上了生产环境,你会发现这两块才是翻车重灾区。今天我就结合自己的实战经验,把 Docker 网络和存储这块掰开揉碎了讲清楚。
4.1 Docker 网络模式:四种模式,四种哲学
Docker 的网络模式,说白了就是决定「容器怎么连上外面,容器之间怎么互相找」。我见过不少团队,所有容器一股脑全用默认 bridge,结果端口冲突、IP 写死,维护起来想骂人。我们先看看这四种模式到底怎么选。
4.1.1 bridge 模式:最常用的「小局域网」
这是 Docker 默认的网络模式。每个容器会分配一个独立的 IP,比如 172.17.0.x。容器之间可以通过 IP 通信,但对外访问需要端口映射。
我个人的习惯:开发环境用 bridge 完全够用。但要注意,容器重启后 IP 会变,所以别在代码里写死容器 IP。我在项目中遇到过,有人把数据库容器的 IP 写死在配置里,结果一重启,整个应用全连不上——那叫一个酸爽。
核心命令:
# 创建自定义 bridge 网络(推荐)
docker network create my-bridge
# 启动容器并指定网络
docker run -d --name web --network my-bridge nginx
# 端口映射
docker run -d --name web -p 8080:80 nginx
避坑指南:我曾经踩过一个坑——默认 bridge 网络不支持容器名解析。也就是说,容器 A 没法通过容器名「web」直接访问容器 B。但自定义 bridge 网络可以!所以,生产环境一定要用自定义 bridge,别偷懒用默认的。
4.1.2 host 模式:直接共享宿主机网络
host 模式,容器直接使用宿主机的网络栈。没有独立 IP,没有端口映射,容器里监听 80 端口,宿主机就是 80 端口。
什么时候用? 对网络性能要求极高的场景,比如一些网络监控工具、高性能代理。但代价是隔离性差,端口冲突风险大。
我记得有一次帮客户优化一个日志采集服务,容器跑在 bridge 模式下,网络吞吐死活上不去。改成 host 模式后,性能直接翻倍。嗯,这就是 host 模式的用武之地。
注意:host 模式下,容器里看到的网络设备就是宿主机的。如果你在宿主机上跑了多个容器都用 host 模式,端口冲突是迟早的事。我建议只在特定场景下用,别当默认选项。
4.1.3 none 模式:完全隔离的「孤岛」
none 模式,容器没有网络接口,只有 lo(回环接口)。说白了,它就是个与世隔绝的容器。
你可能会问:这有什么用?其实很有用。比如一些离线计算任务、安全沙箱、或者你只想让容器跑个一次性脚本,完全不需要网络。我曾在安全审计场景下用过,容器跑敏感数据处理,不连任何网络,数据安全有保障。
4.1.4 overlay 模式:跨主机的「大内网」
overlay 模式是 Swarm 和 Kubernetes 的底层网络基础。它能让不同宿主机上的容器,像在同一个局域网里一样通信。
这个模式我用的最多的是在 Swarm 集群里。你想想看,几十台宿主机,上千个容器,如果每个容器都要通过宿主机 IP + 端口去访问,那配置量简直不敢想。overlay 网络让容器通过服务名直接访问,底层自动路由。
创建 overlay 网络:
# 需要先初始化 Swarm 集群
docker swarm init
# 创建 overlay 网络
docker network create -d overlay my-overlay
# 启动服务
docker service create --name web --network my-overlay nginx
4.2 数据持久化:Volume 与绑定挂载
容器是「用完即弃」的,但数据不行。数据库的数据、日志文件、配置文件,这些都得持久化。Docker 提供了两种方式:Volume 和绑定挂载。
4.2.1 Volume(数据卷):Docker 官方推荐
Volume 由 Docker 管理,存储在宿主机特定目录(通常是 /var/lib/docker/volumes/)。它的好处是:跨平台、备份方便、权限管理好。
我个人强烈推荐:只要不是特殊需求,优先用 Volume。为什么?因为绑定挂载容易出权限问题。我曾经在项目中,用绑定挂载把宿主机目录挂进容器,结果容器里的进程没权限写文件,排查了半天才发现是 UID 不匹配。用 Volume 就没这破事。
常用命令:
# 创建数据卷
docker volume create my-volume
# 挂载数据卷
docker run -d --name db -v my-volume:/var/lib/mysql mysql
# 查看数据卷信息
docker volume inspect my-volume
4.2.2 绑定挂载:灵活但需谨慎
绑定挂载就是把宿主机上的一个目录或文件,直接挂到容器里。开发时很方便,因为你可以实时修改代码,容器里立刻生效。
但要注意:绑定挂载会覆盖容器内的目录。如果你把宿主机空目录挂到 /etc/nginx,那容器里原来的 nginx 配置就没了。我见过有人把整个 /var/log 挂进去,结果容器日志全丢了——因为宿主机目录是空的。
避坑指南:我曾经在生产环境犯过一个低级错误——用绑定挂载挂载了宿主机上的一个 NFS 目录。结果 NFS 网络抖动,容器直接卡死,整个服务挂了半小时。从那以后,生产环境我尽量用 Volume,绑定挂载只用在开发调试。
| 特性 | Volume | 绑定挂载 |
|---|---|---|
| 管理方式 | Docker 管理 | 用户管理 |
| 备份迁移 | 方便 | 需手动处理 |
| 权限问题 | 较少 | 常见 |
| 适用场景 | 生产环境、数据库 | 开发调试、配置文件 |
4.3 多容器通信:Docker Compose 实战
单个容器好管,但真实应用往往是多个容器协作:前端、后端、数据库、缓存、消息队列……手动一个个启动、配置网络,太累了。这时候 Docker Compose 就派上用场了。
Docker Compose 通过一个 docker-compose.yml 文件,定义所有服务、网络、数据卷。一条命令就能拉起整个应用栈。
4.3.1 一个典型的 Web 应用示例
我拿一个常见的 Web 应用举例:Nginx + PHP + MySQL。你想想看,如果手动搞,得先建网络、再启动三个容器、配置链接……用 Compose 就简单多了。
docker-compose.yml:
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
networks:
- app-net
app:
image: php:7.4-fpm
volumes:
- ./html:/var/www/html
networks:
- app-net
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: myapp
volumes:
- db-data:/var/lib/mysql
networks:
- app-net
volumes:
db-data:
networks:
app-net:
看到没?networks 定义了同一个网络 app-net,三个服务都在这个网络里。容器之间通过服务名(web、app、db)直接通信,不用记 IP。
我的经验:我习惯在 Compose 文件里显式声明网络和数据卷,而不是用默认的。这样后期扩容、迁移都方便。而且,depends_on 这个配置要注意——它只控制启动顺序,不等待服务就绪。比如 db 容器启动了,但 MySQL 还没初始化完成,app 连上去就会报错。我一般会在应用层做重试机制。
4.3.2 常用 Compose 命令
# 启动所有服务
docker-compose up -d
# 查看日志
docker-compose logs -f
# 停止并删除
docker-compose down
# 只重启某个服务
docker-compose restart web
4.3.3 多容器通信的底层原理
你可能会好奇:Compose 是怎么让容器互相找到的?其实底层就是 Docker 的 DNS 解析。当容器加入同一个自定义网络时,Docker 内置的 DNS 服务器会自动把服务名解析成容器 IP。
说白了,你在 Compose 里定义的服务名,就是容器在网络里的「主机名」。app 容器里访问 db:3306,就能连上 MySQL。这个机制在 Swarm 和 Kubernetes 里也是类似的思路。
注意:如果你用默认的 bridge 网络,这个 DNS 解析是不生效的。所以再次强调:生产环境一定要用自定义网络。我曾经见过有人把 Compose 里的服务名写成了 IP 地址,结果容器重启后全连不上——这就是没理解 DNS 解析的原理。
4.4 小结
Docker 网络和存储,说难不难,说简单也不简单。核心就几点:
- 网络:开发用 bridge,高性能用 host,隔离用 none,集群用 overlay。自定义网络是王道。
- 存储:生产环境优先用 Volume,开发调试用绑定挂载。注意权限和路径覆盖问题。
- 多容器通信:Docker Compose 是利器,服务名就是主机名,别写死 IP。
嗯,这些经验都是我一个个坑踩出来的。希望你能少走弯路。下一章我们聊聊 Docker 的安全和最佳实践,敬请期待。