ื›ืชื™ื‘ืช ืžืคืขื™ืœ ืขื‘ื•ืจ Kubernetes ื‘ื’ื•ืœื ื’

ื”ืขืจื”. ืชืจื’ื•ื: ืžืคืขื™ืœื™ื ื”ื ืชื•ื›ื ืช ืขื–ืจ ืขื‘ื•ืจ Kubernetes, ืฉื ื•ืขื“ื” ืœื”ืคื•ืš ืืช ื”ื‘ื™ืฆื•ืข ืฉืœ ืคืขื•ืœื•ืช ืฉื’ืจืชื™ื•ืช ืขืœ ืื•ื‘ื™ื™ืงื˜ื™ ืืฉื›ื•ืœ ื›ืืฉืจ ืžืชืจื—ืฉื™ื ืื™ืจื•ืขื™ื ืžืกื•ื™ืžื™ื. ื›ื‘ืจ ื›ืชื‘ื ื• ืขืœ ืžืคืขื™ืœื™ื ื‘ ืžืืžืจ ื–ื”, ืฉื ื”ื ื“ื™ื‘ืจื• ืขืœ ื”ืจืขื™ื•ื ื•ืช ื•ื”ืขืงืจื•ื ื•ืช ื”ื‘ืกื™ืกื™ื™ื ืฉืœ ืขื‘ื•ื“ืชื. ืื‘ืœ ืื ื”ื—ื•ืžืจ ื”ื–ื” ื”ื™ื” ื™ื•ืชืจ ืžื‘ื˜ ืžื”ืฆื“ ืฉืœ ืชืคืขื•ืœ ืจื›ื™ื‘ื™ื ืžื•ื›ื ื™ื ืขื‘ื•ืจ Kubernetes, ืื– ื”ืชืจื’ื•ื ืฉืœ ื”ืžืืžืจ ื”ื—ื“ืฉ ื”ืžื•ืฆืข ื›ืขืช ื”ื•ื ื›ื‘ืจ ื—ื–ื•ืŸ ืฉืœ ืžืคืชื—/ืžื”ื ื“ืก DevOps ื”ืžื‘ื•ืœื‘ืœ ืžื”ื™ื™ืฉื•ื ืฉืœ ืžืคืขื™ืœ ื—ื“ืฉ.

ื›ืชื™ื‘ืช ืžืคืขื™ืœ ืขื‘ื•ืจ Kubernetes ื‘ื’ื•ืœื ื’

ื”ื—ืœื˜ืชื™ ืœื›ืชื•ื‘ ืืช ื”ืคื•ืกื˜ ื”ื–ื” ืขื ื“ื•ื’ืžื” ืžื”ื—ื™ื™ื ื”ืืžื™ืชื™ื™ื ืœืื—ืจ ื”ื ื™ืกื™ื•ื ื•ืช ืฉืœื™ ืœืžืฆื•ื ืชื™ืขื•ื“ ืขืœ ื™ืฆื™ืจืช ืžืคืขื™ืœ ืขื‘ื•ืจ Kubernetes, ืฉืขื‘ืจ ืœื™ืžื•ื“ ื”ืงื•ื“.

ื”ื“ื•ื’ืžื” ืฉืชืชื•ืืจ ื”ื™ื ื–ื•: ื‘ืืฉื›ื•ืœ Kubernetes ืฉืœื ื•, ื›ืœ ืื—ื“ Namespace ืžื™ื™ืฆื’ ืืช ืกื‘ื™ื‘ืช ืืจื’ื– ื”ื—ื•ืœ ืฉืœ ืงื‘ื•ืฆื”, ื•ืจืฆื™ื ื• ืœื”ื’ื‘ื™ืœ ืืช ื”ื’ื™ืฉื” ืืœื™ื”ื ื›ืš ืฉืฆื•ื•ืชื™ื ื™ื•ื›ืœื• ืœืฉื—ืง ืจืง ื‘ืืจื’ื–ื™ ื”ื—ื•ืœ ืฉืœื”ื.

ืืชื” ื™ื›ื•ืœ ืœื”ืฉื™ื’ ืืช ืžื” ืฉืืชื” ืจื•ืฆื” ืขืœ ื™ื“ื™ ื”ืงืฆืืช ืžืฉืชืžืฉ ืœืงื‘ื•ืฆื” ืฉื™ืฉ ืœื• RoleBinding ืœืกืคืฆื™ืคื™ืช Namespace ะธ ClusterRole ืขื ื–ื›ื•ื™ื•ืช ืขืจื™ื›ื”. ื™ื™ืฆื•ื’ 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

(rolebinding.yamlื‘ืชื•ืš ื—ื™)

ืชื™ืฆื•ืจ ืื—ื“ RoleBinding ืืชื” ื™ื›ื•ืœ ืœืขืฉื•ืช ืืช ื–ื” ื™ื“ื ื™ืช, ืื‘ืœ ืœืื—ืจ ื—ืฆื™ื™ืช ืžืื” ืžืจื—ื‘ื™ ื”ืฉืžื•ืช, ื–ื” ื”ื•ืคืš ืœืžืฉื™ืžื” ืžื™ื™ื’ืขืช. ื–ื” ื”ืžืงื•ื ืฉื‘ื• ืžืคืขื™ืœื™ Kubernetes ืฉื™ืžื•ืฉื™ื™ื - ื”ื ืžืืคืฉืจื™ื ืœืš ืœื”ืคื•ืš ืืช ื”ื™ืฆื™ืจื” ืฉืœ ืžืฉืื‘ื™ Kubernetes ืœืื•ื˜ื•ืžื˜ื™ ืขืœ ืกืžืš ืฉื™ื ื•ื™ื™ื ื‘ืžืฉืื‘ื™ื. ื‘ืžืงืจื” ืฉืœื ื• ืื ื—ื ื• ืจื•ืฆื™ื ืœื™ืฆื•ืจ RoleBinding ืชื•ืš ื›ื“ื™ ื™ืฆื™ืจื” Namespace.

