Qeyd. tərcümə.: Operatorlar müəyyən hadisələr zamanı klaster obyektlərində adi hərəkətlərin icrasını avtomatlaşdırmaq üçün nəzərdə tutulmuş Kubernetes üçün köməkçi proqramdır. Artıq operatorlar haqqında yazmışıq
Kubernetes üçün operator yaratmaq üçün sənədləri tapmaq cəhdlərim kodun öyrənilməsindən keçdikdən sonra bu yazını real həyat nümunəsi ilə yazmaq qərarına gəldim.
Təsvir ediləcək nümunə belədir: Kubernetes klasterimizdə hər biri Namespace
komandanın sandbox mühitini təmsil edir və biz onlara girişi məhdudlaşdırmaq istədik ki, komandalar yalnız öz qum qutularında oynaya bilsinlər.
Sahib olduğu qrupa istifadəçi təyin etməklə istədiyinizə nail ola bilərsiniz RoleBinding
konkretə Namespace
и ClusterRole
redaktə hüququ ilə. YAML təqdimatı belə görünəcək:
---
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
(
Belə yaradın RoleBinding
bunu əl ilə edə bilərsiniz, lakin yüzdən çox ad sahəsi əldə etdikdən sonra bu, yorucu bir işə çevrilir. Burada Kubernetes operatorları kömək edir - onlar sizə resurslardakı dəyişikliklər əsasında Kubernetes resurslarının yaradılmasını avtomatlaşdırmağa imkan verir. Bizim vəziyyətimizdə biz yaratmaq istəyirik RoleBinding
yaratarkən Namespace
.
Əvvəlcə funksiyanı təyin edək main
, bəyanatı işə salmaq üçün tələb olunan quraşdırmanı edir və sonra bəyanat hərəkətini çağırır:
(Qeyd. tərcümə.: bundan sonra koddakı şərhlər rus dilinə tərcümə olunur. Bundan əlavə, abzas yalnız Habr tərtibatı çərçivəsində daha yaxşı oxunaqlılıq məqsədilə [Get-də tövsiyə olunur] tabları əvəzinə boşluqlar üçün düzəldilir. Hər siyahıdan sonra GitHub-da orijinala keçidlər var, burada ingilis dilində şərhlər və nişanlar saxlanılır.)
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() // Ожидаем, что все остановлено
}
Biz aşağıdakıları edirik:
- Operatorun zərif şəkildə çıxmasına səbəb olmaq üçün xüsusi əməliyyat sistemi siqnalları üçün işləyici qurduq.
- Biz istifadə edirik
WaitGroup
proqram bitməzdən əvvəl bütün goroutinləri zərif şəkildə dayandırmaq. - Yaratmaqla klasterə girişi təmin edirik
clientset
. - Başlat
NamespaceController
, bütün məntiqimizin yerləşəcəyi.
İndi məntiq üçün əsas lazımdır və bizim vəziyyətimizdə qeyd olunandır 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
}
(
Budur, biz təyin edirik SharedIndexInformer
, bu, səmərəli şəkildə (keşdən istifadə etməklə) ad sahəsinin dəyişməsini gözləyəcək (məqalədə məlumat verənlər haqqında daha çox oxuyun "EventHandler
məlumat verənə, bunun sayəsində ad sahəsi əlavə edərkən (Namespace
) funksiyası çağırılır createRoleBinding
.
Növbəti addım bu funksiyanı təyin etməkdir 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))
}
}
(
Biz ad sahəsini alırıq obj
və onu obyektə çevirin Namespace
. Sonra müəyyənləşdiririk RoleBinding
, təqdim olunan obyektdən istifadə edərək, əvvəlində qeyd olunan YAML faylı əsasında Namespace
və yaratmaq RoleBinding
. Nəhayət, yaradılışın uğurlu olub olmadığını qeyd edirik.
Müəyyən ediləcək son funksiya − 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
}
(
Burada söhbət edirik WaitGroup
ki, biz goroutine başlayır və sonra zəng namespaceInformer
əvvəllər müəyyən edilmişdi. Dayanma siqnalı daxil olduqda, o, funksiyanı dayandıracaq, məlumatlandırın WaitGroup
, artıq icra olunmur və bu funksiya çıxacaq.
Bu bəyanatı Kubernetes klasterində qurmaq və işlətmək haqqında məlumatı burada tapa bilərsiniz
Yaradan bu ifadə üzərinə RoleBinding
nə vaxt Namespace
Kubernetes klasterində hazırdır.
Mənbə: www.habr.com