跳至内容

Knative 开源入门第3部分:API更改

发布时间:2024-05-30

Knative 开源入门第3部分:API更改

作者:Calum Murray 软件工程实习生 @ Red Hat,以及 Leo Li 软件工程实习生 @ Red Hat

您好,欢迎回到博客系列!在本篇博文中,我们将开始对一些 Knative 代码进行实际的代码更改。具体来说,我们将学习 Knative 中的 API 是什么,以及如何更改它们。为了促进这一点以及未来以编码为中心的博文,我们将基于 Knative 示例源代码构建一个简单的事件源。我们的源将与示例源类似,并以一定间隔发送事件,但它将允许您创建一个文本模板,该模板将在发送的每个事件中使用变量填充。在本博文结束时,您应该能够理解 Knative 中的 API 是什么,并且已经修改了示例源 API 以支持我们的新功能(文本模板)。

什么是 API?

API 是“应用程序编程接口”。您可以将其视为一个契约,其中一个应用程序为用户提供了一个接口,用户可以使用该接口以编程方式指定他们希望应用程序为他们做什么

在 Knative 中,API 采用 Kubernetes 自定义资源定义 (CRD) 的形式。这些是 Knative 可以在您的集群中提供的资源的定义。例如,如果您希望为正在构建的事件驱动应用程序提供一个事件代理,则可能希望使用 Knative Eventing Broker CRD。用户通过在其集群中创建自定义资源的实例来与该 API 交互。您可以将其视为对象是类的实例的方式:自定义资源是自定义资源定义的实例。

一旦 Kubernetes 意识到 CRD(例如,通过 kubectl apply -f mycrd.yaml),用户就可以像对待普通 Kubernetes 资源一样与自定义资源进行交互。例如,如果我想获取 my-namespace 命名空间中的所有代理,我可以运行 kubectl get brokers -n my-namespace。这是一个非常强大的概念,也是 Knative 哲学的重要组成部分:我们为用户提供 Kubernetes 原生资源,以便他们能够更轻松地在 Kubernetes 上构建应用程序。在 Knative 中,我们通过使用 自定义资源定义 的核心 Kubernetes API 为用户提供 API,以便我们可以实现成为 Kubernetes 原生的理念。

我们如何更改 API?

现在我们知道了 API 是什么(一般来说,以及在 Knative 的上下文中),我们就可以探索如何对其进行更改。当我们想要更新 API 时,需要执行三个步骤。

更新对象的结构体。在我们的例子中,我们希望更新 SampleSource 结构体。在 Knative 中,这些通常位于 pkg/apis/<groupname>/<version>/<resourcename>_types.go 中。查看此结构体,我们可以看到所有资源通常都遵循其结构

v1/
├── apiserver_conversion.go
├── apiserver_conversion_test.go
├── apiserver_defaults.go
├── apiserver_defaults_test.go
├── apiserver_lifecycle.go
// +genclient
// +genreconciler
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type SampleSource struct {
    metav1.TypeMeta `json:",inline"`
    // +optional
    metav1.ObjectMeta `json:"metadata,omitempty"`

    // Spec holds the desired state of the SampleSource (from the client).
    Spec SampleSourceSpec `json:"spec"`

    // Status communicates the observed state of the SampleSource (from the controller).
    // +optional
    Status SampleSourceStatus `json:"status,omitempty"`
}

查看此代码,我们可以看到有一个嵌套的 metav1.TypeMeta 结构体,一个嵌套的 metav1.ObjectMeta 结构体,然后是一个 Spec 和一个嵌套的 Status 结构体。这就是 Knative 对象(以及大多数 k8s 资源)的结构方式。TypeMeta 和 ObjectMeta 提供有关类型和对象的元数据,通常您只需要知道结构体需要包含它们即可。Spec 和 Status 是您实际要修改的结构体。Spec 是我们提供给 Knative 用户的所有选项所在的位置,而 Status 是我们提供给用户有关特定对象状态的所有信息存储的位置。

现在我们了解了结构体的工作原理,让我们进行实际的更改。尝试将消息模板字段添加到样本源中,以便用户可以在每个事件中配置该消息。在您自己尝试过之后,继续阅读以了解我们是如何做到的!通常,在阅读“解决方案”之前,请先尝试自己完成每个编码步骤。在您继续阅读博文时,我们会提醒您这一点。

