资讯详情

Knative Serving 流量拆分实战:从 Revision 机制到蓝绿发布与金丝雀部署

📅 2026/10/16 2:51:15 | 华诺云谱 👁 阅读
Knative Serving 流量拆分实战:从 Revision 机制到蓝绿发布与金丝雀部署
文档教程云原生【免费下载链接】docsUser documentation for Knative components.项目地址https://gitcode.com/gh_mirrors/docs1/docs点击查看免费下载本文以 Knative Serving 的traffic规范为主线完整演示如何通过kn与kubectl两种方式在 Service 的不同 Revision 之间拆分流量并结合本仓库的文档与源码深入讲解latest语义、流量标签tag、渐进式发布rollout-duration以及蓝绿/金丝雀部署的完整落地流程。读完本文你将掌握创建 Revision、查看流量分布、按百分比切流、验证拆分结果以及在生产中安全发布新版本的全部关键操作与底层原理。什么是 Revision一次配置更新的“时间快照”流量拆分是 蓝绿部署 与金丝雀部署canary deployment的核心手段。要理解它首先必须理解 Knative 中的核心资源Revision。根据本仓库 Revisions 概念文档 的定义Revision 是 Knative Serving 资源包含每次对 Knative Service 做出更改时应用代码与配置的“时间点快照”point-in-time snapshot。Knative 的资源模型中service.serving.knative.dev会全权管理工作负载的生命周期它自动创建 Route、Configuration并在每次 Service 更新时生成新的 Revision。正如 Serving 概述 所述Service 可以被定义为“始终把流量路由到最新 Revision”也可以“固定到某个 Revision”。几个关键事实来自 about-revisions.mdRevision 是自动生成的你无法直接创建 Revision也无法直接修改 Revision 的 specRevision 总是在响应 Configuration spec 的更新时被创建。Revision 基本不可变immutable仅在引用 ConfigMap、Secret 等可变 Kubernetes 资源时例外或受 Revision 默认值变更影响多为语法层面而非语义层面。Revision 可以保留任意时间在 Knative 中一个 Service 的每次配置变更都会生成新的 Revision例如hello-00001、hello-00002。也就是说当你在 Knative Service 上修改任何配置镜像、环境变量等并重新部署时Knative 不会原地覆盖而是冻结当前配置生成一个新 Revision。流量拆分就是在这些新旧 Revision 之间按百分比分配请求。准备部署一个 Hello World Service本教程以 Knative 官方 Go 示例应用helloworld-go为蓝本。该应用读取环境变量TARGET输出Hello ${TARGET}!若TARGET未设置则默认输出Hello World!。完整源码见 helloworld.gofunc handler(w http.ResponseWriter, r *http.Request) { log.Print(helloworld: received a request) target : os.Getenv(TARGET) if target { target World } fmt.Fprintf(w, Hello %s!\n, target) }该示例的官方 Service 定义见 service.yaml构建与部署细节见 README。首先部署第一个版本环境变量设为World详见 部署第一个 Service 教程使用knCLIkn service create hello \ --image ghcr.io/knative/helloworld-go:latest \ --port 8080 \ --env TARGETWorld或使用 YAML 文件hello.yamlapiVersion: serving.knative.dev/v1 kind: Service metadata: name: hello spec: template: spec: containers: - image: ghcr.io/knative/helloworld-go:latest ports: - containerPort: 8080 env: - name: TARGET value: Worldkubectl apply -f hello.yaml注意${LOADBALANCER_IP}的值取决于集群类型——对于kind集群通常为127.0.0.1对于minikube则取决于本地 tunnel 配置。部署完成后第一次部署会生成名为hello-00001的 Revision。创建新 Revision修改 TARGET 并重新部署现在把环境变量TARGET从World改为Knative让应用改为输出 “Hello Knative!”。这会产生一个新的 Revisionhello-00002。使用knkn service update hello \ --env TARGETKnativekn会在 CLI 中打印出有用的信息预期输出Service hello created to latest revision hello-00002 is available at URL: http://hello.default.${LOADBALANCER_IP}.sslip.io使用 YAML编辑已有的hello.yaml使其包含以下内容apiVersion: serving.knative.dev/v1 kind: Service metadata: name: hello spec: template: spec: containers: - image: ghcr.io/knative/helloworld-go:latest ports: - containerPort: 8080 env: - name: TARGET value: Knative应用更新kubectl apply -f hello.yaml预期输出service.serving.knative.dev/hello configured由于是更新已有 Knative ServiceURL 不会改变但新 Revision 的名称变为hello-00002。底层机制为什么 URL 不变、Revision 却变了从本仓库 Serving 概述 可以确认使用Service资源部署时服务会自动拥有对应的 Route 和 Configuration每次 Service 更新都会创建一个新的 Revision。URL 属于 Route 层Route 仍然指向同一个 Service 域名因此对外 URL 不变而 Configuration 每次变更都会冻结出新的 Revision 快照。这也解释了kn service update与kubectl apply两种方式殊途同归的原因——它们最终都修改了同一个Service资源的 spec。一个容易被忽略的细节镜像标签解析本仓库 Tag resolution 文档指出Knative Serving 在创建 Revision 时会把镜像标签tag解析为摘要digest以保证 Deployment 的一致性。也就是说ghcr.io/knative/helloworld-go:latest在 Revision 快照中会被固定到当时的镜像 digest——这正是 Revision 作为“不可变快照”能稳定回滚的前提之一。当然该功能要求 Serving controller 有权限访问容器镜像仓库。访问新 Revision 验证变更在浏览器中再次访问该 Knative Service或在终端中使用curlecho Accessing URL $(kn service describe hello -o url) curl $(kn service describe hello -o url)预期输出Hello Knative!此时hello-00002是新 RevisionKnative 默认把 100% 流量都切到了它上面。查看现有 Revisionskn 与 kubectl 两种视角使用 Knative CLIkn或kubectl查看已有 Revision 列表。使用knkn revisions list预期输出NAME SERVICE TRAFFIC TAGS GENERATION AGE CONDITIONS READY REASON hello-00002 hello 100% 2 30s 3 OK / 4 True hello-00001 hello 1 5m 3 OK / 4 True使用kubectlkubectl get revisions预期输出NAME CONFIG NAME K8S SERVICE NAME GENERATION READY REASON ACTUAL REPLICAS DESIRED REPLICAS hello-00001 hello 1 True 0 0 hello-00002 hello 2 True 0 0使用kn命令时需要重点关注TRAFFIC列可以看到 100% 的流量都指向最新 Revisionhello-00002即GENERATION最大的那一行而hello-00001的流量为 0%。要点当创建一个新 Revision 时Knative 默认将 100% 的流量指向该最新 Revision。你可以通过为每个 Revision 指定流量百分比来改变这一默认行为。补充从输出还能看到ACTUAL REPLICAS为 0、DESIRED REPLICAS为 0。这正是 Knative Serving 按需伸缩scale to zero的体现——没有流量时副本数可以缩到 0这与 Serving 概述 中“Autoscaling, including scaling pods down to zero”的定位一致。同时长时间无流量的非活跃 Revision 会被自动垃圾回收以释放集群资源详见 about-revisions-garbage-collection.md。在 Revisions 之间拆分流量50/50 实战现在把流量在hello-00001与最新 Revision 之间按 50/50 拆分。使用knkn service update hello \ --traffic hello-0000150 \ --traffic latest50使用 YAML在hello.yaml末尾添加traffic段apiVersion: serving.knative.dev/v1 kind: Service metadata: name: hello spec: template: spec: containers: - image: ghcr.io/knative/helloworld-go:latest ports: - containerPort: 8080 env: - name: TARGET value: Knative traffic: - latestRevision: true percent: 50 - latestRevision: false percent: 50 revisionName: hello-00001应用更新kubectl apply -f hello.yaml理解latestlatest始终指向“最新”的 Revision在本例中即hello-00002。使用--traffic latest50可以避免硬编码 Revision 名称下次创建新 Revision 时latest会自动指向它。等价地在 YAML 中通过latestRevision: true表达“指向最新 Revision”而latestRevision: false配合revisionName则用于固定到指定 Revision。验证流量拆分结果再次列出 Revisions 验证流量拆分是否正确kn revisions list预期输出NAME SERVICE TRAFFIC TAGS GENERATION AGE CONDITIONS READY REASON hello-00002 hello 50% 2 10m 3 OK / 4 True hello-00001 hello 50% 1 36m 3 OK / 4 True在浏览器中多次访问该 Service可以看到每个 Revision 提供不同的输出。同样地可以在终端多次访问 Service URL 来观察流量在 Revision 之间的拆分echo Accessing URL $(kn service describe hello -o url) curl $(kn service describe hello -o url)预期输出交替出现Hello Knative! Hello World! Hello Knative! Hello World!这就完成了一次最基本的金丝雀式流量分发新旧两个版本各承担 50% 请求方便你在生产流量中观察新版本表现。深入traffic 规范的完整语义本教程所用的traffic段是 Knative Service 流量管理的核心。结合 traffic-management.md我们总结其完整语义创建 Knative Service 时没有默认的trafficspec通过设置trafficspec你可以把流量拆分到任意数量的固定 Revision或通过latestRevision: true把流量发送到最新 Revision。每个 traffic 条目是一个“流量目标target”常用字段组合如下字段含义示例revisionName固定到指定名称的 RevisionrevisionName: hello-00001latestRevision指向最新 Revisiontrue时通常无需revisionNamelatestRevision: truepercent分配给该目标的流量百分比percent: 50tag为该流量目标创建命名的可访问 URLtag: stagingconfigurationName固定到某 Configuration 的最新就绪 RevisionconfigurationName: config用 tag 创建目标 URL当traffic条目带有tag属性时Route 会为这个特定流量目标生成独立地址。例如 traffic-management.md 中的示例apiVersion: serving.knative.dev/v1 kind: Service metadata: name: example-service namespace: default spec: traffic: - percent: 0 revisionName: example-service-1 tag: staging - percent: 40 revisionName: example-service-2 - percent: 60 revisionName: example-service-3打上tag: staging的 Revision 可以通过staging-route name.namespace.domain访问未打 tag 的example-service-2、example-service-3只能通过主路由route name.namespace.domain访问被 tag 的流量目标会创建一个新的 Kubernetes Service名为staging-route name供集群内其他 Service 访问可通过给它打上networking.knative.dev/visibility: cluster-local标签来限制可见性详见 private-services。这个机制正是金丝雀发布中“先上线 0% 流量 打 tag 内部验证再逐步放量”的基础。通过 kn CLI 管理流量kn提供了与 YAML 等价的流量管理命令kn service update service-name --traffic revision-namepercent参数说明service-name要配置流量路由的 Knative Service 名称revision-name要接收一定百分比流量的 Revision 名称percent要发送给该 Revision 的流量百分比。例如将名为example-service的 Service 流量按 80% 到 Revisiongreen、20% 到 Revisionblue拆分kn service update example-service --traffic green80 --traffic blue20也可以先给 Revision 打 tag再按 tag 拆分流量kn service update example --tag revision-0001green --tag latestbluelatesttag 表示blue解析到该 Service 的最新 Revision。下面的命令将 80% 流量发送到最新 Revision20% 发送到名为v1的 Revisionkn service update example-service --traffic latest80 --traffic v120常见 traffic 配置模式来自官方示例以下示例均出自 traffic-management.md可直接套用模式一100% 流量到最新 Revisionstatus中可看到latestRevision解析出的实际 Revision 名称spec: traffic: - latestRevision: true percent: 100 status: traffic: - percent: 100 revisionName: example-service-1模式二100% 固定到 current Revision同时保留最新 Revision 备用于回滚最新就绪 Revision 即使无流量也保持可用spec: traffic: - tag: current revisionName: example-service-1 percent: 100 - tag: latest latestRevision: true percent: 0模式三双 Revision 各 50%蓝绿/金丝雀的典型形态spec: traffic: - tag: current revisionName: example-service-1 percent: 50 - tag: candidate revisionName: example-service-2 percent: 50 - tag: latest latestRevision: true percent: 0深入渐进式发布gradual rollout如果你在traffic中通过configurationName或latestRevision指向“配置目标”而非固定 Revision那么当新 Revision 创建并就绪后目标流量会立刻 100% 切到新 Revision这可能导致请求在队列代理queue proxy或 Activator 处堆积、过期或被拒绝。Knative 为此提供了rollout-duration参数可将流量渐进式地切到最新 Revision先切 1% 的流量随后按等量递增步长逐步放量到目标值。详见 rolling-out-latest-revision.md 与 gradual-rollout-intro.md。配置方式是在 Service或 Route上加注解apiVersion: serving.knative.dev/v1 kind: Service metadata: name: helloworld-go namespace: default annotations: serving.knative.dev/rollout-duration: 380s值得注意的限制来自官方文档rollout-duration是基于时间的不参与自动伸缩autoscaling子系统的交互该特性同时适用于带 tag 和不带 tag 的流量目标也适用于独立 Route无 Service 包裹的情况。Rollout 期间Route 与 Service 的status.conditions会显示Reason: RolloutInProgress、Status: Unknown消息为 “A gradual rollout of the latest revision(s) is in progress.”详见 route-status-updates.md。以 55% 配比为例rollout 会先让新 Revision 拿到 1%再按约 18% 的步长递增直至到达目标 55%。深入蓝绿部署的完整流程traffic-management.md 给出了基于独立 Route 资源的蓝绿部署完整流程核心思路是“先上线新版本但不放流量 → 打 tag 建立测试端点 → 逐步放量 → 全部切换”。步骤如下部署应用为 Knative Service并找到第一个 Revision 名称kubectl get configurations service-name -ojsonpath{.status.latestCreatedRevisionName}定义 Route把所有流量发送到该 RevisionapiVersion: serving.knative.dev/v1 kind: Route metadata: name: route-name namespace: default spec: traffic: - revisionName: first-revision-name percent: 100 # All traffic goes to this revision验证旧版本可访问kubectl get route route-name查看输出 URL。部署第二个 Revision修改 Servicetemplatespec 中至少一个字段例如image或env环境变量然后通过kubectl apply或kn service update重新部署。再次查询latestCreatedRevisionName拿到第二个 Revision 名称。此时两个 Revision 都已部署并运行。更新 Route主 URL 仍把 100% 流量导向第一 Revision同时给第二 Revision 打 tagv2、流量 0%建立测试端点spec: traffic: - revisionName: first-revision-name percent: 100 # All traffic is still being routed to the first revision - revisionName: second-revision-name percent: 0 # 0% of traffic routed to the second revision tag: v2 # A named route重新应用后第二 Revision 处于“staged”状态主 URL 无流量进入而 Knative 为它创建了名为v2的独立 Route。获取新 Route 的 URL用于在放量前验证新版本行为kubectl get route route-name --output jsonpath{.status.traffic[*].url}50/50 放量spec: traffic: - revisionName: first-revision-name percent: 50 - revisionName: second-revision-name percent: 50 tag: v2100% 切换到新版本spec: traffic: - revisionName: first-revision-name percent: 0 - revisionName: second-revision-name percent: 100 tag: v2提示如果确定不再需要回滚可以直接删除第一 Revision而不必保留 0% 流量的条目。不可路由non-routeable的 Revision 对象随后会被自动垃圾回收详见 about-revisions-garbage-collection.md。访问第一 Revision 的 URL 验证旧版本已不再接收流量。小结与延伸阅读本教程展示了 Knative 流量拆分的完整链路更新 Service 生成新 Revision → 查看 Revision 与流量分布 → 通过--traffic或 YAMLtraffic段按百分比拆分 → 验证新旧版本交替响应。在此基础上tag 机制与rollout-duration分别解决了“独立验证端点”与“平滑放量”两个生产级问题配合蓝绿部署流程即可形成一套完整的发布体系。进一步深入可参考本仓库的以下资料流量管理官方指南tag URL、traffic 示例与蓝绿部署细节Revisions 概念与配置Revision 的不可变性与自动伸缩渐进式发布指南rollout-duration 注解配置Serving 概述Service/Route/Configuration/Revision 四类资源的关系示例应用源码与部署文件可自行构建镜像复现本教程Serving 代码示例索引更多进阶样例赞分享文档教程云原生【免费下载链接】docsUser documentation for Knative components.项目地址https://gitcode.com/gh_mirrors/docs1/docs点击查看免费下载相关推荐Mermaid ELK 布局完整指南改一个词让流程图快速不再乱线Mermaid ELK 布局完整指南改一个词让流程图快速不再乱线 如果你的 Mermaid 流程图节点叠在一起、连线交叉成一团这篇文章教你把布局算法切换为图表库前端数据可视化从NOT_A_JPEG到PARSING_ERRORnode-exif三类错误码的完整处理方案从NOT_A_JPEG到PARSING_ERRORnode exif三类错误码的完整处理方案 node exif 是一个 Node.js 库用于从 JPEG后端免费开源直播聚合工具 Simple Live一个 App 装下 4 大平台源码 5 分钟编出自己的跨平台客户端免费开源直播聚合工具 Simple Live一个 App 装下 4 大平台源码 5 分钟编出自己的跨平台客户端 你切到第五个直播 App点开才发现主播刚下直播音视频移动开发上一篇Ruff 之 ty类型可赋值性诊断错误上下文error context机制全解析下一篇Sim React 组件编写规范结构顺序、列表渲染性能陷阱与 react-doctor 误报甄别创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