mcpField
I
infra-ci-cd-docker

infra-ci-cd-docker

github.com/agents-incクラウド・DevOps2660 回インストール2 日前に更新
リポジトリ

infra-ci-cd-docker について

Node.js/TypeScript プロジェクト向けの Docker コンテナ化スキルで、開発環境と本番イメージの構築を扱います。マルチステージビルド、キャッシュ最適化、コンテナのセキュリティに重点を置いています。

主な機能

  1. 01Node.js/TypeScript のマルチステージビルド
  2. 02Docker Compose の開発環境
  3. 03BuildKit キャッシュとレイヤー最適化
  4. 04非 root ユーザーとシークレット管理
  5. 05ヘルスチェックと graceful shutdown

活用シーン

  1. 01最小限の本番コンテナイメージの作成
  2. 02ローカルの複数コンテナ開発環境の構成
  3. 03依存関係のインストールと CI/CD ビルドの最適化
  4. 04コンテナ実行時のセキュリティ強化

インストール

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

$npx skills add https://github.com/agents-inc/skills --skill infra-ci-cd-docker

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

metadata.yaml
reference.md
examples/
compose.md
core.md
production.md

詳細

Docker コンテナ化のパターン

クイックガイド: BuildKit を使用した、Node.js/TypeScript アプリケーションの Docker コンテナ化。マルチステージビルドで本番用イメージを最小化します(1 GB から 100 MB 未満へ)。開発環境には Docker Compose v2 を使用します。BuildKit のキャッシュマウントで、依存関係のインストールを 10 倍高速化します。本番環境のセキュリティ対策として、非 root ユーザー、ヘルスチェック、シークレットマウントを使用します。サイズを重視する場合は Alpine、互換性を重視する場合は Debian slim を使用します。


<critical_requirements>

重要:このスキルを使用する前に

すべてのコードは、CLAUDE.md のプロジェクト規約に従う必要があります(kebab-case、名前付きエクスポート、インポート順序、import type、名前付き定数)。

(本番用イメージでは必ずマルチステージビルドを使用してください。本番環境に開発用依存関係、TypeScript コンパイラー、ソースファイルを含めないでください)

(コンテナは必ず非 root ユーザーとして実行してください。本番コンテナをデフォルトの root ユーザーとして実行しないでください)

(必ず CMD ["node", "server.js"] の exec 形式を使用してください。npm start や CMD のシェル形式は使用しないでください)

(ビルド時の機密データには必ず BuildKit のシークレットマウントを使用してください。シークレットに ARG や ENV を使用しないでください)

(ソースコードより先に package.json/ロックファイルをコピーしてください。npm ci より前に COPY . . を実行しないでください(レイヤーキャッシュが無効になります))

</critical_requirements>


例

  • Dockerfile のパターン - マルチステージビルド、Bun、モノレポ、レイヤーキャッシュ、.dockerignore、シグナル処理
  • Docker Compose - 開発環境、ネットワーク、ボリューム、ヘルスチェック
  • 本番環境と CI/CD - セキュリティ強化、シークレット、CI/CD パイプライン、脆弱性スキャン
  • クイックリファレンス - Dockerfile の命令、CLI コマンド、ベースイメージの比較

自動検出: Dockerfile、docker-compose、compose.yaml、Docker、コンテナ、マルチステージビルド、BuildKit、.dockerignore、Docker Compose、docker build、docker run、HEALTHCHECK、Docker Scout、docker init、コンテナ化、コンテナイメージ、Docker ネットワーク、Docker ボリューム

使用する場合:

  • Node.js/TypeScript アプリケーション用の Dockerfile を作成する場合
  • 本番用イメージのサイズを最小化するためにマルチステージビルドを設定する場合
  • ローカル開発環境用に Docker Compose を設定する場合
  • Docker のレイヤーキャッシュと BuildKit のキャッシュマウントを最適化する場合
  • コンテナのセキュリティ(非 root、シークレット、読み取り専用ファイルシステム)を実装する場合
  • コンテナオーケストレーション用のヘルスチェックを設定する場合
  • Docker イメージをビルドしてプッシュする CI/CD パイプラインを構築する場合
  • OS プラットフォーム間で一貫した開発環境を必要とするチーム
  • 依存関係を持つサービスを分離する必要があるマイクロサービスアーキテクチャ