// SampleSourceSpec holds the desired state of the SampleSource (from the client).
type SampleSourceSpec struct {
    // inherits duck/v1 SourceSpec, which currently provides:
    // * Sink - a reference to an object that will resolve to a domain name or
    //   a URI directly to use as the sink.
    // * CloudEventOverrides - defines overrides to control the output format
    //   and modifications of the event sent to the sink.
    duckv1.SourceSpec `json:",inline"`

    // ServiceAccountName holds the name of the Kubernetes service account
    // as which the underlying K8s resources should be run. If unspecified
    // this will default to the "default" service account for the namespace
    // in which the SampleSource exists.
    // +optional
    ServiceAccountName string `json:"serviceAccountName,omitempty"`

    // Interval is the time interval between events.
    //
    // The string format is a sequence of decimal numbers, each with optional
    // fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time
    // units are "ns", "us" (or "µs"), "ms", "s", "m", "h". If unspecified
    // this will default to "10s".
    Interval string `json:"interval"`

    // MessageTemplate is the text/template which is used for every event sent.
    //
    // The string format is any valid go text/template template string where
    // the fields are any variables set in the config map
    MessageTemplate string `json:"messageTemplate"`
}

我们只添加了 Spec 中的 MessageTemplate 字符串。请注意 JSON 标签 - 这非常重要!如果没有 JSON 标签,则当控制器从 API 服务器接收有关它的信息时,此字段将不会从 JSON 对象中读取,并且该值不会写入我们发送回 API 服务器的 JSON 中,因此它不会存储在 etcd 中。

更新结构体后,我们通常希望更新 代码生成。Knative 使用自定义代码生成器来自动实现协调器的一部分(在即将发布的博文中将详细介绍),以及 深拷贝 结构体函数和自动生成的 API 文档。在我们的例子中,我们希望更新 SampleSourceSpec 结构体的 DeepCopy 函数。要更新 Knative 中的生成代码,您只需要运行 ./hack/update-codegen.sh 即可。在给定的存储库中,您可能需要运行此操作的特定版本的依赖项,因此在设置存储库进行开发时,请始终检查 DEVELOPMENT.md 文件。

更新结构体后,您还需要更新 CRD yaml 文件。对我们来说,我们正在编辑的 CRD 看起来像;

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  labels:
    samples.knative.dev/release: devel
    eventing.knative.dev/source: "true"
    knative.dev/crd-install: "true"
  annotations:
    registry.knative.dev/eventTypes: |
    [
        { "type": "dev.knative.sample" }
    ]
  name: samplesources.samples.knative.dev
spec:
  group: samples.knative.dev
  versions:
    - &version
    name: v1alpha1
    served: true
    storage: true
    subresources:
        status: {}
    schema:
        openAPIV3Schema:
                  type: object
          properties:
            spec:
              type: object
              properties:
                interval:
                  type: string
                messageTemplate:
                  type: string
                serviceAccountName:
                  type: string
                sink:
                  type: object
                  properties:
                    ref:
                      type: object
                      properties:
                        apiVersion:
                          type: string
                        kind:
                          type: string
                        name:
                          type: string
            status:
              type: object
              properties:
                status:
                  type: string
                sinkUri:
                  type: string

通过遵循这些步骤,您已成功修改了 SampleSource API 以支持一项新功能:文本模板。此更改允许用户提供一个文本模板,我们将在未来的博文中使用它来填充源发送的每个事件的变量。这展示了 Knative API 系统的强大功能和灵活性,以及如何扩展它以满足您的特定需求。

在下一篇博文中,我们将继续我们的项目,并学习如何修改示例源的控制器。这样,当用户使用我们新的 API 选项时,它实际上就会更改系统中的某些内容!

期待您在下一篇博文中与我们见面!在此期间,如果您有任何问题,请在 #knative-contributors 中联系我们,我们将很乐意提供帮助。

我们使用分析和 Cookie 来了解网站流量。为此目的,有关您使用我们网站的信息将与 Google 共享。 了解更多。