C
DevOps/コンテナ/Lesson 02

Docker — コンテナ・イメージ・Dockerfile

45分·theory

Docker — コンテナ・イメージ・Dockerfile

🎯 このレッスンを読み終えたら

このレッスンをすべて読み終えると、以下の3つを自信を持って実践できるようになります。

  • ✅ Docker の4要素:イメージ・コンテナ・ボリューム・ネットワーク
  • ✅ Dockerfile のマルチステージビルド + alpine
  • ✅ docker-compose による複数コンテナの構成 (DB + Redis + アプリ)

学習目標をチェックリストとして手元に置き、すべてに答えられるようになったらレッスンを閉じましょう。

Docker vs VM + 基本概念

一言で言うと: VM = 家丸ごと借りる、コンテナ = 部屋一つ借りる。同じ OS カーネルを共有し、リソース消費が少ない。

項目VMコンテナ (Docker)
分離強い (OS 全体)中程度 (プロセス・名前空間)
起動分単位秒単位
サイズGBMB
リソース重い軽い
ホスト異なる OS も可同じ OS カーネル (Linux on Linux など)

基本概念:

用語意味
イメージコンテナの設計図。不変 (read-only)
コンテナイメージの実行インスタンス
レジストリイメージリポジトリ (Docker Hub・ECR・GCR)
レイヤーイメージ = レイヤーの積み重ね。キャッシュ効率が高い
ボリューム永続データ (コンテナを削除しても保持される)
ネットワークbridge・host・overlay (Swarm)

Dockerfile + マルチステージビルド

Dockerfile — イメージビルドの仕様書:

dockerfile
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Run (smaller image)
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
CMD ["npm", "start"]

主要な命令:

命令用途
FROMベースイメージ
WORKDIR作業ディレクトリ
COPY / ADDファイルのコピー (ADD はアーカイブ展開・URL も対応)
RUNビルド時にコマンドを実行
CMDコンテナ起動コマンド
ENTRYPOINT実行ファイル (引数を受け取る形式)
EXPOSE公開ポート (ドキュメント用)
ENV環境変数
ARGビルド時変数
HEALTHCHECKヘルスチェックコマンド

最適化のヒント:

  • 変更頻度の高いファイルは最後に COPY する (キャッシュ効率 ↑)
  • .dockerignorenode_modules.git を除外する
  • マルチステージビルド — ビルドツールを除外して小さいイメージを作成
  • Alpine ベース (5 MB) を優先し、互換性の問題がある場合は distroless にフォールバック
💻 📌 Docker コマンド
# === イメージ ===
docker build -t myapp:1.0 .          # ビルド
docker images                        # 一覧
docker rmi myapp:1.0                 # 削除
docker tag myapp:1.0 user/myapp:1.0  # タグ
docker push user/myapp:1.0           # レジストリ push
docker pull nginx:latest             # pull

# === コンテナ ===
docker run -d -p 3000:3000 --name web myapp:1.0
docker ps                            # 実行中
docker ps -a                         # 全て (停止含む)
docker logs -f web                   # ログリアルタイム
docker exec -it web bash             # コンテナに入る
docker stop web                      # 停止
docker rm web                        # 削除
docker rm -f $(docker ps -aq)        # 全てのコンテナを強制削除

# === ボリューム ===
docker volume create mydata
docker run -v mydata:/data myapp
docker run -v $(pwd):/app myapp      # bind mount (ローカル開発)

# === ネットワーク ===
docker network create mynet
docker run --network mynet --name db postgres
docker run --network mynet --name web myapp  # web → db ホスト名でアクセス

# === Docker Compose (複数コンテナ) ===
# docker-compose.yml 作成後:
docker-compose up -d                 # 全体開始
docker-compose logs -f               # 全てのログ
docker-compose down                  # クリーンアップ

# === 診断 ===
docker stats                         # リソース使用リアルタイム
docker system df                     # ディスク使用
docker system prune -a               # 使っていないものを全てクリーンアップ

Docker Compose — ローカル開発環境をまとめて立ち上げる

単一コンテナの限界

bash
# 毎回個別に実行する必要がある
docker run -d postgres
docker run -d redis
docker run -d --link postgres --link redis myapp

コマンド5本 + 手動ネットワーク接続 — 複雑でミスが起きやすい。

docker-compose.yml — 1ファイルで完結

yaml
services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: mydb
    ports:
      - "5432:5432"
    volumes:
      - postgres-data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://app:secret@postgres:5432/mydb
      REDIS_URL: redis://redis:6379
    depends_on:
      - postgres
      - redis

volumes:
  postgres-data:
bash
docker compose up -d      # すべて起動
docker compose down       # すべて停止・削除
docker compose logs app   # 特定サービスのログ
docker compose ps         # 状態確認

3つのコンテナ + ネットワーク + ボリュームコマンド1行で起動します。

自動ネットワーク

Compose はすべてのサービスを1つのネットワークにまとめます。サービス名がホスト名になります:

code
app コンテナの内部から:
  postgres:5432   ← 名前でアクセス可能
  redis:6379

localhost ではなくサービス名を使います。古い --link 方式よりもシンプルです。

環境変数 — .env の自動読み込み

yaml
# docker-compose.yml
services:
  app:
    environment:
      DB_PASSWORD: ${DB_PASSWORD}   # .env から自動取得
bash
# .env (同じフォルダ)
DB_PASSWORD=secret123

compose up を実行すると自動的に .env を読み込んで値を展開します。.env を .gitignore に追加することを忘れずに

volumes — データの永続化

yaml
services:
  postgres:
    volumes:
      - postgres-data:/var/lib/postgresql/data    # 名前付きボリューム
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql  # ホストファイル

volumes:
  postgres-data:    # Docker 管理領域

コンテナを削除してもデータは保持されますdown では削除されず、down -v を明示した場合のみ削除されます。

healthcheck + depends_on (モダンな方法)

yaml
services:
  postgres:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      retries: 5

  app:
    depends_on:
      postgres:
        condition: service_healthy   # postgres が*準備完了*になってから起動

depends_on だけでは「起動順序」しか保証されません — DB が実際に接続を受け付ける準備ができているかは保証されません。healthcheck との組み合わせが標準的な方法です。

プロダクションでは Compose 単体は使いません

  • Compose はローカル・開発環境のスタンダード
  • プロダクションは Kubernetes、ECS、Cloud Run など
  • Compose ファイルをそのまま Kubernetes マニフェストに変換するツール (Kompose) もあります

🤖 AI へのリクエスト例

  • 「PostgreSQL + Redis + Node.js アプリが一緒に起動する docker-compose.yml を作って」
  • 「この compose ファイルに healthcheck と depends_on の条件付き起動を追加して」
  • 「環境変数を .env ファイルに分離して」
先に読むとよい概念: DevOps