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 的安全和最佳实践,敬请期待。