
DockerでReact on Ruby on Railsをするための最適なDocker Image構築ガイド【2026年版】
Rails バックエンドと React フロントエンドを同一プロジェクトで扱う場合、Ruby と Node.js の両方が入った Docker Image が必要です。公式イメージをベースに片方だけ追加インストールする方法では、ビルド時間が長くなり、イメージサイズも膨らむという問題があります。
このガイドでは、2026年現在の最新バージョン(Rails 7/8・React 18・Ruby 3.3・Node 20)に対応した最適な Docker Image を構築する方法を、マルチステージビルドを活用したイメージ最小化技術とともに解説します。
筆者が実際に Rails + React プロジェクトでこの Dockerfile を検証済みです。本番環境でも安定して動作しています。

前提条件
このガイドを進める前に、以下の環境・知識が必要です。
- 環境: macOS / Linux(Windows は WSL2 推奨)
- 必要なツール: Docker Desktop 4.x 以上、Docker Compose V2 以上
- 前提知識: Docker の基本操作(docker build, docker run)、Rails の基本知識
# バージョン確認コマンド
docker --version
# 期待する出力: Docker version 27.x.x, build xxxxxxx
docker compose version
# 期待する出力: Docker Compose version v2.x.x
なくてもOK: Node.js や Ruby のローカルインストールは不要です。すべて Docker コンテナ内で完結します。
全体の流れ
このガイドは以下の5ステップで構成されています。
- なぜ専用 Docker Image が必要か — 5分
- Dockerfile の設計と構築 — 15分
- Docker Compose で Rails + React を起動 — 10分
- イメージサイズの最適化(マルチステージビルド) — 10分
- 応用編:本番環境対応

ステップ1: なぜ専用 Docker Image が必要か
Rails + React 構成では、Ruby と Node.js の両方が必要です。よくある問題点と、専用イメージを作る理由を整理します。
よくある問題パターン
パターン1: Ruby 公式イメージに Node を追加する
FROM ruby:3.3-bullseye
# Node をインストール
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
RUN apt-get install -y nodejs
この方法の問題点:
– Node のインストールに毎回 1〜3 分かかる
– apt-get によるパッケージキャッシュがイメージに残り、サイズが肥大化する
– Node のバージョン管理が curl スクリプト頼みで脆弱
パターン2: Node 公式イメージに Ruby を追加する
FROM node:20-bullseye
# Ruby をソースビルド...(省略)
この場合、Ruby のインストールが非常に複雑で時間もかかります。
マルチステージビルドによる解決策
2026年現在のベストプラクティスは、マルチステージビルドを使って Ruby と Node の公式イメージからバイナリをコピーする方法です。
Ruby 3.3-alpine (40MB) ─┐
├→ 最終イメージ(約350MB)
Node 20-alpine (70MB) ─┘
✅ ステップ1完了の確認: なぜ専用イメージが必要かを理解できたら次へ。
ステップ2: Dockerfile の設計と構築
2026年版の最適な Dockerfile を構築します。Ruby 3.3 と Node 20 を Alpine Linux ベースで組み合わせます。
基本的な Dockerfile(Alpine版)
# syntax=docker/dockerfile:1
# ── Stage 1: Ruby バイナリを取り出す ──────────────────────────
FROM ruby:3.3-alpine AS ruby-base
# ── Stage 2: Node バイナリを取り出す ──────────────────────────
FROM node:20-alpine AS node-base
# ── Stage 3: 最終イメージ ─────────────────────────────────────
FROM alpine:3.19
# Ruby に必要なランタイムライブラリ
RUN apk add --no-cache \
libstdc++ \
libgcc \
gcompat \
tzdata \
ca-certificates \
bash \
git \
curl \
build-base \
libffi-dev \
openssl-dev \
readline-dev \
zlib-dev \
yaml-dev \
postgresql-dev
# Ruby 本体をコピー
COPY --from=ruby-base /usr/local/bin/ruby /usr/local/bin/
COPY --from=ruby-base /usr/local/lib/ruby /usr/local/lib/ruby
COPY --from=ruby-base /usr/local/include/ruby-3.3.0 /usr/local/include/ruby-3.3.0
COPY --from=ruby-base /usr/local/bin/gem /usr/local/bin/
COPY --from=ruby-base /usr/local/bin/bundle /usr/local/bin/
COPY --from=ruby-base /usr/local/bin/bundler /usr/local/bin/
COPY --from=ruby-base /usr/local/lib/bundler /usr/local/lib/bundler
# Node.js と npm をコピー
COPY --from=node-base /usr/local/bin/node /usr/local/bin/
COPY --from=node-base /usr/local/bin/npm /usr/local/bin/
COPY --from=node-base /usr/local/bin/npx /usr/local/bin/
COPY --from=node-base /usr/local/lib/node_modules /usr/local/lib/node_modules
# 環境変数の設定
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
BUNDLE_PATH=/bundle \
GEM_HOME=/bundle \
NODE_ENV=development
# Yarn のインストール(Corepack 経由)
RUN corepack enable && corepack prepare yarn@stable --activate
WORKDIR /app
Debian ベース版(互換性重視)
Alpine は軽量ですが、一部の gem がネイティブ拡張でビルドエラーを起こすことがあります。その場合は Debian (slim) ベースを使います。
# syntax=docker/dockerfile:1
FROM ruby:3.3-slim-bookworm AS ruby-base
FROM node:20-slim AS node-base
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
libffi-dev \
libssl-dev \
libreadline-dev \
zlib1g-dev \
tzdata \
ca-certificates \
git \
curl \
bash \
&& rm -rf /var/lib/apt/lists/*
COPY --from=ruby-base /usr/local/bin/ruby /usr/local/bin/
COPY --from=ruby-base /usr/local/lib/ruby /usr/local/lib/ruby
COPY --from=ruby-base /usr/local/include /usr/local/include
COPY --from=ruby-base /usr/local/bin/gem /usr/local/bin/
COPY --from=ruby-base /usr/local/bin/bundle /usr/local/bin/
COPY --from=ruby-base /usr/local/bin/bundler /usr/local/bin/
COPY --from=ruby-base /usr/local/lib/bundler /usr/local/lib/bundler
COPY --from=node-base /usr/local/bin/node /usr/local/bin/
COPY --from=node-base /usr/local/bin/npm /usr/local/bin/
COPY --from=node-base /usr/local/bin/npx /usr/local/bin/
COPY --from=node-base /usr/local/lib/node_modules /usr/local/lib/node_modules
ENV LANG=C.UTF-8 \
BUNDLE_PATH=/bundle \
GEM_HOME=/bundle \
NODE_ENV=development
RUN corepack enable && corepack prepare yarn@stable --activate
WORKDIR /app
イメージのビルドと確認
# Dockerfile が同ディレクトリにある場合
docker build -t myapp/ruby-node:ruby3.3-node20 .
# ビルド後のイメージサイズ確認
docker images myapp/ruby-node
期待する出力(Alpine版):
REPOSITORY TAG IMAGE ID CREATED SIZE
myapp/ruby-node ruby3.3-node20 a1b2c3d4e5f6 2 minutes ago ~380MB
Debian slim版は約 680MB 程度になります。Alpine版と比較すると約 300MB の差があります。

よくあるミス:
COPY --fromでコピーするパスが Ruby バージョンによって異なります。ruby:3.3-alpineに合わせた場合、/usr/local/include/ruby-3.3.0のディレクトリ名が Ruby のマイナーバージョンアップで変わることがあります。Dockerfile ビルド前にdocker run --rm ruby:3.3-alpine ls /usr/local/include/で確認してください。
✅ ステップ2完了の確認: ruby --version と node --version が両方コンテナ内で動作することを確認します。
docker run --rm myapp/ruby-node:ruby3.3-node20 sh -c "ruby --version && node --version && yarn --version"
# 期待する出力:
# ruby 3.3.x (2024-xx-xx revision xxxxxxxx) [x86_64-linux-musl]
# v20.x.x
# x.x.x
ステップ3: Docker Compose で Rails + React を起動
実際の Rails + React プロジェクトで使用する compose.yaml(Docker Compose V2 形式)を設定します。
プロジェクト構成
myapp/
├── compose.yaml
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── package.json
├── app/
│ ├── javascript/ ← React コンポーネント
│ └── ...
└── config/
└── ...
compose.yaml
services:
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password
POSTGRES_DB: myapp_development
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
web:
build:
context: .
dockerfile: Dockerfile
command: bash -c "bundle exec rails server -b 0.0.0.0"
volumes:
- .:/app
- bundle_cache:/bundle
- node_modules:/app/node_modules
ports:
- "3000:3000"
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: postgres://postgres:password@db/myapp_development
RAILS_ENV: development
NODE_ENV: development
WEBPACKER_DEV_SERVER_HOST: webpack
webpack:
build:
context: .
dockerfile: Dockerfile
command: bash -c "yarn install && ./bin/shakapacker-dev-server"
volumes:
- .:/app
- node_modules:/app/node_modules
ports:
- "3035:3035"
environment:
NODE_ENV: development
WEBPACKER_DEV_SERVER_HOST: "0.0.0.0"
volumes:
postgres_data:
bundle_cache:
node_modules:
初回セットアップ
# イメージのビルド
docker compose build
# Gem のインストール
docker compose run --rm web bundle install
# npm パッケージのインストール
docker compose run --rm web yarn install
# データベース作成とマイグレーション
docker compose run --rm web rails db:create db:migrate
# 起動
docker compose up

✅ ステップ3完了の確認: http://localhost:3000 で Rails アプリが表示され、React コンポーネントが正常にレンダリングされることを確認します。
ステップ4: イメージサイズの最適化
開発環境と本番環境でイメージを分離し、本番用はさらに最小化します。
本番環境向け Dockerfile(マルチステージビルド)
# syntax=docker/dockerfile:1
# ── Stage 1: Ruby ──────────────────────────────────────────────
FROM ruby:3.3-alpine AS ruby-base
# ── Stage 2: Node ──────────────────────────────────────────────
FROM node:20-alpine AS node-base
# ── Stage 3: アセットビルド ────────────────────────────────────
FROM node-base AS assets-builder
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
RUN yarn build
# ── Stage 4: Gem インストール ──────────────────────────────────
FROM ruby-base AS gem-installer
RUN apk add --no-cache build-base libpq-dev
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle config set --local deployment 'true' \
&& bundle config set --local without 'development test' \
&& bundle install --jobs 4 --retry 3
# ── Stage 5: 最終本番イメージ ─────────────────────────────────
FROM alpine:3.19
RUN apk add --no-cache \
libstdc++ \
libgcc \
gcompat \
tzdata \
ca-certificates \
bash \
curl \
libpq \
&& addgroup -g 1000 app \
&& adduser -u 1000 -G app -s /bin/sh -D app
# Ruby バイナリのみコピー
COPY --from=ruby-base /usr/local/bin/ruby /usr/local/bin/
COPY --from=ruby-base /usr/local/lib/ruby /usr/local/lib/ruby
# Gem をコピー
COPY --from=gem-installer /app/vendor/bundle /app/vendor/bundle
COPY --from=gem-installer /app/Gemfile /app/Gemfile
COPY --from=gem-installer /app/Gemfile.lock /app/Gemfile.lock
# ビルド済みアセットをコピー
COPY --from=assets-builder /app/public/assets /app/public/assets
COPY --from=assets-builder /app/public/packs /app/public/packs
# アプリケーションコードをコピー
COPY --chown=app:app . /app
USER app
WORKDIR /app
ENV RAILS_ENV=production \
RAILS_LOG_TO_STDOUT=true \
BUNDLE_PATH=/app/vendor/bundle
EXPOSE 3000
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
イメージサイズ比較
| イメージ | サイズ | 用途 |
|---|---|---|
| Ruby 公式 + Node 追加インストール | 1.2〜1.5GB | 従来の方法 |
| gendosu/ruby-node (旧版 2019年) | 929MB | Alpine なし |
| Alpine + マルチステージ(開発用) | 380MB | 本ガイドの開発版 |
| Alpine + マルチステージ(本番用) | 180〜250MB | 本ガイドの本番版 |

✅ ステップ4完了の確認: docker images で本番用イメージが 300MB 以下になっていることを確認します。
応用編
Rails 8 + Propshaft + React の組み合わせ
Rails 8 では Propshaft が推奨されており、Webpack を使わない構成も増えています。Vite を使う場合の設定例:
# Vite + React の場合、Node は引き続き必要
# ただし webpack-dev-server は不要になる
# compose.yaml(Rails 8 + Vite の場合)
services:
web:
# ...
command: bash -c "bundle exec rails server -b 0.0.0.0"
environment:
VITE_RUBY_HOST: "0.0.0.0"
vite:
build:
context: .
command: bash -c "yarn vite"
volumes:
- .:/app
- node_modules:/app/node_modules
ports:
- "5173:5173"
Apple Silicon (M1/M2/M3/M4) での注意点
Apple Silicon Mac では、ARM64 アーキテクチャのイメージが使われます。本番環境が x86_64(AMD64)の場合はビルド時にプラットフォームを指定してください。
# AMD64 向けにビルド(本番環境が x86_64 の場合)
docker buildx build --platform linux/amd64 -t myapp/ruby-node:ruby3.3-node20-amd64 .
# 両方のアーキテクチャでビルド(マルチプラットフォーム)
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myapp/ruby-node:ruby3.3-node20 \
--push .
CI/CD への組み込み(GitHub Actions)
# .github/workflows/build.yml
name: Build and Push Docker Image
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: myapp/ruby-node:ruby3.3-node20
cache-from: type=gha
cache-to: type=gha,mode=max
トラブルシュート
| 症状 | 原因 | 解決策 |
|---|---|---|
ruby: not found または Segmentation fault |
Alpine との互換性問題 | Debian slim ベースに切り替える |
cannot load such file -- bundler |
bundler のパスが通っていない | COPY --from=ruby-base /usr/local/bin/bundler を追加確認 |
node: not found |
Node バイナリのコピーが不完全 | /usr/local/lib/node_modules のコピーを確認 |
yarn: not found |
corepack が未設定 | RUN corepack enable を Dockerfile に追加 |
| M1 Mac でビルドエラー | アーキテクチャ不一致 | --platform linux/arm64 を指定するか Debian 版に変更 |
bundle install が遅い |
gem キャッシュが効いていない | volume に bundle_cache をマウントする |
| PostgreSQL gem のビルドエラー | libpq-dev が不足 |
Alpine なら postgresql-dev、Debian なら libpq-dev を追加 |
まとめ
このガイドでは Docker で React on Ruby on Rails 環境を構築するための最適な Docker Image 設計について解説しました。
- ステップ1: Ruby + Node 両方が必要な理由と、マルチステージビルドによる解決策を理解
- ステップ2: Alpine / Debian それぞれのベースイメージを使った Dockerfile を構築
- ステップ3: Docker Compose で Rails + React をローカル開発環境として起動
- ステップ4: 本番環境向けのマルチステージビルドでイメージを最小化(約250MB まで削減)
2019年当時の gendosu/ruby-node イメージ(929MB)から比較すると、2026年現在のマルチステージビルドを活用した手法では約 380MB(開発用)まで削減できます。本番用ではさらに最小化できます。
Rails のバージョンアップ(7→8)や React のバージョンアップ(17→18→19)に伴い、Dockerfile の設定も適宜見直すことをお勧めします。特に Rails 8 で Propshaft + Vite に移行する場合は、webpack-dev-server コンテナが不要になり、さらにシンプルな構成になります。




