توجه داشته باشید. ترجمه: اپراتورها نرمافزار کمکی برای Kubernetes هستند که برای خودکارسازی اجرای اقدامات معمول روی اشیاء خوشهای هنگام وقوع رویدادهای خاص طراحی شدهاند. قبلاً در مورد اپراتورها نوشته ایم
تصمیم گرفتم این پست را با یک مثال واقعی بنویسم پس از تلاشهایم برای یافتن مستندات مربوط به ایجاد یک اپراتور برای Kubernetes، که از طریق مطالعه کد انجام شد.
مثالی که توضیح داده خواهد شد این است: در خوشه Kubernetes ما، هر کدام Namespace
محیط sandbox یک تیم را نشان میدهد و ما میخواستیم دسترسی به آنها را محدود کنیم تا تیمها فقط بتوانند در 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، آماده است.
منبع: www.habr.com