使用しない場合:

  • コンテナを使用しないサーバーレスデプロイ(AWS Lambda、Vercel Functions)
  • サーバーランタイムを使用しない静的サイトホスティング(Netlify、Vercel、Cloudflare Pages)
  • npm で配布する単純なスクリプトや CLI ツール
  • コンテナ化を必要としないローカル開発
  • 分離による利点より、複雑さの増加が上回る場合
  • Kubernetes 固有のオーケストレーションパターン(Kubernetes スキルを使用してください)

対象となる主なパターン:

  • Node.js/TypeScript 用のマルチステージ Dockerfile(ビルダーパターン)
  • Docker Compose v2 による開発環境
  • BuildKit のキャッシュマウントとレイヤーの最適化
  • コンテナのセキュリティ(非 root、シークレット、ケイパビリティ、読み取り専用)
  • 本番コンテナ用のヘルスチェック
  • ビルドコンテキストを最適化する .dockerignore
  • ボリュームマウント(名前付きボリューム、バインドマウント、tmpfs)
  • Docker ネットワーク(bridge、host、overlay)
  • CI/CD 連携(GitHub Actions の build-push)
  • シグナル処理(正常なシャットダウンのための tini)

## 方針

コンテナを使うと、再現可能で分離された環境を構築でき、「自分のマシンでは動くのに」という問題を解消できます。Dockerは、Node.js/TypeScriptアプリケーションを移植可能で軽量なイメージにパッケージ化するための標準です。

基本原則:

  1. 本番イメージを最小限にする - アプリケーションの実行に必要なもの(コンパイル済みJS、本番用依存関係、ランタイム)のみを含めます
  2. レイヤーキャッシュを最適化する - 変更のないレイヤーを再利用できるようにDockerfileを構成し、再ビルドを高速化します
  3. デフォルトでセキュリティを確保する - 非rootユーザーを使い、イメージにシークレットを含めず、攻撃対象領域を最小限に抑えます
  4. 開発環境と本番環境の構成を一致させる - Docker Composeを使って、本番環境のトポロジーをローカルで再現します

基本パターン

パターン 1:Node.js/TypeScript向けマルチステージDockerfile

マルチステージビルドでは、ビルダー段階でTypeScriptをコンパイルし、コンパイル済みJSと本番用依存関係のみを最小限のランタイムイメージにコピーします。これにより、イメージのサイズを1GB以上から100MB未満に削減できます。

本番用Dockerfileは、次の3つの段階を使用します。

  1. deps - 本番用依存関係のみをインストールします
  2. builder - すべての依存関係をインストールし、TypeScriptをコンパイルします
  3. runner - コンパイル済みの出力と本番用依存関係を最小限のイメージにコピーします
# Stage 1: Production dependencies
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci --omit=dev --no-audit --no-fund

# Stage 2: Build TypeScript
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci --no-audit --no-fund
COPY tsconfig.json ./
COPY src/ ./src/
RUN npm run build

# Stage 3: Production runtime
FROM node:22-alpine AS runner
WORKDIR /app
RUN apk add --no-cache tini
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 appgroup && \
    adduser --system --uid 1001 --ingroup appgroup appuser
COPY --from=deps --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --chown=appuser:appgroup package.json ./
USER appuser
EXPOSE 3000
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "dist/server.js"]

メリット: 3段階のビルドで役割を分離し、BuildKitのキャッシュマウントでnpm ciを高速化します。非rootユーザーとシグナル処理用のtiniを使用し、最終イメージには本番用の成果物のみを含めます。

Bunやモノレポのバリエーションを含む完全なDockerfileについては、examples/core.mdを参照してください。


パターン 2:開発環境向けDocker Compose

Docker Compose v2では、複数コンテナを使用する開発環境を定義できます。docker composeコマンド(ハイフンなし)とcompose.yaml(docker-compose.ymlではありません)を使用します。

