Skip to content

11 | 数据持久化与挂载

可以替换,数据怎么办 ​

沿用多服务与网络的 delivery-demo。同样是 volumes,./site:/usr/share/nginx/html:ro 和 db-data:/var/lib/postgresql/data 的用途不同。

存储位置生命周期与用途本例
容器可写层属于当前容器,删除容器后不保留其修改临时文件,不作为业务数据目录
named volumeDocker 管理,独立于容器db-data 保存 PostgreSQL 数据
bind mount映射明确的宿主机路径./site 供开发时直接修改页面

卷的实际名称通常带项目名前缀。镜像也可能声明匿名卷,不能只看 Dockerfile 就推断数据一定在可写层;用 inspect 确认实际挂载。

验证重建不会删除数据 ​

确认数据库就绪后,在 Bash 中执行:

bash
docker compose exec -T db psql -U demo -d demo -v ON_ERROR_STOP=1 <<'SQL'
CREATE TABLE IF NOT EXISTS course_notes (id INTEGER PRIMARY KEY, note TEXT NOT NULL);
INSERT INTO course_notes VALUES (1, 'volume survives recreation')
ON CONFLICT (id) DO UPDATE SET note = EXCLUDED.note;
SQL
docker compose up -d --force-recreate db

等待 docker compose exec db pg_isready -U demo -d demo 成功,再验证:

bash
docker compose exec -T db psql -U demo -d demo -c 'SELECT * FROM course_notes;'
docker inspect "$(docker compose ps -q db)" --format '{{json .Mounts}}'

预期记录仍存在,挂载目标是 /var/lib/postgresql/data。数据库首次初始化后的密码保存在数据库状态中,只改 Compose 的 POSTGRES_PASSWORD 不会给已有账号改密码;更不能通过删除卷“修复”生产登录问题。

bind mount 与文件权限 ​

修改宿主机 site/index.html 后,再 curl 页面即可看到变化。因为目录被挂载进容器,本实验不需要重新构建镜像。

bash
docker compose exec web sh -c 'touch /usr/share/nginx/html/should-fail'

预期失败,证明 :ro 阻止容器修改该挂载。若读取失败,检查文件权限、父目录遍历权限和容器运行用户,不统一使用 chmod 777。

挂载目录还会遮住镜像中相同位置的内容。后续把 site COPY 进镜像时,应移除开发用的 site 挂载,否则你可能发布了新镜像,却仍然看到宿主机旧文件。Docker Desktop 的目录共享与 Linux 原生路径也有差异,迁移时要核对。

备份必须通过恢复验证 ​

本课用逻辑备份,避免直接复制正在写入的数据目录。下面只处理实验库,backups 中的文件也应按数据敏感性保护。

bash
umask 077
mkdir -p backups
docker compose exec -T db pg_dump -U demo -d demo > backups/demo.sql
# 使用新的实验数据库恢复,不覆盖原库;同名库已存在时先检查其用途。
docker compose exec -T db createdb -U demo demo_restore
docker compose exec -T db psql -U demo -d demo_restore -v ON_ERROR_STOP=1 < backups/demo.sql
docker compose exec -T db psql -U demo -d demo_restore -c 'SELECT * FROM course_notes;'

确认恢复库中记录与原库一致,并记录耗时。卷持久化只能应对容器替换,不能应对误删、磁盘损坏或错误 SQL;正式备份还要考虑异机保存、加密、保留周期与定期恢复演练。

常见存储故障排查 ​

现象原因排查
容器重启后数据消失数据写入了容器可写层,未挂载卷docker inspect 检查 Mounts,确认目标路径
新镜像部署后页面没更新开发时 ./site 挂载遮住了镜像内 COPY 的文件生产部署移除 bind mount,让页面来自镜像
down 后数据库密码不生效首次初始化的密码保存在卷状态中,改 POSTGRES_PASSWORD 不会覆盖不要通过删卷"修复"——先确认卷内数据用途
磁盘空间告警镜像、容器可写层或日志占用docker system df 查看各类占用,docker logs 检查日志大小

排查时先用 docker inspect 确认挂载状态,再判断数据流向。不要在不确定卷内容的情况下执行 docker volume rm 或 down -v。

哪些命令会影响数据 ​

操作本例的数据卷
docker compose stop保留
docker compose downnamed volume 默认保留
docker compose down -v会删除项目声明的卷,不能用于日常发布
docker volume prune可能清理其他项目未使用的卷,不作为本课清理方式

课程结束时可以执行 docker compose down,先保留数据用于复查。下一课将开发时的文件挂载改为镜像构建,并区分构建参数与配置。

参考:Docker volumes、bind mounts、PostgreSQL pg_dump。