KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
Kubernetes 应用课:把编排用对 — keel 龙骨
Kubernetes 应用课:把编排用对 的参考信息:Kubernetes 应用课:把编排用对
课程总览 · 从「会写 YAML」到「能说出这份清单在集群里会怎么跑、哪里会卡住」
Kubernetes 的学习难点不在名词数量,而在它的工作方式和人的直觉相反。
你写一份清单说"我要 4 个副本",kubectl apply 返回成功——但此刻没有任何一个副本在运行,而且不保证将来会有 4 个。你改了一行配置,返回成功——但已经在跑的 Pod 里那行配置还是旧值。你把探针周期调小想让故障被发现得更快——结果每次发布都要多等一轮。
这三件事有同一个根源:K8s 是声明式 + 异步收敛的。"提交了期望状态"和"期望状态已达成"之间隔着一个持续运行的控制器,中间可以卡住、可以超时、可以永久无法达成。
三个现场
现场一:kubectl apply 成功,服务却 502。
Service 的 selector 写的是 app: orders-api,Deployment 的 Pod 模板标签写的是 app: orders-api-v2——两份清单各自都合法,字段校验一个都不报错。但 Service 选不到任何 Pod,于是它没有 endpoints,访问它的流量立刻被拒。这个 bug 在你改过一个标签之后出现,而改动者当时只想着"标签叫得清楚点"。
现场二:新版本上线,用户看到间歇性 503。
maxUnavailable 用了默认值,滚动更新过程中旧副本被减到低于可用下限;同时没有配 readinessProbe,新 Pod 刚被创建就被算作"可用",流量打进去时它还在初始化。
现场三:节点内存告急,最占内存的那个 Pod 被杀了——但它是被冤枉的。
因为所有容器都没写 limits,节点一旦内存紧张,内核按"谁用得多杀谁"来选受害者,而不是按"谁的责任"。没有 limits 不等于不会被杀,只等于被杀时没有保护。
三个现场都不需要你懂 etcd 或调度器算法。它们要的是同一层认知:声明式系统里,期望、判定与后果是三件被拆开的东西。
这门课回答什么
| 你可能正在纠结的问题 | 在哪一章 |
|---|---|
kubectl apply 成功到底意味着什么?控制器在调和什么? |
01 |
| Deployment、Service、ConfigMap、Job 各自负责哪一段?标签为什么是关键? | 02 |
| 探针为什么要三种?分别判错了会怎样? | 03 |
requests 和 limits 为什么必须分开写?超卖是什么意思? |
04 |
滚动更新到底在滚什么?maxUnavailable: 0 保证什么? |
05 |
| ConfigMap 改了为什么 Pod 里没变?密钥怎么进集群? | 06 |
Pending / CrashLoopBackOff / ImagePullBackOff 分别从哪查起? |
07 |
这门课不回答什么
- 不重复容器本身(构建上下文、镜像层、信号与停机三段时序)。那是《Docker 应用课》 的内容,本课假定你已经读过它的 03、06 两章——探针的等待窗口与
terminationGracePeriodSeconds是同一件事的两种表达。 - 不讲控制平面组件原理(etcd 一致性、调度器打分算法、CNI 实现、kubelet 内部机制)。知道"有一个控制器在不停把实际状态拉向期望状态"就够了,再往下属于各自的项目文档。
- 不讲服务网格、多集群、Operator 开发。这些是各自独立的主题,需要时以对应官方文档为准。
- 不讲供应链硬化(按 digest 部署、签名校验、准入控制)。那是《构建打包与部署上线》 与《CI 流水线与质量门禁》 的落点。
与相邻课程的分工
| 课程 | 视角 | 本课与它的关系 |
|---|---|---|
| 《Docker 应用课》 | 容器作为运行环境 | 前置。它的 06 章讲三段时序与 PID 1,本课 05 章的 terminationGracePeriodSeconds 就是那个等待窗口 |
| 《构建打包与部署上线》 | 镜像作为发布产物 | 它 02 章讲镜像、04 章讲五种部署策略的取舍;本课 05 章把其中"滚动更新"这一种落到 K8s 的实际算术上 |
| 《CI 流水线与质量门禁》 | 流水线闸门 | 本课 01 章的"离线校验管道"是流水线里 kubectl apply 之前该有的那一步 |
| 《PostgreSQL 应用课》 | 数据层怎么被正确使用 | 本课 06 章的迁移 Job 与它 05 章的权限/租户讨论在"谁有权改表"这一点上相邻 |
学完以后你能做什么
- 拿到一份清单,能说出每个
kubectl apply成功之后还要等什么,以及等不到时会卡在哪个状态; - 能用两条互补的静态检查(单对象 schema + 跨对象不变量)在提交前抓出 selector 失配、请求超过限制、滚动参数死锁这类问题——并知道这两条都替代不了集群;
- 能解释探针三件套各自的判定后果(重启 / 摘流量 / 延迟生效),并算出启动容忍预算;
- 能算出全清单的
requests合计与limits合计,说出它的超卖比意味着什么; - 能说出
ConfigMap改了之后哪一部分会变、哪一部分不会; - 面对五种常见异常状态,知道第一个该看的字段是什么。
关于证据口径
这门课的实测证据分三层,正文逐处标注:
- 真跑的工具输出:
kubectl kustomize(纯离线构建,本机 kubectl v1.34.1 / Kustomize v5.7.1)、kubeconform v0.8.0(官方 JSON Schema 校验)、以及本课配套的一个静态不变量检查脚本。原始输出留档。 - 本机没有集群:所以
kubectl apply、kubectl get pods、kubectl rollout status、kubectl describe的真实输出没有实测。凡涉及集群内实际行为的描述,按官方文档写成机制说明并标注。 - 一个直接验证到的反直觉事实:
kubectl apply --dry-run=client --validate=false在没有集群时也会失败——它需要向 API 服务器做 API discovery。所以"没集群就用 dry-run 自查"这条流传很广的做法是不成立的,真正离线可用的是kubectl kustomize。
第 3 条本身就值得单独记住:判断一个工具能不能在离线环境用,唯一的办法是拔掉集群试一次。