Nulis operator pikeun Kubernetes di Golang

Catetan. narjamahkeun.: Operator mangrupakeun software bantu pikeun Kubernetes, dirancang pikeun ngajadikeun otomatis palaksanaan lampah rutin dina objék klaster lamun kajadian tangtu lumangsung. Kami parantos nyerat ngeunaan operator di artikel ieu, dimana aranjeunna ngobrol ngeunaan gagasan dasar sarta prinsip karya maranéhanana. Tapi lamun bahan éta leuwih ti pintonan ti sisi operasi komponén siap-dijieun pikeun Kubernetes, lajeng tarjamah tina artikel anyar ayeuna diusulkeun geus visi ti developer / insinyur DevOps puzzled ku palaksanaan operator anyar.

Nulis operator pikeun Kubernetes di Golang

Kuring mutuskeun nulis pos ieu kalawan conto real-hirup sanggeus usaha kuring pikeun manggihan dokuméntasi dina nyieun hiji operator pikeun Kubernetes, nu indit ngaliwatan diajar kode.

Conto anu bakal dijelaskeun nyaéta kieu: dina klaster Kubernetes kami, masing-masing Namespace ngagambarkeun lingkungan sandbox tim urang, sarta kami hayang ngawatesan aksés ka aranjeunna supados tim ngan bisa maénkeun dina sandboxes sorangan.

Anjeun tiasa ngahontal naon anu anjeun pikahoyong ku masihan pangguna grup anu gaduh RoleBinding pikeun husus Namespace и ClusterRole kalawan hak ngédit. Perwakilan YAML bakal katingali sapertos kieu:

---
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.yamldi atah)

Jieun hiji RoleBinding Anjeun tiasa ngalakukeunana sacara manual, tapi saatos nyebrang saratus nami rohangan, éta janten tugas anu pikasieuneun. Ieu tempat operator Kubernetes tiasa dianggo-aranjeunna ngamungkinkeun anjeun pikeun ngajadikeun otomatis nyiptakeun sumber daya Kubernetes dumasar kana parobihan sumber. Bisi kami urang rék nyieun RoleBinding bari nyieun Namespace.

Anu mimiti, hayu urang nangtukeun fungsi mainanu ngalakukeun pangaturan anu diperyogikeun pikeun ngajalankeun pernyataan teras nyauran tindakan pernyataan:

(Catetan. narjamahkeun.: Ieuh jeung handap komentar dina kode nu ditarjamahkeun kana Rusia. Sajaba ti éta, indentation geus dilereskeun kana spasi tinimbang [dianjurkeun dina Go] tab solely pikeun kaperluan readability hadé dina perenah Habr. Saatos unggal daptar aya tautan kana anu asli dina GitHub, dimana koméntar sareng tab dina basa Inggris disimpen.)

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()   // Ожидаем, что все остановлено
}

(utama.godi atah)

Urang ngalakukeun ieu:

  1. Urang ngonpigurasikeun pawang pikeun sinyal sistem operasi husus pikeun ngabalukarkeun terminasi anggun operator.
  2. Urang make WaitGrouppikeun gracefully ngeureunkeun sagala goroutine saméméh terminating aplikasi.
  3. Urang nyadiakeun aksés ka klaster ku nyieun clientset.
  4. Ngaluncurkeun NamespaceController, dimana sadaya logika urang bakal aya.

Ayeuna urang peryogi dasar pikeun logika, sareng dina hal urang ieu anu disebatkeun 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.godi atah)

Di dieu urang ngonpigurasikeun SharedIndexInformer, nu bakal éféktif (ngagunakeun cache a) ngantosan parobahan dina spasi ngaran (baca langkung seueur ngeunaan informan dina tulisan "Kumaha carana sangkan scheduler Kubernetes sabenerna jalan?"- kira-kira. tarjamahan). Sanggeus ieu urang sambungkeun EventHandler ka informer, ku kituna lamun nambahkeun spasi ngaran (Namespace) fungsi disebut createRoleBinding.

Lengkah saterusna nyaéta nangtukeun fungsi ieu 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.godi atah)

Simkuring meunang ngaranspasi salaku obj sarta ngarobahna kana hiji obyék Namespace. Teras we ngartikeun RoleBinding, dumasar kana file YAML disebutkeun di awal, ngagunakeun objék disadiakeun Namespace jeung nyiptakeun RoleBinding. Tungtungna, urang log naha kreasi éta suksés.

Fungsi anu terakhir anu ditetepkeun nyaéta 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.godi atah)

Di dieu urang ngobrol WaitGroupyén urang ngajalankeun goroutine lajeng nelepon namespaceInformer, nu geus didefinisikeun saméméhna. Nalika sinyal eureun datang, éta bakal mungkas fungsi, ngawartosan WaitGroup, nu geus euweuh dieksekusi, sarta fungsi ieu bakal kaluar.

Inpormasi ngeunaan ngawangun sareng ngajalankeun pernyataan ieu dina klaster Kubernetes tiasa dipendakan dina repositories on GitHub.

Éta pikeun operator anu nyiptakeun RoleBinding iraha Namespace dina klaster Kubernetes, siap.

sumber: www.habr.com

Tambahkeun komentar