docker-ops について
docker-opsは、コンテナ化アプリケーションを開発・運用する人向けのDocker運用スキルです。イメージ構築、Compose、キャッシュ、安全対策の実践知識をまとめています。
主な機能
- 01Dockerfileのベストプラクティス
- 02マルチステージビルドの指針
- 03イメージレイヤーのキャッシュ最適化
- 04Composeのサービス構成パターン
- 05コンテナのセキュリティ対策
- 06よくある問題のトラブルシューティング
活用シーン
- 01本番用Dockerfileの設計
- 02イメージサイズとビルド時間の削減
- 03サービスとネットワークの構成
- 04コンテナのセキュリティ設定の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ 0xdarkmatter/ claude-mods --skill docker-opsインストール後、Claude Code で/docker-opsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/.gitkeepreferences/compose-patterns.mdmulti-stage-builds.mdoptimization.mdscripts/.gitkeep詳細
Docker の運用
コンテナ化されたアプリケーションのビルド、実行、構成に関する包括的な Docker のパターンです。
Dockerfile のベストプラクティス
| プラクティス | すべきこと | すべきでないこと |
|---|---|---|
| ベースイメージ | FROM node:20-slim | FROM node:latest |
| レイヤーキャッシュ | 依存関係ファイルを先にコピーし、その後にソースをコピーする | RUN install の前に COPY . . を実行する |
| パッケージのインストール | apt-get update && apt-get install -y ... && rm -rf /var/lib/apt/lists/* | update と install を別々の RUN で実行する |
| ユーザー | USER nonroot(必要に応じて作成する) | 本番環境で root として実行する |
| マルチステージ | ビルドステージとランタイムステージを分ける | コンパイラのツールチェーンを同梱する |
| シークレット | --mount=type=secret(BuildKit) | COPY .env . または ARG PASSWORD |
| ENTRYPOINT と CMD | 固定バイナリには ENTRYPOINT、デフォルト値には CMD を使う | シグナル処理でシェル形式に依存する |
| WORKDIR | WORKDIR /app | RUN cd /app && ... |
| .dockerignore | .git、node_modules、__pycache__ を含める | .dockerignore をまったく用意しない |
| ラベル | LABEL org.opencontainers.image.* | メタデータを付けない |
マルチステージビルドの判断ツリー
言語に応じて、ランタイムのベースイメージを選択します。
Go ──────────── CGO disabled? ──── Yes ──► scratch or distroless/static
No ───► distroless/base or alpine
Rust ─────────── Static musl? ──── Yes ──► scratch or distroless/static
No ───► distroless/cc or debian-slim
Node.js ──────── Need native? ──── Yes ──► node:20-slim
No ───► node:20-alpine (smaller)
Python ────────── Need C libs? ─── Yes ──► python:3.12-slim
No ───► python:3.12-slim (still slim)
Java ──────────── JRE only ──────────────► eclipse-temurin:21-jre-alpine
参照: 言語ごとの注釈付き完全サンプルについては、
references/multi-stage-builds.mdをご覧ください。
レイヤーキャッシュのルール
Docker は各レイヤーをキャッシュします。レイヤー N でキャッシュミスが発生すると、それ以降のすべてのレイヤーが無効になります。
キャッシュが無効になる要因
| 要因 | 影響 |
|---|---|
COPY/ADD 内のファイルが変更された | このレイヤーと、その下のすべてのレイヤーが無効になる |
RUN コマンドのテキストが変更された | このレイヤーと、その下のすべてのレイヤーが無効になる |
ARG の値が変更された | ARG 宣言以降が無効になる |
--no-cache フラグ | すべてが無効になる |
| ベースイメージが更新された | すべてが無効になる |
最適なレイヤー順序
# 1. Base image (changes rarely)
FROM python:3.12-slim
# 2. System dependencies (changes rarely)
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 3. Dependency files (changes occasionally)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 4. Application code (changes frequently)
COPY src/ ./src/
# 5. Runtime config (changes frequently)
CMD ["python", "-m", "app"]
経験則: 変更頻度の低いレイヤーから高いレイヤーの順に並べます。
.dockerignore の要点
# Version control
.git
.gitignore
# Dependencies (rebuilt in container)
node_modules
__pycache__
*.pyc
.venv
vendor/
# Build artifacts
dist/
build/
target/
*.egg-info
# IDE and editor
.vscode
.idea
*.swp
*.swo
# Docker files (prevent recursive context)
Dockerfile*
docker-compose*
.dockerignore
# Environment and secrets
.env
.env.*
*.pem
*.key
# Documentation and tests (unless needed)
docs/
tests/
*.md
LICENSE
重要な理由: .dockerignore がないと、docker build はコンテキストディレクトリ全体をデーモンに送信します。.git フォルダーだけでも、数百メガバイト増えることがあります。
Docker Compose クイックリファレンス
サービス定義
services:
web:
build:
context: .
dockerfile: Dockerfile
target: production # Multi-stage target
image: myapp:latest
ports:
- "8080:8000"
environment:
DATABASE_URL: postgres://db:5432/app
env_file:
- .env
volumes:
- ./src:/app/src # Bind mount (dev)
- app-data:/app/data # Named volume (persistent)
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
restart: unless-stopped
networks:
- backend
ボリュームとネットワーク
volumes:
app-data: # Named volume (Docker-managed)
db-data:
driver: local
networks:
backend:
driver: bridge
frontend:
driver: bridge
参照: プロファイル、ウォッチモード、オーバーライドファイルを含む完全なパターンについては、
references/compose-patterns.mdをご覧ください。
.ddev/フォルダーがある PHP/CMS プロジェクトの場合: DDEV は独自の Compose ファイルを生成します。並行するスタックを手動で記述しないでください。ddev-opsを使用してください(追加サービスは.ddev/docker-compose.<name>.yamlに記述します。その中の Compose 構文は、このスキルのものです)。
セキュリティのクイックリファレンス
| 項目 | 推奨事項 |
|---|---|
| ユーザー | 非 root として実行する:RUN adduser -D appuser && USER appuser |
| ベースイメージ | ダイジェストを固定する:FROM python:3.12-slim@sha256:abc123... |
| ファイルシステム | ルートを読み取り専用にする:docker run --read-only --tmpfs /tmp |
| ケイパビリティ | すべてを削除し、必要なものを追加する:--cap-drop=ALL --cap-add=NET_BIND_SERVICE |
| シークレット | BuildKit のシークレットを使う:RUN --mount=type=secret,id=key cat /run/secrets/key |
| スキャン | イメージをスキャンする:trivy image myapp:latest または grype myapp:latest |
| latest を使わない | 常に具体的なタグを使い、バージョンを固定する |
| 最小限のイメージ | 可能な場合は distroless または scratch を使う |
| SUID を使わない | RUN find / -perm /6000 -type f -exec chmod a-s {} + |
| ネットワーク | バックエンドサービスには内部ネットワークを使う |
非 root ユーザーのパターン
# Debian/Ubuntu-based
RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser
COPY --chown=appuser:appuser . /app
USER appuser
# Alpine-based
RUN addgroup -S appuser && adduser -S -G appuser appuser
COPY --chown=appuser:appuser . /app
USER appuser
# Distroless (built-in nonroot user)
FROM gcr.io/distroless/static:nonroot
USER nonroot:nonroot
よくある落とし穴
| 落とし穴 | 問題 | 対処法 |
|---|---|---|
| イメージが大きい | ビルドツールやnode_modulesを最終イメージに含めてしまう | マルチステージビルドを使います |
| キャッシュの無効化 | RUN npm installの前にCOPY . .を実行する | 先にロックファイルをコピーしてインストールし、その後にソースをコピーします |
| レイヤー内のシークレット | COPY .env .やARG SECRET=...によって、イメージの履歴にシークレットが埋め込まれる | --mount=type=secretまたは実行時の環境変数を使います |
| PID 1の問題 | アプリがSIGTERMを受信できず、ゾンビプロセスが発生する | tiniをinitとして使うか、CMDにexec形式を使います |
| タイムゾーン | コンテナがUTCを使用する | TZ環境変数を設定するか、tzdataをインストールします |
| DNSキャッシュ | AlpineのmuslによるDNSの問題 | RUN apk add --no-cache libc6-compatを使うか、slimに切り替えます |
| aptキャッシュ | 古いレイヤーのapt-get updateがキャッシュされる | update && installは必ず1つのRUNにまとめます |
| シグナルの欠落 | シェル形式(CMD npm start)では/bin/shがラップする | exec形式を使います:CMD ["node", "server.js"] |
| ビルドコンテキストのサイズ | GB単位のデータをデーモンに送信してしまう | .dockerignoreを追加し、docker build --progress=plainで確認します |
| レイヤーの増加 | RUNごとにレイヤーが作成される | 関連するコマンドを&&でつなぎます |
PID 1/シグナル処理の修正
# Option 1: Use tini as init process
RUN apt-get update && apt-get install -y --no-install-recommends tini \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["tini", "--"]
CMD ["node", "server.js"]
# Option 2: Docker init flag (Docker 23.0+)
# docker run --init myapp
# Option 3: Node.js - handle signals in code
# process.on('SIGTERM', () => { server.close(); process.exit(0); });
Dockerの基本コマンド
# Build
docker build -t myapp:1.0 .
docker build -t myapp:1.0 --target production . # Multi-stage target
docker build --no-cache -t myapp:1.0 . # Force rebuild
# Run
docker run -d --name myapp -p 8080:8000 myapp:1.0
docker run --rm -it myapp:1.0 /bin/sh # Interactive debug
docker run --read-only --tmpfs /tmp myapp:1.0 # Read-only root
# Inspect
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
docker history myapp:1.0 # Layer breakdown
docker inspect myapp:1.0 | jq '.[0].Config' # Image config
# Debug running container
docker exec -it myapp /bin/sh
docker logs -f myapp
docker stats myapp
# Cleanup
docker system prune -a --volumes # Remove everything unused
docker image prune -a # Remove unused images
参考ファイル
| ファイル | 内容 |
|---|---|
references/multi-stage-builds.md | 言語ごとのマルチステージビルドのパターン(Go、Rust、Node、Python) |
references/compose-patterns.md | Composeのサービス、ネットワーキング、プロファイル、監視、オーバーライド |
references/optimization.md | イメージサイズ、BuildKit、セキュリティスキャン、デバッグ |
RUNステップ内では、ロックファイルからのみインストールします:npm ci(またはパッケージマネージャーの固定バージョンでのインストール)とcomposer install --no-dev --optimize-autoloaderです。各パッケージマネージャーで必要なコマンドや、イメージ内でnpm installを実行することがバグである理由については、package-manager-opsを参照してください。