Kerangka pemilihan pada Chapter Konsep Persistence berakhir dengan satu saran: bila ragu, mulailah dari volume. Sekarang saatnya membuktikan bahwa anjuran itu berdiri di atas mekanisme nyata, bukan sekadar selera. Chapter ini membedah siklus hidup volume penuh — membuatnya, memeriksa lokasi fisiknya, memasangnya ke container, lalu membawa container itu ke penghujung umur dan menyaksikan datanya tetap berdiri. Kita juga membereskan utang kecil dari chapter sebelumnya: dua volume anonim yang ditinggalkan container postgres Budi, yang diam-diam masih memakan ruang disk.
Membuat dan Memeriksa Volume #
Volume dikelola sebagai objek first-class, setara dengan container dan image — ia punya kelompok perintah docker volume sendiri. Membuatnya tidak butuh container sama sekali:
$ docker volume create data-webOutput yang Dihasilkan:
data-webOutput satu baris itu adalah nama volume yang dikembalikan daemon sebagai tanda keberhasilan. Daftar seluruh volume di mesin kini dapat kita baca:
$ docker volume lsOutput yang Dihasilkan:
DRIVER VOLUME NAME
local 7fdc9b6e34d4aae50353e229b751b7575e42325338f3c76f95a359759135b772
local 800dbb7e18afac9956c38e55c4fdb1e7358a4c95c9cfe9d28bce86e3dd2ff9e2
local data-web
local latihan-volumeMari kita telaah empat baris di atas:
DRIVERbernilailocal— setiap volume dilayani oleh sebuah driver penyimpanan;localadalah driver bawaan yang menyimpan data di disk host tempat daemon berjalan.- Dua baris nama heksadesimal 64 karakter — volume anonim, masing-masing lahir diam-diam ketika Budi menjalankan container postgres dua kali pada Chapter *Konsep Persistence`; datanya masih ada di sana, hanya tidak ada container yang memakainya lagi.
data-web— volume bernama yang baru saja kita buat; namanya ditentukan manusia, sehingga bisa dirujuk kapan pun tanpa menyalin deretan hex.latihan-volume— kenalan lama dari Chapter Struktur Perintah Docker, bukti bahwa volume yang tak terpakai pun tidak terbuang sendiri: volume memang hanya hilang bila dihapus secara eksplisit.
Metadata lengkap sebuah volume bisa kita baca dengan docker volume inspect:
$ docker volume inspect data-webOutput yang Dihasilkan:
[
{
"CreatedAt": "2026-10-13T12:07:44Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/data-web/_data",
"Name": "data-web",
"Options": null,
"Scope": "local"
}
]Mari kita telaah field-field pentingnya:
CreatedAt— waktu volume diciptakan, lengkap dengan zona waktu UTC; ini waktunya perintahdocker volume createtadi dijalankan.Driver: local— driver yang sama dari kolom pertama tabeldocker volume ls, kini tercatat sebagai metadata resmi.Labels: null— volume ini dibuat tanpa label; flag--labelpadadocker volume createbisa menempelkan pasangan key-value untuk kebutuhan inventarisasi.Mountpoint— lokasi fisik data di host:/var/lib/docker/volumes/data-web/_data. Inilah jawaban atas pertanyaan “di mana sebenarnya data volume tinggal”.Scope: local— volume hidup pada satu host Docker saja; lingkup lintas-cluster seperti swarm memakai mekanisme berbeda di luar jalur course ini.
Mountpoint memang berada di filesystem host, tetapi area /var/lib/docker adalah wilayah sang daemon — kita tidak mengedit isinya secara langsung, melainkan memasangnya ke container lewat jalur resminya. Bagaimana bentuk jalur resmi itu? Mari kita pasangkan volume ini ke nginx.
Memasang Volume Bernama ke Container #
Pemasangan volume ke container memakai flag -v yang bagian-bagiannya dipisah titik dua — untuk volume bernama, bagian pertamanya adalah nama volume, bukan path host:
$ docker run -d --name web -p 8080:80 -v data-web:/usr/share/nginx/html nginxOutput yang Dihasilkan:
f7c2a91b3e55913c4a5f1c6c0a4d8e2b3f4a5b6c7d8e9f0a1b2c3d4e5f60718aSesaat setelah container menyala, kita periksa halaman yang disajikannya:
$ curl localhost:8080Output yang Dihasilkan:
<!doctype html>
<html>
<head>
<title>Welcome to nginx!</title>
...Halaman selamat datang bawaan nginx masih utuh — padahal /usr/share/nginx/html sudah tertutup volume kosong. Mari kita telaah apa yang sebenarnya terjadi:
-v data-web:/usr/share/nginx/html— bagian pertama adalah nama volume, bagian kedua adalah path tujuan di dalam container; container kini menulis dan membaca path itu pada volume, bukan pada writable layer.- Volume kosong diisi lebih dulu — ketika sebuah volume masih kosong dipasang pada path yang berisi berkas milik image, daemon menyalin berkas-berkas itu ke dalam volume sebelum container menyala;
index.htmldan50x.htmlbawaan nginx kini menjadi isi awaldata-web. curltetap menampilkan halaman bawaan — karena pra-isi tadi, nginx menyajikan berkas yang sama seolah tidak ada mount sama sekali.
Bentuk pendek -v punya saudara panjang --mount yang menuliskan setiap bagian secara eksplisit:
| Aspek | -v singkat | --mount panjang |
|---|---|---|
| Contoh | -v data-web:/usr/share/nginx/html | --mount type=volume,src=data-web,dst=/usr/share/nginx/html |
| Tata tulis | Tiga bagian dipisah titik dua | Pasangan key=value dipisah koma |
| Jenis mount | Ditebak dari bentuk bagian pertama | Dinyatakan gamblang lewat type=volume |
| Volume belum ada | Dibuat otomatis oleh daemon | Namanya tertulis gamblang sebagai src=... |
| Paling tepat untuk | Perintah cepat di terminal | Skrip dan dokumentasi yang harus terbaca jelas |
Kedua bentuk menunjuk volume yang sama dan saling menggantikan; pilihan di antara keduanya adalah urusan gaya dan kejelasan, bukan fungsi.
Momen Kebenaran: Data yang Selamat dari docker rm #
Inilah demonstrasi inti chapter ini, dan sekaligus balasan langsung atas kehilangan data Budi di chapter sebelumnya. Kita tulis satu berkas ke path yang dipasangi volume:
$ docker exec web sh -c 'echo halo > /usr/share/nginx/html/halo.txt'Berkas halo.txt kini tinggal di dalam volume data-web. Sekarang kita lakukan hal yang pada Chapter Writable Container Layer menghapus segalanya: buang containernya, lalu jalankan container baru dengan memasang volume yang sama:
$ docker rm -f web
$ docker run -d --name web -p 8080:80 -v data-web:/usr/share/nginx/html nginx
$ docker exec web cat /usr/share/nginx/html/halo.txtOutput yang Dihasilkan:
web
f7c2a91b3e55913c4a5f1c6c0a4d8e2b3f4a5b6c7d8e9f0a1b2c3d4e5f60718a
haloSatu kata halo di baris terakhir adalah seluruh bukti yang dibutuhkan. Mari kita telaah mengapa data itu selamat:
docker rm -f webhanya membuang writable layer — container beserta layer tertulisnya terhapus, tetapi volume adalah objek terpisah yang tidak ikut mati; inilah pemisahan umur yang dijanjikan Chapter Konsep Persistence.- Container baru memasang volume yang sama —
-v data-web:/usr/share/nginx/htmlpada run kedua menunjuk volume bernama yang sama, sehingga isi lama langsung terlihat tanpa proses pemulihan apa pun. halo.txtterbaca utuh — berkas itu tidak pernah menumpang writable layer; sejak ditulis, rumahnya adalah mountpoint volume di disk host.- Pola ini berulang sebanyak apa pun — container boleh dibuang dan dijalankan puluhan kali; selama nama volumenya sama, data tetap berdiri.
Volume Anonim versus Volume Bernama #
Dua baris hex pada tabel docker volume ls di awal chapter mewakili kelas kedua volume: yang anonim. Volume anonim lahir tanpa diminta lewat tiga pintu — instruksi VOLUME di Dockerfile image (pintu yang mengejutkan Budi pada Chapter VOLUME dan LABEL), flag -v yang hanya membawa satu path tanpa nama, atau pemasangan --mount tanpa src. Tanpa nama, satu-satunya identitasnya adalah deretan 64 karakter hex yang praktis tidak bisa diingat manusia.
| Aspek | Volume anonim | Volume bernama |
|---|---|---|
| Nama | 64 karakter heksadesimal acak | Ditentukan kita, misalnya data-web |
| Cara lahir | Instruksi VOLUME image, -v /path, atau --mount tanpa src | docker volume create atau -v nama:/path |
| Dipakai ulang | Sulit — nama acak sulit dirujuk dan dicatat | Mudah — cukup sebut namanya di -v atau --mount |
| Nasib setelah container mati | Kerap terlantar tanpa pemilik yang menyadarinya | Tetap dikelola sebagai objek bernama |
| Cara membersihkan | docker volume prune (anonim tak terpakai) | docker volume rm nama saat benar-benar dibuang |
Kabar penting berikutnya menyangkut keselamatan volume dari perintah pembersihan. docker image prune hanya menyentuh image; docker system prune bawaan pun tidak membuang volume — flag --volumes harus dituliskan secara eksplisit untuk itu. Sementara itu, docker volume prune memang khusus: sasaran defaultnya hanya volume anonim yang tidak dipakai container mana pun. Kita buktikan sambil membereskan utang Budi:
$ docker volume pruneOutput yang Dihasilkan:
WARNING! This will remove all anonymous volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
7fdc9b6e34d4aae50353e229b751b7575e42325338f3c76f95a359759135b772
800dbb7e18afac9956c38e55c4fdb1e7358a4c95c9cfe9d28bce86e3dd2ff9e2
Total reclaimed space: 75.6MBMari kita telaah hasil pembersihan ini:
- Dua volume anonim terbuang — keduanya volume anonim bekas container postgres Budi yang tidak lagi dipakai container mana pun; 75.6 MB ruang disk kembali, termasuk sisa data
pesertayang memang sudah tidak berharga. data-webdanlatihan-volumeselamat — keduanya volume bernama, sehingga berada di luar jangkauandocker volume prunebawaan; prinsipnya: yang anonim dianggap sampah, yang bernama dianggap milik.- Konfirmasi
[y/N]— perintah pembersihan meminta konfirmasi karena tidak bisa dibatalkan; tekanyhanya setelahdocker volume lsdibaca ulang.
Volume untuk Database #
Kini kita ulangi kisah Budi dari Chapter Konsep Persistence dengan satu perubahan kecil yang mengubah segalanya: direktori data PostgreSQL dipasang ke volume bernama pgdata. Kali ini kita pakai bentuk panjang --mount untuk latihan membaca gaya eksplisit:
$ docker volume create pgdata
$ docker run -d --name db-latihan --mount type=volume,src=pgdata,dst=/var/lib/postgresql/data -e POSTGRES_PASSWORD=rahasia123 postgres:18-alpine
$ docker exec db-latihan pg_isready -U postgres
$ docker exec db-latihan psql -U postgres -c "CREATE TABLE peserta (nama TEXT); INSERT INTO peserta VALUES ('Budi'), ('Siti');"Output yang Dihasilkan:
pgdata
d3641eb7d82395f49f0077625f0adf08adfccd8a1713158b6e28020b6f533cbf
/var/run/postgresql:5432 - accepting connections
CREATE TABLE
INSERT 0 2Tabel peserta kembali terisi dua baris. Sekarang momen yang di chapter sebelumnya berakhir musnah — container dibuang total, lalu dibangkitkan dengan volume yang sama:
$ docker rm -f db-latihan
$ docker run -d --name db-latihan --mount type=volume,src=pgdata,dst=/var/lib/postgresql/data -e POSTGRES_PASSWORD=rahasia123 postgres:18-alpine
$ docker exec db-latihan psql -U postgres -c "SELECT * FROM peserta;"Output yang Dihasilkan:
db-latihan
aba83107d4358f6a40022b3ca52c7c7b0787198d7c94a180c5d72118f14490be
nama
------
Budi
Siti
(2 rows)Mari kita telaah bedanya dengan kejadian sebelumnya:
- Direktori data kini beralamat di volume —
/var/lib/postgresql/datamenunjuk kepgdata, sehinggainitdbberjalan ke dalam volume, bukan writable layer. - Container kedua tidak menjalankan inisialisasi ulang — entrypoint PostgreSQL mendapati direktori data sudah berisi cluster utuh, jadi
initdbdilewati dan container siap lebih cepat. SELECTmengembalikan data lama — tabelpesertabeserta isinya selamat melewatidocker rm, persis kabar yang gagal kita terima ketika data masih menumpang writable layer.POSTGRES_PASSWORDdiabaikan pada data yang sudah ada — inisialisasi hanya terjadi sekali; variabel lingkungan tadi tidak menimpa cluster yang sudah terbentuk.
Sebelum berpindah topik, kita rapikan arena: docker rm -f web db-latihan menghapus kedua container latihan, sementara volume data-web dan pgdata sengaja kita biarkan hidup — keduanya akan berguna sebagai contoh kenalan pada chapter-chapter selanjutnya. Volume kini terbukti menjadi rumah data yang tahan docker rm, dikelola penuh oleh Docker, dan hidup di area yang tidak perlu kita urus letaknya. Namun ada kelas kebutuhan yang justru ingin kebalikannya: kita ingin menunjuk sendiri path di host — membuka berkas konfigurasi yang kita edit, atau source code yang berubah tiap menit — dan memasangnya langsung ke container. Untuk itu Docker menyediakan bind mount, materi Chapter Bind Mount.
Referensi #
- Volumes — konsep volume bernama, perilaku pra-isi dari image, dan anjuran pemakaiannya.
- docker volume — CLI Reference
— daftar perintah
create,ls,inspect, danprune. - docker run — CLI Reference
— flag
-vdan--mountuntuk memasang volume. - PostgreSQL — perilaku entrypoint initdb dan deklarasi direktori data pada image postgres.