Skip to content
Blog Panji

Panduan Docker untuk Developer: dari Dockerfile sampai Compose

Panduan praktis Docker untuk developer: tulis Dockerfile yang benar, rampingkan image dengan multi-stage build, dan orkestrasi stack dev dengan Docker Compose.

Panji Ihsanudin Fajri

12 min read0 reads

Ilustrasi kontainer Docker untuk developer: tumpukan peti kemas biru di latar terang
Ilustrasi kontainer Docker untuk developer: tumpukan peti kemas biru di latar terang
Contents
  1. Docker untuk developer: masalah apa yang ia selesaikan
  2. Container vs virtual machine
  3. Anatomi Dockerfile: instruksi yang wajib kamu kenal
  4. Menulis Dockerfile pertama: aplikasi Node.js
  5. Multi-stage build: image ramping tanpa sampah build
  6. Docker Compose untuk workflow dev sehari-hari
  7. Workflow harian: perintah yang kamu pakai setiap hari
  8. Contoh nyata: stack API + database + cache
  9. Kesalahan umum pemula Docker
  10. Best practice Docker untuk lingkungan development
  11. FAQ
  12. Apakah Docker hanya untuk deployment, atau berguna juga saat coding harian?
  13. Berapa banyak RAM yang dibutuhkan untuk menjalankan Docker?
  14. Apakah Docker bisa dipakai di Windows dan macOS?
  15. Apa bedanya docker compose dan docker-compose?
  16. Kapan saya sebaiknya tidak memakai Docker?
  17. Kesimpulan

Kalau kamu pernah mendengar kalimat "di laptop saya sih jalan", kamu sudah mengenal masalah yang coba diselesaikan Docker. Panduan docker untuk developer ini ditulis sebagai tutorial docker yang praktis: bukan teori panjang lebar, melainkan Dockerfile, image, container, dan Compose yang bisa langsung kamu pakai di proyek sehari-hari. Di akhir artikel kamu akan bisa menulis Dockerfile sendiri, menjalankan stack multi-service dengan satu perintah, dan menghindari jebakan yang paling sering menjebak pemula.

Ringkasan: Docker mengemas aplikasi beserta dependensinya jadi satu image yang berjalan identik di mana saja. Kamu akan belajar cara kerja container, anatomi Dockerfile, multi-stage build untuk image yang ramping, Docker Compose untuk workflow dev harian, perintah-perintah penting, satu contoh stack nyata (API + database + cache), kesalahan umum pemula, dan best practice yang terbukti.

Ilustrasi kontainer Docker untuk developer: tumpukan peti kemas biru di latar terang
Cover: konsep kontainer sebagai unit pengiriman aplikasi yang konsisten

Docker untuk developer: masalah apa yang ia selesaikan

Docker adalah platform yang mengemas aplikasi dan seluruh dependensinya — library, runtime, konfigurasi — ke dalam satu unit standar bernama container, yang berjalan identik di laptop developer, server staging, maupun production. Container berbagi kernel sistem operasi host, jadi ia ringan dan menyala dalam hitungan detik, tidak seperti virtual machine yang harus mem-boot OS penuh setiap kali.

Masalah yang diselesaikan Docker sangat konkret. Tanpa container, setiap developer memasang Node, Python, atau database versi berbeda di laptopnya, dan bug muncul hanya di satu mesin lalu tidak bisa direproduksi. Dengan Docker, lingkungan development menjadi satu file yang bisa di-version-control: siapa pun yang menjalankan perintah yang sama mendapat environment yang sama. Inilah alasan Docker menjadi keterampilan dasar di hampir semua lowongan backend dan DevOps hari ini.

Container vs virtual machine

Diagram perbandingan arsitektur container Docker dan virtual machine berdampingan
Perbandingan arsitektur: VM membawa OS penuh, container berbagi kernel host

Banyak developer mencampuradukkan container dengan virtual machine (VM). Keduanya mengisolasi aplikasi, tapi caranya berbeda dan implikasinya besar untuk workflow harian.

VM memvirtualisasi hardware: setiap VM membawa kernel dan OS-nya sendiri di atas hypervisor. Container memvirtualisasi sistem operasi: semua container di satu host berbagi kernel yang sama, dan isolasinya ditangani oleh fitur kernel Linux seperti namespace dan cgroup. Hasilnya, container berukuran puluhan MB dan menyala dalam detik, sementara VM berukuran GB dan butuh puluhan detik sampai menit untuk boot.

