Shënim. përkth.: Operatorët janë softuer ndihmës për Kubernetes, i krijuar për të automatizuar ekzekutimin e veprimeve rutinë në objektet e grupimit kur ndodhin ngjarje të caktuara. Ne kemi shkruar tashmë për operatorët në
Vendosa ta shkruaj këtë postim me një shembull të jetës reale pas përpjekjeve të mia për të gjetur dokumentacion për krijimin e një operatori për Kubernetes, i cili kaloi përmes studimit të kodit.
Shembulli që do të përshkruhet është ky: në grupin tonë Kubernetes, secili Namespace
përfaqëson mjedisin e sandbox të një ekipi dhe ne donim të kufizonim aksesin në to në mënyrë që ekipet të mund të luanin vetëm në sandboxet e tyre.
Ju mund të arrini atë që dëshironi duke i caktuar një përdoruesi një grup që ka RoleBinding
të veçanta Namespace
и ClusterRole
me të drejta redaktimi. Përfaqësimi YAML do të duket kështu:
---
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
(
Krijo nje RoleBinding
Mund ta bëni me dorë, por pasi të kaloni shenjën e njëqind hapësirave të emrave, bëhet një detyrë e lodhshme. Kjo është ajo ku operatorët Kubernetes vijnë në ndihmë - ata ju lejojnë të automatizoni krijimin e burimeve të Kubernetes bazuar në ndryshimet në burime. Në rastin tonë ne duam të krijojmë RoleBinding
gjatë krijimit Namespace
.
Para së gjithash, le të përcaktojmë funksionin main
i cili bën konfigurimin e kërkuar për të ekzekutuar deklaratën dhe më pas e quan veprimin e deklaratës:
(Shënim. përkth.: këtu dhe më poshtë komentet në kod janë përkthyer në Rusisht. Përveç kësaj, dhëmbëzimi është korrigjuar në hapësira në vend të skedave [rekomandohet në Shko] vetëm për qëllimin e lexueshmërisë më të mirë brenda paraqitjes Habr. Pas çdo listimi ka lidhje me origjinalin në GitHub, ku ruhen komentet dhe skedat në gjuhën angleze.)
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() // Ожидаем, что все остановлено
}
(
Ne bëjmë sa vijon:
- Ne konfigurojmë një mbajtës për sinjale specifike të sistemit operativ për të shkaktuar ndërprerje të këndshme të operatorit.
- Ne përdorim
WaitGroup
për të ndaluar me hijeshi të gjitha gorutinat përpara se të përfundoni aplikacionin. - Ne ofrojmë qasje në grup duke krijuar
clientset
. - Nisja
NamespaceController
, në të cilën do të vendoset e gjithë logjika jonë.
Tani na duhet një bazë për logjikën, dhe në rastin tonë kjo është ajo e përmendur 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
}
(
Këtu ne konfigurojmë SharedIndexInformer
, i cili në mënyrë efektive (duke përdorur një cache) do të presë për ndryshime në hapësirat e emrave (lexoni më shumë rreth informatorëve në artikullin "EventHandler
te informatori, në mënyrë që kur të shtoni një hapësirë emri (Namespace
) thirret funksioni createRoleBinding
.
Hapi tjetër është përcaktimi i këtij funksioni 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))
}
}
(
Ne e marrim hapësirën e emrave si obj
dhe e kthejnë atë në një objekt Namespace
. Pastaj ne përcaktojmë RoleBinding
, bazuar në skedarin YAML të përmendur në fillim, duke përdorur objektin e dhënë Namespace
dhe duke krijuar RoleBinding
. Së fundi, ne regjistrojmë nëse krijimi ishte i suksesshëm.
Funksioni i fundit që duhet përcaktuar është 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
}
(
Këtu po flasim WaitGroup
që ne lëshojmë gorutinën dhe më pas telefonojmë namespaceInformer
, e cila është përcaktuar më parë. Kur të arrijë sinjali i ndalimit, ai do të përfundojë funksionin, informoni WaitGroup
, i cili nuk ekzekutohet më dhe ky funksion do të dalë.
Informacion rreth ndërtimit dhe ekzekutimit të kësaj deklarate në një grupim Kubernetes mund të gjenden në
Kjo është ajo për operatorin që krijon RoleBinding
kur Namespace
në grupin Kubernetes, gati.
Burimi: www.habr.com