一句话总结
Knative 把 Serverless 的能力("缩容到零, 按请求扩缩, 流量切分, 事件驱动")带到了开放的 Kubernetes 上, 既享受 Serverless 的便利, 又不被某家云厂商绑定. 它由两块组成: Serving(管请求驱动的服务)和 Eventing(管事件的生产与分发).
前置回顾
第 02 篇讲了 Serverless 的理念和代价, 也点出一个痛点: 云厂商 FaaS 的厂商绑定--函数签名, 事件格式各家不同, 深度用了就难迁走. Knative 正是这个问题的答案: 它把 Serverless 建在人人都有的 K8s 上, 标准开放, 可移植. 本篇把 Serverless 从"理念"落到"K8s 上能跑的东西".
为什么需要 Knative: Serverless 的"去绑定"
第 02 篇的云 FaaS(Lambda 等)很好用, 但有两个结构性问题:
- 厂商绑定: 函数写成了 AWS Lambda 的样子(它的签名, 它的事件格式, 它的配套服务), 想换到别的云? 基本要重写.
- 两套世界割裂: 核心服务跑在自建的 K8s 上(有完整的可观测, CI/CD, 网络策略...), 零散任务用云 FaaS, 结果两套运维, 两套监控, 两套心智, 割裂.
Knative 的思路: 既然大家都有 K8s, 那就把 Serverless 能力做成 K8s 上的标准组件--函数/服务还是普通容器, 跑在自己的集群里, 既有 Serverless 的自动扩缩到零, 又不绑定任何云.
云 FaaS 像住进某品牌的全装修公寓: 拎包入住很爽, 但家具全是人家的, 搬走啥也带不了.
Knative 像在自己的房子(K8s)里装了一套智能家居系统: 同样能自动调节(扩缩到零), 但房子是自己的, 标准是开放的, 想换供应商也不至于推倒重来.
回到第 01 篇的抽象阶梯: K8s 已经把"集群"抽象好了, 但还得自己写 Deployment, Service, HPA, Ingress 一堆 YAML, 且 HPA 最少留 1 个 Pod(不能到零). Knative 在 K8s 之上再叠一层: 只声明一个"服务", 它自动展开成底层那一堆资源, 并补上 K8s 原生缺的两件事--缩容到零和按请求量(而非 CPU)扩缩.
它不取代 K8s, 而是站在 K8s 肩膀上.
Knative Serving: 请求驱动的服务
Serving 是 Knative 的核心, 管理"由 HTTP 请求驱动"的服务. 只需写一个 Service 资源(注意: 是 Knative 的 Service, 不是 K8s 原生的那个), 指定一个容器镜像:
|
Serving 帮我们补上了 K8s 原生缺的两个关键能力:
缩容到零与按请求扩缩
K8s 的 HPA 按 CPU/内存扩缩, 且最少留 1 个 Pod. Knative Serving 不同:
- 按请求并发扩缩: 根据"当前有多少并发请求"来决定 Pod 数(更贴合 Web 服务的真实负载), 而非看 CPU.
- 能缩容到零: 一段时间没请求, Pod 数降到 0(第 02 篇的核心特征). 秘密在一个叫 Activator 的组件: 实例为零时, 新请求先被 Activator 接住, 暂存, 同时触发拉起 Pod, Pod 就绪后再把请求放行--所以"零实例"也不会丢请求(只是这第一个请求要承受第 02 篇说的冷启动延迟).
|
流量切分: 天然支持渐进式发布
Serving 用修订版本(Revision) 管理每次部署: 每改一次配置, 就产生一个不可变的 Revision. 然后可以按百分比把流量切分到不同 Revision:
|
有没有觉得眼熟? 这就是 CI/CD 系列第 07 篇讲的金丝雀发布--只是 Knative 把它做成了内建能力, 改个百分比就完成灰度. Knative 的 Revision + 流量切分, 天然契合渐进式交付.
可见云原生的各个主题是彼此咬合的: Serverless 的"流量切分", CI/CD 的"金丝雀", 可观测性的"指标驱动", 本就是同一套发布安全网的不同切面.
Knative Eventing: 事件驱动的另一半
Serving 管的是"请求驱动"(HTTP 来了就处理). 但第 02 篇说 Serverless 的灵魂之一是事件驱动--由消息, 文件上传, 定时器等各种事件触发. 这是 Eventing 负责的部分.
Eventing 解决一个核心问题: 如何让"事件的生产者"和"事件的消费者"解耦--生产者不需要知道谁会消费, 消费者也不需要知道事件从哪来. 它的模型(简化版):
|
- Source(事件源): 产生事件的地方(Kafka, 定时器, 各种系统).
- Broker(代理): 事件的汇聚和分发中枢--生产者把事件发给它.
- Trigger(触发器): 消费者用它声明式地订阅"我要 Broker 里哪一类事件", 并指向处理它的服务.
Eventing 的价值: 松耦合的事件总线
它把系统从"A 直接调 B"的紧耦合, 变成"A 发个事件, 谁关心谁订阅"的松耦合. 新增一个消费者? 加个 Trigger 就行, 生产者完全不用改. 这和微服务里的事件驱动架构(EDA)是一个思路, Knative 把它做成了 K8s 上的标准设施.
配合 CloudEvents(一个描述事件格式的开放规范), 事件的"信封格式"也标准化了--又一次"开放标准对抗厂商绑定".
什么时候用 Knative
延续第 01, 02 篇的理性视角, Knative 也不是人人该上:
| 适合 | 不必急着上 |
|---|---|
| 已有 K8s, 想要 Serverless 能力又怕厂商绑定 | 负载稳定, 用普通 Deployment+HPA 就够好的服务 |
| 有大量"缩容到零"价值的服务(内部工具, 低频接口) | 团队还在被 K8s 基础搞得焦头烂额(先稳住地基) |
| 想要内建的金丝雀/流量切分, 事件驱动架构 | 只有几个服务, 引入 Knative 的运维复杂度不划算 |
Knative 也是有成本的抽象(第 01 篇复杂度守恒)
Knative 给我们便利, 但它本身是一套要安装, 运维, 理解的复杂组件(Serving, Eventing, 底层还常依赖网络层组件). 对一个只有几个常驻服务的团队, 直接用 K8s 的 Deployment + HPA 反而更简单透明.
Knative 的价值在"确实有大量适合 Serverless 的负载, 且想自托管不绑云"时才充分兑现--否则它转移过来的复杂度, 可能盖过省下的那点资源. 还是第 01 篇那句话: 先有真实痛点, 再上对应的抽象.
快速回顾
- Knative = K8s 上的开放 Serverless: 享受缩容到零, 按请求扩缩, 流量切分, 事件驱动, 又不被云厂商绑定
- 定位: 在 K8s 之上叠一层 Serverless 抽象, 补上 K8s 原生缺的"缩容到零"和"按请求扩缩"(HPA 看 CPU 且最少留 1 个)
- Serving: 管请求驱动的服务; Activator 在零实例时接住请求不丢, 触发拉起(代价是冷启动); Revision + 流量切分天然支持金丝雀(呼应 CI/CD 第 07 篇)
- Eventing: 管事件驱动; Source→Broker→Trigger 模型让生产者与消费者松耦合, 配 CloudEvents 标准化事件格式
- 选型: 有 K8s + 大量适合 Serverless 的负载 + 怕绑定 → 值得; 服务少/负载稳/地基未稳 → 别急, Knative 自身也是有成本的复杂抽象
Knative 和直接用 K8s 的 HPA(水平自动扩缩)有什么本质区别?
两个关键区别:
- 能不能到零: HPA 最小副本数至少是 1(它不会把 Pod 缩到 0), Knative 能真正缩容到零, 零成本闲置.
- 按什么扩缩: HPA 主要看 CPU/内存等资源指标, Knative 默认按请求并发数扩缩--对 Web 服务, "有多少请求"比"CPU 多高"更直接反映负载, 扩缩更精准更快.
简言之, HPA 是"给常驻服务调副本数", Knative 是"把服务变成请求驱动, 可归零的 Serverless". 需求不到"缩容到零"那一步, HPA 足矣.
除了 Knative, K8s 上还有别的 Serverless 方案吗?
有. 比如 OpenFaaS(更聚焦 FaaS, 更轻量易上手), KEDA(Kubernetes Event-Driven Autoscaling, 专门做"基于事件源指标的扩缩容", 包括缩容到零, 常和普通 Deployment 配合, 比整套 Knative 轻).
KEDA 尤其值得一提: 如果只想要"根据队列长度等事件指标自动扩缩(含到零)", 而不需要 Knative 那套完整的 Serving/Eventing/流量管理, KEDA 往往是更轻的选择. 再次印证第 01 篇--先明确到底要哪部分能力, 再选匹配的工具, 别一上来就上最重的全家桶.
动手练习
- 部署 Knative Service: 在 k3d/kind 上装 Knative Serving, 部署一个 Knative
Service(用任意 hello 镜像), 访问它确认能通. - 观察缩容到零: 让它闲置一两分钟, 用
kubectl get pods观察 Pod 数归零; 再发一个请求, 观察 Pod 被重新拉起--亲眼看到"缩容到零 + 冷启动". - 流量切分实验: 部署该服务的第二个版本, 用 traffic 把流量按 80/20 切分到两个 Revision, 验证大致按比例分流--这就是内建金丝雀(对照 CI/CD 第 07 篇).
- 体验事件驱动(进阶): 装 Knative Eventing, 配一个定时事件源 + 一个 Trigger, 让它定时触发服务, 体会"事件驱动"和 Source→Broker→Trigger 模型.
- 选型判断: 对照本篇的选型表, 判断手头某个服务该用 Knative, 还是普通 Deployment+HPA, 还是 KEDA, 写出理由.