CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/golang-k8s-io--client-go

Official Go client library for Kubernetes API - typed clients, controllers, and cluster interaction tools

Overview
Eval results
Files

index.mddocs/

k8s.io/client-go

Official Go client library for the Kubernetes API, providing comprehensive tools and clients for building applications, controllers, and operators that communicate with Kubernetes clusters.

Package Information

  • Name: k8s.io/client-go
  • Type: library
  • Language: Go
  • Version: v0.35.0
  • License: Apache-2.0
  • Repository: https://github.com/kubernetes/client-go

Installation

go get k8s.io/client-go@v0.35.0

Quick Start

Creating a Client

In-Cluster Configuration (for pods):

import (
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
)

// rest.InClusterConfig() (*rest.Config, error)
// Returns config from pod's service account
config, err := rest.InClusterConfig()
if err != nil {
    // Handle error
}

// kubernetes.NewForConfig(*rest.Config) (*kubernetes.Clientset, error)
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
    // Handle error
}

Out-of-Cluster Configuration (local development):

import (
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
)

// clientcmd.BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*rest.Config, error)
// Empty masterUrl uses kubeconfig's current-context cluster
// clientcmd.RecommendedHomeFile = ~/.kube/config
config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
if err != nil {
    // Handle error
}

clientset, err := kubernetes.NewForConfig(config)
if err != nil {
    // Handle error
}

Basic CRUD Operations

import (
    "context"
    corev1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// GET: PodInterface.Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Pod, error)
pod, err := clientset.CoreV1().Pods("default").Get(context.TODO(), "my-pod", metav1.GetOptions{})

// LIST: PodInterface.List(ctx context.Context, opts metav1.ListOptions) (*v1.PodList, error)
pods, err := clientset.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})

// CREATE: ServiceInterface.Create(ctx context.Context, service *v1.Service, opts metav1.CreateOptions) (*v1.Service, error)
service := &corev1.Service{
    ObjectMeta: metav1.ObjectMeta{Name: "my-svc"},
    Spec: corev1.ServiceSpec{
        Selector: map[string]string{"app": "myapp"},
        Ports: []corev1.ServicePort{{Port: 80}},
    },
}
result, err := clientset.CoreV1().Services("default").Create(context.TODO(), service, metav1.CreateOptions{})

// UPDATE: DeploymentInterface.Update(ctx context.Context, deployment *v1.Deployment, opts metav1.UpdateOptions) (*v1.Deployment, error)
deployment, err := clientset.AppsV1().Deployments("default").Get(context.TODO(), "my-deploy", metav1.GetOptions{})
if err == nil {
    replicas := int32(3)
    deployment.Spec.Replicas = &replicas
    _, err = clientset.AppsV1().Deployments("default").Update(context.TODO(), deployment, metav1.UpdateOptions{})
}

// DELETE: PodInterface.Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
err = clientset.CoreV1().Pods("default").Delete(context.TODO(), "my-pod", metav1.DeleteOptions{})

Core Concepts

1. Client Types

ClientUse CaseKey MethodsDocumentation
Typed ClientsetBuilt-in K8s resourcesGet, List, Create, Update, Delete, Watch, Patchreference/clientsets.md
Dynamic ClientCustom resources, untyped objectsResource(GVR).Get/List/Create/Update/Deletereference/dynamic-client.md
REST ClientLow-level HTTP controlGet(), Post(), Put(), Delete(), Patch()reference/rest-client.md
Discovery ClientAPI server capabilitiesServerGroups(), ServerResources(), ServerVersion()reference/discovery.md
Metadata ClientLightweight metadata opsGet/List with partial object metadatareference/specialized-clients.md

2. Controller Components

ComponentTypeKey MethodsDocumentation
Informerscache.SharedIndexInformerAddEventHandler(), Run(), HasSynced()reference/controllers.md
ListersLister interfaceList(), Get(), ByNamespace()reference/controllers.md
Work Queuesworkqueue.RateLimitingInterfaceAdd(), Get(), Done(), Forget()reference/tools.md
Leader Electionleaderelection.LeaderElectorRun(), RunOrDie() with callbacksreference/tools.md

