Kubernetes - client-go

Last Updated: 2024-01-28


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

config + http.Client = RESTClient



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 {

list and watch



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).


  • 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.

dynamicClient, err := dynamic.NewForConfig(config)


  • 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


=> 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")


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


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 {
	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 (
restConfig, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig)

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

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

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


rateLimiter is passed from config to client to request.