Belajar Kubernetes - Downward API
Episode 24 of 47

Belajar Kubernetes - Downward API

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.

Arman Dwi Pangestu
Arman Dwi PangestuMarch 30, 2026
0 views
9 min read

Pendahuluan

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.

Apa Itu Downward API?

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:

  • Metadata exposure - Access Pod dan container information
  • No API call - Tidak perlu query Kubernetes API server
  • Two method - Environment variable atau volume file
  • Dynamic value - Reflect current Pod state
  • Self-awareness - Application know context mereka
  • Resource information - Access limit dan request

Kenapa Gunakan Downward API?

Downward API solve beberapa important use case:

  • Application identification - Know Pod name dan namespace
  • Resource awareness - Adapt ke memory dan CPU limit
  • Label-based logic - Make decision based on label
  • Node information - Know node mana Pod run
  • Service account - Access service account name
  • Logging context - Include Pod metadata di log
  • Monitoring tag - Tag metric dengan Pod information
  • Dynamic configuration - Configure based on Pod metadata

Tanpa Downward API, application butuh call Kubernetes API server atau rely on external configuration, adding complexity dan dependency.

Available Metadata Field

Downward API expose various Pod dan container metadata.

Pod Metadata Field

Available via fieldRef:

  • metadata.name - Pod name
  • metadata.namespace - Pod namespace
  • metadata.uid - Pod unique ID
  • metadata.labels['<KEY>'] - Specific label value
  • metadata.labels - Semua label (volume only)
  • metadata.annotations['<KEY>'] - Specific annotation value
  • metadata.annotations - Semua annotation (volume only)

Pod Status Field

Available via fieldRef:

  • status.podIP - Pod IP address
  • status.hostIP - Node IP address
  • spec.serviceAccountName - Service account name
  • spec.nodeName - Node name dimana Pod run

Container Resource Field

Available via resourceFieldRef:

  • requests.cpu - CPU request
  • requests.memory - Memory request
  • requests.ephemeral-storage - Ephemeral storage request
  • limits.cpu - CPU limit
  • limits.memory - Memory limit
  • limits.ephemeral-storage - Ephemeral storage limit

Menggunakan Downward API dengan Environment Variable

Expose metadata sebagai environment variable di container.

Pod Metadata sebagai Environment Variable

Contoh: Basic Pod Information

Kubernetespod-metadata-env.yml
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.nodeName

Label dan Annotation sebagai Environment Variable

Contoh: Accessing Label

Kuberneteslabels-env.yml
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

Kubernetesannotations-env.yml
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']

Resource Limit sebagai Environment Variable

Contoh: Container Resource

Kubernetesresources-env.yml
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-storage

Resource Divisor

Convert resource value ke different unit.

Contoh: Memory dalam Megabyte

Kubernetesresource-divisor.yml
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"

Menggunakan Downward API dengan Volume

Expose metadata sebagai file di volume.

Pod Metadata sebagai File

Contoh: Basic Volume Mount

Kubernetespod-metadata-volume.yml
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.annotations

File created:

  • /etc/podinfo/name - Contains Pod name
  • /etc/podinfo/namespace - Contains namespace
  • /etc/podinfo/labels - Contains semua label
  • /etc/podinfo/annotations - Contains semua annotation

Semua Label dan Annotation

Contoh: Complete Metadata

Kubernetescomplete-metadata-volume.yml
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.annotations

Resource Information sebagai File

Contoh: Container Resource

Kubernetesresources-volume.yml
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.cpu

Contoh Praktis

Contoh 1: Application dengan Self-Awareness

Kubernetesself-aware-app.yml
apiVersion: 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"

Contoh 2: Logging dengan Context

Kuberneteslogging-context.yml
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"}

Contoh 3: Resource-Aware Application

Kubernetesresource-aware-app.yml
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 * 2

Contoh 4: Multi-Container dengan Shared Metadata

Kubernetesmulti-container-metadata.yml
apiVersion: 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.annotations

Contoh 5: Dynamic Configuration

Kubernetesdynamic-config.yml
apiVersion: 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']

Environment Variable vs Volume

Pilih right method untuk use case kalian.

Gunakan Environment Variable Ketika:

  • Butuh specific metadata field
  • Simple key-value pair
  • Application read environment variable
  • Small amount data
  • Static during container lifetime
Kubernetesyml
env:
    - name: POD_NAME
      valueFrom:
          fieldRef:
              fieldPath: metadata.name