Aspek Container Virtual machine
Ukuran tipikal Puluhan–ratusan MB Beberapa GB
Waktu start Detik Puluhan detik–menit
Yang dibawa Aplikasi + dependensi OS penuh + aplikasi + dependensi
Isolasi Isolasi proses (namespace, cgroup) Isolasi hardware penuh
Kepadatan per host Puluhan–ratusan Beberapa–belasan
Kegunaan utama Menjalankan aplikasi dan service Menjalankan OS berbeda per VM

Perlu dicatat: container bukan pengganti VM dalam semua kasus. Kalau kamu butuh kernel berbeda (misalnya menjalankan Linux di Windows tanpa WSL) atau isolasi keamanan setingkat hardware, VM tetap jawabannya. Untuk workflow development sehari-hari — menjalankan API, database, dan cache secara lokal — container hampir selalu lebih cepat dan hemat sumber daya.

Anatomi Dockerfile: instruksi yang wajib kamu kenal

Dockerfile adalah resep teks untuk membangun image. Setiap instruksi menciptakan satu layer, dan layer-layer ini di-cache sehingga build berikutnya hanya mengulang yang berubah. Berikut instruksi yang paling sering kamu pakai:

  • FROM — image dasar, misalnya node:22-alpine. Selalu jadi baris pertama.
  • WORKDIR — direktori kerja di dalam image; semua perintah setelahnya berjalan di sini.
  • COPY — menyalin file dari laptopmu ke dalam image.
  • RUN — menjalankan perintah saat build, misalnya instalasi dependensi.
  • ENV — mengatur environment variable.
  • EXPOSE — mendokumentasikan port yang dipakai aplikasi (tidak otomatis mem-publish).
  • CMD — perintah default saat container dijalankan; bisa dioverride.
  • ENTRYPOINT — perintah yang selalu dijalankan, argumennya bisa ditambah dari docker run.
  • ARG — variable yang hanya ada saat build, cocok untuk versi atau flag.

Urutan instruksi berpengaruh langsung ke kecepatan build. Letakkan instruksi yang jarang berubah (instalasi dependensi) sedini mungkin agar layer cache-nya bisa dipakai ulang, dan salin kode sumber yang sering berubah di akhir.

Untuk referensi lengkap setiap instruksi, baca dokumentasi resmi Dockerfile.

Teori cukup. Berikut Dockerfile nyata untuk aplikasi Node.js yang di-build ke direktori dist:

FROM node:22-alpine

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci --omit=dev

COPY . .
RUN npm run build

EXPOSE 3000
CMD ["node", "dist/index.js"]

Perhatikan urutannya: package.json disalin dan dependensi diinstal sebelum kode sumber disalin. Artinya, selama kamu tidak mengubah dependensi, Docker memakai layer cache untuk npm ci dan build hanya mengulang langkah terakhir. Perintah npm ci --omit=dev memakai lockfile agar versi dependensi persis sama di setiap build — detail kecil yang mencegah bug "di laptop saya jalan".

Build dan jalankan:

# Build image dengan tag
docker build -t myapp:1.0 .

# Jalankan sebagai container, petakan port 3000 host ke 3000 container
docker run -d --name myapp -p 3000:3000 myapp:1.0

# Lihat log secara live
docker logs -f myapp

# Masuk ke shell di dalam container yang sedang berjalan
docker exec -it myapp sh

# Hentikan lalu hapus container
docker stop myapp && docker rm myapp

Flag -d menjalankan container di background, -p memetakan port, dan --name memberi nama agar mudah dirujuk. Pola logs -f dan exec -it adalah dua perintah debugging yang akan kamu pakai setiap hari.

Multi-stage build: image ramping tanpa sampah build

Dockerfile di atas masih membawa tool build (TypeScript compiler, devDependencies saat build) ke dalam image final. Multi-stage build memisahkan tahap build dan runtime menjadi dua image, lalu hanya menyalin hasil akhirnya:

# Tahap 1: build
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

# Tahap 2: runtime yang ramping
FROM node:22-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]

Image final hanya berisi runtime Node, dependensi production, dan hasil build — tanpa source TypeScript, tanpa compiler, tanpa devDependencies. Pada proyek nyata, teknik ini sering memangkas ukuran image 50–80 persen, yang berarti pull lebih cepat di CI dan deploy lebih singkat. Detail lengkapnya ada di dokumentasi multi-stage build.

Docker Compose untuk workflow dev sehari-hari

Menjalankan satu container dengan docker run masih mudah. Masalah dimulai saat aplikasimu butuh database dan cache: tiga perintah docker run dengan belasan flag, urutan start yang benar, dan network yang harus dibuat manual. Docker Compose menyelesaikan ini dengan satu file YAML deklaratif:

services:
  api:
    build: .
    ports:
      - "3000:3000"
    env_file:
      - .env
    depends_on:
      - db
      - cache
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
  cache:
    image: redis:7-alpine

volumes:
  pgdata:

