Pernah nggak sih kamu baru join project baru, tapi butuh waktu seharian cuma buat setup environment? Install MySQL, Redis, PHP, Nginx satu-satu. Belum lagi kalau versinya bentrok sama project lain. Saya pernah mengalami ini dan rasanya frustrasi banget. Semua masalah itu selesai ketika saya kenal Docker Compose.
Docker Compose itu tool yang memungkinkan kamu mendefinisikan dan menjalankan multiple container Docker sekaligus, cukup dengan satu file YAML. Bayangkan kamu punya satu file yang bisa langsung spin up MySQL, Redis, PHP-FPM, Nginx, dan bahkan phpMyAdmin dalam hitungan detik. Tanpa install apapun di host machine. Tanpa konflik versi. Tanpa drama.
Sebelum kenal Docker Compose, setup development environment itu proses yang menyebalkan. Kamu harus install semua dependency di machine lokal, pastikan versinya cocok, dan kalau ada update, kadang semuanya jadi broken. Dengan Docker Compose, semua environment didefinisikan dalam satu file. Mau ganti dari PHP 8.1 ke PHP 8.3? Tinggal ubah satu baris. Mau tambah Elasticsearch? Tambah beberapa baris config. Selesai.
Keunggulan utama Docker Compose untuk development lokal:
docker compose up -d dan semua service langsung berjalan. New developer bisa mulai coding dalam 5 menitSebelum mulai, pastikan Docker sudah terinstall. Di Linux (Ubuntu/Debian), jalankan perintah berikut:
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Tambahkan user ke docker group (tanpa sudo)
sudo usermod -aG docker $USER
# Logout dan login ulang, lalu verify
docker --version
docker compose version
Untuk macOS dan Windows, tinggal download Docker Desktop dari docker.com. Docker Compose sudah included di dalamnya, jadi tidak perlu install terpisah.
Verify instalasi berhasil:
docker --version
# Docker version 27.x.x
docker compose version
# Docker Compose version v2.x.x
File docker-compose.yml (atau compose.yaml di versi baru) adalah jantung dari Docker Compose. Di dalam file ini kamu mendefinisikan semua service, network, dan volume yang dibutuhkan project. Mari kita bedah strukturnya:
services:
# Nama service (bebas, ini jadi hostname di internal network)
app:
image: php:8.3-fpm # Docker image yang digunakan
volumes:
- ./:/var/www/html # Mount folder project ke container
networks:
- app-network # Network yang diikuti
nginx:
image: nginx:alpine
ports:
- "8080:80" # Port mapping host:container
volumes:
- ./:/var/www/html
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app # Pastikan app berjalan dulu
networks:
- app-network
networks:
app-network:
driver: bridge
Setiap service yang didefinisikan akan punya hostname sesuai nama servicenya. Jadi kalau service app berjalan di port 9000, service lain bisa mengaksesnya via app:9000. Ini sangat powerful karena kamu nggak perlu pusing soal IP address internal.
Sekarang kita bikin setup yang real-world. Sebuah environment lengkap untuk development aplikasi web PHP dengan database MySQL, caching Redis, dan web server Nginx. Ini setup yang paling banyak dipakai di project-project Indonesian web development:
services:
# PHP-FPM Application Server
app:
build:
context: .
dockerfile: Dockerfile
container_name: myapp-php
volumes:
- ./:/var/www/html
- ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
networks:
- myapp-network
restart: unless-stopped
# Nginx Web Server
nginx:
image: nginx:alpine
container_name: myapp-nginx
ports:
- "8080:80"
volumes:
- ./:/var/www/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
networks:
- myapp-network
restart: unless-stopped
# MySQL Database
database:
image: mysql:8.0
container_name: myapp-mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: rootsecret123
MYSQL_DATABASE: myapp_db
MYSQL_USER: myapp_user
MYSQL_PASSWORD: myapp_pass123
volumes:
- mysql-data:/var/lib/mysql
- ./database/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- myapp-network
restart: unless-stopped
# Redis Cache
redis:
image: redis:7-alpine
container_name: myapp-redis
ports:
- "6379:6379"
command: redis-server --requirepass redissecret123
volumes:
- redis-data:/data
networks:
- myapp-network
restart: unless-stopped
# phpMyAdmin (opsional, untuk debugging)
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: myapp-pma
ports:
- "8081:80"
environment:
PMA_HOST: database
PMA_USER: myapp_user
PMA_PASSWORD: myapp_pass123
depends_on:
- database
networks:
- myapp-network
restart: unless-stopped
volumes:
mysql-data:
redis-data:
networks:
myapp-network:
driver: bridge
Perhatikan beberapa hal penting di config di atas:
mysql-data dan redis-data memastikan data tidak hilang saat container di-restart. Tanpa volume ini, semua data hilang setiap kali docker compose downImage php:8.3-fpm itu basic. Kamu hampir selalu butuh menambahkan extension seperti PDO, Redis, GD, dll. Buat file Dockerfile di root project:
FROM php:8.3-fpm
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libonig-dev \
libxml2-dev \
libzip-dev \
zip \
unzip \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip \
&& pecl install redis \
&& docker-php-ext-enable redis \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www/html
# Set proper permissions
RUN chown -R www-data:www-data /var/www/html
EXPOSE 9000
CMD ["php-fpm"]
Dockerfile ini melakukan beberapa hal sekaligus: install system library yang dibutuhkan, compile PHP extension, pasang Composer, dan set permissions yang benar. Semua terjadi di build time, jadi container yang dihasilkan sudah siap pakai.
Buat folder nginx/ dan file 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_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
}
Perhatikan fastcgi_pass app:9000 ini merujuk ke service app yang kita definisikan di compose file. Docker network memungkinkan komunikasi antar container via nama service. Nggak perlu tahu IP addressnya.
Sekarang saatnya menjalankan semuanya. Pastikan semua file sudah tersimpan di folder project:
# Build dan start semua container
docker compose up -d --build
# Lihat status container
docker compose ps
# Lihat log semua service
docker compose logs -f
# Lihat log satu service saja
docker compose logs -f app
# Masuk ke container PHP
docker compose exec app bash
# Jalankan artisan/migration (Laravel)
docker compose exec app php artisan migrate
# Jalankan composer install di dalam container
docker compose exec app composer install
# Stop semua container
docker compose down
# Stop DAN hapus semua data (hati-hati!)
docker compose down -v
Setelah semua container berjalan, buka browser dan akses http://localhost:8080. Kalau pakai Laravel atau framework lain yang punya public/ folder, app langsung bisa diakses. phpMyAdmin tersedia di http://localhost:8081.
Salah satu keunggulan Docker Compose untuk development adalah volume mounting. Ketika kamu mount folder project ke container dengan:
volumes:
- ./:/var/www/html
Setiap perubahan file di host machine langsung ter-reflect di container. Edit file di VS Code, save, refresh browser perubahan langsung terlihat. Nggak perlu rebuild container setiap kali edit code. Ini yang bikin workflow development dengan Docker Compose terasa seamless.
Kadang kamu nggak butuh semua service sekaligus. Misalnya, saat development biasa kamu butuh PHP + MySQL + Redis. Tapi saat debugging database, kamu butuh phpMyAdmin juga. Docker Compose profiles solusinya:
services:
app:
# ... config biasa
database:
# ... config biasa
redis:
# ... config biasa
phpmyadmin:
image: phpmyadmin/phpmyadmin
profiles:
- debug
# ... config lainnya
mailhog:
image: mailhog/mailhog
profiles:
- debug
ports:
- "1025:1025"
- "8025:8025"
# Jalankan service biasa saja (tanpa debug tools)
docker compose up -d
# Jalankan semua termasuk debug tools
docker compose --profile debug up -d
Ini sangat berguna saat kamu punya service yang hanya dibutuhkan sesekali. MailHog untuk testing email, Selenium untuk testing browser, atau Elasticsearch untuk full-text search. Semua bisa diaktifkan sesuai kebutuhan tanpa mengubah file.
Jangan hardcode password dan secret di dalam docker-compose.yml. Gunakan file .env di folder project:
# .env file
DB_ROOT_PASSWORD=supersecretroot
DB_NAME=myapp_db
DB_USER=myapp_user
DB_PASSWORD=myapppassword
REDIS_PASSWORD=redispassword123
APP_PORT=8080
PMA_PORT=8081
Lalu referensikan di compose file:
services:
database:
image: mysql:8.0
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
nginx:
ports:
- "${APP_PORT}:80"
Penting: Tambahkan .env ke .gitignore. Jangan pernah commit secrets ke repository. Buat file .env.example dengan nilai placeholder sebagai dokumentasi untuk developer lain.
Setelah pakai Docker Compose di belasan project, ini beberapa tips yang saya pelajari:
./data:/var/lib/mysql) sering bermasalah dengan permission. Named volume (mysql-data:/var/lib/mysql) lebih reliablemysql:latest karena bisa berubah sewaktu-waktu. Pakai mysql:8.0 atau bahkan mysql:8.0.36 untuk konsistensi.dockerignore untuk exclude node_modules, vendor, dan .git dari build context. Ini mempercepat build secara signifikandocker compose exec database mysqldump -u root -p dbname > backup.sql sebelum melakukan perubahan besarBeberapa masalah yang sering muncul dan solusinya:
"3307:3306" di hostuser: "${UID}:${GID}" atau set ownership di Dockerfiledocker compose logs nama_service. Biasanya error di config atau missing dependencydocker network inspect nama_networkDocker Compose mengubah cara saya bekerja sebagai developer. Dari yang dulunya butuh waktu berjam-jam setup environment, sekarang cukup satu perintah. Semua service berjalan dengan versi yang tepat, terisolasi dari system lokal, dan bisa di-share ke seluruh tim via git. Kalau kamu belum pakai Docker Compose untuk development lokal, sekarang waktu yang tepat untuk mulai. File docker-compose.yml di atas bisa langsung kamu copy dan sesuaikan dengan kebutuhan projectmu. Selamat mencoba!