Belajar Kubernetes - Episode 21 - Pengenalan dan Penjelasan Volume

Belajar Kubernetes - Episode 21 - Pengenalan dan Penjelasan Volume

Di episode ini kita akan coba bahas Kubernetes Volume untuk persistent data storage. Kita akan mempelajari different volume type, cara mount volume di Pod, dan best practice untuk data persistence.

Arman Dwi Pangestu
Arman Dwi PangestuMarch 25, 2026
0 views
8 min read

Pendahuluan

Catatan

Untuk kalian yang ingin membaca episode sebelumnya, bisa click thumbnail episode 20 di bawah ini

Episode 20Episode 20

Di episode sebelumnya kita sudah belajar tentang Multi-Container Pod dan design pattern untuk running multiple container together. Selanjutnya di episode 21 kali ini, kita akan coba bahas Volume, mekanisme untuk persisting data di Kubernetes.

Catatan: Disini saya akan menggunakan Kubernetes Cluster yang di install melalui K3s.

By default, container filesystem adalah ephemeral - ketika container restart, semua data hilang. Volume solve problem ini dengan menyediakan persistent storage yang survive container restart dan bisa shared antara container di Pod.

Apa Itu Volume?

Volume adalah directory yang accessible ke container di Pod. Tidak seperti ephemeral container filesystem, volume persist data beyond container restart dan bisa shared antara multiple container.

Bayangkan volume seperti external hard drive - sementara internal storage komputer kalian di wipe ketika reinstall OS, external drive keep data kalian safe. Similarly, volume preserve data ketika container restart atau crash.

Karakteristik kunci Volume:

  • Persistent storage - Data survive container restart
  • Shared access - Multiple container bisa access volume yang sama
  • Multiple type - Different storage backend (local, cloud, network)
  • Pod-scoped - Volume exist selama Pod exist
  • Flexible mounting - Mount di any path di container filesystem
  • Read/write mode - Support read-only dan read-write access

Kenapa Gunakan Volume?

Volume solve beberapa critical storage challenge:

  • Data persistence - Keep data ketika container restart
  • Data sharing - Share file antara container di Pod
  • Configuration injection - Mount ConfigMap dan Secret sebagai file
  • Log collection - Share log directory untuk sidecar container
  • Database storage - Persist database data across restart
  • Stateful application - Run application yang butuh persistent state
  • Backup dan recovery - Preserve data untuk disaster recovery

Tanpa volume, kalian akan lose semua data setiap kali container restart, making it impossible run stateful application seperti database.

Volume Lifecycle

Memahami volume lifecycle sangat crucial:

Pod-Scoped Volume

Kebanyakan volume tied ke Pod lifecycle:

  1. Pod created - Volume di provision
  2. Container start - Volume mounted ke container
  3. Container restart - Volume persist, data remain
  4. Pod deleted - Volume destroyed (untuk ephemeral type)

Persistent Volume

Beberapa volume persist beyond Pod lifecycle:

  1. Volume created - Independent dari Pod
  2. Pod created - Volume attached ke Pod
  3. Pod deleted - Volume remain available
  4. Volume deleted - Manual deletion required

Volume Type

Kubernetes support banyak volume type untuk different use case.

emptyDir

Temporary storage yang exist selama Pod exist.

Use case:

  • Scratch space untuk temporary data
  • Sharing data antara container
  • Cache storage
  • Checkpointing long computation

Contoh:

Kubernetesemptydir-volume.yml
apiVersion: v1
kind: Pod
metadata:
    name: emptydir-pod
spec:
    containers:
        - name: writer
          image: busybox:1.36
          command:
              - sh
              - -c
              - while true; do date >> /data/log.txt; sleep 5; done
          volumeMounts:
              - name: shared-data
                mountPath: /data
        - name: reader
          image: busybox:1.36
          command:
              - sh
              - -c
              - tail -f /data/log.txt
          volumeMounts:
              - name: shared-data
                mountPath: /data
    volumes:
        - name: shared-data
          emptyDir: {}

emptyDir dengan memory:

Kubernetesemptydir-memory.yml
volumes:
    - name: cache
      emptyDir:
          medium: Memory
          sizeLimit: 128Mi