Dengan file ini, docker compose up -d menyalakan API, Postgres, dan Redis sekaligus dalam satu network privat. Service api dibangun dari Dockerfile lokal, sedangkan db dan cache memakai image resmi dari Docker Hub. Volume pgdata menjaga data Postgres tetap ada walau container dihapus dan dibuat ulang. Sintaks lengkapnya tercantum di spesifikasi file Compose.

Diagram alur workflow Docker dari kode ke container berjalan
Alur kerja Docker: kode sumber di-build jadi image, lalu dijalankan sebagai container

Alur kerjanya selalu sama: kode sumber di-build menjadi image, image dijalankan sebagai container, dan Compose mengorkestrasi banyak container sekaligus. Begitu pola ini dikuasai, menambah service baru — misalnya message broker atau search engine — tinggal menambah belasan baris YAML.

Workflow harian: perintah yang kamu pakai setiap hari

Setelah setup awal, 90 persen interaksimu dengan Docker adalah segelintir perintah berikut:

# Nyalakan semua service (build ulang kalau Dockerfile berubah)
docker compose up -d --build

# Cek status semua service
docker compose ps

# Lihat log satu service secara live
docker compose logs -f api

# Restart satu service setelah mengubah kode
docker compose restart api

# Masuk ke shell service db
docker compose exec db psql -U postgres

# Matikan semuanya; tambah -v untuk ikut menghapus volume data
docker compose down

Tiga kebiasaan yang membedakan developer yang nyaman dengan Docker: selalu baca log dulu sebelum menebak (logs -f), beri nama service yang jelas di compose file, dan biasakan docker compose down di akhir hari agar tidak ada container yatim memakan RAM. Menulis perintah dan membaca output dengan presisi adalah keterampilan yang sama pentingnya dengan menulis prompt yang presisi untuk AI — keduanya soal menyampaikan maksud secara eksplisit ke sistem yang literal.

Saat container bermasalah, urutan diagnosis yang hemat waktu: docker compose ps untuk melihat status, docker compose logs <service> untuk pesan error, lalu docker compose exec <service> sh untuk inspeksi langsung. Sembilan dari sepuluh masalah development — port bentrok, environment variable belum di-set, volume me-mount direktori yang salah — terlihat jelas dari tiga perintah itu.

Contoh nyata: stack API + database + cache

Mari gabungkan semuanya dalam skenario nyata: kamu mengembangkan REST API Node.js yang butuh Postgres dan Redis. Struktur proyeknya sederhana — Dockerfile dan compose.yaml di root, kode di src/, dan file .env berisi DB_PASSWORD.

Langkah pertama, tulis Dockerfile multi-stage seperti contoh di atas. Langkah kedua, tulis compose.yaml dengan tiga service. Langkah ketiga, satu perintah:

docker compose up -d --build
docker compose ps

Output ps menunjukkan tiga container berjalan dan sehat. API bisa dijangkau di localhost:3000, Postgres di localhost:5432, Redis di localhost:6379 — masing-masing terisolasi tapi saling terhubung lewat network internal Compose. Kamu bisa me-restart API tanpa menyentuh database, menghapus dan membangun ulang API tanpa kehilangan data (berkat volume pgdata), dan rekan satu tim cukup menjalankan perintah yang sama untuk mendapat environment identik.

Ilustrasi setup development dengan container database dan cache
Setup dev tipikal: laptop menjalankan container aplikasi, database, dan cache secara bersamaan

Inilah nilai terbesar Docker untuk developer: lingkungan development menjadi kode. Onboarding anggota tim baru berubah dari "ikuti 20 langkah instalasi di wiki" menjadi "clone repo, jalankan docker compose up". Perbedaan ini terasa sepele sampai kamu mengalaminya di tim yang anggotanya memakai tiga OS berbeda.

Kesalahan umum pemula Docker

  1. Menyalin seluruh konteks build termasuk node_modules. Tanpa file .dockerignore, COPY . . membawa folder raksasa ke dalam build dan merusak cache layer. Selalu buat .dockerignore berisi minimal node_modules, .git, dan file .env.
  2. Menjalankan container sebagai root tanpa alasan. Image resmi menyediakan user non-root; tambahkan USER node (untuk image Node) agar aplikasi tidak berjalan dengan hak akses penuh.
  3. Menyimpan secret di dalam image. Password atau API key yang di-COPY atau di-ENV di Dockerfile akan selamanya tertanam di layer image. Pakai env_file atau secret management, jangan hardcode.
  4. Satu container menjalankan banyak proses. Pola "API + cron + worker dalam satu container" merusak model satu-service-satu-container dan membuat log sulit dibaca. Pecah jadi service terpisah di Compose.
  5. Tidak memberi tag versi pada image. docker build -t myapp . memakai tag latest yang ambigu. Beri tag eksplisit (myapp:1.2.0) agar rollback dan debugging jelas.
  6. Mengabaikan healthcheck. Tanpa healthcheck, depends_on hanya menunggu container start, bukan service siap. Tambahkan healthcheck pada database agar API tidak crash saat Postgres belum siap menerima koneksi.

