Oracle Cloud Hangout Cafe Season5 #1「Kubernetes Operator 超入門」(2022年1月19日開催)
●STEP1:プロジェクトの作成
まずは、プロジェクトを作成します。
プロジェクトを作成するにはoperator init
コマンドを利用します。この際に、CRの"apiVersion"の一部になる--domain
オプションと、必要に応じてGitHubリポジトリを指定する--repo
オプションを付与します。今回は適当なGitHubリポジトリを付与します。
次に、APIを作成します。APIを作成することで、プロジェクト内に様々なボイラープレートコード*2が作成されます。この際にCRの"apiVersion"の一部になる--group
オプション、CRの"Kind"(=Operatorの操作対象)になる--kind
オプション、OperatorやManifestのボイラープレートコードの自動生成フラグである--controller --resource
を付与します。
*2:ボイラープレートコード : 定型的なソースコードのことで、ここでは雛形となるソースコードやManifestです。
実は、これらのコマンドの裏ではapimachinery
やcontroller-tools
、controller-gen
などが利用されており、その様子がコマンドを実行した際の標準出力ログから以下のように確認できます。
[root@ocha]$ operator-sdk init --domain oracle.com --repo github.com/oracle-japan/ochacafe-operator-intro Writing kustomize manifests for you to edit... Writing scaffold for you to edit... Get controller runtime: $ go get sigs.k8s.io/controller-runtime@v0.13.0 go: downloading sigs.k8s.io/controller-runtime v0.13.0 go: downloading k8s.io/apimachinery v0.25.0 ~~~~~ go: downloading github.com/benbjohnson/clock v1.1.0 Next: define a resource with: $ operator-sdk create api
[root@ocha]$ operator-sdk create api --group ochacafe --version v1alpha1 --kind Ochacafe --controller --resource ~~~~~ test -s /home/ochacafe/ochacafe-operator-intro/bin/controller-gen || GOBIN=/home/ochacafe/ochacafe-operator-intro/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.10.0 go: downloading sigs.k8s.io/controller-tools v0.10.0 ~~~~~ /home/ochacafe/ochacafe-operator-intro/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..." Next: implement your new API and generate the manifests (e.g. CRDs,CRs) with: $ make manifests [root@instance-20230213-1423 test]#
この時点でのディレクトリ構成を確認します。全ては紹介できないので、一部を抜粋して説明します。
. ├── api ==> APIリソース(CR)の定義。Kind毎に生成。Manifestのフィールド定義とも言える │ └── v1alpha1 │ ├── groupversion_info.go │ ├── ochacafe_types.go │ └── zz_generated.deepcopy.go ├── bin │ └── controller-gen ==> 各種コマンド実行時に利用される`controller-gen`バイナリ ├── config ==> 各種Manifestファイル。ソースコードのアノテーションを元に生成(controller-toolsが生成) │ ├── crd │ ├── default │ ・ │ ・ │ ・ ├── controllers ==> Operatorの実装部分。テンプレートをもとに実装(controller-runtimeを利用) │ ├── ochacafe_controller.go │ └── suite_test.go ├── Dockerfile ==> OperatorをコンテナとしてビルドするためのDockerfile ├── Makefile ├── PROJECT └── README.md 17 directories, 43 files
●STEP2:CRの実装
ここからは、実装に入っていきます。まずは、CRを実装します。編集するファイルは
- ユーザが定義するOchacafeリソースの
size
フィールド - Operatorが追記するPodがスケジューリングされたNode名(
kubectl describe
時にスケジューリングしたNode名を確認可能にするため)
実際のコードは、下図の通りです。
これでCRの実装は完了ですが、ここで以下の2つのコマンドを実行します。
./make generate ./make manifests
前者のコマンドはbin/controller-gen
を呼び出し、api/v1/zz_generated.deepcopy.go
を更新します。このファイルには、Operatorが実装する必要のあるインタフェースが実装されていますが、これを自動的に更新します。
後者のコマンドはbin/controller-gen
を呼び出し、config/crd/bases/ochacafe.oracle.com_ochacafe.yaml
を自動生成します。これは、実装したCRに基づいたCRDを生成します。
ここまでの作業の全体イメージは下図の通りです。
●STEP3:RBACの実装
ここでは、RBACの実装を進めます。OperatorはKubernetesのリソースを操作できなくてはなりません。今回で言えば、標準リソースであるDeployment/Podを操作できる必要があります。そのため、ここではRBACを実装します。
とは言っても、何かしらのロジックを実装するわけではなく、Operatorのロジックを実装する箇所にアノテーションで付与したいRBACを定義するだけで実装できます。
ここでは、Deployment/に対するフル権限(get
/list
/watch
/create
/update
/patch
/delete
)、Podに対する参照権限(get
/list
/watch
)を付与します。
編集するファイルはcontrollers/ochacafe_controller.go
です。
このようにRBACを定義したら、先ほどと同様にmake manifests
コマンドを実行します。これにより、config/rbac/role.yaml
に定義されているOperatorのRBAC定義が更新されます。
ちなみに、追記した行を見ると//+kubebuilder:rbac:~
となっていることが分かります。ここにOperator SDKとKubebuilderが統合されている様子が垣間見えます。
ここまでの作業の全体イメージは下図の通りです。
●STEP4:Operatorの実装
ここでは、Operator本体の処理を実装します。なお、この実装について詳細を書くことは難しいので、Operatorで実装すべき入出力パラメーターと実装時の注意点だけ整理しておきます。
・Operatorで実装すべき入出力パラメーター
Operatorで実装すべき入出力パラメーターは、以下の通りです。
内容 | 説明 |
---|---|
入力 | Context(goroutine(スレッド)*3を扱うための情報) / Request(CRに関する情報など) |
出力 | Result(処理結果) / error(エラー情報)| Result.Requeue / Result.RequeueAfterというフィールドに再キューイング要否と遅延時間をそれぞれ指定。正常終了時はerror=nil、異常終了時はerror=Exception情報 |
*3:goroutine : Golangで利用される軽量スレッドです。
入出力のみ実装すると、下図になります。
・Operator実装時に注意すべきこと
補足として、Operator実装時に注意すべき点をまとめます。ここで取り上げるポイントは2点です。
- 結果が必ず収束するように実装
- 処理内で待機したり、時間のかかる処理を実装しない
前者については、Kubernetesで重要なコンセプトである"宣言的オペレーション"に準拠するにはOperatorの処理結果をべき等にすることが必須です。エラーになったとしても、もう一度処理を呼び出した時に必ずリカバリできるようにしておくことが重要です。エラー発生時には前述した出力パラメーターのResult.Requeue
をtrue
に設定すれば再実行されます。
後者については、リソースの状態が変化するまで待機したり、時間がかかる処理を実装するとスケーラブルなOperatorにならず、また大量のリソースを取得するような実装はAPI Serverの負荷を高めることにもつながります。時間のかかる処理や待機が必要な場合はスレッド(goroutineで実行)にし、Result.RequeueAfter
に待機時間を指定するか、キャッシュを上手く活用してAPI Serverへの不必要なアクセスは行わないようにしましょう。
Operator実装時の注意点については、非常に詳しく解説された資料と動画が公開されています。
- Kubernetesオペレータのアンチパターン&ベストプラクティス
2021年11月に開催された「CloudNative Days Tokyo 2021」で発表された資料です。動画も公開されています。
上記のOperatorのソースコードは、こちらのリポジトリで公開しています。必要に応じて確認してください。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- CNDO2021、Kubernetesの運用ツールOperatorを作るチュートリアルセッションを紹介
- Rancherを構成するソフトウェア
- KubeCon China:恒例の失敗談トークはスナップショットの実装について
- Kubeflowを構築する
- NGINX Ingress Controllerの柔軟なアプリケーション制御、具体的なユースケースと設定方法を理解する
- Oracle Cloud Hangout Cafe Season 4 #5「Kubernetesのオートスケーリング」(2021年8月4日開催)
- CI/CDを使ってみよう
- Pulumi Kubernetes Operatorを活用してPulumiのCI/CDを実現しよう
- Rancherコードリーディング入門(1/3)
- 「K8sGPT」の未来と生成AIを用いたKubernetes運用の最前線