Use Cases (更新: 2026/6/3)

Claude CodeとDocker実践ガイド:Compose、Volume、CIまで安全に整える

Claude CodeでDocker開発環境、Compose、CIビルドを安全に作る実装ガイド。

Claude CodeとDocker実践ガイド:Compose、Volume、CIまで安全に整える

Claude CodeにDockerを任せる前に決めること

Claude Codeに「Docker対応して」とだけ頼むと、動くけれどレビューしづらいDockerfileになりがちです。Dockerはアプリの実行環境を小さな箱として固定する仕組みです。箱の設計図がイメージ、実際に起動したものがコンテナ、ホストPCとデータを共有する置き場がボリューム、コンテナ同士が名前で通信する道がネットワークです。

初心者がつまずくのは、Dockerfileだけを見てしまうところです。実務ではDockerfile、docker-compose.yml.dockerignore、環境変数、ヘルスチェック、CIでのビルド確認を1つの流れとして見ます。Claude Codeには、この流れを小さく分けて任せるのが安全です。

公式仕様は変わるので、作業時はDockerfile referenceCompose file referenceDocker build best practicesDocker Build GitHub Actionsを横に置きます。Claude Codeの使い方はClaude Code overviewも確認します。CI全体を整えるならClaude CodeでCI/CDパイプラインを構築、権限の境界はClaude Code権限設定ガイドも合わせて読むと判断が速くなります。

3つの実用ユースケース

Docker連携は「かっこいい開発環境」ではなく、再現性を買うためのものです。Claude Codeに任せる前に、どの問題を解くのかを明文化します。

ユースケースDockerで固定するものClaude Codeに頼む作業
新メンバーのオンボーディングNode.js、PostgreSQL、Redis、ポート、初期コマンドdocker compose upだけで動く構成を作る
本番に近い不具合調査環境変数、サービス名、ヘルスチェック、起動順ローカルと本番の差分を表にして潰す
PRごとの安全確認Dockerfile、lockfile、ビルドキャッシュ、CIログGitHub Actionsでイメージをビルドして壊れたら止める
研修・引き継ぎコマンド、失敗時の見方、復旧手順CLAUDE.mdとREADMEに運用ルールを残す

特に収益化しているサイトやSaaSでは、「自分のPCでは動いた」は事故の入口になります。商品ページ、問い合わせフォーム、決済、管理画面のどれかが壊れると売上に直結します。テンプレートから始めたい場合はClaudeCodeLabのプロダクトへ、チームのリポジトリに合わせてルール化したい場合はClaude Code研修・相談へつなげる導線を記事内にも残しておくと、読者の次の行動が自然になります。

Claude Codeへ渡すプロンプト

最初の依頼では、対象、作ってほしいファイル、禁止事項、検証方法をまとめます。ここを曖昧にすると、Claude Codeは「それっぽいDockerfile」を出しやすくなります。

このNode.js + TypeScript APIをDocker対応してください。

前提:
- パッケージマネージャーはpnpm
- アプリは3000番ポートで起動する
- GET /health が200を返す
- ローカル開発ではPostgreSQL 16とRedis 7を使う

作ってほしいもの:
- 本番用multi-stage Dockerfile
- ローカル開発用docker-compose.yml
- .dockerignore
- package.jsonに追加するDocker関連scripts
- GitHub Actionsでdocker buildだけ確認するworkflow

制約:
- 本番コンテナはrootユーザーで起動しない
- .envや秘密情報をイメージにCOPYしない
- volumeとnetworkの意図をREADME向けに説明する
- 最後に確認コマンドと失敗時の見方を書く

multi-stage buildは、ビルド用の箱と実行用の箱を分ける書き方です。TypeScriptのコンパイルやテストに必要な道具を本番イメージに入れず、実行に必要なファイルだけを残せます。コンテナをrootで動かさないのは、アプリに脆弱性があったときの被害範囲を小さくするためです。

コピペで始めるDockerfile

次の例は、src/index.tsdist/index.jsへビルドするNode.js APIを想定しています。devステージはローカル用、runnerステージは本番用です。

# syntax=docker/dockerfile:1

FROM node:22-bookworm-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
WORKDIR /app
RUN corepack enable

FROM base AS dev
ENV NODE_ENV=development
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
CMD ["pnpm", "dev"]

FROM base AS deps
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

FROM deps AS build
COPY tsconfig.json ./
COPY src ./src
RUN pnpm build

FROM base AS prod-deps
ENV NODE_ENV=production
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod && pnpm store prune