Ini create tmpfs (RAM-backed filesystem) untuk high-performance temporary storage.

hostPath

Mount file atau directory dari host node filesystem.

Use case:

  • Access Docker socket untuk container management
  • Access node log
  • Development dan testing
  • Node-level monitoring agent

Warning

Warning: hostPath volume tidak portable across node dan pose security risk. Gunakan hanya ketika necessary.

Contoh:

Kuberneteshostpath-volume.yml
apiVersion: v1
kind: Pod
metadata:
    name: hostpath-pod
spec:
    containers:
        - name: app
          image: nginx:1.25
          volumeMounts:
              - name: host-data
                mountPath: /usr/share/nginx/html
    volumes:
        - name: host-data
          hostPath:
              path: /data/web
              type: DirectoryOrCreate

hostPath type:

  • DirectoryOrCreate - Create directory jika tidak exist
  • Directory - Harus existing directory
  • FileOrCreate - Create file jika tidak exist
  • File - Harus existing file
  • Socket - Harus existing Unix socket
  • CharDevice - Harus existing character device
  • BlockDevice - Harus existing block device

configMap

Mount ConfigMap data sebagai file di container.

Use case:

  • Application configuration file
  • Environment-specific setting
  • Non-sensitive configuration data

Contoh:

Kubernetesconfigmap-volume.yml
apiVersion: v1
kind: ConfigMap
metadata:
    name: app-config
data:
    app.conf: |
        server {
            listen 80;
            server_name localhost;
        }
    database.conf: |
        host=db.example.com
        port=5432
---
apiVersion: v1
kind: Pod
metadata:
    name: configmap-pod
spec:
    containers:
        - name: app
          image: nginx:1.25
          volumeMounts:
              - name: config
                mountPath: /etc/config
    volumes:
        - name: config
          configMap:
              name: app-config

Konfigurasi tersebut akan membuat file app.conf dan database.conf di dalam container pada path /etc/config. Untuk melihat nya kalian bisa masuk ke dalam container dengan perintah sudo kubectl exec -it configmap-pod -- sh dan melihat file tersebut dengan perintah cat /etc/config/app.conf dan cat /etc/config/database.conf.

Mount specific key:

Kubernetesconfigmap-specific-keys.yml
volumes:
    - name: config
      configMap:
          name: app-config
          items:
              - key: app.conf
                path: nginx.conf

secret

Mount Secret data sebagai file di container.

Use case:

  • Database password
  • API key
  • TLS certificate
  • OAuth token

Contoh:

Kubernetessecret-volume.yml
apiVersion: v1
kind: Secret
metadata:
    name: db-credentials
type: Opaque
stringData:
    username: admin
    password: secretpassword
---
apiVersion: v1
kind: Pod
metadata:
    name: secret-pod
spec:
    containers:
        - name: app
          image: myapp:latest
          volumeMounts:
              - name: credentials
                mountPath: /etc/secrets
                readOnly: true
    volumes:
        - name: credentials
          secret:
              secretName: db-credentials

File created:

  • /etc/secrets/username (contains "admin")
  • /etc/secrets/password (contains "secretpassword")

persistentVolumeClaim

Reference PersistentVolumeClaim untuk durable storage.

Use case:

  • Database storage
  • User upload
  • Application state
  • Long-term data retention

Contoh:

Kubernetespvc-volume.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: data-pvc
spec:
    accessModes:
        - ReadWriteOnce
    resources:
        requests:
            storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
    name: pvc-pod
spec:
    containers:
        - name: app
          image: postgres:15
          volumeMounts:
              - name: data
                mountPath: /var/lib/postgresql/data
    volumes:
        - name: data
          persistentVolumeClaim:
              claimName: data-pvc

Kita akan cover PersistentVolume dan PersistentVolumeClaim secara detail di episode selanjutnya.

downwardAPI

Expose Pod metadata sebagai file.

Use case:

  • Pod name dan namespace
  • Pod label dan annotation
  • Resource limit dan request

Contoh:

