Նշում. թարգմ.Օպերատորները Kubernetes-ի համար նախատեսված օժանդակ ծրագրեր են, որոնք նախատեսված են կլաստերի օբյեկտների վրա սովորական գործողությունների ավտոմատացման համար, երբ տեղի են ունենում որոշակի իրադարձություններ: Մենք արդեն գրել ենք օպերատորների մասին
Ես որոշեցի գրել այս գրառումը իրական օրինակով Kubernetes-ի համար օպերատոր ստեղծելու վերաբերյալ փաստաթղթեր գտնելու իմ փորձերից հետո, որոնք անցել են կոդը ուսումնասիրելով:
Օրինակը, որը նկարագրվելու է, սա է. մեր Kubernetes կլաստերում յուրաքանչյուրը Namespace
ներկայացնում է թիմի Sandbox միջավայրը, և մենք ցանկանում էինք սահմանափակել դրանց մուտքը, որպեսզի թիմերը կարողանան խաղալ միայն իրենց ավազատուփերում:
Դուք կարող եք հասնել այն ամենին, ինչ ցանկանում եք՝ օգտատիրոջը նշանակելով խումբ, որն ունի RoleBinding
կոնկրետ Namespace
и ClusterRole
խմբագրման իրավունքով։ YAML-ի ներկայացուցչությունը կունենա հետևյալ տեսքը.
---
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
(
Ստեղծեք մեկը RoleBinding
Դուք կարող եք դա անել ձեռքով, բայց հարյուր անվանատարածքների նշագիծը հատելուց հետո դա դառնում է հոգնեցուցիչ գործ: Սա այն վայրն է, որտեղ Kubernetes-ի օպերատորները հարմար են. նրանք թույլ են տալիս ավտոմատացնել Kubernetes-ի ռեսուրսների ստեղծումը՝ հիմնվելով ռեսուրսների փոփոխությունների վրա: Մեր դեպքում մենք ուզում ենք ստեղծել RoleBinding
ստեղծագործելիս Namespace
.
Նախ, եկեք սահմանենք գործառույթը main
որը կատարում է պահանջվող կարգավորումը հայտարարությունը գործարկելու համար և այնուհետև կանչում է հայտարարության գործողություն.
(Նշում. թարգմ.այստեղ և ներքևում կոդի մեկնաբանությունները թարգմանված են ռուսերեն: Բացի այդ, նահանջը ուղղվել է բացատների փոխարեն [խորհուրդ է տրվում Go] ներդիրների փոխարեն բացառապես Habr դասավորության շրջանակներում ավելի լավ ընթեռնելի լինելու նպատակով: Յուրաքանչյուր ցուցակից հետո կան հղումներ դեպի բնօրինակը GitHub-ում, որտեղ պահվում են անգլերեն մեկնաբանությունները և ներդիրները:)
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() // Ожидаем, что все остановлено
}
Մենք անում ենք հետևյալը.
- Մենք կարգավորում ենք կարգավորիչը օպերացիոն համակարգի հատուկ ազդանշանների համար՝ օպերատորի նրբագեղ դադարեցման համար:
- Մենք օգտագործում ենք
WaitGroup
հայտը դադարեցնելուց առաջ նրբորեն դադարեցնել բոլոր գորուտինները: - Մենք ապահովում ենք մուտք դեպի կլաստեր՝ ստեղծելով
clientset
. - Մենք մեկնարկում ենք
NamespaceController
, որի մեջ կգտնվի մեր ողջ տրամաբանությունը։
Հիմա տրամաբանության հիմք է պետք, իսկ մեր դեպքում սա նշվածն է 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
}
(
Այստեղ մենք կարգավորում ենք SharedIndexInformer
, որն արդյունավետորեն (օգտագործելով քեշ) կսպասի անվանատարածքների փոփոխություններին (կարդացեք ավելին տեղեկատուների մասին հոդվածում»EventHandler
տեղեկատուին, որպեսզի անվանատարածք ավելացնելիս (Namespace
) ֆունկցիան կոչվում է createRoleBinding
.
Հաջորդ քայլը այս գործառույթի սահմանումն է 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))
}
}
(
Մենք ստանում ենք անվանումների տարածքը որպես obj
և այն վերածել օբյեկտի Namespace
. Այնուհետև մենք սահմանում ենք RoleBinding
, սկզբում նշված YAML ֆայլի հիման վրա՝ օգտագործելով տրամադրված օբյեկտը Namespace
և ստեղծելով RoleBinding
. Ի վերջո, մենք գրանցում ենք, թե արդյոք ստեղծումը հաջող էր:
Վերջին գործառույթը, որը պետք է սահմանվի 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
}
(
Այստեղ մենք խոսում ենք WaitGroup
որ մենք գործարկում ենք գորուտինը և հետո զանգում namespaceInformer
, որը նախկինում սահմանվել է։ Երբ կանգառի ազդանշանը հասնի, այն կավարտի գործառույթը, տեղեկացրեք WaitGroup
, որն այլևս չի կատարվում, և այս ֆունկցիան դուրս կգա:
Kubernetes կլաստերի վրա այս հայտարարությունը կառուցելու և գործարկելու մասին տեղեկությունները կարելի է գտնել այստեղ
Դա այն օպերատորի համար է, որը ստեղծում է RoleBinding
երբ Namespace
Kubernetes կլաստերում, պատրաստ է:
Source: www.habr.com