Note. iwwersat.: Bedreiwer sinn Hëllefssoftware fir Kubernetes, entwéckelt fir d'Ausféierung vu Routineaktiounen op Clusterobjekter ze automatiséieren wann verschidden Eventer optrieden. Mir hu schonn iwwer Opérateuren geschriwwen an
Ech hu beschloss dëse Post mat engem richtege Beispill ze schreiwen no menge Versuche fir Dokumentatioun ze fannen fir e Bedreiwer fir Kubernetes ze kreéieren, deen duerch de Code studéiert ass.
D'Beispill dat beschriwwe gëtt ass dëst: an eisem Kubernetes Cluster, jidderee Namespace
stellt d'Sandkëschtëmfeld vun enger Equipe duer, a mir wollten den Zougang zu hinnen limitéieren, fir datt d'Equipen nëmmen an hiren eegene Sandkëschte spille kënnen.
Dir kënnt erreechen wat Dir wëllt andeems Dir engem Benotzer eng Grupp zougewisen huet, déi huet RoleBinding
zu spezifesch Namespace
и ClusterRole
mat Redaktioun Rechter. D'YAML Representatioun wäert esou ausgesinn:
---
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
(
Schafen eng RoleBinding
Dir kënnt et manuell maachen, awer nodeems Dir déi honnert Nummraim markéiert hutt, gëtt et eng langweileg Aufgab. Dëst ass wou Kubernetes Bedreiwer praktesch kommen - si erlaben Iech d'Schafung vu Kubernetes Ressourcen ze automatiséieren op Basis vun Ännerungen an de Ressourcen. An eisem Fall wëlle mir schafen RoleBinding
beim Schafen Namespace
.
Als éischt, loosst eis d'Funktioun definéieren main
déi de erfuerderleche Setup mécht fir d'Ausso auszeféieren an dann d'Aussoaktioun rufft:
(Note. iwwersat.: hei an ënnen d'Kommentaren am Code sinn op Russesch iwwersat. Zousätzlech ass d'Indentatioun op Plazen korrigéiert anstatt [recommandéiert a Go] Tabs eleng fir den Zweck vun enger besserer Liesbarkeet am Habr Layout. No all Oplëschtung ginn et Linken op d'Original op GitHub, wou engleschsproocheg Kommentarer a Tabs gespäichert sinn.)
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() // Ожидаем, что все остановлено
}
Mir maachen déi folgend:
- Mir konfiguréieren en Handler fir spezifesch Betribssystem Signaler fir eng graziéis Kënnegung vum Bedreiwer ze verursaachen.
- Mir benotzen
WaitGroup
fir all Goroutine graziéis ze stoppen ier Dir d'Applikatioun ofschléisst. - Mir bidden Zougang zum Stärekoup duerch Schafung
clientset
. - Lancéiere
NamespaceController
, an deem all eis Logik wäert sinn.
Elo brauche mir eng Basis fir d'Logik, an an eisem Fall ass dat déi genannt 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
}
(
Hei konfiguréieren mir SharedIndexInformer
, déi effektiv (mat engem Cache) op Ännerungen an den Nummraim waarden (liest méi iwwer Informateuren am Artikel "EventHandler
dem Informateur, sou datt wann Dir en Nummraum derbäisetzt (Namespace
) Funktioun genannt gëtt createRoleBinding
.
De nächste Schrëtt ass dës Funktioun ze definéieren 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))
}
}
(
Mir kréien den Nummraum als obj
a konvertéiert et an en Objet Namespace
. Dann definéieren mir RoleBinding
, baséiert op der YAML-Datei, déi am Ufank erwähnt gouf, mat dem geliwwertem Objet Namespace
an schafen RoleBinding
. Schlussendlech protokolléiere mir ob d'Kreatioun erfollegräich war.
Déi lescht Funktioun déi definéiert gëtt ass 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
}
(
Hei schwätze mer WaitGroup
datt mir d'Goroutine starten an dann ruffen namespaceInformer
, déi virdru definéiert gouf. Wann d'Stoppsignal ukomm ass, wäert et d'Funktioun ophalen, informéieren WaitGroup
, déi net méi ausgefouert gëtt, an dës Funktioun wäert ausgoen.
Informatioun iwwer d'Bauen an d'Ausféierung vun dëser Ausso op engem Kubernetes-Cluster fannt Dir an
Dat ass et fir de Bedreiwer deen erstellt RoleBinding
op Erscheinung Namespace
am Kubernetes Stärekoup, prett.
Source: will.com