Docker untuk yang Baru Mulai: Image, Container, Volume

Setiap kali saya onboarding developer baru ke tim, hampir selalu ada momen bingung yang sama: paham cara pakai docker run, tapi begitu ditanya "image itu apa bedanya sama container?" jawabannya mulai ngambang. Ini wajar, karena dokumentasi resmi sering langsung masuk ke istilah teknis tanpa gambaran mental yang jelas dulu. Padahal begitu tiga konsep intinya nempel di kepala, sisanya jadi jauh lebih mudah dipahami. Di tulisan ini saya coba jelaskan image, container, dan volume pakai analogi yang biasa saya pakai ke tim saya sendiri.

Image: cetakan yang tidak berubah

Anggap image sebagai cetakan kue, atau kalau mau analogi yang lebih dekat ke dunia software, anggap seperti file instalasi aplikasi lengkap dengan semua dependency-nya. Image berisi sistem operasi minimal, runtime (misalnya PHP atau Node.js), library yang dibutuhkan, dan kode aplikasi itu sendiri, semuanya dibekukan dalam satu paket yang tidak berubah (immutable).

Image dibangun dari resep bernama Dockerfile. Sebagai ilustrasi sederhana:

FROM php:8.3-fpm
COPY . /var/www/html
RUN composer install --no-dev

Setiap baris di Dockerfile menghasilkan satu lapisan (layer), dan lapisan-lapisan ini di-cache. Itu sebabnya urutan instruksi penting untuk kecepatan build: taruh langkah yang jarang berubah (seperti install dependency) di atas, dan langkah yang sering berubah (seperti copy kode aplikasi) di bawah. Satu image bisa dipakai untuk menjalankan banyak container sekaligus, persis seperti satu cetakan kue bisa dipakai berkali-kali tanpa cetakannya sendiri ikut berubah bentuk.

Container: instance yang hidup dan bisa dibuang

Kalau image itu cetakan, container adalah kue yang sudah jadi dan sedang dimakan, alias instance dari image yang sedang berjalan. Container punya proses aktif, memori sendiri, dan filesystem sendiri yang merupakan salinan dari image plus perubahan yang terjadi selama container itu hidup.

Poin paling penting yang sering terlewat: container itu sifatnya disposable, boleh dibuang kapan saja. Kalau container mati atau di-docker rm, semua perubahan yang terjadi di dalamnya (file baru, log, cache) ikut hilang kecuali disimpan di tempat lain. Ini bukan bug, ini justru filosofi utama Docker: container seharusnya stateless, sehingga kita bisa dengan tenang mematikan, mengganti, atau scaling container tanpa takut kehilangan sesuatu yang penting. Kalau ada state yang memang harus bertahan, di situlah volume masuk.

Praktik yang saya pegang: satu container idealnya menjalankan satu proses utama. Kalau butuh web server, database, dan cache berjalan bersamaan, itu tiga container terpisah yang saling terhubung lewat jaringan Docker, bukan satu container gemuk berisi tiga proses.

Volume: tempat data yang selamat dari siklus hidup container

Volume adalah area penyimpanan yang dikelola Docker di luar filesystem container, dan tetap ada meski container yang memakainya dihapus. Analoginya seperti hard disk eksternal yang bisa dicolok-lepas ke komputer manapun; komputernya (container) boleh ganti-ganti, tapi datanya tetap aman di disk eksternal itu.

Kasus paling umum yang saya pakai sehari-hari adalah data database. Kalau container MariaDB atau Postgres tidak dipasangi volume, setiap kali container di-recreate (misalnya saat update image), seluruh data ikut hilang. Contoh konfigurasinya di docker-compose.yml:

services:
  db:
    image: mariadb:11
    volumes:
      - db-data:/var/lib/mysql

volumes:
  db-data:

Ada juga bentuk lain yaitu bind mount, yang menghubungkan folder langsung dari host ke dalam container, biasa dipakai saat development supaya perubahan kode di host langsung terlihat di container tanpa perlu build ulang image.

Kenapa tiga konsep ini perlu dipahami sekaligus

Image, container, dan volume itu saling melengkapi: image adalah blueprint yang konsisten dan bisa dipakai ulang, container adalah eksekusi dari blueprint itu yang boleh dibuang kapan saja, dan volume adalah tempat menitipkan data yang tidak boleh ikut terbuang. Begitu tiga peran ini jelas di kepala, keputusan sehari-hari seperti "kenapa data saya hilang setelah restart" atau "kenapa perubahan kode saya tidak muncul" jadi jauh lebih mudah didiagnosis sendiri, tanpa perlu menghafal daftar perintah Docker satu per satu.