Chuyển đến nội dung chính

Bài 2: Container & Docker — Nền tảng đóng gói ứng dụng

Container vs VM, Docker architecture, Dockerfile best practices, multi-stage build, image security scanning, và container networking cơ bản.

🏗️ Kiến trúc — Bài 2 Bài 2: Container & Docker — Nền tảng đóng gói ứng dụng

Cloud Native Microservices Architecture

Phần 1: Cloud Native Foundations

xdev.asia

Bài 2: Container & Docker — Nền tảng đóng gói ứng dụng

Giới thiệu

Container là nền tảng của Cloud Native. Mọi service trong kiến trúc microservices đều được đóng gói thành container image để đảm bảo tính nhất quán giữa development, staging và production. Bài này đi sâu vào container, Docker, và các best practices cần thiết.


1. Container vs Virtual Machine

1.1 Virtual Machine

┌──────────────────────────────────────┐
│           Host Hardware              │
├──────────────────────────────────────┤
│           Host OS (Linux)            │
├──────────────────────────────────────┤
│           Hypervisor (KVM/ESXi)      │
├────────────┬────────────┬────────────┤
│  Guest OS  │  Guest OS  │  Guest OS  │
│  (Ubuntu)  │  (CentOS)  │  (Debian)  │
├────────────┼────────────┼────────────┤
│  Libs/Bins │  Libs/Bins │  Libs/Bins │
├────────────┼────────────┼────────────┤
│   App A    │   App B    │   App C    │
└────────────┴────────────┴────────────┘
  • Mỗi VM chạy một OS riêng (kernel riêng)
  • Tốn tài nguyên: 500MB - 2GB RAM chỉ cho OS
  • Khởi động: 30 giây - vài phút
  • Isolation: Mạnh (hardware-level)

1.2 Container

┌──────────────────────────────────────┐
│           Host Hardware              │
├──────────────────────────────────────┤
│           Host OS (Linux Kernel)     │
├──────────────────────────────────────┤
│        Container Runtime (containerd)│
├────────────┬────────────┬────────────┤
│  Libs/Bins │  Libs/Bins │  Libs/Bins │
├────────────┼────────────┼────────────┤
│   App A    │   App B    │   App C    │
└────────────┴────────────┴────────────┘
  • Tất cả container chia sẻ kernel của Host OS
  • Nhẹ: 5MB - 200MB cho container image
  • Khởi động: < 1 giây
  • Isolation: Process-level (namespaces + cgroups)

1.3 So sánh

Tiêu chíVMContainer
Startup time30s - 5min< 1s
Image sizeGBMB
RAM overhead500MB+ per VM~0 overhead
IsolationStrong (hypervisor)Process-level (namespace)
Density10-20 VMs per host100-1000 containers per host
PortabilityModerateExcellent

2. Docker Architecture

2.1 Core Components

┌─────────────────────────────────────────────────┐
│                Docker Client (CLI)               │
│  docker build, docker run, docker push           │
└───────────────────────┬─────────────────────────┘
                        │ REST API
┌───────────────────────▼─────────────────────────┐
│                Docker Daemon (dockerd)            │
│                                                   │
│  ┌──────────┐  ┌──────────────┐  ┌────────────┐ │
│  │  Images   │  │  Containers  │  │  Volumes   │ │
│  └──────────┘  └──────────────┘  └────────────┘ │
│  ┌──────────┐  ┌──────────────┐                  │
│  │ Networks  │  │  containerd  │                  │
│  └──────────┘  └──────┬───────┘                  │
└──────────────────────┬──────────────────────────┘
                       │
┌──────────────────────▼──────────────────────────┐
│              Container Runtime (runc)             │
│         Linux Kernel: namespaces + cgroups        │
└─────────────────────────────────────────────────┘

2.2 Linux Kernel Features

Container được xây dựng trên 2 tính năng cốt lõi của Linux kernel:

Namespaces — Cách ly (isolation):

  • pid — Process isolation (container chỉ thấy processes của mình)
  • net — Network isolation (mỗi container có network stack riêng)
  • mnt — Mount filesystem riêng
  • uts — Hostname riêng
  • ipc — Inter-process communication riêng
  • user — User/group ID mapping riêng

Cgroups — Giới hạn tài nguyên:

  • CPU (millicores)
  • Memory (bytes)
  • Disk I/O
  • Network bandwidth

3. Dockerfile Best Practices

3.1 Multi-stage Build

Multi-stage build giúp tạo image nhỏ gọn bằng cách tách build environment và runtime:

# === Stage 1: Build ===
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .
RUN npm run build

