5.17. 迁移到 Operator SDK v0.1.0


本指南论述了如何将使用 Operator SDK v0.0.x 构建的 Operator 项目迁移到 Operator SDK v0.1.0 所需的项目结构。

重要

红帽支持的 Operator SDK CLI 工具版本,包括 Operator 项目的相关构建和测试工具已被弃用,计划在以后的 OpenShift Dedicated 发行版本中删除。红帽将在当前发行生命周期中提供对这个功能的程序错误修复和支持,但此功能将不再获得改进,并将在以后的 OpenShift Dedicated 版本中删除。

对于创建新 Operator 项目,不建议使用红帽支持的 Operator SDK 版本。现有 Operator 项目的 Operator 作者可使用 OpenShift Dedicated 4 发布的 Operator SDK CLI 工具版本来维护其项目,并创建针对较新版本的 OpenShift Dedicated 的 Operator 发行版本。

以下与 Operator 项目相关的基础镜像 没有被弃用。这些基础镜像的运行时功能和配置 API 仍然会有程序错误修复和并提供对相关 CVE 的解决方案。

  • 基于 Ansible 的 Operator 项目的基础镜像
  • 基于 Helm 的 Operator 项目的基础镜像

有关 Operator SDK 不支持的、社区维护版本的信息,请参阅 Operator SDK (Operator Framework)

迁移项目的建议方法是:

  1. 初始化新的 v0.1.0 项目。
  2. 将您的代码复制到新项目。
  3. 修改新项目,如 v0.1.0 所述。

本指南使用 memcached-operator (来自 Operator SDK 的示例项目)来说明迁移步骤。有关 pre- 和 post-migration 示例,请参阅 v0.0.7 memcached-operatorv0.1.0 memcached-operator 项目结构。

5.17.1. 创建新的 Operator SDK v0.1.0 项目

重命名 Operator SDK v0.0.x 项目,并在其位置创建一个新的 v0.1.0 项目。

先决条件

  • 开发工作站上安装 operator SDK v0.1.0 CLI
  • 之前使用较早版本的 Operator SDK 部署 memcached-operator 项目

流程

  1. 确保 SDK 版本为 v0.1.0 :

    $ operator-sdk --version
    operator-sdk version 0.1.0
  2. 创建一个新项目

    $ mkdir -p $GOPATH/src/github.com/example-inc/
    $ cd $GOPATH/src/github.com/example-inc/
    $ mv memcached-operator old-memcached-operator
    $ operator-sdk new memcached-operator --skip-git-init
    $ ls
    memcached-operator old-memcached-operator
  3. 从旧项目中复制 .git

    $ cp -rf old-memcached-operator/.git memcached-operator/.git

5.17.2. 从 pkg/apis 中迁移自定义类型

将项目的自定义类型迁移到更新的 Operator SDK v0.1.0 用法。

先决条件

  • 开发工作站上安装 operator SDK v0.1.0 CLI
  • 之前使用较早版本的 Operator SDK 部署 memcached-operator 项目
  • 使用 Operator SDK v0.1.0 创建新项目

