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 状态机

Revision 生命周期状态机 创建中 Building 就绪 Ready 活跃 Active 保留 Reserved 已退役 Retired 错误 Error 构建成功 构建失败 流量接入 流量移除 保留超时 重新接入流量 从未接入流量 重试构建 说明:实线为正常流转路径,虚线为特殊/异常路径。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,以便在出现问题时快速回滚到已知良好的版本。