Basic Docker Compose
Apa itu Docker Compose?
Docker Compose adalah tool untuk mendefinisikan dan menjalankan
aplikasi multi-container dengan satu file
konfigurasi YAML. Dengan satu perintah
docker compose up, semua service, network, dan volume
yang dibutuhkan akan dibuat dan dijalankan.
Instalasi Docker Compose
Docker Compose Plugin (v2 - Versi Modern)
Di Docker versi terbaru, Compose sudah jadi plugin bawaan:
# Cek apakah compose sudah terinstall
docker compose version
Jika belum:
# Install plugin
sudo apt update
sudo apt install docker-compose-plugin
Legacy docker-compose (v1)
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
tipGunakan
docker compose(v2) yang lebih baru. Jika butuh v1, gunakandocker-compose. Keduanya support filedocker-compose.ymlyang sama.
Anatomi docker-compose.yml
version: '3.8' # Versi format file (3.x untuk semua fitur modern)
services: # Daftar container/service
web: # Nama service (bisa diakses via hostname ini)
image: nginx:alpine # Image yang digunakan
container_name: web-nginx # Nama container (opsional)
ports:
- "80:80" # host_port:container_port
volumes:
- ./html:/usr/share/nginx/html:ro # Mount folder
environment:
- NGINX_HOST=example.com
networks:
- frontend
depends_on:
- api
restart: unless-stopped
volumes: # Named volumes untuk persistent data
db_data:
networks: # Custom networks
frontend:
backend:
internal: true # Internal = tidak bisa diakses dari luar
Template 1: MariaDB/MySQL + phpMyAdmin
version: '3.8'
services:
db:
image: mariadb:latest
container_name: mariadb-server
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: rootpassword123
MYSQL_DATABASE: app_db
MYSQL_USER: app_user
MYSQL_PASSWORD: app_password
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
- ./init:/docker-entrypoint-initdb.d # Auto-import SQL saat pertama
networks:
- internal
phpmyadmin:
image: phpmyadmin:latest
container_name: phpmyadmin-ui
restart: unless-stopped
ports:
- "8080:80"
environment:
PMA_HOST: db # Hostname = nama service
PMA_PORT: 3306
UPLOAD_LIMIT: 100M
depends_on:
- db
networks:
- internal
volumes:
db_data:
networks:
internal:
Jalankan:
docker compose up -d
Akses phpMyAdmin di http://vuln.cybersecurity.or.id - login dengan root / rootpassword123.
tipUntuk MySQL sebagai pengganti MariaDB, cukup ganti
image: mariadb:latestdenganimage: mysql:8.0.
Template 2: Nginx + PHP-FPM
version: '3.8'
services:
nginx:
image: nginx:alpine
container_name: web-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./html:/var/www/html # File PHP/HTML
- ./nginx/conf.d:/etc/nginx/conf.d # Konfigurasi Nginx custom
- ./nginx/ssl:/etc/nginx/ssl # SSL certificates
depends_on:
- php
networks:
- app
php:
image: php:8.2-fpm-alpine
container_name: web-php
restart: unless-stopped
volumes:
- ./html:/var/www/html
environment:
- PHP_MEMORY_LIMIT=256M
- PHP_MAX_EXECUTION_TIME=60
networks:
- app
networks:
app:
Contoh nginx/conf.d/default.conf:
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass php:9000; # Hostname service PHP-FPM
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Template 3: Redis + Aplikasi Python
version: '3.8'
services:
redis:
image: redis:7-alpine
container_name: redis-cache
restart: unless-stopped
command: redis-server --requirepass redispass123 --appendonly yes
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- backend
app:
build:
context: ./app
dockerfile: Dockerfile
container_name: python-app
restart: unless-stopped
ports:
- "5000:5000"
environment:
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: redispass123
depends_on:
- redis
volumes:
- ./app:/app
networks:
- backend
volumes:
redis_data:
networks:
backend:
Template 4: CTFd (Platform CTF)
version: '3.8'
services:
ctfd:
image: ctfd/ctfd:latest
container_name: ctfd-platform
restart: unless-stopped
ports:
- "8000:8000"
environment:
- DATABASE_URL=mysql+pymysql://ctfd:ctfdpassword@db/ctfd
- REDIS_URL=redis://:redispass@cache:6379
- SECRET_KEY=your-secret-key-here
- WORKERS=4
- LOG_FOLDER=/var/log/CTFd
volumes:
- ctfd_data:/var/log/CTFd
- ctfd_uploads:/var/uploads
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
networks:
- ctfd
db:
image: mariadb:10.11
container_name: ctfd-db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_USER: ctfd
MYSQL_PASSWORD: ctfdpassword
MYSQL_DATABASE: ctfd
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
networks:
- ctfd
cache:
image: redis:7-alpine
container_name: ctfd-cache
restart: unless-stopped
command: redis-server --requirepass redispass
volumes:
- cache_data:/data
networks:
- ctfd
volumes:
ctfd_data:
ctfd_uploads:
db_data:
cache_data:
networks:
ctfd:
tipTemplate CTFd ini siap pakai untuk event CTF. Tinggal ganti
SECRET_KEYdengan key random:python3 -c "import secrets; print(secrets.token_hex(16))"
Perintah Penting Docker Compose
| Perintah | Deskripsi |
|---|---|
docker compose up -d |
Jalankan semua service di background |
docker compose down |
Hentikan dan hapus semua container, network |
docker compose down -v |
Down + hapus semua volume (⚠️ data hilang) |
docker compose ps |
Lihat status semua service |
docker compose logs -f |
Streaming log semua service |
docker compose logs -f web |
Log service spesifik (contoh: web) |
docker compose exec web sh |
Masuk ke container yang sedang berjalan |
docker compose exec db mysql -u root -p
|
Eksekusi command di dalam container |
docker compose build |
Build ulang image (untuk service dengan
build:) |
docker compose build --no-cache |
Build tanpa cache |
docker compose pull |
Pull image terbaru dari registry |
docker compose restart |
Restart semua service |
docker compose stop |
Stop tanpa hapus container |
docker compose start |
Start container yang sudah di-stop |
docker compose config |
Validasi dan lihat konfigurasi final |
docker compose top |
Lihat proses yang berjalan di setiap service |
Environment Variables (.env)
Buat file .env di folder yang sama dengan
docker-compose.yml:
# .env
DB_ROOT_PASSWORD=supersecret
DB_NAME=app_db
APP_PORT=8080
NGINX_PORT=80
Lalu gunakan di docker-compose.yml:
services:
db:
image: mariadb:latest
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_NAME}
app:
image: myapp:latest
ports:
- "${APP_PORT}:5000"
peringatanJangan commit file
.envke Git! Tambahkan ke.gitignore. Gunakan.env.examplesebagai template.
Volumes & Persistent Data
Named Volumes (direkomendasikan)
volumes:
db_data:
services:
db:
volumes:
- db_data:/var/lib/mysql
Data disimpan di /var/lib/docker/volumes/ - aman,
terkelola Docker.
Bind Mounts
services:
web:
volumes:
- ./html:/usr/share/nginx/html # Folder lokal : folder container
- ./config/nginx.conf:/etc/nginx/nginx.conf:ro # File spesifik (read-only)
Cocok untuk development - perubahan langsung terlihat tanpa rebuild.
Volume Permission Issues
# Solusi: set user ID di container
services:
php:
image: php:8.2-fpm
user: "${UID:-1000}:${GID:-1000}"
volumes:
- ./html:/var/www/html
Networks: Internal vs External
Internal Network
networks:
backend:
internal: true # Hanya bisa diakses antar service, tidak dari host
External Network (gabung dengan stack lain)
networks:
webnet:
external: true # Network sudah ada di luar compose
services:
web:
networks:
- webnet
Buat external network:
docker network create webnet
Multi-Network Setup
services:
web:
networks:
- frontend # Bisa diakses dari luar
- backend # Internal, komunikasi dengan DB
db:
networks:
- backend # Hanya backend, DB tidak terekspos
Troubleshooting
| Masalah | Solusi |
|---|---|
port is already allocated |
Port sudah dipakai. Ganti port host di
ports: atau hentikan service lain:
sudo lsof -i :80 |
Cannot start service: permission denied
|
Volume mount permission. Tambahkan
user:"1000:1000" di service |
service "db" didn't start
|
Cek log: docker compose logs db. Mungkin
port conflict atau env salah |
Volume data hilang setelah down -v |
Jangan gunakan -v di down jika
ingin data tetap ada |
Container restart loop |
Cek log: docker compose logs --tail=50.
Biasanya karena config error |
Environment variable tidak terbaca |
Pastikan .env ada di folder yang sama, atau
pakai
docker compose --env-file .env.prod up |
docker compose: command not found |
Install docker compose plugin:
sudo apt install docker-compose-plugin |
Kesimpulan
Docker Compose adalah wajib untuk development dan deployment multi-service. Dengan satu file YAML, kamu bisa mendefinisikan database, backend, frontend, cache, dan lainnya yang saling terhubung.
Workflow standar:
# 1. Buat docker-compose.yml
# 2. Setup .env untuk konfigurasi
# 3. Jalankan
docker compose up -d
# 4. Cek status
docker compose ps
# 5. Lihat log jika ada error
docker compose logs -f
# 6. Masuk ke container untuk debugging
docker compose exec web sh
# 7. Hentikan
docker compose down
Dengan template-template di atas, kamu bisa langsung deploy aplikasi apapun - dari website sederhana sampai platform CTF penuh!