Docker mengubah cara kita membangun, mengirim, dan menjalankan perangkat lunak. Alih-alih "berjalan di mesin saya", Docker menjamin bahwa aplikasi Anda berjalan dengan cara yang sama di mana saja - di laptop Anda, di mesin rekan kerja, di CI/CD, dan di produksi. Dalam panduan ini, kita akan mulai dari nol hingga men-deploy aplikasi nyata.
Apa itu Docker?
Docker adalah platform yang mengemas aplikasi Anda dan semua dependensinya ke dalam unit standar yang disebut container. Container adalah proses yang terisolasi dan ringan yang berbagi kernel OS host tetapi memiliki filesystem, jaringan, dan ruang proses sendiri.
Container vs Mesin Virtual
| Aspek | Container | Mesin Virtual |
|---|---|---|
| Startup | Detik | Menit |
| Ukuran | MB | GB |
| OS | Berbagi kernel host | OS tamu penuh |
| Isolasi | Level proses | Level hardware |
| Performa | Hampir native | Overhead dari hypervisor |
| Kepadatan | Ratusan per host | Puluhan per host |
Menginstal Docker
# macOS brew install --cask docker # Ubuntu/Debian curl -fsSL https://get.docker.com | sh sudo usermod -aG docker $USER # Verify installation docker --version docker run hello-world
Konsep Inti
Image
Image adalah template read-only dengan instruksi untuk membuat container. Anggap saja sebagai snapshot dari aplikasi dan lingkungannya.
# Pull an image from Docker Hub docker pull node:20-alpine # List local images docker images # Remove an image docker rmi node:20-alpine
Container
Container adalah instance yang sedang berjalan dari sebuah image. Anda dapat membuat, memulai, menghentikan, dan menghapus container.
# Run a container docker run -d --name my-app -p 3000:3000 node:20-alpine # List running containers docker ps # List all containers (including stopped) docker ps -a # Stop a container docker stop my-app # Remove a container docker rm my-app # View logs docker logs my-app # Execute a command inside a running container docker exec -it my-app sh
Menulis Dockerfile
Dockerfile adalah file teks dengan instruksi untuk membangun image. Setiap instruksi membuat sebuah layer.
Dockerfile Dasar untuk Aplikasi Node.js
# Use an official Node.js runtime as base image FROM node:20-alpine # Set working directory WORKDIR /app # Copy package files first (better caching) COPY package.json package-lock.json ./ # Install dependencies RUN npm ci --only=production # Copy application code COPY . . # Expose the port the app runs on EXPOSE 3000 # Command to run the application CMD ["node", "server.js"]
Build dan Jalankan
# Build the image docker build -t my-node-app . # Run the container docker run -d -p 3000:3000 my-node-app # Visit http://localhost:3000
Multi-Stage Build
Multi-stage build menjaga image produksi Anda tetap kecil dengan memisahkan lingkungan build dari runtime.
# Stage 1: Build 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 runner WORKDIR /app COPY /app/dist ./dist COPY /app/node_modules ./node_modules COPY /app/package.json ./ EXPOSE 3000 CMD ["node", "dist/server.js"]
Ini menghasilkan image yang hanya berisi output terkompilasi dan dependensi produksi - tanpa kode sumber, tanpa dependensi pengembangan, tanpa alat build.
Contoh Multi-Stage untuk Next.js
FROM node:20-alpine AS deps WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci FROM node:20-alpine AS builder WORKDIR /app COPY /app/node_modules ./node_modules COPY . . RUN npm run build FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production COPY /app/public ./public COPY /app/.next/standalone ./ COPY /app/.next/static ./.next/static EXPOSE 3000 CMD ["node", "server.js"]
Volume: Data Persisten
Secara default, data di dalam container hilang ketika container dihapus. Volume menyelesaikan masalah ini.
# Create a named volume docker volume create my-data # Run with a volume docker run -d -v my-data:/app/data my-app # Bind mount (map host directory to container) docker run -d -v $(pwd)/data:/app/data my-app # List volumes docker volume ls
Jaringan
Docker membuat jaringan terisolasi agar container dapat berkomunikasi.
# Create a custom network docker network create my-network # Run containers on the same network docker run -d --name api --network my-network my-api docker run -d --name db --network my-network postgres:16 # Containers can reach each other by name # From "api" container: postgres://db:5432
Docker Compose
Docker Compose memungkinkan Anda mendefinisikan dan menjalankan aplikasi multi-container dengan satu file YAML.
docker-compose.yml
services: api: build: ./api ports: - "3000:3000" environment: - DATABASE_URL=postgres://user:pass@db:5432/mydb depends_on: - db db: image: postgres:16-alpine environment: - POSTGRES_USER=user - POSTGRES_PASSWORD=pass - POSTGRES_DB=mydb volumes: - pgdata:/var/lib/postgresql/data ports: - "5432:5432" redis: image: redis:7-alpine ports: - "6379:6379" volumes: pgdata:
Perintah
# Start all services docker compose up -d # View logs docker compose logs -f # Stop all services docker compose down # Rebuild and restart docker compose up -d --build # Scale a service docker compose up -d --scale api=3
.dockerignore
Seperti .gitignore, file ini mencegah file yang tidak diperlukan disalin ke dalam image.
node_modules .git .env *.md .next dist coverage
Praktik Terbaik untuk Produksi
1. Gunakan Image Dasar yang Kecil
# Bad: 1GB+ FROM node:20 # Good: ~180MB FROM node:20-alpine
2. Jangan Jalankan sebagai Root
FROM node:20-alpine RUN addgroup -S app && adduser -S app -G app USER app WORKDIR /home/app COPY . .
3. Gunakan Tag Image yang Spesifik
# Bad: can change unexpectedly FROM node:latest # Good: pinned version FROM node:20.11-alpine3.19
4. Manfaatkan Cache Build
Urutkan instruksi Dockerfile dari yang paling jarang berubah ke yang paling sering berubah:
FROM node:20-alpine WORKDIR /app # These change rarely - cached COPY package.json package-lock.json ./ RUN npm ci --only=production # This changes often - not cached COPY . .
5. Health Check
HEALTHCHECK \ CMD wget -qO- http://localhost:3000/health || exit 1
6. Gunakan Variabel Lingkungan
ENV NODE_ENV=production ENV PORT=3000
Lembar Contekan Perintah Docker Umum
# Images docker build -t name:tag . # Build image docker images # List images docker rmi image_name # Remove image docker image prune # Remove unused images # Containers docker run -d -p 3000:3000 image # Run detached docker ps # List running docker stop container_name # Stop docker rm container_name # Remove docker logs -f container_name # Follow logs docker exec -it container sh # Shell into container # Compose docker compose up -d # Start services docker compose down # Stop services docker compose logs -f # Follow all logs docker compose ps # List services # Cleanup docker system prune -a # Remove everything unused
Dari Docker ke Kubernetes
Docker menangani container individual. Ketika Anda perlu mengorkestrasi ratusan container di beberapa server, Anda memerlukan Kubernetes. Docker dan Kubernetes saling melengkapi:
- Docker: membangun dan menjalankan container
- Kubernetes: mengorkestrasi container dalam skala besar (penjadwalan, penskalaan, penyembuhan)
Jika Anda tertarik dengan langkah selanjutnya, lihat artikel saya tentang Pengantar Kubernetes.
Kesimpulan
Docker adalah keterampilan fundamental bagi pengembang modern. Ini menghilangkan inkonsistensi lingkungan, menyederhanakan deployment, dan merupakan fondasi untuk orkestrasi container dengan Kubernetes. Mulai dengan Dockerfile sederhana, beralih ke Docker Compose untuk aplikasi multi-layanan, dan adopsi multi-stage build serta praktik terbaik keamanan seiring Anda berkembang.
Cara terbaik untuk belajar Docker adalah meng-containerize proyek yang sudah Anda kerjakan. Mulai hari ini.