Dockerベストプラクティス2025

セキュアで高速なコンテナ運用を実現する実践ガイド

Dockerは現代のアプリケーション開発・デプロイメントにおいて不可欠なツールとなりました。 しかし、適切なベストプラクティスを知らないまま使用すると、セキュリティリスクやパフォーマンス問題を引き起こす可能性があります。 本記事では、2025年時点での最新Dockerベストプラクティスを、実践的なコード例とともに詳しく解説します。

イメージサイズの最適化

Dockerイメージのサイズは、ビルド時間、デプロイ速度、ストレージコストに直接影響します。 適切な最適化により、イメージサイズを50%以上削減できます。

❌ 悪い例:肥大化したイメージ

FROM ubuntu:22.04

RUN apt-get update
RUN apt-get install -y python3 python3-pip
RUN apt-get install -y git curl wget vim
RUN pip install flask gunicorn requests pandas numpy

COPY . /app
WORKDIR /app

CMD ["python3", "app.py"]

# イメージサイズ: 1.2GB 😱

✅ 良い例:最適化されたイメージ

FROM python:3.11-slim

# 1つのRUNコマンドでレイヤーを削減
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    && rm -rf /var/lib/apt/lists/*

# 依存関係を先にコピー(キャッシュ効率化)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# アプリケーションコードをコピー
COPY . /app
WORKDIR /app

# 非rootユーザーで実行
RUN useradd -m appuser
USER appuser

CMD ["gunicorn", "-b", "0.0.0.0:8000", "app:app"]

# イメージサイズ: 180MB ✅ (-85%削減)

イメージサイズ削減のポイント

  • 軽量ベースイメージを使用: alpine, slim, distroless
  • レイヤーを最小化: RUNコマンドを結合
  • 不要なファイルを削除: apt cache, pip cache等
  • .dockerignoreを活用: ビルドコンテキストを最小化
  • マルチステージビルド: ビルド成果物のみを含める

マルチステージビルド

マルチステージビルドは、ビルド環境と実行環境を分離し、 最終的なイメージには必要最小限のファイルのみを含めることができます。

Node.jsアプリケーションの例

# ステージ1: ビルド環境
FROM node:18-alpine AS builder

WORKDIR /app

# 依存関係のインストール
COPY package*.json ./
RUN npm ci --only=production

# アプリケーションのビルド
COPY . .
RUN npm run build

# ステージ2: 実行環境
FROM node:18-alpine

WORKDIR /app

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

# 非rootユーザーで実行
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001
USER nodejs

EXPOSE 3000

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

# 最終イメージサイズ: 120MB
# ビルド環境を含めると: 800MB → 85%削減

Go言語アプリケーションの例

# ステージ1: ビルド
FROM golang:1.21-alpine AS builder

WORKDIR /app

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

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

# ステージ2: 実行(distroless)
FROM gcr.io/distroless/static-debian11

COPY --from=builder /app/main /

USER nonroot:nonroot

EXPOSE 8080

CMD ["/main"]

# 最終イメージサイズ: 15MB 🎯

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

1. 非rootユーザーで実行

# 専用ユーザーを作成
RUN useradd -r -u 1001 appuser

# ファイル所有権を変更
RUN chown -R appuser:appuser /app

# ユーザーを切り替え
USER appuser

2. 最小権限の原則

# 必要最小限のパッケージのみ
RUN apt-get install -y \
    --no-install-recommends \
    ca-certificates \
    && rm -rf /var/lib/apt/lists/*

# 読み取り専用ファイルシステム
docker run --read-only \
  -v /tmp \
  myapp:latest

3. イメージの脆弱性スキャン

# Trivyでスキャン
docker run aquasec/trivy image myapp:latest

# CI/CDに統合
- name: Scan image
  run: |
    trivy image \
      --severity HIGH,CRITICAL \
      --exit-code 1 \
      myapp:latest

4. 信頼できるベースイメージ

# 公式イメージを使用
FROM node:18-alpine

# タグを明示(latestは避ける)
FROM python:3.11-slim

# ダイジェストで固定(推奨)
FROM nginx:1.25@sha256:abc123...

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

  • ✅ 非rootユーザーで実行
  • ✅ 最新のベースイメージを使用
  • ✅ 脆弱性スキャンを実施
  • ✅ シークレット情報をイメージに含めない
  • ✅ 不要なツール(curl, wget等)を削除
  • ✅ 読み取り専用ファイルシステムを使用

効率的なDockerfile作成

レイヤーキャッシュの活用

Dockerはレイヤーキャッシュを使用してビルドを高速化します。 変更頻度の低いコマンドを先に配置することで、キャッシュ効率を最大化できます。

❌ 非効率な順序

FROM python:3.11-slim

# アプリケーションコードをコピー(頻繁に変更)
COPY . /app

# 依存関係をインストール(変更が少ない)
RUN pip install -r requirements.txt

# 問題: コードが変わるたびにpip installが再実行される

✅ 効率的な順序

FROM python:3.11-slim

WORKDIR /app

# 依存関係ファイルを先にコピー(変更が少ない)
COPY requirements.txt .

# 依存関係をインストール(キャッシュされる)
RUN pip install --no-cache-dir -r requirements.txt

# アプリケーションコードをコピー(頻繁に変更)
COPY . .

# コードが変わっても、pip installはキャッシュから実行

.dockerignoreの活用

# .dockerignore
.git
.gitignore
.env
.vscode
node_modules
npm-debug.log
README.md
.dockerignore
Dockerfile
docker-compose.yml
.github
tests
*.md
*.log
.pytest_cache
__pycache__
*.pyc
.coverage

# ビルド時間とイメージサイズを削減

Docker Composeの活用

本番環境向けdocker-compose.yml

version: '3.8'

services:
  app:
    image: myapp:${VERSION:-latest}
    build:
      context: .
      dockerfile: Dockerfile
      args:
        - NODE_ENV=production
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=${DATABASE_URL}
    env_file:
      - .env.production
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M
    networks:
      - app-network
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=${DB_NAME}
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 3
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  postgres_data:

本番環境運用のベストプラクティス

ヘルスチェック

コンテナの健全性を継続的に監視し、異常時は自動的に再起動します。

HEALTHCHECK \
  --interval=30s \
  --timeout=3s \
  --start-period=40s \
  CMD curl -f http://localhost/health || exit 1
リソース制限

CPU・メモリの制限を設定し、リソース枯渇を防ぎます。

docker run \
  --cpus="1.5" \
  --memory="512m" \
  --memory-swap="1g" \
  myapp:latest
ログ管理

ログドライバーを設定し、ログの肥大化を防ぎます。

logging:
  driver: "json-file"
  options:
    max-size: "10m"
    max-file: "3"

環境変数の管理

# ❌ 悪い例: Dockerfileにハードコード
ENV DATABASE_PASSWORD=mysecretpassword

# ✅ 良い例: 環境変数またはシークレット管理
# docker-compose.yml
services:
  app:
    environment:
      - DATABASE_URL=${DATABASE_URL}
    secrets:
      - db_password

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

# Docker Swarm
echo "mysecretpassword" | docker secret create db_password -

# Kubernetes
kubectl create secret generic db-password \
  --from-literal=password=mysecretpassword

まとめ

Dockerを本番環境で効果的に活用するためのベストプラクティスをまとめます:

Dockerベストプラクティス チェックリスト

  1. 軽量ベースイメージを使用(alpine, slim, distroless)
  2. マルチステージビルドでイメージサイズを最小化
  3. 非rootユーザーで実行
  4. 脆弱性スキャンをCI/CDに統合
  5. .dockerignoreでビルドコンテキストを最適化
  6. レイヤーキャッシュを活用
  7. ヘルスチェックを実装
  8. リソース制限を設定
  9. ログローテーションを設定
  10. シークレット管理を適切に実施
項目 悪い例 良い例
ベースイメージ ubuntu:latest (80MB+) alpine:3.19 (7MB)
タグ myapp:latest myapp:v1.2.3
ユーザー root(デフォルト) appuser(専用)
RUNコマンド 複数行に分割 &&で結合
シークレット ENV PASSWORD=xxx Docker secrets

これらのベストプラクティスを適用することで、セキュアで高速、かつ保守性の高いコンテナ環境を構築できます。 Dockerは単なるツールではなく、DevOps文化を実現するための重要な要素です。

Dockerコンテナ化をサポートします

Deployでは、アプリケーションのコンテナ化からKubernetes環境での運用まで、 包括的にサポートしています。ベストプラクティスに基づいた実装で、 セキュアで効率的なコンテナ環境を構築します。

無料相談を申し込む