Data Loss #

Docker sangat populer karena kemampuannya menjalankan aplikasi secara konsisten dan terisolasi. Namun, salah satu kesalahan paling umum — dan paling mahal — dalam penggunaan Docker adalah kehilangan data (data loss). Banyak engineer menganggap container sebagai “mini server” permanen, padahal secara konsep Docker tidak dirancang untuk menyimpan data secara persisten di dalam container.

Masalah data loss biasanya baru terasa saat:

  • Container direstart atau di-recreate.
  • Image di-update ke versi baru.
  • Deployment otomatis dijalankan oleh CI/CD.
  • Node tempat container berjalan crash atau di-maintenance.

Di titik itu, data yang sudah dikumpulkan berbulan-bulan — transaksi database, file upload user, log, konfigurasi runtime — musnah dalam sekejap. Recovery seringkali tidak mungkin, dan dampaknya bisa fatal: downtime, kehilangan customer, kerugian finansial, atau bahkan sanksi regulasi.

Artikel ini membahas tuntas penyebab data loss di Docker, mengapa masing-masing terjadi, dan bagaimana mencegahnya. Tujuannya bukan membuat kamu takut menggunakan Docker — Docker sendiri aman dan powerful. Yang berbahaya adalah pemahaman yang salah tentang cara Docker menangani data.

Container yang Hilang, Data yang Hilang #

Untuk memahami data loss, kamu harus paham dulu bagaimana data disimpan dalam container — dan apa yang terjadi saat container tersebut mati.

flowchart TB
    subgraph NORMAL["Container Running"]
        A1[App process] --> A2[Tulis data ke /var/lib/mysql]
        A2 --> A3[Data masuk writable layer]
    end
    
    subgraph DEATH["Container Removed"]
        B1[docker rm container] --> B2[Writable layer dihapus]
        B2 --> B3[Data musnah]
    end
    
    NORMAL -.->|docker rm| DEATH
    
    style DEATH fill:#ff6b6b,color:#fff

Saat kamu menjalankan docker run mysql, MySQL menyimpan data di /var/lib/mysql di dalam container. File-file ini ditulis ke writable layer container — layer unik per container yang berada di host, tapi terikat pada lifecycle container.

Saat container dihapus (docker rm), Docker menghapus writable layer ini. Semua data yang ditulis di sana — database, log, konfigurasi runtime, file temporary — ikut musnah. Tidak ada recycle bin, tidak ada undo. Hilang permanen.


Lima Penyebab Utama Data Loss di Docker #

Data loss di Docker hampir selalu bermuara pada lima pola ini. Pahami masing-masing, dan kamu sudah selangkah lebih maju dari kebanyakan engineer.

1. Menyimpan Data Langsung di Filesystem Container #

Ini adalah penyebab #1 data loss di Docker, dan yang paling sering terjadi. Polanya sederhana: developer menjalankan database atau aplikasi di container tanpa mount volume, data ditulis ke filesystem internal, dan hilang saat container di-restart.

Contoh kesalahan yang sangat umum:

# ANTI-PATTERN: database tanpa volume
docker run -d --name mysql \
  -e MYSQL_ROOT_PASSWORD=secret \
  mysql:8

Database jalan, aplikasi connect, transaksi tersimpan. Tapi /var/lib/mysql ada di writable layer. Saat container di-restart dengan image baru, atau di-recreate, semua database hilang.

# Container restart karena update
docker rm -f mysql
docker run -d --name mysql \
  -e MYSQL_ROOT_PASSWORD=secret \
  mysql:8
# Database baru, KOSONG.

Contoh lain yang sama berbahayanya:

  • Aplikasi upload file ke /uploads di dalam container, tanpa volume.
  • Log aplikasi ditulis ke /var/log/app.log di dalam container, tanpa bind mount.
  • Cache disimpan di /tmp di dalam container — hilang saat container restart.
  • Konfigurasi di-edit manual di dalam container (docker exec ... vim config.yaml) — hilang saat container di-recreate.
Prinsip yang tidak bisa ditawar: Data penting TIDAK BOLEH disimpan di filesystem container. Selalu. Tanpa kecuali. Ini bukan best practice yang bisa dinegosiasikan — ini adalah cara kerja Docker yang immutable.

