Kubernetes-erako operadore bat idazten Golang-en

Ohar. itzul.: Eragileak Kubernetesentzako software laguntzaileak dira, gertaera jakin batzuk gertatzen direnean kluster-objektuetan ohiko ekintzak automatizatzeko diseinatuta. Dagoeneko idatzi dugu operadoreei buruz Artikulu honetan, non euren lanaren oinarrizko ideia eta printzipioei buruz hitz egin zuten. Baina material hori Kubernetesentzako prest egindako osagaiak ustiatzearen aldetik ikuspegi bat gehiago bazen, orain proposatzen den artikulu berriaren itzulpena operadore berri baten ezarpenak harrituta dagoen garatzaile/DevOps ingeniari baten ikuspegia da dagoeneko.

Kubernetes-erako operadore bat idazten Golang-en

Argitalpen hau benetako adibide batekin idaztea erabaki nuen Kubernetes-erako operadore bat sortzeko dokumentazioa aurkitzeko saiakeraren ostean, kodea aztertzen joan zena.

Deskribatuko den adibidea hau da: gure Kubernetes klusterrean, bakoitza Namespace talde baten sandbox ingurunea adierazten du, eta haietarako sarbidea mugatu nahi genuen, taldeek beren sandboxetan soilik jokatu ahal izateko.

Nahi duzuna lor dezakezu erabiltzaile bati duen talde bat esleituz RoleBinding zehatzera Namespace ΠΈ ClusterRole edizio eskubideekin. YAML irudikapenak itxura hau izango du:

---
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

(rol-lotura.yamlin gordinak)

Sortu bat RoleBinding Eskuz egin dezakezu, baina ehun izen-espazio marka gainditu ondoren, lan aspergarria bihurtzen da. Hona hemen Kuberneteseko operadoreak erabilgarriak: baliabideen aldaketetan oinarrituta Kubernetes baliabideen sorrera automatizatzeko aukera ematen dute. Gure kasuan sortu nahi dugu RoleBinding sortu bitartean Namespace.

Lehenik eta behin, defini dezagun funtzioa mainadierazpena exekutatzeko beharrezko konfigurazioa egiten duena eta, ondoren, adierazpen-ekintza deitzen duena:

(Ohar. itzul.: hemen eta azpian kodean iruzkinak errusierara itzulita daude. Horrez gain, koska zuriuneetara zuzendu da [Go-n gomendatua] fitxen ordez, Habr diseinuaren barruan irakurgarritasun hobea izateko soilik. Zerrenda bakoitzaren ondoren GitHub-en jatorrizkorako estekak daude, non ingeleseko iruzkinak eta fitxak gordetzen diren.

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()   // ОТидаСм, Ρ‡Ρ‚ΠΎ всС остановлСно
}

(nagusi.goin gordinak)

Honako hau egiten dugu:

  1. Sistema eragilearen seinale zehatzetarako kudeatzaile bat konfiguratzen dugu operadorearen amaiera dotorea eragiteko.
  2. Erabiltzen dugu WaitGroupaplikazioa amaitu aurretik goroutine guztiak dotorez gelditzeko.
  3. Klustererako sarbidea ematen dugu sortuz clientset.
  4. korrika NamespaceController, bertan kokatuko da gure logika guztia.

Orain logikaren oinarri bat behar dugu, eta gure kasuan hauxe da aipatutakoa 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
}

(kontrolatzailea.joanin gordinak)

Hemen konfiguratzen dugu SharedIndexInformer, eta horrek modu eraginkorrean (cache bat erabiliz) itxarongo du izen-espazioen aldaketei (irakur ezazu informatzaileei buruz gehiago artikuluan "Nola funtzionatzen du Kubernetes programatzaileak?"- gutxi gorabehera. itzulpena). Honen ostean konektatzen gara EventHandler informatzaileari, izen-espazio bat gehitzean (Namespace) funtzioari deitzen zaio createRoleBinding.

Hurrengo urratsa funtzio hori definitzea da 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))
  }
}

(kontrolatzailea.joanin gordinak)

Izen-espazioa honela lortzen dugu obj eta objektu bihurtu Namespace. Orduan definitzen dugu RoleBinding, hasieran aipatutako YAML fitxategian oinarrituta, emandako objektua erabiliz Namespace eta sortuz RoleBinding. Azkenik, sorrera arrakastatsua izan den erregistratzen dugu.

Definitu beharreko azken funtzioa da 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
}

(kontrolatzailea.joanin gordinak)

Hemen ari gara hizketan WaitGroupgoroutina martxan jarri eta gero deitzen dugula namespaceInformer, aurretik definitu dena. Gelditzeko seinalea iristen denean, funtzioa amaituko du, jakinarazi WaitGroup, jada exekutatzen ez dena, eta funtzio hau irtengo da.

Adierazpen hau Kubernetes kluster batean eraikitzeari eta exekutatzeko informazioa hemen aurki daiteke biltegiak GitHub-en.

Hori da sortzen duen operadorearentzat RoleBinding noiz Namespace Kubernetes klusterrean, prest.

Iturria: www.habr.com

Gehitu iruzkin berria