Pernahkah kamu mendengar kalimat "It works on my machine"? Docker hadir untuk menghilangkan masalah tersebut sepenuhnya. Dengan containerization, aplikasimu berjalan identik di development, staging, maupun production tanpa peduli perbedaan OS, versi runtime, atau konfigurasi server.
Dalam panduan ini, kita akan mempelajari Docker secara praktis: dari memahami konsep dasar, menulis Dockerfile efisien, mengorkestrasi multi-service dengan docker-compose, hingga mengoptimasi image untuk production.
1. Konsep Dasar: Container vs Virtual Machine
Sebelum menyelam ke implementasi, penting memahami perbedaan fundamental antara container dan VM:
Virtual Machine menjalankan OS lengkap di atas hypervisor membutuhkan GB RAM dan menit untuk boot. Container berbagi kernel host OS dan hanya mengemas aplikasi beserta dependensinya membutuhkan MB RAM dan detik untuk start.
Insight: Container bukan VM yang lebih ringan. Container menggunakan fitur kernel Linux (namespaces untuk isolasi proses & cgroups untuk alokasi resource) — bukan virtualisasi hardware lengkap.
2. Menulis Dockerfile: Mengemas Aplikasi Node.js
Dockerfile adalah resep untuk membangun image. Setiap instruksi membuat satu layer yang di-cache:
# Gunakan image base yang spesifik (hindari :latest)
FROM node:20-alpine AS base
# Set working directory
WORKDIR /app
# Copy dependency files terlebih dahulu (cache optimization)
COPY package.json package-lock.json ./
# Install dependencies
RUN npm ci --only=production
# Copy source code
COPY . .
# Expose port yang digunakan aplikasi
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget --quiet --tries=1 --spider http://localhost:3000/health || exit 1
# Command untuk menjalankan aplikasi
CMD ["node", "server.js"]
Best practices yang diterapkan:
- Alpine image ukuran 5x lebih kecil dari image Debian default
- Spesifik tag (
node:20-alpine, bukannode:latest) reproducible builds - Copy
package*.jsonduluan layer caching, rebuild hanya saat dependencies berubah npm ciinstalasi lebih cepat dan konsisten dibandingnpm install- HEALTHCHECK Docker tahu kapan container tidak sehat
3. Multi-Stage Build: Optimasi Image Production
Untuk aplikasi yang membutuhkan build step (TypeScript, Next.js, Go), gunakan multi-stage build agar image production hanya berisi artifact final:
# ====== Stage 1: Builder ======
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
# ====== Stage 2: Production ======
FROM node:20-alpine AS production
WORKDIR /app
# Buat non-root user untuk keamanan
RUN addgroup --system --gid 1001 appgroup && \
adduser --system --uid 1001 appuser
# Copy HANYA artifact yang dibutuhkan dari builder
COPY --from=builder /app/package.json ./
COPY --from=builder /app/package-lock.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
# Set environment
ENV NODE_ENV=production
ENV PORT=3000
# Gunakan non-root user
USER appuser
EXPOSE 3000
CMD ["npm", "start"]
Perbandingan ukuran image:
| Approach | Image Size |
|---|---|
| Single stage (Debian) | ~1.2 GB |
| Single stage (Alpine) | ~450 MB |
| Multi-stage (Alpine) | ~180 MB |
Pengurangan hingga 85% ini sangat signifikan untuk download time di CI/CD dan biaya container registry.
4. Docker Compose: Orkestrasi Multi-Service
Aplikasi modern jarang berjalan sendirian. Biasanya ada database, cache, message queue, dll. Docker Compose memungkinkan kamu mendefinisikan dan menjalankan semua service sekaligus:
# docker-compose.yml
version: '3.9'
services:
app:
build:
context: .
dockerfile: Dockerfile
target: production
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/myapp
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
restart: unless-stopped
networks:
- app-network
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: myapp
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 10s
timeout: 5s
retries: 5
ports:
- "5432:5432"
networks:
- app-network
cache:
image: redis:7-alpine
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- app-network
volumes:
postgres_data:
redis_data:
networks:
app-network:
driver: bridge
Jalankan seluruh stack dengan satu perintah:
# Development dengan hot reload
docker compose up --build
# Production background mode
docker compose up -d --build
# Lihat logs
docker compose logs -f app
# Scale service
docker compose up -d --scale app=3
# Hentikan semua
docker compose down -v
5. Docker dalam CI/CD Pipeline
Docker terintegrasi sempurna dengan CI/CD. Berikut contoh GitHub Actions pipeline:
# .github/workflows/deploy.yml
name: Build & Deploy
on:
push:
branches: [main]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build & Push Image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Deploy to Production
run: |
ssh deploy@server 'docker pull ghcr.io/${{ github.repository }}:latest && docker compose up -d'
6. Perintah Docker yang Wajib Dikuasai
# Image management
docker build -t myapp:v1 . # Build image
docker images # List images
docker rmi myapp:v1 # Hapus image
docker image prune -a # Bersihkan unused images
# Container management
docker run -d -p 3000:3000 myapp # Jalankan container
docker ps # List running containers
docker ps -a # List semua containers
docker stop <container_id> # Hentikan container
docker rm <container_id> # Hapus container
# Debugging
docker logs -f <container_id> # Lihat logs (follow)
docker exec -it <container_id> sh # Masuk ke shell container
docker inspect <container_id> # Detail informasi container
docker stats # Resource usage real-time
# Cleanup
docker system prune -a --volumes # Bersihkan SEMUA unused resources
Tips Keamanan: Selalu jalankan container dengan non-root user, gunakan
.dockerignoreuntuk menghindari copy file sensitif (.env,node_modules,.git), dan scan image untuk vulnerability dengandocker scout cves.
Kesimpulan
Docker telah menjadi standar de facto dalam software development modern. Dengan menguasai Dockerfile yang efisien, multi-stage build, docker-compose, dan integrasi CI/CD, kamu memiliki fondasi kuat untuk membangun, menguji, dan men-deploy aplikasi di environment manapun dengan konsistensi yang terjamin.
Langkah selanjutnya? Pelajari Kubernetes untuk orkestrasi container di skala besar, atau eksplorasi Docker Swarm untuk setup yang lebih sederhana namun tetap production-ready.