3. Core Imports Reference

import (
    // Main typed clientset
    "k8s.io/client-go/kubernetes"
    
    // Configuration
    "k8s.io/client-go/rest"                    // REST config and client
    "k8s.io/client-go/tools/clientcmd"         // Kubeconfig loading
    
    // Dynamic and Discovery
    "k8s.io/client-go/dynamic"                 // Dynamic client for any resource
    "k8s.io/client-go/discovery"               // API discovery
    
    // Controller infrastructure
    "k8s.io/client-go/informers"               // Shared informer factories
    "k8s.io/client-go/tools/cache"             // Caching, indexing, event handlers
    "k8s.io/client-go/util/workqueue"          // Rate-limiting work queues
    
    // Server-side apply
    "k8s.io/client-go/applyconfigurations"     // Apply configuration builders
    
    // API types (required for typed operations)
    corev1 "k8s.io/api/core/v1"                // Core resources
    appsv1 "k8s.io/api/apps/v1"                // Apps resources
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"  // Common metadata
    
    // Error handling
    apierrors "k8s.io/apimachinery/pkg/api/errors"  // API error checking
)

Key Capabilities

Typed Clientsets

Strongly-typed clients for all built-in Kubernetes API groups with compile-time checking.

// Clientset interface provides access to all API groups
// kubernetes.NewForConfig(*rest.Config) (*kubernetes.Clientset, error)

// API Group Access Methods:
// - CoreV1() corev1.CoreV1Interface
// - AppsV1() appsv1.AppsV1Interface
// - BatchV1() batchv1.BatchV1Interface
// - NetworkingV1() networkingv1.NetworkingV1Interface
// - RbacV1() rbacv1.RbacV1Interface
// - StorageV1() storagev1.StorageV1Interface

coreClient := clientset.CoreV1()        // Pods, Services, ConfigMaps, Secrets, etc.
appsClient := clientset.AppsV1()        // Deployments, StatefulSets, DaemonSets
batchClient := clientset.BatchV1()      // Jobs, CronJobs

// Resource Interface Methods (all resources):
// - Get(ctx, name, opts) (*Resource, error)
// - List(ctx, opts) (*ResourceList, error)
// - Create(ctx, resource, opts) (*Resource, error)
// - Update(ctx, resource, opts) (*Resource, error)
// - Delete(ctx, name, opts) error
// - Watch(ctx, opts) (watch.Interface, error)
// - Patch(ctx, name, patchType, data, opts, subresources...) (*Resource, error)

pods := coreClient.Pods("namespace")             // PodInterface
deployments := appsClient.Deployments("namespace")  // DeploymentInterface

Features: Full CRUD, Watch, Patch (JSON/Merge/Strategic/Apply), Status subresource, Scale subresource

Detailed Documentation

Dynamic Client

Work with custom resources or any Kubernetes object without generated types.

import (
    "k8s.io/client-go/dynamic"
    "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    "k8s.io/apimachinery/pkg/runtime/schema"
)

// dynamic.NewForConfig(*rest.Config) (dynamic.Interface, error)
dynamicClient, err := dynamic.NewForConfig(config)

// GroupVersionResource identifies the resource type
gvr := schema.GroupVersionResource{
    Group:    "stable.example.com",  // API group (empty for core)
    Version:  "v1",                   // API version
    Resource: "crontabs",             // Resource plural name
}

// NamespaceableResourceInterface methods:
// - Namespace(string) ResourceInterface
// - List(ctx, opts) (*unstructured.UnstructuredList, error)
// - Get(ctx, name, opts) (*unstructured.Unstructured, error)
// - Create(ctx, obj, opts) (*unstructured.Unstructured, error)
// - Update(ctx, obj, opts) (*unstructured.Unstructured, error)
// - Delete(ctx, name, opts) error

