Deploy Aplikasi dengan Docker Compose Production

Docker Compose adalah tool untuk menjalankan aplikasi multi-container Docker dengan satu perintah. Dalam production, Docker Compose memungkinkan Anda mendefinisikan seluruh arsitektur aplikasi dalam satu file YAML dan menjalankannya dengan mudah. Artikel ini membahas cara deploy aplikasi multi-container di environment production.

Pengertian Docker Compose

Docker Compose memungkinkan Anda mendefinisikan beberapa container, jaringan, dan volume dalam satu file docker-compose.yml. Alih-alih menjalankan perintah Docker untuk setiap container, Anda cukup satu perintah docker-compose up -d untuk menjalankan semuanya.

Kapan Menggunakan Docker Compose?

  • Aplikasi web + database + cache
  • Microservices architecture
  • Lingkungan staging dan production
  • Development dan testing

Arsitektur Umum Production

Contoh Arsitektur Website

kode
┌─────────────────┐
│     Nginx        │  (Reverse Proxy / Load Balancer)
├─────────────────┤
│   Aplikasi       │  (Node.js / Python / PHP)
│   Web App        │
├─────────────────┤
│   Database       │  (PostgreSQL / MySQL / MariaDB)
├─────────────────┤
│   Cache          │  (Redis)
├─────────────────┤
│   Storage        │  (Volume untuk file/upload)
└─────────────────┘

Alat yang Dibutuhkan

  • Server Debian 13 dengan Docker dan Docker Compose
  • Akses SSH sebagai root atau sudo
  • Aplikasi web siap dikontainerisasi
  • Domain (opsional)

Instalasi Docker dan Docker Compose

1. Instal Docker

bash
curl -fsSL https://get.docker.com | bash
systemctl enable docker
systemctl start docker

2. Instal Docker Compose

bash
apt install docker-compose-plugin -y
# Atau versi standalone
curl -SL https://github.com/docker/compose/releases/download/v2.27.0/docker-compose-linux-amd64 -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

3. Verifikasi

bash
docker --version
docker compose version

Membuat File Docker Compose

Struktur Project

bash
/opt/myapp/
├── docker-compose.yml
├── app/
│   ├── Dockerfile
│   ├── package.json
│   └── src/
├── nginx/
│   └── nginx.conf
├── db/
│   └── init.sql
└── data/          # Volume data

Contoh 1: Aplikasi Node.js + PostgreSQL + Redis

yaml
version: '3.8'

services:
  # Aplikasi Web
  app:
    build: ./app
    container_name: web-app
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://user:password@db:5432/mydb
      - REDIS_URL=redis://redis:6379
    depends_on:
      - db
      - redis
    restart: always
    volumes:
      - ./app:/app
      - /app/node_modules  # Volume untuk dependencies

  # Database PostgreSQL
  db:
    image: postgres:16-alpine
    container_name: database
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 30s
      timeout: 10s
      retries: 5

  # Redis Cache
  redis:
    image: redis:7-alpine
    container_name: cache
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    restart: always
    command: redis-server --appendonly yes --requirepass YourRedisPassword123!
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 30s
      timeout: 10s
      retries: 5

  # Nginx Reverse Proxy
  nginx:
    image: nginx:alpine
    container_name: reverse-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
    depends_on:
      - app
    restart: always

# Volume untuk persistensi data
volumes:
  postgres_data:
  redis_data:

Contoh 2: WordPress + MySQL + Nginx

yaml
version: '3.8'

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
    depends_on:
      - wordpress
    restart: always

  wordpress:
    image: wordpress:php8.2-nginx
    container_name: wordpress
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: securepassword123!
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wordpress_data:/var/www/html
      - ./wp-config.php:/var/www/html/wp-config.php:ro
    depends_on:
      - db
    restart: always

  db:
    image: mysql:8.0
    container_name: mysql_db
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword123!
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: securepassword123!
    volumes:
      - mysql_data:/var/lib/mysql
    restart: always
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 30s
      timeout: 10s
      retries: 5

volumes:
  wordpress_data:
  mysql_data:

Menjalankan Docker Compose

1. Deploy Semua Layanan

bash
cd /opt/myapp
docker compose up -d

2. Lihat Status

bash
docker compose ps
docker compose logs -f app

3. Hentikan Semua

bash
docker compose down

4. Hentikan dan Hapus Volume

bash
docker compose down -v

5. Restart Layanan Spesifik

bash
docker compose restart app
docker compose restart db redis

6. Scale Layanan (Load Balancing)

bash
# Jalankan 3 instance aplikasi
docker compose up -d --scale app=3

# Cek status
docker compose ps

Volume dan Persistensi

Jenis Volume

