Skip to content

写给懒猫微服玩家的容器小书 Docker篇(四):《数据之岛与持久化卷》

一直想写一本容器小书,真好懒猫基本都做了容器化,所以把这部分分享出来。不同的是,懒猫微服中使用 pg-docker 来替代 docker 命令,使用 dockge 来执行 docker-compose。以下讲解以标准 docker 为主,这样子既学会了 docker 知识,也能够在懒猫微服上启动 Docker 服务。

《数据之岛与持久化卷》讲的是 Docker Volume 持久化数据方案、挂载宿主机目录、多个容器共享数据、自动创建卷、数据备份与恢复等

🏝️ 开篇:数据会随浪消失

有一天,小李运行了一个容器,里面的 Flask 项目能正常写入用户信息到 SQLite 数据库。可当容器一停止,再启动——所有数据消失了!

老周说:“你的数据,被潮水带走了。”

“Docker 容器默认的文件系统是临时的,只要容器删除,数据也就没了。想让数据真正存活,就要登上‘数据之岛’。”


🧠 基础概念:数据卷(Volume)

Docker 提供了三种数据持久化方案:

方案用法场景
VolumeDocker 管理的专属数据区最推荐、安全、可多容器共享
Bind Mount映射宿主机目录更灵活,适合本地调试
tmpfs临时存储在内存适合敏感数据,重启即丢弃

本章重点讲解:Volume(数据卷)Bind Mount(绑定挂载)


📦 第一节:使用 Volume 保存数据

小李重新部署了 MySQL 容器,他决定为数据提供一个“保命空间”。

bash
docker volume create mysql-data

然后运行 MySQL 时挂载:

bash
docker run -d --name my-mysql \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -v mysql-data:/var/lib/mysql \
  mysql:5.7

-v 卷名:容器内目录:将卷挂载到容器内数据库文件存储位置。

容器即使删除,数据卷依然保留!

查看所有卷:

bash
docker volume ls

查看卷详细信息:

bash
docker volume inspect mysql-data

输出中可以看到 Mountpoint,即数据在宿主机上的物理位置。


🧪 第二节:自动创建匿名/具名卷

小李写了个简单的服务:

dockerfile
VOLUME /app/data

每次 docker run 时,Docker 会自动生成匿名卷挂载到 /app/data

但这类匿名卷难以追踪、管理,老周建议:

“生产环境请用具名卷,并在运行时用 -v 显式指定。”


🔗 第三节:绑定挂载宿主机目录(本地调试神器)

开发中,小李想把宿主机的项目代码直接挂进容器,不必每次重建镜像。

bash
docker run -d --name dev-nginx \
  -p 8080:80 \
  -v /Users/xiaoli/site:/usr/share/nginx/html \
  nginx

本地 /Users/xiaoli/site 的代码实时反映在容器内网站目录,修改立刻生效!

使用 Bind Mount 的场景:

  • 本地开发热更新
  • 日志文件落盘
  • 配置文件映射
  • IDE + 容器联调

🤝 第四节:多个容器共享数据卷

老周给小李展示了另一个高级玩法:

“多个容器可以挂载同一个卷,共享数据,就像一块公共磁盘。”

小李准备两个容器:

  • 一个容器写入日志
  • 一个容器实时读取日志
bash
# 写入容器
docker run -d --name logger \
  -v shared-logs:/logs \
  busybox sh -c "while true; do date >> /logs/t.log; sleep 2; done"

# 读取容器
docker run -it --name reader \
  -v shared-logs:/logs \
  busybox tail -f /logs/t.log

这两个容器在不联网的情况下,通过挂载卷实现了数据同步,让小李直呼神奇。


🔄 第五节:备份与恢复数据卷

老周说:

“你现在的数据安全了,但还不够。万一服务器挂了怎么办?你得学会备份。”

备份数据卷为 .tar

bash
docker run --rm \
  -v mysql-data:/data \
  -v $(pwd):/backup \
  busybox \
  tar czf /backup/mysql-backup.tar.gz -C /data .

⛴️ 第一个挂载是数据卷,第二个挂载是宿主机当前目录,输出备份包。

恢复数据卷:

bash
docker run --rm \
  -v mysql-data:/data \
  -v $(pwd):/backup \
  busybox \
  tar xzf /backup/mysql-backup.tar.gz -C /data

只需备份 .tar.gz 文件即可,适合迁移数据、升级、容灾。


🧹 第六节:清理无用卷(慎用)

随着实验多了,小李电脑堆满了无主卷。

查看:

bash
docker volume ls

清理:

bash
docker volume rm 卷名

清除所有未被挂载的孤立卷(慎用):

bash
docker volume prune

清理命令要慎重,别误删生产卷!


📋 Volume 挂载选项速查表

类型命令特点
匿名卷-v /path难追踪,系统自动命名
具名卷-v myvol:/path推荐用法,可管理
Bind 挂载-v /host:/container与宿主机文件交互,适合本地调试
tmpfs--tmpfs /path内存存储,重启即消失
权限控制-v myvol:/path:ro只读挂载
SELinux/AppArmor:z:Z(高级安全挂载)安全增强场景

