1. 简介

在本教程中,我们将探讨如何在 Kubernetes 平台上部署无服务器(Serverless)工作负载。我们将使用 Knative 作为实现该目标的框架。在过程中,我们还将学习使用 Knative 作为无服务器应用框架所带来的优势。

2. Kubernetes 与 Knative

开发无服务器应用如果没有工具支持是相当麻烦的。回想一下 Docker 与 Kubernetes 是如何改变我们管理基于微服务架构的云原生应用的。显然,在无服务器领域我们也同样可以从框架和工具中受益。而 Kubernetes,当然也可以帮助我们实现这一目标。

2.1. Kubernetes 用于无服务器架构

Kubernetes 作为 CNCF 的毕业项目,已成为容器化工作负载编排领域的领先平台之一。它允许我们自动化部署、扩展和管理以 OCI 镜像(如 Docker 或 Buildah 构建的镜像)打包的应用程序:

Kubernetes 架构

其明显优势包括资源利用最优化。但这一点,不也正是我们对无服务器架构的期望吗?

当然,容器编排服务与无服务器服务在目标上有很多重叠之处。但不同的是,虽然 Kubernetes 提供了自动化管理的工具,我们仍需负责配置和维护 Kubernetes 本身。而无服务器的目标是连这些操作也一并免除。

但我们可以利用 Kubernetes 来运行无服务器环境。这样做的好处显而易见:

  • 避免被特定云厂商的 SDK 和 API 所锁定;
  • 通过 Kubernetes 平台,我们可以轻松地将无服务器应用从一个云平台迁移到另一个平台;
  • 我们可以使用一个标准的无服务器框架来构建应用,就像 Ruby on Rails 和 Spring Boot 曾带给我们的便利一样。

2.2. Knative 简介

Knative 是一个开源项目,它为 Kubernetes 添加了部署、运行和管理无服务器应用所需的功能组件。我们可以将服务或函数打包为容器镜像并交给 Knative。Knative 只在需要时运行该容器。

Knative 的核心架构主要包括两个部分:Serving(服务)和 Eventing(事件),运行在 Kubernetes 基础设施之上。

Knative Serving

Knative Serving 允许我们部署可自动伸缩的容器。它基于 Kubernetes 和 Istio 构建,并通过 Custom Resource Definitions (CRDs) 部署一组对象:

Knative Serving

Knative Serving 主要由四个对象组成:Service(服务)、Route(路由)、Configuration(配置)和 Revision(版本)。

  • Service 负责管理整个工作负载的生命周期,并自动创建 Route 和 Configuration;
  • 每次更新 Service 时,会生成一个新的 Revision;
  • 我们可以配置 Service 将流量路由到最新或任意一个 Revision。

Knative Eventing

Knative Eventing 提供了一个用于消费和产生事件的基础设施,这有助于将事件驱动架构与无服务器应用结合:

Knative Eventing

Knative Eventing 使用的资源包括 Source(源)、Broker(事件中心)、Trigger(触发器)和 Sink(目标)。

  • Trigger 可用于过滤和转发事件到订阅者;
  • Source 是产生事件并发送到 Broker 的组件;
  • Broker 是事件的中心枢纽;
  • 可以根据任意属性过滤事件,并通过 Trigger 路由到 Sink。

Knative Eventing 使用 HTTP POST 请求发送和接收符合 CloudEvents 标准的事件。

✅ CloudEvents 是一种用于标准化事件数据描述的规范,目标是简化跨服务和平台的事件声明和传递。该项目属于 CNCF 无服务器工作组。

3. 安装与配置

如前所述,Knative 是一组运行在 Istio 等服务网格和 Kubernetes 等编排集群上的组件。此外,我们还需要安装一些命令行工具以便操作。因此,在安装 Knative 之前,我们需要确保一些依赖项。

3.1. 安装前置依赖

Kubernetes 的安装方式有很多种,本教程不深入细节。例如,Docker Desktop 自带一个简单的 Kubernetes 集群,适用于大多数用途。不过,推荐使用 Kubernetes in Docker (kind) 来运行本地 Kubernetes 集群。

在 Windows 上安装 kind 的最简单方式是使用 Chocolatey 包管理器

choco install kind

与 Kubernetes 交互时,推荐使用命令行工具 kubectl。同样可以通过 Chocolatey 安装:

choco install kubernetes-cli

最后,Knative 也有一个命令行工具 kn。Knative CLI 提供了快速创建资源的接口,也支持自动伸缩和流量拆分等复杂操作。