// Get resource in specific namespace
resource, err := dynamicClient.Resource(gvr).Namespace("default").Get(
    context.TODO(), "my-crontab", metav1.GetOptions{})

// Create resource with unstructured data
obj := &unstructured.Unstructured{
    Object: map[string]interface{}{
        "apiVersion": "stable.example.com/v1",
        "kind":       "CronTab",
        "metadata":   map[string]interface{}{"name": "my-crontab"},
        "spec":       map[string]interface{}{"cronSpec": "* * * * */5"},
    },
}
created, err := dynamicClient.Resource(gvr).Namespace("default").Create(
    context.TODO(), obj, metav1.CreateOptions{})

Detailed Documentation

Controllers and Informers

Build efficient controllers with local caching and event-driven processing.

import (
    "k8s.io/client-go/informers"
    "k8s.io/client-go/tools/cache"
    "time"
)

// SharedInformerFactory creates informers for multiple resources
// informers.NewSharedInformerFactory(client kubernetes.Interface, resyncPeriod time.Duration) SharedInformerFactory
informerFactory := informers.NewSharedInformerFactory(clientset, 10*time.Minute)

// Get resource-specific informer
// Returns PodInformer with methods: Informer(), Lister()
podInformer := informerFactory.Core().V1().Pods()

// SharedIndexInformer.AddEventHandler(handler ResourceEventHandler)
// ResourceEventHandlerFuncs has: AddFunc, UpdateFunc, DeleteFunc
podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
    AddFunc: func(obj interface{}) {
        pod := obj.(*corev1.Pod)
        // Process new pod
    },
    UpdateFunc: func(oldObj, newObj interface{}) {
        oldPod := oldObj.(*corev1.Pod)
        newPod := newObj.(*corev1.Pod)
        // Process updated pod
    },
    DeleteFunc: func(obj interface{}) {
        pod := obj.(*corev1.Pod)
        // Process deleted pod
    },
})

// Start all informers (non-blocking)
// SharedInformerFactory.Start(stopCh <-chan struct{})
stopCh := make(chan struct{})
informerFactory.Start(stopCh)

// Wait for initial cache sync
// SharedInformerFactory.WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
informerFactory.WaitForCacheSync(stopCh)

// Use lister for fast local reads (no API server calls)
// PodLister.Pods(namespace string) PodNamespaceLister
podLister := podInformer.Lister()
pod, err := podLister.Pods("default").Get("my-pod")

Detailed Documentation

Server-Side Apply

Declarative object management with field ownership tracking.

