mcpField
D
docker

docker

github.com/bobmatnycクラウド・DevOps781.0k 回インストール15 週間前に更新
リポジトリ

docker について

ローカル開発、CI/CD、デプロイに携わる開発者向けの Docker コンテナ化ガイドです。例を交えて、イメージ構築、複数コンテナ構成、セキュリティ、デバッグ、本番運用を説明します。

主な機能

  1. 01Dockerfile とイメージ構築の基本
  2. 02Compose による複数コンテナ構成
  3. 03マルチステージイメージ構築
  4. 04コンテナのセキュリティとリソース制限
  5. 05コンテナのデバッグ手法

活用シーン

  1. 01一貫性のあるローカル開発環境の構築
  2. 02再現可能な CI/CD ワークフローの作成
  3. 03デプロイ用サービスのパッケージ化
  4. 04統合テスト用の一時データベース実行

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill docker

インストール後、Claude Code で/dockerを入力して読み込まれたか確認します。

同梱ファイルmetadata.json

詳細

Docker コンテナ化スキル

概要

Docker は、アプリケーションとその依存関係を分離されたポータブルな単位にパッケージ化するコンテナ化を提供します。コンテナによって開発、テスト、本番環境間の一貫性が保たれ、「自分のマシンでは動く」問題を解消できます。

使用する場面

  • ローカル開発:チームメンバー間で一貫した開発環境を実現します
  • CI/CD パイプライン:再現可能なビルドおよびテスト環境を実現します
  • マイクロサービス:個別にスケーリングできる分離されたサービスを実現します
  • 本番環境へのデプロイ:クラウドプロバイダーを問わず、アプリケーションをポータブルにします
  • データベース/サービスのテスト:統合テスト用の一時的なデータベースを利用できます
  • レガシーアプリケーションの分離:互換性のない依存関係を並行して実行できます

クイックスタート

1. Dockerfile を作成する
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
2. イメージをビルドする
docker build -t myapp:1.0 .
3. コンテナを実行する
docker run -p 3000:3000 myapp:1.0

基本概念

イメージとコンテナ
  • イメージ:アプリケーションコード、ランタイム、依存関係を含む読み取り専用のテンプレートです
  • コンテナ:書き込み可能なレイヤーを持つ、イメージの実行中のインスタンスです
  • レジストリ:イメージを保存する場所です(Docker Hub、GitHub Container Registry)
レイヤーとキャッシュ

Dockerfile の各命令はレイヤーを作成します。Docker は変更されていないレイヤーをキャッシュし、ビルドを高速化します。

# GOOD: Dependencies change less frequently than code
FROM python:3.11-slim
COPY requirements.txt .
RUN pip install -r requirements.txt  # Cached unless requirements.txt changes
COPY . .                              # Rebuild only when code changes

# BAD: Invalidates cache on every code change
FROM python:3.11-slim
COPY . .                              # Changes frequently
RUN pip install -r requirements.txt  # Reinstalls on every build
ボリューム

コンテナを再起動しても保持される永続データストレージです。

# Named volume (managed by Docker)
docker run -v mydata:/app/data myapp

# Bind mount (host directory)
docker run -v $(pwd)/data:/app/data myapp

# Anonymous volume (temporary)
docker run -v /app/data myapp
ネットワーク

コンテナは Docker ネットワークを介して通信します。

# Create network
docker network create mynetwork

# Run containers on network
docker run --network mynetwork --name db postgres
docker run --network mynetwork --name app myapp
# App can connect to db using hostname "db"

Dockerfile の基本

基本的な命令
# Base image
FROM node:18-alpine

# Metadata
LABEL maintainer="[email protected]"
LABEL version="1.0"

# Set working directory
WORKDIR /app

# Copy files
COPY package*.json ./
COPY src/ ./src/

# Run commands (creates layer)
RUN npm ci --only=production

# Set environment variables
ENV NODE_ENV=production
ENV PORT=3000

# Expose ports (documentation only)
EXPOSE 3000

# Default command
CMD ["node", "src/server.js"]

