Docker Compose Dasar
Target: Pemula yang sudah memahami dasar Docker (image, container, volume, network) dan ingin menguasai Docker Compose untuk mendefinisikan, mengonfigurasi, dan menjalankan aplikasi multi-kontainer secara deklaratif dan terorkestrasi. Versi: Docker Compose v2.x (Compose Spec) Prasyarat: Dockerfile Dasar Fokus modul pembelajaran ini: konsep orkestrasi multi-kontainer → Compose V2 (
docker compose) → compose.yaml & sintaks YAML → siklus hidup (up/down/stop/start/restart) → pemantauan (ps/logs/top) → exec & run → project name & isolasi → services & ports → environment & env_file → persistent volumes & bind mounts → custom networks & DNS → depends_on & healthcheck sync → restart policy & resource limits → build Dockerfile → extends & overrides → variable interpolation → service scaling → mini project microservices.
Cara Belajar
🟢 Fundamental
→ wajib dipahami untuk menjalankan stack: compose.yaml, up -d, down, ps, logs, services, ports, & env
🟡 Lanjutan
→ pelajari setelah fundamental nyaman: named volumes, networks, depends_on + healthcheck, & build
🔴 Advanced / Operasional
→ penting untuk arsitektur microservices: override files, variable interpolation, & scalingMental model orkestrasi di Docker Compose:
compose.yaml File (Definisi Blueprint)
│
▼ docker compose up -d
Project (Namespace Terisolasi)
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
Services (Apps) Networks (Bridge) Volumes (Storage)
- Web / API / DB - Automatic DNS - Persistent Data
- Ports & Env - Dual Isolation - Bind Mounts Dev
│ │ │
└───────────────────┼───────────────────┘
│
▼
Seluruh Sistem Berjalan Serempak dalam 1 Perintah!Hafalan:
Docker Compose → Tool orkestrasi multi-kontainer berbasis satu file deklaratif YAML
compose.yaml → Nama file standar resmi Compose Specification (tanpa tag version:)
docker compose up -d → Menyalakan seluruh service, network, dan volume di background
docker compose down → Mematikan dan membersihkan seluruh kontainer dan network projectDaftar Isi
🟢 Fundamental
- Pengenalan Docker Compose & Orkestrasi Multi-Container
- Menginstall & Memverifikasi Docker Compose (Compose V2)
- Format File Konfigurasi (compose.yaml vs docker-compose.yml)
- Sintaks Dasar YAML untuk Docker Compose
- Siklus Hidup Compose (docker compose up, start, stop, restart, & down)
- Pemantauan Service & Log (docker compose ps, logs, & top)
- Menjalankan Perintah di Service (docker compose exec & run)
- Project Name & Isolasi Lingkungan (-p / COMPOSE_PROJECT_NAME)
- Deklarasi Service & Image (services: & image:)
- Port Mapping (ports:)
- Environment Variables (environment: & env_file:)
🟡 Lanjutan
- Penyimpanan Persistent: Volumes (volumes:)
- Bind Mounts untuk Development (volumes: host:container)
- Jaringan Antar Service: Networks (networks:)
- Dependensi Urutan Booting: Depends On (depends_on & service_healthy)
- Restart Policy (restart: always, unless-stopped)
- Resource Limits (deploy.resources.limits)
- Custom Dockerfile Build (build: & dockerfile:)
- Health Check (healthcheck:)
🔴 Advanced / Operasional
- Extend Service & Overrides (extends: & docker-compose.override.yml)
- Compose File Interpolation & .env Variables (${VAR:-default})
- Scaling Services (docker compose up —scale)
🛠️ Referensi & Praktik
- Peta Ingatan Cepat
- Tabel Ringkasan
- Cheat Code Docker Compose 10 Detik
- Urutan Belajar yang Disarankan
- Mini Project: Stack Microservices Lengkap (Nginx Proxy + Node.js API + Redis Cache + MySQL Database)
- Referensi Resmi
1. 🟢 Pengenalan Docker Compose & Orkestrasi Multi-Container
Konsep
Docker Compose adalah sebuah tool orkestrasi deklaratif resmi dari Docker yang digunakan untuk mendefinisikan, mengonfigurasi, dan menjalankan aplikasi multi-kontainer (Multi-Container Applications) menggunakan sebuah file konfigurasi berbasis YAML.
Mengapa Membutuhkan Docker Compose?
Aplikasi web modern di dunia nyata hampir tidak pernah berdiri sendiri hanya dengan 1 kontainer tunggal. Sebuah sistem biasanya terdiri dari kombinasi:
- Kontainer Web Server (Nginx / Apache)
- Kontainer Backend API (Node.js / Laravel / Go / Python)
- Kontainer Database (MySQL / PostgreSQL)
- Kontainer In-Memory Cache (Redis)
- Kontainer Message Queue (RabbitMQ / Kafka)
Tanpa Compose: Developer harus mengetikkan puluhan perintah docker network create, docker volume create, dan docker run -d --network ... -p ... -v ... -e ... secara manual dengan urutan yang rawan salah.
Dengan Compose: Seluruh konfigurasi jaringan, volume, variabel environment, dan kontainer didefinisikan secara rapi di dalam file compose.yaml, dan seluruh sistem dapat dinyalakan hanya dengan 1 perintah tunggal: docker compose up -d.
Contoh
Contoh file compose.yaml sederhana yang menghubungkan Web Server Nginx dan Database MySQL:
# compose.yaml
services:
web:
image: nginx:alpine
ports:
- "8080:80"
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret_root_password
MYSQL_DATABASE: app_dbPerintah Menjalankan Seluruh Aplikasi:
# Menyalakan seluruh service di latar belakang
docker compose up -dOutput
[+] Running 3/3
✔ Network myproject_default Created 0.0s
✔ Container myproject-db-1 Started 0.4s
✔ Container myproject-web-1 Started 0.4sCara Kerja
File Definisi: compose.yaml
│
▼
Command: docker compose up -d
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
Buat Network Nyalakan Service Nyalakan Service
(Virtual Bridge) Database (db) Web Server (web)
│ │ │
└───────────────────┼───────────────────┘
│
▼
Seluruh Service Saling Terhubung via DNS Otomatis!Hafalan:
Docker Compose → Tool manajemen aplikasi multi-kontainer menggunakan file YAML
docker compose up -d→ Membuat network, volume, dan menyalakan seluruh service otomatis
docker compose down → Mematikan dan membersihkan seluruh kontainer & network projectBest Practice & Kesalahan Umum
- ✅ Gunakan Docker Compose untuk seluruh kebutuhan development lokal agar setiap anggota tim dapat menjalankan seluruh stack aplikasi dalam 1 kali klik.
- ❌ Jangan menjalankan banyak perintah
docker runterpisah satu per satu di terminal jika aplikasi Anda terdiri dari lebih dari 1 kontainer.
2. 🟢 Menginstall & Memverifikasi Docker Compose (Compose V2)
Konsep
Pada ekosistem Docker modern, Docker Compose telah berevolusi menjadi Compose V2:
- Compose V1 (Jadul / Usang): Ditulis dalam bahasa Python dengan perintah CLI bertanda minus (
docker-compose). Versi ini sudah resmi Deprecated dan dihentikan. - Compose V2 (Standar Modern Resmi): Ditulis ulang dalam bahasa Go dan diintegrasikan langsung sebagai plugin resmi Docker CLI dengan perintah berspasi (
docker compose).
Status Instalasi:
- Docker Desktop (Windows & macOS): Compose V2 sudah terinstal secara otomatis dan langsung siap digunakan.
- Linux Server: Terinstal sebagai paket
docker-compose-plugin.
Contoh
# 1. Memeriksa versi Docker Compose V2 yang terpasang
docker compose version
# 2. Memeriksa daftar sub-perintah bantuan
docker compose --helpOutput
Docker Compose version v2.27.0
Usage: docker compose [OPTIONS] COMMAND
Define and run multi-container applications with Docker.Cara Kerja
Terminal CLI: docker compose ...
│
▼
Docker CLI Engine mengeksekusi plugin "compose" berbasis Go
│
▼
Berkomunikasi langsung dengan Docker Daemon HostHafalan:
docker compose version → Memverifikasi instalasi Compose V2 (Gunakan SPASI, bukan minus '-')
docker compose → Sintaks resmi Compose V2 modern
docker-compose → Sintaks usang Compose V1 (TIDAK LAGI DIGUNAKAN)Best Practice & Kesalahan Umum
- ✅ Selalu gunakan sintaks modern
docker compose(dengan spasi) di seluruh dokumentasi dan skrip CI/CD baru. - ❌ Hindari menggunakan sintaks jadul
docker-compose(dengan tanda minus) karena sudah tidak menerima pembaruan fitur keamanan.
3. 🟢 Format File Konfigurasi (compose.yaml vs docker-compose.yml)
Konsep
Docker Compose membaca konfigurasi deklaratif dari sebuah file di folder direktori aktif.
Urutan Prioritas Penamaan File Resmi (Compose Specification):
compose.yaml(Standar Rekomendasi Resmi Utama saat ini).compose.ymldocker-compose.yamldocker-compose.yml(Format warisan/legacy yang tetap didukung untuk backward compatibility).
Catatan Penting Tentang version: Tag:
Pada spesifikasi Compose Specification modern (Compose V2), baris deklarasi version: '3.8' SUDAH TIDAK DIPERLUKAN LAGI (Obsolete). Docker Compose modern akan secara otomatis menggunakan spesifikasi fitur terbaru tanpa perlu menuliskan tag version di baris pertama.
Contoh
Struktur File compose.yaml Modern yang Bersih:
# compose.yaml (Standar Modern - Tanpa tag 'version:')
services:
frontend:
image: nginx:alpine
ports:
- "80:80"
backend:
image: node:20-alpine
environment:
- NODE_ENV=productionOutput
# Docker otomatis mendeteksi file compose.yaml di direktori saat ini
docker compose configname: my-app
services:
backend:
environment:
NODE_ENV: production
image: node:20-alpine
networks:
default: null
frontend:
image: nginx:alpine
networks:
default: null
ports:
- mode: ingress
target: 80
published: "80"
protocol: tcp
networks:
default:
name: my-app_defaultCara Kerja
Perintah: docker compose up
│
▼
Cari file di folder: compose.yaml ──► Ditemukan!
│
▼
Validasi skema struktur YAML & terjemahkan ke instruksi containerHafalan:
compose.yaml → Nama file standar resmi yang paling direkomendasikan saat ini
docker-compose.yml → Nama file alternatif lama yang masih kompatibel
Tag 'version:' → Sudah usang (obsolete) dan tidak wajib ditulis lagi di Compose V2Best Practice & Kesalahan Umum
- ✅ Gunakan nama file
compose.yamluntuk proyek-proyek baru. - ❌ Jangan khawatir jika tidak menuliskan
version: '3.8'; Compose Specification modern sengaja menghapusnya agar konfigurasi lebih simpel.
4. 🟢 Sintaks Dasar YAML untuk Docker Compose
Konsep
YAML (YAML Ain’t Markup Language) adalah format serialisasi data yang mengandalkan Indentasi Spasi (Whitespace Indentation) untuk menentukan struktur hierarki data.
Aturan Emas Sintaks YAML:
- DILARANG MENGGUNAKAN TAB: Selalu gunakan 2 Karakter Spasi untuk setiap tingkatan indentasi. Menggunakan tombol Tab akan menyebabkan error fatal YAML Syntax Error.
- Key-Value Pairs: Ditulis dengan format
key: value(wajib ada 1 spasi setelah tanda titik dua:). - List / Array (Daftar Item): Ditulis dengan tanda strip minus (
-) diikuti 1 spasi. - Komentar: Ditulis dengan awalan tanda pagar (
#). - String Khusus (Port & Boolean): Selalu bungkus nomor port dengan tanda kutip (misal
"8080:80") agar tidak dianggap sebagai bilangan basis-60 oleh parser YAML.
Contoh
# Contoh Struktur YAML yang Valid & Rapi
services:
# Service 1: Web App
web-app:
image: nginx:alpine
container_name: production-web
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
APP_NAME: "Toko Online"
DEBUG_MODE: "false"
# Service 2: Redis Cache
cache-service:
image: redis:alpine
command: ["redis-server", "--appendonly", "yes"]Output
Memvalidasi sintaks YAML sebelum dijalankan:
docker compose config --quiet && echo "Sintaks YAML 100% VALID!"Sintaks YAML 100% VALID!Cara Kerja
services: (Tingkat 0: Induk Service)
web-app: (Tingkat 1: 2 Spasi - Nama Service)
image: nginx (Tingkat 2: 4 Spasi - Atribut Service)
ports: (Tingkat 2: 4 Spasi - List Port)
- "80:80" (Tingkat 3: 6 Spasi - Item List)Hafalan:
Indentasi YAML → Gunakan 2 spasi konsisten (DILARANG menggunakan tombol TAB)
List / Array → Awali baris dengan '- ' (strip spasi)
Quotes Port → Selalu beri tanda kutip pada port "- "8080:80""Best Practice & Kesalahan Umum
- ✅ Aktifkan ekstensi YAML linter di editor kode (seperti VS Code) untuk mendeteksi spasi yang tidak sejajar secara otomatis.
- ❌ Jangan pernah menggunakan tombol Tab di dalam file
compose.yaml.
5. 🟢 Siklus Hidup Compose (docker compose up, start, stop, restart, & down)
Konsep
Docker Compose mengelola seluruh siklus hidup (Lifecycle) kumpulan kontainer secara serentak sebagai satu kesatuan proyek (Project).
Perintah Siklus Hidup Utama:
docker compose up: Membangun image (jika belum ada), membuat network & volume, lalu menyalakan seluruh kontainer.- Opsi
-d(detached): Menjalankan di latar belakang (background). - Opsi
--build: Memaksa proses build ulang image sebelum kontainer dinyalakan.
- Opsi
docker compose down: Menghentikan dan MENGHAPUS seluruh kontainer dan network yang dibuat oleh file compose.- Opsi
-v(volumes): Ikut menghapus named volume yang terdaftar (Hati-hati: data database akan terhapus!).
- Opsi
docker compose stop: Menghentikan kontainer sementara tanpa menghapusnya.docker compose start: Menyalakan kembali kontainer yang sedang stop.docker compose restart: Memuat ulang seluruh service.
Contoh
# 1. Menyalakan seluruh stack aplikasi di background
docker compose up -d
# 2. Menghentikan service sementara (data kontainer tetap ada)
docker compose stop
# 3. Menyalakan kembali service
docker compose start
# 4. Mematikan dan membersihkan seluruh kontainer & network project
docker compose down
# 5. Membersihkan total beserta Volume database-nya
docker compose down -vOutput
Saat docker compose up -d:
[+] Running 2/2
✔ Container myapp-db-1 Started 0.3s
✔ Container myapp-web-1 Started 0.3sSaat docker compose down:
[+] Running 3/3
✔ Container myapp-web-1 Removed 0.2s
✔ Container myapp-db-1 Removed 0.2s
✔ Network myapp_default Removed 0.1sCara Kerja
docker compose up -d
│
▼
[ Running Services ]
│
┌──────────────┴──────────────┐
docker stop │ │ docker down
▼ ▼
[ Stopped State ] [ Containers & ]
│ [ Network DIHAPUS ]
docker start │
▼
[ Back to Running ]Hafalan:
docker compose up -d → Menyalakan seluruh stack kontainer di background
docker compose down → Mematikan dan menghapus kontainer serta virtual network project
docker compose down -v → Menghapus kontainer + network + VOLUME PERSISTEN
docker compose restart → Memuat ulang seluruh serviceBest Practice & Kesalahan Umum
- ✅ Selalu gunakan
docker compose downsaat selesai bekerja untuk menjaga laptop tetap bersih dari kontainer dan network yang menggantung. - ❌ Hati-hati jangan menambahkan flag
-vpadadocker compose down -vjika Anda tidak berniat menghapus isi database lokal Anda.
6. 🟢 Pemantauan Service & Log (docker compose ps, logs, & top)
Konsep
Ketika mengelola banyak kontainer yang berjalan bersamaan, kita membutuhkan perintah pemantauan terpusat untuk melihat status kesehatan, proses yang berjalan, dan log keluaran dari seluruh service.
Perintah Pemantauan:
docker compose ps: Menampilkan daftar service, status running, dan pemetaan port.docker compose logs: Menggabungkan dan menampilkan rekaman log dari seluruh service dalam satu layar.- Opsi
-f(follow): Memantau stream log secara live real-time. - Opsi
--tail N: MenampilkanNbaris terakhir saja. - Argumen
[service_name]: Hanya memantau log service tertentu (misal:docker compose logs -f web).
- Opsi
docker compose top: Menampilkan daftar proses sistem (PID) yang sedang aktif berjalan di dalam setiap kontainer.
Contoh
# 1. Melihat status seluruh service yang dikelola compose
docker compose ps
# 2. Memantau log gabungan secara live real-time (Ctrl+C untuk keluar)
# docker compose logs -f
# 3. Melihat 20 baris log terakhir hanya dari service database 'db'
docker compose logs --tail 20 db
# 4. Melihat proses PID yang aktif di setiap kontainer
docker compose topOutput
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
myapp-db-1 mysql:8.0 "docker-entrypoint.s…" db 2 minutes ago Up 2 minutes 3306/tcp
myapp-web-1 nginx:alpine "/docker-entrypoint.…" web 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp
myapp-db-1 | 2026-08-29T10:46:01.123456Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections.
myapp-db-1 | Version: '8.0.36' socket: '/var/run/mysqld/mysqld.sock' port: 3306Cara Kerja
Container 'web' (stdout) ──┐
├──► docker compose logs (Menggabungkan log dengan warna berbeda)
Container 'db' (stdout) ──┘Hafalan:
docker compose ps → Menampilkan status seluruh service dalam project aktif
docker compose logs -f [srv] → Memantau rekaman log service secara live real-time
docker compose top → Menampilkan daftar proses aktif di dalam kontainerBest Practice & Kesalahan Umum
- ✅ Sertakan nama service spesifik (misal:
docker compose logs -f backend) agar terminal tidak dipenuhi log dari service lain yang tidak relevan saat debugging. - ❌ Jangan menjalankan
docker compose logstanpa parameter pada sistem yang sudah berjalan lama tanpa batas baris (--tail).
7. 🟢 Menjalankan Perintah di Service (docker compose exec & run)
Konsep
Docker Compose menyediakan dua perintah untuk mengeksekusi instruksi di dalam lingkungan service:
docker compose exec <service> <command>:- Mengeksekusi perintah ke dalam service yang SUDAH AKTIF BERJALAN (mirip
docker exec). - Sangat ideal untuk: membuka shell terminal (
sh/bash), menjalankan migrasi database, atau menjalankan command CLI aplikasi (misal:php artisan migrate,npm run seed).
- Mengeksekusi perintah ke dalam service yang SUDAH AKTIF BERJALAN (mirip
docker compose run <service> <command>:- Membuat dan menyalakan KONTAINER BARU SEMENTARA dari definisi service tersebut, mengeksekusi perintah satu kali, lalu berhenti (one-off task).
- Sangat ideal untuk: inisialisasi awal proyek atau backup data.
Contoh
# 1. Membuka terminal shell interaktif ke dalam service 'web' yang sedang aktif
docker compose exec web sh
# 2. Menjalankan perintah artisan/npm di service backend yang sedang berjalan
docker compose exec backend npm run test
# 3. Menjalankan task satu kali (one-off) dengan kontainer baru sementara
docker compose run --rm backend npm install axiosOutput
Saat membuka shell docker compose exec web sh:
/ # ls -la
total 64
drwxr-xr-x 1 root root 4096 Aug 29 10:46 .
drwxr-xr-x 1 root root 4096 Aug 29 10:46 etc
drwxr-xr-x 1 root root 4096 Aug 29 10:46 usr
/ # exitCara Kerja
docker compose exec backend npm test ──► Masuk ke Kontainer 'backend' yang Sedang Berjalan
│
docker compose run --rm backend npm install ──► Buat Kontainer Baru -> Jalankan -> HapusHafalan:
docker compose exec <service> <cmd> → Menjalankan perintah di dalam kontainer yang SEDANG BERJALAN
docker compose run --rm <service> <cmd> → Menjalankan perintah di dalam kontainer BARU SATU KALIBest Practice & Kesalahan Umum
- ✅ Selalu sertakan flag
--rmsaat menggunakandocker compose run --rmagar kontainer sementara tidak menumpuk sebagai sampah disk. - ❌ Jangan gunakan
docker compose execpada service yang statusnya sedang mati/stopped (service wajib berstatus Up).
8. 🟢 Project Name & Isolasi Lingkungan (-p / COMPOSE_PROJECT_NAME)
Konsep
Secara default, Docker Compose menggunakan nama folder tempat file compose.yaml berada sebagai Project Name.
Nama project ini digunakan oleh Docker Compose sebagai awalan (prefix) penamaan seluruh entitas yang dibuat:
- Nama Kontainer:
<project_name>-<service_name>-1(misal:myproject-web-1). - Nama Network:
<project_name>_default(misal:myproject_default). - Nama Volume:
<project_name>_<volume_name>(misal:myproject_db_data).
Cara Mengubah Project Name:
- Atribut
name:di dalamcompose.yaml: Mendefinisikan nama proyek secara eksplisit. - Flag
-p / --project-name:docker compose -p staging up -d. - Environment Variable
COMPOSE_PROJECT_NAME: Di dalam file.env.
Keuntungan: Memungkinkan kita menjalankan beberapa instance lingkungan yang berbeda (Development, Staging, Feature-Branch) dari file konfigurasi yang sama di satu mesin server tanpa bentrok nama!
Contoh
# compose.yaml
name: toko-online-app
services:
web:
image: nginx:alpineMenjalankan dengan Project Name Khusus via CLI:
# Menjalankan instance versi feature-staging
docker compose -p toko-staging up -dOutput
[+] Running 2/2
✔ Network toko-staging_default Created 0.0s
✔ Container toko-staging-web-1 Started 0.3sCara Kerja
Project Name: toko-staging
│
┌───────────────────────┼───────────────────────┐
▼ ▼ ▼
Nama Kontainer Nama Network Nama Volume
toko-staging-web-1 toko-staging_default toko-staging_db_dataHafalan:
Project Name → Awalan (prefix) penamaan seluruh kontainer, network, & volume
name: custom_name di YAML → Menetapkan nama proyek di dalam compose.yaml
docker compose -p name up -d → Menjalankan stack dengan namespace project terpisahBest Practice & Kesalahan Umum
- ✅ Tetapkan atribut
name: nama-proyekdi baris atascompose.yamlagar penamaan kontainer tetap konsisten meskipun nama folder proyek di-rename oleh developer lain. - ❌ Hati-hati jika menjalankan perintah
docker compose -p nama_a down, jangan sampai tertukar dengan projectnama_b.
9. 🟢 Deklarasi Service & Image (services: & image:)
Konsep
Blok utama di dalam compose.yaml adalah services:. Setiap item di bawah services: merepresentasikan satu komponen aplikasi atau satu kontainer yang akan dijalankan.
Kunci Properti Service:
image:: Menentukan nama Docker Image resmi dari registry (misal:image: postgres:16-alpine).container_name:(Opsional): Memberi nama kustom statis pada kontainer (jika tidak diisi, Docker Compose akan memberi nama otomatis<project>-<service>-1).command:(Opsional): Menimpa defaultCMDbawaan image (misal:command: ["npm", "run", "dev"]).
Contoh
# compose.yaml
services:
# Service Backend
api-service:
image: node:20-alpine
working_dir: /app
command: ["node", "server.js"]
# Service Database
database:
image: postgres:16-alpine
container_name: custom-postgres-db
environment:
POSTGRES_PASSWORD: supersecretpasswordOutput
docker compose up -d
docker compose psNAME IMAGE STATUS PORTS
custom-postgres-db postgres:16-alpine Up 2 seconds 5432/tcp
toko-api-service-1 node:20-alpine Up 2 seconds Cara Kerja
services:
api-service: ──► Tarik Image node:20-alpine ──► Nyalakan kontainer toko-api-service-1
database: ──► Tarik Image postgres:alpine ──► Nyalakan kontainer custom-postgres-dbHafalan:
services: → Blok penampung seluruh kontainer dalam aplikasi
image: <name>:<tag> → Menentukan image yang ditarik dari Docker Hub
container_name: <name> → Memberikan nama statis pada kontainer
command: ["cmd", "arg"] → Menimpa perintah default startup kontainerBest Practice & Kesalahan Umum
- ✅ Berikan nama service yang ringkas dan deskriptif (
web,api,db,cache) karena nama service ini otomatis menjadi Hostname DNS internal. - ❌ Hindari menggunakan
container_name:statis jika Anda berencana melakukan scaling kontainer menjadi banyak instance (--scale), karena nama kontainer akan bentrok.
10. 🟢 Port Mapping (ports:)
Konsep
Secara default, seluruh port antar service di dalam file Compose saling terhubung secara internal melalui private network. Namun port tersebut belum dapat diakses oleh browser dari komputer Host.
Blok ports: digunakan untuk memetakan (publishing / forwarding) port di komputer Host ke port di dalam kontainer.
Format Sintaks:
ports:
- "PortHost:PortContainer"- Selalu gunakan tanda kutip ganda (
"8080:80"). - Jika Anda hanya ingin mengekspos port ke localhost mesin lokal saja (keamanan), tulis:
"127.0.0.1:8080:80".
Contoh
# compose.yaml
services:
# Web Nginx dapat diakses di laptop via http://localhost:8080
web:
image: nginx:alpine
ports:
- "8080:80"
# Database MySQL dibuka ke port 3306 host untuk akses via DBeaver/TablePlus
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
ports:
- "127.0.0.1:3306:3306"Output
docker compose up -d[+] Running 2/2
✔ Container myapp-db-1 Started 0.4s
✔ Container myapp-web-1 Started 0.4sAkses di browser: http://localhost:8080 → Tampil halaman Nginx.
Cara Kerja
Browser di Laptop Host ──► Request ke localhost:8080
│
▼
Port Forwarding Compose ──► Diteruskan ke Port 80 di Container 'web'Hafalan:
ports:
- "HOST:CONTAINER" → Membuka akses dari laptop host ke dalam service kontainer
- "127.0.0.1:p1:p2" → Membatasi akses port hanya untuk mesin lokal (keamanan)Best Practice & Kesalahan Umum
- ✅ Hanya buka port yang benar-benar membutuhkan akses dari luar (misal web server
80/443). Jangan membuka port database ke internet publik di server produksi. - ❌ Jangan lupa membungkus pasangan port dengan tanda kutip (tulis
"8080:80", bukan8080:80).
11. 🟢 Environment Variables (environment: & env_file:)
Konsep
Untuk menyuntikkan konfigurasi dinamis dan kredensial ke dalam kontainer, Docker Compose menyediakan dua pendekatan:
- Atribut
environment:(Inline): Menuliskan variabel langsung di dalam filecompose.yaml. - Atribut
env_file:(File Konfigurasi Eksternal): Membaca variabel dari file konfigurasi rahasia (seperti.envatau.env.production).
Dua Format Penulisan environment::
- Format Array:
- KEY=VALUE - Format Map (Key-Value):
KEY: VALUE
Contoh
# compose.yaml
services:
app-service:
image: node:20-alpine
# 1. Membaca variabel dari file eksternal .env
env_file:
- .env
# 2. Menetapkan / menimpa variabel secara langsung
environment:
NODE_ENV: production
APP_PORT: 3000
DB_HOST: db-service
db-service:
image: postgres:16-alpine
environment:
POSTGRES_USER: admin_toko
POSTGRES_PASSWORD: password_rahasia_123
POSTGRES_DB: toko_dbFile .env Pendukung:
# .env (Dikecualikan dari Git via .gitignore)
JWT_SECRET=super_secret_jwt_key_2026
API_KEY=xyz987654321Output
Memeriksa environment variable di dalam kontainer yang sedang berjalan:
docker compose exec app-service env | grep -E "NODE_ENV|DB_HOST"NODE_ENV=production
DB_HOST=db-serviceCara Kerja
File .env (JWT_SECRET) + compose.yaml (NODE_ENV)
│
▼
Docker Compose menggabungkan seluruh variabel
│
▼
Disuntikkan ke lingkungan eksekusi Container saat bootingHafalan:
environment: → Mendefinisikan variabel lingkungan langsung di file compose
env_file: → Membaca variabel rahasia dari file eksternal (.env)Best Practice & Kesalahan Umum
- ✅ Pisahkan password dan API key rahasia ke dalam file
.envdan masukkan file.envke dalam.gitignore. - ❌ Jangan pernah meng-hardcode password produksi di dalam blok
environment:filecompose.yamlyang di-push ke repositori publik.
12. 🟡 Penyimpanan Persistent: Volumes (volumes:)
Konsep
Untuk menyimpan data yang bersifat permanen (Persistent Data) seperti file database atau file upload user agar tidak hilang saat kontainer dimatikan (docker compose down), kita menggunakan Named Volumes yang dikelola langsung oleh Docker Engine.
Dua Bagian Deklarasi Volume di Compose:
- Blok Level Service (
services.<name>.volumes): Menghubungkan named volume ke path direktori di dalam kontainer (<volume_name>:<container_path>). - Blok Top-Level (
volumes:di baris paling bawah): Mendeklarasikan volume tersebut secara resmi di level proyek.
Contoh
# compose.yaml
services:
database:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secretpassword
# 1. Pasang named volume 'pg_data' ke folder data postgres
volumes:
- pg_data:/var/lib/postgresql/data
# 2. Deklarasikan named volume di level paling bawah (Wajib!)
volumes:
pg_data:Output
Memeriksa volume yang otomatis dibuat dengan prefix nama proyek:
docker compose up -d
docker volume lsDRIVER VOLUME NAME
local myproject_pg_dataCara Kerja
Kontainer 'database' (/var/lib/postgresql/data)
│
▼ (Mount Tautan)
Named Volume Host: myproject_pg_data (Data Aman Selamanya)Hafalan:
services:
db:
volumes:
- named_vol:/path/in/container
volumes:
named_vol: → Wajib didaftarkan di root top-level volumes:Best Practice & Kesalahan Umum
- ✅ Selalu daftarkan nama volume di blok top-level
volumes:di akhir filecompose.yaml. - ❌ Jangan lupa bahwa menjalankan
docker compose down -vakan menghapus seluruh named volume proyek Anda beserta isinya.
13. 🟡 Bind Mounts untuk Development (volumes: host:container)
Konsep
Dalam lingkungan pengembangan (Local Development), developer ingin mengedit file source code di laptop (komputer Host) dan melihat perubahannya langsung terjadi secara instan di dalam kontainer tanpa perlu build ulang image (Hot-Reloading).
Kita menggunakan Bind Mounts pada sintaks volumes: dengan format:
volumes:
- "./path/di/host:/path/di/container"- Jalur host diawali dengan titik slash (
./) yang menandakan folder relatif dari lokasi filecompose.yaml. - Tidak perlu mendaftarkan folder bind mount di blok top-level
volumes:.
Contoh
# compose.yaml
services:
web-dev:
image: node:20-alpine
working_dir: /app
ports:
- "3000:3000"
# Menghubungkan folder ./src di laptop ke /app/src di kontainer
volumes:
- ./src:/app/src:ro # Read-Only (Aman)
- ./package.json:/app/package.json
command: ["npm", "run", "dev"]Output
docker compose up -dEdit file src/App.js di VS Code laptop Anda → Browser di http://localhost:3000 akan me-reload perubahan secara instan!
Cara Kerja
Folder Laptop Developer (./src)
┌─────────────────────────────┐
│ index.js │
└──────────────┬──────────────┘
│ Tautan Langsung (Bind Mount)
▼
Folder di dalam Kontainer (/app/src)
┌─────────────────────────────┐
│ index.js │
└─────────────────────────────┘Hafalan:
- ./local_folder:/container_folder → Bind mount relatif folder lokal ke kontainer (Hot-Reload)
:ro → Opsi Read-Only agar kontainer tidak mengubah file lokal hostBest Practice & Kesalahan Umum
- ✅ Gunakan Bind Mounts untuk lingkungan development lokal (hot reload).
- ❌ Jangan gunakan Bind Mounts untuk database di server produksi; selalu gunakan Named Volume resmi.
14. 🟡 Jaringan Antar Service: Networks (networks:)
Konsep
Secara default, Docker Compose secara otomatis membuat 1 jaringan Virtual Bridge bersama (<project>_default) dan menghubungkan seluruh service yang ada di dalam file ke jaringan tersebut.
Semua service di dalam file yang sama langsung dapat saling memanggil menggunakan NAMA SERVICE-nya sebagai Hostname DNS (misal: service web memanggil http://api:3000 atau backend memanggil database via db:5432).
Kustomisasi Multi-Network (Isolasi Bertingkat):
Kita bisa membuat beberapa jaringan terpisah untuk meningkatkan keamanan (misal: jaringan publik frontend-net dan jaringan privat backend-net).
Contoh
# compose.yaml
services:
# Web publik hanya terhubung ke frontend-net
web:
image: nginx:alpine
ports:
- "80:80"
networks:
- frontend-net
# API backend terhubung ke KEDUA jaringan (jembatan antara web dan db)
api:
image: node:20-alpine
networks:
- frontend-net
- backend-net
# Database terisolasi di backend-net (TIDAK BISA diakses langsung oleh web!)
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secret
networks:
- backend-net
# Deklarasi Networks Top-Level
networks:
frontend-net:
backend-net:Output
[+] Running 5/5
✔ Network myapp_frontend-net Created 0.0s
✔ Network myapp_backend-net Created 0.0s
✔ Container myapp-db-1 Started 0.3s
✔ Container myapp-api-1 Started 0.3s
✔ Container myapp-web-1 Started 0.3sCara Kerja
[web] ◄──(frontend-net)──► [api] ◄──(backend-net)──► [db]
▲ │
│ │
└────────── ISOLASI TOTAL: web TIDAK BISA ───────────┘
berkomunikasi langsung ke dbHafalan:
Automatic DNS → Service 'web' memanggil service 'db' cukup dengan nama hostname "db"
networks: → Membuat jaringan terisolasi untuk memisahkan service publik & database privatBest Practice & Kesalahan Umum
- ✅ Manfaatkan Embedded DNS bawaan Compose: gunakan nama service (
db,cache) sebagai konfigurasiDB_HOSTaplikasi Anda. - ❌ Jangan pernah menghubungkan kontainer menggunakan IP address yang di-hardcode.
15. 🟡 Dependensi Urutan Booting: Depends On (depends_on & service_healthy)
Konsep
Dalam aplikasi nyata, backend tidak boleh menyala sebelum database siap melayani koneksi. Jika backend menyala lebih cepat dari database, backend akan langsung crash (Database Connection Refused).
Atribut depends_on digunakan untuk mengatur urutan prioritas pembuatan dan penyalaan service.
2 Tingkatan depends_on:
- Level Sederhana (Hanya Urutan Start):
depends_on: [db]→ Hanya memastikan kontainerdbdinyalakan terlebih dahulu, TIDAK MENJAMIN database di dalamnya sudah siap menerima query. - Level Lanjutan (Menunggu Status Sehat / SANGAT DIREKOMENDASIKAN):
Menggunakan kombinasi
condition: service_healthybersamaan dengan blokhealthcheck:. Backend HANYA AKAN MENYALA setelah Database berstatus benar-benar Sehat (Healthy).
Contoh
# compose.yaml
services:
# 1. Service Database MySQL dengan Healthcheck Aktif
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret_password
MYSQL_DATABASE: toko_db
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-psecret_password"]
interval: 5s
timeout: 3s
retries: 5
# 2. Service Backend Menunggu Database Benar-benar Siap (Healthy)
backend:
image: node:20-alpine
depends_on:
db:
condition: service_healthy
environment:
DB_HOST: db
command: ["npm", "start"]Output
[+] Running 2/2
✔ Container myapp-db-1 Healthy 12.4s
✔ Container myapp-backend-1 Started 12.6s(Perhatikan: backend menunggu dengan sabar hingga db berstatus Healthy sebelum menyala!).
Cara Kerja
docker compose up
│
▼
Nyalakan Service 'db' (Status: starting)
│
▼ (MySQL inisialisasi database di background...)
Healthcheck Berhasil! (Status: healthy)
│
▼
Nyalakan Service 'backend' (Aman 100% dari Crash!)Hafalan:
depends_on:
service_name:
condition: service_healthy → Menunggu service dependensi berstatus Healthy sebelum startBest Practice & Kesalahan Umum
- ✅ Selalu gunakan pola
condition: service_healthyuntuk dependensi database agar backend tidak mengalami crash saat booting. - ❌ Jangan hanya menggunakan
depends_on: [db]sederhana jika aplikasi backend Anda tidak memiliki logika auto-reconnect retry bawaan.
16. 🟡 Restart Policy (restart: always, unless-stopped)
Konsep
Atribut restart: menentukan kebijakan Docker Engine saat kontainer mengalami crash (abnormal exit) atau saat mesin server host dinyalakan ulang (server reboot).
Pilihan Nilai:
no(Default): Jangan me-restart kontainer secara otomatis.always: Selalu me-restart kontainer dalam kondisi apa pun.on-failure: Me-restart kontainer hanya jika proses aplikasi di dalamnya crash (exit code non-nol).unless-stopped(Sangat Direkomendasikan): Selalu me-restart kontainer, KECUALI jika kontainer dihentikan secara sengaja melalui perintahdocker compose stop.
Contoh
# compose.yaml
services:
web:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
worker:
image: node:20-alpine
restart: on-failure
command: ["node", "worker.js"]Output
docker compose up -d
docker compose psNAME IMAGE STATUS PORTS
myapp-web-1 nginx:alpine Up 5 seconds 0.0.0.0:80->80/tcp
myapp-worker-1 node:20-alpine Up 5 seconds (Jika server host di-reboot, service web akan otomatis langsung menyala kembali!).
Cara Kerja
Server Host Reboot
│
▼
Docker Engine membaca konfigurasi compose: restart: unless-stopped
│
▼
Kontainer otomatis di-boot ulang ke memoriHafalan:
restart: unless-stopped → Kebijakan terbaik: otomatis menyala kembali kecuali dihentikan manual
restart: on-failure → Restart otomatis hanya jika aplikasi mengalami crashBest Practice & Kesalahan Umum
- ✅ Pasang
restart: unless-stoppedpada seluruh service backend dan database yang berjalan di server produksi. - ❌ Hindari menggunakan
restart: alwayspada script migrasi atau seeder yang tugasnya hanya berjalan satu kali (one-off tasks).
17. 🟡 Resource Limits (deploy.resources.limits)
Konsep
Untuk mencegah satu kontainer yang mengalami kebocoran memori (memory leak) atau lonjakan komputasi memonopoli seluruh sumber daya CPU dan RAM server, kita wajib membatasi kapasitas maksimum sumber daya menggunakan blok deploy.resources.limits.
Parameter Pembatasan:
cpus:: Batas alokasi core CPU (misal:'0.5'untuk 50% core CPU,'2.0'untuk 2 core penuh).memory:: Batas alokasi RAM maksimal (misal:512M,1G,2G).
Contoh
# compose.yaml
services:
api-service:
image: node:20-alpine
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.25'
memory: 128M
cache:
image: redis:alpine
deploy:
resources:
limits:
memory: 256MOutput
Memverifikasi batas memori via docker stats:
docker stats --no-streamCONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM %
1a2b3c4d5e6f myapp-api-service-1 0.12% 35.4MiB / 512MiB 6.91%
8a9b0c1d2e3f myapp-cache-1 0.04% 8.21MiB / 256MiB 3.21%Cara Kerja
Compose menyetel parameter cgroups ke Docker Daemon
│
▼
Kontainer dibatasi maksimal 512MB RAM & 1 Core CPUHafalan:
deploy:
resources:
limits:
cpus: '0.5' → Batas maksimal CPU 0.5 Core
memory: 512M → Batas maksimal RAM 512 MegabyteBest Practice & Kesalahan Umum
- ✅ Selalu tetapkan batas
limits.memorypada seluruh service di file compose staging dan produksi. - ❌ Jangan menyetel nilai batas memori terlalu kecil di bawah kapasitas minimal startup runtime aplikasi Anda.
18. 🟡 Custom Dockerfile Build (build: & dockerfile:)
Konsep
Selain menarik image jadi dari Docker Hub (image:), Docker Compose dapat mengompilasi dan membangun Dockerfile lokal milik kita sendiri secara otomatis menggunakan atribut build:.
Atribut Konfigurasi Build:
context:: Direktori root build context tempat file aplikasi berada (misal:./backendatau.).dockerfile:: Nama file Dockerfile jika menggunakan nama kustom (misal:Dockerfile.devatauDockerfile.prod).args:: Mengirimkan argumen build (build argumentsARG) ke dalam Dockerfile.image:(Opsional): Memberikan nama tag pada image yang dihasilkan dari proses build lokal tersebut.
Perintah Rebuild:
docker compose up -d --buildContoh
# compose.yaml
services:
# Membangun image kustom dari folder ./backend
backend-api:
build:
context: ./backend
dockerfile: Dockerfile
args:
NODE_ENV: development
image: my-company/backend-api:local
ports:
- "3000:3000"
# Database menggunakan image publik resmi
database:
image: postgres:16-alpineStruktur Folder:
project-root/
├── compose.yaml
└── backend/
├── Dockerfile
├── package.json
└── src/Output
docker compose up -d --build[+] Building 3.2s (10/10) FINISHED
=> => naming to docker.io/my-company/backend-api:local
[+] Running 2/2
✔ Container project-database-1 Started 0.3s
✔ Container project-backend-api-1 Started 0.3sCara Kerja
docker compose up -d --build
│
▼
Eksekusi build pada ./backend/Dockerfile
│
▼
Beri tag: my-company/backend-api:local
│
▼
Nyalakan kontainer dari image hasil build tersebut!Hafalan:
build:
context: ./path → Direktori tempat Dockerfile dan source code berada
dockerfile: file → Nama file Dockerfile (default: Dockerfile)
docker compose up --build → Memaksa kompilasi ulang image lokal saat menyalakan serviceBest Practice & Kesalahan Umum
- ✅ Selalu sertakan flag
--build(docker compose up -d --build) saat Anda baru saja mengubah isi kode program atau dependensi di Dockerfile lokal. - ❌ Jangan lupa membuat file
.dockerignoredi dalam folder context agar proses build lokal tetap cepat.
19. 🟡 Health Check (healthcheck:)
Konsep
Blok healthcheck: di dalam Docker Compose memungkinkan kita mendefinisikan pengujian kesehatan service secara periodik langsung dari file compose.yaml tanpa perlu mengubah isi file Dockerfile asli.
Parameter Konfigurasi:
test:: Perintah pengujian (misal:["CMD", "curl", "-f", "http://localhost:3000/health"]atau["CMD-SHELL", "pg_isready -U postgres"]).interval:: Jarak waktu antar pengujian (misal:10s).timeout:: Batas waktu respons perintah (misal:5s).retries:: Toleransi jumlah kegagalan (misal:3).start_period:: Waktu jeda inisialisasi awal saat booting (misal:15s).
Contoh
# compose.yaml
services:
web-service:
image: nginx:alpine
ports:
- "80:80"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://localhost/ || exit 1"]
interval: 10s
timeout: 3s
retries: 3
start_period: 5s
postgres-db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secret
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 5Output
Memeriksa status kesehatan seluruh service:
docker compose psNAME IMAGE STATUS PORTS
myapp-postgres-db-1 postgres:16-alpine Up 20 seconds (healthy) 5432/tcp
myapp-web-service-1 nginx:alpine Up 20 seconds (healthy) 0.0.0.0:80->80/tcpCara Kerja
Setiap 10 Detik: Eksekusi test di dalam kontainer
│
┌──────────────┴──────────────┐
[Exit Code 0] [Exit Code 1]
│ │
▼ ▼
Status: (healthy) Status: (unhealthy)Hafalan:
healthcheck:
test: ["CMD", "curl", "-f", "url"] → Perintah pengujian kesehatan kontainer
interval: 10s → Frekuensi pengujian berkalaBest Practice & Kesalahan Umum
- ✅ Pasang Healthcheck pada seluruh service kunci (Database, Redis, API) agar service lain yang bergantung via
depends_ondapat sinkron secara presisi. - ❌ Pastikan tool utilitas uji (seperti
wget,curl, ataupg_isready) tersedia di dalam image yang digunakan.
20. 🔴 Extend Service & Overrides (extends: & docker-compose.override.yml)
Konsep
Dalam proyek profesional, kita sering membutuhkan konfigurasi yang berbeda antara lingkungan Development dan Production (misal: di dev kita butuh bind mounts hot-reload dan debug port, sedangkan di prod kita butuh image build statis dan restart policy ketat).
Docker Compose menyediakan 2 mekanisme pewarisan konfigurasi:
- Pewarisan Otomatis File Override (
docker-compose.override.yml): Secara default, jika filedocker-compose.override.ymlada di folder proyek, Docker Compose akan secara otomatis menggabungkan (merge) isinya di atas filecompose.yamlutama. - Multiple Compose Files (
-f / --file): Menggabungkan beberapa file secara manual:docker compose -f compose.yaml -f compose.prod.yaml up -d - Instruksi
extends:: Mewarisi konfigurasi dari service lain yang ada di file yang sama atau file berbeda.
Contoh
File Konfigurasi Utama (compose.yaml):
# compose.yaml (Konfigurasi Dasar Bersama)
services:
app:
image: node:20-alpine
environment:
APP_NAME: "Toko App"File Konfigurasi Override Development (compose.override.yaml):
# compose.override.yaml (Khusus Development Lokal)
services:
app:
ports:
- "3000:3000"
volumes:
- ./src:/app/src
command: ["npm", "run", "dev"]File Konfigurasi Produksi (compose.prod.yaml):
# compose.prod.yaml (Khusus Server Produksi)
services:
app:
restart: unless-stopped
deploy:
resources:
limits:
memory: 1GEksekusi CLI di Server Produksi:
# Menggabungkan konfigurasi dasar + produksi (override dev otomatis diabaikan jika nama file eksplisit)
docker compose -f compose.yaml -f compose.prod.yaml up -dOutput
Memeriksa hasil penggabungan (Merged Config):
docker compose -f compose.yaml -f compose.prod.yaml configname: myapp
services:
app:
environment:
APP_NAME: Toko App
image: node:20-alpine
restart: unless-stoppedCara Kerja
compose.yaml (Base) + compose.prod.yaml (Production)
│ │
└────────────┬────────────┘
│ (Deep Merge)
▼
Merged Config Siap Dijalankan!Hafalan:
compose.override.yaml → Otomatis digabung saat 'docker compose up' (khusus dev)
docker compose -f f1 -f f2 → Menggabungkan beberapa file compose secara eksplisitBest Practice & Kesalahan Umum
- ✅ Pisahkan konfigurasi sensitif development ke dalam
compose.override.yamldan masukkan ke dalam.gitignore. - ❌ Jangan menaruh konfigurasi port development yang terbuka lebar di dalam file
compose.yamldasar.
21. 🔴 Compose File Interpolation & .env Variables (${VAR:-default})
Konsep
Docker Compose mendukung fitur Interpolasi Variabel (Variable Interpolation), yaitu menyuntikkan nilai dari file .env atau environment host langsung ke dalam teks file compose.yaml menggunakan sintaks ${VARIABLE_NAME}.
Format Sintaks Interpolasi:
${VAR}: Mengambil nilai variabelVAR.${VAR:-default_value}(Fallback Default): JikaVARbelum disetel atau kosong, gunakan nilaidefault_value.${VAR:?error_message}(Wajib Ada): JikaVARbelum disetel, hentikan proses build dan tampilkan pesan error.
Contoh
File compose.yaml:
# compose.yaml
services:
web:
# Menggunakan tag image dinamis (default: latest jika tidak diisi)
image: nginx:${NGINX_VERSION:-alpine}
# Menggunakan port dinamis (default: 8080)
ports:
- "${APP_PORT:-8080}:80"
environment:
# Wajib ada DB_PASSWORD, jika tidak ada proses berhenti dengan pesan error
DB_PASS: ${DB_PASSWORD:?Error: DB_PASSWORD wajib disetel di file .env!}File .env:
# .env
NGINX_VERSION=1.25-alpine
APP_PORT=9000
DB_PASSWORD=secret_database_password_2026Output
Memeriksa hasil interpolasi variabel via docker compose config:
docker compose configname: myapp
services:
web:
environment:
DB_PASS: secret_database_password_2026
image: nginx:1.25-alpine
ports:
- mode: ingress
target: 80
published: "9000"
protocol: tcpCara Kerja
File .env (APP_PORT=9000)
│
▼
compose.yaml: ports: ["${APP_PORT:-8080}:80"]
│
▼
Hasil Evaluasi Nyata: ports: ["9000:80"]Hafalan:
${VAR} → Mengambil nilai variabel dari .env
${VAR:-default} → Menggunakan nilai fallback 'default' jika variabel belum disetel
${VAR:?error_msg} → Menolak berjalan & menampilkan pesan error jika variabel kosongBest Practice & Kesalahan Umum
- ✅ Selalu sediakan nilai fallback default (
${PORT:-3000}) agar file compose tetap bisa berjalan normal meskipun developer baru lupa membuat file.env. - ❌ Jangan mengabaikan pesan error
${VAR:?error}pada variabel kredensial penting.
22. 🔴 Scaling Services (docker compose up —scale)
Konsep
Scaling Services adalah kemampuan Docker Compose untuk menduplikasi dan menjalankan banyak instance kontainer sekaligus dari satu definisi service yang sama (Horizontal Scaling) untuk mendistribusikan beban kerja (Load Balancing).
Format Sintaks CLI:
docker compose up -d --scale <service_name>=<number_of_instances>Syarat Penting Service yang Bisa Di-Scale:
- Service TIDAK BOLEH memiliki binding port host statis (misal
ports: - "80:80") karena port 80 di host akan bentrok. Gunakan port acak (misalports: - "80") atau letakkan di belakang Reverse Proxy (seperti Nginx / Traefik). - Service TIDAK BOLEH memiliki atribut
container_name:statis.
Contoh
# compose.yaml
services:
# Reverse Proxy Load Balancer Publik
nginx-lb:
image: nginx:alpine
ports:
- "80:80"
depends_on:
- worker
# Service Worker Backend yang Siap Di-Scale (Tanpa static port & container_name)
worker:
image: node:20-alpine
command: ["node", "-e", "console.log('Worker aktif ID:', process.env.HOSTNAME); setInterval(()=>{}, 1000)"]Menjalankan 3 Instance Worker Sekaligus:
# Menyalakan 3 kontainer worker bersamaan
docker compose up -d --scale worker=3Output
[+] Running 4/4
✔ Container myapp-worker-1 Started 0.3s
✔ Container myapp-worker-2 Started 0.3s
✔ Container myapp-worker-3 Started 0.3s
✔ Container myapp-nginx-lb-1 Started 0.4sMelihat daftar kontainer hasil scaling:
docker compose psNAME IMAGE STATUS PORTS
myapp-nginx-lb-1 nginx:alpine Up 5 seconds 0.0.0.0:80->80/tcp
myapp-worker-1 node:20-alpine Up 5 seconds
myapp-worker-2 node:20-alpine Up 5 seconds
myapp-worker-3 node:20-alpine Up 5 seconds Cara Kerja
Trafik Masuk (Port 80)
│
▼
[ Nginx Load Balancer ]
│
┌───────────────────────┼───────────────────────┐
▼ ▼ ▼
[ worker-1 ] [ worker-2 ] [ worker-3 ]
(Kontainer #1) (Kontainer #2) (Kontainer #3)Hafalan:
docker compose up -d --scale service=N → Menjalankan N instance kontainer dari satu service
Hindari Static Port & container_name → Syarat mutlak agar service bisa di-scale tanpa errorBest Practice & Kesalahan Umum
- ✅ Gunakan scaling untuk kontainer antrean tugas (background queue workers) atau microservices API tanpa status (stateless).
- ❌ Jangan mencoba men-scale database berstatus tunggal (single-instance stateful database) dengan
--scale db=3karena data storage akan bertabrakan.
23. 🛠️ Peta Ingatan Cepat
Mental Model Hubungan Entitas di Docker Compose
┌───────────────────────────────┐
│ compose.yaml Project │
└───────────────┬───────────────┘
│
┌─────────────────────────────┼─────────────────────────────┐
▼ ▼ ▼
Services (Kontainer) Networks (Jaringan) Volumes (Data)
- image / build - Default Virtual Bridge - Named Volumes (Persist)
- ports ("8080:80") - Custom Network DNS - Bind Mounts (./src)
- environment / env_file - Automatic Service Hostname - db_data:/var/lib/mysql
- depends_on (Healthcheck) - Isolated Backend Net - Top-Level Declaration
│ │ │
└─────────────────────────────┼─────────────────────────────┘
│
▼
Siklus Hidup & Eksekusi CLI
- docker compose up -d
- docker compose down -v
- docker compose exec <srv> sh
- docker compose logs -fPohon Keputusan Fitur Docker Compose
Kebutuhan Arsitektur Compose
│
┌──────────────────────────┴──────────────────────────┐
▼ ▼
Kontainer Butuh Tunggu DB? File Kode Butuh Edit Live?
│ │
▼ ▼
depends_on: Bind Mounts
condition: service_healthy volumes: - ./src:/app
│
▼
Kebutuhan Multi-Environment?
│
┌──────────────────────────┴──────────────────────────┐
▼ ▼
Ganti Variabel Saja? Ganti Struktur Service?
│ │
▼ ▼
Interpolasi: ${PORT:-8080} Multiple Compose Files
(via file .env) -f compose.yaml -f prod.yaml24. 📚 Tabel Ringkasan
| Perintah / Atribut | Kategori | Contoh Penggunaan | Penjelasan & Kegunaan |
|---|---|---|---|
docker compose up -d | CLI | docker compose up -d --build | Membangun & menyalakan seluruh service di background |
docker compose down | CLI | docker compose down -v | Mematikan & membersihkan seluruh kontainer, network, & volume |
docker compose ps | CLI | docker compose ps | Melihat status running & mapping port seluruh service |
docker compose logs | CLI | docker compose logs -f app | Memantau log keluaran service secara live real-time |
docker compose exec | CLI | docker compose exec app sh | Masuk ke terminal shell kontainer yang sedang berjalan |
services: | YAML | services: app: | Blok utama pendefinisian seluruh kontainer aplikasi |
image: | YAML | image: redis:alpine | Menentukan image resmi dari Docker Hub |
build: | YAML | build: ./backend | Mengompilasi image lokal dari Dockerfile |
ports: | YAML | ports: ["8080:80"] | Forwarding port host laptop ke port container |
environment: | YAML | environment: [NODE_ENV=prod] | Menyuntikkan variabel environment ke kontainer |
env_file: | YAML | env_file: [.env] | Membaca variabel dari file konfigurasi eksternal |
volumes: | YAML | volumes: [db_data:/data] | Memasang persistent named volume atau bind mount |
networks: | YAML | networks: [app-net] | Menghubungkan service ke virtual bridge network |
depends_on: | YAML | condition: service_healthy | Mengatur urutan booting menunggu service dependensi sehat |
restart: | YAML | restart: unless-stopped | Menyalakan kembali kontainer otomatis saat reboot |
healthcheck: | YAML | test: ["CMD", "curl", "-f"] | Mendefinisikan tes kesehatan internal service |
25. ⚡ Cheat Code Docker Compose 10 Detik
1. Template Stack Lengkap Web + Database + Volume
services:
web:
image: nginx:alpine
ports:
- "8080:80"
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-psecret"]
interval: 5s
timeout: 3s
retries: 5
volumes:
db_data:2. Perintah Penting Harian
docker compose up -d --build # Nyalakan & build ulang
docker compose logs -f --tail 50 # Pantau log 50 baris live
docker compose exec web sh # Masuk shell
docker compose down -v # Hapus bersih total26. 🧭 Urutan Belajar yang Disarankan
Untuk menguasai orkestrasi Docker Compose dari tingkat pemula hingga tingkat lanjut, ikuti 4 fase bertahap berikut:
FASE 1: Fondasi File Compose & CLI Dasar (Minggu 1)
┌─────────────────────────────────────────────────────────────┐
│ 1. Menguasai sintaks YAML (2 spasi) & nama file compose.yaml│
│ 2. Memahami blok services:, image:, dan ports: ["8080:80"] │
│ 3. Perintah siklus hidup: up -d, down, stop, start, ps │
│ 4. Pemantauan log gabungan: docker compose logs -f │
└──────────────────────────────┬──────────────────────────────┘
│
▼
FASE 2: Konfigurasi, Storage & Jaringan (Minggu 2)
┌─────────────────────────────────────────────────────────────┐
│ 5. Mengelola variabel: environment: dan file rahasia env_file│
│ 6. Bind mounts (./src:/app) untuk hot-reload development │
│ 7. Named Volume persisten untuk database + deklarasi root │
│ 8. Custom bridge networks & DNS hostname resolution │
└──────────────────────────────┬──────────────────────────────┘
│
▼
FASE 3: Keandalan & Sinkronisasi Booting (Minggu 3)
┌─────────────────────────────────────────────────────────────┐
│ 9. Mengonfigurasi healthcheck: pada database & cache │
│ 10. Mengatur dependensi ketat: depends_on + service_healthy │
│ 11. Memasang kebijakan restart: unless-stopped & limit RAM │
│ 12. Mengompilasi Dockerfile lokal via blok build: │
└──────────────────────────────┬──────────────────────────────┘
│
▼
FASE 4: Operasional Lanjutan & Mini Project (Minggu 4)
┌─────────────────────────────────────────────────────────────┐
│ 13. Interpolasi variabel: ${PORT:-8080} via file .env │
│ 14. Multiple compose files & compose.override.yaml │
│ 15. Scaling service stateless: docker compose up --scale │
│ 16. Mengerjakan Mini Project Stack Microservices Lengkap │
└─────────────────────────────────────────────────────────────┘27. 🏗️ Mini Project: Stack Microservices Lengkap (Nginx Proxy + Node.js API + Redis Cache + MySQL Database)
Konsep Project
Project ini membangun satu kesatuan sistem aplikasi web berskala enterprise (Production-Ready Microservices Architecture) menggunakan 4 service yang saling terintegrasi penuh di dalam satu file compose.yaml:
- Service
proxy(Nginx Reverse Proxy): Pintu gerbang publik (Port 80) yang meneruskan trafik HTTP ke backend API. - Service
api(Node.js REST API): Backend service yang terhubung ke database dan in-memory cache. - Service
cache(Redis): Menyimpan session dan query cache sementara. - Service
database(MySQL 8.0): Database utama persisten dengan named volume dan healthcheck ketat. - Fitur Keamanan & Keandalan:
depends_on: condition: service_healthymenjamin backend API hanya menyala saat database & Redis sudah 100% siap.- Dual Network:
public-netuntuk proxy daninternal-netuntuk database/cache. - Named Volume
db_datauntuk persistensi. - Variable Interpolation via file
.env.
File Konfigurasi: compose.yaml
name: ecommerce-microservices
services:
# 1. Reverse Proxy Publik
proxy:
image: nginx:alpine
ports:
- "${PUBLIC_PORT:-8080}:80"
depends_on:
api:
condition: service_started
networks:
- public-net
restart: unless-stopped
# 2. Backend REST API
api:
image: node:20-alpine
working_dir: /app
environment:
NODE_ENV: production
PORT: 3000
DB_HOST: database
DB_NAME: ${DB_NAME:-toko_db}
DB_USER: ${DB_USER:-app_user}
DB_PASS: ${DB_PASSWORD:-password_aman}
REDIS_HOST: cache
depends_on:
database:
condition: service_healthy
cache:
condition: service_healthy
networks:
- public-net
- internal-net
restart: unless-stopped
command: ["node", "-e", "console.log('Backend API Sukses Terhubung ke Database & Cache!'); setInterval(()=>{}, 1000)"]
# 3. Redis In-Memory Cache
cache:
image: redis:alpine
networks:
- internal-net
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
# 4. Database MySQL Persisten
database:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-supersecretroot}
MYSQL_DATABASE: ${DB_NAME:-toko_db}
MYSQL_USER: ${DB_USER:-app_user}
MYSQL_PASSWORD: ${DB_PASSWORD:-password_aman}
volumes:
- mysql_storage:/var/lib/mysql
networks:
- internal-net
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${DB_ROOT_PASSWORD:-supersecretroot}"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
# Jaringan Terisolasi
networks:
public-net:
internal-net:
# Volume Persisten
volumes:
mysql_storage:File Pendukung: .env
PUBLIC_PORT=80
DB_NAME=toko_online_db
DB_USER=toko_user
DB_PASSWORD=PasswordRahasia2026
DB_ROOT_PASSWORD=SuperSecretRootPassword2026Langkah Eksekusi CLI
# 1. Menyalakan seluruh stack sistem multi-kontainer
docker compose up -d
# 2. Memeriksa status kesehatan seluruh service
docker compose psOutput
[+] Running 7/7
✔ Network ecommerce-microservices_public-net Created 0.0s
✔ Network ecommerce-microservices_internal-net Created 0.0s
✔ Volume ecommerce-microservices_mysql_storage Created 0.0s
✔ Container ecommerce-microservices-cache-1 Healthy 6.2s
✔ Container ecommerce-microservices-database-1 Healthy 14.5s
✔ Container ecommerce-microservices-api-1 Started 14.7s
✔ Container ecommerce-microservices-proxy-1 Started 15.1s
NAME IMAGE STATUS PORTS
ecommerce-microservices-api-1 node:20-alpine Up 2 seconds
ecommerce-microservices-cache-1 redis:alpine Up 15 seconds (healthy) 6379/tcp
ecommerce-microservices-database-1 mysql:8.0 Up 15 seconds (healthy) 3306/tcp
ecommerce-microservices-proxy-1 nginx:alpine Up 1 second 0.0.0.0:80->80/tcpCara Kerja
Browser User (Port 80)
│
▼ (public-net)
[ proxy: Nginx Reverse Proxy ]
│
▼ (public-net)
[ api: Node.js Backend ]
│
┌────────┴────────────────────────┐
│ │
▼ (internal-net) ▼ (internal-net)
[ cache: Redis ] [ database: MySQL 8.0 ]
│
▼
[ Volume: mysql_storage ]Hafalan:
Enterprise Microservices Pattern = Dual Networks (Public/Internal) + Healthcheck Sync + Named Volumes + .env28. 🔗 Referensi Resmi
Untuk mempelajari dokumentasi resmi, spesifikasi teknis, dan praktik terbaik Docker Compose:
- Docker Official Documentation — Docker Compose
- Compose Specification (Official Standard Spec)
- Compose File Reference (YAML Attributes & Syntax)
- Docker Compose CLI Command Reference
- Sample Apps with Docker Compose (GitHub Official Samples)
Catatan Versi: Cheatsheet ini disusun mengacu pada spesifikasi Compose Specification / Compose V2 (Docker Engine v26+). Seluruh sintaks perintah CLI yang dibahas menggunakan format standar resmi
docker compose(dengan spasi).