logo

Kubernetes - client-go

Last Updated: 2024-01-28

https://github.com/kubernetes/client-go

Built-in clients like kubectl and kubelet are all based on client-go.

config + http.Client = RESTClient

vendor/k8s.io/client-go/rest/client.go
vendor/k8s.io/client-go/rest/request.go

ListerWatcher

The ListerWatcher interface in the client-go SDK, used in all Go-based Kubernetes controllers, plays a critical role on how these events are generated, propagated and reliably consumed throughout the various Kubernetes components and actors.

type ListerWatcher interface {
  Lister
  Watcher
}

list and watch

client.Get()
client.Watch()

Cache

client-go cache:

  • Reflector watches a specified resource and causes all changes to be reflected in the given store.
  • Store is the interface of the cache; ExpirationCache is one of the implementation.

Package cache is a client-side caching mechanism. It is useful for reducing the number of server calls you'd otherwise need to make. Reflector watches a server and updates a Store. Two stores are provided; one that simply caches objects (for example, to allow a scheduler to list currently available nodes), and one that additionally acts as a FIFO queue (for example, to allow a scheduler to process incoming pods).

Clients

  • http.Client: Go's built-in HTTP Client.
  • rest.RESTClient: client-go provides a rest.RESTClient that wraps a http.Client.
  • kubernetes.Clientset: a set of typed clients that provides pre-generated local API objects for every core resource type (Pods, Deployments, Services, etc.).
  • dynamic.DynamicClient: client-go/dynamic package provides a dynamic client which can perform RESTful operations on arbitrary API resources. The struct dynamic.Interface uses unstructured.Unstructured to represent all object values from the API server. The dynamic package defers all data bindings until runtime.
import
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/dynamic"

dynamicClient, err := dynamic.NewForConfig(config)

Configuration

  • In-Cluster configuration: used when running inside a pod and uses the service account token mounted to the pod /var/run/secrets/kubernetes.io/serviceaccount/token.
    • aud should match API server’s --api-audiences flag.
  • Out-of-Cluster configuration: used when running outside of the cluster and uses either a provided kubeconfig file or the current user’s default kubeconfig file.

The controller-runtime library provides a GetConfig() that first attempts Out-of-Cluster configuration, and if it fails, attempts In-Cluster configuration.

Code Examples

Get in cluster rest config

// vendor/k8s.io/client-go/rest/config.go

// returns a rest Config
rest.InClusterConfig()

RESTClientGetter

=> To RESTConfig: rest.Config ("k8s.io/client-go/rest") => To DiscoveryClient: discovery.CachedDiscoveryInterface ("k8s.io/client-go/discovery") => To RESTMapper: meta.RESTMapper ("k8s.io/apimachinery/pkg/api/meta")

Retry

import "k8s.io/client-go/util/retry"
retry.RetryOnConflict(retryBackoff, func() error {
    //logic
})

Backoff

ctx := context.Background()
secret := &corev1.Secret{}
if err := retry.OnError(wait.Backoff{
  Duration: 10 * time.Second,
  Steps:    6,
}, func(err error) bool { return true }, func() error {
  if err := c.Get(ctx, client.ObjectKey{
    Namespace: "kube-system",
    Name:      "foo-secret",
  }, secret); err != nil {
    return err
  }
  return nil
}); err != nil {
  return fmt.Errorf("failed to get secret foo-secret: %w", err)
}

kubeconfig => clientSet

bytesArray := []byte(*kubeconfig)

clientConfig ,err:= clientcmd.NewClientConfigFromBytes(bytesArray)
if err!=nil {
	logs.Error(err.Error())
	return nil
}

restConfig, _ := clientConfig.ClientConfig()
clientSet, err := kubernetes.NewForConfig(restConfig)

kubeconfig => dynamic client

dynamic client has no knowledge about the resource you want to consume

config, err := rest.InClusterConfig()
if err != nil {
    return nil, err
}

dynClient, err := dynamic.NewForConfig(config)
if err != nil {
    return nil, err
}

How to get kubeconfig from secrets?

capiconfig "sigs.k8s.io/cluster-api/util/kubeconfig"

nn := types.NamespacedName{
  Name: consts.FooName,
  Namespace: consts.FooNamespace,
}
kubeconfig, err := capiconfig.FromSecret(ctx, client, nn)
// kubeconfig []byte

ClientGetter to Client

clientConfig, err := clientGetter.ToRESTConfig()
if err != nil {
    return err
}
client, err := client.New(clientConfig, client.Options{})
if err != nil {
    return err
}

kubeconfig => restconfig

import (
  "k8s.io/client-go/tools/clientcmd"
)
restConfig, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig)

restConfig => (client-go) clientset => node

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

kubeClient, err := kubernetes.NewForConfig(restConfig)
// deal with err...
nodes, err := kubeClient.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{})

RateLimiter

rateLimiter is passed from config to client to request.