🦜

Next.jsとRailsを活用したDocker環境構築

に公開

はじめに

React、TypeScript、Tailwind CSS (v4)、Rails、PostgreSQLを扱えるDocker環境を構築する時に、インストールするパッケージをフロントエンド用とバックエンド用のディレクトリに分け、効率的に管理できるようにしたいと思ったので、備忘録として記事にまとめてみました。

目標

フロントエンドのビルドツールにNext.jsを採用し、 React + TypeScript + Tailwind CSS (v4) + Rails + PostgreSQLを搭載したDocker環境の構築を目指します。
インストールするパッケージはフロントエンド用とバックエンド用でそれぞれ管理できるようにし、dbサービスを含めた計3つのコンテナを構築します。

▲ frontend、backend、dbの3つのコンテナの構成を目指します
frontend、backend、dbの3つのコンテナの構成を目指します

環境構築までのステップ

以下の3ステップを踏んでいき、Docker環境の構築を行います。

【STEP1】React+TypeScriptプロジェクトの生成
 1.
Create-next-appでフロントエンドプロジェクトを生成
 2. TypeScript、Tailswind CSS、App Router(ルーティングシステム)、ESLintのインストール

【STEP2】Railsプロジェクトの生成
 1.
Rails newでRailsプロジェクトを生成

【STEP3】コンテナのビルド
 1.
compose.yml と Dockerfile.dev の作成
 2. コンテナを構築&起動

【準備】作業ディレクトリの作成

作業用のディレクトリを作成します。
アプリ名など分かりやすい名前にしましょう。

bash
$ mkdir myapp   # ここでは作業ディレクトリ名を「myapp」とします

【STEP1】React+TypeScriptプロジェクト生成

手順1. create-next-appの実行

以下のコマンドを実行してください。

⚠️ --tailwindオプションについて

create-next-appで--tailwindオプションを付加すると、Tailwind CSS v4がインストールされるようになったそうです。
v3を使う場合は--tailwindオプションをつけず、手動でインストールをする必要があります。

bash
# 一時的なNode.jsコンテナを起動してコンテナのシェルに接続
$ docker run --rm -it -v $(pwd)/front:/app -w /app node:22.16.0 sh

# yarn createで、next-appでプロジェクトを生成 (⚠️--tailwindオプションについて)
yarn create next-app . --typescript --tailwind --eslint --app --src-dir --turbopack --import-alias "@/*"

# package.jsonの設定
# エイリアスコマンド"dev"を"--hostname 0.0.0.0 --turbopack”として設定
sed -i 's/"dev": "next dev --turbopack"/"dev": "next dev --turbopack --hostname 0.0.0.0"/' package.json

# エイリアスコマンド"start"を"--hostname 0.0.0.0”として設定
sed -i 's/"start": "next start"/"start": "next start --hostname 0.0.0.0"/' package.json

# コンテナから退出
exit
📝 create-next-appのオプション説明
  • -typescript: TypeScriptを使用
  • -tailwind: Tailwind CSSを含める
  • -eslint: ESLintを設定
  • -app: App Routerを使用(Next.js 13+の新機能であるルーティングシステム)
  • -src-dir: ソースコードの格納先となるsrcディレクトリを作成
  • -import-alias "@/*": インポートエイリアスを設定
    モジュールをインポートする際に、相対パスを使わずに@を使ったエイリアスで使用できるようになります。
    相対パスでの指定  :import Component from '../../../components/Component’
    エイリアス@での指定:import Component from '@/components/Component’
📝 sed -i コマンドについて
  • sed: ストリームエディタで、テキストの処理や変換を行うコマンド
  • -i : in-placeの略で、指定したファイルを直接編集するオプション
    これを使うと、変更がそのままファイルに反映される
  • 's/ 文字列1 / 文字列2 /':s/ は置換コマンドで、文字列1を文字列2に置換します
    例えば、 s/[0-9]/X/gと書いた場合、数字を全てXに置き換えることができます
    /g :グローバルの略で、検索ヒットした文字列「全て」を対象にとります
📝 --hostname 0.0.0.0”について

コンテナ内のアプリケーションを外部からアクセス可能にするための設定です。
Next.jsでは--hostではなく、-- hostnameとしないとエラーになります。

