Tikteb operatur għal Kubernetes f'Golang

Nota. transl.: L-operaturi huma softwer awżiljarju għal Kubernetes, iddisinjat biex awtomat l-eżekuzzjoni ta 'azzjonijiet ta' rutina fuq oġġetti cluster meta jseħħu ċerti avvenimenti. Diġà ktibna dwar l-operaturi fil Dan l-artikolu, fejn tkellmu dwar l-ideat u l-prinċipji fundamentali tal-ħidma tagħhom. Imma jekk dak il-materjal kien aktar ta 'opinjoni min-naħa tal-operat ta' komponenti lesti għal Kubernetes, allura t-traduzzjoni tal-artikolu l-ġdid issa proposta hija diġà l-viżjoni ta 'żviluppatur / inġinier DevOps mħawwda bl-implimentazzjoni ta' operatur ġdid.

Tikteb operatur għal Kubernetes f'Golang

Iddeċidejt li nikteb din il-kariga b'eżempju tal-ħajja reali wara t-tentattivi tiegħi biex insib dokumentazzjoni dwar il-ħolqien ta 'operatur għal Kubernetes, li għadda mill-istudju tal-kodiċi.

L-eżempju li se jiġi deskritt huwa dan: fil-cluster Kubernetes tagħna, kull wieħed Namespace jirrappreżenta l-ambjent ta 'sandbox ta' tim, u ridna nillimitaw l-aċċess għalihom sabiex it-timijiet ikunu jistgħu jilagħbu biss fis-sandboxes tagħhom stess.

Tista 'tikseb dak li trid billi tassenja utent grupp li għandu RoleBinding għal speċifiċi Namespace и ClusterRole bi drittijiet ta’ editjar. Ir-rappreżentazzjoni YAML se tidher bħal din:

---
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.yamlpulzieri prima)

Oħloq wieħed RoleBinding Tista 'tagħmel dan manwalment, iżda wara li taqsam il-marka tal-mitt namespaces, issir kompitu tedious. Dan huwa fejn l-operaturi Kubernetes jiġu utli—jippermettulek awtomatizza l-ħolqien tar-riżorsi Kubernetes ibbażat fuq bidliet fir-riżorsi. Fil-każ tagħna rridu noħolqu RoleBinding waqt li toħloq Namespace.

L-ewwelnett, ejja niddefinixxu l-funzjoni mainli jagħmel is-setup meħtieġ biex iħaddem id-dikjarazzjoni u mbagħad isejjaħ l-azzjoni tad-dikjarazzjoni:

(Nota. transl.: hawn u taħt il-kummenti fil-kodiċi huma tradotti għar-Russu. Barra minn hekk, l-indentazzjoni ġiet ikkoreġuta għal spazji minflok [rakkomandat f'Go] tabs biss għall-iskop ta' leġibilità aħjar fit-tqassim tal-Habr. Wara kull lista hemm links għall-oriġinal fuq GitHub, fejn jinħażnu kummenti u tabs bil-lingwa Ingliża.)

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.gopulzieri prima)

Aħna nagħmlu dan li ġej:

  1. Aħna kkonfigurat handler għal sinjali speċifiċi tas-sistema operattiva biex tikkawża t-terminazzjoni graceful tal-operatur.
  2. Aħna nużaw WaitGroupbiex twaqqaf bil-grazzja l-goroutines kollha qabel ittemm l-applikazzjoni.
  3. Aħna nipprovdu aċċess għall-cluster billi noħolqu clientset.
  4. Tnedija NamespaceController, li fiha se tkun tinsab il-loġika tagħna kollha.

Issa neħtieġu bażi għal-loġika, u fil-każ tagħna din hija dik li tissemma 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.gopulzieri prima)

Hawnhekk aħna kkonfigurat SharedIndexInformer, li effettivament (bl-użu ta' cache) tistenna għal bidliet fl-ispazji tal-isem (aqra aktar dwar informaturi fl-artiklu “Kif jaħdem l-iskedar ta' Kubernetes fil-fatt?"- madwar. traduzzjoni). Wara dan aħna nikkonnettjaw EventHandler lill-informatur, sabiex meta żżid spazju tal-isem (Namespace) tissejjaħ funzjoni createRoleBinding.

Il-pass li jmiss huwa li tiddefinixxi din il-funzjoni 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.gopulzieri prima)

Nirċievu l-ispazju tal-isem bħala obj u jaqilbuh għal oġġett Namespace. Imbagħad niddefinixxu RoleBinding, ibbażat fuq il-fajl YAML imsemmi fil-bidu, bl-użu tal-oġġett ipprovdut Namespace u l-ħolqien RoleBinding. Fl-aħħarnett, nilloggjaw jekk il-ħolqien kienx ta 'suċċess.

L-aħħar funzjoni li għandha tiġi definita hija 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.gopulzieri prima)

Hawnhekk qed nitkellmu WaitGroupli nniedu l-goroutine u mbagħad insejħu namespaceInformer, li ġie definit qabel. Meta jasal is-sinjal ta 'waqfien, se jispiċċa l-funzjoni, informa WaitGroup, li m'għadux esegwit, u din il-funzjoni se toħroġ.

Informazzjoni dwar il-bini u t-tħaddim ta' din id-dikjarazzjoni fuq cluster Kubernetes tista' tinstab fi repożitorji fuq GitHub.

Dak hu għall-operatur li joħloq RoleBinding meta Namespace fil-cluster Kubernetes, lest.

Sors: www.habr.com

Żid kumment