Di episode ini kita akan coba bahas Downward API di Kubernetes. Kita akan mempelajari cara expose Pod dan container metadata ke application, gunakan fieldRef dan resourceFieldRef, dan practical use case.

Di episode sebelumnya kita sudah belajar tentang Environment Variable dan cara configure application menggunakan ConfigMap, Secret, dan direct value. Selanjutnya di episode 24 kali ini, kita akan coba bahas Downward API, mekanisme untuk expose Pod dan container metadata ke running application.
Catatan: Disini saya akan menggunakan Kubernetes Cluster yang di install melalui K3s.
Downward API allow container access information tentang diri mereka dan environment mereka tanpa call Kubernetes API server. Ini enable application untuk self-aware dan adapt behavior mereka based on runtime context.
Downward API adalah mekanisme yang expose Pod dan container metadata ke container melalui environment variable atau file. Dia menyediakan cara untuk application discover information tentang Kubernetes environment mereka.
Bayangkan Downward API seperti mirror - dia reflect information tentang Pod back ke container yang running inside. Sama seperti kalian look di mirror untuk see yourself, container gunakan Downward API untuk see metadata mereka sendiri.
Karakteristik kunci Downward API:
Downward API solve beberapa important use case:
Tanpa Downward API, application butuh call Kubernetes API server atau rely on external configuration, adding complexity dan dependency.
Downward API expose various Pod dan container metadata.
Available via fieldRef:
metadata.name - Pod namemetadata.namespace - Pod namespacemetadata.uid - Pod unique IDmetadata.labels['<KEY>'] - Specific label valuemetadata.labels - Semua label (volume only)metadata.annotations['<KEY>'] - Specific annotation valuemetadata.annotations - Semua annotation (volume only)Available via fieldRef:
status.podIP - Pod IP addressstatus.hostIP - Node IP addressspec.serviceAccountName - Service account namespec.nodeName - Node name dimana Pod runAvailable via resourceFieldRef:
requests.cpu - CPU requestrequests.memory - Memory requestrequests.ephemeral-storage - Ephemeral storage requestlimits.cpu - CPU limitlimits.memory - Memory limitlimits.ephemeral-storage - Ephemeral storage limitExpose metadata sebagai environment variable di container.
Contoh: Basic Pod Information
apiVersion: v1
kind: Pod
metadata:
name: downward-env-pod
namespace: default
labels:
app: myapp
version: v1.0
tier: backend
spec:
containers:
- name: app
image: busybox:1.36
command:
- sh
- -c
- |
echo "Pod Name: $POD_NAME"
echo "Pod Namespace: $POD_NAMESPACE"
echo "Pod IP: $POD_IP"
echo "Node Name: $NODE_NAME"
sleep 3600
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeNameContoh: Accessing Label
apiVersion: v1
kind: Pod
metadata:
name: labels-env-pod
labels:
app: myapp
version: v1.0
environment: production
spec:
containers:
- name: app
image: nginx:1.25
env:
- name: APP_LABEL
valueFrom:
fieldRef:
fieldPath: metadata.labels['app']
- name: VERSION_LABEL
valueFrom:
fieldRef:
fieldPath: metadata.labels['version']
- name: ENVIRONMENT_LABEL
valueFrom:
fieldRef:
fieldPath: metadata.labels['environment']Contoh: Accessing Annotation
apiVersion: v1
kind: Pod
metadata:
name: annotations-env-pod
annotations:
description: "Production web server"
owner: "platform-team"
version: "1.0.0"
spec:
containers:
- name: app
image: nginx:1.25
env:
- name: POD_DESCRIPTION
valueFrom:
fieldRef:
fieldPath: metadata.annotations['description']
- name: POD_OWNER
valueFrom:
fieldRef:
fieldPath: metadata.annotations['owner']
- name: POD_VERSION
valueFrom:
fieldRef:
fieldPath: metadata.annotations['version']Contoh: Container Resource
apiVersion: v1
kind: Pod
metadata:
name: resources-env-pod
spec:
containers:
- name: app
image: myapp:latest
resources:
requests:
memory: "256Mi"
cpu: "250m"
ephemeral-storage: "1Gi"
limits:
memory: "512Mi"
cpu: "500m"
ephemeral-storage: "2Gi"
env:
# Memory resource
- name: MEMORY_REQUEST
valueFrom:
resourceFieldRef:
containerName: app
resource: requests.memory
- name: MEMORY_LIMIT
valueFrom:
resourceFieldRef:
containerName: app
resource: limits.memory
# CPU resource
- name: CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: app
resource: requests.cpu
- name: CPU_LIMIT
valueFrom:
resourceFieldRef:
containerName: app
resource: limits.cpu
# Storage resource
- name: STORAGE_REQUEST
valueFrom:
resourceFieldRef:
containerName: app
resource: requests.ephemeral-storage
- name: STORAGE_LIMIT
valueFrom:
resourceFieldRef:
containerName: app
resource: limits.ephemeral-storageConvert resource value ke different unit.
Contoh: Memory dalam Megabyte
apiVersion: v1
kind: Pod
metadata:
name: divisor-pod
spec:
containers:
- name: app
image: myapp:latest
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
env:
# Memory dalam byte (default)
- name: MEMORY_LIMIT_BYTES
valueFrom:
resourceFieldRef:
resource: limits.memory
# Memory dalam megabyte
- name: MEMORY_LIMIT_MB
valueFrom:
resourceFieldRef:
resource: limits.memory
divisor: 1Mi
# CPU dalam millicore (default)
- name: CPU_LIMIT_MILLICORES
valueFrom:
resourceFieldRef:
resource: limits.cpu
# CPU dalam core
- name: CPU_LIMIT_CORES
valueFrom:
resourceFieldRef:
resource: limits.cpu
divisor: "1"Expose metadata sebagai file di volume.
Contoh: Basic Volume Mount
apiVersion: v1
kind: Pod
metadata:
name: downward-volume-pod
namespace: default
labels:
app: myapp
version: v1.0
annotations:
description: "Example application"
owner: "platform-team"
spec:
containers:
- name: app
image: busybox:1.36
command:
- sh
- -c
- |
echo "=== Pod Metadata ==="
cat /etc/podinfo/name
cat /etc/podinfo/namespace
cat /etc/podinfo/labels
cat /etc/podinfo/annotations
sleep 3600
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
volumes:
- name: podinfo
downwardAPI:
items:
- path: "name"
fieldRef:
fieldPath: metadata.name
- path: "namespace"
fieldRef:
fieldPath: metadata.namespace
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotationsFile created:
/etc/podinfo/name - Contains Pod name/etc/podinfo/namespace - Contains namespace/etc/podinfo/labels - Contains semua label/etc/podinfo/annotations - Contains semua annotationContoh: Complete Metadata
apiVersion: v1
kind: Pod
metadata:
name: complete-metadata-pod
labels:
app: myapp
version: v1.0
tier: backend
environment: production
annotations:
description: "Production application"
owner: "platform-team"
contact: "team@example.com"
spec:
containers:
- name: app
image: nginx:1.25
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
volumes:
- name: podinfo
downwardAPI:
items:
- path: "pod-name"
fieldRef:
fieldPath: metadata.name
- path: "pod-namespace"
fieldRef:
fieldPath: metadata.namespace
- path: "pod-ip"
fieldRef:
fieldPath: status.podIP
- path: "node-name"
fieldRef:
fieldPath: spec.nodeName
- path: "service-account"
fieldRef:
fieldPath: spec.serviceAccountName
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotationsContoh: Container Resource
apiVersion: v1
kind: Pod
metadata:
name: resources-volume-pod
spec:
containers:
- name: app
image: myapp:latest
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
volumes:
- name: podinfo
downwardAPI:
items:
- path: "memory-request"
resourceFieldRef:
containerName: app
resource: requests.memory
- path: "memory-limit"
resourceFieldRef:
containerName: app
resource: limits.memory
- path: "cpu-request"
resourceFieldRef:
containerName: app
resource: requests.cpu
- path: "cpu-limit"
resourceFieldRef:
containerName: app
resource: limits.cpuapiVersion: apps/v1
kind: Deployment
metadata:
name: self-aware-app
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
version: v1.0
tier: backend
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
spec:
containers:
- name: app
image: myapp:latest
ports:
- containerPort: 8080
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
env:
# Pod identification
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
# Label untuk application logic
- name: APP_VERSION
valueFrom:
fieldRef:
fieldPath: metadata.labels['version']
- name: APP_TIER
valueFrom:
fieldRef:
fieldPath: metadata.labels['tier']
# Resource limit untuk tuning
- name: MEMORY_LIMIT
valueFrom:
resourceFieldRef:
resource: limits.memory
divisor: 1Mi
- name: CPU_LIMIT
valueFrom:
resourceFieldRef:
resource: limits.cpu
divisor: "1"apiVersion: v1
kind: Pod
metadata:
name: logging-pod
labels:
app: logger
environment: production
spec:
containers:
- name: app
image: myapp:latest
env:
# Pod context untuk structured logging
- name: LOG_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: LOG_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LOG_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: LOG_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: LOG_ENVIRONMENT
valueFrom:
fieldRef:
fieldPath: metadata.labels['environment']
# Application gunakan ini untuk structured log
# Example log: {"level":"info","pod":"logging-pod","namespace":"default","node":"node-1","message":"Started"}apiVersion: v1
kind: Pod
metadata:
name: resource-aware-pod
spec:
containers:
- name: app
image: java-app:latest
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"
env:
# JVM bisa gunakan ini untuk set heap size
- name: MEMORY_LIMIT_MB
valueFrom:
resourceFieldRef:
resource: limits.memory
divisor: 1Mi
- name: CPU_LIMIT_CORES
valueFrom:
resourceFieldRef:
resource: limits.cpu
divisor: "1"
# Application calculate optimal setting
# Example: JVM heap = 80% dari MEMORY_LIMIT_MB
# Example: Thread pool size = CPU_LIMIT_CORES * 2apiVersion: v1
kind: Pod
metadata:
name: multi-container-pod
labels:
app: myapp
version: v1.0
spec:
containers:
# Main application
- name: app
image: myapp:latest
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
# Sidecar untuk monitoring
- name: monitor
image: monitor:latest
env:
- name: MONITORED_POD
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MONITORED_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
readOnly: true
volumes:
- name: podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotationsapiVersion: v1
kind: Pod
metadata:
name: dynamic-config-pod
labels:
app: myapp
feature-flag-new-ui: "true"
feature-flag-beta-api: "false"
cache-enabled: "true"
spec:
containers:
- name: app
image: myapp:latest
env:
# Feature flag dari label
- name: FEATURE_NEW_UI
valueFrom:
fieldRef:
fieldPath: metadata.labels['feature-flag-new-ui']
- name: FEATURE_BETA_API
valueFrom:
fieldRef:
fieldPath: metadata.labels['feature-flag-beta-api']
- name: CACHE_ENABLED
valueFrom:
fieldRef:
fieldPath: metadata.labels['cache-enabled']Pilih right method untuk use case kalian.
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.namevolumes:
- name: podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labelsProblem: Trying access field yang tidak supported oleh Downward API.
Solusi: Gunakan hanya supported field:
# Buruk: Not supported
fieldPath: spec.containers[0].image
# Bagus: Supported field
fieldPath: metadata.name
fieldPath: status.podIPProblem: Reference wrong container di resourceFieldRef.
Solusi: Gunakan correct container name:
# Buruk: Wrong container name
resourceFieldRef:
containerName: wrong-name
resource: limits.memory
# Bagus: Correct container name
resourceFieldRef:
containerName: app
resource: limits.memoryProblem: Reference non-existent label/annotation.
Solusi: Ensure label/annotation exist:
metadata:
labels:
app: myapp # Harus exist
env:
- name: APP_LABEL
valueFrom:
fieldRef:
fieldPath: metadata.labels['app']Problem: Expect environment variable update.
Solusi: Environment variable set di startup only. Gunakan volume untuk update:
# Environment variable tidak update
env:
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
# Volume bisa update untuk some field
volumes:
- name: podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labelsProblem: Gunakan wrong divisor untuk resource conversion.
Solusi: Gunakan appropriate divisor:
# Untuk memory dalam MB
divisor: 1Mi
# Untuk memory dalam GB
divisor: 1Gi
# Untuk CPU dalam core
divisor: "1"
# Untuk CPU dalam millicore (default)
# No divisor neededPilih clear name yang indicate source:
# Bagus: Clear naming
- name: POD_NAME
- name: POD_NAMESPACE
- name: NODE_NAME
# Hindari: Unclear naming
- name: NAME
- name: NS
- name: NODEOrganize environment variable logically:
env:
# Pod identification
- name: POD_NAME
- name: POD_NAMESPACE
- name: POD_IP
# Resource limit
- name: MEMORY_LIMIT
- name: CPU_LIMIT
# Label
- name: APP_VERSION
- name: ENVIRONMENTKetika kalian butuh semua label atau annotation:
volumes:
- name: podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotationsConvert resource ke useful unit:
# Memory dalam megabyte untuk application tuning
- name: MEMORY_LIMIT_MB
valueFrom:
resourceFieldRef:
resource: limits.memory
divisor: 1Mi
# CPU dalam core untuk thread pool sizing
- name: CPU_LIMIT_CORES
valueFrom:
resourceFieldRef:
resource: limits.cpu
divisor: "1"Add comment explaining bagaimana metadata used:
env:
# Used untuk distributed tracing
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
# Used untuk JVM heap sizing (80% dari limit)
- name: MEMORY_LIMIT_MB
valueFrom:
resourceFieldRef:
resource: limits.memory
divisor: 1MiCheck metadata exposed ke container.
sudo kubectl exec <pod-name> -- env | grep PODsudo kubectl exec <pod-name> -- ls -la /etc/podinfo
sudo kubectl exec <pod-name> -- cat /etc/podinfo/labelssudo kubectl describe pod <pod-name>Verify field path correct:
sudo kubectl get pod <pod-name> -o yamlsudo kubectl get pod <pod-name> --show-labels
sudo kubectl describe pod <pod-name>Ensure container name match:
sudo kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].name}'Pada episode 24 ini, kita telah membahas Downward API di Kubernetes. Kita sudah belajar cara expose Pod dan container metadata ke application, gunakan fieldRef dan resourceFieldRef, dan practical use case untuk self-aware application.
Key takeaway:
metadata.labels['key']metadata.labels (volume only)Downward API essential untuk building self-aware application di Kubernetes. Dengan memahami cara expose dan use Pod metadata, kalian bisa create application yang adapt ke runtime environment mereka dan provide better observability.
Bagaimana, makin jelas kan tentang Downward API di Kubernetes? Jadi, pastikan tetap semangat belajar dan nantikan episode selanjutnya!