2. Rebuild Image dan Recreate Container #

Dalam workflow modern, container di-recreate secara rutin — saat deploy, saat scale, saat image di-update. Jika data masih di dalam container, recreate = data loss.

flowchart LR
    A[Code change] --> B[CI/CD build image baru]
    B --> C[Push image ke registry]
    C --> D[Deploy: hapus container lama]
    D --> E[Jalankan container baru]
    
    D -.->|data di container| X[DATA HILANG]
    E -.->|data di volume| OK[Data aman]
    
    style X fill:#ff6b6b,color:#fff
    style OK fill:#51cf66,color:#fff

Docker tidak pernah memindahkan data otomatis antar container. Tidak ada mekanisme untuk “extract data dari container lama ke container baru”. Kalau data di dalam container, ya sudah — hilang.

3. Menganggap docker restart Selalu Aman #

docker restart berbeda dengan docker rm + docker run. Saat restart:

  • Container tetap ada (writable layer tidak dihapus).
  • Process di dalam container di-stop lalu di-start ulang.
  • Filesystem tetap utuh — file yang ditulis masih ada.

Jadi docker restart terlihat “aman”. Tapi ini bukan strategi persistence, dan ada situasi di mana docker restart pun tidak menyelamatkan data:

  • Host crash — Docker daemon mati mendadak, dan dalam kasus tertentu, writable layer bisa corrupt.
  • Disk error — bad sector di storage host membuat file tidak bisa dibaca.
  • OOMKilled — kernel membunuh proses karena kehabisan memory. Data yang sedang ditulis bisa hilang.
  • Force removedocker rm -f atau cleanup otomatis menghapus container tanpa graceful shutdown.
  • Image updatedocker pull image:new && docker compose up -d me-recreate container dengan image baru, data lama di container musnah.

Intinya: docker restart aman secara kebetulan, bukan karena desain. Untuk data penting, selalu gunakan volume.

4. Salah Konfigurasi Volume #

Volume adalah solusi, tapi kalau salah konfigurasi, ia jadi masalah baru.

Kesalahan #1: Lupa mount volume

# ANTI-PATTERN: container tanpa volume
docker run -d --name app -p 3000:3000 my-app

# Seharusnya:
docker run -d --name app -p 3000:3000 \
  -v app-data:/app/data \
  my-app

Container jalan normal, tidak ada error. Tapi /app/data ada di writable layer, dan data hilang saat container di-recreate. Volume tidak pernah terpasang.

Kesalahan #2: Typo path mount

# ANTI-PATTERN: path salah
docker run -d -v /data:/app/data my-app
# ^^^^^ mount folder /data di host, BUKAN /app/data

Aplikasi tetap jalan, tidak ada error. Tapi data ditulis ke path yang salah. Saat di-inspect, kamu bingung karena data “hilang” padahal sebenarnya di tempat yang tidak kamu kira.

Kesalahan #3: Mount ke path yang salah di container

# ANTI-PATTERN: target path salah
docker run -d -v app-data:/var/lib/mysqls mysql
#                              ^^^^^ typo

MySQL tulis data ke /var/lib/mysql (default), tapi volume di-mount ke /var/lib/mysqls (typo). Data tetap di writable layer, volume kosong.

Kesalahan #4: Volume terhapus

docker volume rm app-data   # data hilang
docker volume prune          # hapus semua volume tidak terpakai

docker volume prune membersihkan volume yang tidak sedang dipakai container. Ini berguna untuk housekeeping, tapi berbahaya kalau kamu lupa bahwa volume itu berisi data penting.

5. Data di Bind Mount Host Tanpa Backup #

Bind mount menyimpan data di filesystem host. Ini lebih “transparan” karena bisa di-browse langsung, tapi juga berarti data tunduk pada semua risiko filesystem host:

  • Disk failure — kalau disk host rusak, data di bind mount juga rusak.
  • Salah hapusrm -rf di folder yang salah bisa menghapus data production.
  • Tidak ada backup — bind mount bukan backup. Ia hanya memindahkan lokasi data dari container ke host.
  • Host migration — saat migrasi ke host baru, data harus di-copy manual.
