Volume #
Dalam dunia container, data adalah hal paling rentan untuk hilang. Container bersifat ephemeral: ketika container dihapus, seluruh filesystem di dalamnya ikut hilang. Tanpa mekanisme persistent storage, Docker hanya cocok untuk eksperimen — bukan untuk aplikasi nyata.
Di sinilah Docker Volume berperan. Volume adalah mekanisme resmi Docker untuk menyimpan dan mengelola data secara persisten, terpisah dari lifecycle container. Ia adalah pondasi dari semua strategi storage production di Docker.
Artikel ini membahas volume secara mendalam: dari konsep dasar, jenis-jenis, cara kerja, sintaks CLI dan Compose, sampai integrasi dengan storage eksternal via volume driver. Setelah membaca ini, kamu akan punya pemahaman yang solid untuk memilih dan mengimplementasikan volume di setiap situasi.
Apa Itu Docker Volume? #
Docker Volume adalah direktori khusus yang:
- Disimpan di luar filesystem container (di host, di tempat yang dikelola Docker).
- Dikelola penuh oleh Docker Engine — bukan oleh user atau OS.
- Digunakan untuk menyimpan data secara persisten — bertahan saat container dihapus, di-restart, atau di-recreate.
Secara teknis, volume disimpan di host di direktori yang dikelola Docker (default /var/lib/docker/volumes/). Tapi container tidak perlu tahu lokasi fisiknya — Docker yang mengelola mapping antara path di container dengan path di host.
flowchart LR
subgraph HOST["Host Machine"]
H1[Container A<br/>/app/data]
H2[Container B<br/>/var/lib/mysql]
H3[Container C<br/>/uploads]
VOL[Docker Volume<br/>app-data<br/>disimpan di /var/lib/docker/volumes/]
end
H1 --> VOL
H2 --> VOL
H3 --> VOL
style VOL fill:#ffd8a8
Volume dirancang untuk menyimpan data yang harus bertahan:
- Database (MySQL, PostgreSQL, MongoDB, Redis).
- File upload (gambar, dokumen, attachment).
- Cache yang mahal untuk di-rebuild.
- Shared data antar container.
- Konfigurasi yang harus persist (walau biasanya lebih cocok bind mount).
Mengapa Docker Volume Dibutuhkan? #
Tanpa volume, Docker hampir tidak berguna untuk aplikasi production. Alasannya sederhana.
flowchart TB
subgraph WITHOUT["Tanpa Volume"]
A1[App Container] --> A2[Data di /app/data]
A2 --> A3[Container dihapus]
A3 --> A4[Data HILANG]
end
subgraph WITH["Dengan Volume"]
B1[App Container] --> B2[Data di /app/data]
B2 --> B3[Volume mount]
B3 --> B4[Container dihapus]
B4 --> B5[Volume tetap ada]
B5 --> B6[Container baru bisa mount volume sama]
end
style A4 fill:#ff6b6b,color:#fff
style B5 fill:#51cf66,color:#fff
style B6 fill:#51cf66,color:#fff
Lima masalah yang dipecahkan volume:
- Persistence — data bertahan di luar lifecycle container.
- Backup — data bisa di-backup dengan mudah (volume = direktori di host).
- Sharing — banyak container bisa mount volume yang sama.
- Migration — data bisa dipindahkan ke host lain (volume = folder di host).
- Decoupling — data terpisah dari aplikasi, sesuai prinsip twelve-factor app.
Prinsip penting yang harus kamu pegang:
Container bersifat stateless, data bersifat stateful dan hidup di luar container.
Ini bukan pilihan gaya — ini adalah cara Docker bekerja. Container yang menyimpan state di internal filesystem adalah anti-pattern.
Twelve-Factor App, Factor VI: “Execute the app as one or more stateless processes.” Artinya aplikasi tidak boleh menyimpan state di prosesnya. State harus disimpan di backing service — yang di konteks Docker adalah volume, database eksternal, atau object storage.
Jenis-Jenis Storage di Docker — Perbandingan #
Docker menyediakan tiga mekanisme storage. Masing-masing punya karakteristik yang berbeda.
| Mekanisme | Lokasi | Persisten | Managed By | Use Case |
|---|---|---|---|---|
| Volume | /var/lib/docker/volumes/ |
Ya | Docker | Production, database, multi-container |
| Bind Mount | Path host manual | Ya | User / OS | Development, live reload, config |
| tmpfs | RAM | Tidak | OS | Cache, secret sementara |
flowchart TB
P[Storage di Docker] --> V[Volume]
P --> B[Bind Mount]
P --> T[tmpfs]
V --> V1[✓ Production]
V --> V2[✓ Database]
V --> V3[✓ Multi-container]
V --> V4[✓ Portable]
B --> B1[✓ Development]
B --> B2[✓ Live reload]
B --> B3[✓ Config file]
B --> B4[✗ Tidak portable]
T --> T1[✓ Cepat]
T --> T2[✓ Sensitif]
T --> T3[✗ Tidak persisten]
Volume adalah pilihan default untuk production. Dikelola Docker, portabel, aman, dan mendukung volume driver untuk integrasi storage eksternal.
Bind mount cocok untuk development dan akses file konfigurasi. Tidak portabel karena bergantung pada struktur host.
tmpfs untuk data yang sangat cepat diakses dan tidak perlu persist (cache, session, secret).
Detail lengkap tentang bind mount dan tmpfs dibahas di artikel masing-masing. Fokus artikel ini adalah volume.
Cara Kerja Docker Volume #
Untuk benar-benar memahami volume, kamu perlu tahu apa yang terjadi di balik layar saat kamu membuat dan menggunakan volume.
Anatomi Volume #
flowchart TB
subgraph DOCKER["Docker Host"]
subgraph VOLDIR["/var/lib/docker/volumes/"]
V1[mysql-data/<br/>_data/ ← isi volume]
V2[app-data/<br/>_data/]
V3[cache-data/<br/>_data/]
end
subgraph MOUNT["Mount Point di Container"]
M1[/var/lib/mysql/]
M2[/app/data/]
M3[/tmp/cache/]
end
end
V1 -.->|bind mount| M1
V2 -.->|bind mount| M2
V3 -.->|bind mount| M3
style V1 fill:#a8d8a8
style V2 fill:#a8d8a8
style V3 fill:#a8d8a8
Setiap volume adalah direktori di host. Saat container mount volume, Docker membuat bind mount (internal, level kernel) antara direktori volume di host dengan path di container. Container hanya melihat mount point-nya — tidak tahu atau peduli di mana data disimpan di host.
Tahapan Volume #
stateDiagram-v2
[*] --> Created: docker volume create
Created --> Mounted: container mount volume
Mounted --> Active: container running, write/read data
Active --> Unmounted: container stop/remove
Unmounted --> Mounted: container baru mount volume sama
Unmounted --> Removed: docker volume rm
Removed --> [*]
Lifecycle volume independen dari container. Container bisa dibuat dan dihapus berkali-kali, dan volume yang sama tetap ada.
Yang Terjadi Saat docker volume create
#
docker volume create mysql-data
Docker membuat direktori:
/var/lib/docker/volumes/mysql-data/
├── _data/ # isi volume, kosong saat baru dibuat
└── _metadata/ # metadata Docker (nama, driver, options, dll)
Direktori _data adalah tempat data aplikasi akan ditulis. Docker daemon me-manage ownership dan permission-nya.
Sintaks Volume di Docker CLI #
Membuat Volume #
# Buat volume named
docker volume create mysql-data
# Buat volume dengan driver spesifik
docker volume create --driver local --opt type=nfs mysql-data
# Buat volume dengan label
docker volume create --label env=production mysql-data
Melihat Daftar Volume #
# Semua volume
docker volume ls
# Filter volume yang tidak terpakai (dangling)
docker volume ls -f dangling=true
# Format output
docker volume ls --format "{{.Name}}: {{.Driver}}"
Inspect Volume #
docker volume inspect mysql-data
Output:
[
{
"CreatedAt": "2026-06-06T12:00:00Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/mysql-data/_data",
"Name": "mysql-data",
"Options": {},
"Scope": "local"
}
]
Menghapus Volume #
# Hapus satu volume
docker volume rm mysql-data
# Hapus semua volume yang tidak terpakai
docker volume prune
# Hapus dengan konfirmasi
docker volume prune --force
Peringatan:docker volume rmdandocker volume prunemenghapus data secara permanen. Tidak ada recycle bin, tidak ada undo. Selalu backup dulu sebelum menghapus volume yang berisi data penting.
Mount Volume ke Container #
Format -v:
docker run -d \
--name mysql \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8
Format --mount (lebih eksplisit):
docker run -d \
--name mysql \
--mount source=mysql-data,target=/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8
Perbedaan format:
-v— lebih ringkas, sintaks singkat.--mount— lebih jelas, setiap komponen ditulis eksplisit, lebih mudah di-script.
Named Volume vs Anonymous Volume #
Named volume (direkomendasikan):
# Volume dibuat dengan nama eksplisit
docker volume create app-data
docker run -v app-data:/app/data my-app
Kelebihan: mudah diidentifikasi, di-backup, di-manage.
Anonymous volume (tidak direkomendasikan):
# Docker otomatis generate nama random
docker run -v /app/data my-app
# Volume bernama "abc123def456..." (random hash)
Kekurangan: sulit dilacak, rentan jadi dangling volume, susah di-backup.
Best practice: Selalu gunakan named volume untuk production. Anonymous volume cenderung menumpuk sebagai “dangling volume” dan sulit di-manage. Kalau kamu pernah menjalankan docker volume ls dan melihat banyak volume dengan nama random hash, itu tanda anonymous volume yang perlu di-prune.
Volume di Docker Compose #
Docker Compose adalah cara paling umum mendefinisikan volume di environment modern. Ini deklaratif, reproducible, dan self-documenting.
Sintaks Dasar #
version: "3.9"
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Saat docker compose up pertama kali, Docker otomatis membuat volume pgdata jika belum ada. Saat docker compose down, container dihapus tapi volume tetap ada.
Volume Options #
volumes:
pgdata:
driver: local
driver_opts:
type: none
o: bind
device: /path/on/host
encrypted-data:
driver: local
driver_opts:
type: btrfs
device: /dev/sdb1
Dengan driver_opts, kamu bisa menentukan:
- Tipe filesystem (btrfs, tmpfs, nfs, dll).
- Device (path di host atau device path).
- Mount options (rw, ro, dll).
Menghapus Volume Saat down
#
# Default: volume tetap ada
docker compose down
# Hapus container DAN volume
docker compose down -v
Peringatan: down -v menghapus semua volume yang didefinisikan di compose file. Untuk data production, hampir selalu kamu ingin tidak menghapus volume.
Sharing Volume Antar Service #
services:
app:
image: my-app
volumes:
- shared-data:/app/data
worker:
image: my-worker
volumes:
- shared-data:/input
volumes:
shared-data:
Service app dan worker mount volume yang sama. Cocok untuk pattern “app menghasilkan file, worker memproses file”.
Sharing Volume Antar Container #
Salah satu kekuatan volume adalah bisa di-share ke banyak container secara bersamaan. Ini adalah pattern penting di banyak arsitektur.
Pattern 1: Web Server + Application Server #
services:
nginx:
image: nginx
volumes:
- app-data:/var/www/html:ro # read-only
app:
build: ./app
volumes:
- app-data:/app/public
volumes:
app-data:
app menulis file statis (compiled assets, generated PDFs) ke volume. nginx membaca file yang sama dengan permission read-only. nginx tidak bisa merusak data, app bisa.
Pattern 2: Producer + Consumer #
services:
producer:
build: ./producer
volumes:
- queue-data:/queue
consumer:
build: ./consumer
volumes:
- queue-data:/jobs
volumes:
queue-data:
producer menulis job ke volume. consumer membaca job dan memprosesnya. Decoupling sederhana tanpa message broker.
Pattern 3: App + Backup Service #
services:
app:
image: my-app
volumes:
- app-data:/app/data
backup:
image: alpine
volumes:
- app-data:/source:ro
- ./backups:/backup
command: tar czf /backup/app-$(date +%F).tar.gz -C /source .
volumes:
app-data:
Service backup mount volume yang sama dengan app, tapi dengan mode read-only. Backup bisa dijalankan manual atau via cron, dan container backup bersifat ephemeral.
flowchart LR
A[App Service<br/>write] --> VOL[app-data]
VOL --> B[Backup Service<br/>read-only]
VOL --> C[Analyze Service<br/>read-only]
VOL --> D[Migrate Service<br/>read-write]
style A fill:#a8d8a8
style B fill:#a8d8a8
style C fill:#a8d8a8
style D fill:#ffd8a8
Pattern penting: Service yang berbeda boleh mount volume yang sama dengan mode akses berbeda. Service producer butuh read-write, service consumer cukup read-only. Ini isolasi yang bagus — consumer tidak bisa merusak data meskipun container compromised.
Volume Driver — Integrasi dengan Storage Eksternal #
Docker mendukung volume driver untuk mengintegrasikan volume dengan storage eksternal. Ini penting untuk:
- Production — storage yang lebih reliable dari local disk.
- High availability — data di-replicate ke multiple zone/region.
- Multi-host — volume yang bisa di-mount dari banyak host secara bersamaan.
Driver yang Tersedia #
| Driver | Storage | Use Case |
|---|---|---|
local |
Local filesystem (default) | Single-host deployment |
nfs |
NFS share | Multi-host Linux |
amazon/efs |
AWS EFS | AWS, multi-AZ |
amazon/ebs |
AWS EBS | AWS, single-AZ, high IOPS |
gcs |
Google Cloud Storage | GCP |
azure |
Azure Files | Azure |
cifs/smb |
SMB share | Windows share |
glusterfs |
GlusterFS | On-premise cluster |
Contoh: AWS EFS #
# Install plugin
docker plugin install rexray/efs:latest
# Buat volume dengan driver EFS
docker volume create \
--driver rexray/efs \
--opt fsid=fs-12345678 \
app-data
# Mount ke container
docker run -v app-data:/app/data my-app
Contoh: NFS #
volumes:
shared-data:
driver: local
driver_opts:
type: nfs
o: addr=10.0.0.100,rw
device: ":/exports/shared"
Docker mount NFS share ke container, dan container bisa baca/tulis seperti volume biasa. Cocok untuk multi-host deployment.
Kapan Pakai Volume Driver? #
| Skenario | Rekomendasi |
|---|---|
| Single-host development | local |
| Single-host production | local (dengan backup) |
| Multi-host (Swarm, K8s) | nfs, efs, gcs, azure |
| High IOPS database | ebs provisioned IOPS |
| Object-like access | s3, gcs (lebih cocok) |
| Compliance/HADR | Managed database, replicated storage |
Backup dan Restore Volume #
Volume adalah direktori di host, jadi backup pada dasarnya adalah menyalin isi direktori itu. Tapi ada pola yang lebih elegan.
Backup dengan Container Helper #
# Backup
docker run --rm \
-v mysql-data:/source:ro \
-v $(pwd):/backup \
alpine \
tar czf /backup/mysql-data-$(date +%F).tar.gz -C /source .
# Restore
docker run --rm \
-v mysql-data:/target \
-v $(pwd):/backup \
alpine \
tar xzf /backup/mysql-data-2026-06-06.tar.gz -C /target
Container helper alpine (image kecil) digunakan untuk operasi tar. Source di-mount read-only untuk backup. Target di-mount read-write untuk restore.
Backup dengan Database Tool #
Untuk database, backup file volume saja sering tidak cukup. Logical backup (SQL dump) lebih aman:
# Backup MySQL
docker exec mysql-container \
mysqldump -u root -p mydb > mydb-$(date +%F).sql
# Restore MySQL
docker exec -i mysql-container \
mysql -u root -p mydb < mydb-2026-06-06.sql
Keuntungan logical backup:
- Konsisten — database di-snapshot di satu titik waktu.
- Portabel — bisa di-restore ke MySQL versi berbeda atau di host berbeda.
- Selektif — bisa backup satu database atau satu tabel saja.
Backup Otomatis dengan Cron #
# /etc/cron.d/docker-backup
0 2 * * * root docker run --rm \
-v mysql-data:/source:ro \
-v /backup:/backup \
alpine \
tar czf /backup/mysql-$(date +\%F).tar.gz -C /source . >> /var/log/backup.log 2>&1
Cron di host menjalankan container backup setiap malam. Output di-log untuk audit.
Backup ke Cloud Storage #
# Backup ke S3
0 2 * * * root docker run --rm \
-v mysql-data:/source:ro \
-v /backup:/backup \
amazon/aws-cli:latest \
sh -c "tar czf /backup/db.tar.gz -C /source . && \
aws s3 cp /backup/db.tar.gz s3://my-backups/db-$(date +%F).tar.gz"
Backup ke S3 memberikan 11 nines durability dan akses dari mana saja.
Best Practice Docker Volume #
1. Gunakan Named Volume untuk Production #
# BENAR
docker volume create app-data
docker run -v app-data:/app/data my-app
# ANTI-PATTERN (anonymous volume)
docker run -v /app/data my-app
Named volume lebih mudah di-manage, di-backup, dan di-identifikasi.
2. Naming Convention yang Konsisten #
[nama-app]-[jenis-data]-[environment]
Contoh:
webapp-uploads-prodmysql-data-stagingredis-cache-prodnginx-config-prod
Naming convention yang konsisten memudahkan:
- Identifikasi pemilik volume.
- Filter per environment.
- Audit dan cleanup.
- Dokumentasi.
3. Pisahkan Volume per Jenis Data #
volumes:
- app-data:/app/data # data aplikasi
- app-cache:/app/cache # cache
- app-logs:/app/logs # log
- app-config:/app/config # konfigurasi
Pemisahan memudahkan backup selektif (backup hanya data, tidak perlu backup cache), rotasi log independen, dan migrasi sebagian.
4. Backup Volume Secara Berkala #
Volume bukan backup. Ia hanya memindahkan data ke host. Untuk data penting, selalu backup ke:
- Lokal tapi disk berbeda (minimal).
- NFS share (lokasi berbeda di network yang sama).
- S3/GCS/Azure Blob (cloud, geografis berbeda).
- Tape/offline storage (arsip jangka panjang).
# Cron backup harian + cleanup setelah 30 hari
0 2 * * * root /opt/scripts/backup-volumes.sh
5. Monitor Volume Usage #
# Cek penggunaan disk
docker system df
# Detail per volume
docker system df -v
# Volume yang tidak terpakai
docker volume ls -f dangling=true
Setup alert di monitoring system untuk volume usage > 80%.
6. Gunakan Volume Driver untuk Multi-Host #
Untuk deployment multi-host (Swarm, K8s), local driver tidak cukup. Volume hanya ada di satu host. Pakai:
nfsuntuk multi-host Linux.efsuntuk AWS.azurefileuntuk Azure.gcsuntuk GCP.
7. Hati-hati dengan docker volume prune
#
# Hapus volume yang tidak terpakai
docker volume prune
prune menghapus SEMUA volume yang tidak di-mount ke container. Sebelum menjalankan:
- Pastikan tidak ada container penting yang stopped.
- Cek daftar volume yang akan dihapus (jalankan tanpa
--forcedulu). - Backup dulu kalau ragu.
8. Dokumentasikan Mount Point #
Setiap volume harus didokumentasikan:
Volume: pgdata-prod
Mount point di container: /var/lib/postgresql/data
Service: postgres
Isi: data PostgreSQL production
Backup: harian ke S3, retensi 30 hari
Restore procedure: ./runbooks/postgres-restore.md
Kapan TIDAK Menggunakan Volume #
Ada situasi di mana volume bukan pilihan terbaik:
- Konfigurasi yang perlu di-edit dari host — bind mount lebih cocok.
- Live reload source code — bind mount memungkinkan perubahan source di host langsung terlihat di container.
- File konfigurasi pendek (1-2 file) — bind mount lebih simple dari named volume.
- Cache yang boleh hilang — tmpfs lebih cepat.
flowchart TD
A{Butuh persistent<br/>storage?}
A -- Tidak --> B[tmpfs]
A -- Ya --> C{Data di-host<br/>perlu diakses<br/>langsung?}
C -- Ya --> D[Bind Mount]
C -- Tidak --> E[Volume]
E --> F{Multi-host?}
F -- Ya --> G[Volume Driver<br/>NFS/EFS/dll]
F -- Tidak --> H[Local Volume]
Volume dalam Arsitektur Microservices #
Di arsitektur microservices, setiap service biasanya punya volume sendiri untuk data yang persisten.
version: "3.9"
services:
api:
build: ./api
volumes:
- api-cache:/app/cache
depends_on:
- postgres
- redis
worker:
build: ./worker
volumes:
- worker-tmp:/tmp
depends_on:
- rabbitmq
postgres:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7
volumes:
- redis-data:/data
volumes:
api-cache:
worker-tmp:
pgdata:
redis-data:
Prinsip:
- Satu service, satu atau beberapa volume yang jelas.
- Tidak ada volume yang dishare kecuali memang perlu.
- Database selalu pakai volume (atau lebih baik: managed database).
- Cache boleh pakai volume atau tmpfs tergantung requirement.
- Worker temporary files boleh di tmpfs.
Cara ingat: Volume adalah “filing cabinet” untuk container. Setiap container punya cabinet sendiri untuk dokumen yang harus disimpan. Cabinet bisa dipindahkan, di-restructure, atau di-share ke container lain tanpa mengganggu dokumen di dalamnya.
Ringkasan #
- Docker Volume adalah mekanisme resmi untuk menyimpan data secara persisten, di luar lifecycle container. Disimpan di host (default
/var/lib/docker/volumes/) dan dikelola Docker Engine.- Mengapa dibutuhkan: tanpa volume, data hilang saat container dihapus, sulit di-backup, tidak bisa dishare, dan tidak portabel. Volume menyelesaikan semua itu.
- Tiga jenis storage: volume (untuk production, managed Docker), bind mount (untuk development, path host manual), tmpfs (untuk cache sensitif, di RAM). Pilih sesuai use case.
- Cara kerja: volume = direktori di host, di-mount ke path di container via bind mount level kernel. Container tidak tahu lokasi fisik volume — itulah yang membuat volume portabel.
- Sintaks CLI:
docker volume create,docker volume ls,docker volume inspect,docker volume rm,docker volume prune. Mount dengan-v nama:pathatau--mount source=...,target=....- Sintaks Compose: definisikan di top-level
volumes:, mount di service denganvolumes: - nama:path. Moderountuk read-only,rwuntuk read-write.- Named volume > anonymous volume. Selalu gunakan named volume dengan nama eksplisit untuk production. Anonymous volume (random hash) sulit di-manage.
- Sharing volume: beberapa container bisa mount volume yang sama. Pattern umum: producer-consumer, app+backup, web server + app server. Read-only mount untuk isolasi.
- Volume driver: integrasi dengan storage eksternal (NFS, EFS, EBS, GCS, Azure). Penting untuk production multi-host dan high availability.
- Backup: volume = direktori di host, bisa di-backup dengan
taratau database tool (pg_dump,mysqldump). Backup ke lokasi lain (S3, NFS) untuk durability.- Best practice: named volume, naming convention konsisten, pisahkan volume per jenis data, backup berkala, monitor usage, volume driver untuk multi-host, dokumentasi mount point.
- Aturan emas: Container stateless, data stateful di volume. Selalu mount volume untuk data penting, dan backup ke lokasi lain secara berkala.