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) を参照してください。
プロジェクトの移行で推奨される方法は、以下の通りです。
- 新規 v0.1.0 プロジェクトを初期化します。
- コードを新規プロジェクトにコピーします。
- 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
プロジェクト
手順
SDK バージョンが v0.1.0 であることを確認します。
$ operator-sdk --version operator-sdk version 0.1.0
新しいプロジェクトを作成します。
$ 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
古いプロジェクトから
.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 を使用して作成される新規プロジェクト
手順
カスタムタイプのスキャフォールディング API を作成します。
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
-
古いプロジェクトで定義したカスタムタイプについて、直前のコマンドを繰り返します。それぞれのタイプはファイル
pkg/apis/<group>/<version>/<kind>_types.go
に定義されます。
タイプの内容をコピーします。
-
pkg/apis/<group>/<version>/types.go
ファイルのSpec
およびStatus
の内容を、古いプロジェクトから新規プロジェクトのpkg/apis/<group>/<version>/<kind>_types.go
ファイルにコピーします。 それぞれの
<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/
からの移行
手順
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 プロジェクトの場合、コントローラー を定義してリソースを監視する必要があります。
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
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{})
pkg/stub/handler.go
から調整コード (reconcile code) をコピーし、変更します。v0.1.0 プロジェクトでは、調整コードはコントローラーの Reconciler の
Reconcile()
メソッドで定義されます。これは、古いプロジェクトの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
を再試行しないか、即時に再試行するか、または指定された期間後に再試行します。古いプロジェクトの
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. ... }
調整コードの戻り値を変更します。
-
return err
をreturn reconcile.Result{}, err
に置き換えます。 -
return nil
をreturn reconcile.Result{}, nil
に置き換えます。
-
コントローラーで 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
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)
他のフィールドを
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 }
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 のスキームに登録する方法を確認してください。ユーザー定義ファイルをコピーします。
古いプロジェクトにユーザー定義の
pkg
、スクリプト、またはドキュメントがある場合は、それらのファイルを新しいプロジェクトにコピーします。デプロイメントマニフェストへの変更をコピーします。
古いプロジェクトの次のマニフェストに加えられた更新がある場合は、その変更を新しいプロジェクトの対応するファイルにコピーします。ファイルを直接上書きせずに、必要な変更を検査し、その変更を加えるようにしてください。
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
へ
ユーザー定義の依存関係をコピーします。
古いプロジェクトの
Gopkg.toml
に追加されたユーザー定義の依存関係がある場合は、それをコピーして新しいプロジェクトのGopkg.toml
に追加します。dep ensure
を実行し、新規プロジェクトのベンダーを更新します。変更を確認します。
Operator をビルドして実行し、動作することを確認します。