Kubernetes 现在正在蓬勃发展,许多公司正在转向 Kubernetes,因为它的功能集和对水平自动缩放、数据库、CI/CD 等库的大量支持。为了提供所有这些功能,Kubernetes 提供了扩展自身的方法。所有这些扩展都是作为操作符编写的,它们在 Kubernetes 内部以及有时在外部实现自动化。在我们开始之前,让我们定义一些在开始使用运算符之前应该知道的术语。

操作员、控制器和自定义资源

Operators 是 Kubernetes 的软件扩展,它利用自定义资源来管理应用程序及其组件。

资源是 Kubernetes API 中的一个端点,用于存储某种 API 对象的集合;例如,内置的 pods 资源包含 Pod 对象的集合。

自定义资源是 Kubernetes API 的扩展,在默认 Kubernetes 安装中不一定可用。它表示对特定 Kubernetes 安装的自定义。

Operator 使用控制器来管理自定义资源。这些自定义资源有一个控制循环。

控制回路是调节系统状态的非终止回路。

控制器至少跟踪一种 Kubernetes 资源类型。这些对象有一个表示所需状态的规范字段。该资源的控制器负责使当前状态更接近所需状态。

因此,最终操作员由控制器和自定义资源组成,其中自定义资源是未在默认 Kubernetes 安装中定义的对象,并作为 Kubernetes API 的扩展,控制器是维护自定义资源的定义规范或状态的循环。

如何建立一个?

有多种方法可以为 Kubernetes 构建 operator,kubebuilder是最流行的一种,但我喜欢 Operator SDK,它使脚手架、构建和部署变得容易。

在本教程中,我们将构建执行基本数学函数、加法、减法、乘法和除法的运算符。这些与 Kubernetes 无关,但练习为操作员的工作方式奠定了基础。

先决条件

  1. Kubernetes集群,使用kind或者docker for desktop提供一个配置了kubectl。

2.基本的Golang。

3.安装Operator SDK。

安装后,创建任意名称的文件夹,我在该文件夹中创建了operator-tutorial为您的操作员运行脚手架

operator-sdk init --domain calc.k8s --repo github.com/ratnadeep007/operator-tutorial

您可以提供自己的 github 存储库。--domain是指所有自定义资源所属的命名空间。在默认部署清单中,apiVersion: apps/v1apps是我们在域中定义的。作为最佳实践,我们将自定义资源定义为域,它不应与 Kubernetes 中的其他默认域发生冲突。

此命令将创建多个文件夹和文件,我们将在稍后查看。在此之前,我们需要定义我们的 api 和自定义资源。

要求:

  1. Spec 将包含 2 个数字的输入

  2. 一个操作输出。

operator-sdk create api --group basic --version v1alpha1 --kind Add --resource --controller

在上面的命令中,我们告诉 operator-sdk 脚手架 api 属于calc.k8s的基本组,版本为v1alpha1的种类为Add的资源,这意味着它将添加自定义资源定义和控制器。运行此命令后,您会发现文件夹添加api/v1alpha1controllersapi/v1alpha1将包含自定义资源定义生成代码,controllers包含该自定义资源的控制器。

add_type.go中,主要的 2 个结构是AppSpecAppStatus

// AddSpec defines the desired state of Add
type AddSpec struct {
    Num1 int `json:"num1"`
    Num2 int `json:"num2"`
}

// AddStatus defines the observed state of Add
type AddStatus struct {
    Output int `json:"result"`
}

Num1Num2将是我们的输入,Output是我们在AddStatus中的结果。因此,按照我们的清单添加将如下所示:

apiVersion: basic.calc.k8s/v1alpha1
kind: Add
metadata:
  name: basic-add
spec:
  num1: 1
  num2: 2

默认情况下,kubectl 只会显示nameage的资源。为了显示我们的输入和输出字段,我们需要在//+kubebuilder:subresource:status下方添加以下内容:

//+kubebuilder:printcolumn:JSONPath=".spec.num1",name=Number 1,type=integer
//+kubebuilder:printcolumn:JSONPath=".spec.num2",name=Number 2,type=integer
//+kubebuilder:printcolumn:JSONPath=".status.result",name=Result,type=intege

JSONPath是我们要显示的变量的路径。对于输入,我们使用了.spec.num.spec.num2。对于输出,我们使用了.status.result,因为在AppStatus中我们给出了Output intjson:"result"`,它在创建 json 时将输出字段作为结果字段。

但在应用清单之前,我们需要生成自定义资源定义以及*_types.go文件的代码。

用于生成代码:

make generate

用于生成自定义资源定义(CRD):

make manifest

现在我们需要将这些部署到我们的 Kubernetes 集群。为此,我采取了在我的系统上运行它并通过 kubeconfig 连接到我的集群的最简单路径。因此,如果您可以使用kubectl get nodes获取节点,那么您可以运行

make install run

部署 CRD 并运行控制器。

创建以下清单文件以进行添加:

apiVersion: basic.calc.k8s/v1alpha1
kind: Add
metadata:
  name: basic-add
spec:
  num1: 1
  num2: 2

kubectl apply -f add.yml

在此之后,您可以看到您将自定义资源添加为

$ kubectl get add
NAME            NUMBER 1         NUMBER 2           RESULT
basic-add      1                         2

您可以看到Result,因为我们没有为自定义资源编写任何控制器代码。打开controllers/add_controller.go,在该文件中,我们需要专注于Reconcile函数,该函数在我们的资源更改时运行,无论是创建、更新还是删除。此外,我们需要更新如下:

func (r *AddReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    _ = log.FromContext(ctx)

    instance := &v1alpha1.Add{}

    err := r.Client.Get(ctx, req.NamespacedName, instance)
    if err != nil {
        fmt.Printf("Error getting instance: %s", err)
    }

    instance.Status.Output = instance.Spec.Num1 + instance.Spec.Num2
    err = r.Client.Status().Update(ctx, instance)
    if err != nil {
        fmt.Printf("Error updating instance: %s", err)
    }

    return ctrl.Result{}, nil
}

在上面的代码中,我们正在执行以下操作:

1.获取add的实例。

  1. 检查它是否存在于我们的集群上。

  2. 用结果更新状态的输出字段。

现在,删除并创建我们的添加自定义资源,您会在结果字段中看到输出。

$ kubectl get add
NAME            NUMBER 1         NUMBER 2           RESULT
basic-add      1                         2                           3

所以,这是 Kubernetes 中非常基础的操作符。您可以在此控制器中调用外部 api,修改已经存在的资源,如 Pod 等。

我在我的项目中添加了所有其他函数(减法、乘法、除法),可在此链接中找到:github

如有问题,请发表评论。

保持学习。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