List Pods with Python Client
Use the Kubernetes Python client to list pods in your cluster with hands-on steps, troubleshooting tips, and what to learn next.
Focus: use kubernetes python client to list pods
You’ve spent hours watching kubectl get pods scroll by, wondering how to turn that same operation into a programmatic superpower inside your Python application. The truth is, manually running kubectl commands for every check, health probe, or cleanup job is a recipe for toil — and brittle shell scripting that breaks the moment a node hiccups. This lesson shows you exactly how to use the Kubernetes Python client to list pods in your cluster, turning a routine CLI command into a reusable, testable, and autopilot-ready function. By the end, you'll query pod status, filter by labels, and handle errors like a pro — no YAML surgery required.
The Problem This Lesson Solves
Imagine you’re building a Python service that needs to know whether a deployment is healthy before sending it traffic. Or you’re writing a cleanup cron job that deletes completed pods. Or you’re trying to build a dashboard that shows pod memory usage in real time. In every case, reaching for subprocess.run(["kubectl", "get", "pods"]) is tempting — but it’s a trap.
Here’s why:
- Fragile parsing:
kubectloutput is text, meant for humans. Parsing it with regex orsplit()breaks when columns change or messages wrap. - No error handling: A cluster connectivity issue shows up as an exit code, not a Python exception. Your app can’t react gracefully.
- No native typing: Pod names, statuses, and timestamps come back as strings — no dataclasses, no autocomplete, no type hints.
- Environment coupling: Shelling out requires
kubectlinstalled and configured on the machine, which is a nightmare in containers and CI.
The Kubernetes Python client solves all of this by giving you a first-class API to the cluster’s control plane. It speaks Kubernetes’ REST API directly, so you get structured objects, proper exceptions, and the same power as kubectl — but in idiomatic Python. This lesson teaches you how to use it to list pods, the foundational skill for every other automation you’ll write.
Core Concept / Mental Model
Think of the Kubernetes Python client as a remote control for your cluster’s control plane. While kubectl is the simple factory remote (great for manual work), the Python client is the programmable IR blaster you can wire into your app’s logic.
At its core, the client is a set of generated API clients that mirror Kubernetes’ REST endpoints. To list pods, you use the CoreV1Api object — the API group responsible for core resources like pods, services, namespaces, and configmaps. When you call list_namespaced_pod or list_pod_for_all_namespaces, the client sends an HTTP GET request to the API server, parses the JSON response into Python objects, and returns a V1PodList containing V1Pod items, each with metadata (name, labels, namespace) and status (phase, container states, IP).
Here’s a mental diagram:
Your Python App
│
│ client (CoreV1Api)
▼
Kubernetes API Server ──► etcd (cluster state)
│
▼
V1PodList (Python objects)
The magic is in the response handling: you never touch raw JSON. Instead, you iterate over a typed object where each pod is a V1Pod with attributes like metadata.name and status.phase. This abstraction turns a complex API into Pythonic, discoverable code.
How It Works Step by Step
Let’s dissect what happens when you run a simple pod listing script, step by step.
Step 1: Install the Client
You need the kubernetes Python package. Install it with pip:
pip install kubernetes
This pulls in urllib3, websocket-client, and other dependencies. It’s pure Python, so it works in virtualenvs and containers alike.
Step 2: Load Authentication Configuration
Before you can talk to the API server, you need credentials. The client supports two common methods:
- Kubeconfig file: Use
config.load_kube_config()to read~/.kube/config(the same filekubectluses). - In-cluster config: Use
config.load_incluster_config()when running inside a pod (reads service account token).
For a local dev setup, loading the kubeconfig is simplest.
Step 3: Create the API Client
Instantiate CoreV1Api with the loaded configuration. This object is your gateway.
Step 4: Make the List Call
Choose between list_pod_for_all_namespaces() (global) or list_namespaced_pod(namespace) (scoped). The latter is more common when you care about a specific namespace.
Step 5: Handle the Response
The response is a V1PodList. Iterate over .items to access each V1Pod. Extract fields like metadata.name, metadata.namespace, and status.phase.
Step 6: Deal with Errors
Wrap API calls in try/except blocks catching ApiException for HTTP errors (e.g., 401 Unauthorized, 404 Not Found, 500 Server Error). The exception object has a .status and .reason for logging.
Hands-on Walkthrough
Now let’s put it into practice. We’ll write three complete examples that build on each other.
Example 1: List Pods in a Specific Namespace
This is the hello world of the Python client. It lists all pods in the default namespace with their name, phase, and IP.
from kubernetes import client, config
def list_pods(namespace="default"):
"""List all pods in a namespace."""
# Load kubeconfig (assumes you're running outside the cluster)
config.load_kube_config()
# Create CoreV1Api client
v1 = client.CoreV1Api()
# Fetch pod list
pod_list = v1.list_namespaced_pod(namespace=namespace)
# Print pod details
for pod in pod_list.items:
print(f"Pod: {pod.metadata.name} | Phase: {pod.status.phase} | IP: {pod.status.pod_ip}")
if __name__ == "__main__":
list_pods()
Expected output (your pods will differ):
Pod: my-api-7d9f9f9f9f-abc12 | Phase: Running | IP: 10.244.0.5
Pod: my-worker-0 | Phase: Running | IP: 10.244.0.6
Pod: my-worker-1 | Phase: Pending | IP: None
Example 2: List Pods Across All Namespaces with Label Filtering
Often you want to list pods across the whole cluster, or filter by labels (e.g., app=web). The list_pod_for_all_namespaces method accepts a label_selector parameter.
from kubernetes import client, config
def list_all_pods(label_selector=None):
"""List pods in all namespaces, optionally filtered by label."""
config.load_kube_config()
v1 = client.CoreV1Api()
# Use the label selector if provided
pod_list = v1.list_pod_for_all_namespaces(label_selector=label_selector)
for pod in pod_list.items:
ns = pod.metadata.namespace
name = pod.metadata.name
phase = pod.status.phase
# Count containers that are ready
ready_count = sum(
1 for cs in pod.status.container_statuses if cs.ready
) if pod.status.container_statuses else 0
print(f"{ns}/{name} | Phase={phase} | Ready={ready_count}/{len(pod.status.container_statuses) if pod.status.container_statuses else 0}")
if __name__ == "__main__":
# List all pods
print("=== All pods ===")
list_all_pods()
# List only pods with label 'app=web'
print("\n=== Pods with label app=web ===")
list_all_pods(label_selector="app=web")
Expected output:
=== All pods ===
/default/nginx-abc123 | Phase=Running | Ready=1/1
/kube-system/coredns-12345 | Phase=Running | Ready=1/1
...
=== Pods with label app=web ===
/default/my-web-xyz789 | Phase=Running | Ready=1/1
Example 3: Error Handling and Resource Cleanup
A production script needs to handle missing namespaces or permission errors gracefully. Here’s a robust version with a main() that catches ApiException.
from kubernetes import client, config
from kubernetes.client.rest import ApiException
import sys
def list_pods_safe(namespace="default"):
"""List pods with proper error handling."""
try:
config.load_kube_config()
v1 = client.CoreV1Api()
pod_list = v1.list_namespaced_pod(namespace=namespace, timeout_seconds=10)
return [(pod.metadata.name, pod.status.phase) for pod in pod_list.items]
except ApiException as e:
if e.status == 404:
print(f"Namespace '{namespace}' not found.")
elif e.status == 403:
print("You don't have permission to list pods here.")
else:
print(f"API error {e.status}: {e.reason}")
sys.exit(1)
if __name__ == "__main__":
for name, phase in list_pods_safe():
print(f"{name}: {phase}")
Expected output (if all good):
my-api-7d9f9f9f9f-abc12: Running
my-worker-0: Running
Pro tip: Always set
timeout_secondson API calls to avoid hangs when the control plane is sluggish. The default is 60 seconds; 10 is often plenty for listing.
Compare Options / When to Choose What
You have several ways to list pods. Here’s a quick comparison to help you choose the right tool for the job.
| Method | Use case | Pros | Cons |
|---|---|---|---|
kubectl get pods (CLI) |
Manual debugging, one-off checks | Simple, familiar, filters built-in | Parsing text is fragile, no native typing, can’t programmatically react |
kubernetes Python client |
Automation, monitoring, integration with your app | Typed objects, exception handling, full API access | Requires understanding API concepts, more setup than CLI |
pykube |
Lightweight alternative | Simpler API, less boilerplate | Smaller ecosystem, fewer features |
Direct REST API with requests |
Maximum control, minimal deps | No heavy package, works anywhere | Reinvents the wheel, need to handle auth and JSON yourself |
When to choose which
- Choose the Python client for anything that becomes a part of your application, CI pipeline, or scheduled job. It’s the sweet spot between control and convenience.
- Choose
kubectlfor interactive exploration or quick diagnostics in a terminal. Don’t farm it out to Python. - Choose
pykubeif you’re starting a new project that only does pod listing and want a simpler API — but be aware the community is smaller. - Choose raw REST only if you have a strong reason to avoid the Kubernetes package (e.g., you’re in a lightweight serverless function and want minimal dependencies).
For most of your journey in this track, the standard kubernetes client is the go-to.
Troubleshooting & Edge Cases
Even with the best client, things can go wrong. Here are the most common issues and how to fix them.
ModuleNotFoundError: No module named 'kubernetes'
Cause: Package not installed in the environment you’re running.
Fix: Run pip install kubernetes. If you’re in a virtual environment, activate it first. In a Docker container, add it to your requirements.
config.load_kube_config() fails with No such file or directory
Cause: Your kubeconfig isn’t in the default ~/.kube/config path.
Fix: Pass the explicit path: config.load_kube_config(config_file="/path/to/config"). Or set the KUBECONFIG environment variable before loading.
ApiException: (401) Unauthorized
Cause: Your kubeconfig lacks valid credentials (e.g., expired token, wrong user).
Fix: Check your kubeconfig with kubectl auth can-i list pods. Re-authenticate using kubectl config use-context or refresh your token.
ApiException: (403) Forbidden
Cause: Your service account or user doesn’t have RBAC permissions to list pods in that namespace.
Fix: Create a Role and RoleBinding granting list and get pods permissions. For cluster-wide listing, use a ClusterRole.
Pod appears in Pending phase forever
Cause: Could be many things (unschedulable node, insufficient resources, image pull error).
Fix: Inspect pod.status.conditions and events. The Python client gives you access to those via pod.status.conditions; you can also call read_namespaced_pod to get detailed status.
Empty pod list even though you see pods with kubectl
Cause: Wrong namespace or context. Your Python script might be using a different kubeconfig context than your shell.
Fix: Print client.configuration.host to see which cluster you’re hitting. Ensure you’re using the same context by calling config.load_kube_config() with the right context parameter.
Rate limiting or timeouts
Cause: Frequent calls to the API can exceed limits, or the API server is slow.
Fix: Implement exponential backoff, use cached responses, or set timeout_seconds appropriately. For repeated polling, consider using watch streams (see next lesson).
Pro tip: Always log the API server URL and the namespace you’re targeting when debugging. A mismatch between your current
kubectlcontext and Python’s loaded config is the #1 cause of “why do I see nothing?”
What You Learned & What's Next
Congratulations! You’ve mastered the foundational skill of using the Kubernetes Python client to list pods. Let’s recap what you accomplished:
- You installed the client and understood its role as a programmable interface to the Kubernetes API.
- You loaded cluster configuration both from kubeconfig and in-cluster.
- You listed pods in a namespace and across all namespaces, using label selectors to filter.
- You extracted meaningful fields like pod name, phase, and container readiness from
V1Podobjects. - You handled exceptions like 401/403/404 and learned to avoid common pitfalls like fragmented parsing or wrong contexts.
You’re now equipped to write automation that replaces dozens of manual kubectl commands. The same patterns you used here (API client, try/except, field access) will apply to every other resource: deployments, services, configmaps, and secrets.
Your next step in the track is to learn how to watch cluster state in real time using the client’s watch mechanism — critical for building responsive controllers and autoscalers. You’ll take your static pod listing and make it dynamic, reacting to pod creations, terminations, and status changes as they happen. The skills you just built are the foundation; now you’ll add the superpower of live updates.
Before you move on, solidify what you’ve learned with the practice recap below.
Remember: the Kubernetes Python client turns your Python skills into cluster superpowers. With pod listing under your belt, you can now automate awareness — the first step to automation that actually does something.
Practice recap
Write a script that lists all pods in the kube-system namespace and prints only those that are not Running (e.g., Pending or CrashLoopBackOff). Then try to extend it to also print the container statuses for each non-running pod. Run it against your local cluster to solidify your understanding of the status object.
Common mistakes
- Calling config.load_kube_config() without clarifying which context is active — you might be listing pods in the wrong cluster or namespace.
- Parsing kubectl output instead of using the Python client — fragile, hard to maintain, and breaks on column changes.
- Forgetting to wrap API calls in try/except for ApiException, crashing on transient 500 errors or permission issues.
- Assuming list_namespaced_pod returns a dict — it returns a typed V1PodList, so treat items as objects, not JSON.
- Ignoring timeout_seconds and letting a slow API server hang your script indefinitely.
Variations
- Use client.CoreV1Api().list_pod_for_all_namespaces() when you need cluster-wide visibility, instead of specifying a namespace.
- Try the lighter pykube library if you prefer a simpler, less generated API surface for basic pod operations.
- Implement a generator or async loops with the watch parameter to get live updates without polling.
Real-world use cases
- A health-check service that periodically lists pods in a namespace to verify all replicas are Running before routing traffic.
- A cleanup cron job that lists pods with label 'job-name' and deletes completed or failed ones to reclaim resources.
- A custom dashboard that aggregates pod statuses and container readiness across namespaces for a single operations view.
Key takeaways
- The Kubernetes Python client turns pod listing into typed, error-aware code instead of shelling out to kubectl.
- Always load config with either load_kube_config() or load_incluster_config() depending on where your code runs.
- Use list_namespaced_pod for a specific namespace and list_pod_for_all_namespaces for cluster-wide checks, with label_selector for filtering.
- Catch ApiException to handle HTTP errors gracefully — 403 and 404 are the most common in cluster automation.
- Set timeout_seconds on API calls to prevent hangs, and inspect pod.status.phase and conditions to diagnose issues.
- Mastering pod listing is the foundation for more advanced client operations like watching resources and managing deployments.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.