import (
    appsv1ac "k8s.io/client-go/applyconfigurations/apps/v1"
    corev1ac "k8s.io/client-go/applyconfigurations/core/v1"
    metav1ac "k8s.io/client-go/applyconfigurations/meta/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// Build apply configuration with fluent API
// appsv1ac.Deployment(name, namespace string) *DeploymentApplyConfiguration
deploymentApply := appsv1ac.Deployment("my-deployment", "default").
    WithSpec(appsv1ac.DeploymentSpec().
        WithReplicas(3).
        WithSelector(metav1ac.LabelSelector().
            WithMatchLabels(map[string]string{"app": "myapp"})).
        WithTemplate(corev1ac.PodTemplateSpec().
            WithLabels(map[string]string{"app": "myapp"}).
            WithSpec(corev1ac.PodSpec().
                WithContainers(corev1ac.Container().
                    WithName("myapp").
                    WithImage("myapp:v1.0.0")))))

// Apply with field manager
// DeploymentInterface.Apply(ctx, applyConfig, opts) (*v1.Deployment, error)
// ApplyOptions requires FieldManager, optionally Force
result, err := clientset.AppsV1().Deployments("default").Apply(
    context.TODO(),
    deploymentApply,
    metav1.ApplyOptions{
        FieldManager: "my-controller",  // Required: identifies the applier
        Force:        true,              // Optional: take ownership of fields
    })

Benefits: Only specify managed fields, automatic conflict resolution, multiple controllers can manage different fields.

Detailed Documentation

Common Patterns

Error Handling

import apierrors "k8s.io/apimachinery/pkg/api/errors"

pod, err := clientset.CoreV1().Pods("default").Get(context.TODO(), "my-pod", metav1.GetOptions{})
if err != nil {
    // Type-specific error checking functions:
    // - IsNotFound(err) bool - 404 Not Found
    // - IsAlreadyExists(err) bool - 409 Conflict on create
    // - IsConflict(err) bool - 409 Conflict on update (resource version mismatch)
    // - IsForbidden(err) bool - 403 Forbidden (RBAC)
    // - IsUnauthorized(err) bool - 401 Unauthorized
    // - IsInvalid(err) bool - 422 Unprocessable Entity (validation error)
    // - IsServerTimeout(err) bool - 504 Gateway Timeout
    // - IsServiceUnavailable(err) bool - 503 Service Unavailable
    // - IsTooManyRequests(err) bool - 429 Too Many Requests
    // - IsTimeout(err) bool - Client-side timeout
    
    if apierrors.IsNotFound(err) {
        // Resource does not exist - safe to create
    } else if apierrors.IsConflict(err) {
        // Update conflict - fetch latest version and retry
    } else if apierrors.IsForbidden(err) || apierrors.IsUnauthorized(err) {
        // Permission denied - check RBAC
    } else {
        // Other error - log and handle appropriately
    }
}

Watch Resources

import "k8s.io/apimachinery/pkg/watch"

// ResourceInterface.Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
// ListOptions fields:
// - LabelSelector string - Filter by labels (e.g., "app=myapp,env=prod")
// - FieldSelector string - Filter by fields (e.g., "status.phase=Running")
// - ResourceVersion string - Start watch from specific version
// - TimeoutSeconds *int64 - Watch timeout

watcher, err := clientset.CoreV1().Pods("default").Watch(
    context.TODO(),
    metav1.ListOptions{
        LabelSelector: "app=myapp",
        FieldSelector: "status.phase=Running",
    })
if err != nil {
    // Handle error
}

// CRITICAL: Always stop watcher to prevent resource leaks
defer watcher.Stop()

// watch.Interface.ResultChan() <-chan watch.Event
for event := range watcher.ResultChan() {
    // watch.Event.Type: Added, Modified, Deleted, Bookmark, Error
    // watch.Event.Object: runtime.Object (type assert to specific type)
    
    switch event.Type {
    case watch.Added:
        pod := event.Object.(*corev1.Pod)
        // Handle pod addition
    case watch.Modified:
        pod := event.Object.(*corev1.Pod)
        // Handle pod modification
    case watch.Deleted:
        pod := event.Object.(*corev1.Pod)
        // Handle pod deletion
    case watch.Error:
        // Handle error event
    }
}

More Patterns

API Groups Quick Reference

API GroupClientSet MethodCommon ResourcesPackage Import
Core (v1)CoreV1()Pod, Service, ConfigMap, Secret, Namespace, Node, PersistentVolume, PersistentVolumeClaim, Eventcorev1 "k8s.io/api/core/v1"
Apps (v1)AppsV1()Deployment, StatefulSet, DaemonSet, ReplicaSetappsv1 "k8s.io/api/apps/v1"
Batch (v1)BatchV1()Job, CronJobbatchv1 "k8s.io/api/batch/v1"
Networking (v1)NetworkingV1()Ingress, NetworkPolicy, IngressClassnetworkingv1 "k8s.io/api/networking/v1"
RBAC (v1)RbacV1()Role, RoleBinding, ClusterRole, ClusterRoleBindingrbacv1 "k8s.io/api/rbac/v1"
Storage (v1)StorageV1()StorageClass, VolumeAttachment, CSIDriver, CSINodestoragev1 "k8s.io/api/storage/v1"
Autoscaling (v2)AutoscalingV2()HorizontalPodAutoscalerautoscalingv2 "k8s.io/api/autoscaling/v2"
Policy (v1)PolicyV1()PodDisruptionBudgetpolicyv1 "k8s.io/api/policy/v1"
Coordination (v1)CoordinationV1()Lease (for leader election)coordinationv1 "k8s.io/api/coordination/v1"

Package Structure

k8s.io/client-go contains 383 packages organized into categories:

  • kubernetes/typed/* (110+ packages) - Strongly-typed clients for all API groups and versions
  • informers/* (72 packages) - Shared informer factories for efficient caching
  • listers/* (52 packages) - Read-only indexers for cached objects
  • applyconfigurations/* (53 packages) - Server-side apply configuration builders
  • rest - REST client, configuration, rate limiting, authentication
  • dynamic - Dynamic client for untyped resource access
  • discovery - API discovery and server capabilities
  • tools/cache - Caching infrastructure (Store, Indexer, Reflector)
  • tools/clientcmd - Kubeconfig loading and merging
  • util/workqueue - Rate-limiting work queues
  • tools/leaderelection - Leader election for HA controllers
  • tools/record - Event recording
  • tools/pager - Paginated list operations
  • tools/portforward - Pod port forwarding
  • tools/remotecommand - Pod exec and attach
  • metadata - Metadata-only client (partial object access)
  • scale - Scale subresource client

Configuration Patterns

REST Config Options

import "k8s.io/client-go/rest"

config := &rest.Config{
    Host: "https://kubernetes.example.com:6443",  // API server URL
    
    // Authentication (choose one):
    BearerToken: "token",                          // Token auth
    Username: "user",                              // Basic auth
    Password: "pass",
    BearerTokenFile: "/path/to/token",            // Token from file
    
    // TLS Configuration:
    TLSClientConfig: rest.TLSClientConfig{
        CAFile:   "/path/to/ca.crt",              // CA certificate
        CertFile: "/path/to/client.crt",          // Client certificate
        KeyFile:  "/path/to/client.key",          // Client key
        Insecure: false,                           // Skip TLS verification (not recommended)
    },
    
    // Rate Limiting:
    QPS:   50.0,        // Max queries per second (default: 5)
    Burst: 100,         // Max burst queries (default: 10)
    
    // Timeouts:
    Timeout: 30 * time.Second,  // Request timeout
    
    // User Agent:
    UserAgent: "my-app/v1.0.0",  // Identifies your client
}

clientset, err := kubernetes.NewForConfig(config)

List Options

listOpts := metav1.ListOptions{
    // Label selector (AND semantics):
    // - "key=value" - equality
    // - "key!=value" - inequality
    // - "key in (v1,v2)" - set inclusion
    // - "key notin (v1,v2)" - set exclusion
    // - "key" - key exists
    // - "!key" - key does not exist
    LabelSelector: "app=myapp,environment=production",
    
    // Field selector (resource-specific fields):
    // Common fields: metadata.name, metadata.namespace, status.phase
    FieldSelector: "status.phase=Running,metadata.namespace=default",
    
    // Pagination:
    Limit: 100,              // Max items per page
    Continue: "token",       // Continuation token from previous page
    
    // Versioning:
    ResourceVersion: "12345",      // Start from specific version
    ResourceVersionMatch: "NotOlderThan",  // Version matching strategy
    
    // Watch:
    Watch: false,            // Return watcher instead of list
    AllowWatchBookmarks: true,  // Enable watch bookmarks
    
    // Timeout:
    TimeoutSeconds: &timeout,  // List/watch timeout
}

pods, err := clientset.CoreV1().Pods("default").List(context.TODO(), listOpts)

Best Practices

1. Use Informers for Controllers

// AVOID: Polling with List() - inefficient, high API server load
for {
    pods, _ := clientset.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
    // Process pods
    time.Sleep(5 * time.Second)
}

// PREFER: Informers with event handlers - efficient, cached, event-driven
informerFactory := informers.NewSharedInformerFactory(clientset, 10*time.Minute)
podInformer := informerFactory.Core().V1().Pods()
podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
    AddFunc: func(obj interface{}) { /* handle */ },
    UpdateFunc: func(old, new interface{}) { /* handle */ },
    DeleteFunc: func(obj interface{}) { /* handle */ },
})
informerFactory.Start(stopCh)

