Jacob Tomlinson's profile picture Jacob Tomlinson
Home Blog Talks Newsletter About

A beginner's guide to managing Kubernetes resources in Python with kr8s

5 minute read #python, #kubernetes, #tutorial, #kr8s

Managing Kubernetes resources with Python has never been easier thanks to the kr8s Kubernetes client for Python.

A core goal of kr8s is to provide a simple and complete Python client for Kubernetes to allow folks to get up and running quickly. If you’ve used kubectl then you’ll find the kr8s syntax familiar. Whether you want to write scripts, automate repetitive tasks, build applications that interact with the Kubernetes API or build operators, kr8s is a great place to start.

Setup

To get started you’ll need a Kubernetes cluster and some credentials. kr8s looks in the same places for your credentials as kubectl so if you can run kubectl commands you’re good to go.

$ kubectl get nodes        
NAME                        STATUS   ROLES           AGE   VERSION
kind-control-plane          Ready    control-plane   59d   v1.29.0

In our Python environment we can install the kr8s package using pip.

pip install kr8s

Now let’s verify that we can interact with the Kubernetes API and make the equivalent call to kubectl get nodes.

import kr8s

for node in kr8s.get("nodes"):
    print(node.name)

If you see the same node names printed out then everything is set up!

Creating resources

Let’s start by creating some Kubernetes resources. There are many different ways to do this with kr8s, so let’s explore the most common ones.

First we can generate common resources from a few bits of key information, this is similar to the kubectl run command.

from kr8s.objects import Pod

# Generate a simple Pod spec using the `nginx` container image
pod = Pod.gen(name="webserver", image="nginx:latest", ports=[80])  
# Create the Pod
pod.create()  

We could also define the Pod spec explicitly as a Python dictionary.

from kr8s.objects import Pod

pod = Pod({
        "apiVersion": "v1",
        "kind": "Pod",
        "metadata": {
            "name": "webserver",
        },
        "spec": {
            "containers": [{
                "name": "webserver", 
                "image": "nginx:latest",
                "ports": [{
                    "containerPort": 80, 
                    "protocol": "TCP",
                }]
            }]
        },
    })

pod.create()

Or we could store the resource in a YAML file and use kr8s to load and create the object, similar to kubectl create -f.

# nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: webserver
spec:
  containers:
  - name: webserver
    image: nginx:latest
    ports:
    - containerPort: 80
from kr8s.objects import objects_from_files

# We do this in a loop because there may be more than one resource in a file
for resource in objects_from_files("nginx-pod.yaml"):
    resource.create()

To learn more about creating resources see the kr8s example documentation.

Listing resources

We’ve already seen how we can list resources using kr8s.get() but often we need to do some filtering or querying of objects.

You can use the same selectors that kubectl supports for filtering by labels or fields. For example we can list only running Pods.

import kr8s

for pod in kr8s.get("pods", field_selector="status.phase=Running"):
    print(pod.name)

The resource objects returned by kr8s allow you to access the data from the resource either using dict notation pod["metadata"] or using dot notation pod.metadata. Having our resources available in Python allows you to use the full power of Python to work with these objects. For example if we wanted to sort our Pods by their restart count we can use the built-in sort list operation and a lambda to select which field to sort by.

import kr8s

# Here we are listing Pods in all namespaces
pods = kr8s.get("pods", namespace=kr8s.ALL)  
pods.sort(
    key=lambda pod: pod.status.containerStatuses[0].restartCount, 
    reverse=True
)

for pod in pods:
    print(pod.name, pod.status.containerStatuses[0].restartCount)

We can also get a reference to an object directly if we know it’s name.

from kr8s.objects import Pod

pod = Pod.get("webserver")  # The nginx Pod we created earlier

See the listing resources documentation for more examples.

Patching and updating objects

Resource objects in kr8s can update the remote objects in the Kubernetes cluster with the patch() method. For example we could add labels to the Pod we created earlier.

from kr8s.objects import Pod

pod = Pod.get("webserver")

# Update the labels
pod.patch({"metadata": {"labels": {"foo": "bar"}}})

print(pod.metadata.labels)  # prints '{'foo': 'bar'}'

JSON 6902 style patching is also supported which allows you to make more targeted updates.

pod.patch(
    [{"op": "add", "path": "/metadata/labels/patched", "value": "true"}],
    type="json",
)

Many kr8s objects also have utility methods to simplify making common changes to resources. For example you can add labels with .label().

pod.label({"fizz": "buzz"})

Here are some more common examples:

from kr8s.objects import Deployment

# Scale a deployment
deploy = Deployment.get("metrics-server", namespace="kube-system")
deploy.scale(1)

# Cordon a node
node = Node("k8s-node-1")
node.cordon()

Interacting with running Pods

The Pod resource also has additional operations you may want to perform such as viewing logs, running commands or forwarding ports from your local machine.

# Print the logs from our nginx Pod
for line in pod.logs():
    print(line)
# Exec a command in our nginx Pod and print the stdout
command = pod.exec(["cat", "/etc/os-release"])
print(command.stdout.decode())
# Forward port 80 of nginx to 8080 on our local machine
pod.portforward(80, local_port=8080).run_forever()
# Open http://localhost:8080/ to view the nginx welcome page

For more examples or running commands or setting up port forwarding in the background check out the Pod operations example documentation.

Deleting resources

Deleting resources works the same way as creating them. All we need to know about a resource to delete it is it’s name (and namespace if not default).

from kr8s.objects import Pod

# Get our nginx Pod
pod = Pod.get("webserver")
# Delete it
pod.delete()  

Conclusion

In this guide we’ve only scratched the surface of what is possible with interacting with Kubernetes in Python. Hopefully touching on the basics of creating and manipulating resources gives some ideas for things you could build with kr8s and the Kubernetes API.

For more inspiration head over to the guides section of the kr8s documentation for examples of building end-to-end projects like operators.


Have thoughts?

I love hearing feedback on my posts. You should head over to Twitter and let me know what you think!

Spotted a mistake? Why not suggest an edit!