Docker và Containerization: Hướng dẫn toàn tập cho developer
Hướng dẫn sử dụng Docker từ cơ bản đến nâng cao, bao gồm Dockerfile, Docker Compose và best practices
Docker và Containerization: Hướng dẫn toàn tập cho developer
Docker đã revolutionized cách chúng ta develop, deploy và run applications. Trong bài viết này, chúng ta sẽ explore everything về Docker.
1. Docker là gì? Tại sao nên dùng?
Containerization vs Virtualization
Traditional VMs:
- Hypervisor
- Guest OS
- Guest OS
- Guest OS
- Applications
Containers:
- Docker Engine
- Container 1 (App + Dependencies)
- Container 2 (App + Dependencies)
- Container 3 (App + Dependencies)
Benefits của Docker
- Consistency: Same environment từ development đến production
- Isolation: Mỗi container có riêng filesystem, network, processes
- Portability: Chạy ở đâu cũng được (“build once, run anywhere”)
- Efficiency: Lightweight hơn VMs rất nhiều
- Scalability: Dễ scale applications
2. Docker Basics
Installation
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install docker.io
# macOS (sử dụng Homebrew)
brew install docker
# Windows
# Download từ docker.com hoặc sử dụng Docker Desktop
Docker Architecture
┌─────────────────┐
│ Docker Client │ (docker command)
└────────┬────────┘
│
▼
┌─────────────────┐
│ Docker Daemon │ (dockerd)
└────────┬────────┘
│
▼
┌─────────────────┐
│ Container Runtime│
└────────┬────────┘
│
▼
┌─────────────────┐
│ Linux Kernel │
└─────────────────┘
3. Working với Images
Pull images từ Docker Hub
# Pull official images
docker pull nginx
docker pull node:18-alpine
docker pull postgres:14
# List local images
docker images
# Remove image
docker rmi nginx
Image layers
# Xem layers của image
docker history node:18-alpine
# Inspect image
docker inspect node:18-alpine
4. Working với Containers
Run containers
# Run container interactively
docker run -it ubuntu bash
# Run container in background
docker run -d nginx
# Run với port mapping
docker run -d -p 8080:80 nginx
# Run với volume
docker run -d -v /host/path:/container/path nginx
# Run với environment variables
docker run -d -e NODE_ENV=production -p 3000:3000 my-app
Container management
# List running containers
docker ps
# List all containers (including stopped)
docker ps -a
# Stop container
docker stop container_name
# Start container
docker start container_name
# Remove container
docker rm container_name
# View logs
docker logs container_name
# Execute command trong container
docker exec -it container_name bash
# Copy files từ/to container
docker cp container_name:/path/to/file /host/path
docker cp /host/path container_name:/path/to/file
5. Writing Dockerfiles
Basic Dockerfile
# Base image
FROM node:18-alpine
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy source code
COPY . .
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
# Run application
CMD ["npm", "start"]
Multi-stage Dockerfile (cho production)
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install all dependencies (including dev)
RUN npm ci
# Copy source code
COPY . .
# Build application
RUN npm run build
# Production stage
FROM node:18-alpine AS production
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install production dependencies only
RUN npm ci --only=production && npm cache clean --force
# Copy built application từ build stage
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/public ./public
# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# Change ownership
RUN chown -R nextjs:nodejs /app
USER nextjs
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node healthcheck.js
CMD ["node", "dist/server.js"]
Best Practices cho Dockerfile
- Use specific tags: Tránh
latest, dùngnode:18-alpine - Minimize layers: Group commands với
&& - Use .dockerignore: Loại trừ unnecessary files
- Leverage build cache: Order matters!
- Use multi-stage builds: Reduce final image size
- Run as non-root: Security best practice
- Health checks: Ensure container health
6. Docker Compose
docker-compose.yml
version: '3.8'
services:
# Frontend application
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- REACT_APP_API_URL=http://localhost:8000
volumes:
- ./frontend:/app
- /app/node_modules
depends_on:
- backend
networks:
- app-network
# Backend API
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "8000:8000"
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://user:password@postgres:5432/myapp
- REDIS_URL=redis://redis:6379
volumes:
- ./backend:/app
- /app/node_modules
depends_on:
- postgres
- redis
networks:
- app-network
# PostgreSQL database
postgres:
image: postgres:14-alpine
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- "5432:5432"
networks:
- app-network
# Redis cache
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
networks:
- app-network
# Nginx reverse proxy
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- frontend
- backend
networks:
- app-network
volumes:
postgres_data:
redis_data:
networks:
app-network:
driver: bridge
Docker Compose Commands
# Build and start all services
docker-compose up
# Start in background
docker-compose up -d
# Build services
docker-compose build
# View logs
docker-compose logs -f
# Scale services
docker-compose up -d --scale backend=3
# Stop services
docker-compose down
# Stop và remove volumes
docker-compose down -v
# Execute command trong service
docker-compose exec backend bash
# View service status
docker-compose ps
7. Docker Networking
Network types
# List networks
docker network ls
# Create custom network
docker network create my-network
# Run container với custom network
docker run -d --name web --network my-network nginx
# Connect container to network
docker network connect my-network container_name
# Disconnect container from network
docker network disconnect my-network container_name
# Inspect network
docker network inspect my-network
Network patterns
# docker-compose.yml với networks
version: '3.8'
services:
frontend:
build: ./frontend
networks:
- frontend-network
- backend-network
backend:
build: ./backend
networks:
- backend-network
- database-network
database:
image: postgres:14
networks:
- database-network
networks:
frontend-network:
driver: bridge
backend-network:
driver: bridge
database-network:
driver: bridge
internal: true # Không thể access từ outside
8. Docker Volumes
Volume types
# Named volumes
docker volume create my-volume
docker run -d -v my-volume:/data nginx
# Bind mounts
docker run -d -v /host/path:/container/path nginx
# tmpfs mounts (in-memory)
docker run -d --tmpfs /tmp nginx
Volume best practices
# docker-compose.yml với volumes
version: '3.8'
services:
postgres:
image: postgres:14
volumes:
- type: volume
source: postgres_data
target: /var/lib/postgresql/data
volume:
nocopy: true
- type: bind
source: ./init-scripts
target: /docker-entrypoint-initdb.d
read_only: true
volumes:
postgres_data:
driver: local
9. Docker Security
Security best practices
- Use official images: Tránh unofficial images
- Scan images:
docker scan image_name - Run as non-root: Create user trong Dockerfile
- Use read-only filesystem:
--read-only - Limit resources:
--memory,--cpus - Use secrets: Docker secrets cho sensitive data
- Keep images updated: Regular security updates
Example security configuration
# Multi-user setup
FROM node:18-alpine
# Create app user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S appuser -u 1001
WORKDIR /app
# Copy files với correct ownership
COPY --chown=appuser:nodejs . .
# Install dependencies
RUN npm ci --only=production && npm cache clean --force
# Switch to non-root user
USER appuser
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node healthcheck.js
CMD ["node", "server.js"]
10. Docker trong CI/CD
GitHub Actions example
name: Build and Deploy
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v3
with:
context: .
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/myapp:${{ github.sha }}
${{ secrets.DOCKERHUB_USERNAME }}/myapp:latest
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Deploy to production
run: |
# Deploy commands here
echo "Deploying ${{ secrets.DOCKERHUB_USERNAME }}/myapp:${{ github.sha }}"
11. Debugging Docker Issues
Common commands
# View container logs
docker logs container_name
# Execute command trong container
docker exec -it container_name bash
# Inspect container
docker inspect container_name
# View real-time stats
docker stats
# Check disk usage
docker system df
# Clean up unused resources
docker system prune -a
# View events
docker events
# Check network connectivity
docker network inspect bridge
Common issues và solutions
- Port already in use: Kill process hoặc dùng different port
- Permission denied: Run với sudo hoặc add user to docker group
- Image not found: Check image name và tag
- Container exits immediately: Check CMD và logs
- Volume permission issues: Check ownership và permissions
12. Advanced Topics
Docker Swarm (Basic Orchestration)
# Initialize swarm
docker swarm init
# Join swarm (trên worker nodes)
docker swarm join --token SWMTKN-... manager-ip:2377
# Deploy stack
docker stack deploy -c docker-compose.yml myapp
# List services
docker service ls
# Scale service
docker service scale myapp_web=5
# Remove stack
docker stack rm myapp
# Leave swarm
docker swarm leave --force
Multi-architecture builds
# Create buildx builder
docker buildx create --name mybuilder --use
# Build cho multiple platforms
docker buildx build --platform linux/amd64,linux/arm64 \
-t myapp:latest --push .
13. Kết luận
Docker là essential tool cho modern development. Key takeaways:
- Start simple: Bắt đầu với basic containers
- Use Docker Compose: Cho multi-container applications
- Follow best practices: Security, efficiency, maintainability
- Leverage ecosystem: Docker Hub, Docker Compose, Docker Swarm
- Integrate với CI/CD: Automate build và deployment
💡 Pro Tip: Practice makes perfect! Tạo nhiều projects với Docker để master nó.
Next steps:
- Học Kubernetes cho production orchestration
- Explore Docker Desktop features
- Study container security in depth
- Practice với real-world projects
Bạn đang dùng Docker như thế nào trong projects của bạn? Share experiences trong comments!