---
url: /courses/cloud-platform-build-management/lab-18/index.md
---
# 实训 18：综合运维交付与恢复

## 1. 任务情境

你要交付一个由 Web 和 API 组成的课程项目。项目必须只绑定 ECS 回环端口，通过 SSH 隧道供浏览器访问；部署后要运行自动验收。随后生成带 SHA-256 的站点备份，分别处理页面内容漂移和 API 中断，完成同路回归，最后只清理本课资源。

## 2. 环境和安全边界

| 项目 | 课堂要求 |
|---|---|
| 控制端 | Windows 11 + WSL；教师演示可使用本地控制端 |
| 运行端 | 本人 ECS 或教师授权的云主机 B |
| 远端目录 | `/opt/xpk-course-demos/lesson-18` |
| Compose 项目 | `cloud-course-lab-18` |
| 课程端口 | `127.0.0.1:18018` |
| 服务 | `api`、`web` |
| 数据范围 | `data/site/` 与 `backup/` |
| 禁止范围 | 业务容器、8000/18443、全局 Docker 清理、防火墙、安全组和公网开放 |

本实训只允许注入项目自带的两种可恢复故障。不要停止未知服务，不要删除其他目录，不要创建付费资源。

## 3. 准备个人目录

```bash
[WSL] mkdir -p "$HOME/cloud-course/lab-18"
```

创建本课个人目录。

```bash
[WSL] cp -R starter/. "$HOME/cloud-course/lab-18/"
```

复制教师提供的起始文件。

```bash
[WSL] cd "$HOME/cloud-course/lab-18"
```

进入工作目录。后续本地命令都从这里执行。

```bash
[WSL] find . -maxdepth 3 -type f -print | sort
```

核对 Compose、页面、API 数据、Nginx 配置和七个脚本是否齐全。

```bash
[WSL] bash -n ./*.sh
```

检查脚本语法。没有输出且退出码为 0 表示语法可解析。

## 4. 远端只读预检

```bash
[WSL] ssh B 'nproc; free -h; df -h /'
```

读取 CPU、内存和根文件系统。将 B 换成教师分配的 SSH 别名；不要在报告中写完整公网地址。

```bash
[WSL] ssh B 'docker ps --format "{{.Names}} {{.Ports}}"'
```

记录已有容器与端口。只观察，不停止。

```bash
[WSL] ssh B "ss -lnt 'sport = :18018'"
```

确认 18018 尚未监听。若被占用，停止实训并向教师报告，不自行更换到未知业务端口。

```bash
[WSL] ssh B 'test ! -e /opt/xpk-course-demos/lesson-18'
```

确认课程目录不存在。若目录已存在，先判断是否为本人上次未清理的实验，不覆盖未知文件。

## 5. 上传课程包

```bash
[WSL] ssh B 'mkdir -p /opt/xpk-course-demos/lesson-18'
```

只创建本课远端目录。

```bash
[WSL] rsync -a ./ B:/opt/xpk-course-demos/lesson-18/
```

上传当前目录内容。不要使用指向 `/opt` 或其他上级目录的 `--delete`。

```bash
[WSL] ssh B 'cd /opt/xpk-course-demos/lesson-18 && cp .env.example .env'
```

从示例生成远端 `.env`。实际 `.env` 不上传智慧职教。

```bash
[WSL] ssh B 'cd /opt/xpk-course-demos/lesson-18 && chmod 0755 ./*.sh'
```

只为本课脚本增加执行权限。

## 6. 检查最终 Compose 模型

```bash
[ECS] cd /opt/xpk-course-demos/lesson-18
```

进入项目目录，后续 `[ECS]` 命令都在这里执行。

```bash
[ECS] docker compose --env-file .env config --services
```

预期只列出 `api` 和 `web`。

```bash
[ECS] docker compose --env-file .env config --images
```

预期两个服务都使用课程固定的 `nginx:1.27-alpine`。

```bash
[ECS] docker compose --env-file .env config |
  sed -n '/web:/,/healthcheck:/p'
```

