1. 简介
在本教程中,我们将探讨如何在 Kubernetes 平台上部署无服务器(Serverless)工作负载。我们将使用 Knative 作为实现该目标的框架。在过程中,我们还将学习使用 Knative 作为无服务器应用框架所带来的优势。
2. Kubernetes 与 Knative
开发无服务器应用如果没有工具支持是相当麻烦的。回想一下 Docker 与 Kubernetes 是如何改变我们管理基于微服务架构的云原生应用的。显然,在无服务器领域我们也同样可以从框架和工具中受益。而 Kubernetes,当然也可以帮助我们实现这一目标。
2.1. Kubernetes 用于无服务器架构
Kubernetes 作为 CNCF 的毕业项目,已成为容器化工作负载编排领域的领先平台之一。它允许我们自动化部署、扩展和管理以 OCI 镜像(如 Docker 或 Buildah 构建的镜像)打包的应用程序:
其明显优势包括资源利用最优化。但这一点,不也正是我们对无服务器架构的期望吗?
当然,容器编排服务与无服务器服务在目标上有很多重叠之处。但不同的是,虽然 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 主要由四个对象组成:Service(服务)、Route(路由)、Configuration(配置)和 Revision(版本)。
- Service 负责管理整个工作负载的生命周期,并自动创建 Route 和 Configuration;
- 每次更新 Service 时,会生成一个新的 Revision;
- 我们可以配置 Service 将流量路由到最新或任意一个 Revision。
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 为无服务器架构提供了一个强大、灵活且开放的解决方案。