Official Go client library for Kubernetes API - typed clients, controllers, and cluster interaction tools
This document describes the architectural components and design patterns of k8s.io/client-go.
k8s.io/client-go is organized into layers, from high-level typed clients down to low-level HTTP transport:
┌─────────────────────────────────────────────────────────────┐
│ Application Layer │
│ (Your controllers, operators, CLI tools, applications) │
└────────────────────┬────────────────────────────────────────┘
│
┌────────────────────┴────────────────────────────────────────┐
│ High-Level Client Interfaces │
│ • Typed Clientsets (kubernetes.Interface) │
│ • Dynamic Client (dynamic.Interface) │
│ • Metadata Client (metadata.Interface) │
│ • Discovery Client (discovery.Interface) │
└────────────────────┬────────────────────────────────────────┘
│
┌────────────────────┴────────────────────────────────────────┐
│ Controller Infrastructure │
│ • Informers (shared caching & watching) │
│ • Listers (cached read operations) │
│ • Work Queues (rate-limited event processing) │
│ • Reflectors (watch & cache synchronization) │
└────────────────────┬────────────────────────────────────────┘
│
┌────────────────────┴────────────────────────────────────────┐
│ REST Client Layer │
│ • RESTClient (low-level HTTP operations) │
│ • Request Builder (fluent API construction) │
│ • Content Negotiation (JSON, Protobuf, CBOR) │
└────────────────────┬────────────────────────────────────────┘
│
┌────────────────────┴────────────────────────────────────────┐
│ Configuration & Auth │
│ • rest.Config (connection configuration) │
│ • Transport (TLS, auth, rate limiting) │
│ • Auth Providers (exec, OIDC, certificates) │
└────────────────────┬────────────────────────────────────────┘
│
┌────────────────────┴────────────────────────────────────────┐
│ HTTP Transport Layer │
│ • http.RoundTripper (Go standard library) │
│ • Custom wrappers (retry, metrics, logging) │
└──────────────────────────────────────────────────────────────┘
│
▼
Kubernetes API ServerThe rest.Config struct is the foundation for all client creation:
type Config struct {
// Connection
Host string // API server URL
APIPath string // API path prefix
// Authentication
BearerToken string // Token auth
Username string // Basic auth
Password string // Basic auth
TLSClientConfig TLSClientConfig // Certificate auth
Impersonate ImpersonationConfig // Impersonation
AuthProvider *AuthProviderConfig // Plugin auth
ExecProvider *ExecConfig // External credential provider
// Rate Limiting
QPS float32 // Queries per second
Burst int // Burst allowance
// Transport
Transport http.RoundTripper // Custom transport
WrapTransport WrapperFunc // Transport wrapper
// Timeouts
Timeout time.Duration
Dial func(ctx context.Context, network, address string) (net.Conn, error)
}Sources:
rest.InClusterConfig() - From service account in podclientcmd.BuildConfigFromFlags() - From kubeconfig fileclientcmd.RESTConfigFromKubeConfig() - From kubeconfig bytesPurpose: Strongly-typed access to Kubernetes APIs
Structure:
kubernetes.Clientset
├── CoreV1() → CoreV1Interface
│ ├── Pods(namespace) → PodInterface
│ ├── Services(namespace) → ServiceInterface
│ ├── ConfigMaps(namespace) → ConfigMapInterface
│ └── ...
├── AppsV1() → AppsV1Interface
│ ├── Deployments(namespace) → DeploymentInterface
│ ├── StatefulSets(namespace) → StatefulSetInterface
│ └── ...
├── BatchV1() → BatchV1Interface
├── NetworkingV1() → NetworkingV1Interface
└── ... (40+ API groups)Key Characteristics:
Purpose: Untyped access to any Kubernetes resource including CRDs
Architecture:
dynamic.DynamicClient
└── Resource(GVR) → NamespaceableResourceInterface
├── Namespace(ns) → ResourceInterface
│ ├── Create()
│ ├── Update()
│ ├── Get()
│ ├── List()
│ ├── Delete()
│ ├── Watch()
│ ├── Patch()
│ └── Apply()
└── (cluster-scoped operations)Data Format: unstructured.Unstructured (map[string]interface{})
Use Cases:
Purpose: Low-level HTTP client for Kubernetes API
Request Builder Pattern:
restClient.
Get(). // HTTP method
Namespace("default"). // Namespace
Resource("pods"). // Resource type
Name("my-pod"). // Resource name
VersionedParams(&opts, codec). // Query parameters
Timeout(30 * time.Second). // Request timeout
Do(ctx). // Execute
Into(&pod) // Decode responseCapabilities:
Purpose: Efficient caching and watching of Kubernetes resources
Components:
SharedInformerFactory
└── Resource Informers
├── Reflector
│ ├── ListAndWatch (API calls)
│ └── Sync to Store
├── Store/Indexer
│ ├── In-memory cache
│ └── Index functions
├── Controller
│ └── Process Deltas
└── Event Handlers
├── OnAdd
├── OnUpdate
└── OnDeleteFlow:
Key Features:
Purpose: Read-only interface to informer caches
Architecture:
PodLister (interface)
├── List(selector) → []*v1.Pod
└── Pods(namespace) → PodNamespaceLister
├── List(selector) → []*v1.Pod
└── Get(name) → *v1.PodBenefits:
Purpose: Reliable, rate-limited event processing
Queue Hierarchy:
Interface (basic FIFO)
└── DelayingInterface (delayed items)
└── RateLimitingInterface (rate limiting with backoff)
└── TypedRateLimitingQueue[T] (type-safe)Patterns:
queue := workqueue.NewTypedRateLimitingQueue(
workqueue.DefaultTypedControllerRateLimiter[string]())
// Add item
queue.Add(key)
// Process items
key, shutdown := queue.Get()
defer queue.Done(key)
// Success - remove from queue
queue.Forget(key)
// Failure - retry with backoff
queue.AddRateLimited(key)Rate Limiters:
ItemExponentialFailureRateLimiter: Exponential backoff per itemItemFastSlowRateLimiter: Fast retries then slowBucketRateLimiter: Token bucket algorithmMaxOfRateLimiter: Combines multiple limitersPurpose: Server-Side Apply (SSA) support
Design:
Architecture:
ApplyConfiguration (interface)
└── Generated per API type
├── With<Field>() methods (builders)
└── Extract<Type>() functions (from existing)Field Management:
Resource
├── Field A (managed by controller-1)
├── Field B (managed by controller-2)
└── Field C (managed by controller-1)Multiple controllers can safely manage different fields of the same resource.
Typed Clients: 110+ packages
kubernetes/typed/<group>/<version>kubernetes/typed/core/v1Informers: 72 packages
informers/<group>/<version>informers/apps/v1Listers: 52 packages
listers/<group>/<version>listers/core/v1Apply Configurations: 53 packages
applyconfigurations/<group>/<version>applyconfigurations/apps/v1rest: REST client and configuration kubernetes: Main clientset entry point dynamic: Dynamic (untyped) client discovery: API discovery metadata: Metadata-only client
tools/cache: Core controller primitives
SharedIndexInformer, Store, Indexerutil/workqueue: Work queue implementations
tools/clientcmd: Kubeconfig loading tools/leaderelection: Leader election tools/record: Event recording tools/remotecommand: Pod exec tools/portforward: Port forwarding tools/pager: Large list pagination transport: HTTP transport customization util/retry: Retry utilities util/flowcontrol: Rate limiting util/cert: Certificate utilities
All clients expose interfaces, not concrete types:
// Interface (not concrete Clientset)
type Interface interface {
CoreV1() corev1.CoreV1Interface
AppsV1() appsv1.AppsV1Interface
// ...
}Benefits:
Resources are scoped to namespaces explicitly:
// Namespace-scoped
clientset.CoreV1().Pods("default").Get(...)
// Cluster-scoped
clientset.CoreV1().Nodes().Get(...)
// All namespaces
clientset.CoreV1().Pods("").List(...)Fluent API for request construction:
restClient.
Post().
Resource("pods").
Namespace("default").
Body(pod).
Do(ctx)Multiple controllers share single watch connection:
factory := informers.NewSharedInformerFactory(clientset, resyncPeriod)
// Multiple consumers of same informer
podInformer := factory.Core().V1().Pods()
controller1.usePodInformer(podInformer)
controller2.usePodInformer(podInformer)
// Single watch connection to API server
factory.Start(stopCh)Typed (preferred when possible):
Untyped (when necessary):
Decouple event notification from processing:
// Event Handler: Add to queue
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
key, _ := cache.MetaNamespaceKeyFunc(obj)
queue.Add(key) // Fast, non-blocking
},
})
// Worker: Process from queue
func worker() {
for processNextItem() {
}
}
func processNextItem() bool {
key, quit := queue.Get()
if quit {
return false
}
defer queue.Done(key)
// Heavy processing here
err := syncHandler(key)
handleErr(err, key)
return true
}Benefits:
Important: Event handlers should be fast and non-blocking. Use work queues for heavy processing.
Cache Invalidation: None - relies on watches for updates Resync: Periodic full list to detect missed events Consistency: Eventually consistent with API server
Cache Miss Handling:
HasSynced() before using cachePurpose: Optimistic concurrency control
Flow:
1. Client lists/watches with ResourceVersion=0
2. API server returns current state + ResourceVersion
3. Client stores ResourceVersion
4. Client watches from ResourceVersion (gets incremental updates)
5. On update, client provides ResourceVersion
6. API server checks if ResourceVersion matches
7. If mismatch: Conflict error (resource was modified)Informer Behavior:
Don't:
Do:
Informer Memory:
Work Queue Memory:
Shared Informers:
Watch Semantics:
import "k8s.io/client-go/kubernetes/fake"
clientset := fake.NewSimpleClientset(initialObjects...)Provides:
import "k8s.io/client-go/informers/fake"
// Not commonly used - prefer using real informers with fake clientsetUse real clientset with test cluster (kind, k3d, etc.)
TLS Configuration:
Rate Limiting:
config.Impersonate = rest.ImpersonationConfig{
UserName: "system:serviceaccount:default:my-sa",
Groups: []string{"system:authenticated"},
}Used for testing RBAC policies without multiple credentials.
config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
return &customRoundTripper{
base: rt,
// Add logging, metrics, tracing, etc.
}
}config.ContentConfig = rest.ContentConfig{
ContentType: "application/json",
GroupVersion: &schema.GroupVersion{...},
Negotiator: runtime.ClientNegotiator{...},
}rest.RegisterAuthProviderPlugin("custom", func(...) (rest.AuthProvider, error) {
// Custom authentication logic
})config.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(qps, burst)indexers := cache.Indexers{
"byOwner": func(obj interface{}) ([]string, error) {
// Custom indexing logic
},
}
informer := cache.NewSharedIndexInformer(..., indexers)kubectl:
client-go:
controller-runtime (builds on client-go):
client-go:
Kubernetes Version Skew:
Go Version:
Breaking Changes:
Install with Tessl CLI
npx tessl i tessl/golang-k8s-io--client-go