Community

The community for k8s.io/client-go is closely tied to the Kubernetes community. You can contribute to k8s.io/client-go by submitting pull requests to the main Kubernetes repository.

Contributing to Client-go

The Kubernetes main repository is the primary location for client-go development. README.md specifies that changes in the staging area of the Kubernetes repository are published to the k8s.io/client-go repository daily.

Finding Help

The Kubernetes community is very active and helpful. Here are some resources to find help:

Example: Using a Client-go Example

The k8s.io/client-go repository provides a number of examples to help you get started. For example, the out-of-cluster-client-configuration example demonstrates how to configure a client-go client to interact with a Kubernetes cluster from outside the cluster. The example code can be found in the examples/out-of-cluster-client-configuration directory.

Code Example:

// ... other imports
import (
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
)

func main() {
    // creates the in-cluster config
    config, err := rest.InClusterConfig()
    if err != nil {
        panic(err.Error())
    }

    // creates the clientset
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    // get pods from the default namespace
    pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})
    if err != nil {
        panic(err.Error())
    }

    // print pod information
    for _, pod := range pods.Items {
        fmt.Printf("Pod Name: %s\n", pod.Name)
    }
}

This code first creates a rest.Config object using the rest.InClusterConfig() function. This function automatically configures the client-go client to communicate with the Kubernetes cluster. Then, it creates a kubernetes.Clientset object using the kubernetes.NewForConfig() function. The Clientset object provides methods to interact with the Kubernetes API. Finally, the code uses the clientset.CoreV1().Pods("").List() function to retrieve a list of pods from the default namespace.

Code Example: Using the informer Framework

The informer framework is a powerful tool for building controllers that monitor and manage Kubernetes resources. It provides a way to efficiently listen for changes to resources and respond to them in a timely manner. The informer framework is built on top of the client-go library and is a valuable tool for building reliable and scalable Kubernetes applications.

Code Example:

// ... other imports
import (
    "fmt"
    v1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/apimachinery/pkg/watch"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/cache"
)

func main() {
    // creates the in-cluster config
    config, err := rest.InClusterConfig()
    if err != nil {
        panic(err.Error())
    }

    // creates the clientset
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    // create a new informer for pods
    podInformer := cache.NewInformer(
        &cache.ListWatch{
            ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
                return clientset.CoreV1().Pods("").List(options)
            },
            WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
                return clientset.CoreV1().Pods("").Watch(options)
            },
        },
        &v1.Pod{},
        0,
        cache.ResourceEventHandlerFuncs{
            AddFunc: func(obj interface{}) {
                pod := obj.(*v1.Pod)
                fmt.Printf("Pod added: %s\n", pod.Name)
            },
            UpdateFunc: func(oldObj, newObj interface{}) {
                oldPod := oldObj.(*v1.Pod)
                newPod := newObj.(*v1.Pod)
                fmt.Printf("Pod updated: %s\n", oldPod.Name)
            },
            DeleteFunc: func(obj interface{}) {
                pod := obj.(*v1.Pod)
                fmt.Printf("Pod deleted: %s\n", pod.Name)
            },
        },
    )

    // start the informer
    stopCh := make(chan struct{})
    defer close(stopCh)
    go podInformer.Run(stopCh)

    // wait for the informer to sync
    if !cache.WaitForCacheSync(stopCh, podInformer.HasSynced) {
        panic("Failed to sync cache")
    }

    // your code here
}

This code first creates a cache.NewInformer() object. This object is responsible for listening for changes to pods in the cluster. The ListFunc and WatchFunc functions specify how the informer should retrieve the list of pods and watch for changes to them. The ResourceEventHandlerFuncs object defines the functions that will be called when the informer detects changes to pods.

Once the informer is created, the code starts it using the podInformer.Run() function. The stopCh channel is used to signal the informer to stop. The code then waits for the informer to synchronize its cache with the Kubernetes API using the cache.WaitForCacheSync() function.

After the informer has synchronized, the code can access the list of pods from the informer’s cache using the podInformer.GetIndexer() function. The code can also register event handlers to be called when the informer detects changes to pods.

