Nội dung

DaiPhan

DaiPhan

Full-Stack Developer

Full-stack developer passionate about modern web technologies, best practices, and sharing knowledge with the community.

Skills & Expertise

JavaScript TypeScript React Node.js DevOps
150+
Articles
50k+
Readers
4.9
Rating

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

  1. Use specific tags: Tránh latest, dùng node:18-alpine
  2. Minimize layers: Group commands với &&
  3. Use .dockerignore: Loại trừ unnecessary files
  4. Leverage build cache: Order matters!
  5. Use multi-stage builds: Reduce final image size
  6. Run as non-root: Security best practice
  7. 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

  1. Use official images: Tránh unofficial images
  2. Scan images: docker scan image_name
  3. Run as non-root: Create user trong Dockerfile
  4. Use read-only filesystem: --read-only
  5. Limit resources: --memory, --cpus
  6. Use secrets: Docker secrets cho sensitive data
  7. 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

  1. Port already in use: Kill process hoặc dùng different port
  2. Permission denied: Run với sudo hoặc add user to docker group
  3. Image not found: Check image name và tag
  4. Container exits immediately: Check CMD và logs
  5. 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:

  1. Start simple: Bắt đầu với basic containers
  2. Use Docker Compose: Cho multi-container applications
  3. Follow best practices: Security, efficiency, maintainability
  4. Leverage ecosystem: Docker Hub, Docker Compose, Docker Swarm
  5. 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!