Anda dah selesa dengan Docker Compose asas? Bagus! Sekarang kita naikkan level sedikit. Bab ni akan tunjukkan macam mana nak buat setup Docker anda lebih profesional — reverse proxy, health check, backup, dan pengurusan berbilang host.
Tapi ingat, semua ni optional. Guna bila ada keperluan sebenar, bukan sebab nampak cool.
Apa yang anda akan belajar:
Nota Beginner: Anda tidak perlu Traefik, Macvlan, atau Swarm pada hari pertama. Guna bila ada masalah sebenar yang ia boleh selesaikan. Contohnya, Traefik berguna bila anda dah ada banyak service dan penat taip port number setiap kali.
Docker menyokong beberapa pemacu rangkaian. Setiap satu ada tujuan tersendiri.
Bridge (Default):
Ini rangkaian yang paling biasa. Container dalam rangkaian bridge boleh bercakap antara satu sama lain menggunakan nama container sebagai hostname.
# Rangkaian bridge lalai docker network create --driver bridge my-network # Container dalam rangkaian bridge boleh berkomunikasi # menggunakan nama container sebagai hostname
Host:
Container guna rangkaian host terus — macam app biasa yang jalan terus pada server.
# Container berkongsi rangkaian host terus # Tiada pengasingan rangkaian, tetapi prestasi terbaik docker run --network host nginx
Macvlan:
Setiap container dapat alamat MAC dan IP sendiri. Pada rangkaian, ia nampak macam peranti fizikal yang berasingan.
# Setiap container mendapat alamat MAC dan IP sendiri # Kelihatan seperti peranti fizikal pada rangkaian docker network create -d macvlan \ --subnet=10.0.0.0/24 \ --gateway=10.0.0.1 \ -o parent=eth0 \ my-macvlan
Macvlan sangat berguna untuk perkhidmatan yang memerlukan kehadiran pada rangkaian fizikal, seperti Pi-hole atau Home Assistant.
Nota Beginner: Untuk kebanyakan kes, rangkaian bridge sudah cukup. Guna Macvlan hanya bila service anda perlu IP tersendiri pada rangkaian rumah — contohnya Pi-hole yang perlu jadi DNS server untuk semua peranti.
IPvlan:
# Serupa dengan Macvlan tetapi berkongsi alamat MAC host # Berguna apabila switch mengehadkan MAC per port docker network create -d ipvlan \ --subnet=10.0.0.0/24 \ --gateway=10.0.0.1 \ -o parent=eth0 \ my-ipvlan
Ini contoh yang sangat praktikal — asingkan traffic antara frontend, backend, dan database.
services: traefik: image: traefik:latest networks: - frontend - backend nextcloud: image: nextcloud:latest networks: - backend - database db: image: mariadb:latest networks: - database # Hanya boleh diakses oleh nextcloud networks: frontend: driver: bridge backend: driver: bridge database: driver: bridge internal: true # Tiada akses ke internet
Dengan konfigurasi ini: - Traefik boleh berkomunikasi dengan Nextcloud (melalui backend) - Nextcloud boleh berkomunikasi dengan MariaDB (melalui database) - MariaDB TIDAK boleh diakses terus dari luar (rangkaian internal)
backend
database
internal
Tip dari saya — walaupun dalam homelab, asingkan database dari internet. Ini amalan keselamatan yang baik dan senang nak buat.
Bayangkan anda ada 10 service Docker. Tanpa reverse proxy, anda kena ingat port setiap satu — server:8080 untuk Nextcloud, server:3000 untuk Gitea, server:8096 untuk Jellyfin… penat kan?
server:8080
server:3000
server:8096
Dengan Traefik, anda boleh guna nama domain: cloud.lab.local, git.lab.local, media.lab.local. Lebih kemas dan mudah diingat.
cloud.lab.local
git.lab.local
media.lab.local
Traefik ialah reverse proxy moden yang menawarkan: - Pengesanan automatik container Docker (tiada konfigurasi manual) - Sijil SSL automatik (Let’s Encrypt) - Dashboard masa nyata - Middleware (pengesahan, rate limiting, dll.)
# docker-compose.yml services: traefik: image: traefik:latest container_name: traefik ports: - "80:80" - "443:443" - "8080:8080" # Dashboard volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik/traefik.yml:/etc/traefik/traefik.yml - ./traefik/acme.json:/acme.json networks: - proxy restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`traefik.lab.local`)" - "traefik.http.routers.dashboard.service=api@internal" networks: proxy: external: true
# traefik/traefik.yml api: dashboard: true insecure: true entryPoints: web: address: ":80" http: redirections: entryPoint: to: websecure scheme: https websecure: address: ":443" providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false network: proxy certificatesResolvers: letsencrypt: acme: email: admin@domain.com storage: /acme.json httpChallenge: entryPoint: web
Nota Beginner: Jangan risau kalau config Traefik nampak panjang. Anda hanya perlu setup sekali, dan selepas tu menambah service baru sangat mudah — cuma tambah beberapa baris label sahaja.
Menambah perkhidmatan ke Traefik:
Nampak tak betapa mudahnya? Cuma tambah labels pada service dan Traefik akan auto-detect.
labels
services: nextcloud: image: nextcloud:latest container_name: nextcloud networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.nextcloud.rule=Host(`cloud.lab.local`)" - "traefik.http.routers.nextcloud.tls=true" - "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt" - "traefik.http.services.nextcloud.loadbalancer.server.port=80" restart: unless-stopped
Basic Auth:
labels: - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$hash" - "traefik.http.routers.app.middlewares=auth"
Rate Limiting:
labels: - "traefik.http.middlewares.ratelimit.ratelimit.average=100" - "traefik.http.middlewares.ratelimit.ratelimit.burst=50"
Authelia — SSO untuk Homelab:
Authelia menyediakan Single Sign-On (SSO) dan pengesahan dua faktor untuk semua service anda. Satu login untuk semua — macam Google account tapi untuk homelab anda sendiri.
services: authelia: image: authelia/authelia:latest container_name: authelia volumes: - ./authelia/config:/config networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.authelia.rule=Host(`auth.lab.local`)" - "traefik.http.routers.authelia.tls=true" restart: unless-stopped
# authelia/config/configuration.yml server: address: 'tcp://0.0.0.0:9091/' log: level: info authentication_backend: file: path: /config/users_database.yml access_control: default_policy: deny rules: - domain: "*.lab.local" policy: two_factor session: name: authelia_session domain: lab.local expiration: 1h inactivity: 5m storage: local: path: /config/db.sqlite3 notifier: filesystem: filename: /config/notification.txt
Health check memastikan container bukan sahaja berjalan, tetapi juga benar-benar berfungsi dengan betul. Ada perbezaan besar antara “container is running” dan “service is actually working”.
Dari pengalaman saya, health check sangat berguna untuk container yang kadang-kadang hang tapi masih nampak “up” dalam docker ps.
docker ps
services: nextcloud: image: nextcloud:latest healthcheck: test: ["CMD", "curl", "-f", "http://localhost/status.php"] interval: 30s timeout: 10s retries: 3 start_period: 60s mariadb: image: mariadb:latest healthcheck: test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] interval: 30s timeout: 10s retries: 3
Kebergantungan berdasarkan kesihatan:
Ini sangat berguna — pastikan database dah siap sebelum app cuba connect.
services: nextcloud: depends_on: mariadb: condition: service_healthy redis: condition: service_started
Nota Beginner: start_period memberi masa untuk container “warm up” sebelum health check mula berjalan. Contohnya, database mungkin ambil 30-60 saat untuk sedia. Tanpa start_period, health check akan report “unhealthy” padahal container tu sedang start.
start_period
Docker Swarm membolehkan anda menjalankan container merentasi berbilang server. Kalau satu server down, container boleh dipindahkan ke server lain secara automatik.
Saya cadangkan Swarm hanya kalau anda dah ada 2-3 server dan benar-benar perlu HA (High Availability). Untuk satu server, Docker Compose sahaja dah cukup.
# Inisialisasi Swarm pada node pengurus docker swarm init --advertise-addr 10.0.20.20 # Tambah node pekerja docker swarm join --token TOKEN 10.0.20.20:2377 # Deploy stack docker stack deploy -c docker-compose.yml homelab # Senarai perkhidmatan docker service ls
Portainer menyediakan antara muka web untuk mengurus Docker. Kalau anda lebih selesa dengan GUI, ini wajib ada.
services: portainer: image: portainer/portainer-ce:latest container_name: portainer ports: - "9443:9443" volumes: - /var/run/docker.sock:/var/run/docker.sock - portainer_data:/data restart: unless-stopped volumes: portainer_data:
Ciri Portainer: - Pengurusan container visual - Melihat log dan statistik - Terminal web ke dalam container - Pengurusan imej dan rangkaian - Sokongan Docker Swarm dan Kubernetes - Template aplikasi (deploy 1 klik)
Nota Beginner: Portainer sangat membantu untuk visualize apa yang berlaku dalam Docker anda. Tapi belajar CLI juga ya — nanti dalam kerja sebenar, tak semua environment ada GUI.
Kadang-kadang, imej yang ada di Docker Hub tak cukup untuk keperluan anda. Jadi anda perlu bina sendiri.
# Contoh: Aplikasi Python FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 HEALTHCHECK --interval=30s --timeout=10s --retries=3 \ CMD curl -f http://localhost:8000/health || exit 1 USER 1000:1000 CMD ["python", "app.py"]
# 1. Gunakan imej asas yang kecil FROM alpine:3.19 # ~5MB # bukan FROM ubuntu:24.04 # ~77MB # 2. Gabungkan arahan RUN untuk kurangkan layer RUN apt-get update && \ apt-get install -y curl wget && \ rm -rf /var/lib/apt/lists/* # 3. Gunakan .dockerignore # .dockerignore .git node_modules *.md docker-compose*.yml # 4. Gunakan multi-stage build FROM node:20 AS builder WORKDIR /app COPY . . RUN npm ci && npm run build FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html # 5. Jangan jalankan sebagai root RUN adduser -D appuser USER appuser
Tip dari saya — multi-stage build tu sangat berguna. Anda boleh build app dalam satu stage, dan copy hasil build sahaja ke stage akhir. Imej jadi sangat kecil.
Backup adalah perkara yang ramai orang abaikan sehingga terlambat. Saya dah pernah kena, dan percayalah — rasa dia tak best. Jadi setup backup dari awal.
#!/bin/bash # backup-docker.sh BACKUP_DIR="/mnt/backup/docker" DATE=$(date +%Y%m%d_%H%M%S) COMPOSE_DIR="/opt/docker" # Hentikan perkhidmatan (pilihan - untuk konsistensi) # cd $COMPOSE_DIR && docker compose stop # Sandaran volume dan konfigurasi tar czf "$BACKUP_DIR/docker-backup-$DATE.tar.gz" \ -C "$COMPOSE_DIR" \ --exclude='*/cache/*' \ --exclude='*/logs/*' \ . # Sandaran senarai imej docker images --format "{{.Repository}}:{{.Tag}}" > \ "$BACKUP_DIR/docker-images-$DATE.txt" # Mulakan semula perkhidmatan # cd $COMPOSE_DIR && docker compose up -d # Buang sandaran lama (simpan 7 hari) find "$BACKUP_DIR" -name "docker-backup-*.tar.gz" -mtime +7 -delete echo "Sandaran Docker selesai: $DATE"
Nota Beginner: Script di atas boleh dijadualkan menggunakan cron supaya backup berjalan secara automatik setiap malam. Satu baris cron job, dan anda boleh tidur lena tanpa risau kehilangan data.
cron
Salah satu kelebihan Docker ialah migrasi yang mudah. Kalau anda beli server baru, pindahkan service dalam beberapa minit sahaja.
# Pada server lama: # 1. Eksport konfigurasi cd /opt/docker tar czf docker-configs.tar.gz . # 2. Salin ke server baru scp docker-configs.tar.gz admin@pelayan-baru:/opt/docker/ # Pada server baru: # 3. Ekstrak cd /opt/docker tar xzf docker-configs.tar.gz # 4. Mulakan perkhidmatan docker compose pull docker compose up -d
Nampak tak betapa mudahnya? Itulah keindahan Docker — semuanya portable.
Dalam bab lanjutan ini, kita telah belajar tentang:
Pengetahuan lanjutan ini membolehkan anda membina infrastruktur container yang lebih kukuh dan profesional. Tapi seperti biasa — anda tak perlu guna semua sekali gus. Pilih yang anda perlukan, kuasai ia, dan tambah yang lain bila tiba masanya.
Tahniah kerana sampai ke penghujung bahagian Docker! Anda sekarang ada asas yang kukuh untuk deploy dan urus service dalam homelab. Seterusnya, kita akan belajar tentang pengurusan storan dan NAS — satu langkah pada satu masa!