# Alternative: ENTRYPOINT (not overridden by docker run args)
ENTRYPOINT ["node"]
CMD ["src/server.js"]  # Default args for ENTRYPOINT
キャッシュ効率を高める命令の順序
# 1. Base image (rarely changes)
FROM python:3.11-slim

# 2. System dependencies (rarely change)
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# 3. Application dependencies (change occasionally)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 4. Application code (changes frequently)
COPY . .

# 5. Runtime configuration
ENV PYTHONUNBUFFERED=1
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
.dockerignore

ビルドコンテキストからファイルを除外します(ビルドを高速化し、イメージを小さくします)。

# .dockerignore
node_modules/
npm-debug.log
.git/
.gitignore
*.md
.env
.vscode/
__pycache__/
*.pyc
.pytest_cache/
coverage/
dist/
build/

マルチステージビルド

ビルドステージとランタイムステージを分けて、イメージサイズを最適化します。

Node.js TypeScript の例
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
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/server.js"]

メリット:

  • ビルド依存関係(TypeScript、webpack)を最終イメージから除外できます
  • 最終イメージは約 50MB です(ビルドツールを含めると約 500MB)
  • デプロイが高速になり、攻撃対象領域を縮小できます
Python の例
# Build stage
FROM python:3.11 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt

# Runtime stage
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
Go の例(最小サイズのイメージ)
# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server

# Runtime stage (scratch = empty base image)
FROM scratch
COPY --from=builder /app/server /server
EXPOSE 8080
ENTRYPOINT ["/server"]

結果:約 10MB の最終イメージに、コンパイル済みバイナリのみが含まれます。


Docker Compose

YAML で複数コンテナのアプリケーションを定義します。

基本構造
version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://db:5432/myapp
    depends_on:
      - db
    volumes:
      - ./src:/app/src  # Hot reload in development

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - db_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  db_data:
コマンド
# Start all services
docker-compose up

# Start in background
docker-compose up -d

# Rebuild images
docker-compose up --build

# Stop services
docker-compose down

# Stop and remove volumes
docker-compose down -v

# View logs
docker-compose logs -f app

# Run one-off command
docker-compose run app npm test
フルスタックの例
version: '3.8'

services:
  # Frontend
  web:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - ./frontend/src:/app/src
    environment:
      - REACT_APP_API_URL=http://localhost:8000

  # Backend API
  api:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    volumes:
      - ./backend:/app
    command: uvicorn main:app --host 0.0.0.0 --reload

  # Database
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Cache
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

  # Worker (background jobs)
  worker:
    build: ./backend
    command: celery -A tasks worker --loglevel=info
    environment:
      - REDIS_URL=redis://redis:6379
    depends_on:
      - redis
      - db

volumes:
  db_data:
  redis_data:

networks:
  default:
    name: myapp_network

開発ワークフロー

ボリュームを使ったホットリロード
Node.js
services:
  app:
    build: .
    volumes:
      - ./src:/app/src        # Sync source code
      - /app/node_modules     # Prevent overwriting container's node_modules
    command: npm run dev
# Dockerfile.dev
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install  # Include dev dependencies
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
Python(Django/FastAPI)
services:
  web:
    build: .
    volumes:
      - .:/app
    command: python manage.py runserver 0.0.0.0:8000
    # or for FastAPI:
    # command: uvicorn main:app --host 0.0.0.0 --reload
VS Code Dev Containers

.devcontainer/devcontainer.json:

{
  "name": "Python Dev Container",
  "dockerComposeFile": "../docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/app",
  "customizations": {
    "vscode": {
      "extensions": [
        "ms-python.python",
        "ms-python.vscode-pylance"
      ],
      "settings": {
        "python.defaultInterpreterPath": "/usr/local/bin/python"
      }
    }
  },
  "postCreateCommand": "pip install -r requirements-dev.txt",
  "remoteUser": "vscode"
}
ローカルデータベースコンテナ
# PostgreSQL
docker run -d \
  --name dev-postgres \
  -e POSTGRES_PASSWORD=localdev \
  -e POSTGRES_DB=myapp_dev \
  -p 5432:5432 \
  -v pgdata:/var/lib/postgresql/data \
  postgres:15-alpine

