Docker là nền tảng containerization phổ biến nhất hiện nay, được sử dụng bởi hàng triệu developers và organizations trên toàn thế giới. Docker giúp đóng gói ứng dụng và các dependencies vào một đơn vị nhất quán (container) có thể chạy trên bất kỳ môi trường nào – từ laptop development đến production servers, cloud instances.
Trong bài viết này, chúng ta sẽ tìm hiểu Docker toàn tập – từ những khái niệm cơ bản đến các best practices cho production deployment.
Docker là gì? Tại sao quan trọng?
Docker giải quyết bài toán “works on my machine” mà developers gặp phải hàng ngày. Thay vì cài đặt thủ công từng dependency trên mỗi máy, Docker đóng gói application cùng với tất cả libraries và configuration vào một image có thể reproduce được ở bất kỳ đâu.
Docker containers tương tự như shipping containers trong ngành logistics – một tiêu chuẩn hóa cho phép đóng gói, vận chuyển, và deploy bất kỳ loại hàng hóa nào một cách nhất quán. Tương tự, Docker containers chuẩn hóa cách đóng gói và deploy software.
Container vs Virtual Machine
Nhiều người nhầm lẫn containers với virtual machines (VMs). Cả hai đều cung cấp isolation nhưng có những khác biệt quan trọng:
| Đặc điểm | Container | Virtual Machine |
|---|---|---|
| Kích thước | MBs (thường < 200MB) | GBs (thường 20-100GB) |
| Startup time | Seconds hoặc milliseconds | Minutes |
| Isolation | OS-level (shared kernel) | Full hardware virtualization |
| Resource overhead | Rất thấp (5-10% overhead) | Cao (hypervisor + OS overhead) |
| Density | Có thể chạy 10-100 containers/VM | Thường 1-10 VMs/host |
| Portability | Chỉ Linux containers, cần Docker Desktop cho Windows/Mac | Cross-platform (naturally portable) |
Containers chia sẻ kernel của host OS, trong khi VMs có OS riêng complete với kernel riêng. Điều này khiến containers nhẹ và fast hơn nhiều so với VMs.
Cài đặt Docker
Cài đặt trên Ubuntu 22.04
# Update package index sudo apt update # Install dependencies sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release # Add Docker GPG key curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # Add Docker repository echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # Install Docker Engine sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin # Add current user to docker group (avoid sudo for docker commands) sudo usermod -aG docker $USER # Log out and log back in for group change to take effect # Verify Docker installation docker --version docker compose version # Run hello-world to verify sudo docker run hello-world # Check Docker status sudo systemctl status docker
Cài đặt trên Windows (Docker Desktop)
Windows yêu cầu WSL2 (Windows Subsystem for Linux version 2) và Hyper-V được enable:
- Tải Docker Desktop từ docker.comEnable WSL 2 bằng lệnh:
wsl --installEnable Hyper-V qua Windows FeaturesRestart WindowsChạy Docker Desktop và follow setup wizardCác khái niệm cơ bản trong Docker
Docker Image
Docker Image là template read-only chứa application code, libraries, dependencies, và configuration. Images được sử dụng để create containers. Images có thể be built từ Dockerfile hoặc pulled từ registries.
Docker Container
Container là running instance của một Docker image. Nhiều containers có thể be created từ cùng một image. Mỗi container isolated và independent.
Docker Registry
Docker Registry là nơi lưu trữ và phân phối Docker images. Docker Hub là public registry default. Các registries khác bao gồm Google Container Registry (GCR), Amazon ECR, Azure Container Registry (ACR).
Dockerfile
Dockerfile là file text chứa instructions để build Docker image. Nó defines base image, dependencies, application code, và commands cần chạy.
Docker Commands – Hướng dẫn chi tiết
Working với Images
# List local images docker images docker image ls # Pull image from registry docker pull nginx:latest docker pull ubuntu:22.04 # Build image from Dockerfile docker build -t myapp:latest . # Tag image docker tag myapp:latest myregistry.com/myapp:v1.0 # Push image to registry docker push myregistry.com/myapp:v1.0 # Remove image docker rmi nginx:latest # Inspect image layers docker history nginx:latest # Prune unused images docker image prune -a
Working với Containers
# List running containers docker ps # List all containers (including stopped) docker ps -a # Run container (create + start) docker run -d --name mynginx nginx:latest docker run -it --name myubuntu ubuntu:22.04 /bin/bash # Run container với port mapping docker run -d -p 8080:80 --name web nginx:latest # Run container với environment variables docker run -d -e NODE_ENV=production --name api myapp:latest # Run container với volume mount docker run -d -v /host/data:/container/data --name dataapp myapp:latest # Start/stop/restart container docker start mynginx docker stop mynginx docker restart mynginx # Remove container (must stop first) docker rm mynginx # Force remove running container docker rm -f mynginx # View container logs docker logs -f mynginx # Follow logs with tail docker logs --tail 100 mynginx # Execute command in running container docker exec -it mynginx /bin/bash docker exec mynginx cat /etc/nginx/nginx.conf # Copy files between container và host docker cp mynginx:/etc/nginx/nginx.conf ./nginx.conf docker cp ./config.json mynginx:/app/config.json # Inspect container details docker inspect mynginx # View container resource usage docker stats mynginx # Pause/unpause container docker pause mynginx docker unpause mynginx
Dockerfile – Hướng dẫn chi tiết
Dockerfile định nghĩa cách image được built. Mỗi instruction tạo ra một layer trong image.
# Dockerfile example cho Node.js application # Base image FROM node:18-alpine # Set working directory WORKDIR /app # Copy package files first (for better layer caching) COPY package*.json ./ # Install dependencies RUN npm ci --only=production # Copy application code COPY . . # Set environment variables ENV NODE_ENV=production ENV PORT=3000 # Expose port EXPOSE 3000 # Define health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:3000/health || exit 1 # Run application CMD ["node", "server.js"]
Dockerfile Instructions
| Instruction | Mô tả | Example |
|---|---|---|
| FROM | Base image | FROM node:18-alpine |
| RUN | Execute command during build | RUN npm install |
| COPY | Copy files from context | COPY ./src /app/src |
| WORKDIR | Set working directory | WORKDIR /app |
| ENV | Environment variable | ENV NODE_ENV=production |
| EXPOSE | Declare port | EXPOSE 8080 |
| CMD | Command khi container starts | CMD [“node”, “app.js”] |
| ENTRYPOINT | Main command (hard to override) | ENTRYPOINT [“./entrypoint.sh”] |
| VOLUME | Declare volume mount point | VOLUME /data |
| USER | Set user for commands | USER node |
Docker Compose – Multi-container Applications
Docker Compose là tool định nghĩa và chạy multi-container applications. Thay vì run nhiều docker run commands, bạn define tất cả trong một file docker-compose.yml.
# docker-compose.yml cho full-stack application
version: "3.8"
services:
# Frontend service
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- REACT_APP_API_URL=http://api:3001
depends_on:
- api
networks:
- app-network
# Backend API service
api:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "3001:3001"
environment:
- DATABASE_URL=postgres://db:5432/myapp
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
networks:
- app-network
# PostgreSQL database
db:
image: postgres:15-alpine
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=secretpassword
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U admin -d myapp"]
interval: 5s
timeout: 5s
retries: 5
networks:
- app-network
# Redis cache
cache:
image: redis:7-alpine
networks:
- app-network
# Nginx reverse proxy
proxy:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- frontend
- api
networks:
- app-network
volumes:
db-data:
networks:
app-network:
driver: bridge
Docker Compose Commands
# Start all services docker compose up -d # Start with build docker compose up -d --build # View logs (all services) docker compose logs -f # View logs for specific service docker compose logs -f api # List services docker compose ps # Stop all services docker compose stop # Stop and remove containers docker compose down # Remove volumes too docker compose down -v # Scale service docker compose up -d --scale api=3 # Execute command in service docker compose exec api npm run migrate # Pull latest images docker compose pull
Docker Best Practices
1. Sử dụng Multi-stage Builds
Multi-stage builds cho phép bạn sử dụng multiple FROM statements để separate build environment và production environment, giảm image size đáng kể.
# Multi-stage build example FROM node:18 AS build WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:18-alpine AS production WORKDIR /app COPY --from=build /app/dist ./dist COPY --from=build /app/node_modules ./node_modules CMD ["node", "dist/index.js"] # Final image chỉ chứa production artifacts, không có dev dependencies
2. Không Run as Root
Containers chạy với root by default có thể là security risk. Tạo non-root user và use USER directive.
FROM node:18-alpine # Create non-root user RUN addgroup -g 1001 -S nodejs && adduser -S nodeuser -u 1001 WORKDIR /app COPY --chown=nodeuser:nodejs . . USER nodeuser CMD ["node", "index.js"]
3. Optimize Layer Caching
Docker caches layers khi không có changes. Put commands ít thay đổi lên đầu để leverage cache hiệu quả.
# Bad - package.json changes invalidates entire cache COPY . . RUN npm install # Good - changes to code don't invalidate npm install COPY package*.json ./ RUN npm install COPY . .
4. Use .dockerignore
.dockerignore file loại trừ không cần thiết files từ build context, giảm image size và tránh accidental secrets inclusion.
# .dockerignore node_modules npm-debug.log .git .gitignore .env .env.* *.md README.md Dockerfile docker-compose.yml .vscode .idea *.log
5. Thêm Health Checks
Health checks cho phép Docker và orchestration tools biết container health và perform auto-restart khi cần.
FROM nginx:alpine EXPOSE 80 # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost/ || exit 1 CMD ["nginx", "-g", "daemon off;"]
Docker Networking
Docker cung cấp several networking modes để containers communicate với nhau và external world:
| Driver | Mô tả | Use case |
|---|---|---|
| bridge | Default driver, creates internal network | Standalone containers |
| host | Remove network isolation, use host’s network | Performance-critical apps |
| overlay | Connect containers across multiple Docker hosts | Swarm services |
| macvlan | Assign MAC address to container | Legacy apps requiring direct network |
| none | Disable networking | Isolated containers |
Docker Volumes – Persistent Data
Containers are ephemeral – data bên trong container mất khi container bị remove. Docker volumes cung cấp persistent storage:
# Create volume docker volume create mydata # Run container with volume docker run -d -v mydata:/data --name db postgres:15 # Run container with bind mount (host directory) docker run -d -v /host/path:/container/path --name app myapp:latest # List volumes docker volume ls # Inspect volume docker volume inspect mydata # Remove unused volumes docker volume prune
Câu hỏi thường gặp (FAQ)
Docker và Docker Desktop khác nhau thế nào?
Docker Engine (dockerd) là runtime cho containers. Docker Desktop là full application bao gồm Docker Engine, Docker CLI, Docker Compose, Kubernetes, và GUI dashboard – dành cho developers trên Windows/Mac. Trên Linux, bạn cài Docker Engine trực tiếp.
Làm sao cleanup unused Docker resources?
Sử dụng Docker cleanup commands:
# Remove stopped containers docker container prune # Remove unused images docker image prune -a # Remove unused volumes docker volume prune # Remove unused networks docker network prune # Remove all (containers, networks, images without tag) docker system prune -a # Full cleanup including build cache docker builder prune -a
Docker container có persistent được không?
Mặc định container là ephemeral (stateless). Để persist data, sử dụng Docker volumes hoặc bind mounts. Nếu bạn dùng bind mount, data được lưu trên host filesystem và survive container restarts. Volume thì managed by Docker và có thể share giữa multiple containers.
Sự khác nhau giữa CMD và ENTRYPOINT?
CMD có thể be overridden bởi docker run command arguments. ENTRYPOINT thì hard to override – arguments được appended vào command. Common pattern là combine both: ENTRYPOINT defines main command, CMD provides default arguments that can be overridden.
Tại sao container exit ngay lập tức?
Container exits khi main process (PID 1) finishes. Nếu bạn run container without a persistent process (như bash), container sẽ exit ngay khi bash exits. Use -it flags để keep container running interactively, hoặc ensure main process runs indefinitely.
Làm sao debug container issues?
Các bước debug container:
# 1. Kiểm tra container logs docker logs container_name # 2. Inspect container details docker inspect container_name # 3. Check running processes docker top container_name # 4. View resource usage docker stats container_name # 5. Execute into container docker exec -it container_name /bin/bash # 6. Check network connectivity docker exec -it container_name ping target_host # 7. Verify port bindings docker port container_name
Docker Swarm và Kubernetes – cái nào nên dùng?
Xem thêm bài viết chi tiết: Docker Swarm vs Kubernetes. Tóm lại: Swarm đơn giản và native với Docker, phù hợp cho small-medium deployments. Kubernetes industry standard và phù hợp cho complex, large-scale production deployments.
Kết luận
Docker là công cụ mạnh mẽ giúp đơn giản hóa việc develop, test, và deploy applications. Với containerization, bạn có thể đảm bảo application behavior consistent across tất cả environments.
Những điểm quan trọng cần nhớ:
- Images are templates, containers are running instancesDockerfile defines how to build imagesDocker Compose manages multi-container appsAlways use multi-stage builds for productionNever run containers as root in production
Để tìm hiểu thêm về container orchestration, hãy tham khảo so sánh Docker Swarm vs Kubernetes trên vnhte.com.