Retrieving Specific Pod Details using Go

In Chapter 1, we used the List method to get multiple Pods. But often, you need information about one specific Pod, perhaps identified by its name. For this, we use the Get method provided by the resource interface (e.g., podsClient.Get(...)).

The Get method requires:

  1. context.Context: Similar to List.

  2. name (string): The exact name of the Pod you want to retrieve.

  3. metav1.GetOptions: Options for the get request. Usually, you can pass empty options (metav1.GetOptions{}) if you don't have specific requirements like fetching a particular resource version.

The method returns a pointer to the specific resource object (*v1.Pod in this case) and an error. A crucial error to check for here is errors.IsNotFound, which indicates that no Pod with the given name exists in the specified namespace.

Accessing the Details in Go

Let's write a Go program that takes a Pod name and namespace as input (e.g., via command-line flags) and then fetches and prints the key networking-related details we discussed earlier: podIP, hostIP, phase, and container ports.

// examples/chapter-2/get-pod-details/main.go
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"path/filepath"
	"strings" // For joining port details

	// Kubernetes API imports
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8serrors "k8s.io/apimachinery/pkg/api/errors" // For IsNotFound check

	// client-go imports
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
)

func main() {
	// --- Setup Kubeconfig and Flags ---
	var kubeconfig *string
	if home := homedir.HomeDir(); home != "" {
		kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
	} else {
		kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
	}
	// Flags for target Pod name and namespace
	podName := flag.String("pod", "", "name of the pod to inspect")
	namespace := flag.String("namespace", "default", "namespace of the pod")
	flag.Parse()

	// Validate required flags
	if *podName == "" {
		log.Fatal("Error: --pod flag is required")
	}

	// --- Load Config and Create Clientset ---
	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
	if err != nil {
		log.Fatalf("Error building kubeconfig: %s", err.Error())
	}
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		log.Fatalf("Error creating clientset: %s", err.Error())
	}

	// --- Get Specific Pod ---
	fmt.Printf("Attempting to get Pod '%s' in namespace '%s'...\n", *podName, *namespace)
	podsClient := clientset.CoreV1().Pods(*namespace)

	// Use the Get method
	pod, err := podsClient.Get(context.TODO(), *podName, metav1.GetOptions{})

	// --- Handle Errors (especially NotFound) ---
	if err != nil {
		if k8serrors.IsNotFound(err) {
			log.Fatalf("Pod '%s' not found in namespace '%s'\n", *podName, *namespace)
		} else {
			// Handle other potential errors (permissions, connection issues, etc.)
			log.Fatalf("Error getting pod '%s': %s\n", *podName, err.Error())
		}
	}

	// --- Pod Found - Extract and Print Details ---
	fmt.Printf("Successfully retrieved Pod '%s'.\n", pod.Name)
	fmt.Println("--- Details ---")
	fmt.Printf("  Phase:      %s\n", pod.Status.Phase)
	fmt.Printf("  Pod IP:     %s\n", pod.Status.PodIP)   // Primary Pod IP
	fmt.Printf("  Host IP:    %s\n", pod.Status.HostIP)   // Node IP where the Pod runs
	fmt.Printf("  Node Name:  %s\n", pod.Spec.NodeName) // Name of the Node

	fmt.Println("  Container Ports (from Spec):")
	if len(pod.Spec.Containers) > 0 {
		for _, container := range pod.Spec.Containers {
			fmt.Printf("    Container: %s\n", container.Name)
			if len(container.Ports) > 0 {
				for _, port := range container.Ports {
					portInfo := []string{}
					if port.Name != "" {
						portInfo = append(portInfo, "Name="+port.Name)
					}
					portInfo = append(portInfo, fmt.Sprintf("Port=%d", port.ContainerPort))
					portInfo = append(portInfo, "Proto="+string(port.Protocol)) // Default is TCP
					fmt.Printf("      - %s\n", strings.Join(portInfo, ", "))
				}
			} else {
				fmt.Println("      - No ports defined")
			}
		}
	} else {
		fmt.Println("    No containers defined in spec (this is unusual!)")
	}
	fmt.Println("---------------")
}

How it Works:

  1. Flags: We define flags --pod and --namespace to make the tool reusable.

  2. Get Pod: We obtain the podsClient for the specified namespace and call podsClient.Get(ctx, *podName, metav1.GetOptions{}). (Note: Use *podName to get the string value from the flag pointer).

  3. Error Handling: We immediately check err. Crucially, we use k8serrors.IsNotFound(err) to provide a specific message if the Pod doesn't exist and exit cleanly. Other errors cause a fatal exit.

  4. Accessing Fields: If the Get call is successful ( err == nil), the pod variable holds the *v1.Pod struct. We can then directly access the fields we need using dot notation:

    • pod.Status.Phase

    • pod.Status.PodIP

    • pod.Status.HostIP

    • pod.Spec.NodeName (We added this as it's often useful alongside HostIP)

    • We iterate through pod.Spec.Containers and then through container.Ports to extract the port information defined in the Pod's specification.

Last updated

Was this helpful?