Downward API
Welcome to the module on Downward API. Here you will learn key concepts and best practices to master this topic.
1. The Problem
Sometimes, your application code needs to know something about its environment within Kubernetes—for instance, its own Pod IP address, the Node it is running on, or its CPU/Memory limits.
Analogy: Think of this like a runner in a marathon needing to know their current bib number, their exact route, or the remaining distance. They need this information to execute their race properly, but they shouldn’t have to call the race organizer’s headquarters (the Kubernetes API server) every time they need to check.
However, hardcoding calls to the Kubernetes API server inside your application violates the principle of decoupling. It ties your application logic directly to Kubernetes and requires granting the Pod RBAC permissions to read the API.
2. The Solution: Downward API
The Downward API allows containers to consume information about themselves or the cluster without directly communicating with the Kubernetes API server.
You can expose information via:
- Environment Variables: Useful for simple string values (e.g., Node Name, Pod IP).
- Volume Mounts (Files): Useful for exposing complex data or lists (e.g., Annotations, Labels) which might change during runtime.
3. Interactive: Downward API Visualizer
See how Kubernetes fields are mapped into the container environment.
Pod Manifest Injection
Pod Spec (status.podIP)
kind: Pod
metadata:
name: my-app-pod
status:
podIP: 10.244.1.55
Container Environment
4. Hardware Reality & First Principles
When you map fields using the Downward API as environment variables, the kubelet writes these values into the container’s process environment space before calling exec.
Because environment variables are read once at process startup, if the Pod’s labels or annotations change after the container starts, the environment variables will not update.
Conversely, if you use a Volume Mount for the Downward API, kubelet uses an emptyDir backed by tmpfs (RAM) to write the files. The kubelet periodically reconciles the volume, meaning if you update a label, the file contents will eventually reflect the change. Your application must be capable of reloading the file (e.g., using fsnotify or standard polling) to see the updates.
5. Implementation: Java & Go
Java
// Java: Reading Downward API Environment Variables
public class AppConfig {
public static void main(String[] args) {
// Read the Pod IP injected by the Downward API
String podIp = System.getenv("MY_POD_IP");
String nodeName = System.getenv("MY_NODE_NAME");
if (podIp != null) {
System.out.println("Running on Pod IP: " + podIp);
} else {
System.out.println("MY_POD_IP not set in environment.");
}
if (nodeName != null) {
System.out.println("Scheduled on Node: " + nodeName);
}
}
}
Go
// Go: Reading Downward API Environment Variables
package main
import (
"fmt"
"os"
)
func main() {
// Read the Pod IP injected by the Downward API
podIP := os.Getenv("MY_POD_IP")
nodeName := os.Getenv("MY_NODE_NAME")
if podIP != "" {
fmt.Printf("Running on Pod IP: %s\n", podIP)
} else {
fmt.Println("MY_POD_IP not set in environment.")
}
if nodeName != "" {
fmt.Printf("Scheduled on Node: %s\n", nodeName)
}
}
6. YAML Manifest
Here is how you inject status.podIP and spec.nodeName into a container as environment variables:
apiVersion: v1
kind: Pod
metadata:
name: downward-api-env-demo
spec:
containers:
- name: test-container
image: busybox:1.28
command: [ "sh", "-c", "env | grep MY_" ]
env:
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP