🐳

Dockerfileとdocker-compose.yml完全ガイド:初心者から上級者まで

に公開1

Dockerfileとdocker-compose.yml完全ガイド:初心者から上級者まで

はじめに

DockerとDocker Composeは現代の開発において欠かせないツールです。この記事では、Dockerfileとdocker-compose.ymlの基礎から応用まで、実践的な例を交えながら解説します。

目次

  1. Dockerfile基礎編
  2. Dockerfile応用編
  3. docker-compose.yml基礎編
  4. docker-compose.yml応用編
  5. ベストプラクティス
  6. トラブルシューティング

Dockerfile基礎編

Dockerfileとは

Dockerfileは、Dockerイメージを作成するための設計図です。テキストファイルに一連の命令を記述し、それを元にDockerがイメージをビルドします。

基本的な命令

# ベースイメージの指定
FROM node:18-alpine

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

# ファイルのコピー
COPY package*.json ./

# 依存関係のインストール
RUN npm ci --only=production

# アプリケーションコードのコピー
COPY . .

# ポートの公開
EXPOSE 3000

# コンテナ起動時のコマンド
CMD ["node", "index.js"]

主要な命令の説明

  • FROM: ベースイメージを指定
  • WORKDIR: コンテナ内の作業ディレクトリを設定
  • COPY/ADD: ファイルをコンテナにコピー
  • RUN: ビルド時にコマンドを実行
  • EXPOSE: コンテナが使用するポートを宣言
  • CMD/ENTRYPOINT: コンテナ起動時のコマンドを指定

Dockerfile応用編

マルチステージビルド

イメージサイズを削減する高度なテクニックです:

# ビルドステージ
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 実行ステージ
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]

レイヤーキャッシュの最適化

FROM python:3.11-slim

WORKDIR /app

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

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

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

セキュリティ強化

FROM node:18-alpine

# 非rootユーザーの作成
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

WORKDIR /app

# ファイルの所有権を設定
COPY --chown=nodejs:nodejs package*.json ./
RUN npm ci --only=production

COPY --chown=nodejs:nodejs . .

# 非rootユーザーで実行
USER nodejs

EXPOSE 3000
CMD ["node", "index.js"]

ARGとENVの活用

# ビルド時の変数
ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine

# 環境変数の設定
ENV NODE_ENV=production
ENV PORT=3000

WORKDIR /app

# ビルド引数の利用
ARG BUILD_DATE
ARG VCS_REF
LABEL build_date=$BUILD_DATE \
      vcs_ref=$VCS_REF

COPY package*.json ./
RUN npm ci --only=production
COPY . .

EXPOSE $PORT
CMD ["node", "index.js"]

docker-compose.yml基礎編

docker-compose.ymlとは

複数のコンテナを定義し、まとめて管理するための設定ファイルです。

基本的な構成

version: '3.8'

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - db
    volumes:
      - ./app:/app
      - /app/node_modules

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

主要な設定項目

  • version: Compose fileのバージョン
  • services: コンテナの定義
  • build: Dockerfileの場所
  • image: 使用するイメージ
  • ports: ポートマッピング
  • environment: 環境変数
  • volumes: データの永続化
  • depends_on: サービスの依存関係

docker-compose.yml応用編

開発環境と本番環境の分離

# docker-compose.yml(ベース設定)
version: '3.8'

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    depends_on:
      - db

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
# docker-compose.dev.yml(開発環境用)
version: '3.8'

services:
  web:
    build:
      context: .
      target: development
    ports:
      - "3000:3000"
    volumes:
      - ./src:/app/src
      - ./public:/app/public
    environment:
      - NODE_ENV=development
      - DEBUG=true
    command: npm run dev

  db:
    ports:
      - "5432:5432"
    volumes:
      - postgres_dev_data:/var/lib/postgresql/data

volumes:
  postgres_dev_data:
# docker-compose.prod.yml(本番環境用)
version: '3.8'

services:
  web:
    build:
      context: .
      target: production
    ports:
      - "80:3000"
    environment:
      - NODE_ENV=production
    restart: unless-stopped
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

  db:
    volumes:
      - postgres_prod_data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  postgres_prod_data:

使用方法:

# 開発環境
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up

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

ヘルスチェックの設定

version: '3.8'

services:
  web:
    build: .
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:15-alpine
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

ネットワークの詳細設定

version: '3.8'

services:
  frontend:
    build: ./frontend
    networks:
      - frontend-network
      - backend-network

  backend:
    build: ./backend
    networks:
      - backend-network
      - database-network

  database:
    image: postgres:15-alpine
    networks:
      - database-network