yaml
volumes:
  # Named volume — dikelola Docker
  db_data:
    driver: local
  
  # Bind mount — folder host
  - ./app:/app
  
  # Anonymous volume
  - /data

Backup Volume

bash
# Backup named volume
docker run --rm -v postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/db-backup.tar.gz -C /data .

# Restore volume
docker run --rm -v postgres_data:/data -v $(pwd):/backup alpine tar xzf /backup/db-backup.tar.gz -C /data

Network Configuration

Membuat Network Kustom

yaml
networks:
  backend:
    driver: bridge
  frontend:
    driver: bridge

services:
  app:
    networks:
      - backend
  nginx:
    networks:
      - frontend
      - backend
  db:
    networks:
      - backend

Health Checks dan Monitoring

Health Check di Docker Compose

yaml
services:
  app:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Monitoring dengan Prometheus dan cAdvisor

Tambahkan ke docker-compose.yml:

yaml
  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    container_name: cadvisor
    ports:
      - "8080:8080"
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    restart: always

Scaling Production

1. Multi-Container dengan Swarm

bash
# Inisialisasi swarm
docker swarm init

# Deploy stack
docker stack deploy -c docker-compose.yml myapp

# Scale service
docker service scale myapp_app=5

2. Load Balancing Otomatis

yaml
services:
  app:
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure

Security Production

1. Non-Root Container

yaml
services:
  app:
    security_opt:
      - no-new-privileges:true
    read_only: true
    tmpfs:
      - /tmp

2. Resource Limits

yaml
services:
  app:
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M

3. Environment Variables dari File

yaml
services:
  app:
    env_file:
      - .env.production

Buat .env.production:

env
DATABASE_URL=postgresql://user:password@db:5432/mydb
SECRET_KEY=your-secret-key
NODE_ENV=production

CI/CD Integration

GitHub Actions untuk Auto Deploy

Buat .github/workflows/deploy.yml:

yaml
name: Deploy Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Server
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_IP }}
          username: ${{ secrets.SSH_USER }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /opt/myapp
            docker compose pull
            docker compose up -d
            docker image prune -f

Troubleshooting

1. Container Tidak Bisa Start

Penyebab: Konfigurasi salah atau port conflict. Solusi:

bash
# Cek log
docker compose logs app

# Cek apakah port sudah digunakan
ss -tlnp | grep 3000

# Fix dan restart
docker compose up -d --build

2. Database Tidak Terhubung

Penyebab: Service belum siap atau credential salah. Solusi:

bash
# Cek status database
docker compose ps db
# Cek log
docker compose logs db

# Pastikan depends_on benar

3. Data Hilang Setelah Restart

Penyebab: Volume tidak dikonfigurasi. Solusi:

bash
# Cek volume
docker volume ls
# Pastikan volume ada di compose file

4. Aplikasi Lambat

Penyebab: Resource limit terlalu rendah atau database belum dioptimasi. Solusi:

bash
# Cek resource usage
docker stats
# Naikkan resource limit di compose file

5. Network Error

Penyebab: Network tidak dikonfigurasi atau service di network salah. Solusi:

bash
# Cek network
docker network ls
docker network inspect myapp_backend
# Pastikan service di network yang benar

Kesimpulan

Docker Compose menyederhanakan deploy aplikasi multi-container dalam satu file konfigurasi. Dengan volume untuk persistensi, health checks untuk ketersediaan, dan resource limits untuk keamanan, aplikasi Anda akan berjalan stabil di production. Otomatisasi dengan CI/CD membuat proses deployment menjadi lebih efisien dan minim kesalahan.

Kunci utama:

  • Gunakan volume untuk semua data yang perlu persisten
  • Atur health check agar layanan yang mati otomatis restart
  • Batasi resource untuk mencegah satu service membebani server
  • Backup volume secara rutin
  • Gunakan .env file untuk mengelola secret dan konfigurasi
  • Otomatiskan deployment dengan CI/CD
Catatan penting: Jangan pernah menjalankan container sebagai root di production. Gunakan security_opt dan read_only untuk meminimalkan risiko keamanan. Selalu backup volume data sebelum melakukan update compose file. Jangan lupa hapus image Docker yang tidak terpakai secara berkala agar disk server tidak penuh.
Ingat: Docker Compose cocok untuk aplikasi skala kecil-menengah. Untuk aplikasi berskala besar dengan banyak layanan, pertimbangkan Docker Swarm atau Kubernetes. Docker Compose adalah fondasi yang baik untuk memahami containerisasi sebelum beralih ke orkestrasi yang lebih kompleks.
Dipublikasikan untuk membantu para pengembang dan administrator server dalam mendeploy aplikasi container secara profesional di production.

Artikel Terkait