はじめに
前回は、Rails 7.1 により自動生成された Dockerfile
の中身を一通り確認してみましたが、
今回は、いよいよ、実際にコンテナを起動してみて、動作確認を行なっていきます。1
と言っても、自動生成される Dockerfile
は、本番環境での使用に向けて調整されたものになっているので、まずは、開発環境として利用するために、少し弄らせてもらうことにしましょう。
改めて rails new
を実行しよう
Dockerfile
を自動生成する際の( 特に CSS フレームワークをオプションで指定する場合の )注意点については、すでに別の記事にも書いているので、詳細は割愛しますが、
結論から言えば、以下のような手順で、必要なファイル群を自動生成( rails new
)していきます。
Rails 環境の確認
ここでは、rails new
するためだけに、次のようなコンテナを利用しますが、適宜、自分の環境で、各種ツールのバージョンを確認してもらえれば、それでも構いません。
docker run --rm -v .:/content -w /content -it ruby:3.2.2 bash
ともかく、rails
をインストール、もしくは 7.1
に更新して、バージョンを確認しておいてください。
gem install rails
↓( バージョンを確認 )
# rails --version
Rails 7.1.2
Node 環境の確認
今回は、rails new
を実行する際、css
オプションで Bootstrap を指定する予定なので、Node 環境も確認しておきます。2
お好みに合わせて、バージョンを調整しておきましょう。
apt-get update -qq && apt-get install --no-install-recommends -y npm
npm install -g n
n lts
↓( バージョンを確認 )
# node --version
v20.9.0
Yarn 環境の確認
同様に、とりあえず、Yarn 環境もあった方が良さそうなので、必要に応じて、確認しておいてください。2
npm install --global yarn
↓( バージョンを確認 )
# yarn --version
1.22.21
rails new
の実行
さて、環境は整ったので、そろそろ rails new
を実行していきます。
rails new . --database=postgresql --css=bootstrap
ちなみに、オプションとして、データベースには、PostgreSQL も指定しておきました。
これで、各種ファイルが、正常に生成されましたでしょうか?
開発環境用の Dockerfile
も作ろう
コンテナ内で作業していたとしても、ちゃんとマウントされていれば、ローカルにも、以下のようなファイル群が生成されているはずです。
% ls
.dockerignore .gitignore Dockerfile Procfile.dev app/ config.ru log/ public/ tmp/
.git/ .node-version Gemfile README.md bin/ db/ node_modules/ storage/ vendor/
.gitattributes .ruby-version Gemfile.lock Rakefile config/ lib/ package.json test/ yarn.lock
それでは、次のようにコピーして、本番環境用の Dockerfile.prod
も確保しつつ、開発用として Dockerfile
を編集していきたいと思います。
cp Dockerfile Dockerfile.prod
試しに「 本番環境での使用に向けて調整されている部分を、あえて逆調整する 」なら、例えば、以下のような感じになるでしょうか?
# syntax = docker/dockerfile:1
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.2.2
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
# Rails app lives here
WORKDIR /rails
# Install packages needed to build gems and node modules
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential curl git libpq-dev libvips node-gyp pkg-config python-is-python3 postgresql-client
# Install JavaScript dependencies
ARG NODE_VERSION=20.9.0
ARG YARN_VERSION=1.22.21
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
/tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
npm install -g yarn@$YARN_VERSION && \
rm -rf /tmp/node-build-master
# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
# Install node modules
COPY package.json yarn.lock ./
RUN yarn install
# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]
本番環境用の環境変数の設定とか、マルチステージビルドだとか、non-root ユーザーの作成などといった部分を、単に、根こそぎ削除してみました。3
今回は、これでうまく動くかどうか、ビルドしてみるとしましょう。
compose.yaml
を作成しよう
次に、Rails と PostgreSQL のコンテナを、Docker Compose を使って、簡単に立ち上げ、連携させるために、compose.yaml
ファイルを作成していきます。
この辺については、昔からお世話になっている「 Quickstart: Compose and Rails 」が、未だに参考になりますね。4
services:
db:
image: postgres:16.1-alpine
volumes:
- ./tmp/db:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/rails
ports:
- "3000:3000"
depends_on:
- db
一応、PostgreSQL 5 のバージョンも、固定しておきました。6
関連して、config/database.yml
を編集し、データベースの設定も整えておきましょう。
(...)
default: &default
adapter: postgresql
encoding: unicode
+ host: db
+ username: postgres
+ password: password
# For details on connection pooling, see Rails configuration guide
# https://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
<<: *default
database: content_development
(...)
要するに、以下の三行を追加するだけですね。
host: db
username: postgres
password: password
コンテナを起動しよう
それでは、次のコマンドを実行して( ビルドしつつ )コンテナを起動しましょう。
docker compose up -d --build
ここまでで、起動自体はできているはずですが、接続するデータベースが存在しないとエラーになってしまうので、次のコマンドで作成しておきます。
docker compose run --rm web rails db:create
そして、http://localhost:3000 にアクセスし、ちゃんと Rails が動いているかどうか、確認してみてください。
次のような「 ウェルカムページ 」が表示されれば、とりあえずは、成功です。
ただ、これだけだと「 本当に Bootstrap が使えるようになっているのか? 」までは分かりませんし、今後、その他の確認を行なっていくためにも、次のようなコマンドを実行するなりして、適当なページを作成しておきます。
docker compose run --rm web rails generate controller Articles index
Bootstrap も動作確認しよう
最後に、Bootstrap が使えるようになっているかどうかを確認するため、例として app/views/layouts/application.html.erb
を編集し、Navbar を導入してみましょう。
ほとんどコピペですが、以下のように、body
を更新してみてください。
(...)
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
</li>
</ul>
<form class="d-flex" role="search">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>
<div class="container-fluid mt-2">
<%= yield %>
</div>
</body>
</html>
これで、http://localhost:3000/articles/index にアクセスすると、次のように表示されるでしょうか?
ちなみに、自動的にインストールされた Bootstrap のバージョンについては、package.json
や yarn.lock
ファイルを参照するか、以下のようにコマンドを実行するなどして、確認することができます。
% docker compose run --rm web npm show bootstrap version
5.3.2
import maps について
ところで、上で追加した Navbar ですが、Dropdown を押してみてください。ちゃんと機能しているでしょうか?
ここまで、全く同じように作業してきた場合、おそらく、CSS については、確かにコンパイルされているのですが、実は、Bootstrap が利用する JavaScript の方は、たぶん読み込まれていません。
ブラウザのデベロッパーツールにも、次のようなエラーが出ているはずです。
Uncaught TypeError: Failed to resolve module specifier "bootstrap". Relative references must start with either "/", "./", or "../".
Rails 7 からデフォルトになったらしい、import maps 7 の設定ファイルを確認してみると、やはり Bootstrap は含まれていないようですね。
# Pin npm packages by running ./bin/importmap
pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
いずれは、自動的に追加されるようになるかもしれませんが、例えば、次のようなコマンドを実行すれば、Bootstrap を追加することができます。
docker compose run --rm web bin/importmap pin bootstrap
これで、上の設定ファイルに、以下の二行が追記され、Dropdown も動くようになっているはずです。
pin "bootstrap", to: "https://ga.jspm.io/npm:bootstrap@5.3.2/dist/js/bootstrap.esm.js"
pin "@popperjs/core", to: "https://ga.jspm.io/npm:@popperjs/core@2.11.8/lib/index.js"
場合によっては、import maps さえあれば、Node や Yarn は必要ないようですし、JavaScript 周りについては、改めて整理した方が良さそうですね。
詳細は、Rails ガイドなどを参照してください。
おわりに
もう少し触ってみないことには、どのような問題が潜んでいるか、定かではありませんが、まぁ、最低限の開発環境として、スタートラインには立てたと言って良いでしょうか?
ちなみに、Bootstrap Icons 8 も、すでに使えるようになっているようです。
ともかく、これをベースとして、色々と試してみるとしましょう。