Operator FrameworkでKubernetesのAPIを拡張する方法


Kubebuilderについて説明し、Operator Frameworkを通じてKubernetes APIを拡張する方法を3つの主要なパートで紹介します。

著者:アリババのシニアエンジニアSuxing氏

この記事では、現在のプラクティスとユースケースに基づいて、Operator Frameworkを介してKubernetes APIを拡張する方法を紹介します。(1)Operatorの基礎、(2)Operator Frameworkの基礎と開発プロセスの事例、(3)Operatorの事例の3つのパートで構成されています。

1、オペレーターの概要

基本コンセプト

はじめに、今回の記事に関わる基本的な概念をご紹介します。

  • CustomResourceDefinition(CRD):Kubernetesのカスタムリソースの一種です。
  • Custom Resource(CR):特定のCRDインスタンス。
  • Webhook:Kubernetes APIサーバーに登録されたHTTPコールバックの一種。特定のイベントが発生すると、Kubernetes APIサーバーは登録されているWebhookを照会し、メッセージを転送します。

Webhookはmutating webhookとvalidation webhookに分けられます。Mutating webhookは入力オブジェクトを変更し、validating webhookは入力オブジェクトを読み取るだけです。

  • ワークキュー:コントローラの重要な構成要素。ワークキューは、クラスター内のリソースの変更を監視し、関連するオブジェクトをイベントとして、そのアクションとキー(ポッドのCreateアクションなど)を含めて保存します。
  • コントローラ:コントローラは、ワークキューを周期的に処理し、それぞれのロジックに従ってクラスタのステータスを期待されるステータスにプッシュします。コントローラの種類によって、実行される処理アクションが異なります。たとえば、ReplicaSetコントローラは、レプリカの数を監視し、Pod関連のイベントを処理します。
  • オペレーター:Kubernetesアプリケーションの記述、展開、管理に使用されるメカニズム。実装面では、ユーザーのビジネスロジックを実装するためのCRD、Webhook、コントローラを組み合わせたものがオペレーターとなります。

一般的なオペレーターモード

ワークフロー:

1、CRDを作成します。
2、Kubernetes APIサーバは、登録されたパスリストに基づいて、CRDリクエストをwebhookに転送します。
3、webhookはCRDのデフォルトパラメータ設定とパラメータチェックを完了します。その後、関連するCRがデータベースに書き込まれ、返却されます。
4、コントローラは、バックグラウンドでCRを監視し、ビジネスロジックに基づいてCR関連の特殊操作を処理します。
5、先行する処理により、クラスタのステータスが変化し、コントローラが監視し、CRDのステータスデータとして記録します。

Operatorのワークフローは高レベルで説明されていますが、後ほどケーススタディを通して詳細に説明します。

2、 Operator Frameworkの実践

Operator Frameworkの概要

まず初めに、Operator Frameworkの基本を説明します。Operator Frameworkは、Webhookとコントローラを提供し、一般的な基礎的な詳細を開発者からシールドすることで、メッセージ通知のトリガーや失敗時の再キューなどを実装することなく、マネージドアプリケーションのO&Mロジックの実装に集中することができます。

主流のOperator FrameworkにはKubebuilderとOperator SDKがあり、どちらもcontroller-toolsとcontroller-runtimeを使用しています。Kubebuilderは包括的なテスト、デプロイメント、コードの足場を提供し、一方Operator SDKはAnsible Operatorsと上位層のオペレーションをよりよくサポートします。

Kubebuilderの実践

このセクションでは、Alibaba CloudのオープンソースプロジェクトKruiseでSidercarSetsを介してKubebuilderを使用する方法を説明します。

SidercarSetsは、Sidecarコンテナ(セカンダリコンテナとも呼ばれる)をPodに挿入します。例えば、モニタリングやログ収集に使用するコンテナを挿入することで、Podの機能を充実させることができます。SidercarSetsは、挿入の状態とPodの状態に基づいて自身を更新し、セカンダリコンテナの状態を記録します。

ステップ1:初期化

手順は以下の通りです。GitLabプロジェクトを作成し、kubebuilder init --domain=kruise.ioコマンドを実行します。

パラメータの説明です。domainパラメータは、CRDオブジェクトの登録に使用するグループドメイン名を示します。

結果 依存関係にあるコードライブラリが引き出され、MakefileやDockerfileなどのツールファイルとともにコードフレームワークが作成されます。

以下は、作成された内容を簡略化したものです。

詳細は実際に確認してみてください。

ステップ2:APIの作成

