Not. tercüme: Operatörler, belirli olaylar meydana geldiğinde küme nesneleri üzerinde rutin eylemlerin yürütülmesini otomatikleştirmek için tasarlanmış Kubernetes için yardımcı yazılımlardır. Operatörler hakkında zaten yazmıştık.
Kubernetes için bir operatör oluşturmaya yönelik, kodun incelenmesiyle ilgili dokümantasyon bulma girişimlerimin ardından, bu yazıyı gerçek hayattan bir örnekle yazmaya karar verdim.
Açıklanacak örnek şudur: Kubernetes kümemizde her biri Namespace
bir takımın sanal alan ortamını temsil ediyor ve takımların yalnızca kendi sanal alanlarda oynayabilmesi için bunlara erişimi sınırlamak istedik.
Bir kullanıcıya aşağıdaki özelliklere sahip bir grup atayarak istediğinizi elde edebilirsiniz: RoleBinding
spesifik olarak Namespace
и ClusterRole
düzenleme haklarına sahip. YAML gösterimi şu şekilde görünecektir:
---
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
(
Bir tane yarat RoleBinding
Bunu manuel olarak yapabilirsiniz, ancak yüz ad alanı sınırını geçtikten sonra sıkıcı bir iş haline gelir. Kubernetes operatörlerinin kullanışlı olduğu nokta burasıdır; kaynaklarda yapılan değişikliklere göre Kubernetes kaynaklarının oluşturulmasını otomatikleştirmenize olanak tanır. Bizim durumumuzda yaratmak istiyoruz RoleBinding
oluştururken Namespace
.
Öncelikle fonksiyonu tanımlayalım main
bu, ifadeyi çalıştırmak için gerekli kurulumu yapar ve ardından ifade eylemini çağırır:
(Not. tercüme: burada ve altında koddaki yorumlar Rusçaya çevrilmiştir. Ayrıca, yalnızca Habr düzeninde daha iyi okunabilirlik sağlamak amacıyla girintiler [Go'da önerilir] sekmeleri yerine boşluklara göre düzeltildi. Her listelemeden sonra, İngilizce yorumların ve sekmelerin saklandığı GitHub'da orijinaline bağlantılar bulunur.)
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() // Ожидаем, что все остановлено
}
Aşağıdakileri yapıyoruz:
- Operatörün sorunsuz bir şekilde sonlandırılmasını sağlamak amacıyla belirli işletim sistemi sinyalleri için bir işleyici yapılandırıyoruz.
- Kullanırız
WaitGroup
Uygulamayı sonlandırmadan önce tüm goroutinleri zarif bir şekilde durdurmak için. - Oluşturarak Cluster'a erişim sağlıyoruz.
clientset
. - koşmak
NamespaceController
, tüm mantığımızın yer alacağı yer.
Artık mantık için bir temele ihtiyacımız var ve bizim durumumuzda bahsedilen de bu. 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
}
(
Burada yapılandırıyoruz SharedIndexInformer
, etkili bir şekilde (önbellek kullanarak) ad alanlarındaki değişiklikleri bekleyecektir (makaledeki muhbirler hakkında daha fazla bilgi edinin “EventHandler
bilgilendiriciye, böylece bir ad alanı eklerken (Namespace
) işlevi çağrılır createRoleBinding
.
Bir sonraki adım bu fonksiyonu tanımlamaktır 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))
}
}
(
Ad alanını şu şekilde alıyoruz: obj
ve onu bir nesneye dönüştürün Namespace
. Sonra tanımlarız RoleBinding
, sağlanan nesneyi kullanarak, başlangıçta belirtilen YAML dosyasına göre Namespace
ve yaratmak RoleBinding
. Son olarak, oluşturma işleminin başarılı olup olmadığını günlüğe kaydederiz.
Tanımlanacak son fonksiyon 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
}
(
İşte konuşuyoruz WaitGroup
goroutine'i başlatıyoruz ve sonra çağırıyoruz namespaceInformer
Daha önce tanımlanmış olan . Durdurma sinyali geldiğinde fonksiyonu sonlandıracaktır, bilgilendirin WaitGroup
artık yürütülmeyecek ve bu işlevden çıkılacaktır.
Bu bildirimi bir Kubernetes kümesinde oluşturmaya ve çalıştırmaya ilişkin bilgileri şu adreste bulabilirsiniz:
Oluşturan operatör için bu kadar RoleBinding
görünüşte Namespace
Kubernetes kümesinde hazır.
Kaynak: habr.com