25 Erstellen eines Kubernetes Operators mit KubeBuilder

KubeBuilder erleichtert die Erstellung von Kubernetes Operatoren, indem es Werkzeuge und Bibliotheken bereitstellt, um Custom Resource Definitions (CRDs) und Controller zu erstellen und zu verwalten. Mit KubeBuilder können Sie den gesamten Lebenszyklus einer benutzerdefinierten Ressource verwalten.

25.0.1 Installation von KubeBuilder

Bevor wir anfangen, müssen wir KubeBuilder installieren. Sie können die neueste Version von der offiziellen KubeBuilder GitHub-Seite herunterladen und installieren. Für Unix-Systeme können Sie das folgende Kommando verwenden:

curl -L https://github.com/kubernetes-sigs/kubebuilder/releases/download/v3.2.0/kubebuilder_3.2.0_linux_amd64.tar.gz | tar -xz -C /usr/local/bin/

25.1 Ein neues Projekt mit KubeBuilder erstellen

Erstellen wir ein neues KubeBuilder-Projekt. Wir starten damit, ein neues Verzeichnis für unser Projekt zu erstellen und KubeBuilder zu initialisieren:

mkdir my-operator
cd my-operator
kubebuilder init --domain example.com --repo example.com/my-operator

In diesem Beispiel initialisieren wir ein neues KubeBuilder-Projekt mit der Domäne example.com und dem Repository example.com/my-operator.

25.2 Eine neue API und einen Controller erstellen

Nachdem wir das Projekt initialisiert haben, erstellen wir eine neue API und den zugehörigen Controller:

kubebuilder create api --group webapp --version v1 --kind Guestbook

Dieses Kommando generiert die notwendigen Dateien für eine neue API namens Guestbook in der Gruppe webapp und Version v1. Es erstellt auch die grundlegenden Strukturen für die CRD und den Controller.

25.3 Implementierung der Custom Resource Definition (CRD)

Öffnen Sie die Datei api/v1/guestbook_types.go, die die Struktur unserer benutzerdefinierten Ressource definiert:

package v1

import (
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!

// GuestbookSpec defines the desired state of Guestbook
type GuestbookSpec struct {
    // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
    // Important: Run "make" to regenerate code after modifying this file

    // Foo is an example field of Guestbook. Edit guestbook_types.go to remove/update
    Foo string `json:"foo,omitempty"`
}

// GuestbookStatus defines the observed state of Guestbook
type GuestbookStatus struct {
    // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
    // Important: Run "make" to regenerate code after modifying this file
}

//+kubebuilder:object:root=true
//+kubebuilder:subresource:status

// Guestbook is the Schema for the guestbooks API
type Guestbook struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`

    Spec   GuestbookSpec   `json:"spec,omitempty"`
    Status GuestbookStatus `json:"status,omitempty"`
}

//+kubebuilder:object:root=true

// GuestbookList contains a list of Guestbook
type GuestbookList struct {
    metav1.TypeMeta `json:",inline"`
    metav1.ListMeta `json:"metadata,omitempty"`
    Items           []Guestbook `json:"items"`
}

func init() {
    SchemeBuilder.Register(&Guestbook{}, &GuestbookList{})
}

Passen Sie die GuestbookSpec an, um die gewünschten Felder zu definieren. Beispiel:

// GuestbookSpec defines the desired state of Guestbook
type GuestbookSpec struct {
    Size int32 `json:"size"`
}

25.4 Implementierung des Controllers

Öffnen Sie die Datei controllers/guestbook_controller.go, die die Logik des Controllers enthält. Fügen Sie die Reconcile-Logik hinzu, um die gewünschte Zustandsänderung zu implementieren:

package controllers

import (
    "context"
    "fmt"
    "k8s.io/apimachinery/pkg/api/errors"
    ctrl "sigs.k8s.io/controller-runtime"
    "sigs.k8s.io/controller-runtime/pkg/client"
    "sigs.k8s.io/controller-runtime/pkg/log"
    examplev1 "example.com/my-operator/api/v1"
)

// GuestbookReconciler reconciles a Guestbook object
type GuestbookReconciler struct {
    client.Client
    Scheme *runtime.Scheme
}

//+kubebuilder:rbac:groups=webapp.example.com,resources=guestbooks,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=webapp.example.com,resources=guestbooks/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=webapp.example.com,resources=guestbooks/finalizers,verbs=update

func (r *GuestbookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    _ = log.FromContext(ctx)

    // Fetch the Guestbook instance
    guestbook := &examplev1.Guestbook{}
    err := r.Get(ctx, req.NamespacedName, guestbook)
    if err != nil {
        if errors.IsNotFound(err) {
            // Object not found, return. Created objects are automatically garbage collected.
            // For additional cleanup logic use finalizers.
            return ctrl.Result{}, nil
        }
        // Error reading the object - requeue the request.
        return ctrl.Result{}, err
    }

    // Implement your business logic here
    fmt.Printf("Reconciling Guestbook %s/%s\n", guestbook.Namespace, guestbook.Name)

    return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *GuestbookReconciler) SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
        For(&examplev1.Guestbook{}).
        Complete(r)
}

In diesem Beispiel wird ein Controller definiert, der die Guestbook-Ressource überwacht und entsprechende Aktionen durchführt.

25.5 Erstellen und Bereitstellen des Operators

Nachdem wir die CRD und den Controller implementiert haben, können wir den Operator erstellen und im Kubernetes-Cluster bereitstellen. Führen Sie die folgenden Kommandos aus:

25.5.1 Erstellen des Operators

make install
make run

25.5.2 Bereitstellen des Operators

Erstellen Sie ein Docker-Image und deployen Sie es in Ihrem Kubernetes-Cluster:

make docker-build docker-push IMG=<your-image-name>
make deploy IMG=<your-image-name>

Stellen Sie sicher, dass Sie <your-image-name> durch den tatsächlichen Namen des Docker-Images ersetzen.