ローカル開発環境の構築不要!Dockerを利用したRailsアプリ起動手順

Ruby

こんにちは。Enjoy IT Life管理人の仁科(@nishina555)です。

前回、ローカル環境でRuby on RailsのWebアプリ(以下Railsアプリ)を構築・起動する方法について『Railsの開発環境構築はこれでOK!rbenvの導入からRailsアプリ起動までの詳細手順』の記事で紹介をしました。

Railsの開発環境構築はこれでOK!rbenvの導入からRailsアプリ起動までの詳細手順

記事中でも紹介をしましたが、rbenvでrubyを管理することでRailsアプリで利用するrubyのバージョンを簡単に変更することができます。

今回は、前回紹介したRailsアプリの環境構築・起動をDockerを利用しておこなう方法について紹介します。
Dockerを利用することで、ローカルでrubyの環境を準備しなくてもRailsアプリを起動できるようになります。

Dockerってよく聞くし便利そうだからRails開発で利用したいけど、イマイチなにからやればいいのかわからないなー。

こんな方の参考になればと思います。

なお、今回の開発環境はDocker DesktopがインストールされたmacOS、作成するRailsアプリ名はrails_app、rubyのバージョンは2.6.3となっています。

Gemfileの用意

まずは作業ディレクトリの作成・移動をします。

$ mkdir rails_app
$ cd rails_app

Railsアプリで利用するgemはbundlerでインストールします。
RailsアプリのDockerイメージを作成するにあたり、まずはbundlerで利用するGemfileを作成します。

$ docker run --rm -v `pwd`:/rails_app -w /rails_app ruby:2.6 bundle init

docker runのオプションの意味は以下のようになっています。

docker runのオプション

オプション 内容
–rm Dockerコンテナ終了後、自動でコンテナを削除する
-v ディレクトリのマウント(ホストとDokcerのディレクトリを同期)
-w 作業ディレクトリの指定

上記のdocker runコマンドがやっていることをまとめると以下のようになります。

上記の『docker run』でやっていること
  • ruby:2.6のDockerイメージから作成したDockerコンテナの/rails_app上でbundle initを実行
  • コマンド実行後コンテナを削除
  • ローカルのカレントディレクトリとDockerコンテナの/rails_appのディレクトリを同期させる。
`pwd`の代わりに$PWDでもカレントディレクトリをマウントできます。

図を用いてコマンドの説明すると以下のようになります。

dockerでのbundle init

上記の説明からわかるように、ローカル環境に作成されるGemfileはDocker環境のruby・bundlerを利用しています。

ローカルに開発用のツールをインストールしなくてもアプリ開発ができるのはDockerを利用する大きなメリットです。

さて、先ほど作成されたGemfileですが、Gemfileの gem "rails" の部分のコメントアウトを外します。

Gemfile

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

- # gem "rails"
+ gem "rails"

railsが実行できるDockerイメージの作成

次に、ローカル環境のGemfileを利用して、gemがインストールされたDockerイメージを作成します。

まず、以下のようなDockerファイルを用意しましょう。

$ vim Dockerfile

Dockerfile

# ruby:2.6のDockerイメージをベースとして利用
FROM ruby:2.6

# 作業ディレクトリを/rails_appに指定
WORKDIR /rails_app

# ローカルのGemfileをDokcerにコピー
COPY Gemfile /rails_app/Gemfile

# /rails_appディレクトリ上でbundle install
RUN bundle install

上記のDockerfileをビルドしてDockerイメージを作成します。

カレントディレクトリに存在するDockerファイルからrails_appというDockerイメージを作成します。

$ docker build -t rails_app .

ビルド終了後、以下のようにDockerイメージが作成されていればOKです。

$ docker images

REPOSITORY                               TAG                 IMAGE ID            CREATED             SIZE
rails_app                                latest              bff5950f754a        27 seconds ago      924MB

Dockerイメージからコンテナを作成し、実際にデータが存在しているか確認してみましょう。例としてbundle listを実行してみます。

$ docker run --rm rails_app bundle list

Gems included by the bundle:
  * actioncable (5.2.3)
  * actionmailer (5.2.3)
  * actionpack (5.2.3)
  * actionview (5.2.3)
  ...
  ...
 (以下略)

Docker環境でgemの一覧が参照できることから、先ほど用意したDockerファイルから作成したイメージではbundle installが実行されていることがわかります。

Railsアプリの作成

ここまででrailsが実行できるDockerイメージが作成できました。
次に、作成したDockerイメージを利用してrails newを実行し、Railsアプリの雛形を作成します。
なお、-Bbundle installの実行をスキップするオプションです。

$ docker run --rm -v `pwd`:/rails_app rails_app rails new . -B

