Skip to content

Docker構成

Dockerfileは、アプリケーションを実行するためのコンテナイメージを定義するファイルです。適切に設計することで、再現性、セキュリティ、パフォーマンスを向上させることができます。

問題のあるデプロイ(Dockerがない場合)

Section titled “問題のあるデプロイ(Dockerがない場合)”

問題のある手作業でのデプロイ:

Terminal window
# 問題: 手作業での環境構築
# 1. サーバーにSSH接続
ssh user@production-server
# 2. Rubyのインストール
sudo apt-get update
sudo apt-get install ruby ruby-dev
# 3. Node.jsのインストール
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# 4. データベースクライアントのインストール
sudo apt-get install postgresql-client
# 5. アプリケーションのデプロイ
git clone https://github.com/user/app.git
cd app
bundle install
npm install
# 問題点:
# 1. 環境の再現性が低い(サーバーごとに異なる環境)
# 2. 人的ミスが発生しやすい(手順の漏れ、誤り)
# 3. ロールバックが困難(以前の環境に戻せない)
# 4. スケーリングが困難(新しいサーバーごとに手作業が必要)

解決: Dockerによるコンテナ化

# 解決: Dockerfileによる環境の定義
FROM ruby:3.2.2
RUN apt-get update && apt-get install -y \
postgresql-client \
nodejs \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
CMD ["rails", "s", "-b", "0.0.0.0"]
# メリット:
# 1. 完全な再現性(同じDockerfileで同じ環境を構築)
# 2. 人的ミスの削減(コードで環境を定義)
# 3. 簡単なロールバック(以前のイメージを使用)
# 4. 簡単なスケーリング(同じイメージを複数のサーバーで実行)

Rails アプリケーションの Dockerfile 構成

Section titled “Rails アプリケーションの Dockerfile 構成”

Rails アプリケーションの Dockerfile は、Ruby の実行環境と、必要なライブラリ、データベースクライアントなどを構築します。

  • FROM: ベースとなるイメージを指定します。ruby:3.2.2 のようにバージョンを明示することで、環境の再現性を高めます。
  • WORKDIR: コンテナ内で作業を行うディレクトリを設定します。これにより、以降のコマンドはこのディレクトリ内で実行されます。

3. 必要なパッケージのインストール

Section titled “3. 必要なパッケージのインストール”
  • RUN: コンテナ内でコマンドを実行します。ここでは、Node.js や yarn、データベースクライアント(例:postgresql-client)といった、Rails アプリケーションに必要な依存関係をインストールします。複数の RUN コマンドをまとめることで、レイヤー数を減らし、イメージサイズを最適化できます。

4. ファイルのコピーとインストール

Section titled “4. ファイルのコピーとインストール”
  • COPY: ローカルのファイルをコンテナ内にコピーします。GemfileGemfile.lock を先にコピーして bundle install を実行することで、コードが変更されても Gem のインストールレイヤーを再利用できます。
  • CMD: コンテナが起動したときに実行されるコマンドを定義します。開発環境では rails s -b 0.0.0.0 のようにサーバーを起動するコマンド、本番環境では bundle exec rails s -e production などが一般的です。
# ベースイメージは、Ruby と Node.js が含まれるものを使用
FROM ruby:3.2.2
# 必要なパッケージをインストール
RUN apt-get update && apt-get install -y \
postgresql-client \
git \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 作業ディレクトリを設定
WORKDIR /app
# Gemfile と Gemfile.lock をコピーして bundle install を実行
COPY Gemfile Gemfile.lock ./
RUN bundle install
# ソースコード全体をコピー
COPY . .
# サーバー起動コマンド
CMD ["rails", "s", "-b", "0.0.0.0"]

Next.js アプリケーションの Dockerfile 構成

Section titled “Next.js アプリケーションの Dockerfile 構成”

