Docker dari Dasar sampai Mahir: Panduan Lengkap untuk Developer 2026
Kuasai Docker dari konsep dasar containerization hingga teknik advanced seperti multi-stage builds, compose orchestration, dan production deployment. Panduan praktis dengan contoh kode yang langsung bisa dijalankan.
Docker dari Dasar sampai Mahir: Panduan Lengkap untuk Developer 2026
Introduction
Pernahkah kamu mengalami masalah klasik: "Di laptop saya jalan normal, tapi di server error"? Atau habis berjam-jam setup environment development, lalu rekan kerja baru harus mengulang proses yang sama? Docker hadir untuk mengakhiri semua itu.
Docker adalah platform containerization yang memungkinkan kamu mengemas aplikasi beserta semua dependensinya ke dalam unit standar yang disebut container. Container ini bisa berjalan di mana saja—laptop developer, server testing, atau cloud production—dengan behavior yang 100% konsisten.
Analogi sederhana: Bayangkan container seperti kemasan makanan beku. Di dalamnya sudah ada bahan, bumbu, dan instruksi masak yang lengkap. Siapapun yang memasaknya, di dapur manapun, hasilnya akan sama persis.
Kenapa Docker penting di 2026?
- 85%+ perusahaan sudah mengadopsi containerization
- Kubernetes dan orkestrasi container jadi standar industri
- CI/CD pipelines hampir selalu menggunakan Docker
- Microservices architecture sangat bergantung pada containers
- Development environment jadi portable dan reproducible
Prerequisites
Sebelum mulai, pastikan kamu punya:
- Operating System: Windows 10/11 (dengan WSL2), macOS, atau Linux
- RAM minimal 4GB (8GB+ recommended)
- Pengetahuan dasar command line/terminal
- Pemahaman dasar tentang aplikasi dan dependencies
Tools yang Perlu Diinstall
- Docker Desktop (Windows/macOS) atau Docker Engine (Linux)
- Terminal/Command Prompt
- Text editor (VS Code, Vim, atau apapun)
Core Concepts
Apa itu Container?
Container adalah unit software yang mengemas kode dan semua dependensinya sehingga aplikasi bisa berjalan cepat dan reliable dari satu environment ke environment lain.
Perbedaan Container vs Virtual Machine:
┌─────────────────────────────────────────────────────────────────┐ │ VIRTUAL MACHINE │ ├─────────────────────────────────────────────────────────────────┤ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │ │ App A │ │ App B │ │ App C │ │ │ ├───────────┤ ├───────────┤ ├───────────┤ │ │ │ Bins/Libs│ │ Bins/Libs│ │ Bins/Libs│ │ │ ├───────────┤ ├───────────┤ ├───────────┤ │ │ │ Guest OS │ │ Guest OS │ │ Guest OS │ (HEAVY!) │ │ └───────────┘ └───────────┘ └───────────┘ │ │ ┌─────────────────────────────────────────┐ │ │ │ HYPERVISOR │ │ │ └─────────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────┐ │ │ │ HOST OS │ │ │ └─────────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────┐ │ │ │ PHYSICAL HARDWARE │ │ │ └─────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────┐ │ DOCKER CONTAINER │ ├─────────────────────────────────────────────────────────────────┤ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │ │ App A │ │ App B │ │ App C │ │ │ ├───────────┤ ├───────────┤ ├───────────┤ │ │ │ Bins/Libs│ │ Bins/Libs│ │ Bins/Libs│ (LIGHTWEIGHT!) │ │ └───────────┘ └───────────┘ └───────────┘ │ │ ┌─────────────────────────────────────────┐ │ │ │ DOCKER ENGINE │ │ │ └─────────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────┐ │ │ │ HOST OS │ │ │ └─────────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────┐ │ │ │ PHYSICAL HARDWARE │ │ │ └─────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘
Key Differences:
| Aspek | Virtual Machine | Container |
|---|---|---|
| Boot time | Menit | Detik/milidetik |
| Size | GB | MB |
| Performance | Ada overhead | Near-native |
| Isolation | Full isolation | Process isolation |
| Resource usage | Tinggi | Efisien |
Komponen Utama Docker
1. Dockerfile Blueprint/resep untuk membuat image. Berisi instruksi step-by-step.
2. Image Template read-only yang berisi OS, libraries, dan aplikasi. Dibuat dari Dockerfile.
3. Container Instance running dari image. Bisa dibuat, dijalankan, dihentikan, dan dihapus.
4. Docker Engine Runtime yang menjalankan container. Terdiri dari daemon, CLI, dan API.
5. Docker Hub / Registry Repository untuk menyimpan dan berbagi images.
Docker Architecture
┌─────────────────────────────────────────────────────────────────┐ │ DOCKER ARCHITECTURE │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ CLIENT │ │ CLIENT │ │ CLIENT │ │ │ │ (docker CLI)│ │ (Docker Desktop)│ │ (API calls)│ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ └────────────────────┼────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────┐ │ │ │ DOCKER DAEMON │ │ │ │ (docker daemon) │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ ┌────────────────────┼────────────────────┐ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ IMAGES │ │ CONTAINERS │ │ NETWORKS │ │ │ │ (templates)│ │ (instances) │ │ (connectivity)│ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ ┌─────────────────────────────────────────┐ │ │ │ VOLUMES (persistent data) │ │ │ └─────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────┐ │ │ │ REGISTRY (Docker Hub, ECR, etc) │ │ │ └─────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘
Step-by-Step: Instalasi Docker
Windows (dengan WSL2)
- Enable WSL2:
wsl --install
-
Install Docker Desktop dari docker.com
-
Verify installation:
docker --version docker run hello-world
macOS
# Via Homebrew (recommended) brew install --cask docker # Atau download dari docker.com # Buka Docker.app dan ikuti setup wizard
Linux (Ubuntu/Debian)
# Update packages sudo apt-get update # Install dependencies sudo apt-get install ca-certificates curl gnupg # Add Docker's official GPG key sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg # Add repository echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # Install Docker sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # Add user to docker group sudo usermod -aG docker $USER # Start Docker sudo systemctl start docker sudo systemctl enable docker
Step-by-Step: Docker Basics
1. Hello World
# Run your first container docker run hello-world # Output: # Hello from Docker! # This message shows that your installation appears to be working correctly.
2. Pull dan Run Images
# Pull image dari registry docker pull nginx:latest # Run container docker run -d -p 8080:80 nginx # -d: detached mode (background) # -p 8080:80: map port 8080 host ke port 80 container # Buka browser ke http://localhost:8080
3. Manage Containers
# List running containers docker ps # List all containers (including stopped) docker ps -a # Stop container docker stop <container_id> # Start container docker start <container_id> # Remove container docker rm <container_id> # Force remove running container docker rm -f <container_id>
4. Manage Images
# List images docker images # Remove image docker rmi <image_id> # Remove unused images docker image prune # Build image from Dockerfile docker build -t my-app:1.0 .
Step-by-Step: Membuat Dockerfile
Contoh: Node.js Application
Struktur project:
my-app/ ├── src/ │ └── index.js ├── package.json └── Dockerfile
package.json:
{ "name": "my-app", "version": "1.0.0", "main": "src/index.js", "scripts": { "start": "node src/index.js" }, "dependencies": { "express": "^4.18.2" } }
src/index.js:
const express = require('express'); const app = express(); const PORT = process.env.PORT || 3000; app.get('/', (req, res) => { res.json({ message: 'Hello from Docker!', timestamp: new Date().toISOString() }); }); app.get('/health', (req, res) => { res.json({ status: 'healthy' }); }); app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });
Dockerfile:
# Use official Node.js image as base FROM node:20-alpine # Set working directory WORKDIR /app # Copy package files first (for better caching) COPY package*.json ./ # Install dependencies RUN npm ci --only=production # Copy application code COPY src/ ./src/ # Set environment variable ENV NODE_ENV=production ENV PORT=3000 # Expose port EXPOSE 3000 # Create non-root user for security RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001 # Change ownership RUN chown -R nodejs:nodejs /app # Switch to non-root user USER nodejs # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1 # Start application CMD ["node", "src/index.js"]
Build dan Run
# Build image docker build -t my-app:1.0 . # Run container docker run -d -p 3000:3000 --name my-app-container my-app:1.0 # Test curl http://localhost:3000 # Check logs docker logs my-app-container # Follow logs (live) docker logs -f my-app-container
Step-by-Step: Docker Compose
Docker Compose memungkinkan kamu mendefinisikan dan menjalankan multi-container applications.
Contoh: Web App dengan Database
docker-compose.yml:
version: '3.8' services: # Application service app: build: . container_name: my-app ports: - "3000:3000" environment: - NODE_ENV=production - DATABASE_URL=postgresql://user:password@db:5432/mydb depends_on: db: condition: service_healthy networks: - app-network restart: unless-stopped # Database service db: image: postgres:15-alpine container_name: my-db environment: POSTGRES_USER: user POSTGRES_PASSWORD: password POSTGRES_DB: mydb volumes: - postgres-data:/var/lib/postgresql/data networks: - app-network healthcheck: test: ["CMD-SHELL", "pg_isready -U user -d mydb"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped # Redis cache (optional) redis: image: redis:7-alpine container_name: my-redis ports: - "6379:6379" volumes: - redis-data:/data networks: - app-network restart: unless-stopped networks: app-network: driver: bridge volumes: postgres-data: redis-data:
Compose Commands
# Start all services docker compose up -d # View logs docker compose logs # Follow logs for specific service docker compose logs -f app # Stop all services docker compose down # Stop and remove volumes docker compose down -v # Restart specific service docker compose restart app # Scale service docker compose up -d --scale app=3
Deep Dive: Multi-Stage Builds
Multi-stage builds mengurangi ukuran image final dengan memisahkan build environment dan runtime environment.
# Stage 1: Build stage FROM node:20-alpine AS builder WORKDIR /app # Copy package files COPY package*.json ./ # Install ALL dependencies (including devDependencies) RUN npm ci # Copy source code COPY . . # Build application (if using TypeScript/webpack/etc) RUN npm run build # Stage 2: Production stage FROM node:20-alpine AS production WORKDIR /app # Copy only production dependencies COPY package*.json ./ RUN npm ci --only=production # Copy built artifacts from builder stage COPY --from=builder /app/dist ./dist # Set environment ENV NODE_ENV=production # Expose port EXPOSE 3000 # Start application CMD ["node", "dist/index.js"]
Hasil:
- Builder stage: ~500MB (dengan build tools)
- Production stage: ~100MB (hanya runtime)
Deep Dive: Docker Networking
Network Types
1. Bridge Network (default)
# Create custom bridge network docker network create my-network # Run container in network docker run -d --name app1 --network my-network my-app docker run -d --name app2 --network my-network my-app # Containers can communicate by name # app1 can reach app2 at http://app2:3000
2. Host Network
# Container shares host's network stack docker run -d --network host nginx # No port mapping needed, directly on host ports
3. None Network
# Isolated container, no network access docker run -d --network none my-app
Network Commands
# List networks docker network ls # Inspect network docker network inspect my-network # Connect container to network docker network connect my-network container-name # Disconnect container docker network disconnect my-network container-name
Deep Dive: Volumes dan Data Management
Types of Data Storage
1. Volumes (Recommended)
# Create volume docker volume create my-volume # Use volume in container docker run -v my-volume:/app/data my-app # List volumes docker volume ls # Inspect volume docker volume inspect my-volume # Remove volume docker volume rm my-volume
2. Bind Mounts
# Mount host directory docker run -v /host/path:/container/path my-app # Read-only mount docker run -v /host/path:/container/path:ro my-app
3. tmpfs (Temporary)
# In-memory storage (for sensitive data) docker run --tmpfs /tmp my-app
Volume in docker-compose.yml
services: app: volumes: # Named volume - app-data:/app/data # Bind mount - ./src:/app/src:ro # Anonymous volume - /app/node_modules # tmpfs - type: tmpfs target: /tmp volumes: app-data:
Deep Dive: Docker Security Best Practices
1. Run as Non-Root User
# Create user and group RUN groupadd -r appuser && useradd -r -g appuser appuser # Set ownership RUN chown -R appuser:appuser /app # Switch user USER appuser
2. Use Minimal Base Images
# Instead of: FROM node:20 (1GB+) # Use: FROM node:20-alpine (150MB) # Or even: FROM node:20-slim (200MB)
3. Scan for Vulnerabilities
# Using Docker Scout (built-in) docker scout quickview my-app:1.0 # Detailed CVE report docker scout cves my-app:1.0 # Compare with base image docker scout compare my-app:1.0 --to node:20-alpine
4. Use .dockerignore
# .dockerignore node_modules npm-debug.log Dockerfile docker-compose*.yml .git .gitignore README.md .env* *.test.js coverage .nyc_output
5. Don't Store Secrets in Images
# BAD - secrets in Dockerfile ENV DATABASE_PASSWORD=secret123 # GOOD - use secrets at runtime docker run -e DATABASE_PASSWORD=secret123 my-app # Or use Docker secrets (Swarm) docker secret create db_password ./password.txt docker service create --secret db_password my-app
Best Practices
1. Layer Optimization
# BAD - Multiple RUN commands RUN apt-get update RUN apt-get install -y curl RUN apt-get clean # GOOD - Single RUN command RUN apt-get update && apt-get install -y curl && apt-get clean && rm -rf /var/lib/apt/lists/*
2. Order Instructions by Change Frequency
# Instructions yang jarang berubah di atas FROM node:20-alpine WORKDIR /app # Dependencies jarang berubah COPY package*.json ./ RUN npm ci --only=production # Code sering berubah COPY . . CMD ["node", "index.js"]
3. Use Specific Tags
# BAD - latest tag FROM node:latest # GOOD - specific version FROM node:20.10.0-alpine
4. Health Checks
HEALTHCHECK --interval=30s --timeout=3s --retries=3 CMD curl -f http://localhost:3000/health || exit 1
5. Resource Limits
# Limit memory and CPU docker run -d --memory="512m" --cpus="0.5" my-app
# In docker-compose.yml services: app: deploy: resources: limits: cpus: '0.5' memory: 512M reservations: memory: 256M
Common Mistakes
❌ Mistake 1: Using :latest Tag
# BAD FROM node:latest # GOOD FROM node:20.10.0-alpine
Alasan: latest bisa berubah kapan saja, menyebabkan build yang tidak reproducible.
❌ Mistake 2: Running as Root
# BAD - runs as root by default FROM node:20-alpine CMD ["node", "index.js"] # GOOD - explicit non-root user FROM node:20-alpine RUN addgroup -g 1001 appgroup && adduser -u 1001 -G appgroup -D appuser USER appuser CMD ["node", "index.js"]
❌ Mistake 3: Ignoring .dockerignore
Tanpa .dockerignore, Docker akan copy SEMUA file ke build context, termasuk node_modules yang bisa GB-an.
❌ Mistake 4: Storing Secrets in Dockerfile
# VERY BAD ENV API_KEY=sk-1234567890 ENV DATABASE_PASSWORD=secret123 # GOOD - use environment variables at runtime # docker run -e API_KEY=xxx -e DATABASE_PASSWORD=yyy my-app
❌ Mistake 5: Not Using Multi-Stage Builds
# BAD - single stage, includes build tools in final image FROM node:20 COPY . . RUN npm install RUN npm run build CMD ["node", "dist/index.js"] # GOOD - multi-stage, final image only has runtime FROM node:20 AS builder COPY . . RUN npm install && npm run build FROM node:20-alpine COPY --from=builder /app/dist ./dist CMD ["node", "dist/index.js"]
❌ Mistake 6: Ignoring Container Logs
# Always check logs when debugging docker logs container-name # Follow logs in real-time docker logs -f container-name # Last 100 lines docker logs --tail 100 container-name
Advanced Tips
1. BuildKit untuk Performance
# Enable BuildKit DOCKER_BUILDKIT=1 docker build -t my-app . # Or set as default in daemon.json { "features": { "buildkit": true } }
2. Cache dari Remote Registry
# Pull and use as cache docker pull my-registry.com/my-app:latest docker build --cache-from my-registry.com/my-app:latest -t my-app .
3. Distroless Images untuk Security
# Minimal attack surface FROM gcr.io/distroless/nodejs20-debian12 COPY app.js / CMD ["app.js"]
4. Docker Buildx untuk Multi-Platform
# Build for multiple architectures docker buildx build --platform linux/amd64,linux/arm64 -t my-app .
5. Debug Running Container
# Get shell inside container docker exec -it container-name /bin/sh # Or run new container with shell docker run -it --rm my-app /bin/sh
6. Export/Import Images
# Save image to tar file docker save -o my-app.tar my-app:1.0 # Load image from tar file docker load -i my-app.tar
Troubleshooting
Container Won't Start
# Check logs docker logs container-name # Check container status docker inspect container-name # Run interactively to debug docker run -it --rm my-app /bin/sh
Image Too Large
# Analyze image layers docker history my-app:1.0 # Use dive for detailed analysis dive my-app:1.0
Network Issues
# Check container network docker network inspect bridge # DNS issues - use custom DNS docker run --dns 8.8.8.8 my-app
Permission Denied
# Add user to docker group sudo usermod -aG docker $USER # Logout and login again
Disk Space Full
# Clean up unused resources docker system prune # Remove everything (careful!) docker system prune -a --volumes # Check disk usage docker system df
Summary & Next Steps
Key Takeaways
- Container vs VM - Container lebih ringan, cepat, dan efisien
- Image = Template - Blueprint read-only untuk membuat container
- Dockerfile = Recipe - Instruksi step-by-step untuk build image
- Compose = Orchestrator - Manage multi-container applications
- Volumes = Persistence - Data survive container restart/removal
- Security matters - Non-root user, minimal images, no secrets
Docker Commands Cheat Sheet
| Command | Description |
|---|---|
docker build -t name:tag . | Build image |
docker run -d -p 8080:80 image | Run container |
docker ps | List running containers |
docker logs container | View logs |
docker exec -it container sh | Shell access |
docker stop container | Stop container |
docker rm container | Remove container |
docker rmi image | Remove image |
docker compose up -d | Start compose stack |
docker compose down | Stop compose stack |
docker system prune | Clean up |
Next Steps
- Practice dengan membuat Dockerfile untuk project kamu sendiri
- Learn Kubernetes untuk orchestration skala besar
- Explore CI/CD integration dengan Docker
- Join community di Docker Forums dan Discord
- Get certified dengan Docker Certified Associate
References
- Official Documentation: https://docs.docker.com
- Docker Hub: https://hub.docker.com
- Best Practices Guide: https://docs.docker.com/develop/develop-images/dockerfile_best-practices
- Docker Blog: https://www.docker.com/blog
- Play with Docker: https://labs.play-with-docker.com
- License: Apache 2.0
Docker: Build once, run anywhere. 🐳