Golanqda Kubernetes üçün operator yazırıq

Qeyd. tərcümə.: Operatorlar müəyyən hadisələr zamanı klaster obyektlərində adi hərəkətlərin icrasını avtomatlaşdırmaq üçün nəzərdə tutulmuş Kubernetes üçün köməkçi proqramdır. Artıq operatorlar haqqında yazmışıq Bu məqaləburada öz işlərinin fundamental ideyaları və prinsipləri haqqında danışdılar. Ancaq bu material daha çox Kubernetes üçün hazır komponentlərin işləməsi baxımından bir görünüş idisə, indi təklif olunan yeni məqalənin tərcüməsi artıq yeni bir operatorun tətbiqi ilə çaşqın olan bir inkişaf etdiricinin / DevOps mühəndisinin vizyonudur. .

Golanqda Kubernetes üçün operator yazırıq

Kubernetes üçün operator yaratmaq üçün sənədləri tapmaq cəhdlərim kodun öyrənilməsindən keçdikdən sonra bu yazını real həyat nümunəsi ilə yazmaq qərarına gəldim.

Təsvir ediləcək nümunə belədir: Kubernetes klasterimizdə hər biri Namespace komandanın sandbox mühitini təmsil edir və biz onlara girişi məhdudlaşdırmaq istədik ki, komandalar yalnız öz qum qutularında oynaya bilsinlər.

Sahib olduğu qrupa istifadəçi təyin etməklə istədiyinizə nail ola bilərsiniz RoleBinding konkretə Namespace и ClusterRole redaktə hüququ ilə. YAML təqdimatı belə görünəcək:

---
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 bağlama.yaml, in xam)

Belə yaradın RoleBinding bunu əl ilə edə bilərsiniz, lakin yüzdən çox ad sahəsi əldə etdikdən sonra bu, yorucu bir işə çevrilir. Burada Kubernetes operatorları kömək edir - onlar sizə resurslardakı dəyişikliklər əsasında Kubernetes resurslarının yaradılmasını avtomatlaşdırmağa imkan verir. Bizim vəziyyətimizdə biz yaratmaq istəyirik RoleBinding yaratarkən Namespace.

Əvvəlcə funksiyanı təyin edək main, bəyanatı işə salmaq üçün tələb olunan quraşdırmanı edir və sonra bəyanat hərəkətini çağırır:

(Qeyd. tərcümə.: bundan sonra koddakı şərhlər rus dilinə tərcümə olunur. Bundan əlavə, abzas yalnız Habr tərtibatı çərçivəsində daha yaxşı oxunaqlılıq məqsədilə [Get-də tövsiyə olunur] tabları əvəzinə boşluqlar üçün düzəldilir. Hər siyahıdan sonra GitHub-da orijinala keçidlər var, burada ingilis dilində şərhlər və nişanlar saxlanılır.)

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

Biz aşağıdakıları edirik:

  1. Operatorun zərif şəkildə çıxmasına səbəb olmaq üçün xüsusi əməliyyat sistemi siqnalları üçün işləyici qurduq.
  2. Biz istifadə edirik WaitGroupproqram bitməzdən əvvəl bütün goroutinləri zərif şəkildə dayandırmaq.
  3. Yaratmaqla klasterə girişi təmin edirik clientset.
  4. Başlat NamespaceController, bütün məntiqimizin yerləşəcəyi.

İndi məntiq üçün əsas lazımdır və bizim vəziyyətimizdə qeyd olunandır 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 xam)

Budur, biz təyin edirik SharedIndexInformer, bu, səmərəli şəkildə (keşdən istifadə etməklə) ad sahəsinin dəyişməsini gözləyəcək (məqalədə məlumat verənlər haqqında daha çox oxuyun "Kubernetes planlaşdırıcısı əslində necə işləyir?- təqribən. tərcümə.). Bundan sonra bağlanırıq EventHandler məlumat verənə, bunun sayəsində ad sahəsi əlavə edərkən (Namespace) funksiyası çağırılır createRoleBinding.

Növbəti addım bu funksiyanı təyin etməkdir 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 xam)

Biz ad sahəsini alırıq obj və onu obyektə çevirin Namespace. Sonra müəyyənləşdiririk RoleBinding, təqdim olunan obyektdən istifadə edərək, əvvəlində qeyd olunan YAML faylı əsasında Namespace və yaratmaq RoleBinding. Nəhayət, yaradılışın uğurlu olub olmadığını qeyd edirik.

Müəyyən ediləcək son funksiya − 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 xam)

Burada söhbət edirik WaitGroupki, biz goroutine başlayır və sonra zəng namespaceInformerəvvəllər müəyyən edilmişdi. Dayanma siqnalı daxil olduqda, o, funksiyanı dayandıracaq, məlumatlandırın WaitGroup, artıq icra olunmur və bu funksiya çıxacaq.

Bu bəyanatı Kubernetes klasterində qurmaq və işlətmək haqqında məlumatı burada tapa bilərsiniz GitHub-da depolar.

Yaradan bu ifadə üzərinə RoleBinding nə vaxt Namespace Kubernetes klasterində hazırdır.

Mənbə: www.habr.com

Добавить комментарий