FROM base AS runner
ENV NODE_ENV=production
RUN groupadd --system --gid 1001 nodejs \
  && useradd --system --uid 1001 --gid nodejs appuser
COPY --from=prod-deps --chown=appuser:nodejs /app/node_modules ./node_modules
COPY --from=build --chown=appuser:nodejs /app/dist ./dist
COPY --chown=appuser:nodejs package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --retries=3 CMD node -e "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
CMD ["node", "dist/index.js"]

Claude Codeにレビューさせるときは、「このDockerfileで秘密情報が入る可能性」「キャッシュが効かなくなるCOPY順」「本番イメージに不要なdevDependenciesが残る可能性」を見てもらいます。最初から完璧を狙うより、レビュー項目を固定して毎回同じ観点で直すほうが品質が安定します。

ComposeでVolumeとNetworkを理解する

Composeは複数コンテナをまとめて起動する設定です。ここではAPI、PostgreSQL、Redisを同じネットワークに置きます。apiからはpostgresredisというサービス名で接続できます。これがDockerのネットワークです。

ボリュームはデータをコンテナの外に残す仕組みです。pgdataがないと、PostgreSQLコンテナを消したときにDBデータも消えます。api_node_modulesは、ホストPCのnode_modulesとコンテナ内のnode_modulesが混ざる事故を避けるために分けています。

services:
  api:
    build:
      context: .
      target: dev
    command: pnpm dev
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: development
      DATABASE_URL: postgres://app:app@postgres:5432/app
      REDIS_URL: redis://redis:6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    volumes:
      - .:/app
      - api_node_modules:/app/node_modules
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
      interval: 10s
      timeout: 3s
      retries: 5

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
      POSTGRES_DB: app
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d app"]
      interval: 5s
      timeout: 3s
      retries: 10

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 10

volumes:
  pgdata:
  api_node_modules:

depends_onは起動順を整える機能です。ただし、単にコンテナが起動しただけではDBが接続可能とは限りません。上の例ではcondition: service_healthyを使い、PostgreSQLとRedisのヘルスチェックが通ってからAPIを起動します。

.dockerignoreとpackage.json scripts

.dockerignoreはビルド時に送るファイルを減らすための設定です。ここに.envを入れ忘れると、秘密情報がイメージに入る危険があります。

.git
node_modules
dist
coverage
.env
.env.*
!.env.example
npm-debug.log*
pnpm-debug.log*
Dockerfile*
docker-compose*.yml

package.jsonには、チームが同じコマンドを使えるようにscriptsを残します。Claude Codeに「既存scriptsを壊さず追加して」と明示すると安全です。

{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc -p tsconfig.json",
    "start": "node dist/index.js",
    "docker:dev": "docker compose up --build",
    "docker:check": "bash scripts/docker-check.sh"
  },
  "dependencies": {
    "@fastify/redis": "latest",
    "fastify": "latest",
    "pg": "latest"
  },
  "devDependencies": {
    "tsx": "latest",
    "typescript": "latest"
  }
}

動作確認スクリプトを置く

手元の確認を毎回手打ちにすると、確認漏れが起きます。scripts/docker-check.shとして残しておくと、Claude CodeにもCIにも同じ検証手順を渡せます。

#!/usr/bin/env bash
set -euo pipefail

docker compose build api
docker compose up -d postgres redis api

cleanup() {
  docker compose down
}
trap cleanup EXIT

for attempt in {1..30}; do
  if curl -fsS http://127.0.0.1:3000/health >/dev/null; then
    echo "healthcheck ok"
    exit 0
  fi
  echo "waiting for api... ${attempt}/30"
  sleep 2
done

docker compose logs api
exit 1

このスクリプトは、ビルド、起動、ヘルスチェック、失敗時ログ確認までを1本にまとめています。記事やREADMEにこのコマンドを載せると、読者もチームメンバーも同じ状態から検証できます。

CIではpushせずbuildだけ確認する

最初のPRでは、レジストリへpushする前に「Dockerfileが壊れていないか」だけを見ます。push、署名、脆弱性スキャン、SBOM生成は次の段階で足します。

name: docker-build

on:
  pull_request:
  push:
    branches:
      - main

jobs:
  image:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/build-push-action@v7
        with:
          context: .
          target: runner
          push: false
          tags: claude-code-docker-sample:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Claude Codeには「このworkflowはPRでpushしないか」「権限が過剰ではないか」「cacheが壊れたときにビルドできるか」をレビューさせます。CIの権限設計はClaude Codeセキュリティベストプラクティスにもつながる重要な観点です。

よくある失敗と落とし穴

