コードスタディを経たKubernetesの演算子の作成に関するドキュメントを見つけようと試みた後、実際の例を使用してこの投稿を書くことにしました。
説明する例は次のとおりです。Kubernetesクラスターでは、各
Namespace
      
      スペースはあるチームのサンドボックス環境を表し、チームがサンドボックスでのみプレイできるように、それらへのアクセスを制限したいと考えました。
特定の
Namespace
      
      と編集権限を持つ
ClusterRole
      
      への
RoleBinding
      
      を持つグループにユーザーを割り当てることで、目的を達成できます。 YAMLビューは次のようになります。
--- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: kubernetes-team-1 namespace: team-1 subjects: - kind: Group name: kubernetes-team-1 apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: edit apiGroup: rbac.authorization.k8s.io
( rawのrolebinding.yaml )
このような
RoleBinding
      
      手動で作成することもできますが、100個の名前空間のマークを克服した後は、退屈なタスクになります。 これは、Kubernetesオペレーターが支援する場所です。彼らは、リソースの変更に基づいてKubernetesリソースの作成を自動化します。 この場合、
Namespace
      
      作成するときに
RoleBinding
      
      を作成します。
まず、関数
main
      
      を定義します。これは、オペレーターを開始するために必要な設定を実行してから、オペレーターを呼び出します。
( 注の翻訳 :以降、コード内のコメントはロシア語に翻訳されます。さらに、Habrのフレームワーク内で読みやすくするために、[Go推奨]タブの代わりにインデントがスペースに修正されます。各リストの後に、GitHubのオリジナルへのリンクがあります英語のコメントとタブが保存されています。)
 func main() { //      STDOUT log.SetOutput(os.Stdout) sigs := make(chan os.Signal, 1) //       stop := make(chan struct{}) //     - //   SIGTERM   sigs signal.Notify(sigs, os.Interrupt, syscall.SIGTERM, syscall.SIGINT) // Goroutines      WaitGroup, //      wg := &sync.WaitGroup{} runOutsideCluster := flag.Bool("run-outside-cluster", false, "Set this flag when running outside of the cluster.") flag.Parse() //  clientset     Kubernetes clientset, err := newClientSet(*runOutsideCluster) if err != nil { panic(err.Error()) } controller.NewNamespaceController(clientset).Run(stop, wg) <-sigs //   (      ) log.Printf("Shutting down...") close(stop) //  goroutines  wg.Wait() // ,    }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      ( main.go 、 生 )
次のことを行います。
- オペレーティングシステムの特定の信号のプロセッサを構成して、オペレーターを正しく(正常に)終了させます。
 -   
WaitGroup
を使用して、アプリケーションをシャットダウンする前に、すべてのWaitGroup
を正しく停止します。 -   
clientset
を作成して、クラスターへのアクセスを提供します。 -  すべてのロジックが配置される
NamespaceController
を起動します。 
ここで、ロジックの基礎が必要です。この場合、これは前述の
NamespaceController
      
      です。
 // NamespaceController   Kubernetes API   //      RoleBinding   namespace. type NamespaceController struct { namespaceInformer cache.SharedIndexInformer kclient *kubernetes.Clientset } // NewNamespaceController   NewNamespaceController func NewNamespaceController(kclient *kubernetes.Clientset) *NamespaceController { namespaceWatcher := &NamespaceController{} //      Namespaces namespaceInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { return kclient.Core().Namespaces().List(options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { return kclient.Core().Namespaces().Watch(options) }, }, &v1.Namespace{}, 3*time.Minute, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) namespaceInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: namespaceWatcher.createRoleBinding, }) namespaceWatcher.kclient = kclient namespaceWatcher.namespaceInformer = namespaceInformer return namespaceWatcher }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      ( controller.go 、 生 )
ここで、
SharedIndexInformer
      
      をセットアップし
SharedIndexInformer
      
      。これは、効率的に(キャッシュを使用して)名前空間の変更を期待します(インフォーマーの詳細については、記事「 Kubernetes Schedulerの実際の動作方法 」- 約Transl。を参照してください) 。 その後、
EventHandler
      
      をインフォーマーに接続します。これにより、
Namespace
      
      追加するときに
createRoleBinding
      
      関数が呼び出されます。
次のステップは、この
createRoleBinding
      
      関数を定義することです。
 func (c *NamespaceController) createRoleBinding(obj interface{}) { namespaceObj := obj.(*v1.Namespace) namespaceName := namespaceObj.Name roleBinding := &v1beta1.RoleBinding{ TypeMeta: metav1.TypeMeta{ Kind: "RoleBinding", APIVersion: "rbac.authorization.k8s.io/v1beta1", }, ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("ad-kubernetes-%s", namespaceName), Namespace: namespaceName, }, Subjects: []v1beta1.Subject{ v1beta1.Subject{ Kind: "Group", Name: fmt.Sprintf("ad-kubernetes-%s", namespaceName), }, }, RoleRef: v1beta1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", Name: "edit", }, } _, err := c.kclient.Rbac().RoleBindings(namespaceName).Create(roleBinding) if err != nil { log.Println(fmt.Sprintf("Failed to create Role Binding: %s", err.Error())) } else { log.Println(fmt.Sprintf("Created AD RoleBinding for Namespace: %s", roleBinding.Name)) } }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      ( controller.go 、 生 )
名前空間を
obj
      
      として取得し、
Namespace
      
      オブジェクトに変換します。 次に、最初に説明したYAMLファイルに基づいて、提供された
Namespace
      
      オブジェクトを使用して
RoleBinding
      
      を作成する
RoleBinding
      
      ます。 最後に、作成が成功したかどうかを記録します。
定義される最後の関数は
Run
      
      です:
 // Run        //       . func (c *NamespaceController) Run(stopCh <-chan struct{}, wg *sync.WaitGroup) { //    ,    defer wg.Done() //  wait group, ..   goroutine wg.Add(1) //  goroutine go c.namespaceInformer.Run(stopCh) //   - <-stopCh }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      ( controller.go 、 生 )
ここで、
WaitGroup
      
      を実行してから、以前に定義された
namespaceInformer
      
      を呼び出すことを
WaitGroup
      
      に伝え
namespaceInformer
      
      。 停止信号が到着すると、関数を終了し、
WaitGroup
      
      実行されていないことを伝え、この関数は作業を完了します。
Kubernetesクラスターでのこのステートメントの構築と実行に関する情報は、GitHubのリポジトリにあります 。
これで、
Namespace
      
      RoleBinding
      
      がKubernetesクラスターに表示されるときに
RoleBinding
      
      が作成するステートメントの準備ができました。