5.17. Operator SDK v0.1.0 への移行


以下では、Operator SDK v0.0.x を使用してビルドされた Operator プロジェクトを Operator SDK v0.1.0 で必要なプロジェクト構造に移行する方法を説明します。

重要

Operator プロジェクトの関連スキャフォールディングおよびテストツールなど、Red Hat がサポートするバージョンの Operator SDK CLI ツールは非推奨となり、OpenShift Dedicated の今後のリリースで削除される予定です。Red Hat は、現在のリリースライフサイクル中にこの機能のバグ修正とサポートを提供しますが、この機能は今後、機能拡張の提供はなく、OpenShift Dedicated リリースから削除されます。

新しい Operator プロジェクトを作成する場合、Red Hat がサポートするバージョンの 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 を説明されているように新規プロジェクトを変更します。

ここでは、Operator SDK のサンプルプロジェクトである memcached-operator を使用して、移行手順を説明します。移行前および移行後のそれぞれの例については、v0.0.7 memcached-operator および v0.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. カスタムタイプのスキャフォールディング 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 ファイルの Spec および Status の内容を、古いプロジェクトから新規プロジェクトの pkg/apis/<group>/<version>/<kind>_types.go ファイルにコピーします。
    2. それぞれの <kind>_types.go ファイルには init() 関数があります。これはこのタイプを Manager のスキームに登録するために使用されるため、削除しないでください。

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

5.17.3. 調整 (reconcile) コードの移行

プロジェクトの調整コードを更新 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 プロジェクトの場合、コントローラー を定義してリソースを監視する必要があります。

    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{},
      	})
      }

      2 つ目の Watch() を削除するか、またはこれを CR が所有する 2 つ目のリソースタイプを監視するように変更します。

      複数のリソースを監視すると、アプリケーションに関連する複数リソースの調整ループ (reconcile loop) をトリガーできます。詳細は、監視および eventhandling に関するドキュメントおよび 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 から調整コード (reconcile code) をコピーし、変更します。

    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

    sdk.Event (オブジェクトを含む) を受信する代わりに、Reconcile() 関数は Request (Name/Namespace キー) を受信してオブジェクトを検索します。

    Reconcile() 関数がエラーを返すと、コントローラーは Request を再度キューに入れ、再試行します。エラーが返されない場合は、Result に応じて、コントローラーは Request を再試行しないか、即時に再試行するか、または指定された期間後に再試行します。

    1. 古いプロジェクトの Handle() 関数のコードを、コントローラーの Reconcile() 関数の既存のコードにコピーします。Request のオブジェクトを検索し、これが削除されているかどうかをチェックする Reconcile() コードの最初のセクションを保持するようにします。

      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 errreturn reconcile.Result{}, err に置き換えます。
      2. return nilreturn reconcile.Result{}, nil に置き換えます。
    3. コントローラーで CR を定期的に調整するには、reconcile.ResultRequeueAfter フィールドを設定します。これにより、コントローラーは 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) を reconciler のクライアントに置き換えます。

      詳細は、以下の例および 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. main.go からの変更をコピーします。

    cmd/manager/main.go の v0.1.0 Operator の main 関数が、カスタムリソースを登録し、すべてのコントローラーを起動する Manager をセットアップします。

    ロジックがコントローラーに定義されているため、SDK 関数 sdk.Watch()sdk.Handle()、および sdk.Run() を古い main.go から移行する必要はありません。

    ただし、古い main.go ファイルに Operator 固有のフラグまたは設定が定義されている場合は、それらをコピーします。

    SDK のスキームに登録されているサードパーティーのリソースタイプがある場合、operator-sdk プロジェクトの Advanced Topics を参照し、それを新しいプロジェクトの Manager のスキームに登録する方法を確認してください。

  4. ユーザー定義ファイルをコピーします。

    古いプロジェクトにユーザー定義の pkg、スクリプト、またはドキュメントがある場合は、それらのファイルを新しいプロジェクトにコピーします。

  5. デプロイメントマニフェストへの変更をコピーします。

    古いプロジェクトの次のマニフェストに加えられた更新がある場合は、その変更を新しいプロジェクトの対応するファイルにコピーします。ファイルを直接上書きせずに、必要な変更を検査し、その変更を加えるようにしてください。

    • tmp/build/Dockerfile から build/Dockerfile

      • 新規プロジェクトのレイアウトには tmp ディレクトリーはありません。
    • RBAC ルールは deploy/rbac.yaml から deploy/role.yaml および deploy/role_binding.yaml に更新されます。
    • deploy/cr.yaml から deploy/crds/<group>_<version>_<kind>_cr.yaml
    • deploy/crd.yaml から deploy/crds/<group>_<version>_<kind>_crd.yaml
  6. ユーザー定義の依存関係をコピーします。

    古いプロジェクトの Gopkg.toml に追加されたユーザー定義の依存関係がある場合は、それをコピーして新しいプロジェクトの Gopkg.toml に追加します。dep ensure を実行し、新規プロジェクトのベンダーを更新します。

  7. 変更を確認します。

    Operator をビルドして実行し、動作することを確認します。

Red Hat logoGithubRedditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

© 2024 Red Hat, Inc.