Golang рдорд╛ Kubernetes рдХреЛ рд▓рд╛рдЧреА рдПрдХ рдЕрдкрд░реЗрдЯрд░ рд▓реЗрдЦреНрджреИ

рдиреЛрдЯред рдЕрдиреБрд╡рд╛рджред: рдЕрдкрд░реЗрдЯрд░рд╣рд░реВ Kubernetes рдХреЛ рд▓рд╛рдЧрд┐ рд╕рд╣рд╛рдпрдХ рд╕рдлреНрдЯрд╡реЗрдпрд░ рд╣реБрдиреН, рдЬреБрди рдирд┐рд╢реНрдЪрд┐рдд рдШрдЯрдирд╛рд╣рд░реВ рд╣реБрдБрджрд╛ рдХреНрд▓рд╕реНрдЯрд░ рд╡рд╕реНрддреБрд╣рд░реВрдорд╛ рдирд┐рдпрдорд┐рдд рдХрд╛рд░реНрдпрд╣рд░реВрдХреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдЧрд░реНрди рдбрд┐рдЬрд╛рдЗрди рдЧрд░рд┐рдПрдХреЛ рд╣реЛред рд╣рд╛рдореАрд▓реЗ рдкрд╣рд┐рд▓реЗ рдиреИ рдЕрдкрд░реЗрдЯрд░рд╣рд░реВрдХреЛ рдмрд╛рд░реЗрдорд╛ рд▓реЗрдЦреЗрдХрд╛ рдЫреМрдВ рдпреЛ рд▓реЗрдЦ, рдЬрд╣рд╛рдБ рдЙрдиреАрд╣рд░реВрд▓реЗ рдЖрдлреНрдиреЛ рдХрд╛рдордХреЛ рдЖрдзрд╛рд░рднреВрдд рд╡рд┐рдЪрд╛рд░ рд░ рд╕рд┐рджреНрдзрд╛рдиреНрддрд╣рд░реВрдХреЛ рдмрд╛рд░реЗрдорд╛ рдХреБрд░рд╛ рдЧрд░реЗред рддрд░ рдпрджрд┐ рддреНрдпреЛ рд╕рд╛рдордЧреНрд░реА Kubernetes рдХреЛ рд▓рд╛рдЧрд┐ рддрдпрд╛рд░-рдирд┐рд░реНрдорд┐рдд рдХрдореНрдкреЛрдиреЗрдиреНрдЯрд╣рд░реВ рд╕рдЮреНрдЪрд╛рд▓рди рдЧрд░реНрдиреЗ рдкрдХреНрд╖рдмрд╛рдЯ рдЕрдзрд┐рдХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдерд┐рдпреЛ рднрдиреЗ, рдЕрдм рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рдирдпрд╛рдБ рд▓реЗрдЦрдХреЛ рдЕрдиреБрд╡рд╛рдж рдкрд╣рд┐рд▓реЗ рдиреИ рдПрдХ рдирдпрд╛рдБ рдЕрдкрд░реЗрдЯрд░рдХреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдирдмрд╛рдЯ рдЕрдиреНрдпреЛрд▓рдорд╛ рдкрд░реЗрдХреЛ рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛/DevOps рдЗрдиреНрдЬрд┐рдирд┐рдпрд░рдХреЛ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣реЛред

Golang рдорд╛ Kubernetes рдХреЛ рд▓рд╛рдЧреА рдПрдХ рдЕрдкрд░реЗрдЯрд░ рд▓реЗрдЦреНрджреИ

рдореИрд▓реЗ рдХреБрдмрд░реНрдиреЗрдЯреНрд╕рдХрд╛ рд▓рд╛рдЧрд┐ рдЕрдкрд░реЗрдЯрд░ рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реНрдиреЗ рдХрд╛рдЧрдЬрд╛рддрд╣рд░реВ рдлреЗрд▓рд╛ рдкрд╛рд░реНрдиреЗ рдкреНрд░рдпрд╛рд╕рд╣рд░реВ рдкрдЫрд┐ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЬреАрд╡рдирдХреЛ рдЙрджрд╛рд╣рд░рдгрдХреЛ рд╕рд╛рде рдпреЛ рдкреЛрд╖реНрдЯ рд▓реЗрдЦреНрдиреЗ рдирд┐рд░реНрдгрдп рдЧрд░реЗрдВ, рдЬреБрди рдХреЛрдб рдЕрдзреНрдпрдпрди рдЧрд░реЗрд░ рдЧрдПрдХреЛ рдерд┐рдпреЛред

