写清课程目录、Compose 项目、回环端口、服务和既有业务,先确认 18018 空闲。
外观
外观
约 4206 字大约 14 分钟
综合项目Docker ComposeNginx健康检查
2026-07-30
[Windows PowerShell] wsl ~:打开本机默认的 WSL2 Ubuntu;先在这里检查交付目录和脚本,再进入远程环境。[WSL] ssh root@你的ECS公网IP:从 WSL 连接自己的 ECS;如果登录用户不是 root,请换成控制台显示的实际用户,看到远端提示符后再执行部署、验收、恢复和清理命令。前十七次课分别练过 Linux 巡检、Nginx、备份恢复、Compose、数据库、负载均衡、云平台、Terraform、Kubernetes 和 Ansible。最后一次课不再追求“再认识一个新工具”,而是把已经学过的动作连成一个可以交付、可以验收、可以恢复、也可以安全撤场的小项目。
项目由两个服务组成:web 提供主页并反向代理 /api/,api 返回状态和发布版本。它不大,却故意包含运维交付最重要的几件事:明确边界、自动健康检查、用户路径验证、带校验和的备份、可恢复故障、同路回归和范围化清理。
关键提醒
综合项目的完成标志不是“页面曾经打开过”,而是交付目录完整、配置可解释、服务达到健康、用户路径通过、备份能够验证、故障能够恢复、课程资源能够单独清理,并且每一步都有证据。
学完这一课,做到六件事:
docker compose config、up --wait、ps、curl 和 verify.sh 分层验收。先审查交付目录,再部署并运行自动验收。主页和 API 都通过后,分别完成站点备份、页面漂移恢复和 API 中断恢复,最后只清理本项目。
整个过程使用同一组项目名、目录和回环端口。每次故障都要保留原始现象,恢复后沿原用户路径复测,不能用重建全部环境代替定位。
本课综合项目的完整请求链路如下:
Windows 浏览器
│
│ SSH 隧道
▼
ECS 127.0.0.1:18018
│
▼
web(Nginx)
├── / → 静态项目主页
├── /healthz → Web 健康检测标记
└── /api/status.json → api:80/status.json
│
└── 返回 status、service、release JSON组件角色与边界划分:
| 实体对象 | 本课命名 | 网络暴露边界 | 承担职责 |
|---|---|---|---|
| Compose 项目 | cloud-course-lab-18 | 课程专用项目 | 统一标识项目容器与网络 |
| Web 服务 | web | 绑定宿主机回环 18018 | 提供主页、健康端点与 API 反向代理 |
| API 服务 | api | 仅位于 Compose 内部网络 | 返回 JSON 状态数据 |
| 站点数据 | data/site/ | 只读挂载给 Web | 可备份、可恢复的内容文件 |
| 备份目录 | backup/ | 位于课程目录内部 | 保存归档压缩包与 SHA-256 校验和 |
| 既有业务 | 8000、18443 等端口 | 外部已有服务 | 仅排查端口冲突,切勿停止或修改 |
安全边界
课程项目仅允许在 /opt/xpk-course-demos/lesson-18、cloud-course-lab-18 以及 127.0.0.1:18018 范围内操作。绝对禁止停止未知容器,不要暴露公网端口,切勿修改全局安全组,严禁全局删除容器、卷或镜像。
实训包包含 compose.yaml、.env.example、Nginx 配置、Web/API 应用文件和配套脚本(从智慧职教课程资源区下载 lab-18-starter.zip 解压到工作目录)。
[WSL] mkdir -p ~/cloud-course/lab-18
[WSL] cd ~/cloud-course/lab-18
[WSL] cp -r /path/to/lab-18-starter/* .
[WSL] find starter -maxdepth 3 -type f -print | sort打印交付工程目录的文件树。预期可以看到 Compose 文件、环境变量模板、Nginx 配置、静态页面、API 模板,以及配套的部署、验收、备份与清理脚本。
[WSL] bash -n starter/*.shbash -n 只对 Shell 脚本做语法检查,不实际运行。它能帮你挑出拼写和语法错误,但不能代替真实的 Docker 运行测试。
[WSL] cp starter/.env.example starter/.env从模板复制出一份本地运行环境变量。.env.example 可以随代码交付,而包含具体配置的 .env 切勿打入报告或提交。
[WSL] docker compose --env-file starter/.env \
-f starter/compose.yaml config --quiet校验 Compose 配置的变量展开与语法有效性。若静默退出且返回码为 0,说明 YAML 格式无误;配置合法,容器还没拉起,下一步才是 up。
API 定义健康检查:
healthcheck:
test:
- CMD-SHELL
- wget -q -O - http://127.0.0.1/status.json | grep -q '"status":"ok"'
interval: 5s
timeout: 3s
retries: 6检查容器内部的实际 JSON,而不是只检查进程存在。只有 status=ok 才算 API healthy。
Web 对 API 的依赖写成:
depends_on:
api:
condition: service_healthyDocker 官方文档说明,普通启动顺序只保证容器进入 running,不保证应用已经 ready;service_healthy 会让依赖方等待健康检查通过。
观看时留意:依赖服务怎样用健康条件告诉 Compose 自己已经能够工作?
与本课的关系:综合项目还要继续检查主页、API、发布标记、备份和恢复,健康状态只是其中一层。
ports:
- 127.0.0.1:${COURSE_PORT}:80宿主机入口明确绑定 127.0.0.1。从 Windows 浏览器访问时使用 SSH 隧道,不为临时演示扩大公网暴露。
volumes:
- ./data/site:/usr/share/nginx/html:ro站点目录通过只读 bind mount 进入容器。容器可以读取页面,却不能从容器内改写宿主机课程内容;恢复操作在受控脚本中完成。
沿边界、配置、健康、用户路径、备份、故障回归和清理,审查综合项目是否真正完成。
写清课程目录、Compose 项目、回环端口、服务和既有业务,先确认 18018 空闲。
[ECS] bash deploy.sh脚本先运行 Compose 配置检查,再执行 docker compose up -d --wait --wait-timeout 60。--wait 会等服务达到 running 或 healthy,超时则返回失败。
[ECS] docker compose --env-file .env ps查看两个服务的状态。预期 api 与 web 均为 healthy,只有 Web 显示 127.0.0.1:18018->80/tcp。
[ECS] ss -lnt 'sport = :18018'检查宿主机监听。预期地址是 127.0.0.1:18018,不是 0.0.0.0:18018。
[ECS] curl -fsS http://127.0.0.1:18018/api/status.json沿 Web 反向代理访问 API。预期 JSON 同时包含 "status":"ok" 和 "release":"lesson18-v1"。
[ECS] bash verify.sh自动验收继续检查项目结构、回环绑定、容器健康、主页标题、健康契约和 API 发布标记。任何关键项失败都返回非 0。
在 WSL 中建立 SSH 隧道,把远端回环端口映射到本地:
[WSL] ssh -N -L 18018:127.0.0.1:18018 root@你的ECS公网IP这条命令保持运行期间,Windows 浏览器访问 http://127.0.0.1:18018/ 即可打开远端项目主页。终止 SSH 命令只会关闭隧道,不会停止远端容器。真实环境打开后的效果如下:

页面打开只是其中一层证据。图中 API ready 来自浏览器实际请求 /api/status.json;如果 API 依赖中断,这一张旧截图不能代替重新检查。
[ECS] bash backup.sh脚本把 data/site/ 打成时间戳归档,并在同一目录生成 .sha256 文件。输出中的 OK 表示刚生成的归档与校验记录一致。
[ECS] tar -tzf backup/lesson18-site-时间戳.tar.gz-t 列出归档内容,-z 处理 gzip,-f 指定归档文件。预期只有 site/ 和 site/index.html;恢复前先看清“里面是什么”。
[ECS] cd backup
[ECS] sha256sum -c lesson18-site-时间戳.tar.gz.sha256
[ECS] cd ..校验文件记录的是归档的相对文件名,因此先进入 backup/ 再验证。输出 OK 能发现传输或存储后的字节变化,但不能说明备份内容没有遗漏,也不能保证恢复流程可用。
关键提醒
备份是“保存了什么”,恢复是“能否把目标状态带回来”。只有归档、校验和、恢复过程和恢复后的用户路径都留下证据,才能构成可验证的恢复流程。
[ECS] bash inject-fault.sh脚本只替换本课 data/site/index.html,并把原文件保存在课程目录中。漂移页面仍有 HTML 和标题,Nginx 也继续运行。
[ECS] bash verify.sh此时 API 与 Web 仍 healthy,但主页缺少 lesson18-project-ok,因此出现 [FAIL] 主页内容不符合预期,退出码为 1。
[ECS] bash restore.sh \
backup/lesson18-site-时间戳.tar.gz恢复脚本只接受本项目 backup/ 内的归档,先验证 SHA-256,再检查归档路径没有越界,在临时目录解包并确认健康契约,最后安装页面并自动运行 verify.sh。
真实备份和恢复结果:
命令和相邻输出按原始捕获顺序拆开显示。切换步骤时,先看命令,再从输出中找判断依据。
root@SYG680400:/opt/xpk-course-demos/lesson-18$ bash backup.shlesson18-site-20260728T070000Z.tar.gz: OK[PASS] backup=.../backup/lesson18-site-20260728T070000Z.tar.gz[PASS] checksum=.../lesson18-site-20260728T070000Z.tar.gz.sha256“生成备份与校验”保留了完整命令和与它相邻的输出。判断时应直接引用输出中的字段或状态,不要把步骤名称当成结论。
这一步是“备份生成 SHA-256 校验文件,页面漂移使验收失败,恢复脚本验证校验和与归档路径后还原页面,同路验收通过”证据链中的一环。
只恢复静态站点目录,不包含数据库、容器镜像、主机配置或异地灾备

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
完整记录依次展示归档、查看内容、注入页面漂移、验收失败和恢复回归。时间戳来自本次真实捕获,下面三张单命令卡用于放大其中的校验、漂移和恢复结果。
云主机 B · cloud-course-lab-18 · 2026-07-28
root@SYG680400:/opt/xpk-course-demos/lesson-18$ bash backup.shlesson18-site-20260728T070000Z.tar.gz: OK[PASS] backup=.../backup/lesson18-site-20260728T070000Z.tar.gz[PASS] checksum=.../lesson18-site-20260728T070000Z.tar.gz.sha256脚本生成站点归档和校验文件,并立即验证当前归档字节一致
脚本生成站点归档和校验文件,并立即验证当前归档字节一致
不能证明归档可恢复,也不包含数据库或整台主机

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
OK 表示刚生成的归档与校验记录一致,后两行给出归档和校验文件的位置。此时只能确认“文件已经生成且字节一致”,还不能确认它能恢复页面。
云主机 B · cloud-course-lab-18 · 2026-07-28
root@SYG680400:/opt/xpk-course-demos/lesson-18$ bash verify.sh[PASS] api 为 healthy[PASS] web 为 healthy[FAIL] 主页内容不符合预期[PASS] API 返回 status=ok 与 lesson18-v1验收未通过:1 项失败。verify_exit=1两个容器仍健康、API 仍正常,但主页内容契约识别出漂移
两个容器仍健康、API 仍正常,但主页内容契约识别出漂移
只证明课程定义的主页标记缺失,不说明所有业务功能都异常

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
输出清晰地显示了故障边界:API 和 Web 容器仍为 healthy,API 也返回正确版本,只有主页内容检查失败。因此修复对象应是站点页面,而不是 Docker 服务或 API。
云主机 B · cloud-course-lab-18 · 2026-07-28
root@SYG680400:/opt/xpk-course-demos/lesson-18$ bash restore.sh backup/lesson18-site-20260728T070000Z.tar.gzlesson18-site-20260728T070000Z.tar.gz: OK[PASS] 已从 lesson18-site-20260728T070000Z.tar.gz 恢复站点页面。[PASS] 主页包含项目标题和健康契约[PASS] API 返回 status=ok 与 lesson18-v1验收通过。恢复脚本先校验指定归档,再恢复页面并自动沿原路径验收
恢复脚本先校验指定归档,再恢复页面并自动沿原路径验收
恢复范围只有本课静态页面,不包含数据库、容器镜像或系统配置

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
恢复命令先再次得到校验 OK,随后报告页面恢复,最后主页与 API 同时通过。这里完成的是本课静态页面恢复流程,不包含数据库、镜像或整机恢复。
[ECS] docker compose --env-file .env stop api只停止本课 API 容器。Web 容器继续运行,便于观察依赖中断后的真实用户现象。
[ECS] curl --max-time 8 -sS -o /dev/null \
-w 'http=%{http_code}\n' \
http://127.0.0.1:18018/api/status.json--max-time 8 防止无限等待,-o /dev/null 丢弃响应体,-w 只打印状态码。此时会看到 http=504:Web 收到了请求,但在等待上游 API 时超时。
[ECS] docker compose --env-file .env \
logs --since 30s --tail 10 web查看 Web 最近日志。真实日志包含 upstream timed out while connecting to upstream,把范围从“浏览器打不开 API”缩小到 Web 到 API 的上游连接。
[ECS] bash verify.sh此时脚本同时报告 API 容器缺失和 API 内容不符合预期。Web 自身 healthy、主页仍可读,但完整用户路径还没恢复。
[ECS] docker compose --env-file .env start api只恢复故障对象。不要重启 Docker 服务,也不要重建正常 Web。
[ECS] bash verify.sh等待 API healthy 后,沿原路径重新验收。只有 API 状态、主页和代理请求全部通过,才能宣布恢复。
真实故障、日志、恢复与清理结果:
命令和相邻输出按原始捕获顺序拆开显示。切换步骤时,先看命令,再从输出中找判断依据。
...$ docker compose --env-file .env stop apiContainer cloud-course-lab-18-api-1 Stopped“停止指定服务”保留了完整命令和与它相邻的输出。判断时应直接引用输出中的字段或状态,不要把步骤名称当成结论。
这一步是“API 中断导致真实 504 和上游超时,恢复后完整验收通过;最终仅本课容器和网络被移除,18018 释放且既有业务端口仍监听”证据链中的一环。
只覆盖可恢复的单服务中断,不证明多节点容灾、自动故障转移或业务数据一致性

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
这组记录从停止 API 一直保留到 cleanup.sh。HTTP 504 和上游超时日志描述服务链路的现象;查询日志的命令本身是否返回非 0,原始记录没有单独保存,因此卡片只标注“未记录退出码”。
云主机 B · cloud-course-lab-18 · 2026-07-28
root@SYG680400:/opt/xpk-course-demos/lesson-18$ curl --max-time 8 -sS -o /dev/null -w 'http=%{http_code}\n' http://127.0.0.1:18018/api/status.jsonhttp=504Web 入口仍接收请求,但等待已停止的 API 上游超时
Web 入口仍接收请求,但等待已停止的 API 上游超时
仅凭 504 还不能确定 API 为何不可用,需要结合容器状态和 Web 日志

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
这一条 curl 只证明用户路径返回 504:Web 入口仍能接受请求,但没有及时从上游得到响应。仅凭状态码还无法判断是 API 停止、内部网络异常还是代理配置错误。
云主机 B · cloud-course-lab-18 · 2026-07-28
root@SYG680400:/opt/xpk-course-demos/lesson-18$ docker compose --env-file .env logs --since 30s --tail 6 webupstream timed out while connecting to upstreamrequest: "GET /api/status.json HTTP/1.1"upstream: "http://IP-HIDDEN:80/status.json""GET /api/status.json HTTP/1.1" 504 167请求进入 Web 后,在连接内部 API 上游时超时
请求进入 Web 后,在连接内部 API 上游时超时
内部地址已遮盖,日志不能单独解释 API 停止的原因

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
while connecting to upstream 把范围缩小到 Web 与内部 API 之间;请求路径与上一张图相同,使状态码和内部日志可以相互印证。内部地址已遮盖,日志本身仍不能解释 API 为何停止。
云主机 B · cloud-course-lab-18 · 2026-07-28
root@SYG680400:/opt/xpk-course-demos/lesson-18$ bash verify.sh[PASS] api 为 healthy[PASS] web 为 healthy[PASS] 主页包含项目标题和健康契约[PASS] API 返回 status=ok 与 lesson18-v1验收通过。恢复 API 后,容器健康、主页与代理 API 路径全部重新通过
恢复 API 后,容器健康、主页与代理 API 路径全部重新通过
只证明本次回归检查通过,不替代持续监控和更长时间的稳定性观察

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
恢复后没有换一条更容易通过的检查,而是再次运行同一个 verify.sh。四项 PASS 覆盖两项容器、主页和代理 API;它证明本次回归成功,不替代持续监控。
观看时留意:视频中的 502 与本课观察到的 504,在证据和故障范围上有什么不同?
与本课的关系:完成 API 中断恢复后再展开。状态码不同,不能把案例中的修复动作直接套到本项目。
输入脱敏后的 Compose、健康、HTTP、日志、备份或清理结果,让助教判断证据链缺在哪一层。
本实验的原始聊天仅保存在当前标签页,不会写入全局课程助教上下文。
| 阶段 | 本课证据 | 写法 |
|---|---|---|
| 范围 | 项目名、目录、端口、已有业务 | 只处理 lesson-18 |
| 基线 | 两服务 healthy,主页/API 通过 | 记录故障前状态 |
| 现象 | 页面契约失败或 API 504 | 保留原始退出码 |
| 假设 | 内容漂移;API 上游不可达 | 必须可以被下一条检查证伪 |
| 定位 | 页面 marker;Web upstream 日志 | 不只写“网络问题” |
| 修复 | 从已验证归档恢复;启动 API | 只改变故障对象 |
| 回归 | 再运行同一 verify.sh | 与故障前证据可比 |
| 清理 | Compose 项目为 0,18018 释放 | 同时核对既有业务仍在 |
“重启后好了”不是完整报告,因为它没有说明故障对象、证据、修改范围和回归路径。
[ECS] bash cleanup.sh脚本在本项目目录执行 docker compose down --remove-orphans,只删除本课容器和默认网络,并检查 18018 已释放。
[ECS] docker ps -a \
--filter label=com.docker.compose.project=cloud-course-lab-18按 Compose 项目标签检查残留。预期没有本课容器。
[ECS] ss -lnt | grep -E ':(8000|18443) '复核预先标记的既有业务端口,确认其仍保持原状态。这条命令不能证明业务功能完整,但能发现本课清理是否误停明显监听。
安全边界
不要把清理改成 docker system prune -a、删除所有容器、删除全部网络或停止 Docker。课程资源已经有项目名、目录和端口,清理范围也必须使用这些边界。
完整步骤见实训 18:综合运维交付与恢复。
提交文件名:
班级_学号_姓名_第18次课_综合运维项目报告.docx只上传一个 Word 到智慧职教“第18次课”。报告以操作记录和截图为主,每张图旁边写清环境、命令、关键结果、能够证明什么、不能证明什么。不要提交 .env、公网地址、SSH 配置、密钥、验证码、完整容器 ID、原始备份、完整日志、账号、订单或余额。
检查边界、部署、主页、备份恢复、故障证据、清理和隐私保护是否形成完整闭环。
这组题跨越 Compose 标准化、Kubernetes Service 与发布、Ansible 幂等和综合恢复。重点不是回忆命令拼写,而是判断一条证据能把故障范围缩小到哪里,以及恢复后应沿哪条路径复测。
用 4 道跨阶段题检查 Compose、Kubernetes、Ansible 与综合验收能否连成闭环。
用 6 道题检查健康依赖、用户路径、备份校验、故障定位、回归和范围化清理。
service_healthy 与 up --wait 用健康检查约束依赖启动,但仍需用户路径验收。以下资料在 2026-07-28 核对:
助教会读取当前课程页面和结构化学习记录,但不会读取正文实验框里的原始聊天。