Vinicius Aguiar
DevOps

フロントエンド開発者のための Docker:ゼロからデプロイまで

2026年4月16日 · 10分で読めます

あなたがフロントエンド開発者で Docker を使ったことがないなら、おそらく「自分のマシンでは動くんだけど」というセリフを聞いたことがあるでしょう。Docker はまさにその問題を解決します — アプリケーションをすべての依存関係とともに コンテナ にパッケージ化し、どこでも同じように動かせます。あなたの Mac でも、同僚の PC でも、CI でも、本番環境でも。このガイドでは、実際のフロントエンドプロジェクトに焦点を当てて、ゼロからデプロイまでを解説します。

Docker とは何か(回りくどい説明なしで)

Docker は、アプリケーションを実行するための隔離された環境(コンテナ)を作成するツールです。仮想マシンとは異なり、コンテナは軽量です — システムのカーネルを共有し、数秒で起動します。

  • イメージ — 「型」。ベースとなる OS、Node.js、依存関係、そしてあなたのコードを含みます。
  • コンテナ — イメージから実行されている「インスタンス」。同じイメージから複数のコンテナを起動できます。
  • Dockerfile — イメージをどう構築するかを定義する「レシピ」。
  • docker-compose — 複数のコンテナ(アプリ + データベース + Redis)を 1 つのコマンドでオーケストレーションします。

インストール

お使いの OS 向けの Docker Desktop をインストールしてください。Docker Engine、Docker CLI、Docker Compose が含まれています:

  • macOS: docker.com/products/docker-desktop からダウンロードするか、brew install --cask docker を使用
  • Windows: Docker Desktop をダウンロード(WSL2 が必要)
  • Linux: apt/yum 経由でインストールするか、公式ドキュメントに従う

インストールを確認します:

docker --version
# Docker version 24.x.x

docker compose version
# Docker Compose version v2.x.x

最初の Dockerfile:Next.js アプリケーション

Next.js アプリケーション用の Dockerfile を作成しましょう。概念を理解するために、可能な限りシンプルなものにします:

# Dockerfile
FROM node:20-alpine

WORKDIR /app

# 依存関係を先にコピー(レイヤーキャッシュ)
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile

# コードをコピー
COPY . .

# ビルド
RUN pnpm build

# 実行
EXPOSE 3000
CMD ["pnpm", "start"]

各行が 1 つの レイヤー です。Docker は各レイヤーをキャッシュします — package.json が変更されていなければ、依存関係のインストールをスキップします。だからこそ、コードよりも 先に 依存関係をコピーするのです。

# イメージをビルド
docker build -t meu-app .

# コンテナを実行
docker run -p 3000:3000 meu-app

# アクセス: http://localhost:3000

.dockerignore:イメージに含めないもの

.gitignore と同じように、.dockerignore はイメージ内にコピーすべきでないものを定義します。これによりサイズが削減され、ビルドが高速化します:

# .dockerignore
node_modules
.next
.git
.env
.env.local
README.md
.vscode
.claude

マルチステージビルド:最適化された本番イメージ

基本的な Dockerfile は動作しますが、最終イメージは重くなります — すべての devDependencies、ソースコード、ビルドファイルを含んでいるからです。本番環境ではビルドの出力だけが必要です。マルチステージビルドがこれを解決します:

# Dockerfile (multi-stage)

# Stage 1: 依存関係をインストール
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile

# Stage 2: ビルド
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN corepack enable && pnpm build

# Stage 3: 本番(必要なものだけ)
FROM node:20-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production

# ビルドから必要なものだけをコピー
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

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

違いは非常に大きいです:

  • 基本的な Dockerfile: 約 1GB(完全な node_modules、ソースコード、devDependencies)
  • マルチステージ: 約 150MB(Node.js + ビルド出力 + 静的ファイルのみ)

Docker Compose:完全な開発環境

ローカル開発では、docker-compose が複数のサービスをオーケストレーションします。実際のシナリオ:Next.js アプリ + PostgreSQL + Redis:

# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/myapp
      - REDIS_URL=redis://cache:6379
    depends_on:
      - db
      - cache

  db:
    image: postgres:16-alpine
    ports:
      - '5432:5432'
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: myapp
    volumes:
      - pgdata:/var/lib/postgresql/data

  cache:
    image: redis:7-alpine
    ports:
      - '6379:6379'

volumes:
  pgdata:
# 1 つのコマンドですべてを起動
docker compose up -d

# ログを見る
docker compose logs -f app

# すべてを停止
docker compose down

# 停止してボリュームをクリア(DB のリセット)
docker compose down -v

volumes: - .:/app はローカルコードをコンテナ内にマウントします — コードの変更はリビルドなしで即座に反映されます。- /app/node_modules は、ローカルの node_modules がコンテナのものを上書きするのを防ぎます。

開発環境 vs 本番環境

2 つの Dockerfile を用意するか、compose で target を使うのが一般的です:

# docker-compose.dev.yml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - '3000:3000'
    volumes:
      - .:/app
      - /app/node_modules
    command: pnpm dev
# Dockerfile.dev (シンプル、マルチステージなし)
FROM node:20-alpine
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install
COPY . .
EXPOSE 3000
CMD ["pnpm", "dev"]
# 開発
docker compose -f docker-compose.dev.yml up

# 本番
docker compose up --build

環境変数

シークレットを Dockerfile に決して書かないでください。.env または docker-compose 経由で環境変数を使います:

# .env (コミットしない)
DATABASE_URL=postgresql://user:pass@db:5432/myapp
STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_API_URL=http://localhost:3000/api
# docker-compose.yml
services:
  app:
    env_file:
      - .env
    # または個別に:
    environment:
      - NODE_ENV=production

必須コマンド

私が日常的に使うコマンドです:

# イメージ
docker build -t app .          # イメージをビルド
docker images                  # イメージを一覧表示
docker rmi app                 # イメージを削除

# コンテナ
docker ps                      # 実行中のコンテナ
docker ps -a                   # すべて(停止中を含む)
docker logs -f <container>     # リアルタイムのログ
docker exec -it <container> sh # コンテナに入る
docker stop <container>        # 停止
docker rm <container>          # 削除

# Compose
docker compose up -d           # バックグラウンドで起動
docker compose down            # 停止
docker compose down -v         # 停止 + ボリュームをクリア
docker compose logs -f         # すべてのサービスのログ
docker compose build --no-cache # キャッシュなしでリビルド

# クリーンアップ
docker system prune -a         # 未使用のものをすべて削除

本番環境へのデプロイ

マルチステージイメージが用意できれば、デプロイはレジストリに送信してサーバーで実行するだけです:

# ビルドとタグ付け
docker build -t meu-app:latest .

# Docker Hub(または ECR、GCR など)へプッシュ
docker tag meu-app:latest usuario/meu-app:latest
docker push usuario/meu-app:latest

# サーバー上で(プルして実行)
docker pull usuario/meu-app:latest
docker run -d -p 3000:3000 --env-file .env usuario/meu-app:latest

RenderRailwayFly.io などのサービスは Dockerfile を自動的に検出し、追加設定なしでビルドとデプロイを実行します。

よくあるエラー

  • イメージ内の node_modules + ローカルボリューム — ボリュームがコンテナの node_modules を上書きします。解決策:volumes に - /app/node_modules を追加する。
  • イメージが重すぎるnode:20-alpine ではなく node:20 を使っている。Alpine は約 5 倍小さいです。
  • ビルドが遅い — レイヤーキャッシュを活用できていません。コードよりも先に package.json をコピーしましょう。
  • ポートにアクセスできないEXPOSE を忘れているか、docker run -p でのポートマッピングを忘れています。
  • 環境変数が届かない — Next.js では、NEXT_PUBLIC_* 変数はランタイムだけでなく ビルド時 に利用可能である必要があります。

まとめ

Docker は DevOps だけのものではありません — あらゆる開発者にとっての 生産性 ツールです。Dockerfile と docker-compose があれば、開発からデプロイまで環境が一貫していることを保証できます。学習への投資はリターンに比べて小さいです:環境起因のバグの減少、より速いオンボーディング、そして予測可能なデプロイ。