检查 Web 的 `depends_on`、只读挂载和 `127.0.0.1:18018`。截图时不要包含与课程无关的环境变量。

## 7. 部署和自动验收

```bash
[ECS] bash deploy.sh
```

脚本检查配置，后台启动服务并等待 healthy，然后调用 `verify.sh`。预期全部 `[PASS]`。

```bash
[ECS] docker compose --env-file .env ps
```

预期 API 与 Web 均为 healthy，只有 Web 发布回环端口。

```bash
[ECS] ss -lnt 'sport = :18018'
```

预期监听为 `127.0.0.1:18018`。

```bash
[ECS] curl -fsS http://127.0.0.1:18018/api/status.json
```

预期包含 `status=ok`、`service=lesson18-api` 和 `release=lesson18-v1`。

截图 1 应同时包含 `compose ps`、回环监听和 `verify.sh` 关键结果。

## 8. 通过 SSH 隧道访问主页

在 WSL 另开一个终端：

```bash
[WSL] ssh -N -L 11818:127.0.0.1:18018 B
```

保持终端运行，把 Windows 浏览器访问 `127.0.0.1:11818` 的流量转发到 ECS 回环入口。

在 Windows 浏览器打开：

```txt
http://127.0.0.1:11818/
```

预期看到“综合项目运行概况”、`API ready`、`lesson18-v1` 和 `lesson18-project-ok`。截图 2 保存完整可见页面，不显示公网地址或 SSH 配置。

## 9. 建立带校验和的备份

```bash
[ECS] bash backup.sh
```

生成时间戳归档和 `.sha256` 文件。记录脚本输出的实际文件名。

```bash
[ECS] ls -lh backup/
```

检查归档和校验文件都存在，记录大小。

```bash
[ECS] tar -tzf backup/lesson18-site-实际时间戳.tar.gz
```

检查归档内部只含 `site/` 和页面文件。

```bash
[ECS] cd backup
[ECS] sha256sum -c lesson18-site-实际时间戳.tar.gz.sha256
[ECS] cd ..
```

校验文件保存的是归档的相对文件名，所以要在 `backup/` 中执行。预期返回 `OK`。截图 3 包含归档名、内容清单和校验结果。

## 10. 页面内容漂移与恢复

```bash
[ECS] bash inject-fault.sh
```

只替换课程页面；容器继续运行。

```bash
[ECS] bash verify.sh
```

预期退出码非 0，主页内容检查失败，API 和容器检查仍可能通过。保留原始失败，不修改验收脚本绕过门禁。

```bash
[ECS] bash restore.sh \
  backup/lesson18-site-实际时间戳.tar.gz
```

恢复脚本验证校验和、归档路径和健康标记后安装页面，并自动重跑验收。预期全部通过。

截图 4 要把“故障时失败”和“恢复后通过”放在一起。

若恢复失败：

* `No such file`：先用 `ls backup/` 核对实际文件名；
* 校验失败：停止恢复，保留归档，不重新生成校验和掩盖问题；
* 越界路径：归档不符合课程边界，不继续解包；
* 缺少健康契约：归档不是已验证基线，选择正确备份；
* 页面恢复但 API 失败：按下一节检查独立依赖。

## 11. API 中断与日志定位

```bash
[ECS] docker compose --env-file .env stop api
```

只停止本课 API。

```bash
[ECS] curl --max-time 8 -sS -o /dev/null \
  -w 'http=%{http_code}\n' \
  http://127.0.0.1:18018/api/status.json
```

预期状态码为 504。若结果不同，保留实际输出再看日志，不为了匹配答案改配置。

```bash
[ECS] docker compose --env-file .env \
  logs --since 30s --tail 10 web
```

预期看到连接上游超时和 `/api/status.json` 请求。

```bash
[ECS] bash verify.sh
```

预期 API 容器和 API 内容检查失败，退出码非 0。

```bash
[ECS] docker compose --env-file .env start api
```

只启动 API。

