Slide 1

Slide 1 text

controller-runtime Deep Dive Kubernetes Meetup Tokyo #53 (2022/10/06) @bells17

Slide 2

Slide 2 text

▶ @bells17 ▶ Software Engineer ▶ 普段やってること: + Kubernetes 関連コンポーネントの開発 + Kubernetes as a Service開発 + 社内におけるKubernetes普及活動 ▶ Kubernetes SIG-Docs Japanese localization reviewer ▶ Kubernetes Internal Organizer ▶ #kubenews ▶ @bells17_

Slide 3

Slide 3 text

#kubenews 隔週⾦曜22:00~YouTubeで配信中 Kubernetes/Cloud Native関連のニュースを中⼼に技術雑談してます

Slide 4

Slide 4 text

このセッションについて ▶ セッションを聴いてわかること + controller-runtimeのアーキテクチャ + controller-runtimeの内部実装 + controller-runtimeのtips ▶ このセッションの⽬的 + 既存のドキュメントではあまり解説されていないcontroller-runtimeのアーキテクチャや内部実装、tipsなどを まとめること + controller-runtimeの内部実装を把握することで開発者がcontroller-runtimeを拡張するための基礎知識を 
 まとめること ▶ 対象とする視聴者 + controller-runtimeを使ってアプリケーションを開発する⼈ + Kubernetes関連アプリケーションのアーキテクチャや内部実装に興味のある⼈ ▶ 視聴者に要求する前提知識 + controller-runtimeの概要や基礎知識

Slide 5

Slide 5 text

注意点 ▶ 対象バージョン: controller-runtime v0.12.3 + https://github.com/kubernetes-sigs/controller-runtime/tree/v0.12.3 ▶ あくまでcontroller-runtimeの実装を追った結果での理解の説明になるので、 
 間違いが含まれている可能性があります ▶ 引⽤しているコードはスライドにうまく収めるため省略、⼀部書き換えを 
 ⾏っている箇所があります

Slide 6

Slide 6 text

controller-runtimeとは?

Slide 7

Slide 7 text

controller-runtime ▶ Kubernetesの以下のようなアプリケーションを構築するためのフレームワーク + Kubernetes Operator(CRD+Controller) + Webhook Server(Validating/Mutating/Conversion) + その他k8s clientなどを使⽤したKubernetes向けアプリケーション ▶ client-go単体で使うよりも便利なので、Kubernetesに関するアプリケーションを構築するときには 
 とりあえずcontroller-runtimeを使っておけばOK(拡張API Serverなど⼀部ケースでは向いてない) ▶ kubebuilder/operator-sdkなどのフレームワークの内部で利⽤されている ▶ 上記のフレームワークを使わずに、controller-runtime単体での使⽤も可能 ▶ 以下のようなKubernetesを使ったアプリケーション構築に必要なものが⼀通り 
 含まれている + Controller実⾏を含めたrunnerの管理機能 + Webhook Server + Prometheus Server + cache機能付きk8s clientの提供 + e2eテスト環境構築ツール(envtest)

Slide 8

Slide 8 text

controller-runtimeの利⽤例 ▶ aws-load-balancer-controller(Ingress Controller for AWS): https:// github.com/kubernetes-sigs/aws-load-balancer-controller ▶ kueue(Job Queueing): https://github.com/kubernetes-sigs/kueue ▶ topolvm(CSI Driver for LVM): https://github.com/topolvm/topolvm ▶ moco(MySQL Operator): https://github.com/cybozu-go/moco ▶ logging-operator: https://github.com/banzaicloud/logging-operator ▶ istio(Service Mesh): https://github.com/istio/istio ▶ etc …

Slide 9

Slide 9 text

controller-runtimeの使い⽅を学ぶ ▶ controller-runtime(kubebuilder)の使い⽅については以下のような充実した 
 ドキュメントが公開されている + Kubebuilder Book + つくって学ぶKubebuilder + Ginkgo/GomegaによるKubernetes Operatorのテスト⼿法 ▶ controller-runtimeについて詳しく知りたい⽅は上記ドキュメントと合わせて このセッション資料を⾒てもらえると

Slide 10

Slide 10 text

controller-runtimeのアーキテクチャ

Slide 11

Slide 11 text

