Notu. transl.: Operaciantoj estas helpa programaro por Kubernetes, dizajnita por aŭtomatigi la plenumon de rutinaj agoj sur aretobjektoj kiam certaj okazaĵoj okazas. Ni jam skribis pri operatoroj en
Mi decidis skribi ĉi tiun afiŝon kun reala ekzemplo post miaj provoj trovi dokumentadon pri kreado de operatoro por Kubernetes, kiu trapasis studado de la kodo.
La ekzemplo, kiu estos priskribita, estas ĉi tiu: en nia Kubernetes-grupo, ĉiu Namespace
reprezentas la sablokeston de teamo, kaj ni volis limigi aliron al ili tiel ke teamoj nur povu ludi en siaj propraj sablokestoj.
Vi povas atingi tion, kion vi volas asignante al uzanto grupon kiu havas RoleBinding
al specifa Namespace
и ClusterRole
kun redaktaj rajtoj. La YAML-reprezento aspektos jene:
---
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
(
Kreu unu RoleBinding
Vi povas fari ĝin permane, sed post transpaso de la cent nomspacoj, ĝi fariĝas teda tasko. Ĉi tie utilas Kubernetes-funkciigistoj—ili permesas vin aŭtomatigi la kreadon de Kubernetes-resursoj surbaze de ŝanĝoj al la rimedoj. En nia kazo ni volas krei RoleBinding
dum kreado Namespace
.
Antaŭ ĉio, ni difinu la funkcion main
kiu faras la bezonatan aranĝon por ruli la deklaron kaj poste vokas la deklaron:
(Notu. transl.: ĉi tie kaj sube la komentoj en la kodo estas tradukitaj en la rusan. Krome, la indentaĵo estis korektita al spacoj anstataŭe de [rekomendite en Go] langetoj nur por pli bona legebleco ene de la Habr-aranĝo. Post ĉiu listo estas ligiloj al la originalo en GitHub, kie estas konservitaj anglalingvaj komentoj kaj langetoj.)
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() // Ожидаем, что все остановлено
}
Ni faras la jenon:
- Ni agordas pritraktilon por specifaj operaciumaj signaloj por kaŭzi gracian finon de la funkciigisto.
- Ni uzas
WaitGroup
por gracie haltigi ĉiujn gorutinojn antaŭ ol ĉesigi la aplikaĵon. - Ni provizas aliron al la areto per kreado
clientset
. - Lanĉo
NamespaceController
, en kiu troviĝos nia tuta logiko.
Nun ni bezonas bazon por logiko, kaj en nia kazo ĉi tiu estas la menciita 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
}
(
Ĉi tie ni agordas SharedIndexInformer
, kiu efike (uzante kaŝmemoron) atendos ŝanĝojn en nomspacoj (legu pli pri informantoj en la artikolo "EventHandler
al la informanto, tiel ke aldonante nomspacon (Namespace
) funkcio estas nomita createRoleBinding
.
La sekva paŝo estas difini ĉi tiun funkcion 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))
}
}
(
Ni ricevas la nomspacon kiel obj
kaj konverti ĝin al objekto Namespace
. Tiam ni difinas RoleBinding
surbaze de la YAML-dosiero menciita komence, uzante la provizitan objekton Namespace
kaj kreante RoleBinding
. Fine ni registras ĉu la kreado sukcesis.
La lasta funkcio por esti difinita estas 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
}
(
Jen ni parolas WaitGroup
ke ni lanĉu la gorutinon kaj poste voku namespaceInformer
, kiu estis antaŭe difinita. Kiam la haltsignalo alvenos, ĝi finos la funkcion, informu WaitGroup
, kiu ne plu estas ekzekutita, kaj ĉi tiu funkcio eliros.
Informoj pri konstruado kaj funkciado de ĉi tiu deklaro sur Kubernetes-areto troveblas en
Tio estas por la operatoro kiu kreas RoleBinding
kiam Namespace
en la Kubernetes-areo, preta.
fonto: www.habr.com