Docker Compose 中 Volume 迁移到 Bind Mount 的完整实践

205次阅读
没有评论
内容纲要

>(以 Nexterm 为例)

## 一、背景与目标

在使用 **Docker Compose** 部署服务时,常见的数据持久化方式有两种:

1. **Docker Volume(命名卷)**

2. **Bind Mount(绑定宿主机目录)**

本次目标是:

- 从旧服务器迁移 Nexterm 服务

- **导出 Docker Compose 自动创建的 volume 中的数据**

- 在新服务器中,**改为使用当前目录下的 `./nexterm` 作为数据目录**

- 确保 **用户、配置、数据完整无损**

---

## 二、问题现象:导出的 volume 是空的?

### 现象

- `docker volume ls` 能看到 volume

- `docker run -v nexterm:/data` 打包成功

- 但生成的 `tar.gz` 只有 **几十字节**

- 新服务器解压后目录是空的

### 关键线索

```bash
docker volume ls | grep nexterm
local nexterm_nexterm
```

而导出时使用的是:

```bash
-v nexterm:/data
```

---

## 三、根因解析:Docker Compose 的 volume 命名规则

### 1️⃣ Compose 不会直接使用你写的 volume 名

在 `docker-compose.yml` 中:

```yaml
volumes:
nexterm:
```

**Docker Compose 实际创建的 volume 名是:**

```text
<项目名>_
```

本例中:

|项目|值|
|---|---|
|Compose 项目名|`nexterm`(目录名)|
|volume 名|`nexterm`|
|实际 volume|`nexterm_nexterm`|

---

### 2️⃣ 为什么不会报错?

当你执行:

```bash
docker run -v nexterm:/data ...
```

如果 `nexterm` 不存在:

- Docker 会 **自动创建一个新的空 volume**

- 命令执行成功

- 但打包的是 **空数据**

👉 这是一个**非常容易踩坑**、而且**不会给任何错误提示**的点。

---

## 四、如何确认容器正在使用的真实 volume(推荐方法)

### 方法一:看 volume 列表

```bash
docker volume ls
```

### 方法二(最稳妥):从容器反查

```bash
docker inspect nexterm-nexterm-1 \
--format '{{ range .Mounts }}{{ if eq .Type "volume" }}{{ .Name }}{{ end }}{{ end }}'
```

输出的 **就是你必须使用的 volume 名**。

---

## 五、正确导出 Docker Volume 数据(旧服务器)

### 1️⃣ 使用真实 volume 名导出

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

### 2️⃣ 校验备份是否正常

```bash
ls -lh nexterm-volume-backup.tar.gz
```

- ❌ 几十字节 → 一定有问题

- ✅ 几十 KB / 几 MB → 正常

---

## 六、在新服务器中恢复到 Bind Mount 目录

### 1️⃣ 创建目标目录

```bash
mkdir -p /opt/docker/nexterm/nexterm
```

### 2️⃣ 解压数据

```bash
tar xzf nexterm-volume-backup.tar.gz -C /opt/docker/nexterm/nexterm
```

解压后结构示例:

```text
nexterm/
├── logs/
├── nexterm.db
└── sources/
```

---

## 七、修改 docker-compose.yml(从 Volume → Bind Mount)

### 原配置(命名卷)

```yaml
volumes:
- nexterm:/app/data
```

### 修改后(绑定目录)

```yaml
services:
nexterm:
image: germannewsmaker/nexterm:1.0.5-OPEN-PREVIEW
container_name: nexterm
restart: always
ports:
- "6989:6989"
environment:
ENCRYPTION_KEY: "your-key"
volumes:
- ./nexterm:/app/data
```

⚠️ 注意事项:

- 删除 `volumes:` 全局定义

- 确保 `./nexterm` **已存在并且有数据**

- Compose 执行目录必须是 `docker-compose.yml` 所在目录

---

## 八、启动与验证

```bash
docker compose up -d
```

检查状态:

```bash
docker compose ps
docker logs -f nexterm
```

访问 Web 界面后确认:

- 用户是否存在

- 配置是否完整

- 历史数据是否正常

---

## 九、为什么推荐迁移到 Bind Mount?

|对比项|Docker Volume|Bind Mount|
|---|---|---|
|数据可见性|❌|✅|
|备份便利性|一般|极佳|
|可控性|中|高|
|适合长期运维|一般|**非常适合**|

绑定目录后,备份极其简单:

```bash
tar czf nexterm-backup-$(date +%F).tar.gz nexterm/
```

或直接纳入你的 `rclone / restic / borg` 体系。

---

## 十、经验总结(重点)

> **Docker Compose 中,volume 的真实名字 ≠ yml 里写的名字**

记住一句话即可避免 90% 的坑:

> **凡是用 Compose 的 volume,先用 `docker volume ls` 或 `docker inspect` 确认真实名称,再操作**

---

## 十一、延伸建议(下一步可做)

- 为所有 Docker 服务统一目录规范
`/opt/docker//`

- 数据目录全部使用 bind mount

- Volume 仅用于临时 / cache / 中间层

- 给每个服务写一个 `backup.sh`

---

正文完
 1