Ampliación de kubernetes cliente-go

Estoy escribiendo un controlador que mira kubernetes servicio objetos, y crea tráficos si contienen cierta etiqueta.

Ya que los kubernetes nativos van cliente no apoya el objeto trafficsplit, tuve que encontrar una manera y extender el cliente para que reconocer el recurso personalizado. Encontré esto. guía que fue útil y me permitió abordar el tema así -

import (
    "splitClientV1alpha1 "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned/typed/split/v1alpha1"
    "k8s.io/client-go/kubernetes"
    ...
)

// getting ./kube/config from file
kubehome := filepath.Join(homedir.HomeDir(), ".kube", "config")
// Building the config from file
kubeConfig, err = clientcmd.BuildConfigFromFlags("", kubehome)
if err != nil {
    return fmt.Errorf("error loading kubernetes configuration: %w", err)
}

// Creating the native client object
kubeClient, err := kubernetes.NewForConfig(kubeConfig)
if err != nil {
    return fmt.Errorf("error creating kubernetes client: %w", err)
}

// Creating another clientset exclusively for the custom resource
splitClient, err := splitClientV1alpha1.NewForConfig(kubeConfig)
if err != nil {
    return fmt.Errorf("error creating split client: %s", err)
}

Siento que debe haber una manera de extender el objeto kubeClient con el esquema de tráficosplit, en lugar de crear un cliente separado como lo hice. ¿Hay alguna manera de lograr esto?

Pregunta hecha hace 3 años, 5 meses, 0 días - Por javajedi