流程

  1. 为自定义类型创建 scaffold API。

    1. 使用 operator-sdk add api --api-version=<apiversion> --kind=<kind> 在新项目中创建自定义资源 (CR) 的 API:

      $ cd memcached-operator
      $ operator-sdk add api --api-version=cache.example.com/v1alpha1 --kind=Memcached
      
      $ tree pkg/apis
      pkg/apis/
      ├── addtoscheme_cache_v1alpha1.go
      ├── apis.go
      └── cache
          └── v1alpha1
              ├── doc.go
              ├── memcached_types.go
              ├── register.go
              └── zz_generated.deepcopy.go
    2. 对旧项目中定义的自定义类型重复上一个命令。每个类型都在文件 pkg/apis/<group>/<version>/<kind>_types.go 中定义。
  2. 复制类型的内容。

    1. 将来自旧项目的 pkg/apis/<group>/<version>/types.go 文件的 SpecStatus 的内容复制到新项目的 pkg/apis/<group>/<version>/<kind>_types.go 文件。
    2. 每个 <kind>_types.go 文件都有一个 init() 函数。确保不要删除该类型,因为这会使用 Manager 的方案注册类型:

      func init() {
      	SchemeBuilder.Register(&Memcached{}, &MemcachedList{})

5.17.3. 迁移协调代码

将项目的自定义类型迁移到更新的 Operator SDK v0.1.0 用法。

先决条件

  • 开发工作站上安装 operator SDK v0.1.0 CLI
  • 之前使用较早版本的 Operator SDK 部署 memcached-operator 项目
  • pkg/apis 中迁移自定义类型

流程

  1. 添加控制器以监视 CR。

    在 v0.0.x 项目中,之前在 cmd/<operator-name>/main.go 中定义要监视的资源:

    sdk.Watch("cache.example.com/v1alpha1", "Memcached", "default", time.Duration(5)*time.Second)

    对于 v0.1.0 项目,您必须定义一个 Controller 监视资源:

    1. 添加控制器以使用 operator-sdk add controller --api-version=<apiversion> --kind=<kind> 监视您的 CR 类型。

      $ operator-sdk add controller --api-version=cache.example.com/v1alpha1 --kind=Memcached
      
      $ tree pkg/controller
      pkg/controller/
      ├── add_memcached.go
      ├── controller.go
      └── memcached
          └── memcached_controller.go
    2. 检查 pkg/controller/<kind>/<kind>_controller.go 文件中的 add() 功能:

      import (
          cachev1alpha1 "github.com/example-inc/memcached-operator/pkg/apis/cache/v1alpha1"
          ...
      )
      
      func add(mgr manager.Manager, r reconcile.Reconciler) error {
          c, err := controller.New("memcached-controller", mgr, controller.Options{Reconciler: r})
      
          // Watch for changes to the primary resource Memcached
          err = c.Watch(&source.Kind{Type: &cachev1alpha1.Memcached{}}, &handler.EnqueueRequestForObject{})
      
          // Watch for changes to the secondary resource pods and enqueue reconcile requests for the owner Memcached
          err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{
      		IsController: true,
      		OwnerType:    &cachev1alpha1.Memcached{},
      	})
      }

      删除第二个 Watch() 或修改它,以监视您的 CR 拥有的二级资源类型。

      通过监控多个资源,您可以针对与应用程序相关的多个资源触发协调循环。如需了解更多详细信息,请参阅 监视和事件处理 文档和 Kubernetes 控制器惯例 文档。

      如果 Operator 监视多个 CR 类型,您可以根据应用程序执行以下操作之一:

      • 如果 CR 归您的主 CR 所有,请将其视为同一控制器中的辅助资源,以触发主资源的协调循环。

        // Watch for changes to the primary resource Memcached
            err = c.Watch(&source.Kind{Type: &cachev1alpha1.Memcached{}}, &handler.EnqueueRequestForObject{})
        
            // Watch for changes to the secondary resource AppService and enqueue reconcile requests for the owner Memcached
            err = c.Watch(&source.Kind{Type: &appv1alpha1.AppService{}}, &handler.EnqueueRequestForOwner{
        		IsController: true,
        		OwnerType:    &cachev1alpha1.Memcached{},
        	})
      • 添加新控制器来独立于其他 CR 监视和协调 CR。

        $ operator-sdk add controller --api-version=app.example.com/v1alpha1 --kind=AppService
          // Watch for changes to the primary resource AppService
            err = c.Watch(&source.Kind{Type: &appv1alpha1.AppService{}}, &handler.EnqueueRequestForObject{})
  2. pkg/stub/handler.go 复制和修改协调代码。

    在 v0.1.0 项目中,协调代码在控制器的 ReconcilerReconcile() 方法中定义。这与较旧的项目中的 Handle() 函数类似。请注意参数和返回值之间的区别:

    • Reconcile:

          func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Result, error)
    • Handle:

          func (h *Handler) Handle(ctx context.Context, event sdk.Event) error

    Reconcile() 函数不会接收 sdk.Event (对象会),而是接收一个 Request (Name/Namespace 键) 来查找对象。

    如果 Reconcile() 函数返回错误,控制器会重新排队并重试 Request。如果没有返回错误,则根据 Result,控制器不会在指定持续时间后重试 Request、或立即重试。

    1. 将旧项目的 Handle() 函数中的代码复制到控制器的 Reconcile() 函数中的现有代码。务必在 Reconcile() 代码中保留初始部分,该代码查找 Request 并检查它是否已被删除。

      import (
          apierrors "k8s.io/apimachinery/pkg/api/errors"
          cachev1alpha1 "github.com/example-inc/memcached-operator/pkg/apis/cache/v1alpha1"
          ...
      )
      func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Result, error) {
          // Fetch the Memcached instance
      	instance := &cachev1alpha1.Memcached{}
          err := r.client.Get(context.TODO()
          request.NamespacedName, instance)
          if err != nil {
              if apierrors.IsNotFound(err) {
                  // Request object not found, could have been deleted after reconcile request.
                  // Owned objects are automatically garbage collected.
                  // Return and don't requeue
                  return reconcile.Result{}, nil
              }
              // Error reading the object - requeue the request.
              return reconcile.Result{}, err
          }
      
          // Rest of your reconcile code goes here.
          ...
      }
    2. 更改协调代码中的返回值:

      1. return err 替换为 return reconcile.Result{}, err
      2. return nil 替换为 return reconcile.Result{}, nil
    3. 要定期协调控制器中的 CR,您可以为 reconcile.Result 设置 RequeueAfter 字段。这会导致控制器重新排队 Request,并在所需持续时间后触发协调。请注意,默认值 0 表示没有重新队列。

      reconcilePeriod := 30 * time.Second
      reconcileResult := reconcile.Result{RequeueAfter: reconcilePeriod}
      ...
      
      // Update the status
      err := r.client.Update(context.TODO(), memcached)
      if err != nil {
          log.Printf("failed to update memcached status: %v", err)
          return reconcileResult, err
      }
      return reconcileResult, nil
    4. 将对 SDK 客户端的调用 (Create, Update, Delete, Get, List) 替换为协调器的客户端。

      如需了解更多详细信息,请参阅 operator-sdk 项目中的 controller-runtime客户端 API 文档 示例:

      // Create
      dep := &appsv1.Deployment{...}
      err := sdk.Create(dep)
      // v0.0.1
      err := r.client.Create(context.TODO(), dep)
      
      // Update
      err := sdk.Update(dep)
      // v0.0.1
      err := r.client.Update(context.TODO(), dep)
      
      // Delete
      err := sdk.Delete(dep)
      // v0.0.1
      err := r.client.Delete(context.TODO(), dep)
      
      // List
      podList := &corev1.PodList{}
      labelSelector := labels.SelectorFromSet(labelsForMemcached(memcached.Name))
      listOps := &metav1.ListOptions{LabelSelector: labelSelector}
      err := sdk.List(memcached.Namespace, podList, sdk.WithListOptions(listOps))
      // v0.1.0
      listOps := &client.ListOptions{Namespace: memcached.Namespace, LabelSelector: labelSelector}
      err := r.client.List(context.TODO(), listOps, podList)
      
      // Get
      dep := &appsv1.Deployment{APIVersion: "apps/v1", Kind: "Deployment", Name: name, Namespace: namespace}
      err := sdk.Get(dep)
      // v0.1.0
      dep := &appsv1.Deployment{}
      err = r.client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: namespace}, dep)
    5. 将您的 Handler 结构中的任何其他字段复制到 Reconcile<Kind> 中并初始它们:

      // newReconciler returns a new reconcile.Reconciler
      func newReconciler(mgr manager.Manager) reconcile.Reconciler {
      	return &ReconcileMemcached{client: mgr.GetClient(), scheme: mgr.GetScheme(), foo: "bar"}
      }
      
      // ReconcileMemcached reconciles a Memcached object
      type ReconcileMemcached struct {
          client client.Client
          scheme *runtime.Scheme
          // Other fields
          foo string
      }
  3. Copy changes from main.go.

    cmd/manager/main.go 中 v0.1.0 Operator 的主要功能设置 Manager,它将注册自定义资源并启动所有控制器。

    因为逻辑已在控制器中定义,所以现在不需要从旧的 main.go 中迁移 SDK 函数 sdk.Watch(),sdk.Handle(), 和 sdk.Run()

    但是,如果在旧的 main.go 文件中定义了任何特定于 Operator 的标记或设置,则需要复制它们。

    如果您使用 SDK 的方案注册了任何第三方资源类型,请参阅 operator-sdk 项目中的 高级主题,了解如何使用新项目中的 Manager 方案注册。

  4. 复制用户定义的文件。

    如果较旧的项目中有任何用户定义的 pkgs、脚本或文档,请将这些文件复制到新项目中。

  5. 将更改复制到部署清单。

    对于对旧项目中以下清单所做的任何更新,请将更改复制到新项目中的对应文件。请注意,不要直接覆盖文件,而是检查并进行必要的更改:

    • tmp/build/Dockerfilebuild/Dockerfile

      • 在新项目的布局中没有 tmp 目录
    • RBAC 规则从 deploy/rbac.yaml 更新至 deploy/role.yamldeploy/role_binding.yaml
    • deploy/cr.yamldeploy/crds/<group>_<version>_<kind>_cr.yaml
    • deploy/crd.yamldeploy/crds/<group>_<version>_<kind>_crd.yaml
  6. 复制用户定义的依赖项。

    对于添加到旧项目的 Gopkg.toml 的任何用户定义的依赖项,请复制它们并将其附加到新项目的 Gopkg.toml 中。运行 dep ensure 更新新项目中的供应商。

  7. 确认您的更改。

    构建并运行 Operator 以验证其是否正常工作。

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.