本篇定位
本篇是 Kubernetes 分类的动手实践总纲.每个 Lab 对应前面 1-2 篇理论知识,按复杂度递进.
建议搭建好 k3d 本地集群后,从 Lab 1 开始逐个完成.遇到卡点先翻对应理论篇,实在解决不了再看第 10 篇参考答案.
Lab 0 - 环境搭建
安装工具
|
创建本地集群
|
为什么选 k3d
- k3d 在 Docker 容器中运行 K3s(轻量 K8s 发行版),启动速度快(10 秒内),资源占用低(每节点约 256MB)
- 支持多节点,且自带 Ingress Controller 和 StorageClass,非常适合本地实验
- 如果你更熟悉 kind 或 minikube 也可以使用,核心操作一致
创建实验 namespace
|
Lab 1 - Pod 基础(对应第 02 篇)
学习目标
- 创建和删除 Pod
- 理解 Pod 的生命周期和状态
- 配置探针(liveness / readiness)
- 使用 Init Container
实验任务
Lab 1 任务清单
- 基础 Pod:创建一个 nginx Pod,验证它进入 Running 状态.用
kubectl exec进入 Pod 执行curl localhost. - 多容器 Pod:创建一个 Pod 包含两个容器(nginx + busybox sidecar).busybox 每秒向共享 emptyDir 写入时间戳,nginx 通过挂载同一目录提供文件下载.
- 探针配置:给 nginx Pod 配置 livenessProbe(HTTP GET /)和 readinessProbe(HTTP GET /ready).故意把 readinessProbe 的路径改为不存在的
/healthz,观察 Pod 状态变化(READY 0/1 但仍 Running). - Init Container:创建一个 Pod,Init Container 用
wget下载一个文件到共享 Volume,主容器启动后读取这个文件.验证 Init Container 先于主容器执行. - 资源限制:创建一个 Pod 设置
resources.requests.memory: 64Mi, limits.memory: 128Mi.在 Pod 内运行一个消耗内存的命令(如 stress),观察 OOMKilled.
验证标准
完成 Lab 1 后,你应该能:
- 不看文档写出一个基本 Pod YAML
- 解释 Pod 处于 CrashLoopBackOff / ImagePullBackOff / Pending 各自意味着什么
- 理解探针失败时 K8s 的行为差异(liveness 失败 → 重启,readiness 失败 → 移出 Endpoints)
Lab 2 - 工作负载控制器(对应第 03 篇)
学习目标
- 使用 Deployment 管理无状态应用
- 观察滚动更新过程
- 执行回滚操作
- 体验 StatefulSet 的有序性
实验任务
Lab 2 任务清单
- Deployment 基础:创建一个 Deployment(nginx:1.24, replicas=3).验证 3 个 Pod 都 Running.手动删除一个 Pod,观察是否自动重建.
- 滚动更新:将镜像从 nginx:1.24 更新到 nginx:1.25.同时在另一个终端
kubectl get pods -w观察新旧 Pod 的创建/删除顺序. - 调整更新策略:设置
maxSurge=0, maxUnavailable=1,再次更新到 nginx:1.26,对比滚动行为的差异(先删后建 vs 先建后删). - 回滚:查看 rollout history,回滚到 revision 1(nginx:1.24).验证 Pod 镜像版本.
- StatefulSet 有序性:创建一个 StatefulSet(busybox, replicas=3),观察 Pod 创建顺序是否严格按 0→1→2.缩容到 1,观察删除顺序是否按 2→1.
- DaemonSet:创建一个 DaemonSet(busybox + sleep),验证每个 worker 节点恰好有一个 Pod.给一个节点加 Taint,观察是否有 Pod 被驱逐或无法调度.
Lab 3 - Service 与服务发现(对应第 04 篇)
学习目标
- 创建 ClusterIP / NodePort Service
- 验证 DNS 服务发现
- 理解 Endpoints 与 readiness 的关系
- 体验 Headless Service
实验任务
Lab 3 任务清单
- ClusterIP:为 Lab 2 的 Deployment 创建一个 ClusterIP Service(port:80, targetPort:80).启动一个临时 Pod(
kubectl run tmp --image=curlimages/curl -it --rm -- sh),用 Service 名和 ClusterIP 分别 curl,验证负载均衡(多次 curl 看 hostname). - DNS 发现:在临时 Pod 中用
nslookup验证 DNS 解析.尝试完整域名..svc.cluster.local. - NodePort:将 Service 改为 NodePort,从宿主机
curl localhost:验证外部访问. - Endpoints 联动:给 Deployment 加一个必定失败的 readinessProbe.观察 Endpoints 列表变为空.恢复探针后验证 Endpoints 重新填充.
- Headless Service:创建一个 Headless Service(clusterIP: None)+ StatefulSet.用
nslookup验证返回的是多个 Pod IP 而非 ClusterIP.再用nslookup .验证逐 Pod DNS.
Lab 4 - Ingress 七层路由(对应第 05 篇)
学习目标
- 创建 Ingress 实现域名路由和路径路由
- 配置 TLS(自签名证书)
- 使用 annotation 做路径重写
实验任务
Lab 4 任务清单
- 域名路由:创建两个 Deployment+Service(app-a 和 app-b,各自返回不同内容).创建 Ingress 将
a.lab.local→ app-a,b.lab.local→ app-b.修改 /etc/hosts 后用 curl 验证. - 路径路由:创建一个 Ingress 将
lab.local/api→ api-svc,lab.local/→ frontend-svc.验证不同路径到达不同后端. - TLS:用 openssl 生成自签名证书,创建 tls Secret,在 Ingress 中启用 HTTPS.用
curl -k https://lab.local验证. - 路径重写:配置 rewrite-target 注解,使外部
/app/hello到后端变为/hello.查看后端 Nginx access log 确认路径变化.
k3d 自带 Traefik,不是 Nginx
k3d 默认安装 Traefik 作为 Ingress Controller,注解前缀和 ingress-nginx 不同.如果你想练习 Nginx Ingress 的注解(如 rewrite-target),有两种方式:
- 创建集群时禁用 Traefik:
k3d cluster create --k3s-arg "--disable=traefik@server:0",然后手动安装 ingress-nginx - 直接用 Traefik 的原生语法完成实验
Lab 5 - 配置管理(对应第 06 篇)
学习目标
- 创建和使用 ConfigMap / Secret
- 验证热更新行为差异
- 理解 subPath 的限制
实验任务
Lab 5 任务清单
- ConfigMap 环境变量:创建 ConfigMap(APP_ENV=dev, LOG_LEVEL=debug),用 envFrom 注入 Pod.exec 进 Pod 验证环境变量.
- ConfigMap 文件挂载:创建包含 nginx.conf 的 ConfigMap,挂载到 nginx Pod 的
/etc/nginx/conf.d/.验证 Nginx 使用了自定义配置. - 热更新验证:修改 ConfigMap 的 LOG_LEVEL 值.等 2 分钟后:1. 检查 envFrom 注入的 Pod 环境变量是否变化(预期不变);2. 检查 Volume 挂载的文件是否更新(预期更新).
- subPath 限制:用 subPath 挂载 ConfigMap 中的单个文件.修改 ConfigMap 后验证文件不会自动更新.
- Secret:创建 Secret(username/password),以 Volume 方式挂载到 Pod 的
/etc/secrets/.验证文件权限和内容(应为明文,不是 Base64). - 触发滚动更新:用
kubectl rollout restart deployment/xxx使环境变量注入的配置变更生效.
Lab 6 - 持久化存储(对应第 07 篇)
学习目标
- 对比 emptyDir 和 PVC 的数据持久性
- 使用 StorageClass 动态供给
- 验证 StatefulSet + volumeClaimTemplates
实验任务
Lab 6 任务清单
- emptyDir 生命周期:创建 Pod + emptyDir 挂载到 /data,写入文件.删除 Pod 后重建同名 Pod,验证数据丢失.
- PVC 持久化:创建 PVC(storageClassName: local-path, 1Gi)+ Pod 挂载到 /data,写入文件.删除 Pod,重新创建引用同一 PVC 的 Pod,验证数据保留.
- 动态供给观察:创建 PVC 后用
kubectl get pv观察 PV 是否自动创建.kubectl describe pvc查看绑定状态和事件. - StatefulSet 独立存储:创建 StatefulSet(replicas=3)+ volumeClaimTemplates.验证生成 3 个独立 PVC.在每个 Pod 中写入不同内容,重建 Pod 后验证各自数据独立保留.
- 缩容不删 PVC:将 StatefulSet 缩容到 1,验证 PVC 仍存在.扩回 3,验证数据自动恢复.
- PVC 扩容:修改 PVC 的 requests.storage(如 1Gi → 2Gi),观察 PV 容量是否跟着变化.(注意:local-path 可能不支持在线扩容,若失败则记录原因.)
Lab 7 - 综合实战:部署完整微服务(对应第 01-08 篇)
学习目标
- 将前面所有知识串联在一个真实场景中
- 部署一个包含前端 + API + 数据库 + 缓存的完整应用
- 配置完整的流量链路(Ingress → Service → Pod)
实验任务
Lab 7 任务清单
- 部署 Redis(缓存):StatefulSet + Headless Service + PVC,单副本即可.
- 部署 PostgreSQL(数据库):StatefulSet + Headless Service + PVC + Secret(存储密码).
- 部署 API 服务:Deployment(2 副本)+ ClusterIP Service.通过 ConfigMap 注入 Redis 和 PostgreSQL 的连接信息,Secret 注入数据库密码.
- 部署前端:Deployment(2 副本)+ ClusterIP Service.
- 配置 Ingress:
app.lab.local/api→ api-svc,app.lab.local/→ frontend-svc. - 配置 HPA:为 API 服务配置 HPA(CPU 目标 60%,min=2,max=10).
- 验证完整链路:从浏览器访问
http://app.lab.local,验证前端 → API → 数据库/缓存的完整调用链. - 模拟故障:删除 PostgreSQL Pod,观察 StatefulSet 自动重建 + PVC 数据恢复.删除一个 API Pod,观察 Deployment 自动补齐 + Service 端点自动更新.
镜像建议
如果不想自己写应用代码,可以使用现成的镜像:
- Redis 直接用
redis:7-alpine - PostgreSQL 用
postgres:16-alpine - API 可以用
hashicorp/http-echo或nginx模拟(返回固定内容即可验证链路) - 前端同理用 nginx 提供静态页面
重点是练习 K8s 资源编排,不是写业务代码.
环境清理
|
小结
快速回顾
- Lab 0:k3d 搭建 3 节点本地集群,安装 kubectl / k9s
- Lab 1:Pod 创建,多容器,探针,Init Container,资源限制
- Lab 2:Deployment 滚动更新/回滚,StatefulSet 有序性,DaemonSet
- Lab 3:ClusterIP/NodePort Service,DNS 发现,Endpoints 联动,Headless
- Lab 4:Ingress 域名/路径路由,TLS,路径重写
- Lab 5:ConfigMap/Secret 注入方式,热更新验证,subPath 限制
- Lab 6:emptyDir vs PVC 生命周期,动态供给,StatefulSet 独立存储,扩容
- Lab 7:完整微服务部署(前端 + API + DB + 缓存 + Ingress + HPA)
参考答案
每个 Lab 的完整 YAML 和操作步骤详见第 10 篇-Lab 参考答案.建议先独立尝试,遇到阻塞再查阅.