Docker Compose untuk Pemula: dari Nol Sampai Jalan - BagasUnix
Skip to content Skip to sidebar Skip to footer

Docker Compose untuk Pemula: dari Nol Sampai Jalan

Daftar Isi
  1. Apa Itu Docker Compose? (dan Kenapa Kamu Butuh Ini)
  2. Docker Compose vs docker run Manual
  3. Compose V2 vs V1 — Pakai yang Mana?
  4. Prasyarat
  5. Install Docker Engine
  6. Verifikasi Compose V2
  7. Anatomi File docker-compose.yml
  8. Networks (Kapan Perlu, Kapan Tidak)
  9. depends_on (Urutan Startup)
  10. Hands-on #1: Static Website dengan Nginx
  11. Hands-on #2: App + Database (Node.js + PostgreSQL)
  12. Hands-on #3: Full Stack (Frontend + Backend + DB + Adminer)
  13. Perintah Docker Compose yang Wajib Dihapal
  14. Error Umum & Cara Mengatasinya
  15. "port is already allocated"
  16. "no such service: xxx"
  17. Volume permission denied
  18. Container exit code 137 (OOM Killed)
  19. Docker Compose vs Dockerfile — Bedanya Apa?
  20. Tips & Best Practices
  21. Langkah Selanjutnya

Docker Compose untuk Pemula: dari Nol Sampai Jalan

Oke sobat, jadi kamu udah berhasil install Docker — selamat. Tapi coba bayangin: kamu punya app yang butuh database PostgreSQL, Redis buat caching, plus Nginx di depannya. Jalanin docker run satu-satu? Dengan flag -p, -v, --network... tiga container aja udah bikin terminal kamu penuh command sepanjang rel kereta.

Nah, Docker Compose hadir buat ngatasi persis masalah itu. Satu file YAML, satu command, semua container jalan bareng. Dan di tutorial ini, kamu bakal langsung praktek — bukan cuma teori.

Yang kita bahas:
- Apa itu Docker Compose (dan bedanya sama Dockerfile)
- Setup dari nol (Compose V2, 2026-ready)
- 3 hands-on project: dari simpel sampai full stack
- Troubleshooting error yang pasti kamu temuin

Siap? Langsung gas.

Apa Itu Docker Compose? (dan Kenapa Kamu Butuh Ini)

Kalau Docker itu kayak masak satu menu, Docker Compose itu buku resep lengkap buat satu meja makan. Kamu definisiin semua "hidangan" (container) di satu file — siapa butuh apa, siapa jalan duluan, siapa ngomong sama siapa — terus tinggal docker compose up. Done.

Secara teknis: Docker Compose adalah tool buat define dan run multi-container Docker applications. Kamu tulis konfigurasi di file docker-compose.yml, dan Compose yang handle sisanya — networking, volume, urutan startup.

Docker Compose vs docker run Manual

Aspek docker run manual Docker Compose
Setup Ketik command per container 1 file YAML
Reproducible Harus ingat/catat semua flags File = dokumentasi
Networking Bikin network manual, connect manual Auto-created, semua service bisa saling reach
Start/Stop docker stop satu-satu docker compose down — beres semua
Scaling Manual docker compose up --scale web=3

Compose V2 vs V1 — Pakai yang Mana?

Kalau kamu masih lihat tutorial yang pakai docker-compose (pakai strip), itu Compose V1 — sudah deprecated sejak 2023. Sekarang yang benar:

# V2 (yang kita pakai) — built-in ke Docker CLI
docker compose version

# V1 (deprecated, jangan pakai)
docker-compose --version

Compose V2 itu plugin bawaan Docker Engine. Gak perlu install terpisah. Kalau kamu install Docker Engine terbaru, Compose V2 udah auto ikut.

Prasyarat

Sebelum mulai, pastikan dua hal ini udah ready:

Install Docker Engine

Kalau belum install Docker, cek artikel Install Docker di Ubuntu dulu. Balik lagi ke sini setelah Docker jalan.

Verifikasi Compose V2

docker compose version
# Output: Docker Compose version v2.x.x

Kalau muncul versi 2.x — kamu siap. Kalau command not found, update Docker Engine kamu ke versi terbaru.

Anatomi File docker-compose.yml