Kubernetesdownwardapi-volume.yml
apiVersion: v1
kind: Pod
metadata:
    name: downwardapi-pod
    labels:
        app: myapp
        version: v1.0
spec:
    containers:
        - name: app
          image: busybox:1.36
          command:
              - sh
              - -c
              - while true; do cat /etc/podinfo/*; sleep 10; done
          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

projected

Combine multiple volume source ke single directory.

Use case:

  • Mount multiple ConfigMap together
  • Combine Secret dan ConfigMap
  • Merge ServiceAccount token dengan config

Contoh:

Kubernetesprojected-volume.yml
apiVersion: v1
kind: Pod
metadata:
    name: projected-pod
spec:
    containers:
        - name: app
          image: nginx:1.25
          volumeMounts:
              - name: all-config
                mountPath: /etc/config
    volumes:
        - name: all-config
          projected:
              sources:
                  - configMap:
                        name: app-config
                  - secret:
                        name: db-credentials
                  - downwardAPI:
                        items:
                            - path: pod-name
                              fieldRef:
                                  fieldPath: metadata.name

Volume Mount Option

Customize bagaimana volume di mount di container.

Read-Only Mount

Prevent container dari modifying volume data:

Kubernetesreadonly-mount.yml
volumeMounts:
    - name: config
      mountPath: /etc/config
      readOnly: true

SubPath

Mount specific file atau subdirectory dari volume:

Kubernetessubpath-mount.yml
apiVersion: v1
kind: Pod
metadata:
    name: subpath-pod
spec:
    containers:
        - name: app
          image: nginx:1.25
          volumeMounts:
              - name: config
                mountPath: /etc/nginx/nginx.conf
                subPath: nginx.conf
    volumes:
        - name: config
          configMap:
              name: nginx-config

Ini mount hanya file nginx.conf, bukan entire ConfigMap.

SubPathExpr

Gunakan environment variable di subPath:

Kubernetessubpathexpr-mount.yml
volumeMounts:
    - name: data
      mountPath: /var/data
      subPathExpr: $(POD_NAME)
env:
    - name: POD_NAME
      valueFrom:
          fieldRef:
              fieldPath: metadata.name

Contoh Praktis

Contoh 1: Web Server dengan Persistent Content

Kubernetesweb-persistent.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: web-content-pvc
spec:
    accessModes:
        - ReadWriteOnce
    resources:
        requests:
            storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
    name: web-server
spec:
    replicas: 1
    selector:
        matchLabels:
            app: web
    template:
        metadata:
            labels:
                app: web
        spec:
            containers:
                - name: nginx
                  image: nginx:1.25
                  ports:
                      - containerPort: 80
                  volumeMounts:
                      - name: content
                        mountPath: /usr/share/nginx/html
            volumes:
                - name: content
                  persistentVolumeClaim:
                      claimName: web-content-pvc

Contoh 2: Application dengan Multiple Volume Type

Kubernetesmulti-volume-app.yml
apiVersion: v1
kind: Pod
metadata:
    name: multi-volume-app
spec:
    containers:
        - name: app
          image: myapp:latest
          volumeMounts:
              # Application config dari ConfigMap
              - name: config
                mountPath: /etc/app/config
                readOnly: true
              # Database credential dari Secret
              - name: secrets
                mountPath: /etc/app/secrets
                readOnly: true
              # Persistent data storage
              - name: data
                mountPath: /var/lib/app
              # Temporary cache
              - name: cache
                mountPath: /tmp/cache
              # Log shared dengan sidecar
              - name: logs
                mountPath: /var/log/app
        - name: log-shipper
          image: fluent/fluentd:v1.16
          volumeMounts:
              - name: logs
                mountPath: /var/log/app
                readOnly: true
    volumes:
        - name: config
          configMap:
              name: app-config
        - name: secrets
          secret:
              secretName: app-secrets
        - name: data
          persistentVolumeClaim:
              claimName: app-data-pvc
        - name: cache
          emptyDir:
              medium: Memory
              sizeLimit: 256Mi
        - name: logs
          emptyDir: {}

Contoh 3: Database dengan Persistent Storage

Kubernetesdatabase-persistent.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: postgres-pvc
spec:
    accessModes:
        - ReadWriteOnce
    resources:
        requests:
            storage: 20Gi
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
    name: postgres
spec:
    serviceName: postgres
    replicas: 1
    selector:
        matchLabels:
            app: postgres
    template:
        metadata:
            labels:
                app: postgres
        spec:
            containers:
                - name: postgres
                  image: postgres:15
                  ports:
                      - containerPort: 5432
                  env:
                      - name: POSTGRES_PASSWORD
                        valueFrom:
                            secretKeyRef:
                                name: postgres-secret
                                key: password
                      - name: PGDATA
                        value: /var/lib/postgresql/data/pgdata
                  volumeMounts:
                      - name: data
                        mountPath: /var/lib/postgresql/data
            volumes:
                - name: data
                  persistentVolumeClaim:
                      claimName: postgres-pvc

Contoh 4: Init Container dengan Shared Volume

Kubernetesinit-shared-volume.yml
apiVersion: v1
kind: Pod
metadata:
    name: init-volume-pod
spec:
    initContainers:
        - name: setup
          image: busybox:1.36
          command:
              - sh
              - -c
              - |
                  echo "Downloading configuration..."
                  wget -O /config/app.conf https://config-server/app.conf
                  echo "Setup complete"
          volumeMounts:
              - name: config
                mountPath: /config
    containers:
        - name: app
          image: myapp:latest
          volumeMounts:
              - name: config
                mountPath: /etc/app
    volumes:
        - name: config
          emptyDir: {}

Volume Access Mode

Different volume support different access mode:

ReadWriteOnce (RWO)

Volume bisa di mount read-write oleh single node:

Kubernetesyml
accessModes:
    - ReadWriteOnce

Paling common untuk block storage (AWS EBS, GCE PD).

ReadOnlyMany (ROX)

Volume bisa di mount read-only oleh many node:

Kubernetesyml
accessModes:
    - ReadOnlyMany

Useful untuk shared configuration atau static content.

ReadWriteMany (RWX)

Volume bisa di mount read-write oleh many node:

Kubernetesyml
accessModes:
    - ReadWriteMany

Require network filesystem (NFS, CephFS, GlusterFS).

ReadWriteOncePod (RWOP)

Volume bisa di mount read-write oleh single Pod:

Kubernetesyml
accessModes:
    - ReadWriteOncePod

Kubernetes 1.22+ feature untuk strict single-Pod access.

Kesalahan Umum dan Pitfall

Kesalahan 1: Gunakan emptyDir untuk Persistent Data

Problem: Data lost ketika Pod deleted.

Solusi: Gunakan PersistentVolumeClaim untuk data yang harus survive Pod deletion:

Kubernetesyml
# Buruk: emptyDir untuk database
volumes:
    - name: data
      emptyDir: {}
 
# Bagus: PVC untuk database
volumes:
    - name: data
      persistentVolumeClaim:
          claimName: db-pvc

Kesalahan 2: Lupa readOnly untuk Secret

Problem: Container bisa modify sensitive data.

Solusi: Selalu mount secret sebagai read-only:

Kubernetesyml
volumeMounts:
    - name: secrets
      mountPath: /etc/secrets
      readOnly: true

Kesalahan 3: Wrong Access Mode

Problem: Volume tidak bisa mounted di multiple node.

Solusi: Gunakan ReadWriteMany untuk multi-node access:

Kubernetesyml
accessModes:
    - ReadWriteMany  # Untuk shared access

Kesalahan 4: Tidak Set Storage Limit

Problem: emptyDir bisa fill up node disk.

Solusi: Set sizeLimit untuk emptyDir:

Kubernetesyml
emptyDir:
    sizeLimit: 1Gi

Kesalahan 5: Gunakan hostPath di Production

Problem: Tidak portable, security risk, node dependency.

Solusi: Gunakan PersistentVolume instead:

Kubernetesyml
# Hindari di production
hostPath:
    path: /data
 
# Gunakan instead
persistentVolumeClaim:
    claimName: data-pvc

Best Practice

Gunakan Appropriate Volume Type

Pilih right volume type untuk use case kalian:

Kubernetesyml
# Temporary data
emptyDir: {}
 
# Configuration
configMap:
    name: app-config
 
# Sensitive data
secret:
    secretName: credentials
 
# Persistent data
persistentVolumeClaim:
    claimName: data-pvc

Set Resource Limit

Selalu limit emptyDir size:

Kubernetesyml
emptyDir:
    sizeLimit: 500Mi

Gunakan Read-Only Mount

Mount volume sebagai read-only ketika possible:

Kubernetesyml
volumeMounts:
    - name: config
      mountPath: /etc/config
      readOnly: true

Organize Volume Mount

Group related volume logically:

Kubernetesyml
volumeMounts:
    # Configuration volume
    - name: app-config
      mountPath: /etc/app
    - name: nginx-config
      mountPath: /etc/nginx
    # Data volume
    - name: data
      mountPath: /var/lib/app
    # Temporary volume
    - name: cache
      mountPath: /tmp/cache

Gunakan SubPath Carefully

SubPath bisa cause issue dengan update:

Kubernetesyml
# ConfigMap update tidak reflect dengan subPath
volumeMounts:
    - name: config
      mountPath: /etc/app/config.yml
      subPath: config.yml  # Block update

Mount entire volume ketika possible.

Document Volume Purpose

Add comment explaining volume usage:

Kubernetesyml
volumes:
    # Application configuration file
    - name: config
      configMap:
          name: app-config
    # Database credential
    - name: secrets
      secret:
          secretName: db-credentials
    # Persistent application data
    - name: data
      persistentVolumeClaim:
          claimName: app-data-pvc

Melihat Volume Information

Get Pod Volume

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

Describe Pod

Kubernetesbash
sudo kubectl describe pod <pod-name>

Show semua volume dan mount mereka.

Check Volume Mount

Kubernetesbash
sudo kubectl exec <pod-name> -- df -h

View Volume Content

Kubernetesbash
sudo kubectl exec <pod-name> -- ls -la /path/to/mount

Troubleshooting Volume

Volume Tidak Mounting

Check Pod event:

Kubernetesbash
sudo kubectl describe pod <pod-name>

Look for mount error di event.

Permission Denied

Check volume permission dan security context:

Kubernetesyml
securityContext:
    fsGroup: 1000
    runAsUser: 1000

ConfigMap/Secret Not Found

Verify resource exist:

Kubernetesbash
sudo kubectl get configmap <name>
sudo kubectl get secret <name>

Volume Full

Check disk usage:

Kubernetesbash
sudo kubectl exec <pod-name> -- df -h

Increase sizeLimit atau clean up data.

Penutup

Pada episode 21 ini, kita telah membahas Volume di Kubernetes secara mendalam. Kita sudah belajar tentang different volume type, cara mount mereka di Pod, dan best practice untuk data persistence.

Key takeaway:

  • Volume menyediakan persistent storage untuk container
  • Data di volume survive container restart
  • emptyDir untuk temporary Pod-scoped storage
  • hostPath mount node filesystem (gunakan carefully)
  • configMap dan secret untuk configuration injection
  • persistentVolumeClaim untuk durable storage
  • downwardAPI expose Pod metadata sebagai file
  • projected combine multiple volume source
  • Volume bisa di mount read-only atau read-write
  • subPath mount specific file atau directory
  • Pilih appropriate access mode (RWO, ROX, RWX)
  • Selalu set sizeLimit untuk emptyDir volume
  • Gunakan PersistentVolume untuk production data
  • Mount secret sebagai read-only untuk security

Volume essential untuk running stateful application di Kubernetes. Dengan memahami different volume type dan use case mereka, kalian bisa design robust storage solution untuk application kalian.

Bagaimana, makin jelas kan tentang Volume di Kubernetes? Jadi, pastikan tetap semangat belajar dan nantikan episode selanjutnya!

Catatan

Untuk kalian yang ingin melanjutkan ke episode 21.1 di mana kita membahas secara mendalam PersistentVolume dan PersistentVolumeClaim, bisa click thumbnail Episode 21.1 di bawah ini

Episode 21.1Episode 21.1

Related Posts