# MySQL
docker run -d \
  --name dev-mysql \
  -e MYSQL_ROOT_PASSWORD=localdev \
  -e MYSQL_DATABASE=myapp_dev \
  -p 3306:3306 \
  -v mysqldata:/var/lib/mysql \
  mysql:8

# MongoDB
docker run -d \
  --name dev-mongo \
  -p 27017:27017 \
  -v mongodata:/data/db \
  mongo:7

# Redis
docker run -d \
  --name dev-redis \
  -p 6379:6379 \
  redis:7-alpine

本番環境でのパターン

ヘルスチェック
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

# Health check endpoint
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD node healthcheck.js

EXPOSE 3000
CMD ["node", "server.js"]
// healthcheck.js
const http = require('http');

const options = {
  host: 'localhost',
  port: 3000,
  path: '/health',
  timeout: 2000
};

const request = http.request(options, (res) => {
  if (res.statusCode === 200) {
    process.exit(0);
  } else {
    process.exit(1);
  }
});

request.on('error', () => process.exit(1));
request.end();
セキュリティのベストプラクティス
FROM python:3.11-slim

# 1. Use non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser

# 2. Install dependencies as root
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 3. Copy application files
COPY --chown=appuser:appuser . .

# 4. Switch to non-root user
USER appuser

# 5. Drop unnecessary privileges
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

追加のセキュリティ対策:

  • 最小限のベースイメージ(alpine、distroless)を使用します
  • イメージの脆弱性をスキャンします:docker scan myapp:latest
  • イメージにシークレットを含めないでください(環境変数またはシークレットマネージャーを使用します)
  • ベースイメージを最新の状態に保ちます
  • 可能な場合は読み取り専用のルートファイルシステムを使用します
シークレット管理
# Docker Swarm secrets (production)
echo "db_password_here" | docker secret create db_password -
version: '3.8'
services:
  app:
    image: myapp
    secrets:
      - db_password
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password

secrets:
  db_password:
    external: true

代替方法:環境ファイル

# docker-compose.yml
services:
  app:
    env_file:
      - .env.production  # Never commit this file
# .env.production (gitignored)
DATABASE_URL=postgresql://user:pass@db:5432/prod
SECRET_KEY=your-secret-key
リソース制限
services:
  app:
    image: myapp
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
# Command-line resource limits
docker run -d \
  --memory="512m" \
  --cpus="1.0" \
  --restart=unless-stopped \
  myapp

フレームワーク別の例

Python:Django
FROM python:3.11-slim

ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    postgresql-client \
    && rm -rf /var/lib/apt/lists/*

# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application
COPY . .

# Collect static files
RUN python manage.py collectstatic --noinput

# Create non-root user
RUN useradd -m -u 1000 django && chown -R django:django /app
USER django

EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "myproject.wsgi:application"]

docker-compose.yml:

version: '3.8'

services:
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/app
    ports:
      - "8000:8000"
    environment:
      - DEBUG=1
      - DATABASE_URL=postgres://postgres:postgres@db:5432/django_dev
    depends_on:
      - db

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: django_dev
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
Python:FastAPI
FROM python:3.11-slim

WORKDIR /app

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

COPY . .

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
Node.js:Next.js
# Multi-stage build for Next.js
FROM node:18-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci

FROM node:18-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:18-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

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

next.config.js(standalone 出力に必要):

module.exports = {
  output: 'standalone',
}
Node.js:Express
FROM node:18-alpine

WORKDIR /app

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

# Copy application
COPY . .

# Create non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

EXPOSE 3000

CMD ["node", "server.js"]
TypeScript のビルド
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json tsconfig.json ./
RUN npm ci
COPY src/ ./src/
RUN npm run build

# Production stage
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"]

コンテナオーケストレーションの基本

Docker Swarm(組み込み)
# Initialize swarm
docker swarm init

# Deploy stack
docker stack deploy -c docker-compose.yml myapp

# Scale service
docker service scale myapp_web=5

# Update service (zero-downtime)
docker service update --image myapp:2.0 myapp_web

# Remove stack
docker stack rm myapp
Kubernetes の比較
特徴Docker ComposeDocker SwarmKubernetes
複雑さ低中高
用途ローカル開発小規模クラスター大規模な本番環境
セットアップ単一ファイル組み込み個別にインストール
スケーリング手動自動自動+高度な機能
高可用性なしありあり
エコシステム限定的Docker膨大

それぞれの使用場面:

  • Docker Compose:ローカル開発、シンプルなデプロイ
  • Docker Swarm:小規模な本番クラスター、K8s よりシンプル
  • Kubernetes:大規模な本番環境、マルチクラウド、高度なオーケストレーション

CI/CD 統合

GitHub Actions
# .github/workflows/docker.yml
name: Build and Push Docker Image

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

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

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

    steps:
      - uses: actions/checkout@v3

      - name: Log in to Container Registry
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=sha

      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Run tests
        run: |
          docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} npm test
GitLab CI
# .gitlab-ci.yml
stages:
  - build
  - test
  - deploy

variables:
  DOCKER_DRIVER: overlay2
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG

test:
  stage: test
  script:
    - docker run --rm $IMAGE_TAG npm test

deploy:
  stage: deploy
  script:
    - docker pull $IMAGE_TAG
    - docker tag $IMAGE_TAG $CI_REGISTRY_IMAGE:latest
    - docker push $CI_REGISTRY_IMAGE:latest
  only:
    - main

コンテナーのデバッグ

ログの表示
# Stream logs
docker logs -f container_name

# Last 100 lines
docker logs --tail 100 container_name

# Logs since timestamp
docker logs --since 2024-01-01T10:00:00 container_name

# With timestamps
docker logs -t container_name

# Docker Compose logs
docker-compose logs -f service_name
実行中のコンテナーでコマンドを実行する
# Interactive shell
docker exec -it container_name /bin/sh
# or
docker exec -it container_name /bin/bash

# Run single command
docker exec container_name ls -la /app

# Run as different user
docker exec -u root container_name apt-get update
コンテナーの調査
# Full container details
docker inspect container_name

# Specific field (IP address)
docker inspect -f '{{.NetworkSettings.IPAddress}}' container_name

# Environment variables
docker inspect -f '{{.Config.Env}}' container_name

# Mounted volumes
docker inspect -f '{{.Mounts}}' container_name
リソース使用状況
# Real-time stats
docker stats

# Single container
docker stats container_name

# No streaming (single snapshot)
docker stats --no-stream
ネットワークのデバッグ
# List networks
docker network ls

# Inspect network
docker network inspect bridge

# Test connectivity between containers
docker exec container1 ping container2

# Check DNS resolution
docker exec container_name nslookup other_container
ビルド問題のデバッグ
# Build with no cache
docker build --no-cache -t myapp .

# Show build progress
docker build --progress=plain -t myapp .

# Build specific stage
docker build --target builder -t myapp-builder .

# Inspect intermediate layers
docker history myapp:latest

ローカル Docker のパターン(mcp-browser、mcp-memory)

mcp-browser の開発用 compose
  • docker-compose.yml は、ポート範囲 8875-8895 とオプションの chrome プロファイルを指定して mcp-server を実行します。
  • コードは読み取り専用でマウントされ(./src:/app/src:ro)、ログと一時ボリュームは永続化されます。
  • 環境変数のデフォルト値:MCP_DEBUG=true、MCP_LOG_LEVEL=DEBUG、MCP_HOST=0.0.0.0、MCP_PORT=8875。
  • オプションのプロファイル:chrome(ブラウザー)と tools(開発ツール用コンテナー)。
mcp-browser の Dockerfile.dev
  • ARG PYTHON_VERSION=3.11 を指定し、watchdog と Playwright Chromium をインストールします。
  • パッケージを編集可能モードでインストールし、python -m src.dev_runner を実行します。
  • 非 root ユーザーを使用し、/health をヘルスチェックします。
mcp-memory の本番用 Dockerfile
  • /opt/venv に仮想環境を作成し、python:3.11-slim を使用するマルチステージビルドです。
  • 実行環境ではヘルスチェック用に curl をインストールし、PYTHONPATH=/app を設定します。
  • 非 root ユーザーを使用し、/health のチェックを行いながら CMD ["python", "run_api_server.py"] を実行します。

トラブルシューティング

よくある問題
「ポートはすでに使用されています」
# Find process using port
lsof -i :3000
# or
netstat -tulpn | grep 3000

# Kill process
kill -9 <PID>

# Or use different host port
docker run -p 3001:3000 myapp
「Docker デーモンに接続できません」
# Check Docker is running
docker info

# Restart Docker Desktop (Mac/Windows)
# or
sudo systemctl restart docker  # Linux

# Check permissions (Linux)
sudo usermod -aG docker $USER
# Log out and back in
「デバイスに空き領域がありません」
# Remove unused containers, images, volumes
docker system prune -a --volumes

# Remove only dangling images
docker image prune

# Remove stopped containers
docker container prune

# Remove unused volumes
docker volume prune

# Check disk usage
docker system df
「ビルドコンテキストが大きすぎます」
# Create .dockerignore
cat > .dockerignore << EOF
node_modules/
.git/
*.log
dist/
coverage/
EOF

# Build with specific context
docker build -f Dockerfile -t myapp ./src
コンテナーがすぐに終了する
# Check logs
docker logs container_name

# Run with interactive shell to debug
docker run -it myapp /bin/sh

# Override entrypoint
docker run -it --entrypoint /bin/sh myapp

# Check exit code
docker inspect -f '{{.State.ExitCode}}' container_name
コンテナー内で権限が拒否される
# Run as root to debug
docker exec -u root -it container_name /bin/sh

# Fix ownership
docker exec -u root container_name chown -R appuser:appuser /app

# Or rebuild with correct permissions in Dockerfile
パフォーマンスの問題
ビルドが遅い
# Use BuildKit (faster, better caching)
DOCKER_BUILDKIT=1 docker build -t myapp .

# Multi-stage builds to reduce layers
# Order instructions by change frequency
# Use .dockerignore to exclude unnecessary files
メモリ使用量が多い
# Set memory limits
docker run -m 512m myapp

# Monitor memory
docker stats container_name

# Check for memory leaks in application
ボリュームのマウントが遅い(Mac/Windows)
# Use delegated consistency (Mac)
volumes:
  - ./src:/app/src:delegated

# Or use named volumes instead of bind mounts
volumes:
  - node_modules:/app/node_modules

ベストプラクティス

レイヤーの最適化
  1. 変更頻度に応じて並べる:変更頻度が最も低いものを先にする
  2. RUN コマンドをまとめる:レイヤー数を減らす
  3. 同じレイヤー内でクリーンアップする:一時ファイルをすぐに削除する
# GOOD
RUN apt-get update && apt-get install -y \
    package1 \
    package2 \
    && rm -rf /var/lib/apt/lists/*

# BAD (creates 3 layers, apt cache remains in layer 2)
RUN apt-get update
RUN apt-get install -y package1 package2
RUN rm -rf /var/lib/apt/lists/*
イメージサイズの削減
  1. Alpine イメージを使用する:フル Linux の 100MB 以上に対して 5MB
  2. マルチステージビルド:最終イメージからビルドツールを除外する
  3. 不要なファイルを削除する:ドキュメント、サンプル、テスト
  4. .dockerignore を使用する:開発用ファイルを除外する
# Before: 800MB
FROM node:18
COPY . .
RUN npm install
CMD ["node", "server.js"]

# After: 120MB
FROM node:18-alpine
COPY package*.json ./
RUN npm ci --only=production
COPY server.js .
CMD ["node", "server.js"]
セキュリティチェックリスト
  • 信頼できる提供元の公式ベースイメージを使用する
  • イメージのバージョンを正確に指定する(latest は使用しない)
  • 非 root ユーザーとして実行する
  • イメージの脆弱性をスキャンする
  • ベースイメージを最新の状態に保つ
  • イメージにシークレットを埋め込まない
  • 可能な場合は読み取り専用のルートファイルシステムを使用する
  • 攻撃対象領域を最小限に抑える(Alpine、distroless)
  • Docker Content Trust(イメージ署名)を有効にする
開発環境と本番環境

開発環境:

FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install  # Include dev dependencies
COPY . .
CMD ["npm", "run", "dev"]

本番環境:

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
USER node
CMD ["node", "dist/server.js"]
ロギングのベストプラクティス
# Log to stdout/stderr (Docker captures these)
CMD ["node", "server.js"]  # Good

# Don't log to files (lost when container stops)
CMD ["node", "server.js", ">", "app.log"]  # Bad
// Application logging
console.log('Info message');   // stdout
console.error('Error message'); // stderr

// Use structured logging
console.log(JSON.stringify({
  level: 'info',
  timestamp: new Date().toISOString(),
  message: 'Request processed',
  requestId: '123'
}));
環境設定
# Use ARG for build-time variables
ARG NODE_ENV=production
ENV NODE_ENV=$NODE_ENV

# Use ENV for runtime variables
ENV PORT=3000
ENV LOG_LEVEL=info

# Override at runtime
# docker run -e PORT=8080 -e LOG_LEVEL=debug myapp
ヘルスチェック
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1
# docker-compose.yml
services:
  app:
    image: myapp
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 40s
グレースフルシャットダウン
// Node.js example
process.on('SIGTERM', () => {
  console.log('SIGTERM received, closing server...');
  server.close(() => {
    console.log('Server closed');
    process.exit(0);
  });
});
# Use exec form to properly handle signals
CMD ["node", "server.js"]  # Good
CMD node server.js          # Bad (wrapped in /bin/sh, signals not forwarded)

クイックリファレンス

基本コマンド
# Images
docker build -t name:tag .
docker pull image:tag
docker push image:tag
docker images
docker rmi image:tag

# Containers
docker run -d --name container image
docker ps                    # Running containers
docker ps -a                 # All containers
docker stop container
docker start container
docker restart container
docker rm container
docker logs -f container
docker exec -it container /bin/sh

# Cleanup
docker system prune -a       # Remove all unused resources
docker container prune       # Remove stopped containers
docker image prune          # Remove dangling images
docker volume prune         # Remove unused volumes

# Compose
docker-compose up -d
docker-compose down
docker-compose logs -f
docker-compose exec service /bin/sh
docker-compose build
よく使うフラグ
# docker run flags
-d              # Detached (background)
-it             # Interactive with TTY
-p 8080:80      # Port mapping (host:container)
--name myapp    # Container name
-e VAR=value    # Environment variable
-v /host:/container  # Volume mount
--network name  # Connect to network
--rm            # Remove container on exit
-m 512m         # Memory limit
--cpus 1.0      # CPU limit
Dockerfile の命令
FROM image:tag           # Base image
WORKDIR /path            # Set working directory
COPY src dst             # Copy files
ADD src dst              # Copy (with URL/tar support)
RUN command              # Execute command
ENV KEY=value            # Environment variable
EXPOSE port              # Document port
CMD ["executable"]       # Default command
ENTRYPOINT ["exec"]      # Command prefix
VOLUME /path             # Create mount point
USER username            # Set user
ARG name=default         # Build argument
LABEL key=value          # Metadata
HEALTHCHECK CMD command  # Health check

概要

Docker によるコンテナ化には、次のメリットがあります。

  • 一貫性:開発から本番まで同一の環境を実現します
  • 分離:アプリケーション間で依存関係が競合しません
  • 移植性:Docker が動作するあらゆる場所(クラウド、ローカル、CI)で実行できます
  • 効率性:VM と比べて軽量で、起動も高速です
  • スケーラビリティ:オーケストレーションによる水平スケーリングが簡単です

主なワークフロー:

  1. 開発:ホットリロード用のボリュームを設定した docker-compose
  2. CI/CD:イメージをビルド、テストし、レジストリにプッシュします
  3. 本番:イメージをプルし、リソース制限とヘルスチェックを設定して実行します

次のステップ:

  • イメージサイズを最適化するマルチステージビルドを習得します
  • ヘルスチェックと正常なシャットダウンを実装します
  • ローカル開発用に docker-compose を設定します
  • Docker を CI/CD パイプラインに統合します
  • 本番環境での大規模運用に向けて、オーケストレーション(Swarm または Kubernetes)を検討します

コメント