Basic Operations: Listing Resources
We've set up our connection (rest.Config
) and created our gateway (kubernetes.Clientset
). Now it's time for the payoff: actually interacting with the cluster! The most fundamental operation is often retrieving information, so let's start by listing some common resources like Pods and Nodes.
Listing Pods
To list resources, we use the List
method available on the resource interface we obtained from the clientset (e.g., podsClient.List(...)
). This method typically takes two arguments:
context.Context
: Used for managing deadlines, cancellation signals, and request-scoped values. We'll usually start withcontext.TODO()
orcontext.Background()
for simple examples.metav1.ListOptions
: Allows you to specify options for filtering and pagination, such as filtering by labels (LabelSelector
) or limiting the number of results (Limit
). For now, we'll use empty options (metav1.ListOptions{}
) to get all resources (within the selected namespace).
The List
method returns a pointer to a list struct (e.g., *v1.PodList
for Pods) and an error. The list struct contains an Items
field, which is a slice of the actual resource objects (e.g., []v1.Pod
).
Let's modify our previous code to list all Pods in the default
namespace:
package main
import (
"context" // Import context package
"flag"
"fmt" // Import fmt for printing
"log" // Use log for better error output
"path/filepath"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // Import metav1
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
// v1 "k8s.io/api/core/v1" // We'll use the Pod type later
)
func main() {
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")
}
flag.Parse()
// Load configuration
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
log.Fatalf("Error building kubeconfig: %s", err.Error())
}
// Create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatalf("Error creating clientset: %s", err.Error())
}
// --- List Pods ---
fmt.Println("Listing Pods in 'default' namespace:")
// Get the Pods client for the 'default' namespace
podsClient := clientset.CoreV1().Pods("default")
// List Pods using empty ListOptions
podList, err := podsClient.List(context.TODO(), metav1.ListOptions{})
if err != nil {
log.Fatalf("Error listing pods: %s", err.Error())
}
// Iterate through the returned Pods and print their names and statuses
if len(podList.Items) == 0 {
fmt.Println(" No pods found in the default namespace.")
} else {
for i, pod := range podList.Items {
fmt.Printf(" Pod %d: Name=%s, Status=%s, IP=%s\n",
i+1,
pod.Name,
pod.Status.Phase, // e.g., Pending, Running, Succeeded, Failed, Unknown
pod.Status.PodIP, // The IP address assigned to the Pod
)
}
}
// --- End List Pods ---
// We can add Node listing logic next...
}
When you run this code (assuming your kubeconfig
points to a valid cluster), it will connect to the cluster, get a list of Pods in the default
namespace, and print their name, status phase, and IP address.
Listing Nodes (Cluster-Scoped)
Listing cluster-scoped resources like Nodes follows the same pattern, but you access the resource client directly from the group/version client (e.g., clientset.CoreV1().Nodes()
) without specifying a namespace.
Let's add code to list Nodes:
package main
import (
"context"
"flag"
"fmt"
"log"
"path/filepath"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/api/core/v1" // Import core v1 types for Node Address
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
func main() {
// ... (kubeconfig and clientset setup code from previous example) ...
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")
}
flag.Parse()
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())
}
// --- List Pods (Keep previous code or remove for focus) ---
fmt.Println("Listing Pods in 'default' namespace:")
podsClient := clientset.CoreV1().Pods("default")
podList, err := podsClient.List(context.TODO(), metav1.ListOptions{})
if err != nil {
log.Printf("Warning: Error listing pods: %s (Continuing with Nodes)\n", err.Error())
} else {
if len(podList.Items) == 0 {
fmt.Println(" No pods found in the default namespace.")
} else {
for i, pod := range podList.Items {
fmt.Printf(" Pod %d: Name=%s, Status=%s, IP=%s\n",
i+1,
pod.Name,
pod.Status.Phase,
pod.Status.PodIP,
)
}
}
}
fmt.Println("---") // Separator
// --- List Nodes ---
fmt.Println("Listing Nodes:")
// Get the Nodes client (cluster-scoped)
nodesClient := clientset.CoreV1().Nodes()
// List Nodes
nodeList, err := nodesClient.List(context.TODO(), metav1.ListOptions{})
if err != nil {
log.Fatalf("Error listing nodes: %s", err.Error())
}
// Iterate through nodes and print info
if len(nodeList.Items) == 0 {
fmt.Println(" No nodes found in the cluster.")
} else {
for i, node := range nodeList.Items {
// Extract InternalIP for simplicity (might need more robust logic)
internalIP := "N/A"
for _, addr := range node.Status.Addresses {
if addr.Type == v1.NodeInternalIP {
internalIP = addr.Address
break
}
}
fmt.Printf(" Node %d: Name=%s, InternalIP=%s, KubeletVersion=%s\n",
i+1,
node.Name,
internalIP,
node.Status.NodeInfo.KubeletVersion,
)
}
}
// --- End List Nodes ---
}
This extended example now also lists all the Nodes in your cluster, showing their name, internal IP address, and the version of the Kubelet running on them. Notice how we access node.Status.Addresses
to find the specific IP type we're interested in. Kubernetes objects often have rich status fields containing valuable runtime information.
Listing Namespaces would follow the exact same pattern as Nodes, as Namespaces are also cluster-scoped: clientset.CoreV1().Namespaces().List(...)
.
These basic List
operations form the foundation for many Kubernetes interactions. You can fetch resources, inspect their status, and use that information to make decisions in your Go programs. Next, we'll touch upon how to handle potential errors when making these API calls.
Last updated
Was this helpful?