🧠 小李的应用持久化策略建议

类型内容
数据库必须挂载 Volume 保持数据持久
日志推荐落盘到宿主机或集中采集
配置文件可用 Bind Mount 从本地同步配置
静态资源静态目录挂载 + CDN
临时缓存tmpfs 或容器内路径,无需持久化

🎬 尾声:构建自己的数据之岛

小李站在一个小岛码头,身后是一个个挂载卷,他的应用和数据终于脱离容器生命周期的束缚

老周说:

“真正的服务,要能容器随时销毁,数据却永存。”

小李点头,轻轻拍了拍他那卷 MySQL 的备份包,知道自己已经拥有了构建“数据之岛”的能力。


继续拓展高级内容,围绕:

  1. 🧪 数据卷在 CI/CD 中的作用和实战应用
  2. ☸️ 数据卷在 Kubernetes 中的延伸 —— PVC(PersistentVolumeClaim)挂载

以小李的旅程为主线,继续带你掌握更强大的容器化数据策略。


🔧 拓展一:数据卷在 CI/CD 中的角色与实践

在一次项目发布中,小李加入了公司的 DevOps 流水线。他发现 GitLab CI 跑测试时,每次都重新构建环境,速度太慢,还会出现缓存丢失的问题。

老周告诉他:

“在 CI/CD 环境中,合理使用数据卷可以极大加快构建速度、保留缓存和数据状态。”


✅ 使用场景 1:缓存 pip/npm 依赖,加速构建

小李把 pip install 改成挂载缓存目录:

GitLab Runner 示例:

.gitlab-ci.yml

yaml
cache:
  key: pip-cache
  paths:
    - .cache/pip

build:
  script:
    - docker run --rm
      -v $CI_PROJECT_DIR:/app
      -v $CI_PROJECT_DIR/.cache/pip:/root/.cache/pip
      my-builder-image bash -c "
      cd /app &&
      pip install -r requirements.txt &&
      pytest
      "

🔁 依赖安装过程可被缓存,构建速度提升 50%!


✅ 使用场景 2:测试数据隔离

小李部署端到端自动化测试容器:

bash
docker run --rm \
  -v test-volume:/app/test-results \
  e2e-runner:latest

测试结果可从宿主机挂载目录或卷中提取,用于后续报告生成或持久存档。


✅ 使用场景 3:构建产物跨阶段传递

CI/CD 有多阶段:构建 → 测试 → 部署 小李通过挂载共享卷,将编译好的前端包从构建容器传给部署容器:

bash
docker run --name builder -v build-volume:/output frontend-builder
docker run --rm -v build-volume:/usr/share/nginx/html nginx

☸️ 拓展二:Kubernetes 中的数据卷演进 —— PVC 实战

进入云原生世界,小李不再直接使用 docker run,而是通过 Kubernetes 来编排容器。

在 K8s 中,数据卷概念变得更专业:

  • Volume(临时存储,随 Pod 生命周期)
  • PersistentVolume(PV:管理员创建的存储资源)
  • PersistentVolumeClaim(PVC:用户申请的存储)
  • StorageClass(存储策略模板)

🔐 场景一:部署 Stateful 服务(如 MySQL)

小李写了以下 YAML:

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: standard
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:5.7
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "123456"
          volumeMounts:
            - mountPath: /var/lib/mysql
              name: data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: mysql-pvc

💡 PVC 是 “我要一个 5Gi 的盘”,PV 是“管理员给你一个”,Pod 中挂上它即可持久保存数据。


🧠 小知识点:K8s 中 Volume 的对比

类型生命周期是否持久典型用途
emptyDirPod 生命周期临时缓存、构建产物传递
hostPath节点目录挂载⚠️ 有风险本地开发测试
PVC(推荐)与集群存储绑定数据库存储、日志、持久缓存

📦 StorageClass:自动动态分配 PVC

在云环境(如 EKS、GKE)中,PVC 可以自动创建对应的 PV(EBS、Ceph、NFS 等),只要指定 StorageClass 即可:

yaml
storageClassName: gp2

这种方式可以实现跨节点迁移不丢数据按需付费扩容快照备份等高级功能


✅ 拓展总结:Docker 到 CI/CD,再到 Kubernetes 的数据策略演进

场景技术推荐做法
本地开发Bind Mount映射目录,实时更新
本地持久化Volume隔离性好,便于管理
CI/CD 中间数据卷 / 缓存目录挂载 .cachebuild 等路径
K8s 中数据存储PVC + StorageClass可扩展、可备份、可跨节点持久化

🎬 尾声:从数据孤岛到分布式星图

在 DevOps 流水线中,小李用数据卷构建了无缝衔接的构建流程;

在 Kubernetes 集群中,他用 PVC 实现了跨集群节点的 MySQL 数据持久化部署;

他站在云端存储的星图前,知道自己已经掌握了从 Docker 到 DevOps 再到 Kubernetes 的数据生命周期。

老周拍拍他:

“你已经造好了船,也撑起了帆。下一步,是用 Compose 编排你的舰队。”

❤️喜欢