ืงื•ื“ื ื›ืœ, ื‘ื•ืื• ื ื’ื“ื™ืจ ืืช ื”ืคื•ื ืงืฆื™ื” mainืืฉืจ ืžื‘ืฆืข ืืช ื”ื”ื’ื“ืจื” ื”ื ื“ืจืฉืช ืœื”ืคืขืœืช ื”ื”ืฆื”ืจื” ื•ืœืื—ืจ ืžื›ืŸ ืงื•ืจื ืœืคืขื•ืœืช ื”ื”ืฆื”ืจื”:

(ื”ืขืจื”. ืชืจื’ื•ื: ื›ืืŸ ื•ืžื˜ื” ื”ื”ืขืจื•ืช ื‘ืงื•ื“ ืžืชื•ืจื’ืžื•ืช ืœืจื•ืกื™ืช. ื‘ื ื•ืกืฃ, ื”ื”ื–ื—ื” ืชื•ืงื ื” ืœืจื•ื•ื—ื™ื ื‘ืžืงื•ื ืœืœืฉื•ื ื™ื•ืช [ืžื•ืžืœืฅ ื‘- Go] ืืš ื•ืจืง ืœืžื˜ืจืช ืงืจื™ืื” ื˜ื•ื‘ื” ื™ื•ืชืจ ื‘ืคืจื™ืกืช Habr. ืœืื—ืจ ื›ืœ ืจื™ืฉื•ื ื™ืฉ ืงื™ืฉื•ืจื™ื ืœืžืงื•ืจ ื‘-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ื‘ืชื•ืš ื—ื™)

ืื ื• ืขื•ืฉื™ื ืืช ื”ืคืขื•ืœื•ืช ื”ื‘ืื•ืช:

  1. ืื ื• ืžื’ื“ื™ืจื™ื ืžื˜ืคืœ ืœืื•ืชื•ืช ืกืคืฆื™ืคื™ื™ื ืฉืœ ืžืขืจื›ืช ื”ืคืขืœื” ื›ื“ื™ ืœื’ืจื•ื ืœืกื™ื•ื ื—ื™ื ื ื™ ืฉืœ ื”ืžืคืขื™ืœ.
  2. ื”ืฉืชืžืฉ WaitGroupืœื”ืคืกื™ืง ื‘ื—ืŸ ืืช ื›ืœ ื”ื’ื•ืจื•ื˜ื™ืŸ ืœืคื ื™ ืกื™ื•ื ื”ื™ื™ืฉื•ื.
  3. ืื ื• ืžืกืคืงื™ื ื’ื™ืฉื” ืœืืฉื›ื•ืœ ืขืœ ื™ื“ื™ ื™ืฆื™ืจื” clientset.
  4. ืจื•ืฅ 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, ืืฉืจ ืœืžืขืฉื” (ื‘ืืžืฆืขื•ืช ืžื˜ืžื•ืŸ) ื™ืžืชื™ืŸ ืœืฉื™ื ื•ื™ื™ื ื‘ืžืจื—ื‘ื™ ื”ืฉืžื•ืช (ืงืจื ืขื•ื“ ืขืœ ืžืœืฉื™ื ื™ื ื‘ืžืืžืจ "ื›ื™ืฆื“ ืคื•ืขืœ ืžืชื–ืžืŸ Kubernetes ืœืžืขืฉื”?- ืžืฉื•ืขืจ. ืชืจื’ื•ื). ืื—ืจื™ ื–ื” ืื ื—ื ื• ืžืชื—ื‘ืจื™ื 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. ื•ืื– ื ื’ื“ื™ืจ RoleBinding, ื‘ื”ืชื‘ืกืก ืขืœ ืงื•ื‘ืฅ YAML ืฉื”ื•ื–ื›ืจ ื‘ื”ืชื—ืœื”, ืชื•ืš ืฉื™ืžื•ืฉ ื‘ืื•ื‘ื™ื™ืงื˜ ืฉืกื•ืคืง Namespace ื•ื™ืฆื™ืจื” 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, ืืฉืจ ืื™ื ื• ืžื‘ื•ืฆืข ื™ื•ืชืจ, ื•ื”ืคื•ื ืงืฆื™ื” ื”ื–ื• ืชืฆื.

ืžื™ื“ืข ืขืœ ื‘ื ื™ื™ื” ื•ื”ืคืขืœื” ืฉืœ ื”ืฆื”ืจื” ื–ื• ื‘ืืฉื›ื•ืœ Kubernetes ื ื™ืชืŸ ืœืžืฆื•ื ื‘ ืžืื’ืจื™ื ื‘- GitHub.

ื–ื” ื”ื›ืœ ืขื‘ื•ืจ ื”ืžืคืขื™ืœ ืฉื™ื•ืฆืจ RoleBinding ืžืชื™ Namespace ื‘ืืฉื›ื•ืœ Kubernetes, ืžื•ื›ืŸ.

ืžืงื•ืจ: www.habr.com

ื”ื•ืกืคืช ืชื’ื•ื‘ื”