# ANTI-PATTERN: bind mount tanpa backup
docker run -d \
  -v /home/app/data:/app/data \
  my-app
# Data di /home/app/data host, tanpa backup

Docker bukan solusi backup. Docker hanya menyimpan data di tempat yang lebih terkontrol. Backup tetap tanggung jawab kamu.


Dampak Data Loss: Kenapa Ini Penting #

Data loss bukan masalah kecil. Dampaknya bisa meluas ke banyak aspek.

Downtime dan Kehilangan Revenue #

Untuk aplikasi e-commerce atau fintech, downtime beberapa menit bisa berarti kerugian ratusan ribu dolar. Data loss yang membuat database corrupt bisa menyebabkan downtime berjam-jam atau berhari-hari.

Kehilangan Customer Trust #

Customer yang kehilangan data pribadi, transaksi, atau file upload tidak akan kembali. Trust yang dibangun bertahun-tahun bisa musnah dalam satu insiden.

Biaya Recovery #

Recovery dari data loss tanpa backup hampir selalu membutuhkan:

  • Forensik storage (mahal dan tidak selalu berhasil).
  • Rekonstruksi data manual dari log atau sumber lain.
  • Rebuild database dari nol.
  • Rollback transaksi yang hilang (kalau bisa).

Biaya ini sering ratusan kali lipat lebih besar daripada biaya setup backup yang benar sejak awal.

Compliance Issue #

Untuk industri yang diatur regulasi (finance, healthcare, government), data loss bisa berakibat:

  • Sanksi finansial.
  • Wajib lapor ke regulator.
  • Audit mendalam.
  • Kehilangan lisensi operasi.

Peta Risiko: Jenis Storage dan Tingkat Data Loss #

Tidak semua mekanisme storage punya risiko yang sama. Tabel berikut merangkum:

Jenis Storage Persisten? Risiko Data Loss Catatan
Container FS (writable layer) ❌ Tidak 🔥 Sangat Tinggi Hilang saat container dihapus
tmpfs ❌ Tidak 🔥 Sangat Tinggi Hilang saat container berhenti
Bind Mount tanpa backup ✅ Ya ⚠️ Tergantung host Tergantung backup host
Docker Volume tanpa backup ✅ Ya ⚠️ Rendah-Sedang Aman dari container, tapi bukan backup
External Storage (NFS, EBS) ✅ Ya ✅ Lebih Aman Biasanya sudah ada redundancy
Managed Database (RDS, Cloud SQL) ✅ Ya ✅ Paling Aman Backup otomatis, point-in-time recovery
Object Storage (S3, GCS) ✅ Ya ✅ Paling Aman 11 nines durability
flowchart TD
    A[Risiko Data Loss] --> B[Tinggi]
    A --> C[Sedang]
    A --> D[Rendah]
    
    B --> B1[Container FS]
    B --> B2[tmpfs]
    
    C --> C1[Bind Mount tanpa backup]
    C --> C2[Volume tanpa backup]
    
    D --> D1[External Storage]
    D --> D2[Managed Database]
    D --> D3[Object Storage]
    
    style B1 fill:#ff6b6b,color:#fff
    style B2 fill:#ff6b6b,color:#fff
    style C1 fill:#ffd43b
    style C2 fill:#ffd43b
    style D1 fill:#51cf66,color:#fff
    style D2 fill:#51cf66,color:#fff
    style D3 fill:#51cf66,color:#fff

Mitos vs Fakta Seputar Data Loss #

Banyak miskonsepsi yang beredar. Berikut yang paling umum:

Mitos 1: “Volume Docker = Backup” #

Fakta: Volume memindahkan data dari lifecycle container ke host. Tapi kalau host crash atau disk rusak, data di volume juga hilang. Volume bukan backup. Backup adalah copy data ke lokasi lain (S3, NFS, tape) yang independen dari host.

Mitos 2: “docker restart Aman untuk Data” #

Fakta: docker restart secara default aman (writable layer tidak dihapus). Tapi bukan strategi persistence. Untuk data penting, tetap gunakan volume. Dan ingat, docker compose down menghapus container (meskipun tidak menghapus volume), dan deploy ulang dengan image baru juga menghapus container.