front/package.json
    {
      "name": "app",
      "version": "0.1.0",
      "private": true,
      "scripts": {
        "dev": "next dev --turbopack --hostname 0.0.0.0",    // ここが変更される
        "build": "next build",
        "start": "next start --hostname 0.0.0.0",            // ここが変更される
        "lint": "next lint"
      },
      "dependencies": {
        "react": "^19.0.0",
        "react-dom": "^19.0.0",
        "next": "15.3.3"
      },
      "devDependencies": {
        "typescript": "^5",
        "@types/node": "^20",
        "@types/react": "^19",
        "@types/react-dom": "^19",
        "@tailwindcss/postcss": "^4",
        "tailwindcss": "^4",
        "eslint": "^9",
        "eslint-config-next": "15.3.3",
        "@eslint/eslintrc": "^3"
      }
    }
    

myapp/frontディレクトリ下に、プロジェクトファイル群が生成され、package.jsonが画像のように記述されていればOKです。

手順2. next.config.ts設定の更新

next.config.tsファイルを開き、下記の内容で更新してください。
フロントエンドからのAPIリクエストを直接バックエンドに届くようにします。

next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  experimental: {
    // Docker環境でのファイル監視設定
  },
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: 'http://backend:3001/api/:path*', // Rails APIへのプロキシ
      },
    ];
  },
};

export default nextConfig;

【STEP2】Railsプロジェクトの生成

手順1. Rails newの実行

下記のコマンドは、一時的なbackendコンテナを起動し、コンテナ内でRailsのインストールとRailsプロジェクトを生成します。

bash
$ docker run --rm -it -v $(pwd)/back:/app -w /app ruby:3.4.2 bash -c "gem install rails -v 7.2.2 && rails _7.2.2_ new . -d postgresql -j"
📝 Rails newのオプション

-d postgresql:PostgreSQLデータベースを使用することを指定
-j:JavaScriptを使用することを指定

📝 docker runのオプション

--rm:コマンド実行の完了後、コンテナを破棄
-w:コンテナ内の作業ディレクトリを指定
-i:コンテナの標準入力(STDIN)をオープンにすることができ、コンテナの中にいる状態でコマンドを入力できるようになる。
-t:仮想端末(TTY)を割り当てられ、コンテナ内での出力が確認できるようになる。
-it:-iと-tを組み合わせたオプションで、コンテナ内でコマンドを入力したり、出力を確認したりできるようになる。

画像のように、backディレクトリ内にRailsプロジェクトができていたらOKです。

手順2. database.ymlの設定

config/database.ymlを以下のように追加修正してください

config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: db            # 追加(※compose.ymlで定義したサービス名にすること!)
  username: postgres  # 追加
  password: password  # 追加

【STEP3】 コンテナのビルド

手順1. ファイルの作成

Dockerfile.dev と compose.yml を作成します。
Dockerfile.devはフロントエンド用とバックエンド用の2種類を作成し、各ディレクトリ下に配置します。

1-1. compose.ymlファイルの作成

myapp/下に作成します。

bash
$ touch compose.yml

作成したcompose.ymlに、以下の内容をコピー&ペーストしてください。

compose.yml
version: '3.8'

services:
  # PostgreSQLデータベース
  db:
    image: postgres:17
    restart: always
    environment:
      TZ: Asia/Tokyo
      POSTGRES_DB: myapp_development
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5431:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d myapp_development -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Railsアプリケーション
  backend:
    build:
      context: ./back
      dockerfile: Dockerfile.dev
    command: bash -c "bundle install && bundle exec rails db:prepare && rm -f tmp/pids/server.pid && bundle exec rails server -b 0.0.0.0"
    tty: true
    stdin_open: true
    volumes:
      - ./back:/back
      - bundle_data:/usr/local/bundle:cached
    ports:
      - "3001:3000"
    environment:
      TZ: Asia/Tokyo
    depends_on:
      db:
        condition: service_healthy

  # React開発サーバー(Next.js)
  frontend:
    build:
      context: ./front
      dockerfile: Dockerfile.dev
    command: bash -c "yarn run dev"
    tty: true
    stdin_open: true
    volumes:
      - ./front:/front
      - node_modules_frontend:/front/node_modules
    ports:
      - "3000:3000" # Next.jsのデフォルトポートは3000
    environment:
      TZ: Asia/Tokyo
    depends_on:
      - backend

volumes:
  postgres_data:
  bundle_data:
  node_modules_frontend:

