Ysgrifennu gweithredwr ar gyfer Kubernetes yn Golang

Nodyn. traws.: Mae gweithredwyr yn feddalwedd ategol ar gyfer Kubernetes, sydd wedi'u cynllunio i awtomeiddio gweithredu gweithredoedd arferol ar wrthrychau clwstwr pan fydd digwyddiadau penodol yn digwydd. Rydym eisoes wedi ysgrifennu am weithredwyr yn Mae'r erthygl hon yn, lle buont yn siarad am syniadau ac egwyddorion sylfaenol eu gwaith. Ond pe bai'r deunydd hwnnw'n fwy o farn o ochr gweithredu cydrannau parod ar gyfer Kubernetes, yna mae'r cyfieithiad o'r erthygl newydd a gynigir nawr eisoes yn weledigaeth datblygwr / peiriannydd DevOps sy'n cael ei ddrysu gan weithrediad gweithredwr newydd.

Ysgrifennu gweithredwr ar gyfer Kubernetes yn Golang

Penderfynais ysgrifennu'r swydd hon gydag enghraifft bywyd go iawn ar ôl fy ymdrechion i ddod o hyd i ddogfennaeth ar greu gweithredwr ar gyfer Kubernetes, a aeth trwy astudio'r cod.

Yr enghraifft a fydd yn cael ei disgrifio yw hyn: yn ein clwstwr Kubernetes, bob un Namespace cynrychioli amgylchedd blwch tywod tîm, ac roeddem am gyfyngu mynediad iddynt fel mai dim ond yn eu blychau tywod eu hunain y gallai timau chwarae.

Gallwch chi gyflawni'r hyn rydych chi ei eisiau trwy aseinio grŵp defnyddiwr sydd wedi RoleBinding i benodol Namespace и ClusterRole gyda hawliau golygu. Bydd cynrychiolaeth YAML yn edrych fel hyn:

---
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

(rolrwymiad.yamlYn amrwd)

Creu un RoleBinding Gallwch chi ei wneud â llaw, ond ar ôl croesi'r marc can gofod enwau, mae'n dod yn dasg ddiflas. Dyma lle mae gweithredwyr Kubernetes yn ddefnyddiol - maen nhw'n caniatáu ichi awtomeiddio'r broses o greu adnoddau Kubernetes yn seiliedig ar newidiadau i adnoddau. Yn ein hachos ni rydym am greu RoleBinding wrth greu Namespace.

Yn gyntaf oll, gadewch i ni ddiffinio'r swyddogaeth mainsy'n gwneud y gosodiad gofynnol i redeg y datganiad ac yna'n galw'r datganiad yn weithred:

(Nodyn. traws.: yma ac isod mae'r sylwadau yn y cod yn cael eu cyfieithu i Rwsieg. Yn ogystal, mae'r mewnoliad wedi'i gywiro i fylchau yn lle tabiau [a argymhellir yn Go] yn unig er mwyn gwella darllenadwyedd o fewn cynllun Habr. Ar ôl pob rhestriad mae dolenni i'r gwreiddiol ar GitHub, lle mae sylwadau a thabiau Saesneg yn cael eu storio.)

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

(prif.goYn amrwd)

Rydym yn gwneud y canlynol:

  1. Rydym yn ffurfweddu triniwr ar gyfer signalau system weithredu penodol i achosi terfynu gosgeiddig y gweithredwr.
  2. Rydym yn defnyddio WaitGroupi atal pob goroutines yn osgeiddig cyn terfynu'r cais.
  3. Rydym yn darparu mynediad i'r clwstwr trwy greu clientset.
  4. Lansio NamespaceController, yn yr hwn y bydd ein holl resymeg wedi ei lleoli.

Nawr mae angen sail ar gyfer rhesymeg, ac yn ein hachos ni dyma'r un a grybwyllir 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
}

(rheolydd.goYn amrwd)

Yma rydym yn ffurfweddu SharedIndexInformer, a fydd i bob pwrpas (gan ddefnyddio storfa) yn aros am newidiadau mewn gofodau enwau (darllenwch fwy am hysbyswyr yn yr erthygl “Sut mae amserlennydd Kubernetes yn gweithio mewn gwirionedd?"- tua. traws.). Ar ôl hyn rydym yn cysylltu EventHandler i'r hysbyswr, fel wrth ychwanegu gofod enw (Namespace) swyddogaeth yn cael ei alw createRoleBinding.

Y cam nesaf yw diffinio'r swyddogaeth hon 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))
  }
}

(rheolydd.goYn amrwd)

Cawn y gofod enw fel obj a'i drawsnewid yn wrthrych Namespace. Yna rydym yn diffinio RoleBinding, yn seiliedig ar y ffeil YAML a grybwyllir ar y dechrau, gan ddefnyddio'r gwrthrych a ddarperir Namespace a chreu RoleBinding. Yn olaf, rydym yn cofnodi a oedd y greadigaeth yn llwyddiannus.

Y swyddogaeth olaf i'w diffinio yw 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
}

(rheolydd.goYn amrwd)

Dyma ni yn siarad WaitGroupein bod yn lansio'r goroutine ac yna'n galw namespaceInformer, sydd wedi'i ddiffinio'n flaenorol. Pan fydd y signal stopio yn cyrraedd, bydd yn dod â'r swyddogaeth i ben, hysbysu WaitGroup, nad yw bellach yn cael ei weithredu, a bydd y swyddogaeth hon yn gadael.

Gellir dod o hyd i wybodaeth am adeiladu a rhedeg y datganiad hwn ar glwstwr Kubernetes yn storfeydd ar GitHub.

Dyna ni ar gyfer y gweithredwr sy'n creu RoleBinding pryd Namespace yn y clwstwr Kubernetes, yn barod.

Ffynhonnell: hab.com

Ychwanegu sylw