手順:kubebuilder create api --group apps --version v1alpha1 --kind SidecarSet --namespace=falseコマンドを実行します。

このコマンドを実行すると、API(またはCRD)とともにコントローラフレームワークが作成されます。

パラメータの説明:

  • CRDのGroup: apps.kruise.ioは、groupパラメータとdomainパラメータで構成されています。
  • バージョンパラメータには、コミュニティスタンダードで指定された3つの値があります。

  • v1alpha1:このAPIは不安定です。CRDは廃棄される可能性があり、フィールドは調整される可能性があり、依存関係は必要ありません。

  • v1beta1: この API は安定しており、下位互換性があり、機能の調整が可能です。

  • v1: API と機能は安定しています。

  • kindパラメータは、コミュニティのネイティブサービスタイプと同様に、CRDタイプを示します。

  • namespacedパラメータは、CRDがグローバルに一意であるか、名前空間内で一意であるかを示し、これはnodeやpodの概念に似ています。

パラメータは大きく2種類に分けられます。group、version、kindの各パラメータは、CRDのメタデータの3つの重要な要素に対応しています。パラメータを設定する際には、こちらの一般的な基準を参考にしてください。namespacedパラメータは、CRDがグローバルにユニークであるか(nodeと同様)、名前空間内でユニークであるか(podと同様)を示しています。ここでは、namespaced を false に設定し、SidecarSet がグローバルにユニークであることを示しています。

結果:

CRDとコントローラフレームワークが作成された後、コードを記入します。

結果は以下のようになります。

青字の内容に注目してください。CRDはsidecarset_types.goで定義されており、これは手動で記入する必要があります。コントローラーはsidecarset_controller.goで定義されており、これも記入する必要があります。

ステップ3:CRD関連コードの入力

1、作成したCRDは、pkg/apis/apps/v1alpha1/sidecarset_types.goにあります。以下の2つの作業を行います。

(1)コメントの調整

コードジェネレータはコメントに依存してコードを生成するため、コメントを調整する必要がある場合があります。この例では、SidecarSetの以下のコメントを調整します。

+genclient:nonNamespaced: 非名前空間オブジェクトを作成します。

+kubebuilder:subresource:status: ステータスのサブリソースを作成します。

+kubebuilder:printcolumn:name=MATCHED,type=integer,JSONPath=.status.matchedPods,description=xxx: kubectl get sidecarset: 後ほど説明します。

(2)フィールドの設定

CRDを有効にするために、以下のフィールドを設定してください。

  • SidecarSetSpec: CRDに関する記述的な情報を入力します。
  • SidecarSetStatus:CRDのステータスを入力します。CRDのステータスを入力します。

2、 makeコマンドを実行してコードを生成します。

gRPCインターフェースの設定やコーデックなど、CRDの基本的なコントローラの実装を完了する必要はありません。

最終的なフィールドは以下の通りです。

SidecarSetsはSidecarをpodに注入するためのものです。左図のようにSidecarSetSpecにはSelectorとContainerが定義されています。SelectorはSidecarを注入するPodを示し、ContainersはSidecarのコンテナを定義します。

右図に示すように、SidecarSetStatus にはステータス情報が定義されています。MatchedPodsは、SidecarSetにマッチするポッドの数を示しており、UpdatedPodsは、Sidecarが注入されたポッドの数を示しています。ReadyPodsは、正常に動作しているPodの数を示します。

詳細については、このドキュメントを参照してください。

ステップ4:Webhookフレームワークの作成

1、以下のコマンドを実行して、2つのmutating webhookを作成します。

kubebuilder alpha webhook --group apps --version v1alpha1 --kind SidecarSet --type=mutating --operations=create
kubebuilder alpha webhook --group core --version v1 --kind Pod --type=mutating --operations=create

2、以下のコマンドを実行して、検証用のWebhookを作成します。

kubebuilder alpha webhook --group apps --version v1alpha1 --kind SidecarSet --type=validating --operations=create,update

パラメータの説明:

  • groupおよびkindパラメータは、処理対象となるリソースオブジェクトを示します。
  • typeパラメータは、作成されるフレームワークのタイプを示します。
  • operationsパラメータは、リソースオブジェクトに対する主要な操作を示します。

結果:

  • Webhook フレームワークが作成されます。コードは手動で入力する必要があります。

結果は以下のようになります。

青字の内容は、先の3つのコマンドを実行することで作成される3つのハンドラーを示しています。以下では、ハンドラーの設定方法を説明します。

