Skip to content
Published on

Docker完全攻略2025:コンテナ基礎からマルチステージビルド、Compose、本番デプロイまで

Authors

はじめに

コンテナ技術(ぎじゅつ)は、現代(げんだい)のソフトウェア開発(かいはつ)基盤(きばん)となっています。「(わたし)のローカルでは(うご)くのに?」という伝説的(でんせつてき)()(わけ)をなくしたのがDockerです。2013年の登場(とうじょう)以来、Dockerは開発(かいはつ)、テスト、デプロイのパラダイムを完全(かんぜん)変革(へんかく)し、2025年現在(げんざい)はKubernetes、サーバーレス、AIワークロードまでコンテナが基本(きほん)単位(たんい)として定着(ていちゃく)しています。

このガイドでは、コンテナの根本(こんぽん)原理(げんり)からDockerfile最適化(さいてきか)、マルチステージビルド、Docker Compose実践(じっせん)、セキュリティ、CI/CDパイプライン、本番(ほんばん)運用(うんよう)、Docker代替(だいたい)ツール、AIワークロードまで体系的(たいけいてき)解説(かいせつ)します。


1. コンテナとは何か — VMとの(ちが)

コンテナの定義(ていぎ)

コンテナは、アプリケーションとその依存関係(いぞんかんけい)を一つのパッケージにまとめ、隔離(かくり)された環境(かんきょう)実行(じっこう)する技術(ぎじゅつ)です。仮想(かそう)マシン(VM)とは(こと)なり、OSカーネルを共有(きょうゆう)するため、はるかに軽量(けいりょう)高速(こうそく)です。

Linuxの3つの核心(かくしん)技術(ぎじゅつ)

コンテナはLinuxカーネルの3つの機能(きのう)()()わせたものです。

1) Namespaces — 隔離(かくり)

プロセスが参照(さんしょう)できるシステムリソースの範囲(はんい)制限(せいげん)します。

Namespace隔離(かくり)対象(たいしょう)
PIDプロセスID
NETネットワークインターフェース、ルーティング
MNTファイルシステムマウントポイント
UTSホスト(めい)、ドメイン(めい)
IPCプロセス(かん)通信(つうしん)
USERユーザーおよびグループID
CGROUPcgroupルートディレクトリ

2) Cgroups — リソース制限(せいげん)

CPU、メモリ、ディスクI/O、ネットワーク帯域幅(たいいきはば)などのリソース使用量(しようりょう)制限(せいげん)します。

# cgroupでメモリを256MBに制限する例
sudo cgcreate -g memory:mycontainer
echo 268435456 | sudo tee /sys/fs/cgroup/memory/mycontainer/memory.limit_in_bytes

3) Union Filesystem — レイヤー構造(こうぞう)

複数

( ふくすう )

のファイルシステムレイヤーを一つに

統合

( とうごう )

して

表示

( ひょうじ )

する

技術

( ぎじゅつ )

です。DockerはOverlayFSを

使用

( しよう )

します。

  • ( )

    ( )

    専用

    ( せんよう )

    (Read-Only)レイヤー:ベースイメージ、パッケージインストールなど
  • ( )

    ( )

    可能

    ( かのう )

    (Read-Write)レイヤー:コンテナ

    実行

    ( じっこう )

    ( )

    変更

    ( へんこう )

    事項

    ( じこう )

コンテナ vs VM 比較(ひかく)

┌─────────────────────────────────────────────────────────────┐
│              コンテナアーキテクチャ                            │
├──────────┬──────────┬──────────┬──────────┐                 │
App AApp BApp CApp D   │                 │
├──────────┼──────────┼──────────┼──────────┤                 │
Bins/Bins/Bins/Bins/   │                 │
LibsLibsLibsLibs    │                 │
├──────────┴──────────┴──────────┴──────────┤                 │
Container Runtime                │                 │
├────────────────────────────────────────────┤                 │
Host OS Kernel                │                 │
├────────────────────────────────────────────┤                 │
Infrastructure                │                 │
└────────────────────────────────────────────┘                 │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
VMアーキテクチャ                            │
├──────────┬──────────┬──────────┬──────────┐                 │
App AApp BApp CApp D   │                 │
├──────────┼──────────┼──────────┼──────────┤                 │
Bins/Bins/Bins/Bins/   │                 │
LibsLibsLibsLibs    │                 │
├──────────┼──────────┼──────────┼──────────┤                 │
Guest OSGuest OSGuest OSGuest OS │                 │
├──────────┴──────────┴──────────┴──────────┤                 │
Hypervisor                    │                 │
├────────────────────────────────────────────┤                 │
Host OS                       │                 │
├────────────────────────────────────────────┤                 │
Infrastructure                │                 │
└────────────────────────────────────────────┘                 │
└─────────────────────────────────────────────────────────────┘
項目(こうもく)コンテナVM
起動(きどう)時間(じかん)ミリ(びょう)数分(すうふん)
イメージサイズMB単位(たんい)GB単位(たんい)
パフォーマンスオーバーヘッドほぼなし10〜20%
隔離(かくり)レベルプロセスレベルハードウェアレベル
OS対応(たいおう)ホストカーネル共有(きょうゆう)独立(どくりつ)OS可能(かのう)

