Docker 常见挂载方式有三种:volumebind mounttmpfs

参考:

快速结论

类型 位置由谁管理 数据生命周期 适合场景
volume Docker 独立于容器,容器删除后默认保留 数据库、消息队列、应用持久化数据
bind mount 用户指定宿主机路径 跟宿主机文件一致 源码、配置文件、本地调试
tmpfs 内存 容器停止后消失 临时缓存、敏感临时文件

选择原则:

1
2
3
持久化数据 -> volume
宿主机文件映射 -> bind mount
只要内存临时数据 -> tmpfs

容器自身的可写层跟容器生命周期绑定。只要数据需要脱离容器生命周期,就应该挂载出来。

Volume mount

volume 是 Docker 管理的数据目录,适合放数据库和中间件数据。

1
2
3
4
5
6
docker volume create redis-data

docker run -d \
--name redis \
--mount type=volume,source=redis-data,target=/data \
redis

Compose 写法:

1
2
3
4
5
6
7
8
services:
redis:
image: redis
volumes:
- redis-data:/data

volumes:
redis-data:

常用命令:

1
2
docker volume ls
docker volume inspect redis-data

Bind mount

bind mount 是把宿主机上的文件或目录直接挂进容器。

1
2
3
docker run --rm -it \
--mount type=bind,source="$PWD",target=/app \
node:22 bash

Compose 写法:

1
2
3
4
5
6
services:
app:
image: node:22
working_dir: /app
volumes:
- .:/app

注意:

  • 宿主机和容器会看到同一份文件。
  • 容器进程可能修改宿主机文件。
  • 权限问题比 volume 更常见。
  • Docker Desktop + WSL 场景下,优先挂载 WSL 文件系统路径,例如 ~/workspace/<project>,不要长期把主力项目放在 /mnt/c/... 下运行。

tmpfs mount

tmpfs 是内存挂载,不写入宿主机磁盘。

1
2
3
docker run --rm \
--mount type=tmpfs,target=/tmp/cache \
alpine

Compose 写法:

1
2
3
4
5
services:
app:
image: alpine
tmpfs:
- /tmp/cache

适合临时缓存、运行时临时文件、敏感临时数据。

-v--mount

-v--mount 是两种写法,不是两种挂载类型。

1
2
3
4
5
6
7
# volume
docker run -v redis-data:/data redis
docker run --mount type=volume,source=redis-data,target=/data redis

# bind mount
docker run -v "$PWD":/app node:22
docker run --mount type=bind,source="$PWD",target=/app node:22

写文档和学习时建议优先用 --mount,因为 type=volume|bind|tmpfs 更清楚。

判断 -v 的类型:

1
2
左边是 volume 名称 -> volume
左边是宿主机路径 -> bind mount

常见判断

1
2
3
4
5
6
7
-v redis-data:/data  -> volume
-v "$PWD":/app -> bind mount

容器可写层 -> 容器删除后通常消失
volume -> 容器删除后默认保留
bind mount -> 数据保留在宿主机路径
tmpfs -> 容器停止后消失

生产持久化数据优先考虑 volumebind mount 更适合开发调试、配置文件,或者明确需要访问宿主机固定路径的场景。

Redis 和 MySQL 挂载实践

开发环境可以用同一套规则:

1
2
3
4
数据目录 -> volume
配置目录 -> bind mount,只读
初始化脚本 -> bind mount,只读
日志目录 -> 默认不挂,先用 docker logs

常见目录:

服务 容器目录 用途 推荐挂载
Redis /data RDB / AOF 数据目录 volume
Redis /usr/local/etc/redis 自定义配置目录 bind mount,只读
MySQL /var/lib/mysql 数据目录 volume
MySQL /etc/mysql/conf.d 自定义配置目录 bind mount,只读
MySQL /docker-entrypoint-initdb.d 初始化脚本目录 bind mount,只读
MySQL /var/log/mysql 日志目录 开发环境通常不挂

版本选择:

服务 日常开发推荐 说明
Redis redis:8.8 当前 8.x 稳定线;项目没有明确约束时优先用它
MySQL mysql:8.4 LTS 线,兼容性通常比直接追新大版本更稳

不要在项目配置里使用 latest。如果需要完全可复现,可以进一步锁定 patch 版本,例如 redis:8.8.0mysql:8.4.9。版本最终以项目生产环境和团队约定为准。

推荐项目结构:

1
2
3
4
5
6
7
8
9
10
11
my-project/
├── docker-compose.yml
├── redis/
│ └── conf/
│ └── redis.conf
└── mysql/
├── conf/
│ └── my.cnf
└── init/
├── 01-schema.sql
└── 02-data.sql

项目目录只放配置和初始化脚本;真实数据放 Docker volume,不放 redis/data/mysql/data/

Redis 配置示例:

1
2
dir /data
appendonly yes

MySQL 配置示例:

1
2
3
4
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
default-time-zone=+08:00

推荐 Compose 写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
services:
redis:
image: redis:8.8
container_name: redis-dev
ports:
- "6379:6379"
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
volumes:
- redis-data:/data
- ./redis/conf:/usr/local/etc/redis:ro

mysql:
image: mysql:8.4
container_name: mysql-dev
ports:
- "3307:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: app
volumes:
- mysql-data:/var/lib/mysql
- ./mysql/conf:/etc/mysql/conf.d:ro
- ./mysql/init:/docker-entrypoint-initdb.d:ro

volumes:
redis-data:
mysql-data:

单独用 docker run 时:

1
2
3
4
5
6
7
8
docker volume create redis-data

docker run -d \
--name redis-dev \
-p 6379:6379 \
--mount type=volume,source=redis-data,target=/data \
--mount type=bind,source="$PWD/redis/conf",target=/usr/local/etc/redis,readonly \
redis:8.8 redis-server /usr/local/etc/redis/redis.conf
1
2
3
4
5
6
7
8
9
10
docker volume create mysql-data

docker run -d \
--name mysql-dev \
-p 3307:3306 \
-e MYSQL_ROOT_PASSWORD=root \
--mount type=volume,source=mysql-data,target=/var/lib/mysql \
--mount type=bind,source="$PWD/mysql/conf",target=/etc/mysql/conf.d,readonly \
--mount type=bind,source="$PWD/mysql/init",target=/docker-entrypoint-initdb.d,readonly \
mysql:8.4

关键注意:

  • 不要直接覆盖整个 /etc/mysql,自定义配置放 /etc/mysql/conf.d
  • /docker-entrypoint-initdb.d 只在空数据目录首次初始化时执行。
  • 开发环境先用 docker logs redis-devdocker logs mysql-dev 看日志;只有明确把日志写到文件时,才挂日志目录。
  • 不建议默认使用 /mydata/redis/data:/data/mydata/mysql/data:/var/lib/mysql。这能跑,但权限、备份、迁移和误删都要自己处理。

如果确实要重新初始化数据库:

1
2
docker rm -f mysql-dev
docker volume rm mysql-data

这个操作会删除数据库数据。

如果项目必须使用 MySQL 5.7,就改成:

1
image: mysql:5.7

新项目不建议默认选 MySQL 5.7,版本应跟实际运行环境一致。

快速检查

1
2
3
docker inspect <container>
docker volume ls
docker volume inspect <volume>

清理未使用 volume 前要确认数据价值:

1
docker volume prune