在 Windows 上安装 Knative CLI 的最简单方式是从其 官方发布页面 下载对应的二进制文件,然后从命令行调用即可。

3.2. 安装 Knative

准备好所有前置依赖后,就可以安装 Knative 组件了。如前所述,Knative 组件本质上是一组部署在 Kubernetes 集群上的 CRD。单独安装可能会比较复杂。

幸运的是,Knative 提供了一个 quickstart 插件,可以快速在 Kind 上部署 Knative 开发环境。在 Windows 上安装该插件的方式也是从 官方发布页面 下载二进制文件。

该插件主要完成以下任务:

✅ 确保已安装 Kind
✅ 创建名为 knative 的集群
✅ 安装 Knative Serving,使用 Kourier 作为默认网络层,nip.io 作为 DNS
✅ 安装 Knative Eventing,并创建一个内存中的 Broker 和 Channel 实现

最后,我们可以通过以下命令确认 quickstart 是否成功创建了集群:

kind get clusters

4. 实战 Knative

现在我们已经掌握了足够的理论知识,可以动手实践 Knative 提供的功能了。

4.1. 使用 Knative Serving 部署应用

首先,我们使用 Knative Serving 来部署一个无服务器应用。如前所述,Service 是管理应用整个生命周期的核心对象。我们可以通过 YAML 文件定义它:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: my-service
spec:
  template:
    metadata:
      name: my-service-v1
    spec:
      containers:
        - image: <registry>/my-image:latest
          ports:
            - containerPort: 8080

⚠️ 注意:spec.template.metadata.name 用于命名版本(Revision),便于后续识别。

使用 kubectl 部署:

kubectl apply -f my-service.yaml

也可以使用 Knative CLI 更简洁地完成相同操作:

kn service create hello \
  --image <registry>/my-image:latest \
  --port 8080 \
  --revision-name=my-service-v1

Knative 会自动完成以下步骤:

✅ 创建不可变的 Revision
✅ 配置网络(Route、Ingress、Service、LoadBalancer)
✅ 根据需求自动扩缩容 Pod

4.2. 使用 Knative Serving 实现流量拆分

除了自动扩缩容,Knative Serving 还支持流量拆分。我们可以将流量按比例分配到不同的 Revision,实现灰度发布、A/B 测试等场景。

修改 Service YAML 文件,添加 traffic 配置:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: my-service
spec:
  template:
    metadata:
      name: my-service-v2
    spec:
      containers:
        - image: <registry>/my-image:latest
          ports:
            - containerPort: 8080
  traffic:
  - latestRevision: true
    percent: 50
  - revisionName: my-service-v1
    percent: 50

部署后,使用以下命令查看所有 Revision:

kn revisions list

✅ 这个功能非常适合蓝绿部署、金丝雀发布、A/B 测试等场景。

4.3. 使用 Knative Eventing 构建事件驱动应用

接下来我们使用 Knative Eventing 构建事件驱动的应用。Knative Eventing 的核心是 Source、Broker、Trigger 和 Sink。

首先确认集群中是否有 Broker:

kn broker list

假设我们有一个服务同时作为事件的生产者和消费者,可以这样定义:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: my-service
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/minScale: "1"
    spec:
      containers:
        - image: <registry>/my-image:latest
          env:
            - name: BROKER_URL
              value: http://broker-ingress.namespace.svc.cluster.local/default

BROKER_URL 是事件中心的地址,需根据实际环境替换。

4.4. 使用 Trigger 过滤和订阅事件

定义一个 Trigger,将事件路由到目标服务:

apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
  name: my-trigger
  annotations:
    knative-eventing-injection: enabled
spec:
  broker: default
  filter:
    attributes:
      type: order.created
  subscriber:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: my-service

部署后,服务将只消费 order.created 类型的事件。

✅ Sink 可以是 Addressable(接收并确认事件)或 Callable(接收并处理事件,可返回响应)资源,例如 Service、Broker、Channel 等。

5. 总结

在本教程中,我们探讨了如何使用 Kubernetes 作为底层基础设施,通过 Knative 实现无服务器架构。我们了解了 Knative 的核心组件 Serving 和 Eventing,并实践了部署应用、流量拆分以及事件驱动编程等关键功能。

✅ 使用 Knative 的优势包括:

  • 标准化的无服务器开发框架
  • 跨云平台的可移植性
  • 支持自动扩缩容、灰度发布、事件驱动架构等高级功能

随着云原生的发展,Knative 为无服务器架构提供了一个强大、灵活且开放的解决方案。


原始标题:Serverless Architecture with Knative