OCI標準(ひょうじゅん)

OCI(Open Container Initiative)は、コンテナイメージとランタイムのオープン標準(ひょうじゅん)定義(ていぎ)しています。

  • Runtime Specification:コンテナの実行(じっこう)方法(ほうほう)標準化(ひょうじゅんか)
  • Image Specification:コンテナイメージフォーマットの標準化(ひょうじゅんか)
  • Distribution Specification:イメージ配布(はいふ)方法(ほうほう)標準化(ひょうじゅんか)

Docker、Podman、containerdはすべてOCI標準(ひょうじゅん)準拠(じゅんきょ)しているため、イメージの互換性(ごかんせい)があります。


2. Dockerアーキテクチャ

クライアント・サーバーモデル

Dockerはクライアント・サーバーアーキテクチャを採用(さいよう)しています。

┌─────────────┐     REST API     ┌─────────────────────┐
Docker     │ ──────────────>Docker DaemonCLI   (dockerd)│              │                 │                      │
│  docker run  │                 │  ┌─────────────────┐ │
│  docker build│                 │  │   containerd    │ │
│  docker pull │                 │  │                 │ │
└─────────────┘                 │  │  ┌───────────┐  │ │
                                │  │  │   runc    │  │ │
                                │  │  └───────────┘  │ │
                                │  └─────────────────┘ │
                                └─────────────────────┘
  • Docker CLI:ユーザーがコマンドを入力(にゅうりょく)するクライアント
  • Docker Daemon (dockerd):コンテナのライフサイクルを管理(かんり)するサーバープロセス
  • containerd:OCI準拠(じゅんきょ)のコンテナランタイムマネージャー
  • runc実際(じっさい)にコンテナを作成(さくせい)実行(じっこう)する(てい)レベルランタイム

4つの核心(かくしん)概念(がいねん)

1) イメージ(Image)

( )

( )

専用

( せんよう )

のテンプレートで、コンテナを

( つく )

るための

設計図

( せっけいず )

です。レイヤー

構造

( こうぞう )

により

効率的

( こうりつてき )

保存

( ほぞん )

転送

( てんそう )

されます。

# イメージ管理コマンド
docker images                    # ローカルイメージ一覧
docker pull nginx:1.25-alpine    # イメージダウンロード
docker image inspect nginx       # イメージ詳細情報
docker image prune               # 未使用イメージの整理

2) コンテナ(Container)

イメージの実行(じっこう)インスタンスです。イメージの(うえ)()()可能(かのう)なレイヤーが追加(ついか)されます。

# コンテナの実行と管理
docker run -d --name my-nginx -p 8080:80 nginx:1.25-alpine
docker ps                        # 実行中のコンテナ一覧
docker logs my-nginx             # ログ確認
docker exec -it my-nginx /bin/sh # コンテナ内部にアクセス
docker stop my-nginx             # 停止
docker rm my-nginx               # 削除

3) ボリューム(Volume)

コンテナのデータを永続的(えいぞくてき)保存(ほぞん)するメカニズムです。

# ボリュームの作成と使用
docker volume create my-data
docker run -d -v my-data:/app/data my-app
docker run -d -v /host/path:/container/path my-app  # バインドマウント

4) ネットワーク(Network)

コンテナ(かん)通信(つうしん)管理(かんり)します。

# ネットワークの作成と管理
docker network create my-network
docker run -d --network my-network --name api my-api
docker run -d --network my-network --name db postgres
# apiコンテナからdb:5432でアクセス可能

3. Dockerfileマスタークラス

主要(しゅよう)命令(めいれい)解説(かいせつ)

# ベースイメージの選択
FROM node:20-alpine

# メタデータの追加
LABEL maintainer="dev@example.com"
LABEL version="1.0"

# ビルド時変数(ビルド時のみ使用可能)
ARG NODE_ENV=production

