Tutorial Docker Compose: Cara Menjalankan Multi-Container Aplikasi

Apa Itu Docker Compose dan Mengapa Anda Membutuhkannya?
Ketika aplikasi Anda tumbuh melampaui satu container, mengelola container satu per satu dengan perintah docker run menjadi tidak praktis. Bayangkan aplikasi web modern yang terdiri dari: container Node.js untuk backend, container React untuk frontend, container MySQL untuk database, container Redis untuk caching, dan container Nginx sebagai reverse proxy - menjalankan dan mengatur semua container ini secara manual setiap kali sangat melelahkan dan rawan kesalahan.
Docker Compose adalah tool yang memungkinkan Anda mendefinisikan dan menjalankan seluruh stack aplikasi multi-container menggunakan satu file konfigurasi YAML bernama docker-compose.yml. Dengan satu perintah docker compose up, seluruh stack langsung berjalan - lengkap dengan network, volume, environment variable, dan dependency antar service yang sudah dikonfigurasi. Tutorial Docker Compose ini mencakup semua yang Anda butuhkan untuk mulai produktif.
Prasyarat: Docker sudah terinstal di sistem Anda (VPS atau lokal). Docker Compose Plugin sudah termasuk dalam instalasi Docker Engine modern dan dipanggil dengan docker compose (tanpa tanda hubung). Panduan ini menggunakan sintaks Compose v2 yang merupakan standar saat ini.
Struktur File docker-compose.yml
File docker-compose.yml menggunakan format YAML dan memiliki beberapa blok utama:

