Kubernetes: Using Downward API metadata from a Python application

In a previous post, I described the Kubernetes Downward API and how it allows us to inject pod/container metadata into our runtime container.

In this article, I’ll show how you can read the environment variables and mounted files from inside a containerized Python based application.

Injection of metadata

As explained in the earlier article, there are two types of metadata that can be exposed with the Downward API: pod metadata and container metadata.

This injection is put into environment variables by definitions located at ‘.spec.template.spec.containers[].env’, like below:

env:

  # pulling pod fields
  - name: MY_NODE_NAME
    valueFrom:
      fieldRef:
        fieldPath: spec.nodeName

And the injection of metadata as volume files is defined at ‘.spec.template.spec.volumes’ like below:

volumes:
  - name: podinfo
    downwardAPI:
      items:

        # pulling container fields from containers[].name
        - path: "mem_limit"
          resourceFieldRef:
            containerName: golang-hello-world-web
            resource: limits.memory
            divisor: 1Mi

View my downward-flask-web.yaml for a full example.

Environment variables from Python

From the example above, if you have an environment variable named MY_NODE_NAME coming from the Downward API that is the name of the Kubernetes worker node the pod is running on, then you can get that information using Python.

os.getenv("MY_NODE_NAME","n/a")

This would provide a default value in case it is not passed in, which is useful during non-Kubernetes testing of the container.

File from Python

In our manifest, the Downward API metadata is mounted at the directory “/etc/podinfo”.  Finding all the files in that directory and printing their content is done using Python like below.

files = os.listdir("/etc/podinfo/")
for f in files:
  fullname=os.path.join(path,f)
  if os.path.isfile(fullname):
    with open(fullname) as f:
      content = f.readlines()
      print ( "FILE {} = {}\n".format(fullname,content) )

Full example

If you would like to see a full example at work, see my k8s-downward-flask-web github project.  Here is how you would grab the project, then run ‘kubectl apply’ on the manifest that deploys the Downward API with Python Flask application.

# get requirements
sudo apt-get install git make -y

# grab project from github
git clone https://github.com/fabianlee/k8s-downward-flask-web.git
cd k8s-downward-flask-web

# run kubectl apply
make k8s-apply

View the logs using kubectl.

kubectl logs -l app=downward-flask-web --tail=100

And you should see a result similar to below that shows the injected environment variable and file metadata that are printed out when the container starts and the Python Flask application reads them from ‘main’.

build version/time: 1.0.0/2021-04-30_21:24:08
app context: /downward-flask/
Starting web server on port 8000
ENV MY_NODE_NAME = microk8s-2
ENV MY_POD_NAME = downward-flask-web-6f6bb45f67-qlbxl
ENV MY_POD_IP = 10.1.100.145
ENV MY_POD_SERVICE_ACCOUNT = default
ENV MY_POD_LABEL_APP = downward-flask-web
ENV MY_POD_ANNOTATION_AUTHOR = fabian lee
ENV MY_POD_MEM_LIMIT_MB = 128
ENV MY_POD_MEM_REQUEST_MB = 32
files in /etc/podinfo/:
..data
..2021_04_30_21_43_03.692155107
annotations
labels
namespace
name
mem_request
mem_limit

You can also exec directly into the shell and view  the env vars and volume mounted files directly.

# try 'env' and 'ls /etc/podinfo'
# use 'exit' to quit shell
kubectl exec -it $(kubectl -l app=downward-flask-web get pods --output=jsonpath={.items..metadata.name}) -- sh

 

 

REFERENCES

kubernetes.io, expose pod info to containers through env vars

kubernetes.io, expose pod info to containers through files

kubernetes.io, capabilities of Downward API