Best practice Docker untuk lingkungan development

  • Pakai image dasar yang kecil dan spesifik. node:22-alpine lebih ringan dari node:22, dan tag versi eksplisit mencegah kejutan saat image latest diperbarui.
  • Manfaatkan layer cache secara sadar. Urutkan Dockerfile dari yang paling jarang berubah ke paling sering berubah. Setiap baris yang bisa di-cache adalah detik yang dihemat di setiap build.
  • Pisahkan konfigurasi dev dan production. Pakai compose.yaml untuk base, compose.override.yaml untuk dev (volume mount kode sumber, debug port), dan file terpisah untuk production. Compose menggabungkannya otomatis.
  • Mount kode sumber sebagai volume saat development. Dengan begitu perubahan kode langsung terlihat tanpa rebuild — menghemat puluhan build per hari.
  • Bersihkan sumber daya secara rutin. docker system prune menghapus image, container, dan network yang tidak terpakai. Jalankan tiap beberapa minggu agar disk tidak penuh diam-diam.
  • Dokumentasikan perintah di README atau Makefile. Satu make dev yang menjalankan docker compose up -d --build jauh lebih ramah daripada mengharapkan semua orang hafal flag.
  • Pelajari best practice resmi Dockerfile sebagai checklist sebelum image dipakai production.

FAQ

Apakah Docker hanya untuk deployment, atau berguna juga saat coding harian?

Sangat berguna saat coding harian. Justru di sinilah Docker paling bersinar: menjalankan database, cache, dan service pendukung tanpa menginstal apa pun di laptop. Kamu tetap menulis kode di editor favoritmu, sementara dependensi infrastruktur hidup di container yang bisa dinyalakan dan dimatikan dalam detik.

Berapa banyak RAM yang dibutuhkan untuk menjalankan Docker?

Untuk stack dev tipikal (satu API + satu database + satu cache), 4–8 GB RAM total sistem biasanya cukup. Container sendiri ringan; yang memakan memori adalah aplikasinya — database Postgres di container memakai RAM yang sama seperti Postgres native. Batasi memori per service di Compose kalau laptopmu pas-pasan.

Apakah Docker bisa dipakai di Windows dan macOS?

Bisa, lewat Docker Desktop. Di Windows, Docker memakai WSL 2 sebagai backend; di macOS ia berjalan di VM Linux yang ringan dan dikelola otomatis. Perintah docker dan docker compose yang kamu pelajari di artikel ini bekerja identik di ketiga OS — itulah salah satu janji utama Docker.

Apa bedanya docker compose dan docker-compose?

docker compose (tanpa tanda hubung) adalah versi plugin modern yang terintegrasi ke Docker CLI, sedangkan docker-compose (dengan tanda hubung) adalah binary Python lama yang sudah tidak dikembangkan. Selalu pakai docker compose — sintaks file YAML-nya kompatibel, jadi tidak ada alasan memakai versi lama.

Kapan saya sebaiknya tidak memakai Docker?

Jangan pakai Docker kalau aplikasimu butuh akses hardware langsung yang rumit (misalnya GPU computing dengan driver khusus, walau ini makin membaik), kalau overhead satu layer abstraksi tidak sebanding untuk skrip sekali jalan, atau kalau timmu belum siap memelihara Dockerfile. Docker adalah tool, bukan kewajiban — pakai di mana ia menghilangkan rasa sakit, bukan menambahnya.

Kesimpulan

Docker untuk developer pada intinya adalah satu disiplin: perlakukan environment sebagai kode. Tulis Dockerfile yang memanfaatkan layer cache, rampingkan image dengan multi-stage build, orkestrasi service dengan Compose, dan kuasai segelintir perintah harian sampai menjadi refleks. Setelah itu, frasa "di laptop saya jalan" berhenti menjadi masalah — karena laptop semua orang menjalankan hal yang sama.

Langkah berikutnya yang paling masuk akal: ambil satu proyek pribadimu, tulis Dockerfile dan compose.yaml untuknya, lalu jalankan seluruh stack dengan satu perintah. Kalau kamu ingin workflow development yang lebih cerdas dengan bantuan AI, baca juga panduan lengkap prompt engineering — environment yang konsisten plus instruksi yang presisi membuat iterasi jauh lebih cepat.

Keep reading

Related articles