Pertama kali saya coba deploy aplikasi web yang butuh PHP, Nginx, dan MySQL, saya langsung pusing. Install satu-satu di VPS, konfigurasi manual, belum lagi kalau mau pindah server. Proses yang makan waktu berjam-jam itu akhirnya selesai dalam hitungan menit setelah kenal Docker Compose.
Docker Compose itu tools buat define dan jalanin multiple container sekaligus pakai satu file YAML. Bayangin kamu punya aplikasi yang butuh web server, database, dan cache -- semuanya bisa di-setup dalam satu command: docker compose up. Nggak perlu install manual, nggak perlu pusing dependency conflict.
Tutorial ini bakal nge-cover cara pakai Docker Compose dari nol, sampai kamu bisa deploy aplikasi web production-ready. Cocok buat developer yang mau simplifikasi workflow deployment.
Docker Compose adalah tool yang memungkinkan kamu menjalankan beberapa container Docker sekaligus menggunakan konfigurasi yang didefinisikan dalam satu file docker-compose.yml. Tanpa Compose, kamu harus jalankan perintah docker run berulang kali untuk setiap service, dan harus atur networking antar container secara manual.
Keunggulan utama Docker Compose:
docker compose up -d langsung jalanin semua servicedocker-compose.yml bisa di-commit ke git, jadi perubahan infrastruktur ter-trackdocker compose down berhentikan dan hapus semua container sekaligusBuat yang belum familiar dengan Docker sama sekali, cek dulu tulisan saya tentang troubleshooting Nginx 502/504 -- di situ ada penjelasan soal containerization yang relate sama topik ini.
Sebelum mulai, pastikan Docker sudah terinstall. Di Ubuntu 24.04, prosesnya cukup straightforward:
# Update package index
sudo apt update
# Install dependencies
sudo apt install -y ca-certificates curl gnupg
# Add Docker GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add Docker repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker Engine + Compose plugin
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Verifikasi instalasi:
# Cek versi Docker
docker --version
# Docker version 27.x.x, build xxxxxxxx
# Cek versi Compose
docker compose version
# Docker Compose version v2.x.x
Supaya nggak perlu sudo setiap kali jalankan Docker, tambahkan user kamu ke group docker:
sudo usermod -aG docker $USER
# Logout dan login ulang supaya efektif
File docker-compose.yml adalah jantung dari Docker Compose. Di sini kamu define semua service, network, dan volume yang dibutuhkan aplikasi. Berikut struktur dasarnya:
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./app:/var/www/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
networks:
- app-network
php:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./app:/var/www/html
networks:
- app-network
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: myapp
MYSQL_USER: appuser
MYSQL_PASSWORD: apppass
volumes:
- db-data:/var/lib/mysql
networks:
- app-network
redis:
image: redis:7-alpine
networks:
- app-network
volumes:
db-data:
networks:
app-network:
driver: bridge
Penjelasan komponen-komponen di atas:
host:container)Mari kita bikin setup yang realistis. Misalnya kamu punya aplikasi PHP (bisa CodeIgniter, Laravel, atau plain PHP) yang butuh Nginx dan MySQL.
Struktur project:
myproject/
docker-compose.yml
Dockerfile
nginx/
default.conf
app/
index.php
.env
Dockerfile untuk PHP-FPM:
FROM php:8.3-fpm-alpine
# Install ekstensi PHP yang dibutuhkan
RUN docker-php-ext-install pdo pdo_mysql mysqli opcache
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www/html
# Install dependencies kalau ada composer.json
# RUN composer install --no-dev --optimize-autoloader
Konfigurasi Nginx (nginx/default.conf):
server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
Kalau kamu pakai CodeIgniter 4, konfigurasi Nginx di atas sudah benar -- root-nya ke /public. Buat yang butuh setup Nginx lebih lengkap termasuk SSL dan load balancing, baca tulisan tentang Nginx Reverse Proxy setup.
docker-compose.yml final:
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./app:/var/www/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
restart: unless-stopped
networks:
- app-network
php:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./app:/var/www/html
restart: unless-stopped
networks:
- app-network
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: myapp
MYSQL_USER: appuser
MYSQL_PASSWORD: apppass
ports:
- "3306:3306"
volumes:
- db-data:/var/lib/mysql
restart: unless-stopped
networks:
- app-network
redis:
image: redis:7-alpine
restart: unless-stopped
networks:
- app-network
volumes:
db-data:
networks:
app-network:
driver: bridge
Setelah file docker-compose.yml siap, kamu bisa mulai jalankan semua service:
# Jalankan semua container (background mode)
docker compose up -d
# Lihat status container
docker compose ps
# Lihat log semua container (real-time)
docker compose logs -f
# Lihat log satu container tertentu
docker compose logs -f web
# Masuk ke dalam container (shell)
docker compose exec php sh
# Jalankan artisan/migration di container PHP
docker compose exec php php artisan migrate
# Stop semua container
docker compose down
# Stop + hapus volume (database terhapus!)
docker compose down -v
# Rebuild image setelah ubah Dockerfile
docker compose up -d --build
Jangan pernah hardcode password atau API key langsung di docker-compose.yml. Gunakan file .env yang terpisah:
# .env file (jangan di-commit ke git!)
MYSQL_ROOT_PASSWORD=supersecretrootpass
MYSQL_DATABASE=myapp
MYSQL_USER=appuser
MYSQL_PASSWORD=strongpassword123
REDIS_PASSWORD=redispass
Lalu di docker-compose.yml, referensikan pakai variabel:
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
Tambahkan .env ke .gitignore supaya nggak ke-commit. Untuk production, gunakan Docker secrets atau environment variable dari server.
Salah satu kesalahan pemula yang paling sering: database hilang setelah docker compose down. Ini terjadi kalau kamu nggak define volume. Named volume akan persist data meski container dihapus:
volumes:
db-data:
driver: local
redis-data:
driver: local
Untuk development, kamu juga bisa bind mount folder lokal supaya perubahan file langsung ter-refleksi di container:
services:
php:
volumes:
- ./app:/var/www/html # Bind mount (sync realtime)
- vendor-data:/var/www/html/vendor # Named volume (persist)
Kalau kamu pakai macOS atau Windows, bind mount bisa lambat karena Docker harus sync file system. Pakai volume untuk folder vendor atau node_modules yang berisi banyak file kecil.
Container di network yang sama bisa saling komunikasi pakai nama service sebagai hostname. Misalnya dari container PHP, kamu bisa koneksi ke MySQL pakai:
// Di dalam container PHP
$pdo = new PDO('mysql:host=db;port=3306;dbname=myapp', 'apppuser', 'apppass');
// 'db' = nama service di docker-compose.yml
Nggak perlu pakai IP address atau localhost. Docker Compose otomatis bikin DNS internal yang resolve nama service ke IP container.
Seringkali kamu butuh konfigurasi berbeda untuk development dan production. Docker Compose profiles bisa handle ini:
services:
php:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./app:/var/www/html
profiles:
- dev
php-prod:
build:
context: .
dockerfile: Dockerfile.prod
profiles:
- prod
adminer:
image: adminer
ports:
- "8080:8080"
profiles:
- dev
Jalankan untuk development:
docker compose --profile dev up -d
Container yang nggak punya profiles akan selalu dijalankan (seperti db, redis). Container dengan profiles hanya jalan kalau profile-nya diaktifkan.
Untuk production, tambahkan health check supaya Docker tahu kapan container benar-benar siap menerima request:
services:
db:
image: mysql:8.0
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped
web:
image: nginx:alpine
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
Dengan restart: unless-stopped, container otomatis restart kalau crash. Tapi container tetap stop kalau kamu jalankan docker compose down secara manual.
Gunakan depends_on dengan kondisi health check supaya Nginx nggak start sebelum MySQL benar-benar ready:
services:
web:
depends_on:
db:
condition: service_healthy
php:
condition: service_started
Beberapa hal yang sering dilupakan saat deploy Docker Compose ke production:
services:
php:
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
services:
web:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
services:
web:
read_only: true
tmpfs:
- /tmp
Beberapa masalah yang sering muncul dan solusinya:
Port sudah dipakai:
# Cari proses yang pakai port 80
sudo lsof -i :80
# Kill prosesnya atau ganti port mapping di compose file
Container gagal start:
# Cek log error
docker compose logs nama-service
# Cek apakah image berhasil di-build
docker compose build --no-cache
Database connection refused:
# Pastikan MySQL sudah selesai startup
docker compose exec db mysqladmin ping -h localhost -u root -p
# Cek apakah container ada di network yang sama
docker network ls
docker network inspect nama-project_app-network
Kalau kamu sering kena masalah server saat deploy, cek juga tulisan tentang debug Nginx 502/504 yang sering muncul kalau PHP-FPM belum ready saat Nginx sudah menerima request.
Docker Compose mengubah cara kita deploy aplikasi web. Dari yang dulunya butuh berjam-jam setup manual, sekarang cukup satu file YAML dan satu command. Untuk developer yang kerja dengan stack PHP + Nginx + MySQL, Docker Compose adalah game changer yang bikin workflow deployment jauh lebih predictable dan reproducible.
Mulai dari setup sederhana di development, lalu tambahkan health check, resource limits, dan log rotation saat mau deploy ke production. Jangan lupa pakai .env file untuk rahasia dan commit docker-compose.yml ke version control.
Kamu udah coba Docker Compose di project sendiri? Atau masih lebih suka install manual di VPS? Share pengalaman kamu di kolom komentar!