本文档说明如何使用 Knative Service 管理 APP 的多个版本(Revision),通过 Tag 和 Header 实现版本路由。
概念映射
| 业务概念 | Knative 概念 | 说明 |
|---|---|---|
| APP | Knative Service | 一个应用对应一个 Knative Service |
| APP 版本 | Revision | 每次更新 Service 的 template 会生成新的 Revision |
| 版本标识 | Tag | 通过 traffic 配置中的 tag 字段标识版本 |
请求方式
所有版本共用同一个 Host,通过 Knative-Serving-Tag Header 区分版本:
# 访问 v1 版本
curl -H "Knative-Serving-Tag: v1" -H "Host: echo-server.default.example.com" http://<gateway-ip>
# 访问 v2 版本
curl -H "Knative-Serving-Tag: v2" -H "Host: echo-server.default.example.com" http://<gateway-ip>
# 不带 Tag Header,走默认流量分配(percent 配置)
curl -H "Host: echo-server.default.example.com" http://<gateway-ip>
场景一:创建新 APP
创建一个新的 Knative Service,初始版本标记为 v1。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: echo-server
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/maxScale: "10"
spec:
containers:
- image: ghcr.io/knative/helloworld-go:latest
ports:
- containerPort: 8080
env:
- name: TARGET
value: "World"
traffic:
- latestRevision: true
percent: 100
tag: v1
应用后查看 Revision:
kubectl get revisions -l serving.knative.dev/service=echo-server
输出示例:
NAME CONFIG NAME READY REASON
echo-server-00001 echo-server True
场景二:创建 APP 新版本
更新 Service 的 template 并添加新的 Tag。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: echo-server
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/maxScale: "10"
spec:
containers:
- image: ghcr.io/knative/helloworld-go:latest
ports:
- containerPort: 8080
env:
- name: TARGET
value: "Knative v2"
traffic:
# 新版本 v2,暂不分配默认流量(staging)
- latestRevision: true
percent: 0
tag: v2
# 旧版本 v1,保持 100% 默认流量
- revisionName: echo-server-00001
percent: 100
tag: v1
此时:
- 不带 Header 的请求 → 100% 路由到 v1
- 带
Knative-Serving-Tag: v2的请求 → 路由到 v2 - 带
Knative-Serving-Tag: v1的请求 → 路由到 v1
场景三:调整流量分配
将 v2 版本设为主版本,v1 作为备用。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: echo-server
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/maxScale: "10"
spec:
containers:
- image: ghcr.io/knative/helloworld-go:latest
ports:
- containerPort: 8080
env:
- name: TARGET
value: "Knative v2"
traffic:
# v2 成为主版本
- revisionName: echo-server-00002
percent: 100
tag: v2
# v1 保留但不分配默认流量
- revisionName: echo-server-00001
percent: 0
tag: v1
场景四:停用某个版本(maxScale=0)
将某个版本的最大副本数设为 0,使其不再接收请求。
方法:通过 Revision 级别的 annotation 无法直接修改已创建的 Revision。需要通过以下方式实现:
方案 A:从 traffic 中移除该版本
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: echo-server
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/maxScale: "10"
spec:
containers:
- image: ghcr.io/knative/helloworld-go:latest
ports:
- containerPort: 8080
env:
- name: TARGET
value: "Knative v2"
traffic:
# 只保留 v2
- revisionName: echo-server-00002
percent: 100
tag: v2
# v1 从 traffic 中移除,不再可访问
移除后,v1 版本的 Pod 会自动缩容到 0(scale to zero)。
方案 B:使用 PodAutoscaler 强制缩容
如果需要保留 Tag 但强制停机,可以直接 patch 对应 Revision 的 PodAutoscaler:
# 查找 v1 对应的 PodAutoscaler
kubectl get pa -l serving.knative.dev/revision=echo-server-00001
# 设置 maxScale 为 0(需要 Knative 支持,部分版本可能不支持)
kubectl annotate revision echo-server-00001 \\
autoscaling.knative.dev/maxScale="0" --overwrite
注意:Revision 的 annotation 在创建后通常不可变。更可靠的方式是从 traffic 中移除。
场景五:删除某个版本
5.1 先从 traffic 中移除
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: echo-server
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/maxScale: "10"
spec:
containers:
- image: ghcr.io/knative/helloworld-go:latest
ports:
- containerPort: 8080
env:
- name: TARGET
value: "Knative v2"
traffic:
- revisionName: echo-server-00002
percent: 100
tag: v2
5.2 删除 Revision
kubectl delete revision echo-server-00001
场景六:删除整个 APP
删除 Knative Service 会自动清理所有关联的 Revision、Configuration、Route 等资源。
kubectl delete ksvc echo-server -n default
验证清理完成:
kubectl get revisions -l serving.knative.dev/service=echo-server
kubectl get configurations -l serving.knative.dev/service=echo-server
kubectl get routes -l serving.knative.dev/service=echo-server
完整示例:三版本共存
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: echo-server
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/maxScale: "10"
spec:
containers:
- image: ghcr.io/knative/helloworld-go:latest
ports:
- containerPort: 8080
env:
- name: TARGET
value: "Knative v3"
traffic:
# v3 - 最新版本,灰度 10%
- latestRevision: true
percent: 10
tag: v3
# v2 - 主力版本,承担 90% 流量
- revisionName: echo-server-00002
percent: 90
tag: v2
# v1 - 旧版本,仅通过 Tag 访问,不分配默认流量
- revisionName: echo-server-00001
percent: 0
tag: v1
访问方式:
# 按比例分配(90% v2, 10% v3)
curl -H "Host: echo-server.default.example.com" http://<gateway-ip>
# 指定访问 v1
curl -H "Knative-Serving-Tag: v1" -H "Host: echo-server.default.example.com" http://<gateway-ip>
# 指定访问 v2
curl -H "Knative-Serving-Tag: v2" -H "Host: echo-server.default.example.com" http://<gateway-ip>
# 指定访问 v3
curl -H "Knative-Serving-Tag: v3" -H "Host: echo-server.default.example.com" http://<gateway-ip>
操作速查表
| 操作 | 方法 |
|---|---|
| 创建新 APP | 创建 Knative Service,template 中定义容器,traffic 中设置 tag |
| 创建新版本 | 更新 template,在 traffic 中添加新 tag 指向 latestRevision |
| 停用版本(保留) | 从 traffic 中移除该 revisionName,或设置 percent: 0 且不带 tag |
| 删除版本 | 先从 traffic 移除,再 kubectl delete revision <name> |
| 删除整个 APP | kubectl delete ksvc <name> |
| 灰度发布 | 调整 traffic 中各版本的 percent 比例 |
| 回滚 | 将旧版本的 percent 设为 100,新版本设为 0 |