Official Go client library for Kubernetes API - typed clients, controllers, and cluster interaction tools
Official Go client library for the Kubernetes API, providing comprehensive tools and clients for building applications, controllers, and operators that communicate with Kubernetes clusters.
go get k8s.io/client-go@v0.35.0In-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
}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{})| Client | Use Case | Key Methods | Documentation |
|---|---|---|---|
| Typed Clientset | Built-in K8s resources | Get, List, Create, Update, Delete, Watch, Patch | reference/clientsets.md |
| Dynamic Client | Custom resources, untyped objects | Resource(GVR).Get/List/Create/Update/Delete | reference/dynamic-client.md |
| REST Client | Low-level HTTP control | Get(), Post(), Put(), Delete(), Patch() | reference/rest-client.md |
| Discovery Client | API server capabilities | ServerGroups(), ServerResources(), ServerVersion() | reference/discovery.md |
| Metadata Client | Lightweight metadata ops | Get/List with partial object metadata | reference/specialized-clients.md |
| Component | Type | Key Methods | Documentation |
|---|---|---|---|
| Informers | cache.SharedIndexInformer | AddEventHandler(), Run(), HasSynced() | reference/controllers.md |
| Listers | Lister interface | List(), Get(), ByNamespace() | reference/controllers.md |
| Work Queues | workqueue.RateLimitingInterface | Add(), Get(), Done(), Forget() | reference/tools.md |
| Leader Election | leaderelection.LeaderElector | Run(), RunOrDie() with callbacks | reference/tools.md |
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
)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") // DeploymentInterfaceFeatures: Full CRUD, Watch, Patch (JSON/Merge/Strategic/Apply), Status subresource, Scale subresource
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{})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")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.
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
}
}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
}
}| API Group | ClientSet Method | Common Resources | Package Import |
|---|---|---|---|
| Core (v1) | CoreV1() | Pod, Service, ConfigMap, Secret, Namespace, Node, PersistentVolume, PersistentVolumeClaim, Event | corev1 "k8s.io/api/core/v1" |
| Apps (v1) | AppsV1() | Deployment, StatefulSet, DaemonSet, ReplicaSet | appsv1 "k8s.io/api/apps/v1" |
| Batch (v1) | BatchV1() | Job, CronJob | batchv1 "k8s.io/api/batch/v1" |
| Networking (v1) | NetworkingV1() | Ingress, NetworkPolicy, IngressClass | networkingv1 "k8s.io/api/networking/v1" |
| RBAC (v1) | RbacV1() | Role, RoleBinding, ClusterRole, ClusterRoleBinding | rbacv1 "k8s.io/api/rbac/v1" |
| Storage (v1) | StorageV1() | StorageClass, VolumeAttachment, CSIDriver, CSINode | storagev1 "k8s.io/api/storage/v1" |
| Autoscaling (v2) | AutoscalingV2() | HorizontalPodAutoscaler | autoscalingv2 "k8s.io/api/autoscaling/v2" |
| Policy (v1) | PolicyV1() | PodDisruptionBudget | policyv1 "k8s.io/api/policy/v1" |
| Coordination (v1) | CoordinationV1() | Lease (for leader election) | coordinationv1 "k8s.io/api/coordination/v1" |
k8s.io/client-go contains 383 packages organized into categories:
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)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)// 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)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
},
)// 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// 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{})// 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// 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
}// 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
}Check server version compatibility:
import "k8s.io/client-go/discovery"
discoveryClient, _ := discovery.NewDiscoveryClientForConfig(config)
version, err := discoveryClient.ServerVersion()
// version.Major, version.Minor, version.GitVersionInstall with Tessl CLI
npx tessl i tessl/golang-k8s-io--client-go@0.35.0