Piezīme. tulk.: operatori ir Kubernetes palīgprogrammatūra, kas paredzēta, lai automatizētu parasto darbību izpildi klastera objektos, kad notiek noteikti notikumi. Mēs jau rakstījām par operatoriem
Es nolēmu uzrakstīt šo ziņu ar piemēru no reālās dzīves pēc tam, kad mēģināju atrast dokumentāciju par Kubernetes operatora izveidi, kas tika veikta koda pētīšanā.
Piemērs, kas tiks aprakstīts, ir šāds: mūsu Kubernetes klasterī katrs Namespace
ir komandas smilškastes vide, un mēs vēlējāmies ierobežot piekļuvi tām, lai komandas varētu spēlēt tikai savās smilšu kastēs.
Varat sasniegt to, ko vēlaties, piešķirot lietotājam grupu, kurai ir RoleBinding
uz konkrētu Namespace
и ClusterRole
ar rediģēšanas tiesībām. YAML attēlojums izskatīsies šādi:
---
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
(
Izveidot vienu RoleBinding
To var izdarīt manuāli, taču pēc simts nosaukumvietu atzīmes šķērsošanas tas kļūst par nogurdinošu uzdevumu. Šeit noder Kubernetes operatori — tie ļauj automatizēt Kubernetes resursu izveidi, pamatojoties uz izmaiņām resursos. Mūsu gadījumā mēs vēlamies radīt RoleBinding
veidojot Namespace
.
Vispirms definēsim funkciju main
kas veic nepieciešamo iestatījumu, lai palaistu priekšrakstu, un pēc tam izsauc paziņojuma darbību:
(Piezīme. tulk.: šeit un zemāk komentāri kodā ir tulkoti krievu valodā. Turklāt atkāpe ir koriģēta uz atstarpēm, nevis [ieteicams lietotnē Go] cilnēm, lai nodrošinātu labāku lasāmību Habr izkārtojumā. Pēc katra ieraksta ir saites uz oriģinālu vietnē GitHub, kur tiek glabāti komentāri un cilnes angļu valodā.)
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() // Ожидаем, что все остановлено
}
Mēs veicam šādas darbības:
- Mēs konfigurējam apdarinātāju konkrētiem operētājsistēmas signāliem, lai izraisītu operatora graciozu pārtraukšanu.
- Mēs izmantojam
WaitGroup
lai graciozi apturētu visas gorutīnas pirms pieteikuma pārtraukšanas. - Mēs nodrošinām piekļuvi klasterim, izveidojot
clientset
. - Palaist
NamespaceController
, kurā atradīsies visa mūsu loģika.
Tagad mums ir vajadzīgs pamats loģikai, un mūsu gadījumā tas ir minēts 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
}
(
Šeit mēs konfigurējam SharedIndexInformer
, kas efektīvi (izmantojot kešatmiņu) gaidīs izmaiņas nosaukumvietās (vairāk par informatoriem lasiet rakstā “EventHandler
ziņotājam, lai, pievienojot nosaukumvietu (Namespace
) tiek izsaukta funkcija createRoleBinding
.
Nākamais solis ir definēt šo funkciju 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))
}
}
(
Mēs iegūstam nosaukumvietu kā obj
un pārvērst to par objektu Namespace
. Tad mēs definējam RoleBinding
, pamatojoties uz sākumā minēto YAML failu, izmantojot norādīto objektu Namespace
un radot RoleBinding
. Visbeidzot mēs reģistrējam, vai izveide bija veiksmīga.
Pēdējā definējamā funkcija ir 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
}
(
Šeit mēs runājam WaitGroup
ka mēs palaižam gorutīnu un pēc tam zvanām namespaceInformer
, kas ir definēts iepriekš. Kad pienāk apstāšanās signāls, tas beigs funkciju, informē WaitGroup
, kas vairs netiek izpildīts, un šī funkcija tiks aizvērta.
Informāciju par šī paziņojuma izveidi un izpildi Kubernetes klasterī var atrast
Tas ir paredzēts operatoram, kurš rada RoleBinding
kad Namespace
Kubernetes klasterī, gatavs.
Avots: www.habr.com