version: "3.9" # Versi spec Compose (opsional di Compose v2+)
services: # Daftar container/service yang akan dijalankan
nama-service:
image: nama-image:tag # Gunakan image siap pakai, ATAU
build: ./path/ke/dir # Build dari Dockerfile
ports:
- "host:container"
environment:
- NAMA_VAR=nilai
volumes:
- nama-volume:/path/di/container
depends_on:
- service-lain
networks:
- nama-network
restart: unless-stopped
volumes: # Definisi named volumes
nama-volume:
networks: # Definisi custom networks
nama-network:
driver: bridge
Indentasi sangat penting di YAML - gunakan spasi (bukan tab) secara konsisten. Dua spasi per level indentasi adalah konvensi yang paling umum digunakan.
Contoh 1: Stack Laravel + MySQL + Redis
Mari mulai dengan contoh praktis yang relevan bagi developer Indonesia: stack Laravel dengan MySQL dan Redis:
# Buat direktori proyek
mkdir ~/laravel-stack && cd ~/laravel-stack
# Buat struktur direktori
mkdir -p src nginx/conf.d
Buat file docker-compose.yml:
cat > docker-compose.yml << 'EOF'
version: "3.9"
services:
# Nginx sebagai reverse proxy dan web server
nginx:
image: nginx:1.25-alpine
container_name: laravel-nginx
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./src:/var/www/html
- ./nginx/conf.d:/etc/nginx/conf.d
depends_on:
- app
networks:
- laravel-net
# PHP-FPM untuk Laravel
app:
build:
context: .
dockerfile: Dockerfile.app
container_name: laravel-app
restart: unless-stopped
working_dir: /var/www/html
volumes:
- ./src:/var/www/html
environment:
- APP_ENV=production
- APP_KEY=${APP_KEY}
- DB_CONNECTION=mysql
- DB_HOST=mysql
- DB_PORT=3306
- DB_DATABASE=${DB_DATABASE}
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
- REDIS_HOST=redis
- REDIS_PORT=6379
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- laravel-net
# MySQL database
mysql:
image: mysql:8.0
container_name: laravel-mysql
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
networks:
- laravel-net
# Redis untuk caching dan session
redis:
image: redis:7-alpine
container_name: laravel-redis
restart: unless-stopped
volumes:
- redis-data:/data
networks:
- laravel-net
volumes:
mysql-data:
redis-data:
networks:
laravel-net:
driver: bridge
EOF
Buat file .env untuk menyimpan nilai yang sensitif:
cat > .env << 'EOF'
APP_KEY=base64:ganti-dengan-key-laravel-anda
DB_DATABASE=laravel_db
DB_USERNAME=laravel_user
DB_PASSWORD=UserPass789Kuat
DB_ROOT_PASSWORD=RootPass123Kuat
EOF
Contoh 2: Stack Node.js + MongoDB + Nginx
Contoh kedua untuk developer yang menggunakan stack JavaScript modern dengan MongoDB:
cat > docker-compose.yml << 'EOF'
version: "3.9"
services:
nginx:
image: nginx:1.25-alpine
container_name: node-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- api
networks:
- app-net
api:
build: ./api
container_name: node-api
restart: unless-stopped
environment:
- NODE_ENV=production
- PORT=3000
- MONGO_URI=mongodb://mongo:27017/appdb
- JWT_SECRET=${JWT_SECRET}
depends_on:
- mongo
networks:
- app-net
# Tidak expose port ke host - hanya diakses via Nginx
expose:
- "3000"
mongo:
image: mongo:7.0
container_name: node-mongo
restart: unless-stopped
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
MONGO_INITDB_DATABASE: appdb
volumes:
- mongo-data:/data/db
networks:
- app-net
volumes:
mongo-data:
networks:
app-net:
driver: bridge
EOF
Perintah Docker Compose yang Paling Sering Digunakan
Berikut referensi lengkap perintah Docker Compose untuk operasional sehari-hari. Semua perintah dijalankan dari direktori yang berisi file docker-compose.yml:
# Menjalankan seluruh stack (download image, build, dan start)
docker compose up
# Menjalankan stack di background (detached mode)
docker compose up -d
# Membangun ulang image sebelum menjalankan (setelah perubahan kode)
docker compose up -d --build
# Menghentikan semua container dalam stack
docker compose down
# Menghentikan dan menghapus volumes (HATI-HATI: menghapus data!)
docker compose down -v
# Melihat status semua service dalam stack
docker compose ps
# Melihat log semua service
docker compose logs
# Melihat log service tertentu dan ikuti output real-time
docker compose logs -f app
# Restart service tertentu
docker compose restart app
# Menghentikan service tertentu
docker compose stop mysql
# Memulai kembali service yang berhenti
docker compose start mysql
# Menjalankan perintah di dalam container service yang berjalan
docker compose exec app bash
docker compose exec app php artisan migrate
# Menjalankan perintah di container baru (tidak perlu service sedang running)
docker compose run --rm app php artisan key:generate
# Melihat resource usage semua container dalam stack
docker compose top
# Melihat konfigurasi yang sudah di-resolve (berguna untuk debug)
docker compose config
# Scale service tertentu ke beberapa instance
docker compose up -d --scale api=3
Menggunakan Environment Variables dengan File .env
Docker Compose secara otomatis membaca file .env di direktori yang sama dan menggunakan nilainya untuk substitusi variabel dalam docker-compose.yml. Ini adalah cara terbaik mengelola konfigurasi yang berbeda antara development dan production:
# .env untuk development
cat > .env.development << 'EOF'
APP_ENV=local
DB_DATABASE=myapp_dev
DB_USERNAME=dev_user
DB_PASSWORD=dev_password_local
DEBUG=true
EOF
# .env untuk production
cat > .env.production << 'EOF'
APP_ENV=production
DB_DATABASE=myapp_prod
DB_USERNAME=prod_user
DB_PASSWORD=PasswordSangatKuatProduction!
DEBUG=false
EOF
# Gunakan file .env tertentu
docker compose --env-file .env.production up -d
Jangan pernah commit file .env yang berisi nilai production ke version control (Git). Tambahkan .env dan .env.* ke .gitignore. Untuk CI/CD, inject environment variables melalui platform secrets (GitHub Actions secrets, GitLab CI variables, dll).

