4. Revision 创建与版本控制:Configuration 变更触发 Revision 创建、Revision 生命周期管理
在 Knative Service 模型中,Revision(修订版本) 是流量管理和版本控制的核心单元。每个 Revision 代表一个不可变的快照,包含代码、配置和运行时环境。本章深入剖析 Revision 的创建机制、生命周期状态转换以及 Configuration 如何驱动版本演进。
4.1 Configuration 变更触发 Revision 创建
Knative 采用 Configuration → Revision 的驱动模型。每当用户更新 Service 的 .spec.template 字段(例如修改镜像、环境变量、资源限制或并发设置),Configuration 控制器会检测到变更,并自动生成一个新的 Revision。
关键原则: Revision 一旦创建即为不可变对象。任何配置变更都不会修改已有 Revision,而是创建新的 Revision。这一设计保证了版本的可追溯性和回滚能力。
4.1.1 触发 Revision 创建的配置字段
| 配置字段 | 路径(YAML) | 变更影响 |
|---|---|---|
| 容器镜像 | spec.template.spec.containers[0].image |
镜像摘要或标签变更 → 新 Revision |
| 环境变量 | spec.template.spec.containers[0].env |
新增/删除/修改任意变量 → 新 Revision |
| 资源请求/限制 | spec.template.spec.containers[0].resources |
CPU/内存调整 → 新 Revision |
| 并发设置 | spec.template.spec.containerConcurrency |
并发数变更 → 新 Revision |
| 超时时间 | spec.template.spec.timeoutSeconds |
请求超时调整 → 新 Revision |
| 卷挂载 | spec.template.spec.volumes |
卷定义变更 → 新 Revision |
最佳实践: 在生产环境中,每次部署新镜像版本时,建议同时更新 Service 的
metadata.generation 或显式修改 spec.template 中的任意字段(如添加一个 REVISION_TIMESTAMP 环境变量),确保 Configuration 控制器能够准确感知变更。
4.1.2 Revision 命名规则
Knative 自动为每个新 Revision 生成名称,格式为:{configuration-name}-{generation-number}。例如:
# Configuration 名称: hello-world
# 第一次变更 → Revision: hello-world-00001
# 第二次变更 → Revision: hello-world-00002
# 第三次变更 → Revision: hello-world-00003
Generation 编号从 00001 开始递增,始终反映 Configuration 的变更次数。即使删除旧 Revision,新 Revision 的编号也不会回退。
4.2 Revision 生命周期管理
每个 Revision 从创建到销毁经历多个状态阶段。理解这些状态对于流量路由、自动扩缩容和故障排查至关重要。
4.2.1 Revision 状态机
4.2.2 各状态详细说明
| 状态 | 含义 | Pod 存在 | 可接收流量 | 触发条件 |
|---|---|---|---|---|
| 创建中 | Revision 正在构建容器镜像或初始化 | 否 | 否 | Configuration 变更触发 |
| 就绪 | Revision 构建完成,等待流量分配 | 否(冷启动) | 是(按需扩缩) | 构建成功,健康检查通过 |
| 活跃 | Revision 当前正在处理流量 | 是(≥1 个 Pod) | 是 | 流量路由指向该 Revision |
| 保留 | Revision 曾活跃但流量已移除,等待退役 | 可能(缩容中) | 否 | 流量百分比降至 0% |
| 已退役 | Revision 被标记为可清理,不再保留 | 否 | 否 | 保留超时或手动删除 |
| 错误 | Revision 构建或启动失败 | 否 | 否 | 镜像拉取失败、健康检查失败等 |
4.2.3 Revision 保留策略
为避免无限累积旧 Revision 占用资源,Knative 提供两种保留机制:
- 保留已就绪 Revision 数量(
revision-requested-remaining-count):默认保留 20 个就绪状态的 Revision。超过此数量时,最旧的 Revision 会被标记为已退役。 - 保留已退役 Revision 数量(
revision-requested-remaining-count):默认保留 20 个已退役状态的 Revision。超过此数量时,最旧的已退役 Revision 会被物理删除。
注意: 如果某个 Revision 正在被流量路由引用(即使流量为 0%),它不会被退役或删除。只有流量百分比明确设置为 0% 且超过保留超时时间后,Revision 才会进入退役流程。
4.3 实战:观察 Revision 创建与状态变化
以下命令演示如何通过 kubectl 观察 Revision 的创建和状态流转:
# 1. 部署 Service,查看初始 Revision
kubectl apply -f service.yaml
kubectl get revisions -l serving.knative.dev/service=hello-world
# 输出示例:
# NAME CONFIG NAME K8S SERVICE NAME GENERATION READY REASON
# hello-world-00001 hello-world hello-world-00001 1 True
# 2. 修改镜像版本,触发新 Revision
kubectl patch service hello-world --patch '{"spec":{"template":{"spec":{"containers":[{"image":"gcr.io/knative-samples/helloworld-go:v2"}]}}}}'
# 3. 观察新 Revision 创建
kubectl get revisions -l serving.knative.dev/service=hello-world
# 输出示例:
# NAME CONFIG NAME K8S SERVICE NAME GENERATION READY REASON
# hello-world-00001 hello-world hello-world-00001 1 True
# hello-world-00002 hello-world hello-world-00002 2 True
# 4. 查看 Revision 详细状态
kubectl get revision hello-world-00002 -o yaml | grep -A 5 "status:"
# 输出示例:
# status:
# conditions:
# - lastTransitionTime: "2024-01-15T10:30:00Z"
# status: "True"
# type: Ready
# - lastTransitionTime: "2024-01-15T10:30:00Z"
# status: "True"
# type: Active
# imageDigest: gcr.io/knative-samples/helloworld-go@sha256:abc123...
# observedGeneration: 2
4.4 Revision 版本控制最佳实践
核心建议:
- 命名约定: 使用有意义的 Configuration 名称,便于通过 Revision 名称追溯版本来源。
- 保留策略调整: 根据集群资源容量调整
revision-requested-remaining-count和revision-requested-remaining-count参数,避免过多 Revision 占用 etcd 存储。 - 灰度发布: 利用 Revision 不可变特性,将新 Revision 的流量百分比从 0% 逐步提升至 100%,实现零停机部署。
- 回滚准备: 始终保留至少 2-3 个历史 Revision,以便在出现问题时快速回滚到已知良好的版本。