Σημείωση. μετάφρ.: Οι χειριστές είναι βοηθητικό λογισμικό για το 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
που κάνει την απαιτούμενη ρύθμιση για την εκτέλεση της δήλωσης και στη συνέχεια καλεί την ενέργεια της δήλωσης:
(Σημείωση. μετάφρ.: εδώ και κάτω τα σχόλια στον κώδικα μεταφράζονται στα ρωσικά. Επιπλέον, η εσοχή έχει διορθωθεί σε κενά αντί για καρτέλες [προτείνεται στο Μετάβαση] αποκλειστικά για λόγους καλύτερης αναγνωσιμότητας εντός της διάταξης 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