PiezÄ«me:: Operatori (operators) ir atbalsta programmatÅ«ra Kubernetes, kas paredzÄta rutÄ«nu uzdevumu automatizÄÅ”anai attiecÄ«bÄ uz klastera objektiem noteiktos notikumos. MÄs jau esam rakstÄ«juÅ”i par operatoriem , kur aplÅ«kojÄm to pamatidejas un darbÄ«bas principus. TaÄu, ja iepriekÅ”Äjais materiÄls bija drÄ«zÄk skatÄ«jums no puses uz gatavu komponentu izmantoÅ”anu Kubernetes, tad Å”is jaunais raksts ir izstrÄdÄtÄja/DevOps inženiera skatÄ«jums, kas mocÄs ar jauna operatora izstrÄdi.

Å o ierakstu ar reÄla piemÄra aprakstu es nolÄmu uzrakstÄ«t pÄc tam, kad mÄÄ£inÄju atrast dokumentÄciju par operatora izveidi Kubernetes, kas iekļÄva koda izpÄti.
PiemÄrs, kuru mÄs aprakstÄ«sim, ir Å”Äds: mÅ«su Kubernetes klasterÄ« katrs Namespace pÄrstÄv kÄdas komandas smilÅ”u kasti, un mÄs vÄlÄjÄmies ierobežot piekļuvi tÄm tÄ, lai komandas varÄtu spÄlÄt tikai savÄs smilÅ”u kastÄs.
VÄlamo var panÄkt, pieŔķirot lietotÄjam grupu, kurai ir RoleBinding attiecÄ«bÄ uz Namespace un 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(, vienÄ no saviem ziÅojumiem )
Å Ädus RoleBinding var izveidot arÄ« manuÄli, taÄu, kad ir jÄizveido vairÄk par simtu nosaukumu telpÄm, tas kļūst nogurdinoÅ”s darbs. TieÅ”i Å”eit noder Kubernetes operatori ā tie ļauj automatizÄt Kubernetes resursu izveidi, pamatojoties uz resursu izmaiÅÄm. MÅ«su gadÄ«jumÄ mÄs vÄlamies izveidot RoleBinding nosaukumu telpÄ izveidoÅ”anas laikÄ. Namespace.
Vispirms noskaidrosim funkciju main, kas veic nepiecieÅ”amos iestatÄ«jumus operatora palaiÅ”anai un pÄc tam izsauc operatora darbÄ«bu:
(PiezÄ«me:: Å”eit un turpmÄk kodÄ komentÄri ir tulkoti uz krievu valodu. TurklÄt, ieloces ir labotas tÄ, lai izmantotu atstarpes vietÄ [Go ieteiktos] tabulÄcijas simbolus, lai uzlabotu lasÄmÄ«bu Å”ajÄ Hubra noformÄjumÄ. PÄc katra saraksta ir saites uz oriÄ£inÄlu GitHub, kurÅ« ir saglabÄti angļu valodas komentÄri un tabulÄcijas simboli.
func main() {
// IestatÄm žurnÄlu izvadi konsolÄ STDOUT
log.SetOutput(os.Stdout)
sigs := make(chan os.Signal, 1) // Izveidojam kanÄlu, lai saÅemtu OS signÄlus
stop := make(chan struct{}) // Izveidojam kanÄlu, lai saÅemtu apstopÄÅ”anas signÄlu
// ReÄ£istrÄjam SIGTERM saÅemÅ”anu kanÄlÄ sigs
signal.Notify(sigs, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
// Goroutines var paŔas pievienot sevi WaitGroup,
// lai gaidītu to izpildes pabeigŔanu
wg := &sync.WaitGroup{}
runOutsideCluster := flag.Bool("run-outside-cluster", false, "LÅ«dzu, iestatiet Å”o karoga vÄrtÄ«bu, kad darbojas Ärpus klusteru.")
flag.Parse()
// Izveidojam clientset, lai mijiedarbotos ar Kubernetes klasteri
clientset, err := newClientSet(*runOutsideCluster)
if err != nil {
panic(err.Error())
}
controller.NewNamespaceController(clientset).Run(stop, wg)
<-sigs // GaidÄm signÄlus (pirms signÄla saÅemÅ”anas nekas netiek darÄ«ts)
log.Printf("Aizveram...")
close(stop) // SakÄm goroutines apstÄties
wg.Wait() // GaidÄm, lÄ«dz viss ir apstÄdinÄts
}(, vienÄ no saviem ziÅojumiem )
MÄs veicam sekojoÅ”o:
- IestÄdÄm specifisku operÄtÄjsistÄmas signÄlu apstrÄdÄtÄju, lai izsauktu pareizu (graceful) operatora aizvÄrÅ”anu.
- Izmantojam
WaitGroup, lai pareizi apstÄdinÄtu visas goroutines pirms programmas izbeigÅ”anas. - NodroÅ”inÄm piekļuvi klasterim, izveidojot
clientset. - SÄksim
NamespaceController, kurÄ bÅ«s izvietota visa mÅ«su loÄ£ika.
Tagad nepiecieÅ”ama pamata loÄ£ika, un mÅ«su gadÄ«jumÄ tÄ ir minÄtais 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
}(, vienÄ no saviem ziÅojumiem )
Å eit mÄs iestatÄm SharedIndexInformer, kas efektÄ«vi (izmantojot keÅ”atmiÅu) gaidÄ«s izmaiÅas vÄrdnÄ«cÄs (vairÄk par informatoriem lasiet rakstÄ "Ā» ā piez. tulk.). PÄc tam mÄs pievienojam EventHandler informatoram, tÄdÄjÄdi, pievienojot vÄrdnÄ«cu (Namespace), tiek izsaukta funkcija createRoleBinding.
NÄkamais solis ā 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("NeizdevÄs izveidot Role Binding: %s", err.Error()))
} else {
log.Println(fmt.Sprintf("Izveidots AD RoleBinding vÄrdnÄ«cai: %s", roleBinding.Name))
}
}(, vienÄ no saviem ziÅojumiem )
MÄs iegÅ«stam vÄrdnÄ«cu kÄ obj un pÄrvÄrÅ”am to par objektu Namespace. PÄc tam definÄjam RoleBinding, pamatojoties uz iepriekÅ” minÄto YAML failÄ, izmantojot norÄdÄ«to objektu Namespace un izveidojot RoleBinding. Visbeidzot, reÄ£istrÄjam, vai izveide noritÄja veiksmÄ«gi.
PÄdÄjÄ funkcija, kas jÄnosaka, 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
}(, vienÄ no saviem ziÅojumiem )
Å eit mÄs sakÄm WaitGroup, ka palaidÄ«sim goroutine un pÄc tam izsauksim namespaceInformer, kas tika iepriekÅ” definÄts. Kad saÅemsim apstÄÅ”anÄs signÄlu, tas pabeigs funkciju un paziÅos WaitGroup, ka vairs netiek izpildÄ«ts, un Ŕī funkcija pabeigs savu darbu.
InformÄciju par Ŕī operators bÅ«vÄÅ”anu un palaiÅ”anu Kubernetes klasterÄ« var atrast .
Å eit operators, kas izveido RoleBinding parÄdīŔanÄs brÄ«dÄ« Namespace Kubernetes klasterÄ« ir gatavs.
Avots: habr.com