Ini jantungnya Compose. Satu file YAML yang nge-define seluruh stack kamu. Struktur dasarnya:

services:
  nama-service:
    image: nama-image:tag
    ports:
      - "host:container"
    volumes:
      - ./local-folder:/container-path
    environment:
      - KEY=value
    depends_on:
      - service-lain

Breakdown:

  • services — daftar container yang mau kamu jalankan. Tiap service = 1 container.
  • image — Docker image yang dipake (dari Docker Hub atau custom build).
  • ports — mapping port host ke container. "8080:80" artinya akses port 8080 di laptop, nyambung ke port 80 di container.
  • volumes — mount folder lokal ke dalam container. Data persist walau container dihapus.
  • environment — env variables. Bisa juga pakai file .env.
  • depends_on — urutan startup. "Jangan jalanin service ini sebelum yang itu ready."

Networks (Kapan Perlu, Kapan Tidak)

By default, Compose bikin satu network untuk semua service di file yang sama. Artinya semua service bisa saling communicate pakai nama service sebagai hostname. Kamu gak perlu define network secara eksplisit kecuali:
- Mau isolasi antar grup service
- Mau connect ke network external (misal dari Compose project lain)

depends_on (Urutan Startup)

services:
  app:
    depends_on:
      - db
  db:
    image: postgres:16

Ini memastikan container db start duluan sebelum app. Tapi perhatian: depends_on cuma nunggu container start, bukan nunggu sampai service di dalamnya ready. Kalau butuh nunggu sampai database beneran accepting connections, pakai healthcheck.

Hands-on #1: Static Website dengan Nginx

Mulai dari yang paling simpel. Kita serve static HTML pakai Nginx.

1. Bikin folder project:

mkdir compose-demo && cd compose-demo
mkdir html

2. Bikin file HTML sederhana:

cat > html/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head><title>Compose Works!</title></head>
<body><h1>Docker Compose berhasil jalan! 🎉</h1></body>
</html>
EOF

3. Bikin docker-compose.yml:

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro

Penjelasan:
- nginx:alpine — image Nginx yang ringan (~20MB compressed, jauh lebih kecil dari versi Debian ~70MB)
- "8080:80" — akses port 8080 di browser, nyambung ke Nginx di port 80
- ./html:/usr/share/nginx/html:ro — mount folder html kita ke document root Nginx. :ro = read-only (Nginx gak perlu nulis)

4. Jalankan:

docker compose up -d

Flag -d = detached (jalan di background). Tanpa -d, log bakal nempel di terminal.

5. Buka browser: http://localhost:8080

Kalau muncul "Docker Compose berhasil jalan!" — selamat, Compose pertama kamu udah live.

6. Matiin:

docker compose down

Semua container, network yang di-create otomatis — semua di-cleanup. Bersih.

Hands-on #2: App + Database (Node.js + PostgreSQL)

Sekarang naik level. Kita bikin app Node.js yang connect ke PostgreSQL — dua container yang saling ngobrol.

1. Struktur folder:

mkdir compose-app && cd compose-app
mkdir app

2. Bikin app sederhana (app/index.js):

const http = require('http');
const { Pool } = require('pg');

const pool = new Pool({
  host: 'db',          // nama service di compose = hostname
  user: 'myuser',
  password: 'mypass',
  database: 'mydb',
});

const server = http.createServer(async (req, res) => {
  try {
    const result = await pool.query('SELECT NOW() as time');
    res.end(`DB connected! Server time: ${result.rows[0].time}`);
  } catch (err) {
    res.end(`DB error: ${err.message}`);
  }
});

server.listen(3000, () => console.log('App running on :3000'));

3. app/package.json:

{
  "name": "compose-app",
  "dependencies": { "pg": "^8.11.0" },
  "scripts": { "start": "node index.js" }
}

4. app/Dockerfile:

FROM node:20-alpine
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
CMD ["npm", "start"]

5. docker-compose.yml:

services:
  app:
    build: ./app
    ports:
      - "3000:3000"
    environment:
      - PGHOST=db
      - PGUSER=myuser
      - PGPASSWORD=mypass
      - PGDATABASE=mydb
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=mypass
      - POSTGRES_DB=mydb
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Yang baru di sini:
- build: ./app — Compose build image dari Dockerfile di folder ./app
- depends_on — db start duluan
- volumes: pgdata: — named volume. Data PostgreSQL persist walau docker compose down. Kalau pakai docker compose down -v, baru volume ikut dihapus.