# compose.yaml
services:
  app:
    build:
      context: .
      target: builder
    volumes:
      - .:/app:cached
      - /app/node_modules
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:17-alpine
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U dev"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:

メリット: condition: service_healthyで依存サービスのヘルスチェックを行い、macOSでのパフォーマンス向上のために:cached付きのバインドマウントを使用します。匿名ボリュームでnode_modulesを保護し、名前付きボリュームでデータベースの永続化を実現します。

Redis、ネットワーク、ボリュームのパターンを含む完全な開発環境については、examples/compose.mdを参照してください。


パターン 3:BuildKitのキャッシュマウント

Docker Engine 23以降でデフォルトとなっているBuildKitは、ビルド間でパッケージマネージャーのキャッシュを保持するキャッシュマウントを提供し、インストール時間を10分の1以下に短縮できます。

# npm
RUN --mount=type=cache,target=/root/.npm \
    npm ci --no-audit --no-fund

# pnpm
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
    pnpm install --frozen-lockfile

レイヤーの順序に関するルール: ベースイメージのバージョンを固定する > 依存関係のマニフェストをコピーする > 依存関係をインストールする > ソースコードをコピーする > ビルド/コンパイルする。この順序により、キャッシュのヒット率を最大化できます。

npm、Bun、pnpm、apt向けのキャッシュマウントのパターンについては、examples/core.mdを参照してください。


パターン 4:コンテナのセキュリティ
非rootユーザー
RUN addgroup --system --gid 1001 appgroup && \
    adduser --system --uid 1001 --ingroup appgroup appuser
COPY --chown=appuser:appgroup --from=builder /app/dist ./dist
USER appuser
シークレットマウント(ビルド時)
# Secret is ephemeral - never persisted in image layers
RUN --mount=type=secret,id=npm_token,env=NPM_TOKEN \
    npm ci --no-audit --no-fund
# Build: docker build --secret id=npm_token,env=NPM_TOKEN .
実行時のセキュリティ強化
services:
  app:
    read_only: true
    tmpfs: [/tmp]
    security_opt: [no-new-privileges:true]
    cap_drop: [ALL]

本番用Composeの完全な設定、シークレット管理、CI/CDパイプラインについては、examples/production.mdを参照してください。


パターン 5:ヘルスチェック

ヘルスチェックを設定すると、オーケストレーターが応答しないコンテナを検出し、自動的に再起動できます。

HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=30s \
    CMD ["node", "-e", "fetch('http://localhost:3000/health').then(r => { if (!r.ok) process.exit(1) }).catch(() => process.exit(1))"]

メリット: Node.js組み込みのfetchを使用するため、Alpineにcurlは不要です。start-periodによってアプリケーションの起動時間を確保し、ルートパスだけでなく専用のヘルスチェックエンドポイントを確認します。

ヘルスチェックエンドポイントの実装とComposeのヘルスチェックパターンについては、examples/production.mdを参照してください。


パターン 6:.dockerignore
node_modules
dist
.git
.env
.env.*
!.env.example
Dockerfile*
compose.yaml
__tests__
*.test.ts
coverage
.github

メリット: node_modules(決定論的に再インストールされます)、.envファイル(シークレットの漏えいを防ぎます)、.git(キャッシュの無効化を防ぎます)を除外し、ビルドコンテキストを小さく保ちます。

包括的な.dockerignoreファイルについては、examples/core.mdを参照してください。


パターン 7:シグナル処理とグレースフルシャットダウン

PID 1として実行されるNode.jsは、SIGTERM/SIGINTを正しく処理しません。initシステムとしてtiniを使用してください。

RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "dist/server.js"]

メリット: Tiniがシグナルをnodeプロセスに転送し、ゾンビプロセスを回収します。また、docker stop時のグレースフルシャットダウンを確実にします。

TypeScriptでのグレースフルシャットダウンの完全な実装については、examples/core.mdを参照してください。


パフォーマンスの最適化

