文档首页/ 云容器引擎 CCE/ 最佳实践/ 弹性伸缩/ 使用Knative Serving构建Serverless应用平台
更新时间:2026-10-14 GMT+08:00
分享

使用Knative Serving构建Serverless应用平台

本文介绍如何在CCE集群上部署Knative Serving v1.19,构建具备按需弹性伸缩、灰度发布、Scale to Zero等能力的Serverless应用平台。内容涵盖从安装、配置域名、部署服务、验证Scale to Zero到灰度发布的完整上线流程,并给出KPA调优、资源配额、SWR镜像迁移等生产环境配置建议。

概述

Knative是一款基于Kubernetes的Serverless框架,旨在提供跨平台的Serverless编排标准。它通过整合容器构建(或函数)、工作负载管理及事件驱动能力,在Kubernetes之上提供“声明式 API + 自动编排 + 流量控制”的Serverless体验。

Knative的核心价值:

  • 请求驱动的自动扩缩容(KPA):不同于HPA基于容器指标(CPU/内存),Knative Pod Autoscaler(KPA)基于请求并发数或QPS动态调整Pod数量,支持缩容到0,无流量时不占用计算资源。
  • 零冷启动兜底:Pod缩容到0后,Activator组件拦截请求、触发扩容、排队等待,Pod就绪后转发,保证请求不丢失。
  • 版本管理与灰度发布:Revision不可变,Route通过流量权重实现蓝绿发布与金丝雀发布,无需额外工具链。
  • 标准化:基于Kubernetes CRD,与云原生生态无缝集成。

前提条件

  • 已创建1.28及以上版本(推荐1.30+)的CCE Standard或Turbo集群,至少2个节点,节点规格不低于4核8GB。Turbo集群(独享节点池)适合对隔离性有要求的AI推理场景。
  • 已创建弹性负载均衡实例,用于Kourier网关对外暴露服务。
  • 已开通容器镜像服务。
  • 节点可访问公网,或已将Knative组件镜像迁移至SWR。

约束与限制

  • 本实践仅部署Knative Serving(请求驱动的工作负载管理),暂不涉及Knative Eventing(事件驱动模型)。若需事件驱动模型(如IoT、消息队列),可在Serving之上叠加Knative Eventing组件。
  • CCE不会为type: LoadBalancer的Service自动创建和绑定ELB,需手动创建并通过kubernetes.io/elb.id注解关联。
  • 网络插件需支持NetworkPolicy,CCE默认容器网络(Cilium/Tunnel)均支持。
  • Scale to Zero冷启动耗时取决于镜像拉取速度与应用启动时长(通常1~3秒),对冷启动敏感的业务建议设置min-scale≥1。
  • Knative Service的services.serving.knative.dev与core Service的services名称冲突,在部分CCE版本下需调整service-webhook的apiGroups配置,详见创建Knative Service时报错Forbidden?。

