Schreiwen engem Bedreiwer fir Kubernetes zu Golang

Note. iwwersat.: Bedreiwer sinn Hëllefssoftware fir Kubernetes, entwéckelt fir d'Ausféierung vu Routineaktiounen op Clusterobjekter ze automatiséieren wann verschidden Eventer optrieden. Mir hu schonn iwwer Opérateuren geschriwwen an dësen Artikel, wou si iwwer déi fundamental Iddien a Prinzipien vun hirer Aarbecht geschwat hunn. Awer wann dat Material méi eng Vue war vun der Säit vun der Operatioun vu fäerdege Komponenten fir Kubernetes, dann ass d'Iwwersetzung vum neien Artikel elo proposéiert schonn d'Visioun vun engem Entwéckler / DevOps Ingenieur, deen duerch d'Ëmsetzung vun engem neie Bedreiwer verwonnert ass.

Schreiwen engem Bedreiwer fir Kubernetes zu Golang

Ech hu beschloss dëse Post mat engem richtege Beispill ze schreiwen no menge Versuche fir Dokumentatioun ze fannen fir e Bedreiwer fir Kubernetes ze kreéieren, deen duerch de Code studéiert ass.

D'Beispill dat beschriwwe gëtt ass dëst: an eisem Kubernetes Cluster, jidderee Namespace stellt d'Sandkëschtëmfeld vun enger Equipe duer, a mir wollten den Zougang zu hinnen limitéieren, fir datt d'Equipen nëmmen an hiren eegene Sandkëschte spille kënnen.

Dir kënnt erreechen wat Dir wëllt andeems Dir engem Benotzer eng Grupp zougewisen huet, déi huet RoleBinding zu spezifesch Namespace и ClusterRole mat Redaktioun Rechter. D'YAML Representatioun wäert esou ausgesinn:

---
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, an rau)

Schafen eng RoleBinding Dir kënnt et manuell maachen, awer nodeems Dir déi honnert Nummraim markéiert hutt, gëtt et eng langweileg Aufgab. Dëst ass wou Kubernetes Bedreiwer praktesch kommen - si erlaben Iech d'Schafung vu Kubernetes Ressourcen ze automatiséieren op Basis vun Ännerungen an de Ressourcen. An eisem Fall wëlle mir schafen RoleBinding beim Schafen Namespace.

Als éischt, loosst eis d'Funktioun definéieren maindéi de erfuerderleche Setup mécht fir d'Ausso auszeféieren an dann d'Aussoaktioun rufft:

(Note. iwwersat.: hei an ënnen d'Kommentaren am Code sinn op Russesch iwwersat. Zousätzlech ass d'Indentatioun op Plazen korrigéiert anstatt [recommandéiert a Go] Tabs eleng fir den Zweck vun enger besserer Liesbarkeet am Habr Layout. No all Oplëschtung ginn et Linken op d'Original op GitHub, wou engleschsproocheg Kommentarer a Tabs gespäichert sinn.)

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.goen, an rau)

Mir maachen déi folgend:

  1. Mir konfiguréieren en Handler fir spezifesch Betribssystem Signaler fir eng graziéis Kënnegung vum Bedreiwer ze verursaachen.
  2. Mir benotzen WaitGroupfir all Goroutine graziéis ze stoppen ier Dir d'Applikatioun ofschléisst.
  3. Mir bidden Zougang zum Stärekoup duerch Schafung clientset.
  4. Lancéiere NamespaceController, an deem all eis Logik wäert sinn.

Elo brauche mir eng Basis fir d'Logik, an an eisem Fall ass dat déi genannt 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.goen, an rau)

Hei konfiguréieren mir SharedIndexInformer, déi effektiv (mat engem Cache) op Ännerungen an den Nummraim waarden (liest méi iwwer Informateuren am Artikel "Wéi funktionnéiert de Kubernetes Scheduler eigentlech?"- ca. Iwwersetzung). Duerno verbannen mir EventHandler dem Informateur, sou datt wann Dir en Nummraum derbäisetzt (Namespace) Funktioun genannt gëtt createRoleBinding.

De nächste Schrëtt ass dës Funktioun ze definéieren 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.goen, an rau)

Mir kréien den Nummraum als obj a konvertéiert et an en Objet Namespace. Dann definéieren mir RoleBinding, baséiert op der YAML-Datei, déi am Ufank erwähnt gouf, mat dem geliwwertem Objet Namespace an schafen RoleBinding. Schlussendlech protokolléiere mir ob d'Kreatioun erfollegräich war.

Déi lescht Funktioun déi definéiert gëtt ass 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.goen, an rau)

Hei schwätze mer WaitGroupdatt mir d'Goroutine starten an dann ruffen namespaceInformer, déi virdru definéiert gouf. Wann d'Stoppsignal ukomm ass, wäert et d'Funktioun ophalen, informéieren WaitGroup, déi net méi ausgefouert gëtt, an dës Funktioun wäert ausgoen.

Informatioun iwwer d'Bauen an d'Ausféierung vun dëser Ausso op engem Kubernetes-Cluster fannt Dir an Repositories op GitHub.

Dat ass et fir de Bedreiwer deen erstellt RoleBinding op Erscheinung Namespace am Kubernetes Stärekoup, prett.

Source: will.com

Setzt e Commentaire