controller-runtime architecture overview 画像はKubebuilder Book( https://book.kubebuilder.io/architecture.html ) より引⽤ ▶ Manager: 
 実⾏する各種runnerやclientなどを管理 ▶ Client & Cache: 
 client-goをベースにしたcache機能付きの 
 独⾃k8s clientを提供 ▶ Controller: 
 ユーザーが実装したReconcilerを実⾏ ▶ Webhook: 
 ユーザー定義に基づくWebhook Serverを 
 実⾏ ※ runner: 「各種Controller/Serverなどを含めたManagerが管理 する処理の実⾏単位」くらいに考えてもらえればOK ユーザー独⾃のrunnerを実⾏することも可能

Slide 12

Slide 12 text

Reconciler & Controller

Slide 13

Slide 13 text

kubebuilderでControllerを⽣成すると $ kubebuilder create api --group sample-operator --version v1beta1 --kind Sample Create Resource [y/n] y Create Controller [y/n] y

Slide 14

Slide 14 text

CRDが⽣成され // SampleSpec defines the desired state of Sample type SampleSpec struct { Message string `json:"message,omitempty"` } // SampleStatus defines the observed state of Sample type SampleStatus struct { Message string `json:"message,omitempty"` } // Sample is the Schema for the samples API type Sample struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` Spec SampleSpec `json:"spec,omitempty"` Status SampleStatus `json:"status,omitempty"` }

Slide 15

Slide 15 text

Reconcilerが⽣成されて // SampleReconciler reconciles a Sample object type SampleReconciler struct { client.Client Scheme *runtime.Scheme } // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. func (r *SampleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { _ = log.FromContext(ctx) // TODO(user): your logic here return ctrl.Result{}, nil } // SetupWithManager sets up the controller with the Manager. func (r *SampleReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&sampleoperatorv1beta1.Sample{}). Complete(r) }

Slide 16

Slide 16 text

main.goのコードが⾃動でアップデートされる func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(sampleoperatorv1beta1.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme } func main() { … if err = (&controllers.SampleReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Sample") os.Exit(1) } //+kubebuilder:scaffold:builder }

Slide 17

Slide 17 text

controllerの登録と実⾏の流れ

Slide 18

Slide 18 text

controller登録の流れ ▶ Controllerを⽣成してmgr.Add()でManagerのrunnerに登録 ▶ 対象リソースの変更監視を設定: SharedInformerのEventHandlerを追加 ▶ controller-runtime Managerの起動時にControllerを起動

Slide 19

Slide 19 text

controller実⾏の流れ ▶ SharedInformerがKube API Serverから対象リソースをList & Watchで監視 ▶ 対象リソースの変更時に登録したEventHandlerでイベントを受信 ▶ 受信したイベントをPredicatesでフィルタリング ▶ フィルタリングしたイベントをEventHandlerでWorkQueueのイベントに変換 ▶ ControllerがWorkQueueに溜まっているイベントを元にReconcilerを実⾏

Slide 20

Slide 20 text

Reconciler & Controllerまとめ ▶ Reconciler: controller-runtimeを使って開発者が実装する調整ループの中⾝ ▶ Controller: 作成したReconcilerやPredicateなどの設定を元にcontroller-runtimeが ⽣成~実⾏制御を⾏うもの ▶ Controllerの起動はmgr.Add()によってManagerに管理される controller-runtimeにおいては開発者が実装するのはReconcilerとControllerの設定のみ Controller本体はcontroller-runtimeが⽣成や管理を⾏ってくれる

Slide 21

Slide 21 text

Managerについて

Slide 22

Slide 22 text

Manager(controller-runtime) overview

Slide 23

Slide 23 text

Manager(controller-runtime)の全体像 ▶ Managerを通してアプリケーション全体を管理するのでManager=controller-runtimeと思ってもらってOK ▶ ManagerはRunnerという仕組みを中⼼成り⽴っている ▶ Runnerの登録はmgr.Add()というメソッドで⾏うことができる ▶ Runner: Runnableというinterfaceを満たす実装を予め登録しておき、Manager起動時に登録した実装を実 ⾏する機能 ▶ Runnerの種類: Runnerはどのようなinterfaceを満たすかに応じて4種類に分類される + Webhooks: Webhookサーバーへのhandlerの登録処理を⾏う + Caches: Informerの起動を⾏う + LeaderElections: LeaderElectionでリーダー選出された際のみ実⾏されるRunner + Others: LeaderElectionによるリーダー選出に関わらず実⾏されるRunner ▶ 以下のServerはRunnerとは独⽴して実⾏される + Metric Server: controller-runtimeのメトリクスを取得するためのprometheus server + Health Prove Server: 任意のcheckerを設定できるヘルスチェック⽤サーバー

Slide 24

Slide 24 text

Webhook Runners ▶ Webhook Runnerは基本的にmgr.GetWebhookServer()によってWebhook Serverを⽣成 したときのみに設定されるRunner種別 ▶ Webhook ServerはRunnerの仕組みを通して起動される ▶ Webhook ServerにはCertWatcherという機能があり、SSL証明書ファイルが更新された 際に⾃動でリロードする仕組みが提供されている

Slide 25

Slide 25 text

Cache Runners ▶ Cache Runnersは基本的にManagerが内部で⽣成するclusterオブジェクトのみに設定 されるRunner種別 ▶ 設定したInformerを起動しKube API Serverからのリソース監視処理を開始するために 利⽤される

Slide 26

Slide 26 text

LeaderElection Runners ▶ LeaderElectionでリーダー選出された際にのみ実⾏されるRunner ▶ Runnerはデフォルトでこの種類のRunnerとして実⾏される ▶ LeaderElectionでリーダー選出された際に実⾏されるため、この種別のRunnerが起動 されるのはManagerの起動時(mgr.Start()を呼び出したとき)ではなく、Leader選出され た際になる

Slide 27

Slide 27 text

Other Runners ▶ LeaderElectionによるリーダー選出に関わらず実⾏されるRunner ▶ この種類のRunnerとして登録したい場合は、NeedLeaderElectionメソッドを実装し、 このメソッドでfalseを返すようにする必要がある

Slide 28

Slide 28 text

Metric Server ▶ Metrics Serverはcontroller-runtimeのメトリクスを設定されたPrometheus Server ▶ そのためmetrics.Registry.MustRegisterを呼び出し、このMetrics Serverに 
 カスタムメトリクスを設定することができる

Slide 29

Slide 29 text

Health Probe Server ▶ Health Probe Serverはヘルスチェック⽤のHTTPサーバー ▶ `/healthz`と`/readyz`の2つのヘルスチェック⽤のエンドポイントを提供している ▶ ヘルスチェック処理は予め登録したcheckerによるチェックをパスしたかどうかで判定 される仕組みになっている ▶ このcheckerはそれぞれ、AddHealthzCheckとAddReadyzCheckという2つメソッドに よって登録することができるようになっている

Slide 30

Slide 30 text

Manager(controller-runtime)まとめ ▶ ManagerはRunnerという仕組みを中⼼成り⽴っていて、Manager起動時にRunnerとし て登録したアプリケーション群の実⾏を⾏う仕組みになっている ▶ Runnerには4つ種類がある ▶ Runnerの内、LeaderElectionsはManager起動後、Leader選出された際に実⾏される ▶ その他のRunnerはManager起動時に実⾏される ▶ Metric ServerとHealth Probe ServerはRunnerとは独⽴した仕組みで実⾏される

Slide 31

Slide 31 text

k8s client

Slide 32

Slide 32 text

k8s client ▶ controller-runtimeではclient-goをベースとした3種類のk8s clientが提供されている ▶ k8s clientの種類は以下の通り + Delegating Client: 読み取り系の処理時にCache clientを利⽤するクライアント + Cache Client: Informerを通したローカルキャッシュからデータ取得を⾏う 
 reader + API Reader: キャッシュを使⽤せず都度API Serverにリクエストを送りデータ取得を⾏ うreader ▶ そのため基本的には以下のようにclientを使い分けておけばOK + Delegating Client: 特に理由がなければこのクライアントを利⽤する + API Reader: 最新のデータ取得を確実に⾏いたい際に利⽤ + Cache Client: Delegating Client内部で使⽤されているので基本的に利⽤する必要無し

Slide 33

Slide 33 text

Delegating ClientとCache Clientはオプションから独⾃クライアントを 使⽤可能 func main() { mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ NewCache: cache.New, NewClient: cluster.DefaultNewClient, … }) if err != nil { setupLog.Error(err, "unable to start manager") os.Exit(1) } } ※ API Readerについては独⾃クライアントへの上書きはできない

Slide 34

Slide 34 text

各clientは以下のように取得することが可能 mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{}) if err != nil { setupLog.Error(err, "unable to start manager") os.Exit(1) } delegatedClient := mgr.GetClient() cache := mgr.GetCache() apireader := mgr.GetAPIReader()

