curl 访问 ECS 127.0.0.1:18008,请求先进入 lb:80。
外观
外观
约 3209 字大约 11 分钟
Nginx反向代理负载均衡upstream
2026-07-30
[Windows PowerShell] wsl ~:打开本机默认的 WSL2 Ubuntu;出现 用户名@主机名:~$ 后再执行标为 [WSL] 的命令。[WSL] ssh root@你的ECS公网IP:从 WSL 连接自己的 ECS;如果登录用户不是 root,请换成控制台显示的实际用户,看到远端提示符后再执行标为 [ECS] 的命令。前几次课里,浏览器始终连接某一个 Web 服务。如果同一站点有两个后端实例,需要在它们前面增加一个稳定入口:客户端只认识负载均衡器,负载均衡器再选择后端。
本课运行三个隔离容器:
lb:Nginx 负载均衡入口,只绑定 ECS 的 127.0.0.1:18008;backend-a:返回页面标识 backend-a;backend-b:返回页面标识 backend-b。连续请求看到两个不同标识时,说明请求确实到过不同后端。停止其中一个后端,入口仍能返回另一个后端的页面;恢复后再次观察到两个标识,才算走完一轮完整的故障处理验证。
安全边界
只允许停止 cloud-course-lab-08 中的 backend-b。不要停止服务器现有 Nginx、所有容器或其他 Compose 项目,也不要把 18008 改为公网绑定。
反向代理(代表后端服务接收客户端请求,再把请求转发到内部服务的中间层) 对浏览器暴露一个统一入口。用户访问时只认这个公开地址,通常不必知道后端有多少台机器、内部 IP 是什么。
完整请求路径如下:
Windows 浏览器
-> WSL SSH 隧道
-> ECS 127.0.0.1:18008
-> lb:80
-> backend-a:80 或 backend-b:80正向代理替客户端去访问外网资源,反向代理则是替服务端接收并分发外部请求。本课聚焦在反向代理场景。
关键提醒
负载均衡器本身存活,后端不一定正常;配置了两个后端,流量也不一定平摊过去。必须结合静态配置、后端直连测试与入口访问日志综合判断。
观看时留意:客户端看见的是代理入口还是后端地址,代理又替谁选择后端?
与本课的关系:视频解释代理位置。课程中的端口、upstream 名称和隔离边界以本课配置为准。
upstream 定义后端组本课的核心 Nginx 配置:
upstream course_backends {
server backend-a:80 max_fails=1 fail_timeout=5s;
server backend-b:80 max_fails=1 fail_timeout=5s;
}upstream course_backends 为后端服务组命名。两条 server 指向 Compose 服务的名称,避免写死容器的动态 IP。
在未指定额外调度算法时,Nginx 默认采用轮询(Round Robin)。max_fails=1 fail_timeout=5s 规定在 5 秒内如果某后端连续失败 1 次,就暂时将其剔除;这属于请求驱动的被动熔断,不是主动探针检测。
入口代理配置:
location / {
proxy_pass http://course_backends;
proxy_connect_timeout 2s;
proxy_read_timeout 5s;
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_timeout 6s;
proxy_next_upstream_tries 2;
}proxy_pass 把请求转发给后端组。proxy_connect_timeout 2s 限制连接单个后端的等待时间,proxy_next_upstream_timeout 6s 限制本次请求在候选后端之间重试的总时间。没有这两个边界时,停止后端后的第一条请求可能等待很久,终端看上去像“卡住了”。
进入 ECS 上的项目目录:
[ECS] mkdir -p ~/cloud-course/lab-08
[ECS] cd ~/cloud-course/lab-08
[ECS] cp -r starter/* .实训包包含 compose.yaml、lb.conf 和两个后端目录(从智慧职教课程资源区下载 lab-08-starter.zip 解压)。
解析 Compose 配置:
[ECS] docker compose config --services输出应包含 backend-a、backend-b、lb。这能证明 service 定义正确。
[ECS] docker compose config --quiet命令静默无输出说明 YAML 语法合法。而 Nginx 内部的配置文件语法,等容器启动后再用 nginx -t 进一步校验。
[ECS] ss -lnt 'sport = :18008'启动前预期无输出。如果端口已被占用,请先暂停,并按课程分配重新确认端口。
启动容器服务:
[ECS] docker compose up -d
[ECS] docker compose psbackend-a、backend-b 只显示内部 80;lb 显示 127.0.0.1:18008->80/tcp。
检查 Nginx 配置:
[ECS] docker compose exec -T lb nginx -t预期出现 syntax is ok 和 test is successful。这能证明语法和引用文件可加载,后端页面能不能访问还得接着看。
分别从负载均衡器直连两个后端:
[ECS] docker compose exec -T lb wget -qO- http://backend-a/输出应包含 backend-a。
[ECS] docker compose exec -T lb wget -qO- http://backend-b/输出应包含 backend-b。两次直连把“后端本身不可达”和“负载算法异常”分开。
云主机 B 隔离 Compose 项目 · 2026-07-28 真实运行
root@SYG680400:/opt/xpk-course-demos/lesson-08$ docker compose psSERVICE IMAGE STATUS PORTSbackend-a nginx:1.27-alpine Up (healthy) 80/tcpbackend-b nginx:1.27-alpine Up (healthy) 80/tcplb nginx:1.27-alpine Up (healthy) 127.0.0.1:18008->80/tcp这条命令读取运行状态。应关注服务名称、健康状态、就绪数量和端口映射,不要只凭命令返回了表格就判断业务正常。
这一步是“三个服务健康、后端无宿主机映射、入口回环绑定、Nginx 配置和两条后端直连通过”证据链中的一环。
不能单独证明请求已在两个后端之间分配

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
从回环入口出发,沿着 location、upstream 和后端响应定位负载均衡证据。
curl 访问 ECS 127.0.0.1:18008,请求先进入 lb:80。
一次请求只能证明”某个后端返回了响应”,请求是不是真的分到了不同后端还得继续验证。
Bash for 循环的格式是 for 变量 in 列表; do 命令; done——i 依次取列表中的每个值,$i 在循环体内展开为当前值。下面的循环把 i 从 1 走到 6,每次请求入口并提取后端标识:
[ECS] for i in 1 2 3 4 5 6; do
printf 'request-%s -> ' “$i”
curl -sS http://127.0.0.1:18008/ | grep -o 'backend-[ab]'
done预期交替或近似交替出现 backend-a、backend-b。默认轮询表示按请求选择后端,但连接复用、失败重试和配置变化都会影响实际序列;验收重点是两个标识都出现,不要求死记固定顺序。
观看时留意:为什么一次请求不能证明轮询,多次请求时应该观察哪个后端标记?
与本课的关系:轮询结果要用连续请求验证,不能只凭配置文件声称负载均衡已经生效。
[ECS] curl -sSI http://127.0.0.1:18008/ | grep -i '^X-Course-Upstream:'本课配置额外返回 X-Course-Upstream,用于教学观察。生产环境是否公开上游信息要根据安全策略决定。
云主机 B 回环入口 127.0.0.1:18008 · 2026-07-28 真实请求
...$ for i in 1 2 3 4 5 6; do curl ...; donerequest-1 -> backend-arequest-2 -> backend-arequest-3 -> backend-brequest-4 -> backend-arequest-5 -> backend-brequest-6 -> backend-a这条命令沿实际访问路径发起请求。状态码、响应头或正文是本步的判断依据;只看到一次响应,还不能说明服务长期稳定。
这一步是“连续六次请求中同时出现 backend-a 和 backend-b”证据链中的一环。
不能证明后端性能相同、长期严格交替或写请求可以安全重试

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
故障前保存基线:
[ECS] docker compose ps只停止本项目的 backend-b:
[ECS] docker compose stop backend-b再次连续请求:
[ECS] for i in 1 2 3 4; do
curl --max-time 8 -sS http://127.0.0.1:18008/ | grep -o 'backend-[ab]'
done预期请求仍返回 backend-a。--max-time 8 是客户端总等待上限;首次命中故障后端时,Nginx 会在配置的连接和重试时间内转向下一项可用后端。
查看最近日志:
[ECS] docker compose logs --since 30s --tail 20 lb重点寻找 connect() failed、upstream 地址和最终 HTTP 状态。日志能说明负载均衡器怎样处理请求,不要因为看到一行错误就认定整个站点已经不可用。
恢复后端:
[ECS] docker compose start backend-b先确认容器健康:
[ECS] docker compose ps等待 backend-b 为 healthy,超过 fail_timeout 后再次执行多次请求。重新看到 backend-a 与 backend-b,表示后端已经回到请求链。
命令和相邻输出按原始捕获顺序拆开显示。切换步骤时,先看命令,再从输出中找判断依据。
...$ docker compose stop backend-bContainer cloud-course-lab-08-backend-b-1 Stopped“停止指定服务”保留了完整命令和与它相邻的输出。判断时应直接引用输出中的字段或状态,不要把步骤名称当成结论。
这一步是“backend-b 停止后入口重试 backend-a 并保持 200,恢复后两项后端重新出现”证据链中的一环。
只验证本课 GET 请求和单后端连接故障,不代表入口、主机或数据层高可用

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
完整记录按“停止后端—重复请求—查看日志—启动后端—再次请求”的顺序展开。日志中出现 connect() failed,描述的是 Nginx 访问上游时遇到的故障,不代表 docker compose logs 这条查询命令执行失败。
云主机 B · cloud-course-lab-08 · 2026-07-28
root@SYG680400:/opt/xpk-course-demos/lesson-08$ for i in 1 2 3 4; do curl --max-time 8 -sS http://127.0.0.1:18008/ | grep -o 'backend-[ab]'; donebackend-abackend-abackend-abackend-abackend-b 停止后,四次只读请求仍由 backend-a 返回
backend-b 停止后,四次只读请求仍由 backend-a 返回
不能据此推断带副作用的写请求可以安全重试

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
四行 backend-a 与上方同一条循环命令直接对应,说明捕获时这些只读请求仍得到响应。它没有说明 Nginx 怎样完成切换,下一张日志才补上内部证据。
云主机 B · cloud-course-lab-08 · 2026-07-28
root@SYG680400:/opt/xpk-course-demos/lesson-08$ docker compose logs --since 30s --tail 20 lbconnect() failed (113: Host is unreachable) while connecting to upstreamstatus=200 upstream=IP-HIDDEN, IP-HIDDEN upstream_status=502, 200第一次上游连接失败后,Nginx 尝试另一后端并最终返回 200
第一次上游连接失败后,Nginx 尝试另一后端并最终返回 200
内部地址已遮盖,日志只对应捕获时的这次 GET 请求

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
日志中的 connect() failed 是第一次上游连接失败,upstream_status=502, 200 表示同一请求先遇到失败,随后从另一候选后端取得成功响应。内部地址已经遮盖,这段日志也只对应捕获时的 GET 请求。
云主机 B · cloud-course-lab-08 · 2026-07-28
root@SYG680400:/opt/xpk-course-demos/lesson-08$ for i in 1 2 3 4 5 6; do curl -sS http://127.0.0.1:18008/ | grep -o 'backend-[ab]'; donebackend-abackend-bbackend-abackend-bbackend-abackend-bbackend-b 恢复并度过失败窗口后,两项后端重新出现在请求结果中
backend-b 恢复并度过失败窗口后,两项后端重新出现在请求结果中
不能说明两项后端性能相同,也不能证明长期分配比例固定

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
输出重新同时出现 backend-a 与 backend-b,证明恢复后的后端已经回到请求链。这个短序列只能证明两个后端都被选中过,不能用来比较性能或推断长期分配比例。
观看时留意:后端退出调度和后端成为备用节点时,请求分配会发生什么变化?
与本课的关系:配置状态不等于完整高可用。本课还要用故障请求、日志和恢复结果验证。
输入脱敏后的配置检查、后端直连、入口请求或日志,让助教区分入口、upstream 和后端故障。
本实验的原始聊天仅保存在当前标签页,不会写入全局课程助教上下文。
开源 Nginx 的上述配置依赖真实请求发现连接错误。它没有解决所有高可用问题:
lb 仍然是单个入口,若它停止,两个后端都无法通过该入口访问;因此,本课结果应表述为“单个后端连接失败时,入口仍能把本次只读请求交给另一个后端”,而不是“系统已经永不宕机”。
nginx -t 失败
先根据错误行号检查 upstream、分号和 proxy_pass。不要反复重启,配置无法加载时重启只会重复失败。
两个后端直连都成功,入口返回 502
查看 lb 日志和 proxy_pass 的组名,确认入口 location 使用的是 course_backends,再检查 Nginx 是否加载了修改后的配置。
多次请求始终只有一个后端
先确认另一后端健康并能直连,再检查是否存在 ip_hash、权重、失败计数或浏览器缓存。不要仅凭两次请求断定轮询失效。
停止一个后端后入口也失败
检查另一后端能否直连、proxy_next_upstream 条件和错误日志。若两个后端同时不可达,负载均衡器无法凭空生成业务响应。
完整步骤见实训 08:负载均衡与后端故障恢复。
保底任务
标准任务
nginx -t;backend-b,记录入口、日志与恢复结果;verify.sh,清理项目并确认 18008 释放。挑战任务
backend-a 设置权重 2,记录 12 次请求的分布;least_conn,说明它与轮询关注的指标差异;提交前清理实验环境:
[ECS] docker compose down
[ECS] ss -lnt 'sport = :18008'
[ECS] rm -rf ~/cloud-course/lab-08最后一条确认 18008 端口已释放。
提交:
班级_学号_姓名_第08次课_Nginx负载均衡报告.docx只上传一个 Word 到智慧职教“第08次课”,不上传公网地址、SSH 配置、容器日志全集或其他项目信息。
检查项目范围、轮询证据、单后端故障、恢复、能力边界和提交规范。
这组题不重复本课术语,而是检查你能否把前八次课的环境定位、Web 链路、备份恢复、Compose 依赖和负载均衡证据重新调动起来。先独立作答;错题回到对应证据层复查,不靠背选项。
用 4 道跨课题检查环境、Web、备份和多服务排障知识是否仍能调动。
完成后可立即查看反馈和解析。
upstream 定义后端组,默认算法为轮询。下一次课将进入阶段考核:从环境基线出发,独立定位并修复一组匿名化故障。
带入第 9 次课的不是某一条“万能修复命令”,而是一张简短工单:正常基线是什么、故障时哪一层先异常、你用了什么最小修改、修复后跑了哪些同路检查。阶段考核只提供现象,不提示故障层级,这张工单就是你的排查路线。
以下资料在 2026-07-28 核对:
助教会读取当前课程页面和结构化学习记录,但不会读取正文实验框里的原始聊天。