# 環境変数(ランタイムでも使用可能)
ENV NODE_ENV=$NODE_ENV
ENV PORT=3000

# 作業ディレクトリの設定
WORKDIR /app

# ファイルコピー(COPYを推奨)
COPY package*.json ./

# コマンド実行
RUN npm ci --only=production

# ソースコードのコピー
COPY . .

# ポートのドキュメント化(実際にはポートを開かない)
EXPOSE 3000

# コンテナのヘルスチェック
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1

# 実行ユーザーの変更(セキュリティ)
USER node

# コンテナ起動時に実行するコマンド
ENTRYPOINT ["node"]
CMD ["server.js"]

COPYとADDの(ちが)

機能(きのう)COPYADD
ローカルファイルコピーOO
URLダウンロードXO
tar自動(じどう)展開(てんかい)XO
推奨度(すいしょうど)推奨(すいしょう)特殊(とくしゅ)場合(ばあい)のみ

結論(けつろん):ほとんどの場合(ばあい)COPY使用(しよう)してください。ADDはtar自動(じどう)展開(てんかい)必要(ひつよう)場合(ばあい)のみ使(つか)います。

CMDとENTRYPOINTの(ちが)

# CMDのみ使用 - docker run時に完全に上書き可能
CMD ["python", "app.py"]
# docker run my-image python test.py  (CMDがtest.pyに置換)

# ENTRYPOINTのみ使用 - 常に実行される
ENTRYPOINT ["python"]
# docker run my-image app.py  (python app.pyとして実行)

# ENTRYPOINT + CMD の組み合わせ(最も柔軟)
ENTRYPOINT ["python"]
CMD ["app.py"]
# docker run my-image         -> python app.py
# docker run my-image test.py -> python test.py

ARGとENV

# ARG: ビルド時にのみ存在(ランタイムには存在しない)
ARG BUILD_VERSION=1.0
RUN echo "Building version: $BUILD_VERSION"

# ENV: ビルド時 + ランタイムの両方で存在
ENV APP_VERSION=1.0
# コンテナ実行時にもAPP_VERSIONが使用可能

Dockerfile最適化(さいてきか)ベストプラクティス

1) レイヤーの順序(じゅんじょ)がキャッシュを決定(けってい)する

# 悪い例: ソース変更時にnpm installが再実行
COPY . .
RUN npm install

# 良い例: package.json変更時にのみnpm installが再実行
COPY package*.json ./
RUN npm ci
COPY . .

2) RUNコマンドの統合(とうごう)

# 悪い例: 3つのレイヤーを生成
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*