Slide 35

Slide 35 text

client-go overview 画像引⽤元: https://github.com/kubernetes/sample-controller/blob/v0.25.0/docs/images/client-go-controller-interaction.jpeg ▶ Re fl ector: API Serverから指定リソースをList & Watch で取得 & 以降の変更を監視 ▶ Delta Fifo queue: Re fl actorが取得したデータをqueue として格納 ▶ Informer: Delta Fifo queueからデータを取り出して 1. データをIndexerへと渡す 2. Informerに設定された各EventHandlerを呼び出す ▶ Indexer: 渡されたデータをインメモリにキャッシュ 
 (structのmapにデータを設定するだけ) Kubernetes ControllerはInformerのEventHandlerに 
 それぞれのhandlerを設定することでイベント受信して 
 動作するよう振る舞うが、ここではclientがメインなので 以降の流れは省略

Slide 36

Slide 36 text

controller-runtime client overview ▶ Delegating Client: 
 Cache ClientをReaderとして 
 Default ClientをWriterとしてそれぞれ使⽤ ▶ Cache Client: リソースごとの各SharedInformerを 
 データソースとしてデータを取得するクライアント ▶ Base Client: 
 Delegating ClientのWriterとして使⽤される 
 内部クライアント 
 API ReaderはこのBase ClientをReaderとして使⽤ したもの(structとしては同じもの) ▶ Rest Client: 
 実際にAPI Serverにhttp(s) requestを送るclient

