Golangdagi Kubernetes uchun operator yozish

Eslatma. tarjima.: Operatorlar Kubernetes uchun yordamchi dasturiy ta'minot bo'lib, ma'lum hodisalar sodir bo'lganda klaster ob'ektlarida muntazam harakatlarni bajarishni avtomatlashtirish uchun mo'ljallangan. Biz allaqachon operatorlar haqida yozgan edik Ushbu maqola, bu erda ular o'z faoliyatining asosiy g'oyalari va tamoyillari haqida gapirdilar. Ammo agar bu material Kubernetes uchun tayyor komponentlarni ishlatish nuqtai nazaridan ko'proq bo'lgan bo'lsa, unda yangi maqolaning hozir taklif qilinayotgan tarjimasi allaqachon yangi operatorni amalga oshirishdan hayratda qolgan ishlab chiquvchi/DevOps muhandisining tasavvuridir.

Golangdagi Kubernetes uchun operator yozish

Kodni o'rganishdan o'tgan Kubernetes uchun operator yaratish bo'yicha hujjatlarni topishga urinishlarimdan so'ng, men ushbu postni hayotiy misol bilan yozishga qaror qildim.

Ta'riflanadigan misol bu: bizning Kubernetes klasterimizda, har biri Namespace jamoaning sandbox muhitini ifodalaydi va biz ularga kirishni cheklashni xohladik, shunda jamoalar faqat o'zlarining sandboxlarida o'ynashlari mumkin.

Foydalanuvchiga guruhni tayinlash orqali siz xohlagan narsangizga erishishingiz mumkin RoleBinding aniqlikka Namespace ΠΈ ClusterRole tahrir qilish huquqi bilan. YAML taqdimoti quyidagicha ko'rinadi:

---
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, in xom)

Bir yarating RoleBinding Siz buni qo'lda qilishingiz mumkin, lekin yuzta nom maydoni belgisini kesib o'tganingizdan so'ng, bu zerikarli vazifaga aylanadi. Bu erda Kubernetes operatorlari yordam beradi β€” ular resurslarga o'zgartirishlar asosida Kubernetes resurslarini yaratishni avtomatlashtirish imkonini beradi. Bizning holatlarimizda biz yaratmoqchimiz RoleBinding yaratish paytida Namespace.

Avvalo, funksiyani aniqlaymiz mainbayonotni ishga tushirish uchun kerakli sozlashni amalga oshiradi va keyin bayonot harakatini chaqiradi:

(Eslatma. tarjima.: bu yerda va quyida koddagi izohlar rus tiliga tarjima qilingan. Bundan tashqari, chekinish faqat Habr tartibida yaxshiroq o'qilishi uchun [O'tish-da tavsiya etilgan] yorliqlari o'rniga bo'shliqlarga tuzatildi. Har bir ro'yxatdan so'ng GitHub-da ingliz tilidagi sharhlar va yorliqlar saqlanadigan asl nusxaga havolalar mavjud.)

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.go, in xom)

Biz quyidagilarni bajaramiz:

  1. Operatorni oqilona tugatishga olib keladigan muayyan operatsion tizim signallari uchun ishlov beruvchini sozlaymiz.
  2. Biz foydalanamiz WaitGroupilovani tugatishdan oldin barcha gorutinlarni ehtiyotkorlik bilan to'xtatish.
  3. Biz yaratish orqali klasterga kirishni ta'minlaymiz clientset.
  4. Ishga tushirish NamespaceController, unda bizning barcha mantiqimiz joylashgan bo'ladi.

Endi biz mantiq uchun asosga muhtojmiz va bizning holatlarimizda bu aytilgan 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.go, in xom)

Bu erda biz konfiguratsiya qilamiz SharedIndexInformer, bu samarali (kesh yordamida) nomlar bo'shliqlarida o'zgarishlarni kutadi (axborotchilar haqida ko'proq maqolada o'qing"Kubernetes rejalashtiruvchisi aslida qanday ishlaydi?- taxminan. tarjima). Shundan so'ng biz ulanamiz EventHandler ma'lumot beruvchiga, shuning uchun nom maydoni qo'shganda (Namespace) funksiya chaqiriladi createRoleBinding.

Keyingi qadam bu funktsiyani aniqlashdir 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.go, in xom)

Biz nom maydonini olamiz obj va uni ob'ektga aylantiring Namespace. Keyin aniqlaymiz RoleBinding, boshida aytib o'tilgan YAML fayliga asoslanib, taqdim etilgan ob'ektdan foydalangan holda Namespace va yaratish RoleBinding. Nihoyat, biz yaratish muvaffaqiyatli bo'lganligini qayd qilamiz.

Belgilanishi kerak bo'lgan oxirgi funktsiya 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.go, in xom)

Mana biz gaplashamiz WaitGroupbiz goroutinni ishga tushiramiz va keyin qo'ng'iroq qilamiz namespaceInformer, bu avvalroq aniqlangan. To'xtash signali kelganda, u funktsiyani tugatadi, xabar bering WaitGroup, bu endi bajarilmaydi va bu funktsiya o'chadi.

Ushbu bayonotni Kubernetes klasterida yaratish va ishga tushirish haqida ma'lumotni quyidagi sahifada topishingiz mumkin GitHub-dagi omborlar.

Bu yaratuvchi operator uchun RoleBinding qachon Namespace Kubernetes klasterida tayyor.

Manba: www.habr.com

a Izoh qo'shish