📝 command: bash -c "yarn run dev" について

package.jsonのscriptsでは、任意のシェルスクリプトをエイリアス設定できます。

front/package.json
{
 // 省略

 "scripts": {
   // 任意のシェルスクリプトをエイリアス設定
   "dev": "next dev --turbopack --hostname 0.0.0.0",
   "build": "next build",
   "start": "next start --hostname 0.0.0.0",
   "lint": "next lint"
},

// 省略

よって、yarn runコマンドでエイリアス”dev”を呼び出していることになるので、command: bash -c "yarn run dev”は以下のシェルスクリプトを実行していることになります。

bash
# next.jsサーバーを開発モードで起動させるコマンド
next dev --turbopack --hostname 0.0.0.0
📝 Volumesのマウントについて

ホストマシン側のディレクトリとコンテナ側のディレクトリのマウント設定を行うと、紐づけたディレクトリ同士のデータが同期状態となります。
マウントの設定の対象となったコンテナのディレクトリ内のデータは、コンテナを再起動してもデータが失われなくなります(=データの永続化)。

compose.yml
volumes:
 - ./back:/back # myapp/back(ホストマシン側)を/back(コンテナ側)にマウント

1-2. front/Dockerfile.devファイルの作成

frontディレクトリ下に作成します

bash
$ touch front/Dockerfile.dev

作成したDockerfile.devに、以下の内容をコピー&ペーストしてください。

front/Dockerfile.dev
# Node.jsのltsである22.16.0
FROM node:22.16.0

# 必要なパッケージをインストール
RUN apt-get update && apt-get install -y libc6-dev git && apt-get clean

# アプリケーションディレクトリを作成
WORKDIR /front

# package.jsonとyarn.lockをコピーしてyarn install
COPY ./package.json ./yarn.lock ./
RUN yarn install

# アプリケーションコードを.(/front/)にコピー
COPY . .

1-3. back/Dockerfile.devファイルの作成

backディレクトリ下に作成します

bash
$ touch back/Dockerfile.dev

作成したDockerfile.devに、以下の内容をコピー&ペーストしてください。

back/Dockerfile.dev
# Ruby 3.4.2 のイメージを取得
FROM ruby:3.4.2

# 必要なパッケージをインストール
RUN apt-get update -qq && apt-get install -y \
    postgresql-client \
    build-essential \
    libpq-dev \
    imagemagick \
    git \
    && rm -rf /var/lib/apt/lists/*

# アプリケーションディレクトリを作成
WORKDIR /back

# GemfileとGemfile.lockをコピーしてbundle install
COPY ./Gemfile ./Gemfile.lock ./
RUN bundle install

# アプリケーションコードを.(/back/)にコピー
COPY . .

手順2. ディレクトリ構成の確認

Dockerfile.devとcompose.ymlが以下のように配置されていることを確認してください。

bash
myapp/
│
├── compose.yml
│
├── back/  # バックエンド(Rails)用フォルダ
│     └── Dockerfile.dev
│
└── front/ # フロントエンド用フォルダ
      └── Dockerfile.dev

手順3. コンテナを起動

3つのコンテナを構築&起動していきます。

bash
# コンテナイメージの作成 -> コンテナの構築 -> コンテナ起動までを一括で実行
$ docker compose up --build
📝 起動中のコンテナとイメージ、ボリューム、キャッシュを削除
bash
# 起動中のコンテナ、イメージ、ボリュームを削除
$ docker compose down --volumes --remove-orphans

# キャッシュの削除
$ docker builder prune -f

※もしコンテナの再構築を行う場合、前のコンテナのキャッシュを削除しないままdocker compose up --buildを実行してしまうと、修正前のDockerfile.devをもとにコンテナイメージを構築してしまうので必ずキャッシュを削除すること!

手順4. アプリの起動の確認

それぞれのローカルホストのURLに飛んで、成功例と同じ画面が表示されたら成功です。

  • localhost:[フロントエンドのポート番号]

  • localhost:[バックエンドのポート番号]

まとめ

今回はフロントエンド用とバックエンド用のコンテナに分けてのDocker環境構築を行いました。
自分の検索能力が低いからか、記事を見つけることができなかったので、自分なりの構築手順でまとめてみました。
なるべく手間のかからない環境構築手順に仕上げたつもりなので、もし参考になりましたら幸いです。

Discussion