рд╡рд░реНрдгрди рдЧрд░рд┐рдиреЗ рдЙрджрд╛рд╣рд░рдг рдпреЛ рд╣реЛ: рд╣рд╛рдореНрд░реЛ 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 рддрдкрд╛рдИрдВ рдпрд╕рд▓рд╛рдИ рдореНрдпрд╛рдиреБрдЕрд▓ рд░реВрдкрдорд╛ рдЧрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫ, рддрд░ рд╕рдп рдирд╛рдо рд╕реНрдерд╛рди рдЪрд┐рдиреНрд╣ рдкрд╛рд░ рдЧрд░реЗрдкрдЫрд┐, рдпреЛ рдПрдХ рдХрдард┐рди рдХрд╛рдо рд╣реБрдиреНрдЫред рдпрд╣рд╛рдБ рдХреБрдмреЗрд░рдиреЗрдЯ рдЕрдкрд░реЗрдЯрд░рд╣рд░реВ рдХрд╛рдордорд╛ рдЖрдЙрдБрдЫрдиреНтАФрддрд┐рдиреАрд╣рд░реВрд▓реЗ рддрдкрд╛рдИрдВрд▓рд╛рдИ рд╕реНрд░реЛрддрд╣рд░реВрдорд╛ рдкрд░рд┐рд╡рд░реНрддрдирдХреЛ рдЖрдзрд╛рд░рдорд╛ Kubernetes рд╕реНрд░реЛрддрд╣рд░реВрдХреЛ рд╕рд┐рд░реНрдЬрдирд╛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдЧрд░реНрди рдЕрдиреБрдорддрд┐ рджрд┐рдиреНрдЫред рд╣рд╛рдореНрд░реЛ рдЕрд╡рд╕реНрдерд╛рдорд╛ рд╣рд╛рдореА рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реНрди рдЪрд╛рд╣рдиреНрдЫреМрдВ RoleBinding рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реНрджрд╛ Namespace.

рд╕рдмреИ рднрдиреНрджрд╛ рдкрд╣рд┐рд▓реЗ, рдкреНрд░рдХрд╛рд░реНрдп рдкрд░рд┐рднрд╛рд╖рд┐рдд рдЧрд░реМрдВ mainрдЬрд╕рд▓реЗ рд╕реНрдЯреЗрдЯрдореЗрдиреНрдЯ рдЪрд▓рд╛рдЙрди рдЖрд╡рд╢реНрдпрдХ рд╕реЗрдЯрдЕрдк рдЧрд░реНрдЫ рд░ рддреНрдпрд╕рдкрдЫрд┐ рд╕реНрдЯреЗрдЯрдореЗрдиреНрдЯ рдПрдХреНрд╢рдирд▓рд╛рдИ рдХрд▓ рдЧрд░реНрдЫ:

(рдиреЛрдЯред рдЕрдиреБрд╡рд╛рджред: рдпрд╣рд╛рдБ рд░ рддрд▓ рдХреЛрдбрдорд╛ рдЯрд┐рдкреНрдкрдгреАрд╣рд░реВ рд░реВрд╕реАрдорд╛ рдЕрдиреБрд╡рд╛рдж рдЧрд░рд┐рдПрдХреЛ рдЫред рдердк рд░реВрдкрдорд╛, рдЗрдиреНрдбреЗрдиреНрдЯреЗрд╕рдирд▓рд╛рдИ Habr рд▓реЗрдЖрдЙрдЯ рднрд┐рддреНрд░ рд░рд╛рдореНрд░реЛ рдкрдардиреАрдпрддрд╛рдХреЛ рдЙрджреНрджреЗрд╢реНрдпрдХрд╛ рд▓рд╛рдЧрд┐ рдорд╛рддреНрд░ [Go рдорд╛ рд╕рд┐рдлрд╛рд░рд┐рд╕ рдЧрд░рд┐рдПрдХреЛ] рдЯреНрдпрд╛рдмрд╣рд░реВрдХреЛ рд╕рдЯреНрдЯрд╛ рдЦрд╛рд▓реА рдард╛рдЙрдБрд╣рд░реВрдорд╛ рд╕рдЪреНрдпрд╛рдЗрдпреЛред рдкреНрд░рддреНрдпреЗрдХ рд╕реВрдЪреА рдкрдЫрд┐ 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 рдХреНрд▓рд╕реНрдЯрд░рдорд╛, рддрдпрд╛рд░ рдЫред

рд╕реНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдердкреНрди