目录① 导读卡片② 背景与目标容器数据为什么需要持久化不理解这个问题的后果学完你能做什么③ 概念与原理3.1 什么是卷Volume3.2 Docker 的两种卷类型3.3 Docker Compose 是如何区分两者的④ 逻辑与对比命名卷 vs 绑定挂载最全对比命名卷的完整关系图⑤ 核心详解5.1 命名卷Named Volume深入怎么创建命名卷命名卷的数据藏在哪命名卷的生命周期管理5.2 绑定挂载Bind Mount深入绑定挂载的权限问题5.3 命名卷的高级配置5.4 多命名卷实战⑥ 案例实战实战一Jenkins 数据持久化命名卷 vs 绑定挂载的对比实战二开发环境热加载绑定挂载典型场景实战三查看数据位置排错技巧⑦ 避坑 最佳实践常见坑点① 导读卡片一句话定位Docker 数据持久化的两种核心方式——命名卷Named Volume和绑定挂载Bind Mount到底有什么区别、怎么选、怎么用一文讲透。适合人群刚入门 Docker被volumes写法搞晕的开发者难度⭐⭐☆☆☆阅读时长12 分钟前置知识知道docker run和docker-compose.yml基本语法② 背景与目标容器数据为什么需要持久化Docker 容器的文件系统是临时性的——容器被删除后里面产生的所有数据都会丢失。这对以下场景是灾难性的数据库数据PostgreSQL、MySQL 的数据文件应用配置Jenkins、GitLab 的配置日志文件访问日志、错误日志为了解决这个问题Docker 提供了卷Volume机制把容器内的某个目录映射到宿主机上容器删了数据还在。不理解这个问题的后果你在看教程时一定会遇到两种写法version: 3.8 services: jenkins: volumes: - jenkins_home:/var/jenkins_home # 写法 A - /var/lib/jenkins:/var/jenkins_home # 写法 B两种写法看上去差不多但背后的行为完全不同。不理解它们的区别会导致找不到数据存在哪里权限问题反复报错教程里说得对但你运行结果不对学完你能做什么✅ 一眼分辨命名卷和绑定挂载✅ 知道数据实际存在宿主机的哪个位置✅ 根据场景选择正确的持久化方式✅ 彻底理解为什么有的文件需要sudo才能访问✅ 在一个docker-compose.yml里灵活混用两种卷③ 概念与原理3.1 什么是卷Volume卷 容器内目录与宿主机目录之间的映射桥梁。3.2 Docker 的两种卷类型Docker 提供两种卷区别只在于谁来指定宿主机上的路径类型宿主路径由谁指定语法特征命名卷Named VolumeDocker名字开头不带/绑定挂载Bind Mount用户以/、./、../开头3.3 Docker Compose 是如何区分两者的这是 Docker Compose 的语法规则写死了volumes: - jenkins_home:/var/jenkins_home # ✅ 命名卷名字不带 / - /var/lib/jenkins:/var/jenkins_home # ✅ 绑定挂载/ 开头 - ./data:/app/data # ✅ 绑定挂载./ 开头 - ../shared:/shared # ✅ 绑定挂载../ 开头 - myproject_jenkins_home:/data # ✅ 命名卷下划线不算路径分隔符判定规则极简左侧内容以/或./或../开头→ 绑定挂载 左侧内容不是以上述开头→ 命名卷这就是你写jenkins_home:/var/jenkins_home时Docker 把它当作卷名的原因。④ 逻辑与对比命名卷 vs 绑定挂载最全对比维度命名卷Named Volume绑定挂载Bind Mount语法卷名:容器路径/宿主机路径:容器路径数据存放/var/lib/docker/volumes/卷名/_data/你指定的路径创建方式Docker 自动创建需手动确保路径存在权限Docker 管理需sudo宿主机当前用户权限备份需要知道系统路径路径明确直接备份共享性多容器可共享多容器可共享便携性需导出/导入卷直接拷贝目录适用场景数据库、生产环境开发调试、配置文件注入命名卷的完整关系图Docker 引擎 │ ├── 卷管理 │ ├── vol_jenkins_home → 数据在 /var/lib/docker/volumes/vol_jenkins_home/_data/ │ ├── vol_postgres_data → 数据在 /var/lib/docker/volumes/vol_postgres_data/_data/ │ └── vol_redis_data → 数据在 /var/lib/docker/volumes/vol_redis_data/_data/ │ ├── 容器 A挂载 vol_jenkins_home、vol_redis_data ├── 容器 B挂载 vol_jenkins_home └── 容器 C挂载 vol_postgres_data核心特点一个命名卷可被多个容器同时挂载一个容器可挂载多个命名卷卷的生命周期独立于容器——容器删了卷还在Docker 可以管理任意数量的命名卷没有上限⑤ 核心详解5.1 命名卷Named Volume深入怎么创建命名卷方式一docker volume create独立创建docker volume create my_custom_volume # 查看卷列表 docker volume ls # 查看卷详情可以看到真实路径 docker volume inspect my_custom_volume输出示例[ { CreatedAt: 2024-01-15T10:00:00Z, Driver: local, Mountpoint: /var/lib/docker/volumes/my_custom_volume/_data, Name: my_custom_volume, Options: null, Scope: local } ]方式二docker run -v时自动创建docker run -v my_data:/app/data alpine # Docker 检查到 my_data 卷不存在自动创建方式三docker-compose.yml 中自动创建services: jenkins: volumes: - jenkins_home:/var/jenkins_home volumes: # 显式声明推荐 jenkins_home:命名卷的数据藏在哪# 默认路径 /var/lib/docker/volumes/项目名_卷名/_data/ # 例如项目文件夹叫 jenkins卷名 jenkins_home # 实际位置/var/lib/docker/volumes/jenkins_jenkins_home/_data/⚠️ 注意这个路径默认只有root可读。如果你直接用普通用户去访问会报Permission denied。解决办法# 方式一用 sudo sudo ls /var/lib/docker/volumes/jenkins_jenkins_home/_data/ # 方式二改用绑定挂载推荐调试用 # 把数据丢到自己用户目录下命名卷的生命周期管理# 列出所有卷 docker volume ls # 删除卷卷必须不被任何容器使用 docker volume rm my_custom_volume # 删除所有未被使用的卷 docker volume prune # 备份卷方法临时容器打包 docker run --rm -v my_data:/source -v $(pwd):/backup alpine tar czf /backup/my_data_backup.tar.gz -C /source .5.2 绑定挂载Bind Mount深入绑定挂载的关键好处是路径由你掌控services: nginx: volumes: # 挂载单个配置文件 - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro # 挂载整个目录开发时热加载 - ./html:/usr/share/nginx/html # 挂载日志目录 - ./logs:/var/log/nginxro标志挂载为只读防止容器内修改配置文件。绑定挂载的权限问题# ❌ 可能出错宿主目录不存在 volumes: - /my/custom/path:/app # 如果 /my/custom/path 不存在Docker 会创建它但可能权限不对 # ✅ 安全做法先创建目录 mkdir -p /home/user/jenkins_data chown -R 1000:1000 /home/user/jenkins_data # Jenkins 容器以 UID 1000 运行5.3 命名卷的高级配置在docker-compose.yml的顶级volumes中你可以做更多配置volumes: # 基本声明 basic_volume: # 使用外部已存在的卷不由 Compose 管理生命周期 external_volume: external: true # 指定卷驱动如 NFS、云存储驱动 nfs_volume: driver: local driver_opts: type: nfs o: addr192.168.1.100,rw device: :/path/to/nfs/share # 给卷加标签 labeled_volume: labels: environment: production backup: daily外部卷external: true的应用场景# 场景多个 Compose 项目共享同一个数据库卷 # 先用 docker volume create 创建 # docker volume create shared_postgres_data services: postgres: image: postgres:14 volumes: - shared_postgres_data:/var/lib/postgresql/data volumes: shared_postgres_data: external: true # 不创建新卷使用已存在的5.4 多命名卷实战一个docker-compose.yml里可以写任意多个命名卷version: 3.8 services: jenkins: image: jenkins/jenkins:lts volumes: - jenkins_home:/var/jenkins_home - jenkins_logs:/var/log/jenkins postgres: image: postgres:14 volumes: - postgres_data:/var/lib/postgresql/data - postgres_backup:/backup redis: image: redis:7-alpine volumes: - redis_data:/data volumes: # 所有命名卷在此声明 jenkins_home: jenkins_logs: postgres_data: postgres_backup: redis_data:即使不在顶级volumes中声明Compose 也会隐式创建卷。但显式声明是好习惯尤其是你需要在多个服务间共享卷你需要设置外部卷或驱动选项你想让docker compose down -v可预测地删除卷⑥ 案例实战实战一Jenkins 数据持久化命名卷 vs 绑定挂载的对比命名卷写法version: 3.8 services: jenkins: image: jenkins/jenkins:lts privileged: true user: root ports: - 8080:8080 volumes: - jenkins_home:/var/jenkins_home - /var/run/docker.sock:/var/run/docker.sock volumes: jenkins_home:数据位置/var/lib/docker/volumes/项目名_jenkins_home/_data/绑定挂载写法version: 3.8 services: jenkins: image: jenkins/jenkins:lts privileged: true user: root ports: - 8080:8080 volumes: - /opt/jenkins_data:/var/jenkins_home - /var/run/docker.sock:/var/run/docker.sock数据位置/opt/jenkins_data/你可以随时访问权限修复绑定挂载常见问题# Jenkins 容器内进程以 UID 1000 运行 # 如果宿主机目录权限不对会报 Permission denied sudo chown -R 1000:1000 /opt/jenkins_data实战二开发环境热加载绑定挂载典型场景version: 3.8 services: frontend: image: node:18 working_dir: /app command: npm run dev volumes: - ./frontend:/app # 绑定挂载代码修改立即同步到容器 - /app/node_modules # 匿名卷保护容器内 npm 安装的模块 backend: build: ./backend volumes: - ./backend:/app # 绑定挂载热加载 - /app/node_modules # 匿名卷保护 environment: - NODE_ENVdevelopment关键技巧说明volumes: - ./backend:/app # 宿主机项目的 ./backend 覆盖容器 /app - /app/node_modules # 注意这个没有宿主机路径第二行- /app/node_modules的作用是宿主机目录./backend先挂载到容器/appDocker 创建了一个匿名卷挂载到/app/node_modules由于更具体的挂载点优先/app/node_modules使用的是容器内原有的node_modules包含 npm 安装的包宿主机上可能没有node_modules避免了空目录覆盖导致模块丢失实战三查看数据位置排错技巧# 1. 找到命名卷的实际路径 docker volume inspect myproject_db_data # → Mountpoint: /var/lib/docker/volumes/myproject_db_data/_data/ # 2. 查看容器使用的挂载 docker inspect my_container | grep -A 10 Mounts # 3. 绑定挂载的数据路径 # 直接去你指定的路径看就好了