RailsアプリをDocker化する手順
既存のRailsアプリをDocker上で動かせるように環境構築を行います。
- Railsアプリを用意する
- Dockerfileを作成する
- docker-compose.ymlを作成する
- Gemfileを編集する
- config/database.ymlを編集する
- Dockerイメージをビルドする
- Dockerコンテナを作成し起動する
- webコンテナに対してデータベースを作成するコマンドを実行する
- http://localhost:3000 にアクセスして表示を確認する
Railsアプリを用意する
使用するバージョンは以下の通り。
- ruby 3.0.2
- rails 6.0.3
- gem 3.2.22
- bundler 2.2.22
- node 12.22.12
- npm 6.14.16
- yarn 1.22.19
- PostgreSQL 13.9
Dockerの基本的な使い方
Dockerは基本的に以下の流れで環境構築を行う。
- Docker Hubからイメージを取得する、またはDockerfileでイメージをビルドする
- イメージからコンテナを作成し起動する
- コンテナで任意の操作を行う
Dockerfileを作成する
Dockerfileを使ってコンテナの元となるイメージを作成する。
Dockerfileの内容は以下の通り。
# ベースイメージを指定する
FROM node:12 as node
FROM ruby:3.0.2
# ワーキングディレクトリを指定する
WORKDIR /src
# マルチステージビルドでrubyコンテナにnodeとnpmを追加する
COPY --from=node /usr/local/bin/node /usr/local/bin/
COPY --from=node /usr/local/lib/node_modules/ /usr/local/lib/node_modules/
RUN ln -fs /usr/local/bin/node /usr/local/bin/nodejs \
&& ln -fs /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
&& ln -fs /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx
# aptを更新し、必要なパッケージをインストールする
RUN apt-get update && apt-get install -y \
build-essential \
libpq-dev \
postgresql-client
# ホストのGemfileとGemfile.lockをコンテナの/src/にコピーする
COPY Gemfile Gemfile.lock /src/
# Gemをインストールする
RUN bundle install
# ホストのpackage.jsonとyarn.lockをコンテナ内にコピーする
COPY package.json yarn.lock /src/
# npmを使ってyarnをグローバルインストールする
RUN npm install --global yarn
# yarnを更新する
RUN yarn install
ベースイメージを指定する
FROM node:12 as node
FROM ruby:3.0.2
From
は使用するイメージを指定する。
Rubyとnodeのイメージを使う。イメージ名の後ろはバージョンを指定する。as
を使ってイメージ名を変更できる。
基本的にDockerfileは1つのファイルにつき1つのイメージだが、ここではマルチステージビルドを使ってnodeをインストールする。
マルチステージビルドによって複数のイメージを同時にビルドでき、イメージの容量を小さくできる。
ワークディレクトリを指定する
WORKDIR /src
WORKDIR
はDockerfileの内容を実行するディレクトリを指定する命令。
マルチステージビルドでrubyコンテナにnodeとnpmを追加する
マルチステージビルドを行うために、nodeとnpmのバイナリファイルをコピーして、シンボリックリンクを貼る。
COPY --from=node /usr/local/bin/node /usr/local/bin/
COPY --from=node /usr/local/lib/node_modules/ /usr/local/lib/node_modules/
COPY
はホストのファイルをコンテナ内にコピーする命令。
コマンドの最後にある\
はコマンドを改行するための文字で、2行目と3行目にある&&
はコマンドをつなげて同時に実行するための文字。
RUN ln -fs /usr/local/bin/node /usr/local/bin/nodejs \
&& ln -fs /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
&& ln -fs /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx
RUN
は後ろに記述したコマンドをコンテナ内で実行する命令。
ln
はファイルのリンクを作成するLinuxのコマンドで、-fs
オプションでシンボリックリンクを作成する。
aptを更新し、必要なパッケージをインストールする
RUN apt-get update && apt-get install -y \
build-essential \
libpq-dev \
postgresql-client
apt
はDebian系のLinuxディストリビューションのパッケージ管理システムのことで、apt-get
でコマンドを実行できる。
apt-get update
でaptを更新する。
apt-get install -y
でパッケージをインストールする。-y
のオプションをつけることで、インストール時に聞かれる質問を飛ばすことができる。
build-essential
は開発に必須のビルドツールを提供しているLinuxのパッケージ。
libpq-dev
はPostgreSQLクライアントのヘッダやライブラリを含むパッケージで、PostgreSQLを使うために必要になる。
postgresql-client
はPostgreSQLのクライアントアプリケーションであるpsqlを使えるようにするためのパッケージ。
ホストのGemfileとGemfile.lockをコンテナの/src/にコピーする
COPY Gemfile Gemfile.lock /src/
COPY
はホストのファイルをコンテナにコピーする命令。ホストとは自分のPCのこと。ここではGemfileとGemfile.lockをコピーする。
Gemfile
はRubyのパッケージ管理システムであるGem
を使うためのファイル。RailsもGemを使ってインストールする。
Gemfile.lock
はインストールされているパッケージとそのバージョンが記述されているファイル。
既存のRailsアプリなので、GemfileとGemfile.lockはすでに用意されている。
Gemをインストールする
RUN bundle install
bundle install
によって、コンテナ側でコピーしたホストのGemfileの内容を元にパッケージをインストールする。
bundle
はgemを管理するライブラリのこと。bundleを使うことで、gemの依存関係や互換性を管理してくれ、gemのパッケージを一括でインストールしたりできる。
ホストのpackage.jsonとyarn.lockをコンテナ内にコピーする
COPY package.json yarn.lock /src/
package.json
はnpmのパッケージ名が記述されたファイル。npmとはNode.jsのパッケージ管理システムのこと。
yarn.lock
はyarnのlockファイル。yarnとはnpm同様、Node.jsのパッケージ管理システムで、npmより動作が速い。
yarnではなくnpmを使ってもいい。npmの場合はpackage.lock.jsonを使う。
npmを使ってyarnをグローバルインストールする
RUN npm install --global yarn
npmを使ってyarnをグローバルインストールする。
yarnを更新する
RUN yarn install
yarn install
によってコピーしたpackage.jsonの内容でインストールされる。
docker-compose.ymlを作成する
Docker Composeを使用するためにdocker-compose.ymlを作成する。今回はDockerfileと同じディレクトリに作成する。
Docker Composeを使えば、複数のコンテナを同時に操作でき、またコンテナ同士で通信を行うためのネットワークを自動で作成できる。
docker-comopose.ymlの内容は以下の通り。
# Docker Composeのバージョンを指定する
version: '3'
# 各コンテナを指定する
services:
# webコンテナ
web:
# コマンドを実行するディレクトリにあるDockerfileを使ってビルドする
build: .
# ホストの3000番ポートとコンテナの3000番ポートを紐づける
ports:
- '3000:3000'
# コンテナを起動した時にrails serverを起動する
command: bundle exec rails s -p 3000 -b '0.0.0.0'
# docker-compose.ymlと同じディレクトリにあるファイルやフォルダをコンテナの/src配下にマウントする(ホストでの変更がコンテナに反映されるようにする)
volumes:
- .:/src
# dbコンテナを起動してからwebを起動する
depends_on:
- db
# dbコンテナ
db:
# Docker Hubのイメージを使う
image: postgres
# コンテナに環境変数を設定する
environment:
- POSTGRES_PASSWORD=password
Gemfileを編集する
railsでPostgreSQLを使うために、Gemfileに以下のコードを追記する。
gem 'pg', '~> 0.18.4'
config/database.ymlを編集する
Railsアプリを作成するとデータベースの設定を行うconfig/database.yml
が作られており、デフォルトではsqlite
になっているのでこれをpostgresql
に変更する。
database.ymlの内容は以下の通り。
default: &default
adapter: postgresql
encoding: unicode
host: db
username: postgres
password: password
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
<<: *default
database: rails-docker_development
test:
<<: *default
database: rails-docker_test
production:
<<: *default
database: rails-docker_production
イメージをビルドする
Docker Composeを使ってイメージをビルドする。
docker compose build
コンテナを作成し起動する
ビルドしたイメージを使ってコンテナを作成し起動する。
docker compose up -d
webコンテナでデータベースを作成する
起動したwebコンテナでrailsアプリのデータベースを作成する。
docker compose exec web rails db:create db:migrate
docker compose exec
コマンドは起動しているコンテナに対して後の命令を実行する。ここではwebコンテナに対してコマンドを実行する。
exec
の後ろはコンテナの名前を指定する。コンテナの名前はdocker-compose.ymlを使っていればservices
に記述した名前を使う。
web
以降のコマンドはrailsのコマンドを実行している。db:create
でデータベースを作成し、db:migrate
でデータベースのテーブルを作成する。
Railsのページを確認する
ここまでの操作がうまく実行できていれば、http://localhost:3000 にアクセスするとRailsのページが表示される。
3000というのはdocker-compose.yml内で記述したポート番号。もし違うアプリで3000番を使っている場合は他の番号を指定する。
※webコンテナがExitedになってしまう場合
webコンテナが起動してもすぐExitedになってしまうエラーが発生。
エラーメッセージ
/usr/local/bundle/gems/webpacker-5.4.4/lib/webpacker/configuration.rb:103:in `rescue in load': Webpacker configuration file not found /src/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /src/config/webpacker.yml (RuntimeError)
とりあえずconfig/webpacker.yml
を作成し、以下の内容を記述。
# Note: You must restart bin/webpack-dev-server for changes to take effect
default: &default
source_path: app/javascript
source_entry_path: packs
public_root_path: public
public_output_path: packs
cache_path: tmp/cache/webpacker
webpack_compile_output: true
# Additional paths webpack should lookup modules
# ['app/assets', 'engine/foo/app/assets']
additional_paths: []
# Reload manifest.json on all requests so we reload latest compiled packs
cache_manifest: false
# Extract and emit a css file
extract_css: false
static_assets_extensions:
- .jpg
- .jpeg
- .png
- .gif
- .tiff
- .ico
- .svg
- .eot
- .otf
- .ttf
- .woff
- .woff2
extensions:
- .mjs
- .js
- .sass
- .scss
- .css
- .module.sass
- .module.scss
- .module.css
- .png
- .svg
- .gif
- .jpeg
- .jpg
development:
<<: *default
compile: true
# Reference: https://webpack.js.org/configuration/dev-server/
dev_server:
https: false
host: localhost
port: 3035
public: localhost:3035
hmr: false
# Inline should be set to true if using HMR
inline: true
overlay: true
compress: true
disable_host_check: true
use_local_ip: false
quiet: false
pretty: false
headers:
'Access-Control-Allow-Origin': '*'
watch_options:
ignored: '**/node_modules/**'
test:
<<: *default
compile: true
# Compile test packs to a separate directory
public_output_path: packs-test
production:
<<: *default
# Production depends on precompilation of packs prior to booting for performance.
compile: false
# Extract and emit a css file
extract_css: true
# Cache manifest.json for performance
cache_manifest: true
うまく起動した。
webpackerはrailsのフロントの部分を便利に書けるもので、rails6では標準になっているらしい。
参考