k8s.io/client-go/kubernetes package
client-go is the official Go library for talking to a Kubernetes
cluster over HTTP (the same API that kubectl uses).
Package
k8s.io/client-go/kubernetes gives a client for every
built-in Kubernetes resource — Pods, Services, Deployments,
Secrets, and so on.
*kubernetes.Clientset
struct that holds a REST client for each API group in Kubernetes. We pick the group, then the resource, then call List / Get / Create / Update / Delete.
clientset
├── CoreV1() → Pods, Services, ConfigMaps, Secrets, Namespaces …
├── AppsV1() → Deployments, StatefulSets, DaemonSets …
├── BatchV1() → Jobs, CronJobs
├── NetworkingV1()→ Ingress, NetworkPolicy …
└── … → other built-in API groups
Each call returns a typed interface. For example
clientset.CoreV1().Pods("default") gives you a
PodInterface with methods like List(),
Get(), Create().
| Go call | Same as kubectl |
|---|---|
clientset.CoreV1().Pods("default").List(...) |
kubectl get pods -n default |
clientset.CoreV1().Pods("default").Get(ctx, "nginx", ...)
|
kubectl get pod nginx -n default |
clientset.AppsV1().Deployments("prod").Create(...)
|
kubectl create -f deployment.yaml -n prod |
“Clientset” = set of clients — one entry point instead of constructing a separate HTTP client for every resource type yourself.
Function NewForConfig?
func NewForConfig(c *rest.Config) (*Clientset, error)
It takes a *rest.Config — connection settings for the
cluster — and returns a ready-to-use *Clientset.
NewForConfig does not talk to the cluster yet. It
only builds the Clientset with those settings wired in. The first real
HTTP call happens when you call something like .List() or
.Create().
kubeconfig file → rest.Config → NewForConfig → Clientset → .CoreV1().Pods().List()
(~/.kube/config) (connection) (factory) (typed API) (HTTP to API server)
Typical way to get rest.Config on a laptop:
clientcmd.BuildConfigFromFlags("", kubeconfigPath) reads
your ~/.kube/config (same file kubectl uses).
Simple example — list Pods in default
package main
import (
"context"
"fmt"
"path/filepath"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
func main() {
// 1. Load kubeconfig (same credentials kubectl uses)
kubeconfig := filepath.Join(homedir.HomeDir(), ".kube", "config")
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
panic(err)
}
// 2. NewForConfig → build the Clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
// 3. Use the Clientset — list Pods in namespace "default"
pods, err := clientset.CoreV1().Pods("default").List(
context.TODO(),
metav1.ListOptions{},
)
if err != nil {
panic(err)
}
fmt.Printf("Found %d pod(s) in default:\n", len(pods.Items))
for _, pod := range pods.Items {
fmt.Printf(" - %s (phase: %s)\n", pod.Name, pod.Status.Phase)
}
}
Example output
$ go run main.go
Found 2 pod(s) in default:
- nginx-7c4b8c9d-xk2lm (phase: Running)
- redis-0 (phase: Running)
Create a Pod — same Clientset, different method
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-from-go",
Namespace: "default",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "nginx",
Image: "nginx:1.25",
},
},
},
}
created, err := clientset.CoreV1().Pods("default").Create(
context.TODO(),
pod,
metav1.CreateOptions{},
)
// created.Name == "demo-from-go"
Add import:
corev1 "k8s.io/api/core/v1" for the Pod struct.
Inside the cluster (in-cluster config)
When your Go binary runs as a Pod, there is no
~/.kube/config. Use the service account mounted into the
Pod instead:
import "k8s.io/client-go/rest"
config, err := rest.InClusterConfig()
clientset, err := kubernetes.NewForConfig(config)
Install
go mod init my-k8s-tool
go get k8s.io/client-go@latest
go get k8s.io/api@latest
go get k8s.io/apimachinery@latest
Pin versions to match your cluster when possible (e.g. client-go v0.29.x for Kubernetes 1.29). Run the program with a valid kubeconfig or from inside the cluster.
client-go vs controller-runtime
k8s.io/client-go/kubernetes |
sigs.k8s.io/controller-runtime |
|---|---|
| Direct CRUD on API objects | Watch + reconcile loop for controllers |
You call List / Get when you want |
Framework calls your Reconcile() when things change
|
| Good for scripts, CLIs, one-shot tools | Good for operators and long-running controllers |
controller-runtime uses client-go under the hood. For a
controller, prefer
controller-runtime. For “list all pods and print names,” use
kubernetes.NewForConfig.
Related
Go Packages and Modules
controller-runtime
Kubernetes Controller