资源规划

  • 节点规划

    节点池

    规格

    数量

    用途

    系统节点池

    4C8G

    2

    运行Knative控制面(knative-serving命名空间)+ Kourier网关。

    业务节点池

    按业务峰值估算(如8C16G)

    ≥ 2

    运行Knative Service业务Pod;启用Scale to Zero后,节点资源可被其他工作负载复用。

    GPU节点池(可选)

    Ascend 910 / NVIDIA GPU

    ≥ 1

    AI推理场景(如vLLM部署大模型),需安装对应设备插件。

  • 网络规划

    资源

    规划

    说明

    ELB(公网型)

    1 个

    Kourier Gateway的LoadBalancer服务将绑定此ELB,对外提供Knative Service访问入口。

    域名

    1 个(生产环境)

    如“*.knative.example.com”,泛域名解析至ELB绑定的EIP;测试环境可用sslip.io自动解析。

    命名空间

    knative-serving(控制面)、default或业务命名空间

    控制面命名空间由安装YAML自动创建。

  • ELB规划

    CCE的hws-cloudprovider不会为type: LoadBalancer的Service自动创建和绑定ELB,必须手动创建ELB实例,然后通过Service注解显式关联。

    • ELB类型选择

      类型

      elb.class

      适用场景

      配额

      共享型 ELB

      union

      测试环境、低流量场景

      监听器/后端服务器组配额较小,多个Service共享时易触发Quota exceeded for resources: pool。

      独享型 ELB

      performance

      生产环境、高流量场景

      独立资源配额,性能隔离,推荐Knative生产部署使用。

    • 创建ELB。
      • 类型选择:测试环境用共享型,生产环境用独享型。
      • 网络配置:选择与当前CCE集群相同的VPC。
      • 记录ELB ID。

        无需手动配置监听器与后端服务器组,hws-cloudprovider会根据Service的spec.ports自动创建。若之前apply失败导致ELB残留了监听器或Pool,需在ELB控制台手动清理后重新 apply。

    • 绑定ELB到Kourier Service
      • 在Kourier Gateway Service(kourier-system命名空间下的kourier Service)上添加注解:
        apiVersion: v1
        kind: Service
        metadata:
          name: kourier
          namespace: kourier-system
          annotations:
            kubernetes.io/elb.id: <your-elb-id>        # 替换为实际ELB ID
            kubernetes.io/elb.class: union              # 共享型填union,独享型填performance
        spec:
          type: LoadBalancer
          # ... 其余字段保持不变
      • 通过kubectl命令:
        kubectl annotate svc kourier -n kourier-system \
          kubernetes.io/elb.id=<your-elb-id> \
          kubernetes.io/elb.class=union                 # 独享型改为performance

        注意:若绑定失败,请检查以下常见报错:

        • “listener is empty”或“elb.id is not defined, skip”:Service缺少elb.id注解,hws-cloudprovider无法创建监听器。
        • “Quota exceeded for resources: pool(ELB.8905)”:共享型ELB的后端服务器组配额已满,需清理或更换独享型ELB。
  • 镜像仓库规划

    Knative组件镜像默认来自gcr.io/knative-releases与ghcr.io/knative,CCE节点若无法直接拉取公网镜像,需将镜像迁移至SWR。镜像迁移详情请参见上传镜像。

    组件

    默认镜像

    SWR 目标

    activator / autoscaler / controller / webhook

    gcr.io/knative-releases/knative.dev/serving/cmd/*
    swr.<region>.myhuaweicloud.com/<project>/knative-*:v1.19.6

    net-kourier-controller / kourier-gateway

    gcr.io/knative-releases/knative.dev/net-kourier/cmd/*
    swr.<region>.myhuaweicloud.com/<project>/kourier-*:v1.19.0

操作流程

步骤一:安装kn CLI客户端

kn是Knative的命令行客户端,用于创建、更新、删除Knative Service与管理Revision。

  1. 使用kubectl连接集群,详情请参见通过kubectl连接集群。
  2. 执行以下命令,安装kn CLI客户端。本文以knative-v1.19.0为例。
    # Linux amd64
    curl -Lo ./kn https://github.com/knative/client/releases/download/knative-v1.19.0/kn-linux-amd64
    chmod +x ./kn
    sudo mv ./kn /usr/local/bin/
  3. 验证安装:
    kn version

    预期输出:

    Version:      v1.19.0
    Build Date:   2026-xx-xx
    Git Revision: xxxxxxx
    Supported APIs:
    * Serving v1 (knative-serving v1.19.x)

步骤二:安装Knative Serving CRD与核心组件

若节点无法拉取公网镜像,请先完成SWR镜像迁移,并将下方YAML中的镜像地址替换为SWR地址。

  1. 安装CRD。
    kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.19.6/serving-crds.yaml
    kubectl wait --for=condition=Established --all crd --timeout=120s

    预期输出信息包含以下内容。

    customresourcedefinition.apiextensions.k8s.io/services.serving.knative.dev created
    customresourcedefinition.apiextensions.k8s.io/configurations.serving.knative.dev created
    customresourcedefinition.apiextensions.k8s.io/revisions.serving.knative.dev created
    customresourcedefinition.apiextensions.k8s.io/routes.serving.knative.dev created
    ...
  2. 安装核心组件。
    kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.19.6/serving-core.yaml

    该YAML部署以下组件到knative-serving命名空间:

    组件

    说明

    controller

    监听Service/Configuration CRD变化,协调生成Revision与Deployment。

    webhook

    校验CRD合法性,注入默认值。

    autoscaler

    收集Pod并发指标,调整Deployment的replicas,支持缩容到0。

    activator

    Pod缩容到0时拦截请求,触发扩容并排队转发。

  3. 执行以下命令,确认knative-serving命名空间下所有Pod状态均为Running。
    kubectl get pods -n knative-serving

    预期输出:

    NAME                                READY   STATUS    RESTARTS   AGE
    activator-xxxxx-xxxxx               1/1     Running   0          60s
    autoscaler-xxxxx-xxxxx              1/1     Running   0          60s
    controller-xxxxx-xxxxx              1/1     Running   0          60s
    webhook-xxxxx-xxxxx                 1/1     Running   0          60s

    若webhook处于CrashLoopBackOff,多为TLS证书未就绪,等待1~2分钟后自动恢复。Knative v1.19自带证书签发,无需额外部署cert-manager。

步骤三:部署Kourier网关并配置Ingress

Knative支持多种Ingres网关(Kourier/Istio/Contour)。Kourier是基于Envoy的轻量级网关,依赖少、启动快,推荐作为入门与生产默认选型。

  1. 部署Kourier。
    kubectl apply -f https://github.com/knative/net-kourier/releases/download/knative-v1.19.0/kourier.yaml

    Kourier部署到kourier-system命名空间,包含3scale-kourier-gateway(数据面Envoy)。其中Gateway通过“type: LoadBalancer”暴露,CCE不会自动绑定ELB并分配外部IP,需要在Kourier Service上通过注解手动关联已创建的ELB实例。未配置ELB注解时,hws-cloudprovider会报“listener is empty”或“elb.id is not defined, skip”错误。

  2. 配置Kourier为默认Ingress。
    kubectl patch configmap/config-network \
      --namespace knative-serving \
      --type merge \
      --patch '{"data":{"ingress-class":"kourier.ingress.networking.knative.dev"}}'
  3. 验证网关就绪并获取入口IP地址。
    kubectl get pods -n kourier-system
    kubectl get svc kourier -n kourier-system

    预期输出:

    NAME                             READY   STATUS    RESTARTS   AGE
    3scale-kourier-control-xxxxx    1/1     Running   0          60s
    3scale-kourier-gateway-xxxxx     1/1     Running   0          60s
    
    NAME      TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)                      AGE
    kourier   LoadBalancer   10.x.x.x      121.xxx.xxx.xxx   80:3xx/TCP,443:3xx/TCP        90s

    EXTERNAL-IP为ELB绑定的公网/私网IP地址,需提前通过kubernetes.io/elb.id注解关联ELB。请记录该IP地址,后续配置域名解析时使用。

步骤四:配置域名与DNS

Knative默认域名后缀由config-domain ConfigMap决定,所有Knative Service的访问地址为<service-name>.<namespace>.<domain>。

  • 测试环境:使用sslip.io自动解析

    sslip.io会将{ip}.sslip.io解析为{ip},无需自建DNS。将上一步获取的ELB IP地址拼接为域名:

    INGRESS_IP=$(kubectl get svc kourier -n kourier-system -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    KNATIVE_DOMAIN="${INGRESS_IP}.sslip.io"
    
    kubectl patch configmap/config-domain \
      --namespace knative-serving \
      --type merge \
      --patch "{\"data\":{\"${KNATIVE_DOMAIN}\":\"\"}}"
    
    echo "Knative domain: ${KNATIVE_DOMAIN}"

    预期输出以下内容。

    Knative domain: 121.xxx.xxx.xxx.sslip.io
  • 生产环境:使用自定义域名
    1. 将泛域名“*.knative.<your-domain>”解析至ELB绑定的EIP。
    2. 配置config-domain:
      kubectl patch configmap/config-domain \
        --namespace knative-serving \
        --type merge \
        --patch '{"data":{"knative.example.com":""}}'
    3. (可选)为Kourier Gateway的443端口配置TLS证书,建议通过CCE的证书管理或Secret注入实现HTTPS访问。

步骤五:部署首个Knative Service

  1. 使用kn部署helloworld。
    kn service create helloworld \
      --image ghcr.io/knative/helloworld-go:latest \
      --port 8080 \
      --env TARGET=World

    若节点无法拉取ghcr.io镜像,请先迁移至SWR并替换为swr.<region>.myhuaweicloud.com/<project>/helloworld-go:latest。

    预期输出:

    Creating service 'helloworld' in namespace 'default':
      0.030s The Route is still working to reflect the latest desired specification.
      0.062s ...
      0.080s Configuration "helloworld" is waiting for a Revision to become ready.
      8.156s ...
      8.178s Ingress has not yet been reconciled.
      8.298s Ready to serve.
    Service 'helloworld' created with latest revision 'helloworld-00001' and URL:
    http://helloworld.default.121.xxx.xxx.xxx.sslip.io
  2. 查看服务与底层资源。
    kn service list
    kubectl get configuration,revision,route,deployment -l serving.knative.dev/service=helloworld

    预期输出:

    NAME            URL                                                LATEST CREATED   LATEST READY   READY   REASON
    helloworld      http://helloworld.default.121.xxx.xxx.xxx.sslip.io  helloworld-00001 helloworld-00001 True
    
    NAME                                                  READY   STATUS
    configuration.serving.knative.dev/helloworld          True
    revision.serving.knative.dev/helloworld-00001         True
    route.serving.knative.dev/helloworld                  True
    deployment.apps/helloworld-00001-deployment           1/1

    根据Knative Serving的自动伸缩机制,当无流量进入时,Revision对应的Deployment副本数将自动缩容至0(即0/0)。

    Knative Service自动创建了Configuration、Revision、Route、Deployment四级资源,对应CRD层级关系:Service →Configuration → Revision → Deployment。

  3. 访问服务。在任意能访问公网的节点或机器上测试helloworld服务。
    curl http://helloworld.default.${KNATIVE_DOMAIN}

    返回“Hello World!”即表示服务部署成功。

步骤六:验证Scale to Zero

Scale to Zero是Knative的核心特性:无流量时Autoscaler将Deployment replicas缩为0,请求到达时由Activator拦截并触发扩容。

  1. 观察缩容到0。

    服务无请求一段时间后(默认30秒空闲窗口),Pod自动终止:

    # 持续观察Pod状态
    kubectl get pod -l serving.knative.dev/service=helloworld -w

    预期结果:约30~60秒后,Pod数量变为0。

    NAME                                         READY   STATUS    RESTARTS   AGE
    helloworld-00001-deployment-xxxxx-xxxxx      2/2     Running   0          60s
    helloworld-00001-deployment-xxxxx-xxxxx      2/1     Terminating   0      90s
    helloworld-00001-deployment-xxxxx-xxxxx      0/1     Terminating   0      95s
  2. 触发冷启动。

    Pod数为0时发起请求,Activator拦截、触发扩容、转发:

    curl -w "\nTotal time: %{time_total}s\n" http://helloworld.default.${KNATIVE_DOMAIN}

    预期输出:

    Hello World!
    Total time: 1.2s

    首次冷启动耗时取决于镜像拉取与应用启动时长(通常1~3秒)。再次请求会直接命中已运行的Pod,耗时降至毫秒级。

  3. (可选)调整缩容窗口。

    Knative默认在空闲30秒后将Pod缩容到 0,可通过Revision注解调整该窗口,例如延长至1分钟。

    kn service update helloworld \
      --annotation autoscaling.knative.dev/scale-to-zero-pod-retention-period=1m

    预期输出:

    Updating service 'helloworld' in namespace 'default':
      0.030s The Route is still working to reflect the latest desired specification.
      0.062s ...
      0.080s Configuration "helloworld" is waiting for a Revision to become ready.
      1.156s ...
      1.178s Ingress has not yet been reconciled.
      1.298s Ready to serve.
    Service 'helloworld' updated to latest revision 'helloworld-00003' and URL:
    http://helloworld.default.121.xxx.xxx.xxx.sslip.io

    修改注解会触发Knative创建新的Revision(如上例中的helloworld-00003),旧Revision将逐步停止流量,新Revision承接后续请求。

步骤七:验证灰度发布(蓝绿/金丝雀)

Knative通过Revision不可变快照 + Route流量权重实现灰度发布,无需引入额外工具链。

  1. 更新镜像(自动生成新Revision)。
    kn service update helloworld \
      --image ghcr.io/knative/helloworld-go:latest \
      --env TARGET=Knative

    该操作会自动创建新Revision(helloworld-00002),默认Route将100%流量切到新版本。旧Revision(helloworld-00001)保留但不接流量。

  2. 金丝雀发布:按权重分流。

    将流量拆分为旧版本90%、新版本10%,观察后再逐步放开:

    kn service update helloworld \
      --traffic helloworld-00001=90 \
      --traffic helloworld-00002=10

    --traffic参数格式为“Revision名称=百分比”,多个Revision的权重总和应为100。

  3. 验证流量分配。多次请求服务,观察返回内容的比例分布。
    for i in $(seq 1 10); do
      curl -s http://helloworld.default.${KNATIVE_DOMAIN}
    done | sort | uniq -c

    预期输出(约9:1比例):

    9 Hello World!
    1 Hello Knative!
  4. 查看路由详情。
    kn route describe helloworld

    预期输出:

    Name:       helloworld
    Namespace:  default
    Age:        10m
    URL:        http://helloworld.default.121.xxx.xxx.xxx.sslip.io
    
    Traffic Targets:
      90%  @latest  (helloworld-00001) # still old
            URL:  http://helloworld.default.../helloworld-00001
      10%  helloworld-00002
            URL:  http://helloworld.default.../helloworld-00002
  5. 版本回滚。

    Revision为不可变快照,回滚操作即将流量权重重新指向旧Revision:

    kn service update helloworld --traffic helloworld-00001=100

    执行后流量立即切回helloworld-00001,无需重新部署。

配置优化

KPA弹性伸缩调优

Knative Pod Autoscaler(KPA)默认基于并发数(concurrency)进行弹性伸缩。生产环境需根据业务特征调整关键参数。

关键参数通过Revision的template.metadata.annotations注解配置:

注解

默认值

说明

调优建议

autoscaling.knative.dev/metric

concurrency

伸缩指标

高QPS短任务用rps;长连接或重计算任务用concurrency。

autoscaling.knative.dev/target

100(concurrency)/ 200(rps)

单Pod目标并发/速率

按单Pod承载能力设定,过低会过度扩容,过高会触发限流。

autoscaling.knative.dev/max-scale

0(无上限)

最大Pod数

生产环境必设,防止流量突增打满节点池资源。

autoscaling.knative.dev/min-scale

0

最小Pod数

对冷启动敏感的场景设为1~2,保留温实例。

autoscaling.knative.dev/scale-to-zero-pod-retention-period

0s

缩容到0前的保留时长

设30s~1m,平滑应对间歇性流量。

autoscaling.knative.dev/window

60s

伸缩计算窗口

突发流量场景缩短至30s;平稳流量延长至120s减少抖动。

该表注解作用于单个Revision。如需为所有Service设置全局默认值,请编辑“config-autoscaler ConfigMap:kubectl edit configmap/config-autoscaler -n knative-serving”。注解优先级高于全局默认。

示例:为高QPS Web服务配置KPA

以下以helloworld服务为例,演示如何为高QPS场景配置KPA参数。

kn service create web-api \
  --image swr.cn-north-7.myhuaweicloud.com/<project>/web-api:latest \
  --port 8080 \
  --annotation autoscaling.knative.dev/metric=rps \
  --annotation autoscaling.knative.dev/target=200 \
  --annotation autoscaling.knative.dev/max-scale=20 \
  --annotation autoscaling.knative.dev/min-scale=2 \
  --annotation autoscaling.knative.dev/window=30s

资源配额与限制

为避免控制面过载、Pod调度失败或集群资源耗尽,建议按以下策略配置资源配额。

配置项

建议值

说明

控制面Pod resources requests

controller/autoscaler 500m/512Mi,webhook 100m/50Mi

默认值偏低,在生产负载下建议适当上调。

业务Pod requests

按单实例承载能力设定

设置过低可能导致节点资源超卖;设置过高可能导致调度失败。Knative默认按requests计算并发数。

业务Pod limits

requests的2~4倍

预留突发流量的资源余量,避免突发流量OOM。在GPU场景下,limits应等于requests。

namespace ResourceQuota

按业务命名空间实际需要进行设定

限制单个命名空间的资源配额,防止Knative Service无限扩容导致集群资源耗尽或服务不可用。

通过config-resource ConfigMap全局调整默认资源策略:

kubectl patch configmap/config-resource \
  --namespace knative-serving \
  --type merge \
  --patch '{"data":{"pod-container-default-requests":"{\"cpu\":\"500m\",\"memory\":\"512Mi\"}"}}'

常见问题

相关文档