Cluster Resource Watcher

A Kubernetes client tool that demonstrates three core client-go patterns: listing pods across all namespaces, creating a ConfigMap resource, and watching for pod changes in real-time using a shared informer. It auto-detects whether it's running in-cluster or locally (via ~/.kube/config) and handles graceful shutdown on Ctrl+C.

package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"time"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
)

func main() {
	clientset, err := buildClient()
	if err != nil {
		log.Fatalf("building client: %v", err)
	}

	// 1. List existing pods
	fmt.Println("=== Current Pods ===")
	pods, err := clientset.CoreV1().Pods("").List(
		context.Background(), metav1.ListOptions{},
	)
	if err != nil {
		log.Fatalf("listing pods: %v", err)
	}
	for _, pod := range pods.Items {
		fmt.Printf("  %s/%s [%s]\n", pod.Namespace, pod.Name, pod.Status.Phase)
	}

	// 2. Create a ConfigMap
	fmt.Println("\n=== Creating ConfigMap ===")
	cm := &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "devops-tool-config",
			Namespace: "default",
		},
		Data: map[string]string{
			"version":   "1.0.0",
			"log_level": "debug",
		},
	}

	created, err := clientset.CoreV1().ConfigMaps("default").Create(
		context.Background(), cm, metav1.CreateOptions{},
	)
	if err != nil {
		log.Printf("create configmap: %v (may already exist)", err)
	} else {
		fmt.Printf("  Created: %s (uid: %s)\n", created.Name, created.UID)
	}

	// 3. Watch pods with informer
	fmt.Println("\n=== Watching Pods (Ctrl+C to stop) ===")
	ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
	defer cancel()

	factory := informers.NewSharedInformerFactory(clientset, 60*time.Second)
	podInformer := factory.Core().V1().Pods().Informer()

	podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			pod := obj.(*corev1.Pod)
			fmt.Printf("  [+] %s/%s\n", pod.Namespace, pod.Name)
		},
		DeleteFunc: func(obj interface{}) {
			pod := obj.(*corev1.Pod)
			fmt.Printf("  [-] %s/%s\n", pod.Namespace, pod.Name)
		},
	})

	factory.Start(ctx.Done())
	factory.WaitForCacheSync(ctx.Done())
	<-ctx.Done()

	fmt.Println("\nShutting down.")
}

func buildClient() (*kubernetes.Clientset, error) {
	config, err := rest.InClusterConfig()
	if err != nil {
		kubeconfig := filepath.Join(homedir.HomeDir(), ".kube", "config")
		config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
		if err != nil {
			return nil, err
		}
	}
	return kubernetes.NewForConfig(config)
}

💻 Run locally

Copy the code above and run it on your machine

© 2026 ByteLearn.dev. Free courses for developers. · Privacy