# === Stage 2: Runtime ===
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
CMD ["node", "dist/main.js"]

Kết quả: Image build ~800MB → Image runtime ~150MB

3.2 Layer Caching

Docker cache mỗi layer. Sắp xếp Dockerfile để tối ưu cache:

# ✅ Tốt: Dependencies ít thay đổi → cache được layer này
COPY package*.json ./
RUN npm ci
# Source code thay đổi thường xuyên → chỉ invalidate từ đây
COPY . .
RUN npm run build

# ❌ Xấu: Mỗi lần thay đổi code → rebuild tất cả
COPY . .
RUN npm ci && npm run build

3.3 Security Best Practices

# 1. Dùng specific version, KHÔNG dùng :latest
FROM node:20.11-alpine3.19

# 2. Chạy với non-root user
RUN addgroup -S app && adduser -S app -G app
USER app

# 3. Không copy file nhạy cảm
# .dockerignore:
# .env
# .git
# node_modules
# *.secret

# 4. Scan image trước khi push
# trivy image myapp:1.0.0

3.4 Java / Go / Python Examples

Java (Spring Boot):

FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY gradle/ gradle/
COPY gradlew build.gradle.kts settings.gradle.kts ./
RUN ./gradlew dependencies --no-daemon
COPY src/ src/
RUN ./gradlew bootJar --no-daemon

FROM eclipse-temurin:21-jre-alpine
RUN addgroup -S app && adduser -S app -G app
COPY --from=build /app/build/libs/*.jar /app/app.jar
USER app
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

Go:

FROM golang:1.22-alpine AS build
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /server ./cmd/server

FROM scratch
COPY --from=build /server /server
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/server"]

Go với scratch base image → image size ~10-15MB.


4. Container Networking

4.1 Docker Network Types

Bridge (default)     Host              None         Overlay (Swarm/K8s)
┌────────────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────────┐
│ Container A    │  │Container │  │Container │  │ Host 1    Host 2 │
│ 172.17.0.2     │  │shares    │  │no network│  │ ┌─────┐  ┌─────┐│
│ Container B    │  │host's    │  │isolated  │  │ │ C-A │  │ C-B ││
│ 172.17.0.3     │  │network   │  │          │  │ └──┬──┘  └──┬──┘│
│      │         │  │stack     │  │          │  │    └────┬────┘   │
│ docker0 bridge │  │          │  │          │  │   VXLAN overlay  │
└────────────────┘  └──────────┘  └──────────┘  └──────────────────┘

4.2 Docker Compose Networking

services:
  order-service:
    build: ./order-service
    ports:
      - "8080:8080"
    networks:
      - backend
    depends_on:
      postgres:
        condition: service_healthy

  payment-service:
    build: ./payment-service
    ports:
      - "8081:8080"
    networks:
      - backend

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: orders
      POSTGRES_USER: app
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - backend
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      timeout: 3s
      retries: 5

networks:
  backend:
    driver: bridge

volumes:
  pgdata:

secrets:
  db_password:
    file: ./secrets/db_password.txt

Trong cùng network, services gọi nhau qua tên service:

order-service → http://payment-service:8080/api/pay

5. Image Registry

5.1 Quy trình CI/CD với Registry

Developer → Git Push → CI Pipeline:
  1. docker build -t registry.example.com/order-service:v1.2.3
  2. trivy image registry.example.com/order-service:v1.2.3
  3. docker push registry.example.com/order-service:v1.2.3
  4. Update K8s manifest → ArgoCD sync

Registry Options:
├── Docker Hub (public)
├── Harbor (self-hosted, recommended)
├── AWS ECR
├── Google Artifact Registry
└── GitHub Container Registry (ghcr.io)

5.2 Image Tagging Strategy

# ✅ Semantic versioning
registry.example.com/order-service:1.2.3
registry.example.com/order-service:1.2.3-alpine

# ✅ Git commit hash (immutable)
registry.example.com/order-service:abc123f

# ❌ KHÔNG dùng :latest trong production
registry.example.com/order-service:latest

6. Tổng kết

ConceptKey Point
Container vs VMContainer nhẹ hơn, khởi động nhanh hơn, density cao hơn
Multi-stage BuildTách build và runtime để giảm image size
Layer CachingSắp xếp Dockerfile để tối ưu cache
Non-root UserLuôn chạy container với non-root user
Image ScanningScan trước khi push, block vulnerable images
NetworkingContainers trong cùng network gọi nhau qua service name

Bài tiếp theo: Kubernetes Architecture — Cách Kubernetes orchestrate hàng trăm container, tự động scale, self-heal và manage toàn bộ lifecycle.