---
url: /courses/cloud-platform-build-management/lab-17/index.md
---
# 实训 17：Ansible 幂等部署与健康检查

## 1. 任务情境

你要从 WSL 控制端管理教师指定的 ECS：先用 Inventory 和 ping 模块证明 SSH/Python 链路可用，再运行 `site.yml` 部署课程专用站点。相同输入立即执行第二次，比较 changed。随后把页面替换为仍返回 HTTP 200 的漂移版本，让 `health.yml` 发现业务标记错误；最后重新应用期望状态并清理本课资源。

## 2. 环境与安全边界

| 项目 | 课堂要求 |
|---|---|
| 控制端 | 学生 WSL；教师演示可使用本地控制端 |
| 被管理端 | 本人 ECS 或教师授权的云主机 B |
| Inventory 组 | `course_hosts` |
| 远端目录 | `/opt/xpk-course-demos/lesson-17` |
| 容器 | `cloud-course-lab-17-web` |
| 端口 | `127.0.0.1:18017` |
| 允许变更 | 本课目录、容器、页面和健康检查 |
| 禁止操作 | 业务容器、8000/18443、全局清理、防火墙和公网规则 |

不要把私钥、密码、验证码、完整地址、实际 Inventory 和完整日志提交到智慧职教。

## 3. 控制端准备

```bash
[WSL] python3 --version
```

确认版本不低于 Python 3.10。若版本更低，先请教师统一处理 WSL 环境，不要直接替换系统 Python。

```bash
[WSL] python3 -m venv "$HOME/.venvs/cloud-course-ansible"
```

创建虚拟环境。

```bash
[WSL] "$HOME/.venvs/cloud-course-ansible/bin/python" -m pip install \
  "ansible-core==2.17.14"
```

安装课堂验证版本。选择 2.17.14 是为了兼容 Ubuntu 22.04 常见的 Python 3.10；更高版本的 Ansible Core 可能要求更高版本的 Python。

```bash
[WSL] source "$HOME/.venvs/cloud-course-ansible/bin/activate"
```

进入环境。

```bash
[WSL] ansible --version
```

记录 core、Python 和配置文件路径。报告不需要提交虚拟环境。

## 4. 准备实验目录

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

创建个人目录。

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

复制课堂文件。

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

进入实验目录。

目录：

```txt
lab-17/
├── ansible.cfg
├── inventory.ini
├── site.yml
├── health.yml
├── fault.yml
├── cleanup.yml
└── verify.sh
```

将 `inventory.ini` 中的 SSH 别名和用户改为教师分配值。不要写密码和私钥内容。

## 5. 步骤一：Inventory、语法和连接

```bash
[WSL] ansible-inventory --graph
```

预期 `course_hosts` 下只有授权目标。

```bash
[WSL] ansible-playbook --syntax-check \
  site.yml health.yml fault.yml cleanup.yml
```

预期每个 Playbook 都能解析。

```bash
[WSL] ansible course_hosts -m ansible.builtin.ping -o
```

预期 `SUCCESS`、`changed: false` 和 `"ping": "pong"`。

如果 unreachable：

```bash
[WSL] ssh -o BatchMode=yes B true
```

用教师分配的别名替换 B。若 SSH 失败，先解决连接、用户、密钥、known\_hosts 和网络，不修改 Playbook。

截图 1 包含 Ansible 版本、Inventory 图和 ping 结果；遮盖完整地址。

## 6. 步骤二：远端只读预检

```bash
[WSL] ansible course_hosts -m ansible.builtin.shell -a \
  "nproc; free -h; df -h /; docker ps; ss -lnt 'sport = :18017'"
```

记录 CPU、可用内存、磁盘、已有容器和 18017 是否空闲。不要停止任何既有容器。

检查点：

* 远端目录只使用 lesson-17；
* 容器名只使用本课名称；
* 18017 尚未监听；
* 入口固定为 127.0.0.1；
* 8000、18443 保持原状态。

## 7. 步骤三：第一次部署

```bash
[WSL] ansible-playbook site.yml
```

观察各任务：