2. Implement Retry on Conflict

import "k8s.io/apimachinery/pkg/util/wait"

// Retry update operations on conflict
err := wait.ExponentialBackoff(
    wait.Backoff{Duration: 10*time.Millisecond, Factor: 2.0, Steps: 5},
    func() (bool, error) {
        // Get latest version
        deployment, err := clientset.AppsV1().Deployments("ns").Get(ctx, "name", metav1.GetOptions{})
        if err != nil {
            return false, err
        }
        
        // Modify
        replicas := int32(3)
        deployment.Spec.Replicas = &replicas
        
        // Update
        _, err = clientset.AppsV1().Deployments("ns").Update(ctx, deployment, metav1.UpdateOptions{})
        if apierrors.IsConflict(err) {
            return false, nil  // Retry
        }
        return err == nil, err
    },
)

3. Configure Appropriate Rate Limits

// Set QPS and Burst based on application needs
config.QPS = 50.0    // Sustained queries per second
config.Burst = 100   // Burst capacity

// For controllers: higher limits
config.QPS = 100.0
config.Burst = 200

// For CLI tools: lower limits
config.QPS = 10.0
config.Burst = 20

4. Always Use Context

// AVOID: context.TODO() in production
pod, err := clientset.CoreV1().Pods("ns").Get(context.TODO(), "name", metav1.GetOptions{})

// PREFER: Context with timeout and cancellation
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
pod, err := clientset.CoreV1().Pods("ns").Get(ctx, "name", metav1.GetOptions{})

5. Graceful Shutdown

// Proper cleanup for controllers
stopCh := make(chan struct{})
defer close(stopCh)

// Start informers
informerFactory.Start(stopCh)

// Handle shutdown signals
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)

<-sigCh  // Wait for signal
close(stopCh)  // Stop informers
queue.ShutDown()  // Drain work queue

6. Use Selectors for Filtering

// AVOID: Client-side filtering
allPods, _ := clientset.CoreV1().Pods("default").List(ctx, metav1.ListOptions{})
for _, pod := range allPods.Items {
    if pod.Labels["app"] == "myapp" {
        // Process
    }
}

// PREFER: Server-side filtering with selectors
pods, _ := clientset.CoreV1().Pods("default").List(ctx, metav1.ListOptions{
    LabelSelector: "app=myapp",
})
for _, pod := range pods.Items {
    // All pods already filtered
}

7. Handle Resource Versions Correctly

// Get current resource
deployment, err := clientset.AppsV1().Deployments("ns").Get(ctx, "name", metav1.GetOptions{})

// Modify and update - resource version ensures optimistic concurrency
deployment.Spec.Replicas = &replicas
updated, err := clientset.AppsV1().Deployments("ns").Update(ctx, deployment, metav1.UpdateOptions{})

// If conflict, fetch latest and retry
if apierrors.IsConflict(err) {
    // Fetch fresh copy and retry
}

Documentation Index

Getting Started

Reference Documentation

Version Compatibility

  • v0.35.0 → Kubernetes v1.35.x
  • Compatibility: ±1 minor version (e.g., v0.35 client works with v1.34-v1.36 servers)
  • Version format: v0.MINOR.PATCH (follows Kubernetes versioning)
  • Breaking changes: Major version bumps only

Check server version compatibility:

import "k8s.io/client-go/discovery"

discoveryClient, _ := discovery.NewDiscoveryClientForConfig(config)
version, err := discoveryClient.ServerVersion()
// version.Major, version.Minor, version.GitVersion

Additional Resources

Install with Tessl CLI

npx tessl i tessl/golang-k8s-io--client-go@0.35.0

docs

index.md

tile.json