Slide 37

Slide 37 text

controller-runtime object controller-runtimeのclientは内部で更に3種類のclientを保持している 
 これらのclientを渡されたObjectに応じて⾃動で使い分ける仕組みになっている

Slide 38

Slide 38 text

clientに渡すObjectに応じて内部clientは⾃動で切り替わる client := mgr.GetClient() // use structured client podList := corev1.PodList{} err := client.List(ctx, podList) // use unstructured client uList := unstructured.UnstructuredList{} uList.SetGroupVersionKind(corev1.GroupVersion.WithKind("PodList")) err := client.List(ctx, podList) // use metadata client pList := metav1.PartialObjectMetadataList{} pList.SetGroupVersionKind(corev1.GroupVersion.WithKind("PodList")) err := client.List(ctx, podList)

Slide 39

Slide 39 text

k8s client object ▶ Structured: PodやPodListなどの各リソースごとのstruct ▶ Unstructured: "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" にある以下のstruct + Unstructured: Podなどのリソース単体向けに使⽤ + UnstructuredList: PodListなどのListリソース向けに使⽤ + Unstructured ObjectはStructured Objectのようにリソースの取得・更新など諸々の操作を ⾏うことが可能なObject ▶ Metadata: "k8s.io/apimachinery/pkg/apis/meta/v1" にある以下のstruct + PartialObjectMetadata: Podなどのリソース単体向けに使⽤ + PartialObjectMetadataList: PodListなどのListリソース向けに使⽤ + Metadata Objectはリソースのmetadata取得・更新にのみ利⽤できる

Slide 40

Slide 40 text

scheme.Convert()を利⽤することで異なるObjectのデータを 
 変換することができる client := mgr.GetClient() uList := unstructured.UnstructuredList{} uList.SetGroupVersionKind(corev1.GroupVersion.WithKind("PodList")) err := client.List(ctx, uList) if err != nil { return err } podList := corev1.PodList{} err = mgr.GetScheme().Convert(uList, podList, nil) if err != nil { return err }

Slide 41

Slide 41 text

Unstructured(List)とMetadata(List)はGVKによってリソース種別を 
 判定している u := unstructured.Unstructured{} u.SetGroupVersionKind(schema.GroupVersionKind{ Group: "networking", Version: "v1", Kind: "Ingress", }) p := metav1.PartialObjectMetadata{} u.SetGroupVersionKind(schema.GroupVersionKind{ Group: "", Version: "v1", Kind: "Pod", }) ※ Structured Objectはre fl ect.ValueOf(obj).Elem().Type() で取得できるObjectの re fl ect.Type をキーにリソースを判定している

Slide 42

Slide 42 text

つまり、scheme.Convert()・GVK・Unstructuredを利⽤して異なる Structured Objectを変換可能 client := mgr.GetClient() ingress := networkingv1.Ingress{} err := client.Get(ctx, types.NamespacedName{Name: "ingress", Namespace: "default"} ingress) if err != nil { return err } u := unstructured.Unstructured{} err = mgr.GetScheme().Convert(ingress, u, nil) if err != nil { return err } ingressbeta := networkingv1beta1.Ingress{} u.SetGroupVersionKind(networkingv1beta1.GroupVersion.WithKind("Ingress")) err = mgr.GetScheme().Convert(u, ingressbeta, nil) if err != nil { return err } ※ CRDのgroup名をrenameしたときになどはこの⽅法を使うと便利だった

