Ekri yon operatè pou Kubernetes nan Golang

Remak. trad.: Operatè yo se lojisyèl oksilyè pou Kubernetes, ki fèt pou otomatize ekzekisyon aksyon woutin sou objè gwoup lè sèten evènman rive. Nou te deja ekri sou operatè yo nan atik sa a, kote yo te pale sou lide fondamantal ak prensip travay yo. Men, si materyèl sa a te plis nan yon gade nan bò a nan opere konpozan pare-fè pou Kubernetes, Lè sa a, tradiksyon an nan nouvo atik la kounye a pwopoze a se deja vizyon an nan yon enjenyè devlopè / DevOps pè pa aplikasyon an nan yon nouvo operatè.

Ekri yon operatè pou Kubernetes nan Golang

Mwen deside ekri pòs sa a ak yon egzanp lavi reyèl apre tantativ mwen jwenn dokiman sou kreye yon operatè pou Kubernetes, ki te ale nan etidye kòd la.

Egzanp ki pral dekri a se sa a: nan gwoup Kubernetes nou an, chak Namespace reprezante anviwònman sandbox yon ekip, e nou te vle limite aksè a yo pou ekip yo te kapab jwe sèlman nan pwòp sandbox yo.

Ou ka reyalize sa ou vle lè w bay yon itilizatè yon gwoup ki genyen RoleBinding a espesifik Namespace и ClusterRole ak dwa koreksyon. Reprezantasyon YAML a pral sanble tankou sa a:

---
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.yamlpous anvan tout koreksyon)

Kreye youn RoleBinding Ou ka fè li manyèlman, men apre yo fin travèse make la san espas non, li vin tounen yon travay fatigan. Sa a se kote operatè Kubernetes yo vin an sou la men—yo pèmèt ou otomatize kreyasyon an nan resous Kubernetes ki baze sou chanjman nan resous yo. Nan ka nou an nou vle kreye RoleBinding pandan y ap kreye Namespace.

Premye a tout, se pou yo defini fonksyon an mainki fè konfigirasyon ki nesesè pou kouri deklarasyon an epi li rele aksyon deklarasyon an:

(Remak. trad.: isit la ak anba kòmantè yo nan kòd la yo tradui nan Ris. Anplis de sa, yo te korije endentasyon an nan espas olye pou yo [rekòmande nan Go] onglet sèlman nan bi pou yo ka pi byen lizibilite nan layout Habr la. Apre chak lis, gen lyen ki mennen nan orijinal la sou GitHub, kote yo estoke kòmantè ak onglè ann angle.)

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.gopous anvan tout koreksyon)

Nou fè bagay sa yo:

  1. Nou konfigirasyon yon moun kap okipe siyal sistèm operasyon espesifik yo lakòz revokasyon grasyeuz nan operatè a.
  2. Nou itilize WaitGrouppou sispann tout goroutines yo anvan ou mete fen nan aplikasyon an.
  3. Nou bay aksè nan gwoup la pa kreye clientset.
  4. Lanse NamespaceController, nan ki tout lojik nou yo pral lokalize.

Koulye a, nou bezwen yon baz pou lojik, ak nan ka nou an sa a se youn nan mansyone 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.gopous anvan tout koreksyon)

Isit la nou konfigirasyon SharedIndexInformer, ki pral efektivman (lè l sèvi avèk yon kachèt) tann pou chanjman nan espas non yo (li plis sou enfomatè nan atik la "Ki jan pwogramè Kubernetes aktyèlman ap travay?"- approx. tradiksyon). Apre sa nou konekte EventHandler bay enfòmatè a, pou lè w ajoute yon espas non (Namespace) yo rele fonksyon createRoleBinding.

Pwochen etap la se defini fonksyon sa a 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.gopous anvan tout koreksyon)

Nou jwenn namespace la kòm obj epi konvèti li an yon objè Namespace. Lè sa a, nou defini RoleBinding, ki baze sou dosye YAML mansyone nan kòmansman an, lè l sèvi avèk objè yo bay la Namespace ak kreye RoleBinding. Finalman, nou konekte si kreyasyon an te reyisi.

Dènye fonksyon yo dwe defini se 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.gopous anvan tout koreksyon)

Men nap pale WaitGroupke nou lanse goroutine a ak Lè sa a, rele namespaceInformer, ki te deja defini. Lè siyal la sispann rive, li pral fini fonksyon an, enfòme WaitGroup, ki pa egzekite ankò, epi fonksyon sa a pral sòti.

Ou ka jwenn enfòmasyon sou bati ak kouri deklarasyon sa a sou yon gwoup Kubernetes nan depo sou GitHub.

Sa a se li pou operatè a ki kreye RoleBinding Kilè Namespace nan gwoup Kubernetes, pare.

Sous: www.habr.com

Add nouvo kòmantè