外观
实训 15:K3s 工作负载、Service 与扩缩容
约 2076 字大约 7 分钟
云计算实训第15次课
2026-07-30
1. 任务情境
课程团队准备把一个静态站点交给 Kubernetes 管理。你需要在教师指定的隔离集群中完成单副本部署,证明 Service 可以访问页面,再把副本扩到 3。随后注入一次“Service 选不中 Pod”的可恢复故障,按证据定位并恢复,最后只清理本课命名空间。
本实训不要求在个人低配 WSL 或云主机 B 上安装 K3s。教师演示环境为本地 k3d/K3s;学生只操作教师授权的上下文和 cloud-course-15 命名空间。
2. 环境与安全边界
| 项目 | 课堂要求 |
|---|---|
| 控制端 | Windows 11 的 WSL,或教师准备的本地终端 |
| 集群 | 教师指定的隔离 K3s/k3d 集群 |
| 命名空间 | cloud-course-15 |
| 工作负载 | lesson15-web |
| 镜像 | nginx:1.27-alpine |
| 允许变更 | 本课清单、Deployment 副本数、本课 Service 选择器 |
| 禁止操作 | 其他命名空间、系统组件、未知集群、全局删除、kubeconfig 上传 |
开始前完成四项确认:
- 教师已经明确本课 kubecontext;
- 当前上下文不是生产集群或其他课程集群;
- 只操作
cloud-course-15; - 报告不会包含 kubeconfig、令牌、证书、完整地址和其他命名空间数据。
3. 起始文件
将 starter/ 复制到个人实验目录:
[WSL] mkdir -p "$HOME/cloud-course/lab-15"创建本课个人目录。
[WSL] cp -R starter/. "$HOME/cloud-course/lab-15/"复制清单和验收脚本。不要移动教师原始文件。
[WSL] cd "$HOME/cloud-course/lab-15"进入本课目录。后续相对路径都以这里为起点。
目录应包含:
lab-15/
├── manifests/
│ ├── namespace.yaml
│ ├── configmap.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
├── verify.sh
└── cleanup.sh4. 步骤一:上下文与节点预检
[WSL] kubectl config current-context记录当前上下文。若与教师公布名称不同,立即停止,不执行 apply。
[WSL] kubectl cluster-info检查 API Server 是否可访问。报告遮盖完整地址,只保留“可访问/不可访问”和集群类型。
[WSL] kubectl get nodes -o wide预期至少一个节点为 Ready。记录版本、角色和容器运行时;不要把 Ready 写成应用已经可用。
5. 步骤二:阅读并预检清单
[WSL] kubectl kustomize manifests > lesson15-rendered.yaml把所有资源展开到临时文件,便于整体检查。该文件不包含凭据,但提交前仍只截取本课对象。
[WSL] grep -E '^(kind:| name:| namespace:| replicas:| image:| type:)' \
lesson15-rendered.yaml查看对象类型、名称、命名空间、副本、镜像和 Service 类型。预期副本为 1、Service 为 ClusterIP。
[WSL] kubectl apply --dry-run=client -k manifests执行客户端预检。全部对象显示 created (dry run) 后才能继续。
检查点 1:
- 命名空间是否只为
cloud-course-15; - Deployment 与 Service 的标签是否一致;
- 是否设置 readinessProbe 和 livenessProbe;
- 是否设置 CPU、内存 requests/limits;
- 是否没有 NodePort、LoadBalancer 和公网地址。
6. 步骤三:部署单副本
[WSL] kubectl apply -k manifests提交四类对象。记录 created/configured 结果。
[WSL] kubectl rollout status deployment/lesson15-web \
-n cloud-course-15 --timeout=120s等待 Deployment 完成。超时后不要反复 apply,转到第 9 节排查。
[WSL] kubectl get pod,service -n cloud-course-15 -o wide预期一个 Pod 为 1/1 Running,Service 类型为 ClusterIP。
[WSL] kubectl get deployment lesson15-web -n cloud-course-15预期 READY 为 1/1、AVAILABLE 为 1。
截图 1 应包含节点、Pod、Service 和明确的本地/授权环境说明。
7. 步骤四:验证 Service 路径
[WSL] kubectl get endpointslice -n cloud-course-15 \
-l kubernetes.io/service-name=lesson15-web -o wide预期 EndpointSlice 中有一个端点。若为 <none>,先比 Service selector 与 Pod labels。
[WSL] kubectl exec -n cloud-course-15 deploy/lesson15-web -- \
wget -q -O - http://lesson15-web从 Pod 内访问 Service DNS。预期 HTML 中同时出现:
K3s service ready
deployment=lesson15-web截图 2 应包含请求命令、页面关键内容和 EndpointSlice。报告注明这只证明集群内部路径。
8. 步骤五:从 1 扩容到 3
[WSL] kubectl scale deployment/lesson15-web \
-n cloud-course-15 --replicas=3把期望副本改为 3。scaled 不是最终验收。
[WSL] kubectl rollout status deployment/lesson15-web \
-n cloud-course-15 --timeout=120s等待三个副本达到可用。
[WSL] kubectl get deployment,pods -n cloud-course-15 -o wide记录 Deployment 3/3、三个 Pod 的就绪状态和不同 Pod IP。
[WSL] kubectl get endpointslice -n cloud-course-15 \
-l kubernetes.io/service-name=lesson15-web -o wide预期端点由一个增加到三个。它说明 Service 选择了三个就绪 Pod,不代表流量一定平均。
[WSL] bash verify.sh运行自动验收。全部为 PASS 后保留结果。
截图 3 应包含 Deployment 3/3、三个就绪 Pod 和三个端点。
9. 步骤六:注入并恢复 Service 选择器故障
先保存原值:
[WSL] kubectl get service lesson15-web -n cloud-course-15 -o yaml \
> lesson15-service.before.yaml确认备份文件非空。
[WSL] test -s lesson15-service.before.yaml && echo "[PASS] service baseline saved"预期输出 PASS。
注入故障:
[WSL] kubectl patch service lesson15-web -n cloud-course-15 \
--type=merge -p '{"spec":{"selector":{"app.kubernetes.io/name":"wrong-label"}}}'只改变本课 Service 的选择器。
[WSL] kubectl get service,pods,endpointslice \
-n cloud-course-15 --show-labels观察 Service 仍存在、Pod 仍 Running,但 selector 与 labels 不同,端点为空。
[WSL] kubectl exec -n cloud-course-15 deploy/lesson15-web -- \
wget -T 3 -q -O - http://lesson15-web请求预期超时或失败。保留退出状态和原始现象,不要反复重启 Pod。
恢复:
[WSL] kubectl apply -f manifests/service.yaml用课程原始清单恢复 Service。lesson15-service.before.yaml 含服务端生成字段,仅用于保留原值和现象;资源变化后直接 apply 它可能发生 resourceVersion 冲突。
[WSL] kubectl get endpointslice -n cloud-course-15 \
-l kubernetes.io/service-name=lesson15-web -o wide等待三个端点重新出现。
[WSL] bash verify.sh沿原来的上下文、对象、端点和 HTTP 路径完成回归。
10. 常见故障排查
10.1 Pod 长时间 Pending
[WSL] kubectl describe pod -n cloud-course-15 POD_NAME把 POD_NAME 换成实际名称。查看 Events 是否提示资源不足、节点不可调度或约束不满足。
10.2 ImagePullBackOff
[WSL] kubectl get pods -n cloud-course-15先确认具体 Pod。
[WSL] kubectl describe pod -n cloud-course-15 POD_NAME查看镜像名和拉取错误。不要在聊天、截图或命令历史中粘贴镜像仓库密码。
10.3 Running 但 0/1
[WSL] kubectl describe pod -n cloud-course-15 POD_NAME检查 Readiness probe 失败的路径、端口和状态码。
[WSL] kubectl logs -n cloud-course-15 POD_NAME --tail=30查看应用最近日志。日志无错误也不能替代探针和请求验证。
10.4 Service 没有端点
[WSL] kubectl get service lesson15-web -n cloud-course-15 \
-o jsonpath='{.spec.selector}{"\n"}'打印 Service 选择器。
[WSL] kubectl get pods -n cloud-course-15 --show-labels显示 Pod 标签。逐字段比较,不要重启整个集群。
11. 恢复与清理
如果故障练习尚未恢复,先执行:
[WSL] kubectl apply -f manifests/service.yaml用版本控制中的原始清单恢复 Service。
[WSL] bash verify.sh确认扩容后的完整路径通过。
[WSL] bash cleanup.sh脚本只删除 cloud-course-15 命名空间,并检查是否返回 NotFound。
[WSL] kubectl get namespaces复核其他命名空间仍在。不要删除不认识的资源。
12. 人工检查
自动脚本之外,教师还会检查:
- 上下文与命名空间边界是否正确;
- 单副本与三副本证据是否来自同一隔离环境;
- Service 请求是否确实返回本课页面;
- 故障是否保留原始现象、原配置和恢复回归;
- 是否把 ClusterIP 写成了集群内部入口;
- 是否删除本课命名空间且未影响其他资源;
- Word 是否不含 kubeconfig、令牌、证书和完整地址。
13. 报告与提交
填写:
班级_学号_姓名_第15次课_K3s入门报告.docx至少包含:
- 环境门禁和 kubecontext 核对;
- 清单结构与标签关系;
- 节点、Pod、Deployment、Service 的分层证据;
- Service 内部访问结果;
- 从 1 到 3 的扩容前后对比;
- 选择器故障、证据、恢复和同路回归;
- 自动验收与人工检查;
- 清理结果和证明范围。
只上传 Word 到智慧职教“第15次课”。不要上传 lesson15-rendered.yaml、lesson15-service.before.yaml、kubeconfig、证书、令牌或完整终端历史。