networks:
  frontend-network:
    driver: bridge
  backend-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16
  database-network:
    driver: bridge
    internal: true  # 外部からアクセス不可

シークレット管理

version: '3.8'

services:
  web:
    build: .
    secrets:
      - db_password
      - api_key
    environment:
      DB_PASSWORD_FILE: /run/secrets/db_password
      API_KEY_FILE: /run/secrets/api_key

  db:
    image: postgres:15-alpine
    secrets:
      - db_password
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password

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

ベストプラクティス

1. イメージサイズの最小化

# 良い例:軽量なベースイメージを使用
FROM alpine:3.18
RUN apk add --no-cache python3 py3-pip

# 悪い例:不要なパッケージが含まれる
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3 python3-pip

2. .dockerignoreの活用

# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.vscode
.idea
*.swp
*.swo
*~

3. ビルドキャッシュの最適化

# 頻繁に変更されないファイルを先にコピー
COPY package*.json ./
RUN npm ci

# 頻繁に変更されるファイルは後でコピー
COPY . .

4. セキュリティスキャン

# Dockerイメージのセキュリティスキャン
docker scout cves myimage:latest

# Trivyを使用したスキャン
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  aquasec/trivy image myimage:latest

5. ログ管理

version: '3.8'

services:
  web:
    build: .
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

トラブルシューティング

1. ビルドが遅い

問題: Dockerビルドに時間がかかる

解決策:

  • BuildKitを有効化: DOCKER_BUILDKIT=1 docker build .
  • キャッシュマウントの使用:
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt

2. コンテナ間の通信ができない

問題: サービス間で接続できない

解決策:

  • サービス名を使用(localhostではなく)
  • ネットワークの確認: docker network ls
  • DNSの確認: docker exec container nslookup service_name

3. ボリュームの権限問題

問題: コンテナ内でファイルの読み書きができない

解決策:

# ユーザーIDを一致させる
ARG UID=1000
ARG GID=1000
RUN groupadd -g $GID appuser && \
    useradd -m -u $UID -g $GID appuser
USER appuser

4. メモリ不足

問題: コンテナがOOMKillerに終了される

解決策:

services:
  web:
    deploy:
      resources:
        limits:
          memory: 512M
        reservations:
          memory: 256M

高度なテクニック

1. ビルド時の条件分岐

# syntax=docker/dockerfile:1.4
FROM alpine:3.18

ARG INSTALL_DEV_TOOLS=false
RUN <<EOF
if [ "$INSTALL_DEV_TOOLS" = "true" ]; then
    apk add --no-cache git vim curl
fi
EOF

2. heredocの活用

# syntax=docker/dockerfile:1.4
FROM python:3.11-slim

RUN <<EOF
apt-get update
apt-get install -y --no-install-recommends \
    build-essential \
    libpq-dev
apt-get clean
rm -rf /var/lib/apt/lists/*
EOF

3. Docker Composeでの環境変数の階層化

# .env.base
APP_NAME=myapp
LOG_LEVEL=info

# .env.dev
include .env.base
LOG_LEVEL=debug
DEBUG=true

# .env.prod
include .env.base
LOG_LEVEL=warning
DEBUG=false

4. 動的なポート割り当て

version: '3.8'

services:
  web:
    build: .
    ports:
      - "${PORT:-3000}:3000"

パフォーマンスチューニング

1. ビルドの並列化

# syntax=docker/dockerfile:1.4
FROM golang:1.21-alpine AS builder

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

COPY . .
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    CGO_ENABLED=0 go build -o app .

2. コンテナの起動順序制御

version: '3.8'

services:
  web:
    build: .
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    command: >
      sh -c "
        until nc -z db 5432; do
          echo 'Waiting for database...'
          sleep 1
        done
        exec node index.js
      "

まとめ

DockerfileとDocker Composeを効果的に使用することで、開発環境の構築からプロダクション環境へのデプロイまで、一貫性のある環境を提供できます。

重要なポイント:

  • イメージサイズの最小化を心がける
  • セキュリティを考慮した設計を行う
  • 開発環境と本番環境を適切に分離する
  • キャッシュを効果的に活用する
  • ログとモニタリングを適切に設定する

これらの知識を活用して、より効率的で安全なコンテナ環境を構築してください。

参考リンク

GitHubで編集を提案

Discussion

YuneKichiYuneKichi

完全ガイドとありますが、Composeまわりが2023年6月末にEOLを迎えたCompose V1に取り残されているように見えます。