3 Respuestas:

  • ¡Esto es definitivamente posible! Usted quiere utilizar las características de extensión de struct de go :)

    Básicamente, creamos una estructura que extiende ambas kubernetes.Clientset y splitClientV1alpha1.SplitV1alpha1Client e inicializarlo usando código muy similar al suyo arriba. Entonces podemos utilizar métodos de cualquier cliente en esa estructura.

    import (
        "fmt"
        splitClientV1alpha1 "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned/typed/split/v1alpha1"
        "k8s.io/client-go/kubernetes"
        "k8s.io/client-go/tools/clientcmd"
        "k8s.io/client-go/util/homedir"
        "path/filepath"
    )
    
    type MyKubeClient struct {
        kubernetes.Clientset
        splitClientV1alpha1.SplitV1alpha1Client
    }
    
    func getClient() (*MyKubeClient, error) {
        // getting ./kube/config from file
        kubehome := filepath.Join(homedir.HomeDir(), ".kube", "config")
        // Building the config from file
        kubeConfig, err := clientcmd.BuildConfigFromFlags("", kubehome)
        if err != nil {
            return nil, fmt.Errorf("error loading kubernetes configuration: %w", err)
        }
    
        // Creating the native client object
        kubeClient, err := kubernetes.NewForConfig(kubeConfig)
        if err != nil {
            return nil, fmt.Errorf("error creating kubernetes client: %w", err)
        }
    
        // Creating another clientset exclusively for the custom resource
        splitClient, err := splitClientV1alpha1.NewForConfig(kubeConfig)
        if err != nil {
            return nil, fmt.Errorf("error creating split client: %s", err)
        }
    
        return &MyKubeClient{
            Clientset:           *kubeClient,
            SplitV1alpha1Client: *splitClient,
        }, nil
    }
    
    func doSomething() error {
        client, err := getClient()
        if err != nil {
            return err
        }
    
        client.CoreV1().Pods("").Create(...)
        client.TrafficSplits(...)
    }
    

    Si necesita pasar a su cliente personalizado a una función que sólo espera el original kubernetes.ClientSet, puedes hacerlo con:

    
    func doSomething() error {
        client, err := getClient()
        if err != nil {
            return err
        }
    
        useClientSet(&client.Clientset)
    }
    
    func useOriginalKubeClientSet(clientSet *kubernetes.Clientset) {
        # ... do things
    }
    

    Respondida el Dec 19, 2020 a las 07:45 - por compilercaptain

    Votos positivos: 0 | Votos negativos: 0

  • Sí, puedes extender el cliente de Kubernetes para que pueda manejar recursos personalizados como TrafficSplit utilizando CRD (Custom Resource Definitions). Para lograr esto, necesitas registrar el esquema del recurso personalizado en el cliente de Kubernetes.

    Aquí te dejo un ejemplo de cómo podrías hacerlo:

    go
    import (
        "k8s.io/client-go/kubernetes"
        "k8s.io/client-go/rest"
        "k8s.io/client-go/util/retry"
        myv1alpha1 "github.com/example.com/api/v1alpha1"
        myclientset "github.com/example.com/clientset/versioned"
        myinformers "github.com/example.com/informers/externalversions"
        mylisters "github.com/example.com/listers"
    )
    
    func extendClientWithCustomResource(kubeClient kubernetes.Clientset, kubeConfig rest.Config) (*kubernetes.Clientset, error) {
        customClient, err := myclientset.NewForConfig(kubeConfig)
        if err != nil {
            return nil, err
        }
    
        // Create informers for custom resource
        myInformersFactory := myinformers.NewSharedInformerFactory(customClient, 0)
        customInformer := myInformersFactory.Example().V1alpha1().MyResources().Informer()
    
        // Create lister for custom resource
        customLister := mylisters.NewMyResourceLister(customInformer.GetIndexer())
    
        // You can now use customClient to interact with your custom resource
    
        // Example operations
        retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
            customResource, err := customClient.ExampleV1alpha1().MyResources(namespace).Get(name, metav1.GetOptions{})
            if err != nil {
                return err
            }
    
            // Perform operations on customResource
    
            _, updateErr := customClient.ExampleV1alpha1().MyResources(namespace).Update(customResource)
            return updateErr
        })
    
        if retryErr != nil {
            return nil, retryErr
        }
    
        return kubeClient, nil
    }
    
    // Usage in your code
    kubeClient, err := kubernetes.NewForConfig(kubeConfig)
    if err != nil {
        return nil, fmt.Errorf("error creating kubernetes client: %w", err)
    }
    
    kubeClient, err = extendClientWithCustomResource(kubeClient, kubeConfig)
    if err != nil {
        return nil, fmt.Errorf("error extending client with custom resource: %w", err)
    }
    

    En este ejemplo, extendClientWithCustomResource registra el esquema del recurso personalizado MyResource en el cliente de Kubernetes. Luego, puedes usar el customClient para interactuar con tu recurso personalizado.

    Es importante tener en cuenta que cada recurso personalizado puede tener sus propias definiciones y es necesario ajustar el código a la estructura de tu recurso personalizado y a su ubicación dentro del código fuente de tu proyecto.

    Espero que esta información te sea útil. ¡Déjame saber si tienes alguna otra pregunta!

    Respondida el Dec 20, 2020 a las 07:43 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Sí, es posible ampliar el objeto kubeClient para incluir el esquema trafficsplit. Puedes hacerlo usando el paquete kubernetes/client-go/dynamic. Aquí tienes un ejemplo de cómo hacerlo:

    
    import (
        "context"
        "fmt"
        "io"
    
        "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha1"
        dynamic "k8s.io/client-go/dynamic/fake"
        "k8s.io/client-go/restmapper"
        "k8s.io/client-go/tools/clientcmd"
    )
    
    func main() {
        // Get the kubeconfig path
        kubehome := filepath.Join(homedir.HomeDir(), ".kube", "config")
        // Build the config from the kubeconfig file
        kubeConfig, err := clientcmd.BuildConfigFromFlags("", filepath.Join(kubehome))
        if err != nil {
            panic(err)
        }
    
        // Create the dynamic client
        dynamicClient, err := dynamic.NewForConfig(kubeConfig)
        if err != nil {
            panic(err)
        }
    
        // Create the discovery client
        discoveryClient, err := restmapper.NewDiscoveryClientForConfig(kubeConfig)
        if err != nil {
            panic(err)
        }
    
        // Add the trafficsplit schema to the discovery client
        if err := discoveryClient.AddとはいえResourceSchema("split.smi-spec.io", v1alpha1.SchemeGroupVersion.WithResource("trafficsplits")); err != nil {
            panic(err)
        }
    
        // Create the extended client
        extendedClient := dynamicClient.Resource(
            discoveryClient.ResourceNamesForGroupVersionResource("split.smi-spec.io", "v1alpha1", "trafficsplits"),
            "",
        )
    
        // Use the extended client to create a trafficsplit
        trafficsplit := &v1alpha1.TrafficSplit{
            TypeMeta: metav1.TypeMeta{
                APIVersion: "split.smi-spec.io/v1alpha1",
                Kind:       "TrafficSplit",
            },
            Metadata: metav1.Metadata{
                Name: "my-trafficsplit",
            },
            Spec: v1alpha1.TrafficSplitSpec{
                Backends: []v1alpha1.TrafficSplitBackend{
                    {
                        Service: "my-service",
                        Weight:  50,
                    },
                },
            },
        }
        if _, err := extendedClient.Create(context.TODO(), trafficsplit, metav1.CreateOptions{}); err != nil {
            panic(err)
        }
    
        // Get the created trafficsplit
        if got, err := extendedClient.Get(context.TODO(), "my-trafficsplit", metav1.GetOptions{}); err != nil {
            panic(err)
        } else {
            fmt.Fprintf(io.Stdout, "Got trafficsplit: %v", got)
        }
    }
    

    Ten en cuenta que este es un ejemplo simplified, y es posible que necesites hacer algunos cambios para adaptarlo a tu caso de uso específico. Por ejemplo, es posible que necesites añadir el esquema trafficsplit a la lista de esquemas aceptados en la configuración del cliente.

    Respondida el Dec 20, 2020 a las 07:52 - por Gemini

    Votos positivos: 0 | Votos negativos: 0