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

Qeyd. tərcümə.Operatorlar müəyyən hadisələr baş verdikdə klaster obyektlərində gündəlik hərəkətləri avtomatlaşdırmaq üçün nəzərdə tutulmuş Kubernetes üçün köməkçi proqramdır. Biz artıq operatorlar haqqında yazmışıq Bu məqaləəsas ideyaları və fəaliyyət prinsiplərini müzakirə edən . Lakin bu material hazır Kubernetes komponentlərinin istismarı baxımından daha çox perspektiv olsa da, bu yeni məqalənin təklif olunan tərcüməsi yeni operatorun tətbiqi ilə çaşqın qalan bir inkişaf etdiricinin/DevOps mühəndisinin perspektividir.

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

Kubernetes üçün operator yaratmaq üçün sənədləri tapmaq cəhdlərimdən sonra bu yazını real dünya nümunəsi ilə yazmaq qərarına gəldim və bu, kodu öyrənməyimə səbəb oldu.

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.

İstənilən nəticə istifadəçini olan qrupa təyin etməklə əldə edilə bilər 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ə yaratmaq RoleBinding Bunu əl ilə edə bilərsiniz, lakin 100 ad sahəsi nişanını keçdikdən sonra bu, yorucu olur. Burada Kubernetes operatorları kömək edir – onlar sizə resurs dəyişiklikləri ə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 mainoperatoru işə salmaq üçün tələb olunan quraşdırmanı yerinə yetirir və sonra operatorun hərəkətini çağırır:

(Qeyd. tərcümə.: Bundan sonra koddakı şərhlər rus dilinə tərcümə edilmişdir. Əlavə olaraq, abzaslar yalnız Habr tərtibatında oxunaqlılığı yaxşılaşdırmaq məqsədilə [Get-də tövsiyə olunur] nişanlar əvəzinə boşluqlara dəyişdirilib. Hər bir siyahıdan sonra ingiliscə şərhlər və nişanlar qorunub saxlanılan orijinal GitHub koduna keçidlər var.

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ə dayandırılmasına səbəb olmaq üçün xüsusi əməliyyat sistemi siqnalları üçün işləyicini konfiqurasiya edirik.
  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)

Burada qurduq SharedIndexInformer, bu, səmərəli şəkildə (keşdən istifadə etməklə) ad boşluqlarında dəyişiklikləri gözləyəcək (məqalədə məlumat verənlər haqqında daha çox oxuyunKubernetes 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ə, belə ki, 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ə çevirmək Namespace. Sonra müəyyən edirik RoleBinding, təqdim olunan obyektdən istifadə edərək, əvvəlində qeyd olunan YAML faylı əsasında Namespace və yaratmaq RoleBindingNəhayət, yaradılışın uğurlu olub olmadığını qeyd edirik.

Müəyyən edilməli olan son funksiyadır 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 danışırıq WaitGroup, biz goroutine başlamaq və sonra zəng ki, namespaceInformerəvvəllər müəyyən edilmişdi. Dayanma siqnalı qəbul edildikdə, o, funksiyanı, hesabatı dayandıracaq WaitGroup, artıq işləmir və bu funksiya dayandırılacaq.

Bu operatoru Kubernetes klasterində qurmaq və idarə etmək haqqında məlumatı burada tapa bilərsiniz GitHub-da depolar.

Yaradan bu operatorda RoleBinding görünüşünə görə Namespace Kubernetes klasterində hazırdır.

Mənbə: www.habr.com

DDoS mühafizəsi, VPS VDS serverləri olan saytlar üçün etibarlı hostinq alın 🔥 DDoS qorunması, VPS VDS serverləri ilə etibarlı veb sayt hostinqi alın | ProHoster