イメージサイズの削減
手法効果
マルチステージビルド1GBから100MB未満に削減(90%以上の削減)
Alpineベースイメージ135MB(フル版は1GB、スリム版は200MB)
npm ci --omit=dev本番環境から開発用依存関係を削除
.dockerignoreビルドコンテキストが小さくなり、送信も高速化
ビルド速度の最適化
手法効果
BuildKitのキャッシュマウント依存関係のインストールが10倍高速化
レイヤーの順序付け(ソースより依存関係を先に)ソースのみの変更時にキャッシュがヒット
node_modulesを除外する.dockerignoreGB単位のデータをデーモンに送信するのを防止
--no-audit --no-fundフラグ不要なnpmチェックを省略
並列マルチステージビルドBuildKitが独立したステージを並行してビルド
CI/CDビルドキャッシュ
# GitHub Actions - Cache Docker layers
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v7
  with:
    cache-from: type=gha
    cache-to: type=gha,mode=max

有効な理由: GitHub Actionsのキャッシュ(type=gha)はCIの実行をまたいでレイヤーを保持し、mode=maxは最終レイヤーだけでなく、すべてのレイヤーをキャッシュします。

CI/CDパイプラインの完全な例については、examples/production.mdを参照してください。


<decision_framework>

選択の指針

ベースイメージの選択
Which base image?
  |
  +-- Need smallest image? --> Alpine (node:22-alpine, ~135MB)
  |     +-- musl libc compatibility issues? --> Use Debian slim instead
  |
  +-- Need maximum compatibility? --> Debian slim (node:22-slim, ~200MB)
  |     +-- Native extensions work out of the box
  |
  +-- Need debugging tools? --> Full image (node:22, ~1GB)
  |     +-- Development only, never for production
  |
  +-- Maximum security? --> Distroless (gcr.io/distroless/nodejs22-debian12)
        +-- No shell, no package manager, smallest attack surface
ComposeとDockerfileターゲットの比較
How to manage dev vs prod?
  |
  +-- Multi-stage Dockerfile with targets
  |     +-- `docker compose build --target builder` for dev
  |     +-- Final stage for production
  |
  +-- Separate compose files
        +-- compose.yaml (base)
        +-- compose.override.yaml (dev - auto-loaded)
        +-- compose.prod.yaml (production)
ボリューム戦略
What data needs to persist?
  |
  +-- Source code (dev hot reload) --> Bind mount with :cached
  +-- Database files --> Named volume
  +-- Temporary/cache data --> tmpfs
  +-- Secrets at runtime --> Docker secrets or tmpfs
  +-- node_modules in dev --> Anonymous volume (protect from host)

</decision_framework>


統合ガイド

Dockerエコシステムのツール:

  • Docker Scout:CLIとCIでの脆弱性スキャンにdocker scout cvesを使用します
  • BuildKit:Docker Engine 23以降のデフォルトのビルドエンジンです。キャッシュマウント、シークレットマウント、マルチプラットフォームビルドを利用できます

CI/CDとの統合:

DockerイメージはあらゆるCI/CDパイプラインと統合できます。ビルドとプッシュのパターン、脆弱性スキャンのワークフローについては、examples/production.mdを参照してください。

コンテナオーケストレーション:

本番用イメージは、あらゆるコンテナオーケストレーターで動作します。プラットフォームにかかわらず、ヘルスチェック(HEALTHCHECK命令)と非rootユーザーは必須です。

置き換えるもの:

  • VMベースの開発環境(Docker Composeなら、より軽量に分離できます)
  • 手動でのサーバープロビジョニング(Dockerfileで環境構築をコード化します)
  • コンテナ内のNodeバージョンマネージャー(Dockerfileではベースイメージのタグを使ってNodeのバージョンを正確に固定します)

<red_flags>

要注意事項

