如何在多个不同的容器之间共享同一个数据卷或宿主机目录?
在 Docker 中,在多个不同的容器之间共享同一个数据卷(Volume)或宿主机目录是非常常见且实用的需求(例如:一个容器写日志,另一个容器收集日志;或者多个 Web 容器共享静态资源)。
主要有以下两种方式来实现共享:
方式一:使用 Docker 命名数据卷(Named Volumes)—— 推荐
这是 Docker 官方推荐的方式。数据卷由 Docker 引擎管理,具有更好的移植性、性能和安全性。
1. 命令行(CLI)实现
首先,创建一个命名数据卷:
bash
docker volume create my-shared-volume
然后,在启动多个容器时,都将这个数据卷挂载到它们各自的目录中:
- 启动容器 A(向卷中写入数据):bash
docker run -d --name container_a -v my-shared-volume:/app/data alpine sh -c "while true; do echo 'Hello from A' >> /app/data/log.txt; sleep 5; done" - 启动容器 B(从同一个卷中读取数据):bash
docker run -d --name container_b -v my-shared-volume:/app/read_data alpine sh -c "tail -f /app/read_data/log.txt"
注意:容器 A 挂载到了 /app/data,容器 B 挂载到了 /app/read_data,它们指向的是同一个物理存储,路径可以不同。
2. Docker Compose 实现(最常用)
如果你使用 Docker Compose,定义共享卷非常简单:
yaml
version: '3.8'
services:
web:
image: nginx:alpine
volumes:
- shared-assets:/usr/share/nginx/html
app:
image: node:alpine
volumes:
- shared-assets:/usr/src/app/public
volumes:
shared-assets: # 在最外层定义共享卷
2. 方式二:挂载同一个宿主机目录(Bind Mounts)
如果你希望直接在宿主机上看到和修改这些文件,可以直接将宿主机的某个绝对路径挂载到多个容器中。
1. 命令行(CLI)实现
假设宿主机目录为 /home/user/shared_dir(确保该目录已存在):
- 启动容器 A:bash
docker run -d --name container_a -v /home/user/shared_dir:/data1 alpine sh -c "touch /data1/file_from_a.txt" - 启动容器 B:bash
docker run -d --name container_b -v /home/user/shared_dir:/data2 alpine sh -c "ls /data2"
2. Docker Compose 实现
yaml
version: '3.8'
services:
service_a:
image: alpine
volumes:
- /home/user/shared_dir:/app/data
command: tail -f /dev/null
service_b:
image: alpine
volumes:
- /home/user/shared_dir:/app/backup
command: tail -f /dev/null
3. 进阶技巧:只读挂载(Read-Only)
在多容器共享数据时,为了安全起见,通常只有一个容器负责写入,其他容器负责读取。你可以将读取端的容器设置为“只读”挂载。
在挂载路径后面加上 :ro 即可:
- 命令行:bash
docker run -d --name reader_container -v my-shared-volume:/data:ro alpine - Docker Compose:yaml
services: reader: image: alpine volumes: - shared-assets:/data:ro # ro 表示 read-only
总结与选择
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 命名数据卷 (Volume) | 1. Docker 管理,跨平台兼容性好 2. 性能更好 3. 方便备份和迁移 |
在宿主机上不容易直接定位到具体的文件路径(默认在 /var/lib/docker/volumes/ 下) |
容器间的数据传递、数据库持久化、不需要人工频繁修改宿主机文件的场景。 |
| 绑定挂载 (Bind Mount) | 1. 宿主机路径直观,方便人工直接修改和查看文件 | 1. 依赖宿主机的目录结构,移植性差 2. 可能引入权限问题(UID/GID 不一致) |
开发环境、需要读取宿主机上的配置文件或源代码、收集日志。 |