#はじめに
Railsの勉強を始めようと思ったが、どうせならDockerを使って仮想環境で開発したい。
しかしどちらも実務で使ったことがないためよくわからない(というかRubyすら触ったことがない)。
ということで、一から調べてみた。RailsとDockerの欲張りセット。
筆者はMacBookProを使っているため、MacOS向けの記事となります。
tl;td
- Rubyにまつわる各用語の確認、ローカル環境でRailsの導入・起動方法の確認
- 手動でDocker上でのRailsの導入・起動方法の確認
-
dockerfile
にRailsの導入・起動情報を文書化して格納し、docker-compose
から呼び出して起動
対象読者
- わたし
- これからRailsを勉強しようという方
- これからDockerを勉強しようという方
ロードマップ(超簡易版)
最終目標:Dockerによる仮想環境上でRails serverを起動し、開発できるようにする
※RailsのデフォルトサーバーはPumaです。この記事ではデフォルトのままなのでPumaを使いますが、便宜上「Rails server」と呼称します。
- Railsをローカル環境で起動する
- ローカル環境にRubyを導入する
- ローカル環境にRailsを導入する
- Railsプロジェクトを作成し、Rails serverを起動
- Docker環境を構築して仮想環境でRails serverを起動する
- ローカル環境にDockerを導入する
- DockerでRubyを使える仮想環境を構築する
- 仮想環境でRails serverを起動する
-
dockerfile
とdocker-compose
を使ってコマンド一つでRails serverを起動する-
dockerfile
を作成する -
docker-compose.yml
を作成し、起動する
-
Railsをローカル環境で起動する
これについては各所でがっつり解説されているので、ここでは流れ・用語の説明と参考資料の紹介にとどめます。
なお、この章の目的はRubyにまつわる各用語とRails serverの起動までの流れについて確認することが目的なので、既にバッチリの方は飛ばしてください。
参考資料:Ruby初学者のRuby On Rails 環境構築【Mac】
ローカル環境にRubyを導入する
流れ
Homebrewの導入(更新)-> rbenvの導入 -> Rubyの導入
ざっくりHomebrew解説
- MacOSにおけるパッケージ管理ツール
- Rubyのためだけのものではない
- 参考資料:homebrewとは何者か。仕組みについて調べてみた
ざっくりrbenv解説
- Rubyのバージョンを管理するためのツール
- Rubyのバージョン管理をrbenvで、rbenvのバージョン管理をHomebrewで行う(Homebrewは自分でやる)
- 参考資料:rbenvとは?(rbenvを利用したRubyのインストール)
ローカル環境にRailsを導入する
流れ
Bundlerの導入 -> BundlerでGemfileの作成 -> Gemfileの編集 -> Gemの取得(Railsの導入)
ざっくりGem解説
- RubyGemsが公開しているライブラリ
- 要はRubyの開発で使える便利なツール群のこと
- RailsもGemの一つ
- 参考資料:Ruby on Rails 初心者必見!パッケージ管理ツール『gem』を徹底解説
ざっくりBundler解説
- Gemの管理ツール
-
Gemfile
から利用するGemの情報を読み取り、ライブラリを自動で構築してくれるすごいヤツ - この記事では
$ bundle init
と$ bundle install
さえ覚えておけばOK - 参考資料:Bundlerの使い方
- 参考資料:bundle install と bundle updateの違いについて
Railsプロジェクトを作成し、Rails serverを起動
流れ
Railsからプロジェクトを作成 -> Rails serverの起動 -> 接続確認
Docker環境を構築して仮想環境でRails serverを起動する
ローカル環境にDockerを導入する
Docker公式から最新版を取得しましょう。
アカウントの登録が必要です。
なお、Dockerの基礎的な仕組みやコマンドなどについては、以下の参考資料がおすすめです。
参考資料:Dockerでプログラマが最低限知るべきことが、最速でわかるチュートリアル
docker
参考資料:【図解】Dockerの全体像を理解する -前編-
ざっくりDocker解説
- 仮想環境の構築・管理を行うツール
- 擬似的に様々な環境を構築することができ、ローカル環境と本番環境との差異を減らすことができる
- 「本番環境で急に動かなくなった問題」や「環境構築面倒すぎる問題」の救世主……らしい
DockerでRubyを使える仮想環境を構築する
参考資料:RailsアプリをDockerで開発するための手順
ここからが本題です。
まずは利用するイメージを決めます。Docker Hubにruby
という便利なイメージが用意されているので、ありがたく使わせていただきましょう。
$ docker pull ruby
イメージが取得できたら早速run……する前に、このイメージについて調べましょう。
$ docker inspect ruby
コマンドを実行すると大量の文字が吐き出されます。
目眩がするかもしれませんが、頑張って大事な記述を確認しましょう。注目するのは以下の場所です。
"ContainerConfig": {
……
"Env": [
"PATH=/usr/local/bundle/bin:/usr/local/bundle/gems/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"RUBY_MAJOR=2.6",
"RUBY_VERSION=2.6.0",
"RUBY_DOWNLOAD_SHA256=acb00f04374899ba8ee74bbbcb9b35c5c6b1fd229f1876554ee76f0f1710ff5f",
"GEM_HOME=/usr/local/bundle",
"BUNDLE_PATH=/usr/local/bundle",
"BUNDLE_SILENCE_ROOT_WARNING=1",
"BUNDLE_APP_CONFIG=/usr/local/bundle"
],
……
RUBY_VERSION=2.6.0
Rubyのバージョンを示しています。Docker Hubでも確認できますが、イメージ本体にも情報がしっかり記されていますね。
このバージョンは重要なので覚えておきましょう。あるいはイメージをpull
する段階で指定してあげてもいいでしょう。
BUNDLE_PATH=/usr/local/bundle
Bundlerのパスが指定されています。BundlerによるGemfile
を使ったGem管理を行えることがわかりますね。
ではこのイメージからコンテナを起動しましょう。
適当な名前のディレクトリを作成し、ターミナルの作業フォルダとします。
以降はプロジェクト名をproject_name
とします。
※project_name
以外の名前でも構いません。本記事ではこの名前で統一するということです。
$ docker run -i -t --name TEST -p 3000:3000 -v "$PWD":/usr/src/project_name ruby /bin/bash
まずは各オプションについて。
-i :コンテナのSTDIN(標準入力)にアタッチ。標準入力に入力できる状態にするということ。
-t :疑似ターミナル (pseudo-TTY) を割り当て。ターミナル画面で操作できるようにするということ。
--name :コンテナの名前。今回は'TEST'を指定。
-p :ポートの指定。今回は3000ポートを解放しています。
-v :ボリュームの指定。[ホストPCのディレクトリ指定]:[コンテナ内のディレクトリ指定]。
/bin/bash:コンテナ起動後に実行するコマンド。今回はシェルを指定。
上記の説明は簡略したもので語弊を含むので、気になった項目は別途調べることをお勧めします。
-i
と-t
の二つはセットで使う(-it
)ことが多いので是非覚えておきましょう。
ボリュームについては概念が難しいですが、とりあえず[ホストPCで指定したディレクトリ]を[コンテナ内で指定したディレクトリ]として扱えるようにする、程度の理解でいいと思います。
参考資料:Dockerリファレンス
うまく起動できたら下のような状態になるはずです。
root@03eb04059b1f:/#
コンテナの中のターミナルを操作しているようなイメージですね。
コンテナの中から一旦抜ける時はcontrol + pq
、再接続するときは$ docker attach [コンテナの指定]
です。
※exit
でも抜けられますが、コンテナが停止してしまうため注意。停止した場合、ポートを閉じてしまうようです。
※$ docker exec
でもコンテナに接続できます。ただし、プロセス接続するごとにプロセスが増えます。
仮想環境でRails serverを起動する
それでは今起動したコンテナでRails serverの準備をしましょう。
先ほどコンテナを起動した際に、コンテナ内のproject_name
ディレクトリをボリュームとして指定しました。
指定したディレクトリが作成されているはずなので、そこまで移動しましょう。
$ cd /usr/src/project_name
このディレクトリにRailsプロジェクトを作成していきます。
まずは何をするにもGemfile
が必要なので、Bundlerを使って作成しましょう。
$ bundle init
次にRailsを導入していきます。
Gemfile
を編集する必要がありますが、これはコンテナ内で行う必要はありません。Gemifile
を作成したディレクトリはコンテナ起動時にホストPC側のディレクトリとセットでボリューム指定したため、ホストPC側の指定したディレクトリにもGemfile
が作成されています。このGemfile
を編集するだけでOKです。
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
- # gem "rails"
+ gem "rails"
$ cat Gemfile
これでGemfile
の準備ができたので、GemのインストールとRailsプロジェクトの作成を行いましょう。
$ bundle install
$ bundle exec rails new .
rails exec .
は作業ディレクトリに対してRailsプロジェクトを作成します。
実行するとGemfile
の上書き確認をされるので許可しましょう。
ローカル環境ではこの時点でRails serverを起動できましたが、ruby
イメージから作成したコンテナではまだRails serverは起動できません。
ですが、なぜ起動できないか確認するためにも一度試してみましょう。
$ bundle exec rails server
/usr/src/project_name/vendor/bundle/ruby/2.6.0/gems/execjs-2.7.0/lib/execjs/runtimes.rb:58:in `autodetect': Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)
ExecJS::RuntimeUnavailable
というエラーについて調べてみると、どうやらJavaScriptランタイムというものが必要のようです。
今回はnode.js
を導入することにしましょう。
参考資料:rails sコマンド実行時に「Could not find a JavaScript runtime.」とエラーが出る場合の対処法
ruby
イメージではyum
コマンドは対応していないようなので、apt-get
を使ってインストールしましょう。
参考資料:apt-get - パッケージの操作・管理 - Linuxコマンド
$ apt-get update
$ apt-get install nodejs
完了したら今度こそRails serverが起動できるはずです。
$ bundle exec rails server
http://localhost:3000/に接続して起動できているか確認しましょう。
dockerfile と docker-compose を使ってコマンド一つでRails serverを起動する
ここからは今まで行ってきたことを設定として文書化していきます。
先ほどまで使用していたコンテナはもう使わないので、$ exit
で停止しておきましょう。
ただし、作成したRailsプロジェクトはそのままにしておいてください。
参考資料:Dockerfile リファレンス
参考資料:Compose ファイル・リファレンス
参考資料:RailsアプリをDockerで開発するための手順
dockerfile を作成する
まず、前の章で行ったことを整理しておきましょう。
-
ruby
イメージからコンテナを作成(本記事ではバージョン2.6.0) - ポート3000:3000を開放し、ボリュームを指定してコンテナを起動
- コンテナ内でRailsプロジェクトを作成
- コンテナに
node.js
をインストール - Rails serverを実行
dockerfile
を書くということは、これらの作業を文書化していくということです。
それではdockerfile
を書いていきます。Railsプロジェクトを作成したディレクトリにdockerfile
という名前でファイルを作成し、編集していきます。
まずは使用したイメージの情報です。
FROM ruby:2.6.0
:2.6.0
はバージョン情報です。指定しなければ最新版が自動で選択されますが、固定させた方がいいでしょう。
これはRubyのバージョンと同じなので、もし違うバージョンからRailsプロジェクトを作成したならそのバージョンに合わせてください。
次にポートの開放とボリューム指定ですが、dockerfile
ではホストPCのディレクトリを指定することはできません(後でdocker-compose.yml
で指定します)。よって、ここではポートの開放だけを行います。
FROM ruby:2.6.0
EXPOSE 3000
ここでポートの開放を行なっても、run
コマンドやdocker-compose.yml
で指定しなければ直接接続できないので注意してください。
次はコンテナ内でRailsプロジェクト作成ですが、これは後でボリューム指定により共有する予定なので必要ありません。
ですが、Gemfile
が無くてはGemのインストールができず、rails
コマンドが実行できません。
そこで、Gemfile
だけをコンテナ内にコピーしてインストールすることにします。
FROM ruby:2.6.0
ENV APP_ROOT /usr/src/project_name
WORKDIR ${APP_ROOT}
COPY Gemfile ${APP_ROOT}
COPY Gemfile.lock ${APP_ROOT}
RUN bundle install
EXPOSE 3000
各コマンドは以下の通りです。
ENV [key] [value] …… 環境変数の定義。
WORKDIR [ディレクトリ指定] …… 作業ディレクトリの指定
COPY [ソース指定] [保存先指定] …… ファイルのコピー。
RUN [コマンド] …… コマンドの実行。
これでコンテナ内でもrails
コマンドが利用できるようになります。
最後にnode.js
のインストールとRails serverの起動です。
FROM ruby:2.6.0
ENV APP_ROOT /usr/src/project_name
WORKDIR ${APP_ROOT}
RUN apt-get update && \
apt-get install -y nodejs
COPY Gemfile ${APP_ROOT}
COPY Gemfile.lock ${APP_ROOT}
RUN bundle install
EXPOSE 3000
CMD bundle exec rails server
Railse sever の起動がRUN
ではなくCMD
なのは、コンテナの立ち上げが完了してから実行してほしいからです。
もしRUN
で書いてしまうとそこで動作が止まってしまい、いつまでもコンテナが立ち上がらないということになってしまいます。
では、これでうまく動作するかどうか確認してみましょう。
$ docker build .
エラーが出ずにRails serverの起動までできればOKです。
docker-compose.yml を作成し、起動する
では、先ほど作成したdockerfile
を使ってdocker-compose.yml
を作っていきましょう。
先ほどと同じく、Railsプロジェクトのディレクトリに作成し、以下の通りに編集してください。
app:
build: .
ports:
- '3000:3000'
volumes:
- .:/usr/src/project_name
app: …… アプリケーションの名前。今回はappとした。
build: …… docker-composeのパス指定。今回は同一ディレクトリにある。
ports: …… 開放するポートの指定。
volumes: …… ボリュームの指定。
これで完了です。では起動してみましょう。
$ docker-compose up -d
http://localhost:3000/に接続して、いつものアレが表示されたらOKです!
ちなみに、ホストPCのディレクトリを参照しているため、ファイルを編集すると即座に反映されます。Gemfile
と同じですね。
おわりに
というわけで、起動できました。とりあえず動いたので満足。