په ګولنګ کې د کبرنیټس لپاره د آپریټر لیکل

نوټ. ژباړه: آپریټرونه د Kubernetes لپاره مرستندویه سافټویر دي، د کلستر شیانو په اړه د معمول کړنو اجرا کولو اتومات کولو لپاره ډیزاین شوی کله چې ځینې پیښې واقع کیږي. موږ دمخه د آپریټرانو په اړه لیکلي دي دا مقاله، چیرته چې دوی د خپل کار د بنسټیزو نظرونو او اصولو په اړه خبرې وکړې. مګر که دا مواد د کوبرنیټس لپاره د چمتو شوي اجزاو عملیات کولو اړخ څخه ډیر لید و ، نو د نوې مقالې ژباړه اوس وړاندیز شوې لا دمخه د پراختیا کونکي / DevOps انجینر لید دی چې د نوي آپریټر پلي کولو لخوا حیران شوی.

په ګولنګ کې د کبرنیټس لپاره د آپریټر لیکل

ما پریکړه وکړه چې دا پوسټ د ریښتیني ژوند مثال سره ولیکم وروسته له دې چې زما د کوبرنیټس لپاره د آپریټر رامینځته کولو په اړه د اسنادو موندلو هڅو وروسته ، کوم چې د کوډ مطالعې څخه تیر شو.

هغه مثال چې به یې تشریح شي دا دی: زموږ د کوبرنیټس کلستر کې، هر یو 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 تاسو کولی شئ دا په لاسي ډول ترسره کړئ، مګر د سوو نوم ځایونو نښه کولو وروسته، دا یو ستړی کار کیږي. دا هغه ځای دی چې د کوبرنیټس آپریټرونه په کار کې راځي — دوی تاسو ته اجازه درکوي د سرچینو بدلونونو پراساس د Kubernetes سرچینو رامینځته کول اتومات کړئ. زموږ په قضیه کې موږ غواړو جوړ کړو 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
}

(controller.goپه خام)

دلته موږ ترتیب کوو SharedIndexInformer، کوم چې به په مؤثره توګه (د کیچ په کارولو سره) په نوم ځایونو کې بدلونونو ته انتظار باسي (په مقاله کې د خبر ورکوونکو په اړه نور ولولئ "د کبرنیټس مهالویش واقعیا څنګه کار کوي؟"- نږدې ژباړه). له دې وروسته موږ وصل کوو 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 کلستر کې، چمتو دی.

سرچینه: www.habr.com

Add a comment