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

忘机山人

发布于380天前
博客图片修整中,看不了可以先搜索公众号“忘机山人”看。
> 一直想写一本容器小书,真好懒猫基本都做了容器化,所以把这部分分享出来。不同的是,懒猫微服中使用pg-docker来替代docker命令,使用dockge来执行docker-compose。以下讲解以标准docker为主,这样子既学会了docker知识,也能够在懒猫微服上启动Docker服务。

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


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

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

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

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

------

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

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

| 方案       | 用法                    | 场景                       |
| ---------- | ----------------------- | -------------------------- |
| Volume     | Docker 管理的专属数据区 | 最推荐、安全、可多容器共享 |
| 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 的对比

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

------

### 📦 StorageClass:自动动态分配 PVC

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

```yaml
storageClassName: gp2
```

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

------

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

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

------

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

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

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

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

老周拍拍他:

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

评论

0

暂无评论

说点什么呢~
收藏
0
0
0