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 wizard

Cá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.

Chào các bạn mình là Quốc Hùng , mình sinh ra thuộc cung song tử ,song tử luôn khẳng định chính mình ,luôn luôn phấn đấu vượt lên phía trước ,mình sinh ra và lớn lên tại vùng đất võ cổ truyền ,đam mê của mình là coder ,ngày đi học tối về viết blog ...