Kubernetes Downward API

Photo by Growtika on Unsplash

Kubernetes Downward API

Accessing Pod's Metadata from a Container: Exploring the Downward API

What is it?

Data that is already known can be passed to the Pod using ConfigMap or Secret volumes. But there are a few cases where the data isn't known upfront such as Pod's IP or name as well as the data that is defined elsewhere, such as Pod's labels and annotations. How to pass this data to a container? This is where the Kubernetes Downward API comes into the picture.

The Kubernetes Downward API enables a container to access information about itself without having to interact with the Kubernetes API Server directly. This can be done in two ways:

  • Through Environment Variables

  • Through files in downwardAPI Volume

It is important to note that this isn't like a REST endpoint where the app has to hit to get the data. It's a way of having environment variables of files populated with values from Pod's specification or status.

Now let's see what are all fields available through this Downward API.

Information Available through Downward API

  • The pod's name

  • The pod's namespace

  • The pod's unique ID

  • The pod's IP

  • The host's IP

  • The pod's labels

  • The pod's annotations

  • The name of the node where the pod is executing

  • CPU and memory requests for each container

  • CPU and memory limits for each container

A more extensive list can be found in the official documentation.

Using Environment Variables

The YAML specification is taken from the official documentation.

  • fieldRef: Refer to a field's value using downwardAPI.

  • resourceFieldRef: Refer to resource-related information.

  • containerName: Refer to container-related metadata instead of a pod (can be container resource limits/requests, etc)

apiVersion: v1
kind: Pod
metadata:
  name: dapi-envars-fieldref
spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "sh", "-c"]
      args:
      - while true; do
          echo -en '\n';
          printenv MY_POD_NAME MY_POD_NAMESPACE;
          printenv MY_POD_IP MY_CPU_REQUEST;
          sleep 10;
        done;
      resources:
        requests:
          memory: "32Mi"
          cpu: "125m"
        limits:
          memory: "64Mi"
          cpu: "250m"
      env:
        - name: MY_POD_NAME
          valueFrom:
            fieldRef: 
              fieldPath: metadata.name
        - name: MY_POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: MY_POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: MY_CPU_REQUEST
          valueFrom:
            resourceFieldRef:
              containerName: test-container # get information related a specific container rather than a pod
              resource: requests.cpu
        - name: MY_CPU_LIMIT
          valueFrom:
            resourceFieldRef:
              containerName: test-container
              resource: limits.cpu
  restartPolicy: Never

Using downwardAPI Volume Files

We must use downwardAPI volume for exposing the pod’s labels and annotations because neither can be exposed through environment variables. The reason for this is that labels and annotations can be modified when a pod is running. So when they change, Kubernetes updates the files holding them. If they were stored in environment variables, the pod needs to be restarted for the effects to take place.

apiVersion: v1
kind: Pod
metadata:
  name: kubernetes-downwardapi-volume-example
  labels:
    zone: us-est-coast
    cluster: test-cluster1
    rack: rack-22
  annotations:
    build: two
    builder: john-doe
spec:
  containers:
    - name: client-container
      image: registry.k8s.io/busybox
      command: ["sh", "-c"]
      args:
      - while true; do
          if [[ -e /etc/podinfo/labels ]]; then
            echo -en '\n\n'; cat /etc/podinfo/labels; fi;
          if [[ -e /etc/podinfo/annotations ]]; then
            echo -en '\n\n'; cat /etc/podinfo/annotations; fi;
          sleep 5;
        done;
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo # mount path where Kubernetes will store the information about labels and annotations
  volumes:
    - name: podinfo
      downwardAPI: # this is the volume type we'll use with downwardAPI
        items:
          - path: "labels" # name of the file in which the labels information will get saved
            fieldRef: # Refers to pod's labels
              fieldPath: metadata.labels
          - path: "annotations"
            fieldRef:
              fieldPath: metadata.annotations

Let's assume that we posted the above YAML file using the following command:

$ kubectl apply -f downward-api-files.yaml

Now according to the specification, we should have a folder path /etc/podinfo in our container. And inside that folder we should have two files named: labels and annotations. Let's check that:

$ kubectl exec kubernetes-downwardapi-volume-example -- ls /etc/podinfo
# output
annotations
labels

Yes, we have two files inside /etc/podinfo. Let's look at the contents of those two files:

$ kubectl exec kubernetes-downwardapi-volume-example -- cat /etc/podinfo/labels
# output
cluster="test-cluster1"
rack="rack-22"
zone="us-est-coast"%

$ kubectl exec kubernetes-downwardapi-volume-example -- cat /etc/podinfo/annotations
build="two"
builder="john-doe"

That's awesome. We have all the information about labels and annotations from the specification in those files.

Conclusion

By leveraging the Downward API, developers can easily access details such as the pod's name, namespace, IP address, labels, annotations, and other important metadata. This information can be utilized to make runtime decisions, and dynamically adjust application behavior.

Feedback is highly appreciated. Let me know about any improvements or suggestions. Thanks!

References