Mitos 3: “Docker Commit Bisa Save Data” #

Fakta: docker commit memang membekukan writable layer menjadi image baru. Tapi ini anti-pattern karena:

  • Image menjadi bloated dengan data runtime.
  • Setiap commit membuat layer baru, image membengkak.
  • Data sensitif (password, secret) ikut ter-commit ke image.
  • Distribusi image menjadi tidak aman.

Gunakan backup tool (pg_dump, mysqldump, tar) untuk save data, bukan docker commit.

Mitos 4: “Kalau Container Ada di Kubernetes, Aman” #

Fakta: Kubernetes tidak otomatis mem-backup data. Pod bisa di-evict, deployment di-rollback, dan PVC (Persistent Volume Claim) bisa di-delete. Kubernetes mempermudah deployment, tapi tidak menggantikan backup strategy.

Mitos 5: “File di Writable Layer Aman Selama Container Hidup” #

Fakta: Writable layer bisa corrupt karena:

  • Disk penuh.
  • OOMKilled saat proses sedang menulis.
  • Host crash mendadak.
  • Docker daemon bug (jarang, tapi ada).

File yang “sedang ditulis” sangat rentan corruption. Untuk data penting, transaction log database harus di-flush ke disk secara berkala (wal, fsync, dsb).


Best Practice Mencegah Data Loss #

1. Gunakan Docker Volume untuk Data Penting #

services:
  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Ini langkah pertama dan paling penting. Selalu mount volume untuk database, upload, dan data stateful lainnya.

2. Pisahkan State dan Stateless #

Container sebaiknya stateless. Data disimpan di:

  • Volume untuk data yang boleh di-host lokal.
  • Database service (RDS, Cloud SQL) untuk data terstruktur.
  • Object storage (S3, GCS) untuk file besar.
  • Cache service (Redis, Memcached) untuk cache.
flowchart TB
    APP[App Container<br/>stateless] --> DB[(Database Service)]
    APP --> OBJ[Object Storage]
    APP --> CACHE[Cache Service]
    APP --> VOL[Docker Volume<br/>untuk data lokal]
    
    style APP fill:#a8d8a8
    style DB fill:#ffd8a8
    style OBJ fill:#ffd8a8
    style CACHE fill:#ffd8a8
    style VOL fill:#ffd8a8

3. Gunakan External Storage untuk Data Kritis #

Untuk data yang tidak boleh hilang, gunakan managed service:

  • Database: AWS RDS, Google Cloud SQL, Azure Database.
  • File upload: AWS S3, Google Cloud Storage, MinIO.
  • Cache: AWS ElastiCache, Redis Labs, Upstash.
  • Search: AWS OpenSearch, Elastic Cloud.

Managed service memberikan:

  • Backup otomatis.
  • Point-in-time recovery.
  • Replication ke multiple zone.
  • Monitoring dan alerting.
  • Patch management.

4. Jangan Menyimpan Data di Image #

# ANTI-PATTERN
FROM ubuntu
COPY ./database.dump /tmp/db.dump
COPY ./user-uploads/ /uploads/

Image adalah immutable artifact. Data runtime tidak boleh ada di image. Data harus:

  • Dibaca dari volume saat runtime.
  • Di-restore dari backup saat first run.
  • Di-seed dari migration saat container start.

5. Selalu Punya Backup Strategy #

Backup harus:

  • Otomatis — tidak bergantung pada manusia yang ingat.
  • Berkala — harian untuk data aktif, mingguan untuk data arsip.
  • Off-site — copy ke lokasi geografis berbeda.
  • Tested — restore harus dites secara berkala, bukan diasumsikan berhasil.
# Contoh cron backup harian
0 2 * * * docker run --rm \
  -v pgdata:/source:ro \
  -v /backup:/backup \
  postgres:16 \
  pg_dump -U postgres mydb > /backup/db-$(date +%F).sql

6. Implementasi Health Check #

Health check membantu orchestrator mendeteksi container yang hang dan me-restart-nya. Ini mengurangi risiko data corruption dari proses yang zombie.

