Official Go client library for Kubernetes API - typed clients, controllers, and cluster interaction tools
This guide will help you get started with k8s.io/client-go and perform common operations with Kubernetes clusters.
Add k8s.io/client-go to your project:
go get k8s.io/client-go@v0.35.0Use this when your application runs inside a Kubernetes pod:
package main
import (
"fmt"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
func main() {
// Creates configuration using the pod's service account
config, err := rest.InClusterConfig()
if err != nil {
panic(err.Error())
}
// Create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
fmt.Println("Connected to cluster!")
}Use this for local development or CLI tools:
package main
import (
"fmt"
"path/filepath"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
func main() {
// Build kubeconfig path
var kubeconfig string
if home := homedir.HomeDir(); home != "" {
kubeconfig = filepath.Join(home, ".kube", "config")
}
// Load kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
panic(err.Error())
}
// Create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
fmt.Println("Connected to cluster!")
}package main
import (
"fmt"
"path/filepath"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
func getClient() (*kubernetes.Clientset, error) {
// Try in-cluster config first
config, err := rest.InClusterConfig()
if err != nil {
// Fall back to kubeconfig
var kubeconfig string
if home := homedir.HomeDir(); home != "" {
kubeconfig = filepath.Join(home, ".kube", "config")
}
config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
return nil, err
}
}
return kubernetes.NewForConfig(config)
}
func main() {
clientset, err := getClient()
if err != nil {
panic(err.Error())
}
fmt.Println("Connected to cluster!")
}List all pods in a namespace:
import (
"context"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func listPods(clientset *kubernetes.Clientset, namespace string) {
pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("There are %d pods in namespace %s\n", len(pods.Items), namespace)
for _, pod := range pods.Items {
fmt.Printf("- %s (Status: %s)\n", pod.Name, pod.Status.Phase)
}
}List deployments:
func listDeployments(clientset *kubernetes.Clientset, namespace string) {
deployments, err := clientset.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("There are %d deployments in namespace %s\n", len(deployments.Items), namespace)
for _, deployment := range deployments.Items {
fmt.Printf("- %s (Replicas: %d/%d)\n",
deployment.Name,
deployment.Status.ReadyReplicas,
*deployment.Spec.Replicas)
}
}Get a single pod by name:
func getPod(clientset *kubernetes.Clientset, namespace, name string) {
pod, err := clientset.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("Pod: %s\n", pod.Name)
fmt.Printf("Namespace: %s\n", pod.Namespace)
fmt.Printf("Status: %s\n", pod.Status.Phase)
fmt.Printf("Node: %s\n", pod.Spec.NodeName)
fmt.Printf("IP: %s\n", pod.Status.PodIP)
}Create a namespace:
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func createNamespace(clientset *kubernetes.Clientset, name string) {
namespace := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
result, err := clientset.CoreV1().Namespaces().Create(context.TODO(), namespace, metav1.CreateOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("Created namespace %s\n", result.Name)
}Create a deployment:
import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func createDeployment(clientset *kubernetes.Clientset, namespace string) {
replicas := int32(2)
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-deployment",
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "demo",
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "demo",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "nginx",
Image: "nginx:1.21",
Ports: []corev1.ContainerPort{
{
ContainerPort: 80,
},
},
},
},
},
},
},
}
result, err := clientset.AppsV1().Deployments(namespace).Create(context.TODO(), deployment, metav1.CreateOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("Created deployment %s\n", result.Name)
}Update a deployment's replica count:
func updateDeploymentReplicas(clientset *kubernetes.Clientset, namespace, name string, replicas int32) {
// Get the deployment
deployment, err := clientset.AppsV1().Deployments(namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
panic(err.Error())
}
// Update replicas
deployment.Spec.Replicas = &replicas
// Apply update
result, err := clientset.AppsV1().Deployments(namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("Updated deployment %s to %d replicas\n", result.Name, *result.Spec.Replicas)
}Delete a pod:
func deletePod(clientset *kubernetes.Clientset, namespace, name string) {
err := clientset.CoreV1().Pods(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("Deleted pod %s\n", name)
}Delete a deployment:
func deleteDeployment(clientset *kubernetes.Clientset, namespace, name string) {
deletePolicy := metav1.DeletePropagationForeground
err := clientset.AppsV1().Deployments(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{
PropagationPolicy: &deletePolicy,
})
if err != nil {
panic(err.Error())
}
fmt.Printf("Deleted deployment %s\n", name)
}Always handle errors properly using the apierrors package:
import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
)
func safePodGet(clientset *kubernetes.Clientset, namespace, name string) {
pod, err := clientset.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
if apierrors.IsNotFound(err) {
fmt.Printf("Pod %s not found in namespace %s\n", name, namespace)
return
} else if apierrors.IsForbidden(err) {
fmt.Println("Permission denied")
return
} else if apierrors.IsUnauthorized(err) {
fmt.Println("Authentication failed")
return
}
panic(err.Error())
}
fmt.Printf("Found pod: %s\n", pod.Name)
}Filter resources by labels:
func listPodsByLabel(clientset *kubernetes.Clientset, namespace string) {
// List pods with label app=demo
pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{
LabelSelector: "app=demo",
})
if err != nil {
panic(err.Error())
}
fmt.Printf("Found %d pods with label app=demo\n", len(pods.Items))
// Multiple label selectors
pods, err = clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{
LabelSelector: "app=demo,environment=production",
})
}Filter by field values:
func listRunningPods(clientset *kubernetes.Clientset, namespace string) {
// List only running pods
pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{
FieldSelector: "status.phase=Running",
})
if err != nil {
panic(err.Error())
}
fmt.Printf("Found %d running pods\n", len(pods.Items))
}Here's a complete working example that demonstrates multiple operations:
package main
import (
"context"
"fmt"
"path/filepath"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
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() {
// Setup client
var kubeconfig string
if home := homedir.HomeDir(); home != "" {
kubeconfig = filepath.Join(home, ".kube", "config")
}
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
panic(err.Error())
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
namespace := "demo-namespace"
deploymentName := "demo-deployment"
// Create namespace
fmt.Println("Creating namespace...")
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}
_, err = clientset.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{})
if err != nil && !apierrors.IsAlreadyExists(err) {
panic(err.Error())
}
// Create deployment
fmt.Println("Creating deployment...")
replicas := int32(2)
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: deploymentName,
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"app": "demo"},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"app": "demo"},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "nginx",
Image: "nginx:1.21",
Ports: []corev1.ContainerPort{
{ContainerPort: 80},
},
},
},
},
},
},
}
_, err = clientset.AppsV1().Deployments(namespace).Create(context.TODO(), deployment, metav1.CreateOptions{})
if err != nil && !apierrors.IsAlreadyExists(err) {
panic(err.Error())
}
// List pods
fmt.Println("Listing pods...")
pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("Found %d pods:\n", len(pods.Items))
for _, pod := range pods.Items {
fmt.Printf(" - %s (Status: %s)\n", pod.Name, pod.Status.Phase)
}
fmt.Println("Done!")
}This error occurs when trying to use rest.InClusterConfig() outside a pod. Use kubeconfig-based configuration instead.
Check that:
Ensure your service account or kubeconfig user has the necessary RBAC permissions.
context.TODO() or a proper context with timeoutsfake.NewSimpleClientset() for unit testsInstall with Tessl CLI
npx tessl i tessl/golang-k8s-io--client-go@0.35.0