上記のコマンドの解説をします。

ローカル環境のカレントディレクトリとDocker環境の/rails_appをマウントさせることで、Docker環境にあるファイル・ディレクトリをローカルに同期しています。

また、bundle installですが、このあとDockerイメージを再度ビルドするときに実行されるため、rails newをするこのタイミングでは-Bオプションでスキップしています。

さて、ローカル環境を確認すると、先ほどローカル環境とDocker環境のディレクトリをマウントしたため、Railsアプリのディレクトリ構成がローカル環境に構築されていることがわかります。

.
├── Dockerfile
├── Gemfile
├── README.md
├── Rakefile
├── app
├── bin
├── config
├── config.ru
├── db
├── lib
├── log
├── package.json
├── public
├── storage
├── test
├── tmp
└── vendor
bundle installはDocker環境で実行されているため、bundle install後に作成されるGemfile.lockはこの時点ではローカル環境に存在しません。

また、bundlerでインストールしたgemはDocker環境の”/usr/local/bundle”に保存されています。
“/usr/local/bundle”はマウント対象のディレクトリではないため、ローカル環境にはbundlerでインストールしたgemは存在していません。

Railsアプリを起動するDockerイメージの作成

ここまででRailsアプリの作成が完了しました。
ここからはDockerファイルを編集し、『Railsアプリが起動するDockerイメージ』を作成します。

先ほど作成したDockerファイルを以下のように編集します。Railsアプリの起動に必要な最低限のものだけを用意しています。

Dockerfile

FROM ruby:2.6
+ RUN apt-get update -qq && apt-get install -y nodejs
WORKDIR /rails_app
COPY Gemfile /rails_app/Gemfile
RUN bundle install

+ COPY . /rails_app

# Start the main process.
+ CMD ["rails", "server", "-b", "0.0.0.0"]

以下の内容がDockerファイルに追加されています。

Dockerファイルに追加された内容
  • Railsアプリの起動に必要なパッケージ(nodejs)のインストール
  • ローカル環境のディレクトリ(rails newで作成された一式)をDocker環境にコピー
  • rails serverコマンドでRailsアプリを起動

なお、rails serverでは-bでバインドするIPアドレス(応答をするIPアドレス)の指定できます。
Dockerファイルでは0.0.0.0(ワイルドカード)を指定しているため、どのIPアドレスでリクエストがきても応答するようになっています。

Docker環境で起動したアプリケーションに外部からアクセスをする場合、『0.0.0.0』と指定をしないとアクセスできないので気をつけてください。(Docker環境のlocalhostとローカル環境のlocalhostは指すものが違うため。)

Dockerファイルを作成したら再度ビルドします。

$ docker build -t rails_app .

今回のDockerイメージから生成したコンテナにはRailsアプリのディレクトリが構築されていることがわかります。

$ docker run --rm rails_app ls

Dockerfile    README.md  bin        db   package.json  test
Gemfile       Rakefile   config     lib  public        tmp
Gemfile.lock  app    config.ru  log  storage       vendor

Railsアプリの起動

先ほど作成したDockerイメージからコンテナを作成し、Railsアプリを起動させましょう。
-p [ホストのポート]:[コンテナのポート]でホストとDockerコンテナのポートをマッピング(ポートフォワーディング)できます。

また、-vディレクトリをマウントさせた状態で起動することで『ローカル環境で修正したソースコードがDocker環境のRailsアプリにも反映される』『Docker環境のGemfile.lockが更新された際にローカル環境のGemfile.lockも自動更新される』といったことが可能になります。

$ docker run --rm -p 3000:3000 -v `pwd`:/rails_app rails_app

上記のコマンドの場合、『ローカル環境の3000番ポートにアクセス = Docker環境の3000番ポートにアクセス』となります。

localhost:3000にアクセスして以下のような画面が出ればOKです。

まとめ: Dockerはローカル開発環境構築の手間が省ける便利ツール

以上でDocker環境でRailsアプリを起動する手順について紹介を終わります。

Dockerを利用することで、ローカル環境にrbenv, ruby, bundlerなどの用意をせずにRailsアプリの開発をすることができるようになりました。

Docker環境でRailsアプリを起動する手順まとめ
  1. Dockerのrubyイメージを利用してbundle initを実行し、Gemfileを作成
  2. bundle installを実行したDockerイメージを作成
  3. railsがインストールされたDockerイメージを利用してrails new
  4. rails serverを実行するDockerイメージを作成
  5. Dockerコンテナをポートフォワーディングさせた状態で起動し、ブラウザにアクセス

この記事がいいなと思いましたらツイッター(@nishina555)のフォローもよろしくお願いします!