Next.js の Dockerfile は、マルチステージビルドを使用するのが一般的です。これにより、開発環境に必要なツール(npm など)を含まず、本番環境で必要なファイルのみを含む軽量なイメージを作成できます。

  • FROM: ビルド用のベースイメージを指定します。
  • WORKDIR: 作業ディレクトリを設定します。
  • COPY: package.jsonpackage-lock.json をコピーして、npm install を実行します。
  • RUN: npm run build を実行し、本番環境用の Next.js アプリケーションをビルドします。
  • FROM: 本番環境用のベースイメージを指定します。通常はより軽量な Node.js イメージを使用します。
  • WORKDIR: 作業ディレクトリを設定します。
  • COPY —from=builder: 第一ステージでビルドした成果物(.nextpublicnode_modules など)をコピーします。これにより、本番環境のイメージにビルドツールを含める必要がなくなります。
  • CMD: アプリケーションを本番モードで起動するコマンドを定義します。
# 第一ステージ: ビルド
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build
# 第二ステージ: 本番環境
FROM node:18-alpine
WORKDIR /app
# .env.production や public フォルダをコピー
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json
# ポートを公開
EXPOSE 3000
# 本番環境で起動
CMD ["npm", "start"]

問題のあるDockerfile:

# 問題: コードを変更するたびにすべてのレイヤーが再ビルドされる
FROM node:18-alpine
WORKDIR /app
COPY . . # 問題: コードを最初にコピー
RUN npm install # 問題: package.jsonが変更されていなくても再実行される
RUN npm run build

解決: レイヤーキャッシュの最適化

# 解決: 変更頻度の低いファイルを先にコピー
FROM node:18-alpine
WORKDIR /app
# 1. package.jsonを先にコピー(変更頻度が低い)
COPY package.json package-lock.json ./
# 2. 依存関係をインストール(キャッシュされやすい)
RUN npm ci
# 3. ソースコードをコピー(変更頻度が高い)
COPY . .
# 4. ビルドを実行
RUN npm run build
# メリット:
# - package.jsonが変更されない限り、npm ciはキャッシュから実行される
# - ビルド時間が大幅に短縮される

問題のあるDockerfile:

# 問題: ビルドツールが本番イメージに含まれる
FROM node:18
WORKDIR /app
COPY package.json ./
RUN npm install
COPY . .
RUN npm run build
# 問題: node_modulesに開発依存関係も含まれる
# 問題: ビルドツールが本番イメージに含まれる
# イメージサイズ: 約1GB

解決: マルチステージビルド

# 第一ステージ: ビルド環境
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
# 第二ステージ: 本番環境
FROM node:18-alpine
WORKDIR /app
# ビルド成果物のみをコピー
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
# 開発依存関係を削除
RUN npm prune --production
# イメージサイズ: 約200MB(80%削減)
# 1. 非rootユーザーで実行
FROM node:18-alpine
# 非rootユーザーを作成
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
WORKDIR /app
# ファイルの所有権を変更
COPY --chown=nextjs:nodejs . .
# 非rootユーザーに切り替え
USER nextjs
CMD ["npm", "start"]
# 1. 軽量なベースイメージを使用
FROM node:18-alpine # alpine版は約5MB(通常版は約300MB)
# 2. 不要なファイルを削除
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# 3. マルチステージビルドを使用
# (上記の例を参照)

Dockerfileの適切な設計は、コンテナのパフォーマンス、セキュリティ、保守性に大きく影響します。

シニアエンジニアとして考慮すべき点:

  1. レイヤーキャッシュ: 変更頻度の低いファイルを先にコピー
  2. マルチステージビルド: 本番イメージのサイズを最小化
  3. セキュリティ: 非rootユーザーでの実行、脆弱性スキャン
  4. イメージサイズ: 軽量なベースイメージの使用
  5. ドキュメント化: Dockerfileの各ステップの目的をコメントで説明

これらの構成は一般的なものであり、各プロジェクトの要件に合わせてカスタマイズできます。