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

レッスン 2: コンテナーと Docker — アプリケーション パッケージング プラットフォーム

コンテナと VM、Docker アーキテクチャ、Dockerfile のベスト プラクティス、マルチステージ ビルド、イメージ セキュリティ スキャン、および基本的なコンテナ ネットワーキング。

🏗️ アーキテクチャ — レッスン 2 レッスン 2: コンテナーと Docker — クローズド プラットフォーム アプリケーションパッケージ

クラウドネイティブのマイクロサービスアーキテクチャ

パート 1: クラウド ネイティブの基盤

xdev.asia

レッスン 2: コンテナーと Docker — アプリケーション パッケージング プラットフォーム

はじめに

コンテナはクラウドネイティブの基盤です。マイクロサービス アーキテクチャ内のすべてのサービスは、開発、ステージング、運用の間の一貫性を確保するためにコンテナ イメージにパッケージ化されています。この記事では、コンテナー、Docker、および重要なベスト プラクティスについて詳しく説明します。


1. コンテナと仮想マシンの比較

1.1 仮想マシン

┌──────────────────────────────────────┐
│           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    │
└────────────┴────────────┴────────────┘
  • 各 VM は 別の OS (別のカーネル) を実行します
  • リソース消費量: 500MB - OS のみ 2GB RAM
  • 起動:30秒~数分
  • 分離: 強力 (ハードウェアレベル)

1.2 コンテナ

┌──────────────────────────────────────┐
│           Host Hardware              │
├──────────────────────────────────────┤
│           Host OS (Linux Kernel)     │
├──────────────────────────────────────┤
│        Container Runtime (containerd)│
├────────────┬────────────┬────────────┤
│  Libs/Bins │  Libs/Bins │  Libs/Bins │
├────────────┼────────────┼────────────┤
│   App A    │   App B    │   App C    │
└────────────┴────────────┴────────────┘
  • すべてのコンテナはホスト OS の カーネルを共有
  • ライト: コンテナ イメージの場合は 5MB ~ 200MB
  • 起動: < 1 秒
  • Isolation: Process-level (namespaces + cgroups)

1.3 比較

基準VMコンテナ
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

コンテナは、Linux カーネルの 2 つのコア機能に基づいて構築されています。

名前空間 — 分離:

  • pid — プロセスの分離 (コンテナは自身のプロセスのみを認識します)
  • net — ネットワーク分離 (各コンテナには独自のネットワーク スタックがあります)
  • mnt — 独自のファイルシステムをマウントする
  • uts — プライベートホスト名
  • ipc — プロセス間通信を個別に行う
  • user — ユーザー/グループ ID の個別のマッピング

Cgroups — リソース制限:

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

3. Dockerfile Best Practices

3.1 Multi-stage Build

マルチステージ ビルドは、ビルド環境とランタイムを分離することで、コンパクトなイメージを作成するのに役立ちます。

# === 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"]

結果: イメージ ビルド ~800MB → イメージ ランタイム ~150MB

3.2 Layer Caching

Docker は各レイヤーをキャッシュします。キャッシュを最適化するために Dockerfile を調整します。

# ✅ 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"]

一緒に行く 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

同じネットワーク内では、サービスは サービス名 で相互に呼び出します。

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

5. Image Registry

5.1 レジストリを使用した CI/CD パイプライン

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. まとめ

ConceptKey Point
コンテナと VMコンテナーの軽量化、起動の高速化、高密度化
多段階ビルドビルドとランタイムを分離してイメージ サイズを削減する
レイヤーキャッシュキャッシュを最適化するために Dockerfile を調整する
非 root ユーザー常に非 root ユーザーでコンテナを実行する
画像スキャンプッシュ前にスキャンし、危険な画像をブロック
ネットワーキング同じネットワーク内のコンテナは、サービス名

次の記事: Kubernetes アーキテクチャ — Kubernetes が何百ものコンテナをオーケストレーションし、自動的にスケールし、自己修復し、ライフサイクル全体を管理する方法。