Golang ۾ Kubernetes لاء هڪ آپريٽر لکڻ

نوٽ. ترجمو: آپريٽرز Kubernetes لاءِ معاون سافٽ ويئر آهن، جيڪي ڪلسٽر آبجیکٹ تي معمولي عملن جي عمل کي خودڪار ڪرڻ لاءِ ٺهيل آهن جڏهن ڪجهه واقعا ٿين ٿا. اسان اڳ ۾ ئي آپريٽرز بابت لکيو آهي اهو مضمون، جتي انهن پنهنجي ڪم جي بنيادي خيالن ۽ اصولن بابت ڳالهايو. پر جيڪڏهن اهو مواد ڪبرنيٽس لاءِ تيار ڪيل اجزاء کي هلائڻ جي پاسي کان وڌيڪ نظريو هو، ته پوءِ نئين آرٽيڪل جو ترجمو هاڻي پيش ڪيو ويو آهي اڳ ۾ ئي هڪ ڊولپر/DevOps انجنيئر جو خواب آهي جيڪو نئين آپريٽر جي عمل درآمد سان حيران ٿي ويو آهي.

Golang ۾ Kubernetes لاء هڪ آپريٽر لکڻ

مون ڪبرنيٽس لاءِ آپريٽر ٺاهڻ تي دستاويز ڳولڻ جي ڪوشش کان پوءِ هن پوسٽ کي حقيقي زندگي جي مثال سان لکڻ جو فيصلو ڪيو، جيڪو ڪوڊ جي مطالعي مان گذريو.

مثال جيڪو بيان ڪيو ويندو اهو آهي: اسان جي ڪبرنيٽس ڪلستر ۾، هر هڪ Namespace ھڪڙي ٽيم جي سينڊ باڪس ماحول جي نمائندگي ڪري ٿي، ۽ اسان انھن تائين رسائي کي محدود ڪرڻ چاھيو ٿا ته جيئن ٽيمون صرف پنھنجي سينڊ باڪس ۾ راند ڪري سگھن.

توھان حاصل ڪري سگھو ٿا جيڪو توھان چاھيو ٿا صارف کي تفويض ڪندي ھڪڙي گروپ کي جيڪو آھي 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 توهان اهو دستي طور تي ڪري سگهو ٿا، پر سو نالو اسپيس جي نشان کي پار ڪرڻ کان پوء، اهو هڪ مشڪل ڪم بڻجي ويندو آهي. هي اهو آهي جتي ڪبرنيٽس آپريٽرز ڪم ۾ اچن ٿا- اهي توهان کي اجازت ڏين ٿا ته ڪبرنيٽس وسيلن جي تخليق کي خودڪار ڪرڻ جي بنياد تي وسيلن ۾ تبديليون. اسان جي صورت ۾ اسان ٺاهڻ چاهيون ٿا RoleBinding ٺاهڻ دوران Namespace.

سڀ کان پهريان، اچو ته فنڪشن جي وضاحت ڪريون mainجيڪو بيان کي هلائڻ لاءِ گهربل سيٽ اپ ڪري ٿو ۽ پوءِ بيان عمل کي سڏي ٿو:

(نوٽ. ترجمو: هتي ۽ هيٺ ڏنل تبصرا ڪوڊ ۾ ترجمو ڪيا ويا آهن روسي ۾. ان کان علاوه، انڊينٽيشن کي درست ڪيو ويو آهي خالن جي بجاءِ [گو ۾ تجويز ڪيل] ٽيب جي مقصد لاءِ صرف هيبر جي ترتيب ۾ بهتر پڙهڻ جي. هر لسٽنگ کان پوءِ 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
}

(ڪنٽرولر.go۾ را)

هتي اسان ترتيب ڏيون ٿا SharedIndexInformer، جيڪو مؤثر طور تي (ڪيش استعمال ڪندي) نالي جي جڳھن ۾ تبديلين جو انتظار ڪندو (مضمون ۾ ڄاڻ ڏيڻ وارن بابت وڌيڪ پڙهو "ڪبرنيٽس شيڊولر اصل ۾ ڪيئن ڪم ڪندو آهي؟"- لڳ ڀڳ ترجمو). ان کان پوء اسان ڳنڍيندا آهيون EventHandler informer ڏانهن، ته جيئن هڪ نالي جي جاء شامل ڪرڻ وقت (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))
  }
}

(ڪنٽرولر.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
}

(ڪنٽرولر.go۾ را)

هتي اسان ڳالهائي رهيا آهيون WaitGroupته اسان گوروٽين شروع ڪريون ۽ پوءِ ڪال ڪريون namespaceInformer، جنهن جي اڳ ۾ وضاحت ڪئي وئي آهي. جڏهن اسٽاپ سگنل اچي ٿو، اهو فنڪشن ختم ڪندو، ڄاڻ ڏيو WaitGroup, جنهن کي هاڻي جاري نه ڪيو ويو آهي، ۽ هي فنڪشن نڪرندو.

ڪبرنيٽس ڪلستر تي هن بيان جي تعمير ۽ هلائڻ بابت معلومات ملي سگهي ٿي GitHub تي ذخيرو.

اھو اھو آھي جيڪو ٺاھيندڙ آپريٽر لاءِ RoleBinding ڪڏهن Namespace ڪبرنيٽس ڪلستر ۾، تيار.

جو ذريعو: www.habr.com

تبصرو شامل ڪريو