Using informer to build a controller:

The informer framework is a key component of building controllers in Kubernetes. Controllers are applications that monitor and manage the state of Kubernetes resources. They use the informer to listen for changes to resources and then take actions to ensure that the resources are in the desired state.

For example, a controller could be used to automatically scale a deployment based on the number of pods in a service. When the number of pods in the service falls below a certain threshold, the controller could automatically scale the deployment to add more pods. When the number of pods in the service exceeds a certain threshold, the controller could automatically scale the deployment to remove pods.

Example: Using Leader Election

The Leader Election package helps you design HA controllers that run in Kubernetes. This example illustrates how to use this package.

Code Example:

// ... other imports
import (
    "context"
    "fmt"
    "time"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/leaderelection"
    "k8s.io/client-go/tools/leaderelection/resourcelock"
)

func main() {
    // creates the in-cluster config
    config, err := rest.InClusterConfig()
    if err != nil {
        panic(err.Error())
    }

    // creates the clientset
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    // Create a leader election resource lock
    lock := resourcelock.NewEndpointsLock("my-leader-election", "my-namespace", clientset.CoreV1(), resourcelock.ResourceLockConfig{
        Identity:      "my-leader",
        EventRecorder: createRecorder(clientset, "leader-election"),
    })

    // Create a leader election configuration
    leaderelection.RunOrDie(context.Background(), leaderelection.LeaderElectionConfig{
        Lock:          lock,
        LeaseDuration: 15 * time.Second,
        RenewDeadline: 10 * time.Second,
        RetryPeriod:   5 * time.Second,
        Callbacks: leaderelection.LeaderCallbacks{
            OnStartedLeading: func(ctx context.Context) {
                fmt.Println("I am the leader!")

                // Your code to run when you are the leader
                // ...

            },
            OnStoppedLeading: func() {
                fmt.Println("I am no longer the leader.")
            },
            OnNewLeader: func(identity string) {
                if identity == "my-leader" {
                    return
                }
                fmt.Printf("New leader elected: %s\n", identity)
            },
        },
    })

}

func createRecorder(clientset *kubernetes.Clientset, name string) record.EventBroadcaster {
    eventBroadcaster := record.NewBroadcaster()
    eventBroadcaster.StartLogging(func(event *v1.Event) {
        fmt.Printf("Event: %+v\n", event)
    })

    eventBroadcaster.StartRecordingToSink(&v1.EventSinkImpl{Interface: clientset.CoreV1().Events("")})
    return eventBroadcaster
}

This code first creates a resourcelock.NewEndpointsLock() object. This object defines the resource lock that will be used for leader election. The lock is based on the Kubernetes Endpoints resource. The Identity field specifies the identity of the leader, which is used to identify the leader in the lock. The EventRecorder field specifies the recorder that will be used to log leader election events.

Next, the code creates a leaderelection.LeaderElectionConfig object. This object defines the configuration for leader election. The Lock field specifies the resource lock that will be used for leader election. The LeaseDuration, RenewDeadline, and RetryPeriod fields specify the duration of the leader lease, the deadline for renewing the lease, and the period to wait before retrying to acquire the lease, respectively. The Callbacks field specifies the functions that will be called when the leader is elected, loses the leadership, or a new leader is elected.

Finally, the code starts the leader election process using the leaderelection.RunOrDie() function. This function starts the leader election loop and blocks until the leader election process is stopped.

Using Leader Election in a Controller:

The Leader Election package is a valuable tool for building HA controllers in Kubernetes. It ensures that only one instance of a controller is running at a time, even if multiple instances of the controller are deployed. This ensures that the controller is operating in a consistent and reliable manner.

For example, a controller could use leader election to ensure that only one instance of the controller is responsible for managing a set of resources. This ensures that multiple instances of the controller do not try to update the same resources simultaneously, which could lead to data corruption.

Important Note:

Remember, these examples are just a starting point. They can be customized and extended to meet the specific needs of your applications. For more detailed information on using k8s.io/client-go, please refer to the official documentation at https://kubernetes.io/docs/reference/generated/kubernetes-api/.