オリジナルリンク:Kubernetesは、カスタムコントローラを書きます
マップのgithubのからKubernetesの公式:
図に示すように、図中のコンポーネントに分割して、クライアント行くとカスタムコントローラ二つの部分:
-
クライアント・ゴーセクション
- リフレクター:特定のリソースのK8S APIを監視し、監視対象デルタFIFOキューに新しいオブジェクトは、この機能はListAndWatchを完了しています。
- 情報提供:キューからデルタFIFOアウトオブジェクトは、この操作の機能は完全にprocessLoopです。
- インデクサ:オブジェクトとキーを格納するために、スレッドレベルのセキュリティを提供します。
-
カスタムコントローラ部分
- インフォーマ参照:情報提供のオブジェクト参照
- インデクサ参照:インデクサオブジェクト参照
- リソースイベントハンドラ:コールバック関数は、さらに処理を行うために、オブジェクトキー、および作業キューにキーを取得するために使用されているフォーマ、これらの機能の役割と呼ばれています。
- 作業キュー:作業キュー、キーオブジェクト渡され、作業キューに追加を抽出するために、リソースイベントハンドラ関数を用意し、そこに配信対象を分離するための処理。
- 処理項目:オブジェクトの処理のための作業キューは、一つ以上の他の機能と一緒にそこに処理することができる;これらの関数は、典型的には、ラッパーをリストインデクサ基準を使用するか、キーに対応するオブジェクトを取得します。
公式のコード例は、クライアント行きます
パッケージのメイン インポート( " フラグ" " FMT " " 時間" " k8s.io/klog " " k8s.io/api/core/v1 " meta_v1 " k8s.io/apimachinery/pkg/apis/meta/v1 " 「K8S。 IO / apimachinery / PKG /フィールド" " k8s.io/apimachinery/pkg/util/runtime " " k8s.io/apimachinery/pkg/util/wait " " k8s.io/client-go/kubernetes " " k8s.io/クライアント行く/ツール/キャッシュ「 」K8S。IO /クライアント行く/ツール/ clientcmd " "k8s.io/client-go/util/workqueue " ) // 構造の定義コントローラ タイプコントローラのstruct { インデクサcache.Indexer キューworkqueue.RateLimitingInterface フォーマcache.Controller } //はコントローラ機能を取得 NewController(キューworkqueue.RateLimitingInterface funcを、インデクサcache.Indexer、フォーマcache.Controller)* コントローラ{ リターン・コントローラ{ フォーマ:インフォーマ、 インデクサ:インデクサ、 キュー:キュー、 } } // で処理ワークキュー FUNC(C *とコントローラ)processNextItem( )BOOL { // 新しい項目が作業キューに存在するまで待って キーを終了し、:= c.queue.Get() 場合は終了{ 返す 偽 } // 我々は、このキーを処理して行われたキューに知らせます。これは、他の労働者のための鍵ブロック解除 // 同じキーを持つ2つのポッド内で処理されることはありませんので、これは安全な並列処理を可能にする // 平行に。 c.queue.Done(キー)を延期 // ビジネスロジック含むメソッド呼び出し ERR:= c.syncToStdout(。キー(文字列)) //何かがビジネスロジックの実行時に間違っていた場合は、エラーを処理 c.handleErr(ERR、キー) を返す 真 } // syncToStdoutは、コントローラのビジネスロジックです。このコントローラでは、それは単に印刷し // stdoutにポッドについての情報を。エラーが起こった場合、それは単にエラーを返すことがあります。 // 再試行ロジックは、ビジネス・ロジックの一部であってはなりません。 FUNC(C *とコントローラ)syncToStdout(キー文字列)エラー{ OBJ、ERR、存在する: = c.indexer.GetByKey(キー) 場合誤る=ゼロ{klog.Errorf(!" ストアからキー%sのフェッチオブジェクトは%で失敗しましたV「キー、ERR) リターンERR } 場合!が存在する{ // 我々が表示されますように、私たちは、ポッドと私たちのキャッシュを温める下記1ポッドのために削除 fmt.Printf(」ポッド%sはn個\もはや存在しません。」、キー) } 他{ // あなたも、あなたが地元の制御リソース、持っている場合はUIDをチェックする必要があることに注意してください // 実際のインスタンスに依存しているが、ポッドは同じ名前で再作成されたことを検知する fmt.Printf (" Syncは/ポッド%sの\ nに追加/更新"、OBJ。(* v1.Pod).GetName()) } 戻りはnil } // handleErrチェックし、エラーが起こったと私たちは、後で再試行されますを確認します場合。 FUNC(C *とコントローラ)handleErr(ERRエラー、キーインタフェース{}){ 場合 ERR == nilの{ // 成功するたびに、同期のキーの#AddRateLimitedの歴史を忘れます。 // これは、このキーのアップデートの将来の処理が原因で延期されていないことを保証します // 時代遅れのエラー履歴。 c.queue.Forget(キー) リターン } // 何かがうまくいかない場合は、このコントローラは、5回再試行します。その後、それはしようと停止します。 もしc.queue.NumRequeues(キー)< 5 { klog.Infof(" ポッド%のV同期エラー:%のV " 、キー、ERR) // 再エンキュー鍵レート制限されています。上のレートリミッタに基づいて //のキューと再エンキュー歴史、キーは後で再処理されます。 c.queue.AddRateLimited(キー) リターン } c.queue.Forget(キー) // でも、いくつかの再試行の後、我々は正常にこのキーを処理できませんでした、外部エンティティへの報告書 runtime.HandleError(ERR)を klog.Infof(" キューのうちポッド%qを削除します。%V 」)、キーを誤ります } FUNC(Cの *コントローラ)を実行します(threadinessのint型、stopChちゃんのstruct {}){ (runtime.HandleCrashを延期) // 我々が行われたときに労働者が停止してみましょう )延期c.queue.ShutDown( klog.Info(「ポッドコントローラーを開始" ) c.informer.Run(stopChが)行く // 開始されたキューからアイテムを処理する前に、同期されるように関係するすべてのキャッシュを待って いる場合!cache.WaitForCacheSync(stopCh、c.informer.HasSynced){runtime.HandleError(FMT .Errorf(「同期するためにキャッシュを待ってタイムアウトしました」)) リターン } についてI:= 0 ; 私はthreadinessを<; 私は++ { wait.Until(c.runWorker、time.Second、stopCh)を行く } - < stopCh klog.Info(" 停止ポッドコントローラ" ) } FUNC(のC *のrunWorker(){コントローラ) 用c.processNextItem(){ } } FUNCメイン(){ VARの kubeconfigのストリング VaRのマスタストリング // 指定kubeconfig文件 flag.StringVar(&kubeconfig、" kubeconfig "、"" 、"絶対kubeconfigファイルへのパス" ) flag.StringVar( &マスター、" マスター" "" 、" マスターURL 」) flag.Parse() //が接続作成 ERR、設定を:=のclientcmd.BuildConfigFromFlags(マスター、kubeconfig) であれば誤る=!ゼロ{klog.Fatal(ERR) } //はclientsetの作成 = clientsetを、ERR kubernetes.NewForConfig(設定) 場合誤る=!ゼロ{klog.Fatal(ERR) } // ポッドウォッチャーを作成します podListWatcher:= cache.NewListWatchFromClient(clientset.CoreV1()RESTClient()、。" ポッド" 、v1.NamespaceDefault、fields.Everything()) // ワークキューの作成 キューを:= workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()) / / 情報提供の助けを借りて、キャッシュにワークキューをバインドします。私たちがいることを確認してください。この方法 // キャッシュが更新されるたびに、ポッドキーがワークキューに追加されます。 // 我々は最終的にワークキューから項目を処理するとき、私たちは新しいバージョン見るかもしれないことに注意してください // 更新をトリガを担当したバージョンよりポッドのを。 インデクサ、情報提供= cache.NewIndexerInformer(podListWatcher、&v1.Pod {}、0 、cache.ResourceEventHandlerFuncs { AddFunc:FUNC(OBJ インターフェイス{}){ キー、ERR: = cache.MetaNamespaceKeyFunc(OBJ) 場合 ERR == ゼロ{ queue.Add(キー) } }、 UpdateFunc:FUNC(古いインターフェース {}、新しい インターフェイス{}){ キー、ERR: = cache.MetaNamespaceKeyFunc(新しい) 場合 ERR == ゼロ{ queue.Add(キー) } }、 DeleteFunc:FUNC(OBJのインターフェースは、{}){ // IndexerInformerしたがって、削除のために、我々は、この使用する必要があり、デルタキューを使用 // キー機能。 キー、ERR:=はcache.DeletionHandlingMetaNamespaceKeyFunc(OBJ) 場合 ERR == ゼロ{ queue.Add(キー) } 、} }、cache.Indexers {}) コントローラ: = NewController(キュー、インデクサ、情報提供) // 現在、缶初期同期のキャッシュをウォームアップ。 //したがって、キャッシュに追加し、我々は私たちの最後の実行のポッド「mypod」を知っていたと仮定しましょう。// このポッドはもう存在しない場合には、コントローラは、後の除去について通知されます//のキャッシュが同期しています。indexer.Add(&v1.Pod {ObjectMeta:meta_v1.ObjectMeta {名: "mypod"、名前空間:v1.NamespaceDefaultは、}、})// 今度は、コントローラ始めましょう :(ちゃん=作る停止を構造体{})( クローズ延期しますストップ) controller.Run(行く1 、停止) //は永遠に待っ 選択} { }