1. 目录 changed；
2. 页面 changed；
3. inspect ok；
4. 创建容器 changed；
5. 边界检查 ok；
6. HTTP 和标记检查 ok。

recap 预期 `failed=0 unreachable=0`，changed 数量以实际环境为准。

```bash
[WSL] ansible course_hosts -m ansible.builtin.command \
  -a "docker inspect cloud-course-lab-17-web"
```

确认课程容器存在。

## 8. 步骤四：第二次执行

```bash
[WSL] ansible-playbook site.yml
```

不修改任何输入。教师真实环境的第二次执行为：

```txt
ok=6 changed=0 unreachable=0 failed=0 skipped=1
```

创建容器任务因容器已存在而 skipped。截图 2 要把首跑和第二次 recap 放在一起。

若第二次仍 changed：

* 找到 changed 的具体任务；
* 检查模板是否含时间戳或随机值；
* 检查 command 是否每次都强制 changed；
* 不要直接用 `changed_when: false` 隐藏问题；
* 修正后重新从已知基线验证。

## 9. 步骤五：健康检查基线

```bash
[WSL] ansible-playbook health.yml
```

预期：

* 容器 `status=running`；
* 镜像为 `nginx:1.27-alpine`；
* HTTP 状态 200；
* `release=lesson17-v1`；
* `health=lesson17-health-ok`；
* `changed=0 failed=0`。

## 10. 步骤六：内容漂移故障

```bash
[WSL] ansible-playbook fault.yml
```

只替换课程页面，copy 使用 backup 保存远端临时备份。容器不停止。

```bash
[WSL] ansible-playbook health.yml
```

预期 `uri` 返回 ok，assert 随后失败，退出码非 0。保留：

* HTTP 仍为 200；
* 缺少健康标记；
* release 变为 unknown-drift；
* assert 的 fail\_msg；
* recap `failed=1`。

不要为让脚本“通过”而给断言加 ignore\_errors。

## 11. 步骤七：重新应用期望状态

```bash
[WSL] ansible-playbook site.yml
```

copy 应为 changed，容器任务 skipped，HTTP 检查通过。只修复页面，不重建正常容器。

```bash
[WSL] ansible-playbook health.yml
```

预期 `lesson17 health check passed` 和 `changed=0 failed=0`。

截图 3 包含故障断言、恢复 changed=1 和健康通过。

## 12. 自动验收

```bash
[WSL] bash verify.sh
```

脚本检查：

* 必要文件；
* Inventory 只能解析到课程组；
* 四个 Playbook 语法；
* Ansible ping；
* 当前健康检查。

自动脚本不替代首跑/二次执行对比、故障原始证据和清理复核。

## 13. 清理

```bash
[WSL] ansible-playbook cleanup.yml
```

删除本课容器和目录。

```bash
[WSL] ansible course_hosts -m ansible.builtin.shell -a \
  "docker ps -a --filter name=^/cloud-course-lab-17-web$; test ! -e /opt/xpk-course-demos/lesson-17; ss -lnt 'sport = :18017'"
```

预期没有本课容器，目录不存在，18017 没有监听。

```bash
[WSL] ansible course_hosts -m ansible.builtin.shell -a \
  "ss -lnt | grep -E ':(8000|18443) '"
```

复核既有业务端口保持原状态。只查看，不修改。

## 14. 人工检查

教师还会检查：

* 截图是否区分学生 WSL 和教师控制端；
* Inventory 是否只含授权目标且不含凭据；
* 首跑和二次执行是否来自相同输入；
* changed=0 的结论是否限定范围；
* HTTP 200 漂移是否被业务标记发现；
* 恢复是否只改变页面而未重建正常容器；
* cleanup 是否只处理课程资源；
* 8000、18443 是否未受影响。

## 15. 报告与提交

填写：

```txt
班级_学号_姓名_第17次课_Ansible与可观测性报告.docx
```

只上传 Word 到智慧职教“第17次课”。不要提交虚拟环境、SSH 配置、私钥、实际 Inventory、完整地址、远端备份文件或完整日志。