Healthcheck dan Dependency Ordering
Salah satu masalah umum dengan Docker Compose adalah service yang bergantung pada service lain (misalnya app yang membutuhkan database) kadang mencoba connect sebelum database siap menerima koneksi. Solusinya adalah menggunakan healthcheck dan depends_on dengan kondisi:
services:
mysql:
image: mysql:8.0
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 10s # Cek setiap 10 detik
timeout: 5s # Timeout jika tidak ada respons dalam 5 detik
retries: 5 # Coba maksimal 5 kali sebelum dianggap unhealthy
start_period: 30s # Beri waktu 30 detik untuk startup awal
app:
depends_on:
mysql:
condition: service_healthy # Tunggu hingga mysql healthcheck pass
redis:
condition: service_started # Cukup tunggu hingga redis container started
Docker Compose untuk Development vs Production
Praktik terbaik adalah memisahkan konfigurasi Compose untuk development dan production menggunakan multiple Compose files:
# docker-compose.yml - konfigurasi base (shared)
# docker-compose.override.yml - override untuk development (dibaca otomatis)
# docker-compose.prod.yml - override untuk production
Buat docker-compose.override.yml untuk development:
cat > docker-compose.override.yml << 'EOF'
version: "3.9"
services:
app:
build:
target: development # Gunakan stage development di multi-stage Dockerfile
volumes:
- ./src:/var/www/html # Hot-reload: mount kode langsung dari host
environment:
- APP_ENV=local
- APP_DEBUG=true
# Tambah phpMyAdmin hanya untuk development
phpmyadmin:
image: phpmyadmin:latest
ports:
- "8080:80"
environment:
PMA_HOST: mysql
networks:
- laravel-net
EOF
Buat docker-compose.prod.yml untuk production:
cat > docker-compose.prod.yml << 'EOF'
version: "3.9"
services:
app:
build:
target: production # Gunakan stage production (image lebih kecil, lebih aman)
deploy:
resources:
limits:
memory: 512M
cpus: "1.0"
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
EOF
# Jalankan dengan konfigurasi production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Mengelola Secrets dengan Docker Compose
Untuk informasi sensitif seperti API key dan database password di production, hindari menyimpan nilai langsung di docker-compose.yml atau environment variable yang mudah dibaca. Gunakan Docker Secrets (tersedia di Docker Swarm) atau approach berbasis file:
# Simpan secret dalam file (di luar version control)
echo "PasswordSuperRahasia" > secrets/db_password.txt
chmod 600 secrets/db_password.txt
# Referensikan di docker-compose.yml
services:
mysql:
image: mysql:8.0
secrets:
- db_password
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_password
secrets:
db_password:
file: ./secrets/db_password.txt
Backup dan Restore Database dengan Docker Compose
Mengelola backup database di environment Docker Compose:
# Backup database MySQL dari container yang berjalan
docker compose exec mysql mysqldump -u root -p${DB_ROOT_PASSWORD} --all-databases | gzip > backup_$(date +%Y%m%d_%H%M%S).sql.gz
# Restore database dari backup
gunzip < backup_20260609_020000.sql.gz | docker compose exec -T mysql mysql -u root -p${DB_ROOT_PASSWORD}
# Backup volume langsung (lebih universal)
docker run --rm -v laravel-stack_mysql-data:/data -v $(pwd):/backup alpine tar czf /backup/mysql-volume-backup.tar.gz /data
FAQ: Pertanyaan Umum Docker Compose
Apa perbedaan docker-compose (v1) dan docker compose (v2)?
Docker Compose v1 adalah tool terpisah yang diinstal sebagai binary docker-compose (dengan tanda hubung), ditulis dalam Python. Docker Compose v2 adalah reimplementasi dalam Go yang terintegrasi langsung sebagai plugin Docker CLI, dipanggil dengan docker compose (tanpa tanda hubung). Compose v2 jauh lebih cepat, mendukung semua fitur terbaru, dan merupakan standar yang direkomendasikan saat ini. Compose v1 sudah tidak lagi dikembangkan.
Berapa banyak service yang bisa didefinisikan dalam satu docker-compose.yml?
Tidak ada batasan teknis untuk jumlah service dalam satu file Compose. Namun dari sisi praktikalitas, jika stack Anda memiliki lebih dari 10–15 service, pertimbangkan memecahnya menjadi beberapa stack Compose terpisah, atau beralih ke orchestrator yang lebih powerful seperti Kubernetes. Untuk kebanyakan aplikasi web di VPS, 3–7 service sudah mencukupi.
Bagaimana cara menjalankan perintah migrasi database secara otomatis saat stack dimulai?
Ada dua pendekatan umum: (1) Tambahkan perintah migrasi di entrypoint script container app Anda - jalankan migrasi sebelum menjalankan server. (2) Gunakan service sementara (one-shot service) di Compose dengan docker compose run --rm app php artisan migrate setelah stack berjalan. Pendekatan entrypoint script lebih otomatis, sedangkan one-shot service memberi kontrol lebih manual.
Apakah Docker Compose cocok untuk production?
Docker Compose sangat cocok untuk production pada skala single-server (satu VPS). Untuk VPS tunggal dengan traffic sedang, Compose memberikan keseimbangan sempurna antara kemudahan manajemen dan fungsionalitas. Batasan utama Compose adalah tidak mendukung distribusi container ke beberapa server secara native. Jika aplikasi Anda membutuhkan horizontal scaling ke beberapa server, pertimbangkan Docker Swarm (sederhana) atau Kubernetes (lengkap tapi kompleks).
Bagaimana cara update service tertentu tanpa menghentikan service lain?
Gunakan perintah docker compose up -d --build --no-deps nama-service. Flag --no-deps mencegah Compose me-restart service yang bergantung pada service yang diupdate. Contoh: docker compose up -d --build --no-deps app akan rebuild dan restart hanya service app tanpa mengganggu MySQL dan Redis yang sedang berjalan.
Kenapa container app saya selalu gagal connect ke database meskipun sudah pakai depends_on?
depends_on tanpa kondisi hanya menunggu container database dimulai, bukan menunggu database siap menerima koneksi. Database seperti MySQL dan PostgreSQL membutuhkan beberapa detik hingga siap setelah container running. Solusi: tambahkan healthcheck pada service database dan gunakan depends_on: condition: service_healthy pada service yang bergantung, seperti yang dicontohkan di bagian Healthcheck di atas.
Bagaimana cara melihat log dari semua service sekaligus di Docker Compose?
Gunakan docker compose logs -f --tail=100 untuk melihat 100 baris log terakhir dari semua service dan terus mengikuti output baru secara real-time. Untuk log service tertentu: docker compose logs -f --tail=50 app. Untuk menyimpan log ke file: docker compose logs --no-color > stack-logs.txt.
Kesimpulan: Docker Compose sebagai Fondasi Deployment Modern
Dengan memahami tutorial Docker Compose ini, Anda kini bisa mendefinisikan, menjalankan, dan mengelola aplikasi multi-container dengan cara yang terstruktur, reproducible, dan mudah di-maintain. File docker-compose.yml menjadi "dokumentasi hidup" dari arsitektur aplikasi Anda yang bisa di-commit ke Git dan digunakan oleh seluruh anggota tim.
Untuk menjalankan Docker Compose stack di VPS production, pastikan server Anda memiliki spesifikasi yang memadai. VPS HostingEkspres tersedia dengan berbagai pilihan RAM dan CPU yang cocok untuk berbagai ukuran stack - mulai dari proyek personal hingga aplikasi bisnis. Langkah selanjutnya: pelajari cara deploy Docker container ke VPS production dengan strategi zero-downtime dan CI/CD otomatis.
Artikel Terkait
Cara Setup Docker di VPS: Panduan Containerization untuk Developer Indonesia
Panduan lengkap cara setup Docker di VPS Linux untuk developer Indonesia: instalasi Docker Engine, konfigurasi keamanan, menjalankan container pertama, manajemen image, hingga praktik terbaik containerization di production.
Baca Selengkapnya →Cara Deploy Docker Container ke VPS dan Cloud Hosting Indonesia
Panduan lengkap cara deploy Docker container ke VPS dan cloud hosting Indonesia: push image ke registry, strategi zero-downtime deployment, CI/CD pipeline, reverse proxy Nginx, SSL otomatis, hingga monitoring production.
Baca Selengkapnya →Cara Setup VPS Linux dari Nol: Panduan Lengkap untuk Pemula
Panduan lengkap cara setup VPS Linux dari nol untuk pemula: dari akses SSH pertama, konfigurasi keamanan dasar, instalasi web server Nginx, PHP, MySQL, hingga deploy website WordPress. Step-by-step dengan perintah lengkap.
Baca Selengkapnya →Butuh Hosting untuk Website Anda?
Dapatkan hosting cepat, aman, dan terpercaya dengan harga terjangkau. Gratis domain, SSL, dan support 24/7.
Jangan Ketinggalan Promo!
Subscribe newsletter kami dan dapatkan diskon hingga 50% untuk pembelian pertama kamu.
Gratis, tanpa spam. Bisa unsubscribe kapan saja.