6. Jalankan:

docker compose up -d --build

Flag --build paksa rebuild image kalau ada perubahan di Dockerfile/source.

7. Test: http://localhost:3000 — kalau muncul "DB connected! Server time: ..." berarti app berhasil ngomong ke database.

Hands-on #3: Full Stack (Frontend + Backend + DB + Adminer)

Level terakhir. Empat service, custom network, .env file, dan healthcheck.

1. Struktur folder:

fullstack/
├── docker-compose.yml
├── .env
├── frontend/
│   └── index.html
└── backend/
    ├── Dockerfile
    ├── package.json
    └── index.js

2. File .env (simpan secrets di sini, JANGAN commit ke git):

POSTGRES_USER=admin
POSTGRES_PASSWORD=supersecret123
POSTGRES_DB=fullstack_db

3. docker-compose.yml:

services:
  frontend:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./frontend:/usr/share/nginx/html:ro
    depends_on:
      - backend
    networks:
      - front-net

  backend:
    build: ./backend
    ports:
      - "3000:3000"
    env_file:
      - .env
    depends_on:
      db:
        condition: service_healthy
    networks:
      - front-net
      - back-net

  db:
    image: postgres:16-alpine
    env_file:
      - .env
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks:
      - back-net

  adminer:
    image: adminer:latest
    ports:
      - "8888:8080"
    depends_on:
      - db
    networks:
      - back-net

networks:
  front-net:
  back-net:

volumes:
  db-data:

Yang baru dan penting:
- env_file: .env — load environment variables dari file. Lebih aman daripada hardcode di YAML.
- healthcheck — Compose nunggu sampai pg_isready return OK sebelum start backend. Ini solusi masalah "app start tapi DB belum ready".
- condition: service_healthy — depends_on yang beneran nunggu service ready, bukan cuma started.
- Custom networksfrontend cuma bisa reach backend, gak bisa langsung ke db. Isolasi yang proper.
- Adminer — web UI buat manage database. Akses di localhost:8888.

4. Jalankan seluruh stack:

docker compose up -d --build

5. Verifikasi semua jalan:

docker compose ps

Harusnya keempat service status "Up" (atau "Up (healthy)" buat db).

Perintah Docker Compose yang Wajib Dihapal

Ini cheat-sheet yang bakal kamu pakai tiap hari:

Perintah Fungsi
docker compose up -d Start semua service (background)
docker compose down Stop + hapus containers & networks
docker compose down -v Sama, tapi hapus volumes juga (data hilang!)
docker compose ps List semua service yang running
docker compose logs -f Live log semua service
docker compose logs -f app Live log service tertentu
docker compose exec db bash Masuk ke shell container db
docker compose build Rebuild semua image
docker compose restart app Restart satu service
docker compose pull Pull image terbaru dari registry
docker compose config Validasi & tampilkan final YAML

Tips: docker compose logs -f --tail=50 buat lihat 50 baris terakhir + follow realtime. Ini lifesaver waktu debugging.

Error Umum & Cara Mengatasinya

Bagian ini yang jarang dibahas tutorial lain. Padahal kamu pasti ketemu minimal satu dari ini:

"port is already allocated"

Error response from daemon: driver failed programming external connectivity:
Bind for 0.0.0.0:8080 failed: port is already allocated

Penyebab: Port 8080 udah dipake proses lain (mungkin container lama yang belum di-down).

Solusi:

# Cek siapa yang pakai port itu
sudo lsof -i :8080
# atau
docker ps  # mungkin container lain masih jalan

# Kill proses yang pakai, atau ganti port di compose:
ports:
  - "8081:80"  # ganti host port

"no such service: xxx"

Penyebab: Typo di nama service, atau kamu jalankan docker compose di folder yang salah (gak ada docker-compose.yml).

Solusi:
- Cek kamu di folder yang benar
- Cek indentasi YAML (YAML sensitif soal spasi)
- docker compose config buat validasi file

Volume permission denied