# 良い例: 1つのレイヤーを生成 + キャッシュクリア
RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    rm -rf /var/lib/apt/lists/*

3) .dockerignoreの活用(かつよう)

# .dockerignore
node_modules
.git
.env
*.md
Dockerfile
docker-compose*.yml
.github
coverage
dist

4) (ちい)さなベースイメージの選択(せんたく)

イメージサイズ用途(ようと)
ubuntu:22.04約77MBフルOS必要(ひつよう)()
node:20-slim約200MBほとんどのNode.jsアプリ
node:20-alpine約130MB軽量(けいりょう)Node.jsアプリ
alpine:3.19約7MB最小(さいしょう)ベース
distroless約2MB最小限(さいしょうげん)のランタイムのみ
scratch0MB静的(せいてき)バイナリ専用(せんよう)

4. マルチステージビルド — イメージを90%削減(さくげん)

マルチステージビルドは、ビルドツールと最終(さいしゅう)実行(じっこう)環境(かんきょう)分離(ぶんり)し、イメージサイズを劇的(げきてき)削減(さくげん)する技法(ぎほう)です。

Node.jsの(れい):1.2GBから120MBへ

# Stage 1: ビルド環境
FROM node:20 AS builder
WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build

# Stage 2: プロダクション環境
FROM node:20-alpine AS production
WORKDIR /app

# プロダクション依存関係のみインストール
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# ビルド成果物のみコピー
COPY --from=builder /app/dist ./dist

# セキュリティ: non-rootユーザー
USER node

EXPOSE 3000
CMD ["node", "dist/server.js"]

結果(けっか)node:20フルイメージ(約1.1GB)の()わりにAlpineベース(約130MB)+ ビルドツール除外(じょがい)最終(さいしゅう)120MB

Goの(れい):800MBから15MBへ

# Stage 1: ビルド
FROM golang:1.22-alpine AS builder
WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server .

# Stage 2: 最小イメージ
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app/server /server

EXPOSE 8080
ENTRYPOINT ["/server"]

結果(けっか):Goビルド環境(かんきょう)(約800MB)から静的(せいてき)バイナリのみ抽出(ちゅうしゅつ)して15MB以下(いか)

Java/Spring Bootの(れい):400MBから80MBへ

# Stage 1: ビルド
FROM eclipse-temurin:21-jdk AS builder
WORKDIR /app

COPY gradlew build.gradle settings.gradle ./
COPY gradle ./gradle
RUN ./gradlew dependencies --no-daemon

COPY src ./src
RUN ./gradlew bootJar --no-daemon

# Stage 2: ランタイム
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app

COPY --from=builder /app/build/libs/*.jar app.jar

RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

Pythonの(れい)

# Stage 1: 依存関係のビルド
FROM python:3.12-slim AS builder
WORKDIR /app

RUN pip install --no-cache-dir poetry
COPY pyproject.toml poetry.lock ./
RUN poetry export -f requirements.txt -o requirements.txt --without-hashes
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

# Stage 2: ランタイム
FROM python:3.12-slim
WORKDIR /app

COPY --from=builder /install /usr/local
COPY . .

RUN useradd --create-home appuser
USER appuser

EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app.main:app"]

ビルド結果(けっか)比較(ひかく)要約(ようやく)

言語(げんご)シングルステージマルチステージ削減率(さくげんりつ)
Node.js1.2GB120MB90%
Go800MB15MB98%
Java400MB80MB80%
Python900MB150MB83%

5. Docker Compose実践(じっせん)

docker-compose.ymlの基本(きほん)構造(こうぞう)

Docker Composeは、複数(ふくすう)のコンテナを1つのYAMLファイルで定義(ていぎ)管理(かんり)します。

# docker-compose.yml
version: '3.9'

services:
  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    ports:
      - '3000:3000'
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    healthcheck:
      test: ['CMD', 'wget', '--spider', 'http://localhost:3000/health']
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    restart: unless-stopped
    networks:
      - app-network

  db:
    image: postgres:16-alpine
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./init-scripts:/docker-entrypoint-initdb.d
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secret
    ports:
      - '5432:5432'
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U postgres']
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes --maxmemory 256mb
    volumes:
      - redis-data:/data
    ports:
      - '6379:6379'
    networks:
      - app-network

  nginx:
    image: nginx:1.25-alpine
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
    depends_on:
      - api
    networks:
      - app-network

volumes:
  postgres-data:
    driver: local
  redis-data:
    driver: local

networks:
  app-network:
    driver: bridge

環境(かんきょう)変数(へんすう)とSecrets管理(かんり)

# .envファイルの使用
services:
  api:
    env_file:
      - .env
      - .env.production

# Docker Secrets(Swarmモード)
services:
  api:
    secrets:
      - db_password
      - api_key

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    external: true

Composeの主要(しゅよう)コマンド

# サービスの起動(バックグラウンド)
docker compose up -d

# サービスログの確認
docker compose logs -f api

# サービスのスケーリング
docker compose up -d --scale api=3

# サービスの再ビルド + 再起動
docker compose up -d --build

# サービスの停止とリソースのクリーンアップ
docker compose down

# ボリュームも含めてすべて削除
docker compose down -v

# 特定サービスのみ再起動
docker compose restart api

# 実行中のサービスのステータス確認
docker compose ps

開発(かいはつ)環境(かんきょう)本番(ほんばん)環境(かんきょう)分離(ぶんり)

# docker-compose.yml(共通)
services:
  api:
    build: ./api

# docker-compose.override.yml(開発環境 - 自動ロード)
services:
  api:
    volumes:
      - ./api:/app    # ホットリロード用マウント
    environment:
      - DEBUG=true
    command: npm run dev

# docker-compose.prod.yml(本番)
services:
  api:
    environment:
      - NODE_ENV=production
    deploy:
      replicas: 3
      resources:
        limits:
          memory: 512M
          cpus: "0.5"
# 開発環境(overrideファイルが自動ロード)
docker compose up

# 本番環境
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

6. ネットワーキング深掘(ふかぼ)

Dockerネットワークドライバー

ドライバー説明(せつめい)ユースケース
bridgeデフォルトドライバー、同一(どういつ)ホスト(ない)のコンテナ通信(つうしん)シングルホスト開発(かいはつ)環境(かんきょう)
hostホストネットワークスタックを直接(ちょくせつ)使用(しよう)パフォーマンスが重要(じゅうよう)場合(ばあい)
overlay複数(ふくすう)Dockerホスト(かん)通信(つうしん)Swarm、マルチホスト
macvlanコンテナに実際(じっさい)のMACアドレスを()()レガシーネットワーク統合(とうごう)
noneネットワーク無効化(むこうか)セキュリティ隔離(かくり)

コンテナDNS解決(かいけつ)

( おな )

じDockerネットワーク

( じょう )

のコンテナは、サービス

( めい )

( たが )

いを

発見

( はっけん )

できます。

# カスタムネットワークの作成
docker network create my-app

# 同じネットワークでコンテナを実行
docker run -d --name api --network my-app my-api-image
docker run -d --name db --network my-app postgres

# apiコンテナ内部からdbコンテナにアクセス
# ホスト名 "db" が自動的に解決される
curl http://db:5432

ポートマッピング戦略(せんりゃく)

# 特定のポートマッピング
docker run -p 8080:80 nginx

# 特定のインターフェースにのみバインド
docker run -p 127.0.0.1:8080:80 nginx

# ランダムなホストポートの割り当て
docker run -p 80 nginx

# 複数のポートマッピング
docker run -p 80:80 -p 443:443 nginx

サービスディスカバリパターン

# Docker Composeでの自動サービスディスカバリ
services:
  api-gateway:
    image: nginx
    depends_on:
      - user-service
      - order-service

  user-service:
    image: my-user-service
    # api-gatewayからhttp://user-service:3000でアクセス可能

  order-service:
    image: my-order-service
    # api-gatewayからhttp://order-service:3000でアクセス可能

7. セキュリティベストプラクティス

1) Non-rootユーザーでの実行(じっこう)

# Node.js - 組み込みのnodeユーザーを活用
FROM node:20-alpine
WORKDIR /app
COPY --chown=node:node . .
RUN npm ci --only=production
USER node
CMD ["node", "server.js"]

# カスタムユーザーの作成
FROM python:3.12-slim
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser
CMD ["python", "app.py"]

2) ()()専用(せんよう)ファイルシステム

docker run --read-only --tmpfs /tmp --tmpfs /var/run my-app
# Docker Composeで
services:
  api:
    read_only: true
    tmpfs:
      - /tmp
      - /var/run

3) イメージセキュリティスキャン

# Trivyで脆弱性をスキャン
trivy image my-app:latest

# 深刻度でフィルタリング
trivy image --severity HIGH,CRITICAL my-app:latest

# Docker Scout(Docker Desktop内蔵)
docker scout cves my-app:latest
docker scout recommendations my-app:latest

# Snyk
snyk container test my-app:latest

4) Secrets管理(かんり)絶対(ぜったい)にDockerfileに()れないこと)

# 絶対にやってはいけません
ENV API_KEY=sk-1234567890
COPY .env /app/.env

# 正しい方法: ビルド時にシークレットをマウント(BuildKit)
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
# ビルド時にシークレットを渡す
DOCKER_BUILDKIT=1 docker build --secret id=npmrc,src=.npmrc -t my-app .

5) ルートレスDocker

# ルートレスモードでDockerをインストール
dockerd-rootless-setuptool.sh install

# 確認
docker info | grep -i rootless
# Security Options: rootless

6) Content Trustとイメージ署名(しょめい)

# Docker Content Trustを有効化
export DOCKER_CONTENT_TRUST=1

# 署名されたイメージのみPull可能
docker pull my-registry/my-app:latest  # 署名がなければ失敗

# Cosignでイメージに署名(Sigstore)
cosign sign my-registry/my-app:latest
cosign verify my-registry/my-app:latest

7) セキュリティチェックリスト

[セキュリティチェックリスト]
- Non-rootユーザーで実行(USERディレクティブ)
- 最小ベースイメージの使用(Alpine、distroless、scratch)
- イメージ脆弱性の定期スキャン(Trivy、Snyk、Scout)
- Dockerfileにシークレット/認証情報を絶対に含めない
- 読み取り専用ファイルシステムの使用
- ネットワーク露出の最小化
- リソース制限の設定(メモリ、CPU)
- Docker Content Trustの有効化
- ベースイメージの定期的な更新
- 不要なパッケージ/ツールの削除

8. CI/CDパイプライン

GitHub Actions + Dockerビルド/プッシュ

# .github/workflows/docker-build.yml
name: Docker Build and Push

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: my-org/my-app

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: my-username
          password: my-token

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/my-org/my-app
          tags: |
            type=ref,event=branch
            type=sha,prefix=
            type=semver,pattern=v{{version}}

      - name: Build and Push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: steps.meta.outputs.tags
          labels: steps.meta.outputs.labels
          cache-from: type=gha
          cache-to: type=gha,mode=max
          platforms: linux/amd64,linux/arm64

マルチプラットフォームビルド(amd64 + arm64)

# Buildxビルダーの作成
docker buildx create --name multiarch --use

# マルチプラットフォームでビルドおよびプッシュ
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --tag my-registry/my-app:latest \
  --push .

CIでのレイヤーキャッシュ

# GitHub Actions Cache
- name: Build with cache
  uses: docker/build-push-action@v5
  with:
    cache-from: type=gha
    cache-to: type=gha,mode=max

# レジストリベースのキャッシュ
- name: Build with registry cache
  uses: docker/build-push-action@v5
  with:
    cache-from: type=registry,ref=ghcr.io/my-org/my-app:buildcache
    cache-to: type=registry,ref=ghcr.io/my-org/my-app:buildcache,mode=max

主要(しゅよう)コンテナレジストリの比較(ひかく)

レジストリ無料(むりょう)ティア特徴(とくちょう)
Docker Hubプライベートリポ1つ最大(さいだい)のパブリックレジストリ
GitHub Container Registry(GHCR)パブリック無制限(むせいげん)GitHub Actions統合(とうごう)
Amazon ECR500MBフリーティアAWSサービス統合(とうごう)
Google Artifact Registry500MBフリーティアGCPサービス統合(とうごう)
Azure Container RegistryなしAzureサービス統合(とうごう)

9. 本番(ほんばん)運用(うんよう)

ロギング戦略(せんりゃく)

# コンテナのログドライバー設定
docker run -d \
  --log-driver=json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  my-app

# syslogドライバー
docker run -d \
  --log-driver=syslog \
  --log-opt syslog-address=tcp://logserver:514 \
  my-app
# Docker Composeでのロギング設定
services:
  api:
    logging:
      driver: json-file
      options:
        max-size: '10m'
        max-file: '3'

ロギングのベストプラクティス:アプリケーションは(つね)にstdout/stderrにログを出力(しゅつりょく)してください。ファイルに直接(ちょくせつ)()()まないでください。Dockerがログドライバーを(つう)じて収集(しゅうしゅう)します。

モニタリング:Prometheus + cAdvisor

# docker-compose.monitoring.yml
services:
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - '9090:9090'

  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - '8080:8080'

  grafana:
    image: grafana/grafana:latest
    volumes:
      - grafana-data:/var/lib/grafana
    ports:
      - '3000:3000'
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin

volumes:
  grafana-data:

リソース制限(せいげん)

# メモリ制限: 512MB(超過時OOM Kill)
docker run -m 512m my-app

# CPU制限: 1.5コア
docker run --cpus="1.5" my-app

# 組み合わせ
docker run -m 512m --cpus="1.5" --memory-swap=1g my-app
# Docker Composeで
services:
  api:
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: '1.5'
        reservations:
          memory: 256M
          cpus: '0.5'

グレースフルシャットダウン(SIGTERM処理(しょり)

// Node.jsの例
process.on('SIGTERM', async () => {
  console.log('SIGTERM received. Graceful shutdown...')

  // 新しいリクエストを拒否
  server.close(async () => {
    // DB接続を閉じる
    await db.close()
    // Redis接続を閉じる
    await redis.quit()

    console.log('All connections closed. Exiting.')
    process.exit(0)
  })

  // 30秒後に強制終了
  setTimeout(() => {
    console.error('Forced shutdown after timeout')
    process.exit(1)
  }, 30000)
})
# Dockerfileでの正しいENTRYPOINT形式
# exec形式を使用(SIGTERMがアプリに直接配信される)
ENTRYPOINT ["node", "server.js"]

# shell形式は使用禁止(SIGTERMがshにのみ配信される)
# ENTRYPOINT node server.js  # これはやめてください

ヘルスチェックパターン

# Dockerfileでのヘルスチェック
HEALTHCHECK --interval=30s --timeout=3s --start-period=30s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1
# Docker Composeでのヘルスチェック
services:
  api:
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:3000/health']
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  db:
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U postgres']
      interval: 10s
      timeout: 5s
      retries: 5

10. Docker代替(だいたい)ツール:Podman、containerd、nerdctl

Podman — ルートレス、デーモンレス

Podmanは、Red Hatが開発(かいはつ)したDocker互換(ごかん)のコンテナエンジンです。

# Dockerとほぼ同じCLI
podman run -d -p 8080:80 nginx
podman ps
podman images

# Docker互換のためのエイリアス
alias docker=podman
特徴(とくちょう)DockerPodman
アーキテクチャデーモン基盤(きばん)(dockerd)デーモンなし(フォークモデル)
root必要(ひつよう)基本的(きほんてき)必要(ひつよう)デフォルトでルートレス
Compose対応(たいおう)docker composepodman-compose
システム統合(とうごう)独自(どくじ)systemd統合(とうごう)
Pod対応(たいおう)XO(Kubernetes Pod互換(ごかん)

containerd — Kubernetesデフォルトランタイム

containerdは、Dockerから分離(ぶんり)されたコンテナランタイムで、Kubernetesのデフォルトランタイムです。

# ctr - containerdネイティブCLI(低レベル)
ctr images pull docker.io/library/nginx:latest
ctr run docker.io/library/nginx:latest my-nginx

nerdctl — containerd(よう)Docker互換(ごかん)CLI

# Dockerと同じUX
nerdctl run -d -p 8080:80 nginx
nerdctl compose up -d
nerdctl build -t my-app .

# 追加機能: イメージ暗号化
nerdctl image encrypt --recipient jwe:public-key.pem my-app encrypted-app

ツール選択(せんたく)ガイド

シナリオ推奨(すいしょう)ツール
ローカル開発(かいはつ)Docker Desktopまたは Podman
CI/CDパイプラインDocker(BuildKit)
Kubernetesランタイムcontainerd
セキュリティ重視(じゅうし)環境(かんきょう)Podman(ルートレス)
Docker互換(ごかん) + containerdnerdctl

11. Docker + AIワークロード

NVIDIA Container Toolkit

AI/MLワークロードでGPUをコンテナに(わた)すには、NVIDIA Container Toolkitが必要(ひつよう)です。

# NVIDIA Container Toolkitのインストール
distribution=ubuntu22.04
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
  sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg

# パッケージのインストール
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit

# Dockerランタイムの設定
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

GPUパススルー

# すべてのGPUを使用
docker run --gpus all nvidia/cuda:12.3-base nvidia-smi

# 特定のGPUのみ使用
docker run --gpus '"device=0,1"' my-ml-app

# Docker Composeで
services:
  ml-training:
    image: my-ml-app
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 2
              capabilities: [gpu]

MLモデルサービングコンテナ

# PyTorchモデルサービングDockerfile
FROM pytorch/pytorch:2.2.0-cuda12.1-cudnn8-runtime

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY model/ ./model/
COPY serve.py .

EXPOSE 8000

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD curl -f http://localhost:8000/health || exit 1

CMD ["python", "serve.py"]
# TensorFlow Serving
services:
  tf-serving:
    image: tensorflow/serving:latest-gpu
    ports:
      - '8501:8501'
    volumes:
      - ./models:/models
    environment:
      - MODEL_NAME=my_model
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

  triton-server:
    image: nvcr.io/nvidia/tritonserver:24.01-py3
    ports:
      - '8000:8000'
      - '8001:8001'
      - '8002:8002'
    volumes:
      - ./model-repository:/models
    command: tritonserver --model-repository=/models
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

主要(しゅよう)MLフレームワークコンテナ

フレームワーク公式(こうしき)イメージGPU対応(たいおう)
PyTorchpytorch/pytorchO
TensorFlowtensorflow/tensorflowO
NVIDIA Tritonnvcr.io/nvidia/tritonserverO
Hugging Face TGIghcr.io/huggingface/text-generation-inferenceO
vLLMvllm/vllm-openaiO

クイズ

DockerとコンテナについてのDockerとコンテナについての理解(りかい)確認(かくにん)しましょう。

Q1:コンテナがVMよりも軽量(けいりょう)である根本的(こんぽんてき)理由(りゆう)は?

正解(せいかい):コンテナはホストOSのカーネルを共有(きょうゆう)するからです。VMはそれぞれ独立(どくりつ)したゲストOSを()ち、(すう)GBのオーバーヘッドがありますが、コンテナはLinuxのnamespacesとcgroupsを使(つか)ってプロセスレベルで隔離(かくり)するため、MB単位(たんい)のサイズとミリ(びょう)単位(たんい)起動(きどう)時間(じかん)実現(じつげん)します。

Q2:DockerfileにおけるCOPYとADDの(ちが)い、そしてCOPYが推奨(すいしょう)される理由(りゆう)説明(せつめい)してください。

正解(せいかい):COPYはローカルファイル/ディレクトリをイメージにコピーする単純(たんじゅん)機能(きのう)のみを提供(ていきょう)します。ADDは追加(ついか)でURLダウンロードとtar自動(じどう)展開(てんかい)機能(きのう)があります。COPYが推奨(すいしょう)される理由(りゆう)は、(1)動作(どうさ)明示的(めいじてき)予測(よそく)可能(かのう)、(2)ADDのURLダウンロードがキャッシュ無効化(むこうか)()()こす可能性(かのうせい)がある、(3)意図(いと)しないtar展開(てんかい)(ふせ)ぐためです。tar自動(じどう)展開(てんかい)必要(ひつよう)場合(ばあい)のみADDを使(つか)ってください。

Q3:マルチステージビルドでGoイメージを800MBから15MBに削減(さくげん)できる理由(りゆう)は?

正解(せいかい):Goは静的(せいてき)バイナリ(static binary)をコンパイルできるからです。CGO_ENABLED=0でビルドすると、外部(がいぶ)Cライブラリ依存(いぞん)のない独立(どくりつ)実行(じっこう)ファイルが生成(せいせい)され、これをscratch((から)のイメージ)(じょう)にコピーすると、バイナリサイズそのものが最終(さいしゅう)イメージサイズになります。ビルドツール(コンパイラ、パッケージマネージャーなど)がすべて除去(じょきょ)されるため、サイズが劇的(げきてき)削減(さくげん)されます。

Q4:Dockerfileのレイヤー順序(じゅんじょ)がビルドキャッシュに重要(じゅうよう)理由(りゆう)(れい)使(つか)って説明(せつめい)してください。

正解(せいかい):Dockerは(かく)レイヤーをキャッシュし、あるレイヤーが変更(へんこう)されると、それ以降(いこう)のすべてのレイヤーを(さい)ビルドします。(たと)えば、Node.jsアプリでCOPY . .の(あと)にRUN npm installを(おこな)うと、ソースコードが1文字(もじ)()わるだけでもnpm installが(さい)実行(じっこう)されます。()わりに、package.jsonだけを(さき)にCOPYし、npm installを実行(じっこう)してからソースをコピーすると、package.jsonが変更(へんこう)されない(かぎ)依存関係(いぞんかんけい)インストールレイヤーがキャッシュから再利用(さいりよう)され、ビルド時間(じかん)大幅(おおはば)短縮(たんしゅく)されます。

Q5:Dockerのセキュリティでnon-rootユーザーで実行(じっこう)すべき理由(りゆう)方法(ほうほう)は?

正解(せいかい):コンテナがrootで実行(じっこう)されていると、コンテナエスケープ(container escape)の脆弱性(ぜいじゃくせい)発生(はっせい)した場合(ばあい)攻撃者(こうげきしゃ)がホストシステムのroot権限(けんげん)取得(しゅとく)できる可能性(かのうせい)があります。DockerfileのUSERディレクティブを使(つか)ってnon-rootユーザーを指定(してい)する必要(ひつよう)があります。Node.jsイメージには()()みのnodeユーザーがあり、(ほか)のイメージではRUN groupadd/useraddでユーザーを作成(さくせい)し、USERディレクティブで()()えます。ファイルの所有権(しょゆうけん)はCOPY --chownオプションで設定(せってい)します。


参考(さんこう)資料(しりょう)

  1. Docker公式(こうしき)ドキュメント(もっと)信頼(しんらい)できるリファレンス
  2. Dockerfileベストプラクティス公式(こうしき)最適化(さいてきか)ガイド
  3. Docker Composeスペック — Composeファイルリファレンス
  4. OCI仕様(しよう) — コンテナ標準(ひょうじゅん)仕様(しよう)
  5. NVIDIA Container Toolkit — GPUコンテナガイド
  6. Trivyセキュリティスキャナー — コンテナ脆弱性(ぜいじゃくせい)スキャン
  7. Podman公式(こうしき)ドキュメント — Docker代替(だいたい)コンテナエンジン
  8. containerd公式(こうしき)ドキュメント業界(ぎょうかい)標準(ひょうじゅん)コンテナランタイム
  9. Docker BuildKitガイド高度(こうど)なビルド機能(きのう)
  10. Sigstore/Cosign — コンテナイメージ署名(しょめい)
  11. cAdvisor — コンテナリソースモニタリング
  12. Distrolessイメージ最小(さいしょう)コンテナイメージ
  13. Dockerセキュリティチートシート — OWASPセキュリティチェックリスト
  14. マルチプラットフォームDockerビルド — クロスプラットフォームビルドガイド
  15. Docker + AI/MLガイド — Docker GenAIスタック
  16. Hugging Face TGI — LLMモデルサービング
  17. vLLMプロジェクト高性能(こうせいのう)LLM推論(すいろん)エンジン