```bash
[ECS] docker compose --env-file .env ps
```

等待 API 状态变为 healthy。若仍 starting，数秒后再观察；若 unhealthy，使用 `docker inspect` 和 API 日志定位。

```bash
[ECS] bash verify.sh
```

沿相同用户路径完成回归。预期全部通过。

截图 5 包含 504、上游日志、恢复后的 healthy 和验收通过。

## 12. 最终项目验收

```bash
[ECS] bash verify.sh
```

最终自动检查必须通过。

人工检查表：

| 检查 | 预期 |
|---|---|
| 项目文件 | 部署、验证、备份、恢复、清理齐全 |
| 配置 | 只含 api/web，Web 等待 API healthy |
| 容器 | api/web healthy |
| 入口 | 只绑定 127.0.0.1:18018 |
| 主页 | 标题与 `lesson18-project-ok` |
| API | status=ok、lesson18-v1 |
| 备份 | 归档、SHA-256、内容清单 |
| 故障 | 页面漂移与 API 中断都有原始证据 |
| 恢复 | 使用同一 verify.sh 通过 |

## 13. 清理

先关闭 WSL 中的 SSH 隧道，按 `Ctrl+C` 结束。

```bash
[ECS] bash cleanup.sh
```

删除本课 Compose 容器与默认网络，检查 18018 释放。

```bash
[ECS] docker ps -a \
  --filter label=com.docker.compose.project=cloud-course-lab-18
```

预期没有输出。

```bash
[ECS] ss -lnt 'sport = :18018'
```

预期没有监听。

```bash
[ECS] ss -lnt | grep -E ':(8000|18443) '
```

只读复核教师指定的既有业务端口保持原状态。学生自己的服务器若没有这些端口，应按本人基线核对，不照抄教师结果。

```bash
[ECS] cd /opt/xpk-course-demos
```

离开课程目录，避免删除当前工作目录。

```bash
[ECS] rm -rf -- /opt/xpk-course-demos/lesson-18
```

只有在确认路径完全一致、报告证据已保存、容器已清理后，才删除本课远端目录。不要用变量、通配符或上级目录替代这个精确路径。

## 14. 自动脚本的限制

`verify.sh` 能检查：

* `.env` 和 Compose 配置；
* api/web 服务声明；
* 回环端口绑定；
* 两个容器健康；
* 主页标题和健康契约；
* API 状态和发布版本。

它不能证明：

* SSH 隧道与 Windows 浏览器长期可用；
* 备份覆盖数据库或整机；
* 所有故障都能自动恢复；
* 公网、安全组、费用和长期监控正确；
* 截图与报告真实、完整且不泄密；
* 最终清理没有影响任何未登记业务。

## 15. 报告与提交

填写：

```txt
班级_学号_姓名_第18次课_综合运维项目报告.docx
```

只上传一个 Word 到智慧职教“第18次课”。每张截图旁边填写环境、命令、关键结果、证明范围和限制。

不要提交：

* `.env`、SSH 配置、私钥、密码、验证码；
* 公网地址、云账号、资源 ID、订单、余额；
* 原始未脱敏截图、完整容器 ID、完整日志；
* 实际备份归档、其他业务文件、远端课程目录；
* 项目 `node_modules`、镜像或虚拟环境。

## 16. 评分证据

| 维度 | 分值 | 达标证据 |
|---|---:|---|
| 边界与预检 | 10 | 目录、项目、端口、已有业务基线 |
| 配置理解 | 15 | 依赖、健康、回环、只读挂载 |
| 部署与访问 | 15 | healthy、verify、真实主页 |
| 备份与校验 | 15 | 归档、内容、SHA-256 |
| 页面恢复 | 15 | 漂移失败、受控恢复、同路回归 |
| API 故障 | 15 | 504、日志、最小恢复 |
| 清理与业务保护 | 10 | 本课资源为 0、端口释放、业务保留 |
| 报告质量 | 5 | 图文相邻、证明范围准确、无敏感信息 |