ステップ5:Webhookの設定

作成されたWebhookハンドラは、以下の場所にあります。

  • pkg/webhook/default_server/sidecarset/mutating/xxx_handler.go
  • pkg/webhook/default_server/sidecarset/validating/xxx_handler.go
  • pkg/webhook/default_server/pod/mutating/xxx_handler.go

コードを以下のように書き換えるか、記入します。

  • 入力CRD以外のリソースが必要な場合は、Kubernetesクライアントをインジェクトします。本実施例では、SidecarSetが作成された後にSidecarがPodに注入されるため、Kubernetesクライアントを注入します。
  • mutatingSidecarSetFnまたはvalidatingSidecarSetFnでWebhookを設定します。リソースオブジェクトのポインタが渡された後、webhookの設定のためにobject属性を調整します。

最終的なコードは以下の通りです。

ステップ4では、SidecarSet mutating webhook、SidecarSet validating webhook、Pod mutating webhookの3つのwebhookを作成します。

前述の左図は、SidecarSet mutating webhookを示しています。デフォルトの設定はsetDefaultSidecarSetで完了します。

右図は、SidecarSetのフィールドをチェックするためのValidating webhookを示しています。

mutatingSidecarSetFnはデフォルト値を設定せず、setDefaultSidecarSetの値をフェッチし、その値をpodに注入します。

ステップ6:コントローラーの設定

作成したコントローラフレームワークは、pkg/controller/sidecarset/sidecarset_controller.goにあります。以下の修正を行います。

  • パーミッションのコメントを修正します。コントローラフレームワークは、//+kuberbuilder:rbac;groups=apps,resources=deployments/status,verbs=get;update;pathのようなコメントを自動的に作成します。必要に応じてコメントを修正し、ロールベースのアクセスコントロール(RBAC)ルールを作成します。
  • キューイングロジックを追加します。デフォルトのコードフレームワークでは、CRDのキューイングロジックを記入します。例えば、SidecarSetオブジェクトの追加、削除、修正のアクションは、ワークキューに追加されます。例えば、SidecarSetがポッドの変更を監視することを要求するなど、関連するリソースオブジェクトのトリガーメカニズムが必要な場合は、手動でキューイングロジックを追加します。
  • ビジネスロジックを入力します。Reconcile 関数を変更して、ワークキューを周期的に処理します。Reconcile 関数は、spec に基づいてビジネス・ロジックを実装し、ビジネス・ロジックの実装結果を status に返します。デフォルトでは、Reconcile関数から返されたエラーメッセージが再キューイングのトリガーとなります。

次の図は、SidecarSetコントローラの最終的なコードを示しています。

addPodは、PodにマッチしたSidecarSetを取得し、Reconcile関数による処理のためにキューに入れるために使用されます。

SidecarSetを取得した後、Reconcile機能はSelectorの設定に基づいてマッチしたPodを選択し、現在のPodのステータスに基づいてクラスターのステータスを計算し、それに応じてCRDのステータスを記入します。

3、SidecarSetのワークフロー

このセクションでは、Operatorの動作を理解するために、SidecarSetのワークフローをまとめます。

1、SidecarSetを作成します。
2、SidecarSet作成リクエストを受信した後、Webhookがデフォルト設定を完了し、設定内容を確認します。その後、SidecarSetはデータベースに保存され、あなたに返却されます。
3、Podを作成します。
4、webhookは対応するSidecarSetをフェッチし、コンテナを取得し、Podに注入します。そのため、データベースに格納されているときのSidecarがPodに含まれています。
5、コントローラはバックグラウンドで常にポーリングを行い、クラスターの状態変化を監視します。ステップ4のインジェクションにより、SidecarSetのキューイングが開始されます。コントローラは、SidecarSetのUpdatedPodsに1を追加します。

以上のプロセスは、SidecarSetの簡単な実装です。

追加情報です。一般的に、webhookはコントローラを介してビジネスロジックを実装し、ステータスを更新します。ただし、コントローラがオプションになっている場合もあります。前述の例では、コントローラを介さずに webhook が主要なビジネスロジックを実装しています。

4. まとめ

この記事で学んだことをまとめてみましょう。

  • オペレータは、CRD、Webhook、コントローラと組み合わせて、Kubernetesでユーザーのビジネスロジックを拡張するために使用されます。
  • Kubebuilderは公式に標準化されたOperatorフレームワークであり、コミュニティで高く評価されています。
  • この記事で紹介されている手順に基づいて、カスタムコードでOperatorを実装することができます。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