Slide 43

Slide 43 text

Unstructured Objectのキャッシュを有効化するには CacheUnstructuredオプションを有効化する必要がある func NewCustomDelegatingClient( cache cache.Cache, config *rest.Config, options client.Options, uncachedObjects ...client.Object ) (client.Client, error) { c, err := client.New(config, options) if err != nil { return nil, err } return client.NewDelegatingClient(client.NewDelegatingClientInput{ CacheReader: cache, Client: c, UncachedObjects: uncachedObjects, CacheUnstructured: true // enable caching for unstructured objects }) } func main() { mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ NewClient: NewCustomDelegatingClient, … }) if err != nil { setupLog.Error(err, "unable to start manager") os.Exit(1) } }

Slide 44

Slide 44 text

k8s clientまとめ ▶ controller-runtimeでは以下の3種類のclientが提供されている + Delegating Client: Readerのみキャッシュが利⽤されるクライアント + Cache Client: SharedInformerを利⽤したキャッシュクライアント + API Reader: 都度同期的にAPI Serverにリクエストするクライアント ▶ Delegating ClientとCache Clientはオプションで独⾃クライアントに上書き可能 ▶ Client objectには以下の3種類が提供されている + Structured + Unstructured + Metadata ▶ Structured ObjectやUnstructured Objectはscheme.Convert()で相互変換が可能 ▶ Unstructured ObjectとMetadata Clientは内部のGVK情報によってGVKを管理 ▶ Structured Objectはstructのre fl ect.TypeをキーにGVKを管理 ▶ `CacheUnstructured: true` に設定することでUnstructured Objectのキャッシュが可能になる

Slide 45

Slide 45 text

より詳しい内容を知りたい⽅はこちら https://zenn.dev/bells17/articles/controller-runtime-client

Slide 46

Slide 46 text

envtestについて

Slide 47

Slide 47 text

envtest ▶ controller-runtimeに付属するe2eテストツール ▶ 指定Kubernetesバージョンのetcd/API Serverのダウンロード~起動・設定を⾏ってくれる ▶ controller-managerや実際のnodeなどが必要なe2eテストを動かしたい場合は実際のk8s クラスターを⽤意する必要あり + `USE_EXISTING_CLUSTER ` 環境変数を使うことで、構築済クラスターをe2eテストに 利⽤することが可能

Slide 48

Slide 48 text

envtest overview ▶ setup-envtest 
 指定Kubernetesバージョンの 
 etcd/API Serverなどのダウンロードを⾏う ▶ envtest.Environment.Start 
 以下のようなAPI Serverを使ったKubernetes Operatorのe2eテスト環境のセットアップを⼀通り ⾏ってくれる + KUBEBUILDER_ASSETSを通して渡された 
 パスにあるetcd/API Serverの起動 + CRDのインストール + デフォルトユーザーの追加 + Webhook設定 ▶ envtest.Environment.Stopで起動した 
 etcd/API Serverの停⽌が可能

Slide 49

Slide 49 text

Tips: 
 対象バージョンのkubectlの使⽤や独⾃ユーザーの設定などが可能 testEnv = &envtest.Environment{ CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, ErrorIfCRDPathMissing: true, } var err error cfg, err = testEnv.Start() Expect(err).NotTo(HaveOccurred()) Expect(cfg).NotTo(BeNil()) // use kubectl cmd testEnv.ControlPlane.KubeCtl().Run("get", "nodes") // add user & use kubectl cmd user, err := env.ControlPlane.AddUser(envtest.User{ Name: "envtest-admin", Groups: []string{"system:masters"}, }, nil) Expect(err).NotTo(HaveOccurred()) kubectl, err := user.Kubectl() Expect(err).NotTo(HaveOccurred()) kubectl.Run("get", "nodes")

Slide 50

Slide 50 text

その他

Slide 51

Slide 51 text

設定ファイルの拡張 type customConfig struct { metav1.TypeMeta `json:",inline"` configv1alpha1.ControllerManagerConfigurationSpec `json:",inline"` CustomValue string `json:"customValue"` } func main() { options := ctrl.Options{ Scheme: scheme, HealthProbeBindAddress: ":8081", MetricsBindAddress: ":8080", Port: 9443, } var err error config := customConfig{} options, err = options.AndFrom(ctrl.ConfigFile().AtPath("./config.yaml").OfKind(&config)) if err != nil { setupLog.Error(err, "unable to load the config file") os.Exit(1) } fmt.Println(config.CustomValue) } # ./config.yaml apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 kind: CustomControllerManagerConfiguration customValue: foo port: 9442 controller-runtimeの設定ファイルを拡張して独⾃設定を渡せるので、設定の数が多いときに便利

Slide 52

Slide 52 text

Controller: Reconcile対象以外のリソースからのイベントを元に調整ループを実⾏ func (r *SampleReconciler) SetupWithManager(mgr ctrl.Manager) error { handler := &eventHandler{} return ctrl.NewControllerManagedBy(mgr). For(&sampleoperatorv1beta1.Sample{}). Watches(&source.Kind{Type: &corev1.Service{}}, handler). Complete(r) } type eventHandler struct {} func (h *eventHandler) Create(e event.CreateEvent, queue workqueue.RateLimitingInterface) { svc := e.Object.(*corev1.Service) queue.Add(reconcile.Request{NamespacedName: types.NamespacedName{ Namespace: svc.Namespace, Name: svc.Name, }}) } func (h *eventHandler) Update(e event.UpdateEvent, queue workqueue.RateLimitingInterface) {} func (h *eventHandler) Delete(e event.DeleteEvent, queue workqueue.RateLimitingInterface) {} func (h *eventHandler) Generic(e event.GenericEvent, queue workqueue.RateLimitingInterface) {} 上記の例の場合、Serviceリソースが作成されたら、ServiceリソースのName/NamespaceをキーにSample CRDのReconcileを実⾏することになる

Slide 53

Slide 53 text

Controller: Goチャネルからのイベントを元に調整ループを実⾏ func (r *SampleReconciler) SetupWithManager(mgr ctrl.Manager) error { handler := &eventHandler{} evt := make(chan event.GenericEvent) return ctrl.NewControllerManagedBy(mgr). For(&sampleoperatorv1beta1.Sample{}). Watches(&source.Channel{Source: evt}, handler). Complete(r) } type eventHandler struct {} func (h *eventHandler) Create(e event.CreateEvent, queue workqueue.RateLimitingInterface) {} func (h *eventHandler) Update(e event.UpdateEvent, queue workqueue.RateLimitingInterface) {} func (h *eventHandler) Delete(e event.DeleteEvent, queue workqueue.RateLimitingInterface) {} func (h *eventHandler) Generic(e event.GenericEvent, queue workqueue.RateLimitingInterface) { queue.Add(reconcile.Request{NamespacedName: types.NamespacedName{ Namespace: e.Object.GetNamespace(), Name: e.Object.GetName(), }}) } 上記の例の場合、Serviceリソースが作成されたら、ServiceリソースのName/NamespaceをキーにSample CRDのReconcileを実⾏することになる

Slide 54

Slide 54 text

まとめ

Slide 55

Slide 55 text

まとめ ▶ controller-runtimeのアーキテクチャや内部実装の概要、tipsについてまとめました ▶ 独⾃クライアントを使えるようにしたりといったcontroller-runtimeを拡張して使ってい くためのベースとなる知識もいくつか紹介できたと思います

Slide 56

Slide 56 text

参考資料 ▶ controller-runtime clientについて: https://zenn.dev/bells17/articles/controller-runtime-client ▶ controller-runtime: https://github.com/kubernetes-sigs/controller-runtime/tree/v0.12.3 ▶ aws-load-balancer-controller: https://github.com/kubernetes-sigs/aws-load-balancer-controller/tree/v2.4.4 ▶ kueue: https://github.com/kubernetes-sigs/kueue/tree/v0.2.1 ▶ Kubebuilder Book: https://book.kubebuilder.io/architecture.html ▶ つくって学ぶKubebuilder: https://zoetrope.github.io/kubebuilder-training/ ▶ Ginkgo/GomegaによるKubernetes Operatorのテスト⼿法: https://zenn.dev/zoetro/books/testing-kubernetes-operator ▶ Caching Unstructured Objects using controller-runtime: https://ymmt2005.hatenablog.com/entry/2021/07/25/ Caching_Unstructured_Objects_using_controller-runtime ▶ kubebuilder-declarative-pattern: https://github.com/kubernetes-sigs/kubebuilder-declarative-pattern ▶ kubebuilder: https://github.com/kubernetes-sigs/kubebuilder ▶ controller-tools: https://github.com/kubernetes-sigs/controller-tools

Slide 57

Slide 57 text

Thanks / Question? ▶ @bells17 ▶ Slide: https://speakerdeck.com/bells17 ▶ @bells17_