Nivîsandina operatorek ji bo Kubernetes li Golang

Not. werger.: Operator ji bo Kubernetes nermalava alîkar in, ku dema ku hin bûyer diqewimin ji bo otomatîkkirina pêkanîna kiryarên rûtîn li ser tiştên komê hatine çêkirin. Me berê li ser operatorên di nav de nivîsand vê gotara, li wir behsa raman û prensîbên bingehîn ên xebata xwe kirin. Lê heke ew materyal ji hêla xebitandina hêmanên amadekirî yên ji bo Kubernetes ve bêtir nêrînek bû, wê hingê wergera gotara nû ya ku nuha tê pêşniyar kirin jixwe vîzyona pêşdebirek / endezyarek DevOps e ku ji pêkanîna operatorek nû matmayî maye.

Nivîsandina operatorek ji bo Kubernetes li Golang

Min biryar da ku ez vê postê bi mînakek jiyanek rastîn binivîsim piştî hewildanên min ên ku ez belgeya li ser afirandina operatorek ji bo Kubernetes-ê bibînim, ku di xwendina kodê re derbas bû.

Mînaka ku dê were vegotin ev e: di koma meya Kubernetes de, her yek Namespace hawîrdora sandboxê ya tîmek temsîl dike, û me xwest ku gihîştina wan sînordar bikin da ku tîm tenê di sandboxên xwe de bilîzin.

Hûn dikarin tiştê ku hûn dixwazin bi destnîşankirina bikarhênerek komek ku heye bi dest bixin RoleBinding bi taybetî Namespace и ClusterRole bi mafên sererastkirinê. Nûnertiya YAML dê bi vî rengî xuya bike:

---
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.yamlin xavî)

Yek çêbikin RoleBinding Hûn dikarin wê bi destan bikin, lê piştî derbaskirina nîşana sed navan, ew dibe karekî bêzar. Li vir operatorên Kubernetes bi kêr têne - ew dihêlin ku hûn li ser bingeha guheztinên çavkaniyan çêkirina çavkaniyên Kubernetes otomatîk bikin. Di doza me de em dixwazin biafirînin RoleBinding dema afirandin Namespace.

Berî her tiştî, em fonksiyonê diyar bikin mainku sazkirina pêwîst dike da ku daxuyaniyê bimeşîne û dûv re banga çalakiya daxuyaniyê dike:

(Not. werger.: li vir û jêr şîroveyên di kodê de bi rûsî têne wergerandin. Zêdeyî vê yekê, xêzkirin li şûna tabloyên [di Go de tê pêşniyar kirin] tenê ji bo xwendina çêtir di nav xêzkirina Habrê de li cîhan hatiye rast kirin. Piştî her navnîşê lînkên orîjînal li ser GitHub hene, ku li wir şîrove û tabloyên bi zimanê Îngilîzî têne hilanîn.)

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()   // Ожидаем, что все остановлено
}

(serekî.goin xavî)

Em jêrîn dikin:

  1. Em ji bo îşaretên pergala xebitandinê ya taybetî rêvekerek mîheng dikin da ku bibe sedema bidawîbûna xweş a operator.
  2. Em bikar tînin WaitGroupberî ku serîlêdanê biqede, bi dilşewatî hemî gorutinan rawestînin.
  3. Em bi afirandinê ve gihîştina komê peyda dikin clientset.
  4. Destpêkirin NamespaceController, ku dê hemî mantiqa me tê de cih bigire.

Niha ji me re bingehek ji bo mantiqê hewce ye, û di rewşa me de ya ku hatî destnîşan kirin ev e 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.goin xavî)

Li vir em mîheng dikin SharedIndexInformer, ku dê bi bandor (bi karanîna cache) li benda guhertinên navên navan bimîne (di gotarê de li ser agahdarkeran bêtir bixwînin "Plansazkerê Kubernetes bi rastî çawa dixebite?"- approx. werger). Piştî vê yekê em girêdidin EventHandler ji agahdarker re, da ku gava navekî lê zêde bike (Namespace) fonksiyon tê gotin createRoleBinding.

Pêngava din ev e ku meriv vê fonksiyonê diyar bike 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.goin xavî)

Em cîhê navan wekî obj û wê biguherînin tiştekî Namespace. Piştre em diyar dikin RoleBinding, li ser bingeha pelê YAML ku di destpêkê de hatî behs kirin, bi karanîna tiştê hatî peyda kirin Namespace û afirandin RoleBinding. Di dawiyê de, em têkevin ka afirandin serketî bû.

Fonksîyona dawî ya ku tê diyarkirin ev e 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.goin xavî)

Li vir em dipeyivin WaitGroupku em gorutine dest pê bikin û paşê bang bikin namespaceInformer, ku berê hatiye diyarkirin. Dema ku sînyala rawestandinê tê, ew ê fonksiyonê biqedîne, agahdar bike WaitGroup, ku êdî nayê darve kirin, û ev fonksiyon dê derkeve.

Agahdariya li ser çêkirin û meşandina vê daxuyaniyê li ser komek Kubernetes dikare tê de were dîtin depoyên li ser GitHub.

Ji bo operatorê ku diafirîne ew e RoleBinding heke Namespace di koma Kubernetes de, amade ye.

Source: www.habr.com

Add a comment