在使用 Docker Compose 管理数据库、中间件等基础设施时,数据持久化是必须考虑的问题。PostgreSQL、Redis、Weaviate、Elasticsearch、MySQL——这些服务的数据默认存储在容器内部,当容器被删除,数据也会一起丢失。
Docker 本身的数据持久化机制(bind mount、named volume、tmpfs)在 Docker 数据管理与持久化 中已有整理,这里聚焦在 Compose 场景下的实践方式和项目结构设计。
两种挂载方式
Bind Mount
services:
postgres:
image: postgres:17
volumes:
- ./docker-data/postgres:/var/lib/postgresql/data格式是 宿主机目录:容器目录。以 ./ 开头的相对路径会解析为 docker-compose.yml 所在目录,因此不同项目之间不会冲突——项目 A 的 ./postgres_data 和项目 B 的 ./postgres_data 是两个完全不同的路径。
Named Volume
services:
postgres:
image: postgres:17
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:postgres_data 不是宿主机上的目录,而是 Docker 管理的 Volume。Docker Compose 会自动根据项目名加上前缀(如 traceops_postgres_data、blog_postgres_data),不同项目之间同样不会冲突。
在 macOS 上使用 Docker Desktop 时,Volume 实际存储在 Docker Desktop 虚拟机内的 /var/lib/docker/volumes,不直接暴露在 Mac 文件系统中。管理方式:
docker volume ls
docker volume inspect volume_nameBind Mount vs Named Volume
| 项目 | Bind Mount | Named Volume |
|---|---|---|
| 存储位置 | 当前项目目录 | Docker 管理 |
| 是否可见 | 可见 | 不直接可见 |
| 数据迁移 | 简单复制 | Docker 管理 |
| 跨平台 | 一般 | 更好 |
| 本地开发 | 更适合 | 一般 |
| 生产环境 | 一般 | 更适合 |
本地开发推荐方案
对于个人开发项目,使用 Bind Mount,将数据统一放在项目内的 docker-data/ 目录下:
项目根目录
├── docker-compose.yml
├── docker-data
│ ├── postgres
│ ├── redis
│ └── weaviate
├── backend
└── frontend
services:
postgres:
image: postgres:17
volumes:
- ./docker-data/postgres:/var/lib/postgresql/data
redis:
image: redis:7
volumes:
- ./docker-data/redis:/data
weaviate:
image: cr.weaviate.io/semitechnologies/weaviate:1.34.4
volumes:
- ./docker-data/weaviate:/var/lib/weaviate优点:数据位置清晰,删除容器不会丢数据,方便备份和迁移。
团队/企业项目推荐方案
团队项目通常使用 Named Volume:
volumes:
postgres_data:原因:不依赖开发者目录结构,避免权限问题,CI/CD 更友好,更接近生产部署方式。
几个实践细节
数据服务必须挂载 Volume,否则容器删除即数据丢失。
.gitignore 中排除数据目录:
docker-data/
.env密码不要写死在 compose 文件中,通过环境变量引用:
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}固定镜像版本,避免将来重建时版本漂移导致环境异常:
image: postgres:17 # 不写 postgres(latest)总结
核心原则:容器负责运行,Volume 负责保存数据,不要让数据库数据依赖容器生命周期。
个人学习和开发项目用 Bind Mount + 项目内 docker-data/ 目录,直观、易管理。团队生产环境用 Docker Named Volume。