Գոլանգում Kubernetes-ի համար օպերատոր գրել

Նշում. թարգմ.Օպերատորները Kubernetes-ի համար նախատեսված օժանդակ ծրագրեր են, որոնք նախատեսված են կլաստերի օբյեկտների վրա սովորական գործողությունների ավտոմատացման համար, երբ տեղի են ունենում որոշակի իրադարձություններ: Մենք արդեն գրել ենք օպերատորների մասին այս հոդվածը, որտեղ նրանք խոսեցին իրենց աշխատանքի հիմնարար գաղափարների ու սկզբունքների մասին։ Բայց եթե այդ նյութն ավելի շատ դիտվում էր Kubernetes-ի համար պատրաստի բաղադրիչների գործարկման կողմից, ապա այժմ առաջարկվող նոր հոդվածի թարգմանությունն արդեն մշակողի/DevOps ինժեների տեսլականն է, որը տարակուսած է նոր օպերատորի ներդրմամբ:

Գոլանգում Kubernetes-ի համար օպերատոր գրել

Ես որոշեցի գրել այս գրառումը իրական օրինակով Kubernetes-ի համար օպերատոր ստեղծելու վերաբերյալ փաստաթղթեր գտնելու իմ փորձերից հետո, որոնք անցել են կոդը ուսումնասիրելով:

Օրինակը, որը նկարագրվելու է, սա է. մեր Kubernetes կլաստերում յուրաքանչյուրը Namespace ներկայացնում է թիմի Sandbox միջավայրը, և մենք ցանկանում էինք սահմանափակել դրանց մուտքը, որպեսզի թիմերը կարողանան խաղալ միայն իրենց ավազատուփերում:

Դուք կարող եք հասնել այն ամենին, ինչ ցանկանում եք՝ օգտատիրոջը նշանակելով խումբ, որն ունի RoleBinding կոնկրետ Namespace и ClusterRole խմբագրման իրավունքով։ YAML-ի ներկայացուցչությունը կունենա հետևյալ տեսքը.

---
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Մեջ հում)

Ստեղծեք մեկը RoleBinding Դուք կարող եք դա անել ձեռքով, բայց հարյուր անվանատարածքների նշագիծը հատելուց հետո դա դառնում է հոգնեցուցիչ գործ: Սա այն վայրն է, որտեղ Kubernetes-ի օպերատորները հարմար են. նրանք թույլ են տալիս ավտոմատացնել Kubernetes-ի ռեսուրսների ստեղծումը՝ հիմնվելով ռեսուրսների փոփոխությունների վրա: Մեր դեպքում մենք ուզում ենք ստեղծել RoleBinding ստեղծագործելիս Namespace.

Նախ, եկեք սահմանենք գործառույթը mainորը կատարում է պահանջվող կարգավորումը հայտարարությունը գործարկելու համար և այնուհետև կանչում է հայտարարության գործողություն.

(Նշում. թարգմ.այստեղ և ներքևում կոդի մեկնաբանությունները թարգմանված են ռուսերեն: Բացի այդ, նահանջը ուղղվել է բացատների փոխարեն [խորհուրդ է տրվում Go] ներդիրների փոխարեն բացառապես Habr դասավորության շրջանակներում ավելի լավ ընթեռնելի լինելու նպատակով: Յուրաքանչյուր ցուցակից հետո կան հղումներ դեպի բնօրինակը GitHub-ում, որտեղ պահվում են անգլերեն մեկնաբանությունները և ներդիրները:)

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Մեջ հում)

Մենք անում ենք հետևյալը.

  1. Մենք կարգավորում ենք կարգավորիչը օպերացիոն համակարգի հատուկ ազդանշանների համար՝ օպերատորի նրբագեղ դադարեցման համար:
  2. Մենք օգտագործում ենք WaitGroupհայտը դադարեցնելուց առաջ նրբորեն դադարեցնել բոլոր գորուտինները:
  3. Մենք ապահովում ենք մուտք դեպի կլաստեր՝ ստեղծելով clientset.
  4. Մենք մեկնարկում ենք NamespaceController, որի մեջ կգտնվի մեր ողջ տրամաբանությունը։

Հիմա տրամաբանության հիմք է պետք, իսկ մեր դեպքում սա նշվածն է 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Մեջ հում)

Այստեղ մենք կարգավորում ենք SharedIndexInformer, որն արդյունավետորեն (օգտագործելով քեշ) կսպասի անվանատարածքների փոփոխություններին (կարդացեք ավելին տեղեկատուների մասին հոդվածում»Ինչպե՞ս է իրականում աշխատում Kubernetes-ի ժամանակացույցը:- մոտ. թարգմանություն). Դրանից հետո մենք կապում ենք EventHandler տեղեկատուին, որպեսզի անվանատարածք ավելացնելիս (Namespace) ֆունկցիան կոչվում է createRoleBinding.

Հաջորդ քայլը այս գործառույթի սահմանումն է 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Մեջ հում)

Մենք ստանում ենք անվանումների տարածքը որպես obj և այն վերածել օբյեկտի Namespace. Այնուհետև մենք սահմանում ենք RoleBinding, սկզբում նշված YAML ֆայլի հիման վրա՝ օգտագործելով տրամադրված օբյեկտը Namespace և ստեղծելով RoleBinding. Ի վերջո, մենք գրանցում ենք, թե արդյոք ստեղծումը հաջող էր:

Վերջին գործառույթը, որը պետք է սահմանվի 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Մեջ հում)

Այստեղ մենք խոսում ենք WaitGroupոր մենք գործարկում ենք գորուտինը և հետո զանգում namespaceInformer, որը նախկինում սահմանվել է։ Երբ կանգառի ազդանշանը հասնի, այն կավարտի գործառույթը, տեղեկացրեք WaitGroup, որն այլևս չի կատարվում, և այս ֆունկցիան դուրս կգա:

Kubernetes կլաստերի վրա այս հայտարարությունը կառուցելու և գործարկելու մասին տեղեկությունները կարելի է գտնել այստեղ պահոցներ GitHub-ում.

Դա այն օպերատորի համար է, որը ստեղծում է RoleBinding երբ Namespace Kubernetes կլաստերում, պատրաստ է:

Source: www.habr.com

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