3. Service 资源定义详解:Revision、Configuration、Route 的关系,YAML 字段含义与常见错误
Knative Service 是用户面对无服务器工作负载的唯一入口,但它背后由 Configuration、Revision 和 Route 三个核心资源协同工作。理解这三者的关系以及 YAML 字段的精确含义,是故障排查与恢复的基础。本节将拆解 Service 的抽象层,并指出最容易引发生产事故的配置陷阱。
3.1 三驾马车:Revision、Configuration、Route 的职责与关系
Knative Service 并非一个单体资源,而是一个“资源控制器”,它自动管理以下三个子资源:
| 资源 | 职责 | 核心行为 |
|---|---|---|
| Configuration | 定义“期望的”应用版本(镜像、环境变量、资源限制) | 每次 spec 变更自动创建一个新的 Revision |
| Revision | 代表一个不可变的、特定版本的代码+配置快照 | 自动扩缩容至零,基于 Configuration 自动生成 |
| Route | 将流量路由到指定的一个或多个 Revision | 支持灰度发布、流量拆分、按标签路由 |
故障排查要点: 当 Service 无法正常访问时,首先检查 Route 是否指向了正确的 Revision;其次检查 Configuration 是否生成了预期的 Revision。不要直接修改 Revision,它只读。
3.2 Service YAML 核心字段详解
一个完整的 Knative Service YAML 包含多个嵌套层。以下是生产环境中最常见的字段及其含义:
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: hello-world
namespace: default
spec:
template: # --- RevisionTemplate 开始 ---
metadata:
annotations:
autoscaling.knative.dev/min-scale: "1" # 最小副本数,避免冷启动
autoscaling.knative.dev/max-scale: "10" # 最大副本数
spec:
containers:
- image: gcr.io/knative-samples/helloworld-go:latest
env:
- name: TARGET
value: "Knative"
ports:
- containerPort: 8080 # Knative 默认监听端口
resources:
requests:
cpu: "250m"
memory: "64Mi"
limits:
cpu: "500m"
memory: "128Mi"
livenessProbe: # 存活探针
httpGet:
path: /healthz
readinessProbe: # 就绪探针
httpGet:
path: /ready
traffic: # --- Route 流量配置 ---
- latestRevision: true
percent: 100
# - revisionName: hello-world-00001
# percent: 50
# - revisionName: hello-world-00002
# percent: 50
3.3 常见 YAML 错误与故障模式
根据生产环境故障统计,以下错误占据了 Knative Service 部署失败的 80% 以上:
| 错误类别 | 典型表现 | 根本原因 | 修复方法 |
|---|---|---|---|
| 镜像拉取失败 | Revision 状态显示 ContainerCannotRun |
镜像地址错误、私有仓库未配置 imagePullSecrets |
检查镜像名、标签;添加 imagePullSecrets 到 ServiceAccount |
| 端口不匹配 | Revision 就绪探针失败,Pod 一直 CrashLoopBackOff | containerPort 未设置或与应用实际监听端口不一致 |
显式设置 ports.containerPort 为应用监听端口(通常 8080) |
| 资源限制过小 | Pod 启动缓慢,OOMKilled | resources.limits.memory 设置低于应用实际需求 |
根据压测结果调整 limits,建议至少 128Mi |
| 并发设置冲突 | 请求延迟飙升,部分请求被拒绝 | containerConcurrency 设置过小(如 1)且流量突增 |
移除或设置为 0(无限制),或根据 QPS 合理设置 |
| 流量配置错误 | 访问 Service 返回 404 或路由到错误的 Revision | traffic 中 latestRevision 与 revisionName 混用导致歧义 |
明确指定 latestRevision: true 或具体的 revisionName,不要同时设置 |
| 环境变量缺失 | 应用启动后立即报错,日志显示配置缺失 | env 中未注入必要的配置项(如数据库连接串) |
使用 ConfigMap 或 Secret 挂载,或直接在 env 中定义 |
高危陷阱: 在生产环境中,不要在
spec.template 中直接写 imagePullPolicy: Always,除非你明确需要每次部署都拉取最新镜像。这会导致不必要的网络开销和部署延迟。默认策略 IfNotPresent 在大多数场景下更优。
3.4 Revision 自动生成与命名规则
每次修改 Service 的 spec.template(Configuration 部分),Knative 都会自动生成一个新的 Revision。Revision 的命名遵循以下规则:
- 格式:
{service-name}-{序列号},例如hello-world-00001、hello-world-00002。 - 序列号递增: 从
00001开始,每次 Configuration 变更 +1。 - 不可变性: 一旦生成,Revision 的 spec 不可修改。任何修改都会导致创建新的 Revision。
故障排查技巧: 使用
kubectl get revisions -l serving.knative.dev/service=hello-world 可以列出某个 Service 的所有 Revision。检查 READY 列的状态,快速定位哪个 Revision 启动失败。
3.5 Route 流量拆分与灰度发布
Route 是 Knative 实现灰度发布和蓝绿部署的核心。以下是一个典型的流量拆分配置:
spec:
traffic:
- revisionName: hello-world-00001
percent: 90
tag: stable
- revisionName: hello-world-00002
percent: 10
tag: canary
- latestRevision: false
关键字段说明:
revisionName:指定要路由到的具体 Revision 名称。percent:分配给该 Revision 的流量百分比,总和必须为 100。tag:为 Revision 分配一个标签,可以通过{tag}-{service-name}.{namespace}.example.com直接访问该 Revision,绕过流量拆分。latestRevision:如果设置为true,则自动将流量指向最新的 Revision。当与revisionName同时使用时,容易引发歧义,建议二选一。
最佳实践: 灰度发布时,先使用
tag 让内部测试人员通过特定 URL 访问新版本,确认无误后再将流量百分比从 10% 逐步提升到 100%。最后移除旧 Revision 的流量条目。
3.6 故障排查快速检查清单
当 Service 部署后无法正常访问时,按以下顺序排查:
- 检查 Service 状态:
kubectl get ksvc hello-world -o wide,查看URL、READY、REASON列。 - 检查 Configuration 状态:
kubectl get configuration hello-world -o yaml,确认status.latestCreatedRevisionName和status.latestReadyRevisionName是否一致。 - 检查 Revision 状态:
kubectl get revision hello-world-00001 -o yaml,查看status.conditions中的错误信息。 - 检查 Route 状态:
kubectl get route hello-world -o yaml,确认status.traffic中的路由规则是否正确。 - 检查 Pod 日志:
kubectl logs -l serving.knative.dev/service=hello-world --tail=50,查看应用启动日志。