services:
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 3

7. Monitor Storage Usage #

Volume bisa penuh tanpa disadari. Monitor dengan:

# Cek penggunaan storage
docker system df

# Detail per volume
docker system df -v

# Cleanup otomatis (hati-hati, bisa hapus data!)
docker volume prune

Alert di monitoring system saat volume usage > 80%.

8. Gunakan Image yang Tepat #

Pilih image database yang mature dan battle-tested. Image tidak resmi atau image yang dimodifikasi mungkin tidak handle persistence dengan benar.

# Gunakan image resmi
image: postgres:16        # ✅ official
image: mysql:8.0          # ✅ official
image: bitnami/postgresql # ✅ trusted third party
image: some-random-user/custom-pg  # ❌ tidak terjamin

9. Dokumentasikan Layout Storage #

Tim yang baru onboard harus bisa langsung paham:

  • Volume mana yang berisi apa.
  • Path di host untuk setiap volume.
  • Prosedur backup.
  • Prosedur restore.
  • SLA backup (berapa lama data bisa dikembalikan).

Studi Kasus: Data Loss di Dunia Nyata #

Kasus 1: Startup E-commerce Kehilangan Database Saat Deploy #

Situasi: Startup baru launch, MySQL jalan di container tanpa volume. Developer push kode baru, CI/CD deploy ulang, container di-recreate.

Dampak: Database kosong, 3 bulan data transaksi customer hilang. Tidak ada backup.

Penyebab: Tidak ada volume mount. CI/CD tidak punya step backup.

Solusi: Mount volume mysql-data. Tambahkan backup harian ke S3. Setup monitoring alert untuk volume usage.

Pelajaran: Backup harus jadi bagian dari pipeline, bukan afterthought.

Kasus 2: Aplikasi Upload File Hilang Saat Update #

Situasi: Aplikasi web menerima upload PDF dari user. File disimpan di /app/uploads di dalam container.

Dampak: Saat deploy image baru, semua file upload hilang. Customer protes, tim support overwhelmed.

Penyebab: Data di container, tidak ada volume.

Solusi: Mount volume uploads-data ke /app/uploads. Untuk skala besar, migrasi ke S3.

Pelajaran: File upload user hampir selalu butuh persistent storage. Default-nya harus volume, bukan filesystem container.

Kasus 3: Bind Mount Salah Path, Developer Tidak Sadar #

Situasi: Developer mount bind mount -v ./data:/app/data untuk development. Path ./data salah di-resolve, container menyimpan data di path yang tidak terduga.

Dampak: Saat developer cek “kok datanya kosong”, ternyata data ditulis di tempat lain. Bug ditemukan terlambat.

Penyebab: Path relatif terhadap working directory, bukan file docker-compose.yml (di Compose, path relatif terhadap file compose; di docker run, relatif terhadap shell).

Solusi: Gunakan path absolut atau path relatif yang eksplisit. Tambahkan health check dan log volume di startup script.

Pelajaran: Mount path harus diverifikasi. Lebih baik over-eksplisit daripada under-eksplisit.

Kasus 4: Disk Penuh, Database Crash #

Situasi: Volume database penuh karena log aplikasi yang tidak di-rotate.

Dampak: Database crash, aplikasi error. Recovery butuh restart container + cleanup.

Penyebab: Tidak ada log rotation, tidak ada monitoring disk usage.

Solusi: Setup log rotation (logrotate atau Docker log driver json-file dengan max-size). Monitor disk usage dan alert di 80%.

Pelajaran: Storage tanpa monitoring = bom waktu.


Anti-Pattern yang Harus Dihindari #

1. Backup Image Sebagai Pengganti Data #

# ANTI-PATTERN
docker commit running-container my-backup:latest
docker save my-backup:latest > backup.tar

Ini bukan backup. Image yang mengandung data runtime:

  • Berisi data sensitif.
  • Tidak konsisten (database mungkin di tengah transaksi).
  • Besar dan lambat.
  • Tidak bisa di-restore selektif.

Gunakan pg_dump, mysqldump, atau tar untuk backup data, bukan docker commit.

2. Tidak Pernah Mengetes Restore #