優先度の高い問題:

  • 本番環境のコンテナを root で実行する(デフォルトの動作です。必ず USER ディレクティブを追加してください)
  • ARG/ENV/COPY にシークレットを指定する(イメージレイヤーに残ります。--mount=type=secret を使用してください)
  • 本番環境に開発用の依存関係とソースコードを含めたまま、単一ステージでビルドする
  • CMD に npm start を使用する(npm は SIGTERM を握りつぶすため、CMD ["node", "dist/server.js"] を使用してください)
  • .dockerignore ファイルがない(node_modules がデーモンに送信され、シークレットがイメージに漏洩します)
  • ベースイメージに :latest タグを使用する(ビルドの再現性がありません)

優先度が中程度の問題:

  • npm ci より前に COPY . . を実行する(ファイルが変更されるたびに依存関係のキャッシュが無効になります)
  • ヘルスチェックが定義されていない(オーケストレーターが応答しないコンテナを検知できません)
  • docker-compose.yml に version: キーを使用する(非推奨です。バージョン指定のない compose.yaml を使用してください)
  • condition: service_healthy を指定せずに depends_on を使用する(依存先の準備が整う前にコンテナが起動します)
  • Dockerfile で npm ci ではなく npm install を使用する(再現性がなく、処理も遅くなります)

よくある間違い:

  • 開発環境で node_modules 用の匿名ボリューム(/app/node_modules)を忘れる(ホスト側のモジュールでコンテナ内のモジュールが上書きされます)
  • macOS でバインドマウントに :cached を指定しない(パフォーマンスが大幅に低下します)
  • ビルダーステージではなく最終ステージにビルドツール(gcc、make、python)をインストールする
  • 本番環境の Compose でデータベースのポートをホストに公開する(開発環境でのみ必要です)

注意点と例外的なケース:

  • Alpine は musl libc を使用するため、ネイティブの C バインディングを含む npm パッケージ(bcrypt、sharp、canvas)が失敗することがあります。npm rebuild を実行するか、Debian slim に切り替えてください
  • Node.js の fetch() は Node 18 以降で使用できます(Alpine のヘルスチェックに curl は不要です)
  • BuildKit のキャッシュマウントには、# syntax=docker/dockerfile:1、または BuildKit がデフォルトで有効になっている Docker Engine 23 以降が必要です
  • docker compose down -v は名前付きボリュームを削除します(データが失われます)。データを保持するには、-v を付けずに docker compose down を使用してください
  • macOS/Windows の Docker Desktop は Linux とファイルシステムのパフォーマンスが異なり、バインドマウントの処理が遅くなります
  • COPY --chown は COPY と RUN chown の組み合わせより効率的です(レイヤーが 2 つではなく 1 つになります)
  • Alpine に tini をインストールするには、明示的に指定する必要があります(apk add --no-cache tini)。node:alpine イメージにはデフォルトで含まれていません
  • node_modules/.cache ディレクトリは開発中に大きくなることがあります。.dockerignore に追加してください

</red_flags>


<critical_reminders>

重要な注意事項

すべてのコードは、CLAUDE.md に記載されたプロジェクトの規約に従う必要があります(kebab-case、名前付きエクスポート、インポート順序、import type、名前付き定数)

(本番用イメージでは、必ずマルチステージビルドを使用してください。本番環境に開発用の依存関係、TypeScript コンパイラー、ソースファイルを絶対に含めないでください)

(コンテナは必ず非 root ユーザーで実行してください。本番用コンテナを root で実行することは絶対に避けてください(デフォルトの動作です))

(必ず CMD ["node", "server.js"](exec 形式)を使用してください。CMD に npm start やシェル形式を絶対に使用しないでください)

(ビルド時の機密データには必ず BuildKit のシークレットマウントを使用してください。シークレットに ARG や ENV を絶対に使用しないでください)

(ソースコードより先に、必ず package.json/ロックファイルをコピーしてください。npm ci より前に COPY . . を絶対に実行しないでください(レイヤーキャッシュが無効になります))

これらのルールに従わないと、肥大化したイメージ(1GB 以上)、セキュリティ上の脆弱性(root アクセス、シークレットの漏洩)、正常なグレースフルシャットダウンの失敗(デプロイ時のリクエスト消失)、CI ビルドの遅延(レイヤーキャッシュなし)につながります。

</critical_reminders>

コメント