Gunakan Volume Ketika:

  • Butuh semua label atau annotation
  • Large amount metadata
  • Application read file
  • Want update tanpa restart (untuk some field)
  • Multiple container sharing metadata
Kubernetesyml
volumes:
    - name: podinfo
      downwardAPI:
          items:
              - path: "labels"
                fieldRef:
                    fieldPath: metadata.labels

Kesalahan Umum dan Pitfall

Kesalahan 1: Access Unavailable Field

Problem: Trying access field yang tidak supported oleh Downward API.

Solusi: Gunakan hanya supported field:

Kubernetesyml
# Buruk: Not supported
fieldPath: spec.containers[0].image
 
# Bagus: Supported field
fieldPath: metadata.name
fieldPath: status.podIP

Kesalahan 2: Wrong Container Name

Problem: Reference wrong container di resourceFieldRef.

Solusi: Gunakan correct container name:

Kubernetesyml
# Buruk: Wrong container name
resourceFieldRef:
    containerName: wrong-name
    resource: limits.memory
 
# Bagus: Correct container name
resourceFieldRef:
    containerName: app
    resource: limits.memory

Kesalahan 3: Missing Label atau Annotation

Problem: Reference non-existent label/annotation.

Solusi: Ensure label/annotation exist:

Kubernetesyml
metadata:
    labels:
        app: myapp  # Harus exist
env:
    - name: APP_LABEL
      valueFrom:
          fieldRef:
              fieldPath: metadata.labels['app']

Kesalahan 4: Expect Update

Problem: Expect environment variable update.

Solusi: Environment variable set di startup only. Gunakan volume untuk update:

Kubernetesyml
# 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.labels

Kesalahan 5: Incorrect Divisor

Problem: Gunakan wrong divisor untuk resource conversion.

Solusi: Gunakan appropriate divisor:

Kubernetesyml
# 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 needed

Best Practice

Gunakan Descriptive Environment Variable Name

Pilih clear name yang indicate source:

Kubernetesyml
# Bagus: Clear naming
- name: POD_NAME
- name: POD_NAMESPACE
- name: NODE_NAME
 
# Hindari: Unclear naming
- name: NAME
- name: NS
- name: NODE

Organize environment variable logically:

Kubernetesyml
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: ENVIRONMENT

Gunakan Volume untuk Semua Label/Annotation

Ketika kalian butuh semua label atau annotation:

Kubernetesyml
volumes:
    - name: podinfo
      downwardAPI:
          items:
              - path: "labels"
                fieldRef:
                    fieldPath: metadata.labels
              - path: "annotations"
                fieldRef:
                    fieldPath: metadata.annotations

Set Appropriate Divisor

Convert resource ke useful unit:

Kubernetesyml
# 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"

Document Metadata Usage

Add comment explaining bagaimana metadata used:

Kubernetesyml
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: 1Mi

Melihat Downward API Data

Check metadata exposed ke container.

View Environment Variable

Kubernetesbash
sudo kubectl exec <pod-name> -- env | grep POD

View Volume File

Kubernetesbash
sudo kubectl exec <pod-name> -- ls -la /etc/podinfo
sudo kubectl exec <pod-name> -- cat /etc/podinfo/labels

Describe Pod

Kubernetesbash
sudo kubectl describe pod <pod-name>

Troubleshooting Downward API

Check Field Path

Verify field path correct:

Kubernetesbash
sudo kubectl get pod <pod-name> -o yaml

Verify Label dan Annotation

Kubernetesbash
sudo kubectl get pod <pod-name> --show-labels
sudo kubectl describe pod <pod-name>

Check Container Name

Ensure container name match:

Kubernetesbash
sudo kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].name}'

Penutup

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:

  • Downward API expose Pod metadata ke container
  • Dua method: environment variable dan volume file
  • Gunakan fieldRef untuk Pod metadata (name, namespace, label, dll)
  • Gunakan resourceFieldRef untuk container resource (limit, request)
  • Environment variable set di container startup
  • Volume file bisa update untuk some field
  • Access specific label dengan metadata.labels['key']
  • Access semua label dengan metadata.labels (volume only)
  • Gunakan divisor untuk convert resource unit
  • No API call needed - metadata injected automatically
  • Enable self-aware application yang adapt ke context
  • Useful untuk logging, monitoring, dan resource tuning
  • Pilih environment variable untuk simple value
  • Pilih volume untuk semua label/annotation

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!