Opomba. prevod: Operatorji so pomožna programska oprema za Kubernetes, zasnovana za avtomatizacijo izvajanja rutinskih dejanj na objektih gruče, ko pride do določenih dogodkov. O operaterjih v smo že pisali , kjer so spregovorili o temeljnih idejah in načelih svojega delovanja. Če pa je bilo to gradivo bolj pogled s strani delovanja že pripravljenih komponent za Kubernetes, potem je prevod zdaj predlaganega novega članka že vizija razvijalca/inženirja DevOps, ki ga zmede implementacija novega operaterja.

Za pisanje te objave s primerom iz resničnega življenja sem se odločil, potem ko sem poskušal najti dokumentacijo o ustvarjanju operaterja za Kubernetes, ki je šel skozi preučevanje kode.
Primer, ki bo opisan, je naslednji: v naši gruči Kubernetes vsak Namespace predstavlja okolje peskovnika ekipe in želeli smo omejiti dostop do njih, tako da bi ekipe lahko igrale samo v svojih peskovnikih.
Če želite, lahko dosežete tako, da uporabniku dodelite skupino, ki ima RoleBinding do določenega Namespace и ClusterRole s pravicami urejanja. Predstavitev YAML bo videti takole:
---
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(V )
Ustvarite enega RoleBinding To lahko storite ročno, a ko presežete oznako sto imenskih prostorov, postane dolgočasno opravilo. Tu pridejo prav operaterji Kubernetes – omogočajo vam avtomatizacijo ustvarjanja virov Kubernetes na podlagi sprememb virov. V našem primeru želimo ustvarjati RoleBinding med ustvarjanjem Namespace.
Najprej definirajmo funkcijo mainki izvede zahtevano nastavitev za zagon stavka in nato pokliče dejanje stavka:
(Opomba. prevod: tukaj in spodaj so komentarji v kodi prevedeni v ruščino. Poleg tega je bil zamik popravljen na presledke namesto zavihkov [priporočeno v Go] izključno zaradi boljše berljivosti znotraj postavitve Habr. Za vsakim seznamom so povezave do izvirnika na GitHubu, kjer so shranjeni komentarji in zavihki v angleškem jeziku.)
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() // Ожидаем, что все остановлено
}(V )
Delamo naslednje:
- Konfiguriramo upravljalnik za določene signale operacijskega sistema, da povzroči elegantno prekinitev operaterja.
- Uporaba
WaitGroupda elegantno ustavite vse goroutine, preden prekinete aplikacijo. - Dostop do grozda omogočimo z ustvarjanjem
clientset. - Kosilo
NamespaceController, v katerem se bo nahajala vsa naša logika.
Zdaj potrebujemo osnovo za logiko in v našem primeru je ta omenjena 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
}(V )
Tukaj konfiguriramo SharedIndexInformer, ki bo učinkovito (z uporabo predpomnilnika) čakal na spremembe v imenskih prostorih (več o informatorjih preberite v članku “"- pribl. prevod). Po tem se povežemo EventHandler informerju, tako da ob dodajanju imenskega prostora (Namespace) je poklicana funkcija createRoleBinding.
Naslednji korak je definiranje te funkcije 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))
}
}(V )
Imenski prostor dobimo kot obj in ga pretvorite v predmet Namespace. Nato definiramo RoleBinding, ki temelji na datoteki YAML, omenjeni na začetku, z uporabo podanega predmeta Namespace in ustvarjanje RoleBinding. Nazadnje zabeležimo, ali je bilo ustvarjanje uspešno.
Zadnja funkcija, ki jo je treba definirati, je 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
}(V )
Tukaj se pogovarjamo WaitGroupda zaženemo goroutine in nato pokličemo namespaceInformer, ki je bil predhodno opredeljen. Ko pride signal za zaustavitev, bo ta končal funkcijo, obvešča WaitGroup, ki se ne izvaja več, in ta funkcija se bo zaprla.
Informacije o gradnji in izvajanju te izjave v gruči Kubernetes lahko najdete v .
To je vse za operaterja, ki ustvarja RoleBinding kdaj Namespace v gruči Kubernetes, pripravljeno.
Vir: www.habr.com