Backup yang tidak pernah di-restore = backup yang tidak ada. Banyak tim backup rutin tapi tidak pernah benar-benar melakukan restore. Saat disaster, mereka kaget karena file backup corrupt atau proses restore gagal.

Best practice: Restore backup ke environment test secara berkala. Verifikasi data integritas. Latih tim untuk prosedur restore.

3. Backup Manual Tanpa Automasi #

# ANTI-PATTERN
# "Oh iya, lupa backup bulan ini..."

Backup manual pasti terlewat. Gunakan cron, scheduled CI job, atau backup service untuk automasi.

4. Single Point of Failure #

Backup di host yang sama dengan data = tidak ada backup. Kalau host crash, backup dan data hilang bersamaan. Selalu copy backup ke lokasi lain.

flowchart LR
    A[Host] -->|backup| B[Same Disk]
    A -->|backup| C[Different Host]
    A -->|backup| D[Cloud Storage]
    
    B -.->|disk fail| X[Backup HILANG]
    C -.->|host fail| OK[Backup AMAN]
    D -.->|region fail| OK2[Backup AMAN]
    
    style B fill:#ff6b6b,color:#fff
    style X fill:#ff6b6b,color:#fff

5. Tidak Mendokumentasikan Prosedur Restore #

Saat disaster, kamu tidak ingin membuka notes untuk mencari langkah restore. Prosedur harus:

  • Tercatat di RUNBOOK.md.
  • Bisa dijalankan dengan satu script.
  • Sudah dites.
  • Diketahui semua engineer on-call.

Langkah Konkret: Audit Storage Docker Kamu #

Sebelum artikel ini selesai, lakukan audit sederhana pada setup Docker kamu saat ini:

CHECKLIST AUDIT DATA LOSS:

CONTAINER:
  □ Apakah ada container yang menyimpan data di filesystem?
  □ Apakah ada bind mount yang berisi data penting?
  □ Apakah ada volume yang isinya tidak jelas?

BACKUP:
  □ Apakah volume di-backup secara berkala?
  □ Apakah backup disimpan di lokasi berbeda?
  □ Apakah restore sudah pernah di-tes?

MONITORING:
  □ Apakah disk usage di-monitor?
  □ Apakah ada alert untuk volume penuh?
  □ Apakah ada alert untuk container yang sering restart?

DOKUMENTASI:
  □ Apakah layout storage didokumentasikan?
  □ Apakah prosedur restore ada di runbook?
  □ Apakah tim tahu cara restore saat disaster?

Kalau ada item yang belum di-check, kamu punya PR untuk dilakukan minggu ini.


Ringkasan #

  • Data loss di Docker bukan bug, tapi kesalahan pemahaman konsep. Container bersifat ephemeral, dan menyimpan data di filesystem container adalah anti-pattern paling umum.
  • Lima penyebab utama: menyimpan data di container, recreate container saat deploy, menganggap docker restart selalu aman, salah konfigurasi volume (lupa mount, typo path), dan bind mount tanpa backup.
  • Volume ≠ backup. Volume memindahkan data ke host, tapi tidak menggantikan backup. Untuk data penting, selalu backup ke lokasi lain (S3, NFS).
  • Tingkat risiko: Container FS dan tmpfs = risiko sangat tinggi. Volume dan bind mount tanpa backup = risiko sedang. External storage dan managed service = risiko rendah.
  • Prinsip utama: Container = stateless, data = stateful di luar container. Database harus pakai volume. File upload harus pakai volume atau object storage. Image = immutable, bukan tempat data runtime.
  • Best practice: gunakan volume untuk data penting, pisahkan state dan stateless, gunakan external storage untuk data kritis, jangan simpan data di image, selalu punya backup strategy (otomatis, berkala, off-site, tested).
  • Mitos yang harus diluruskan: volume bukan backup, docker restart bukan strategi persistence, docker commit bukan cara backup, Kubernetes tidak otomatis backup, writable layer tidak selalu aman.
  • Audit storage secara berkala: cek container yang menyimpan data tanpa volume, verifikasi backup, test restore, monitor disk usage.

← Sebelumnya: Persistent Data   Berikutnya: Volume →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact