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

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
golangpkg:golang/k8s.io/client-go@v0.35.0
Publish Source
CLI
Badge
tessl/golang-k8s-io--client-go badge