在使用 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_datablog_postgres_data),不同项目之间同样不会冲突。

在 macOS 上使用 Docker Desktop 时,Volume 实际存储在 Docker Desktop 虚拟机内的 /var/lib/docker/volumes,不直接暴露在 Mac 文件系统中。管理方式:

docker volume ls
docker volume inspect volume_name

Bind Mount vs Named Volume

项目Bind MountNamed 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。