PermissionError: [Errno 13] Permission denied: '/data'

Penyebab: Container jalan sebagai user tertentu tapi folder mount-nya punya permission berbeda.

Solusi:

# Opsi 1: Ubah ownership folder lokal
sudo chown -R 1000:1000 ./data

# Opsi 2: Tambah user mapping di compose
services:
  app:
    user: "1000:1000"

Container exit code 137 (OOM Killed)

Penyebab: Container kehabisan memory. Docker (atau OS) kill paksa.

Solusi:

services:
  app:
    deploy:
      resources:
        limits:
          memory: 512M  # set limit eksplisit

Atau cek app kamu ada memory leak gak — 137 itu selalu soal RAM.

Docker Compose vs Dockerfile — Bedanya Apa?

Ini pertanyaan yang sering banget muncul, terutama buat yang baru belajar. Simpelnya:

Dockerfile Docker Compose
Fungsi Bikin satu image custom Orchestrate banyak container
Isinya Instruksi build (FROM, RUN, COPY) Deklarasi services (image, ports, volumes)
Output 1 Docker image Multi-container app yang running
Analogi Resep bikin satu masakan Menu lengkap satu meja makan

Kapan pakai Dockerfile?
- Kamu butuh image custom (install dependencies, copy source code, dll)
- App kamu gak tersedia di Docker Hub

Kapan pakai Docker Compose?
- Kamu jalankan lebih dari 1 container yang saling terhubung
- Kamu mau reproducible setup (tinggal docker compose up)

Kombinasi keduanya? Itu yang paling umum. Compose pakai build: buat point ke Dockerfile, kayak di Hands-on #2 dan #3 di atas.

Tips & Best Practices

Beberapa hal yang bakal bikin hidup kamu lebih gampang:

1. Selalu pakai .env untuk secrets

Jangan hardcode password di docker-compose.yml. Pakai .env file dan tambahkan ke .gitignore:

echo ".env" >> .gitignore

2. Pin image version

# ❌ Jangan
image: postgres:latest

# ✅ Pakai versi spesifik
image: postgres:16-alpine

:latest bisa berubah kapan aja tanpa kamu tau. Satu hari jalan, besok tiba-tiba break.

3. Named volumes untuk data persist

volumes:
  db-data:  # ini named volume — survive docker compose down

Kalau pakai bind mount (./data:/var/lib/...), permission sering jadi masalah. Named volumes lebih aman untuk database.

4. docker compose logs -f untuk debugging

Kalau ada service yang gak mau start, SELALU cek log dulu:

docker compose logs -f nama-service

90% masalah ketahuan dari sini.

5. Pakai docker compose config sebelum up

docker compose config

Ini validasi YAML kamu dan tampilkan final config setelah variable substitution. Tangkap error sebelum runtime.

Langkah Selanjutnya

Kamu udah bisa bikin multi-container app dengan Docker Compose — dari static site sampai full stack dengan healthcheck dan network isolation. Itu udah cover 80% use case development sehari-hari.

Mau lanjut lebih dalam? Beberapa topik yang worth dipelajari:

  • Docker networking deep-dive — custom bridge, overlay network untuk multi-host
  • Multi-stage build — bikin image production yang kecil dan aman
  • Deploy ke VPS — dari laptop ke server pakai Compose + SSH
  • Docker Compose Watch — auto-rebuild saat code berubah (hot reload untuk container)

BACA JUGA:
- Cara Install Docker di Ubuntu 24.04
- Setup WSL2 + Arch Linux untuk Ngoding


Segitu dulu sobat. Kalau ada yang stuck atau error aneh, drop di kolom komentar. Error Docker itu pattern-nya mirip-mirip — kemungkinan besar gue atau pembaca lain bisa bantu.

Semoga bermanfaat! 🐳


Artikel ini menggunakan Docker Compose V2 (versi 2.x) yang merupakan standar sejak 2023. Semua command sudah diverifikasi di Docker Engine 24+ pada Ubuntu 22.04/24.04.

Sumber referensi:
- Docker Compose Documentation — Official docs
- Compose File Reference — Spesifikasi lengkap YAML
- Docker Compose Networking — Deep-dive networking

Post a Comment for "Docker Compose untuk Pemula: dari Nol Sampai Jalan"