Knative Serving 组件、请求流与配置
Knative Serving 接住一个 HTTP 请求时,背后会同时动到几类对象。
Route 先决定请求发往哪个 Revision,网络层再决定流量经过 Activator 还是直接进入 Revision Pod。Pod 内的 queue-proxy 把请求交给业务容器,并把并发指标送给 Autoscaler。副本数随之变化,网络路径也可能再次切换。看清这段过程,需要把三条关系放在一起。资源关系说明 Service 怎样展开成 Configuration、Revision 和 Route,请求路径说明流量怎样穿过网关、Activator 与 queue-proxy,扩缩容关系说明请求压力怎样改变副本数。三者合起来,才是 Knative Serving 一次完整的请求处理过程。
以下内容按 Knative 1.21 的归档文档整理。不同网络插件生成的资源名称和实现细节会有差异,各插件遵循的核心请求模型相同。
先从资源关系入手
用户通常从
Service 开始,也就是命令里常写的 ksvc。它位于最上层,向下管理同名的 Configuration 和 Route。Configuration保存工作负载的期望配置。模板有变化时,它会生成新的Revision。Revision是某次代码和配置的不可变快照。每个 Revision 都有自己的扩缩容状态,可以独立承接流量。Route决定域名以及流量发往哪些 Revision,也负责灰度比例和命名流量目标。
顺着它往下看,资源关系大致是这样。
Knative Serving 组件、请求流与配置 (text)
Service
├── Configuration
│ └── Revision
│ ├── Deployment
│ ├── Pod
│ └── Knative Pod Autoscaler
└── Route
└── KIngress 与具体网络插件资源这条资源链决定请求最终能落到哪里。Configuration 负责生成可运行的 Revision,Route 负责选择 Revision 并形成对外地址,KIngress 和网络插件再把这份选择交给网关。下面三条命令可以把这些对象放在一起查看。
Knative Serving 组件、请求流与配置 (bash)
kubectl get ksvc,configuration,revision,route -n <namespace>
kubectl describe ksvc <service> -n <namespace>
kubectl get revision -n <namespace>组件各自负责什么
资源链理清以后,再看组件就容易多了。控制面负责协调状态,数据面转发请求,网络适配层把 Knative 的路由要求交给具体网关。
组件 | 所在位置 | 主要职责 | 是否经过业务请求 |
|---|---|---|---|
controller | knative-serving 命名空间 | 监听 Knative 资源,创建和协调下游 Kubernetes 资源,并回写状态 | 否 |
webhook | knative-serving 命名空间 | 校验和默认化 Knative 资源,拦住不合法的写入 | 否 |
autoscaler | knative-serving 命名空间 | 收集 Revision 的请求指标,计算目标副本数 | 否 |
activator | knative-serving 命名空间 | 在低流量或无可用容量时暂存请求,向 autoscaler 提供流量信号,等容量就绪后转发 | 视流量状态而定 |
queue-proxy | 每个业务 Pod 的 sidecar | 位于业务容器前,执行并发限制、超时、优雅终止、就绪探测和指标采集 | 是 |
网络插件控制器 | 例如 net-istio-controller | 把 Knative 的 KIngress 抽象翻译成具体网关规则 | 否 |
Ingress Gateway | Istio、Kourier 或 Contour 等网络层 | 接收集群内外请求,并按当前路由状态选择 Activator 或 Revision Pod | 是 |
这张表里最容易混淆的是两组组件。
controller 和 autoscaler 都会影响副本。controller 协调 Knative 资源及其下游对象,autoscaler 根据指标和请求需求计算副本。它们属于控制面,业务请求不会从这两个组件中穿过。activator 和 queue-proxy 都能暂存请求,位置却完全不同。Activator 是共享的数据面组件,处理缩零唤醒,也能在容量不足时缓冲突发流量。queue-proxy 跟着每个业务 Pod 存在,送往业务容器的 Knative 请求总要先经过它。一个冷请求怎样唤醒 Revision
某个 Revision 缩到零以后,集群里没有对应的业务 Pod。新请求先由 Ingress Gateway 送到 Activator。Activator 找到目标 Revision,保留正在等待的请求,同时把这次需求送进扩缩容控制链。
Autoscaler 据此算出目标副本,控制链随后把 Revision 对应的 Deployment 从零拉起。新 Pod 启动后,queue-proxy 会参与业务容器的就绪检查。等 Pod 通过检查,Activator 才把请求转给 queue-proxy,再由 queue-proxy 交给业务容器。
Knative Serving 组件、请求流与配置 (text)
客户端
-> Ingress Gateway
-> Activator
-> 等待 Revision 出现可用容量
-> queue-proxy
-> 业务容器首个请求会等过网关转发、调度、镜像拉取、容器启动和就绪探测。Activator 负责保留请求,却不会省掉后面的启动过程。镜像大小、节点容量、应用启动时间和 readiness 都会进入这次等待。
下面几条命令可以看到 Revision 从零到可用的变化,以及 Activator 和 Autoscaler 在这段时间内留下的记录。
Knative Serving 组件、请求流与配置 (bash)
kubectl get revision <revision> -n <namespace> -o yaml
kubectl get pod -n <namespace> -w
kubectl logs -n knative-serving deploy/activator --since=10m
kubectl logs -n knative-serving deploy/autoscaler --since=10m热路径为什么还可能经过 Activator
Pod 已经存在,流量也可能继续经过 Activator。Knative 会根据当前需求、可用容量和
target-burst-capacity 决定是否保留这层缓冲。等容量足够,网络层才会把流量直接送到 Revision Pod。Knative Serving 组件、请求流与配置 (text)
客户端
-> Ingress Gateway
-> queue-proxy
-> 业务容器Activator 退出热路径以后,queue-proxy 仍然挡在业务容器之前。它继续统计并发、执行
containerConcurrency 硬限制,并处理超时和优雅终止。流量变化或剩余容量不足时,网络层还可能把 Activator 放回路径。冷路径和热路径只是两个容易画清楚的端点。运行中还会出现 Pod 大于零、请求仍经 Activator 的状态。Activator 有流量,只能说明它当时还在请求路径里,不能单凭这一点认定服务刚发生了冷启动。
Autoscaler 到底在看什么
Knative Serving 默认使用 KPA。它能根据并发或每秒请求数扩缩容,也支持缩到零。可选的 HPA 能按 CPU 扩缩容,却不提供 Knative 的缩零能力。
KPA 处理并发时会同时使用稳定窗口和恐慌窗口。稳定窗口负责平滑常规波动,默认是 60 秒。恐慌窗口更短,流量突然超过阈值时会更快扩容。这样可以减少偶发尖峰带来的抖动,同时保留突发扩容能力。
调并发之前,先分清硬上限和扩缩容目标。
配置 | 含义 |
|---|---|
spec.template.spec.containerConcurrency | queue-proxy 执行的单 Pod 并发硬上限, 0 表示不设硬限制 |
autoscaling.knative.dev/target | Autoscaler 希望维持的单 Pod 指标目标 |
container-concurrency-target-percentage | 为突发流量预留余量的全局利用率比例 |
假设硬上限是 80,目标并发是 50。Autoscaler 会按每个 Pod 约 50 个并发来计算副本,queue-proxy 则把同时处理的请求限制在 80 以内。两者取同一个值也能运行,只是给突发流量留下的余量更小。
下面这份 Service 配置会把参数写进 Revision 模板。它给单 Pod 设置 80 的并发硬上限,把扩缩容目标设为 50,并把副本范围限制在 0 到 20。
Knative Serving 组件、请求流与配置 (yaml)
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: checkout
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/class: kpa.autoscaling.knative.dev
autoscaling.knative.dev/metric: concurrency
autoscaling.knative.dev/target: "50"
autoscaling.knative.dev/min-scale: "0"
autoscaling.knative.dev/max-scale: "20"
autoscaling.knative.dev/scale-to-zero-pod-retention-period: "30s"
spec:
containerConcurrency: 80
timeoutSeconds: 300
containers:
- image: ghcr.io/example/checkout:1.0.0改完模板会生成新 Revision,旧 Revision 不会原地更新。同一个 Service 因此可能同时保留多个 Revision,Route 决定其中哪些版本正在接收流量。
ConfigMap 该改哪一个
准备改配置时,先确认这个选项属于单个 Revision 还是整个集群。集群级配置大多放在
knative-serving 命名空间。某个选项若支持 Revision 注解或字段,可以先在单个服务上试清楚,再决定是否改成全局默认。通过 Knative Operator 安装的集群还要多查一处。配置应维护在
KnativeServing 自定义资源的 spec.config 中,直接改 ConfigMap 可能在后续协调时被 Operator 覆盖。想解决的问题 | 主要配置入口 | 常见键或字段 |
|---|---|---|
调整 KPA 目标、窗口和突发容量 | config-autoscaler | stable-window、target-burst-capacity、container-concurrency-target-default |
控制缩零行为 | config-autoscaler 与 Revision 注解 | enable-scale-to-zero、scale-to-zero-grace-period、scale-to-zero-pod-retention-period |
设置 Revision 默认超时和并发 | config-defaults | revision-timeout-seconds、container-concurrency |
设置默认域名 | config-domain | 域名后缀及选择器 |
设置外部 TLS 和证书类 | config-network | external-domain-tls、certificate-class、http-protocol |
配置 cert-manager 签发者 | config-certmanager | issuerRef、clusterLocalIssuerRef、systemInternalIssuerRef |
调整旧 Revision 回收 | config-gc | retain-since-create-time、retain-since-last-active-time、min-non-active-revisions、max-non-active-revisions |
调整底层 Deployment 生成方式 | config-deployment | registries-skipping-tag-resolving、progress-deadline、runtime-class-name |
开启受控的 PodSpec 能力 | config-features | 以当前版本中的 feature flags 为准 |
先把集群里的实际配置导出来。安装清单中的示例值、文档默认值和正在生效的值未必相同。
Knative Serving 组件、请求流与配置 (bash)
kubectl get cm -n knative-serving config-autoscaler -o yaml
kubectl get cm -n knative-serving config-defaults -o yaml
kubectl get cm -n knative-serving config-network -o yaml
kubectl get cm -n knative-serving config-domain -o yamlscale-to-zero-grace-period 最容易改错
这个值给内部网络编程留出时间。Revision 删除最后一个副本前,系统要先确保后续流量能够转向 Activator。
scale-to-zero-grace-period 给这段等待设的是上限,它不决定空闲多久以后开始缩零,也不保证最后一个 Pod 会保留这么久。scale-to-zero-pod-retention-period 决定 Autoscaler 作出缩零决定后,最后一个 Pod 至少继续保留多久。实际缩零时点还会受到稳定窗口、最小副本、Autoscaler 类型和持续请求的影响。为了制造冷启动而把
scale-to-zero-grace-period 改成 10 秒,会削短网络切换的安全余量,严重时可能在缩零阶段丢请求。只有确认网络编程耗时有问题时,才需要碰这个参数。域名、TLS 和网关要分开看
config-domain 只决定 Knative Route 使用哪个域名后缀。外部 DNS 还要把这个域名指向 Ingress Gateway。改完 ConfigMap,公网 DNS 不会跟着自动出现。Knative Serving 组件、请求流与配置 (bash)
kubectl patch configmap config-domain \
-n knative-serving \
--type merge \
-p '{"data":{"apps.example.com":""}}'外部 HTTPS 还依赖网络插件、证书签发组件以及
config-network 中的 external-domain-tls。使用 cert-manager 集成时,签发者引用放在 config-certmanager。域名解析、网关接收流量和证书签发分别由不同对象完成。下面这些命令可以列出 Istio 与 cert-manager 组合下的对应对象。
Knative Serving 组件、请求流与配置 (bash)
kubectl get ksvc -A
kubectl get kingress -A
kubectl get certificate -A
kubectl get gateways.networking.istio.io -A把整条请求路径串起来
场景 | 资源或请求路径 | 参与组件 |
|---|---|---|
创建或更新 Service | Service → Configuration → Revision | webhook、controller |
生成访问地址并分配流量 | Service → Route → KIngress → Ingress Gateway | controller、网络插件控制器 |
Revision 缩到零后的首个请求 | Ingress Gateway → Activator → queue-proxy → 业务容器 | Activator、Autoscaler、queue-proxy |
Revision 容量充足时的请求 | Ingress Gateway → queue-proxy → 业务容器 | Ingress Gateway、queue-proxy |
请求压力上升 | queue-proxy 或 Activator 提供指标 → Autoscaler 计算副本 | queue-proxy、Activator、Autoscaler |
流量回落并缩到零 | Autoscaler 降低副本 → 网络路径转回 Activator | Autoscaler、网络插件控制器、Activator |
Activator 是否出现在路径里,取决于 Revision 的流量和可用容量。queue-proxy 始终位于业务容器之前,持续执行并发限制、就绪检查与指标采集。Autoscaler 不转发请求,它根据这些指标改变 Revision 的副本数,再间接影响下一批请求会走哪条路径。