1つ目は、.envをCOPYしてしまう事故です。Dockerイメージに秘密情報が入ると、レジストリやCIログ経由で漏れる可能性があります。.dockerignoreとCIのsecret管理をセットで確認します。

2つ目は、ホストPCのnode_modulesをコンテナにマウントして壊す事故です。macOS、Windows、Linuxでネイティブモジュールの中身が違うことがあります。api_node_modules:/app/node_modulesのように分けると安定します。

3つ目は、DBが起動する前にAPIが接続して落ちる事故です。depends_onだけで安心せず、DB側のhealthcheckとアプリ側のリトライを両方見ます。

4つ目は、本番コンテナをrootで動かすことです。小さなサンプルでは見逃されますが、実務では避けたい設定です。Claude Codeには「rootで動かしていない証拠をdiffから示して」と頼むとレビューしやすくなります。

5つ目は、Docker化しただけで本番と同じになったと誤解することです。CPU、メモリ、ネットワーク遅延、マネージドDB、TLS、ログ基盤はローカルComposeでは再現できません。Composeは「本番に近づける道具」であって「本番そのもの」ではありません。

このpitfallを避けるには、PR説明に「ローカルで証明できたこと」と「本番で別途確認すること」を分けて書かせます。Claude Codeにこの2列を出させるだけでも、Docker化を過信する事故はかなり減ります。

Claude Codeにレビューさせるチェックリスト

Docker対応を入れたPRでは、Claude Codeに「良さそうです」と言わせるだけでは足りません。確認観点を固定して、毎回同じ質問を投げます。たとえば「この差分で秘密情報がimageに入る経路はあるか」「build cacheが効きにくくなる行はあるか」「本番imageにdevDependenciesやテストファイルが残るか」「healthcheckが本当にアプリの依存先まで見ているか」を順番に聞きます。

さらに、Claude Codeの回答には証拠を求めます。「Dockerfileの何行目でnon-rootになっているか」「Composeのどのvolumeが何を守っているか」「CI workflowのどの設定でpushしないと言えるか」のように、ファイル名と設定名まで言わせると、人間のレビューがかなり速くなります。ここを曖昧にすると、記事を読んだ初心者はコードをコピーして終わりになり、実務で使うときに危険な差分を見逃します。

小さなチームでは、最後に1枚の運用メモを残すのも効果があります。開発者はdocker:devで起動する、DBを初期化したいときだけvolumeを消す、CIが落ちたらまずdocker:checkを手元で再現する、秘密情報は.env.exampleだけ共有する、という程度で十分です。このメモをCLAUDE.mdに入れておくと、次回Claude Codeに依頼したときも同じ前提で作業できます。

安全な開発ワークフロー

実務でおすすめする順番は、まずClaude Codeに既存リポジトリを読ませ、必要なruntime、ポート、DB、外部APIを書き出してもらうことです。次に.dockerignoreを先に作り、秘密情報が入らない状態を固定します。その後、開発用Compose、本番用Dockerfile、確認スクリプト、CIの順で足します。

各ステップの終わりに、必ず人間がgit diffを読みます。Claude Codeには「変更したファイル」「なぜ必要か」「確認したコマンド」「残ったリスク」を短く出させます。この形式はセッション引き継ぎテンプレートとも相性がよく、途中で作業者が変わっても迷いません。

初心者が最初に詰まるのは、Dockerの構文よりも「どこまでをコンテナに入れるか」です。最初から本番DB、決済、メール、画像変換、バッチ処理まで全部Composeに入れると、原因切り分けが難しくなります。まずはアプリ、DB、キャッシュの3つに絞り、外部SaaSは.env.exampleとモックで扱います。Claude Codeにも「今回は外部APIを本物につながない」と明示すると、秘密情報や課金事故を避けやすくなります。

Docker対応は、記事一本で終わる作業ではなく、チームの開発習慣を変える作業です。自分で進めるならプロダクト集のチェックリストを使い、チーム導入なら研修・相談CLAUDE.md、権限、CI、レビュー項目までまとめて決めるのが現実的です。

実際に試した結果

実際に試した結果、Claude CodeにいきなりDockerfileを書かせるより、.dockerignore、Compose、ヘルスチェック、CI buildの順に小さく任せたほうが修正回数が減りました。特にnode_modules用volumeとDBのservice_healthy待ちを最初から入れると、初心者が詰まりやすい「起動したのに接続できない」「Windowsだけ動かない」という相談が減ります。Docker化の目的はコンテナを増やすことではなく、同じ確認手順で安全にリリースへ近づくことです。

#Claude Code #Docker #コンテナ #DevOps #インフラ
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。