(初学者向け)DockerでRails環境構築
初めに
この記事について
私が未経験からエンジニアとして会社に入った時、Dockerでローカルの環境構築を行いました。先輩の言う通りに操作を行い、環境構築はできましたが、自分では何が起こっているか全く理解できませんでした。今でもわからないことも多いですが、自分も多少Dockerへの理解が深まったので、この記事では私が実施したRails6の環境構築について解説していきます。
この記事を読む対象者
- DockerでRailsの環境構築してみたい初学者
解説の前に(私がDockerを学んだツール)
Dockerは奥が深いと思います。この記事を読んでも完璧に理解できるようにはなりませんし、自分もネットでいろんな記事を断片的に読んでもなかなか理解できない部分もありました。なので断片的な情報ではなく、Dockerの基礎からしっかり学べるものを2つだけ簡単に紹介させていただきます。
実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本
実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本
上記リンクのzennの本です。タイトルの通り、dockerよくわからないという人にピッタリな本で、これが無料なのかと驚きました。実際dockerよくわからなかった自分が、この本を丸々読んで、dockerなんとなくわかった!という気持ちになりました。
Docker&仮想サーバー完全入門
こちらの本です。基礎的なことから書いてあり、dockerへの理解を深められます。私は1つ目のzennの本を読んでから、こっちを読んだのですが、こちらの本からのみ得られた気づきもありましたし、サンプルコードが色々あるのも、自分が環境構築するときの参考になってよかったです。今回のRails環境もこちらの記事を参考に作成させていただきました。
環境構築するための前提知識
Dockerとは
まず、DockerとはDocker社が開発しているコンテナ型の仮想環境を作るプラットフォームです。
Dockerを用いることで、コンテナという箱の中に他とは隔離された環境を作り出すことができます。コンテナで分けることによって、異なる環境で動くアプリケーションを同時に動かすことができたり、他の人とその環境を共有することも簡単になります。
Dockerがどんなものなのか、どんなメリットがあるのかについてはいろんな方がわかりやすく説明しているので、調べてみてください。
(以下リンクは参考です)
Dockerで環境構築する大まかな手順
コンテナはイメージを基に作成されます。イメージはDockerHubというネット上に公開されている場所から持ってきて使うことができます。また、DockerHubから持ってきたイメージのままでは不足がある場合、Dockerfileを用いることで作成するイメージをカスタマイズすることができます。つまり、Dockerfileとはイメージを自分でアレンジして作りたいときに必要となるもので、既存のイメージで十分であれば不要なファイルということになります。
Dockerの特徴として、1つのイメージからは全く同じ複数のコンテナを作ることができ、イメージさえ持っていれば同じ環境を複製することができるというDockerのメリットになります。
例えるならば、
- イメージ=鋳型
- Dockerfile=イメージ(鋳型)を細かく設計する指示書
- コンテナ=イメージ(鋳型)から作られる実物
みたいな認識になります。
Dockerで環境構築する大まかな手順は以下のようになります。
- イメージを作成する
- イメージからコンテナを作る
- コンテナを起動する
Docker compose
続いてDocker Composeとは複数のコンテナの構築、実行する手順を自動化するツールです。1つ1つコマンドを打って、オプションを指定したり、コンテナを作成や起動するというのが面倒なので、それをcompose.ymlファイルを記載し、実行することでコマンドを打ち込む量を減らすことができるといった感じです。Docker Composeを用いなくても、都度docker container runなどのコマンドを打っていけば複数コンテナを用いた環境構築を行うこともできます。逆にコンテナが1つでもDocker Composeを用いてもいいのです。
なお、Docker ComposeにはV1とV2というバージョンがあり、V1ではdocker-compose.ymlファイル、docker-composeコマンドを用い、V2ではcompose.ymlファイル、docker composeコマンドを用いる等の違いがあります。現状V1で記述しても問題なく動作しますが、V2の使用が推奨となるので、今回はV2を用いて記述していきます。V1を用いた解説も多くあり、困惑してしまうかもしれないので、頭の片隅に入れてもらえればと思います!
実際にRails環境構築
実際にDockerを用いてrailsの環境を作っていきたいと思います。全ては説明し切れない部分もあるかと思いますが、なるべく初学者がわからない単語は解説するように心がけます。
(Dockerは既にインストール済みの前提で話を進めていきます)
まず新しくdocker_rails_testディレクトリを作成します。
このあとのファイル構成は以下のようになり、ターミナルでのコマンド実行も作成したdocker_rails_testディレクトリ下で実行していきます。
- docker_rails_testディレクトリ
- compose.yml
- Dockerfile
- Gemfile
- Gemfile.lock
わかりづらければ私のGithubのコードを参考にしてください。
compose.yml
では、compose.ymlを作成します。このファイルがdocker composeする際に必要なファイルです。
services:
#dbコンテナ
db:
image: mariadb:10.9
environment:
MARIADB_ROOT_PASSWORD: password
volumes:
- db-data:/var/lib/mysql
#webコンテナ
web:
build: .
depends_on:
- db
environment:
DATABASE_PASSWORD: password
ports:
- "3000:3000"
volumes:
- .:/docker_rails_test
volumes:
db-data:
いろんなオプションなどがあってわかりづらいですが、簡単に説明すると生成するコンテナに対する設定を行っています。webというアプリケーション用のコンテナとdbというデータベース用のコンテナを作成する際の設定を記述しています。
一部のコードについて見ていきましょう。
image: mariadb:10.9
railsを動かすためにはデータベースが必要なので今回はmariadbというものを用いています。細かくは説明しませんが、dbコンテナは上記のコードによりイメージをDockerHubから持ってきて使用しています。今回このイメージをカスタマイズする必要はないので、データベース用のDockerfileは作成しません。
build: .
それに対して、webコンテナにはimageという記述がないです。その代わり、上記のコードで現在のディレクトリに存在するDockerfileを基にイメージを作るということを記述しています。
Dockerfile
では、そのDockerfileをディレクトリ内に作成しましょう。
ここではアプリケーション用のイメージを作るために、railsの環境構築をする記述を書いていきます。
#Docker Hubからruby:3.0.5のイメージをプルする
FROM ruby:3.0.5
#debian系のためapt-getを使用してnode.jsとyarnをインストール
RUN apt-get update -qq
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
&& apt-get install -y nodejs
RUN npm install --global yarn
#docker内の作業ディレクトリを作成&設定
WORKDIR /docker_rails_test
#Gemfile,Gemfile.lockをローカルからCOPY
COPY Gemfile Gemfile.lock /docker_rails_test/
#コンテナ内にコピーしたGemfileを用いてbundel install
RUN bundle install
#railsを起動する
CMD ["rails", "server", "-b", "0.0.0.0"]
コメントアウトにもある程度の情報を記述しました。
合わせて同一ディレクトリ内にGemfileとGemfile.lockも作成します。
Gemfileは以下のように作成し、Gemfile.lockは中身空でファイルだけ作成します。
source 'https://rubygems.org'
gem 'rails', '6.1.0'
FROM ruby:3.0.5
まずはベースとなるイメージをDocker Hubから持ってきています。今回はrubyのバージョン3.0.5のイメージを持ってきています。これにより、rubyをインストールする手間は省くことができます。ベースとなるイメージをrubyではなく、OSのイメージを用いるとrubyをインストールするところから、記述を始めることになります。
RUN apt-get update -qq
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
&& apt-get install -y nodejs
RUN npm install --global yarn
続いてこちらは少しわかりづらいですが、要はrails6.0に必要なnode.jsとyarnをインストールしています。ここでのapt-getというコマンドは入っているOSによって変わります。今回はDebian系のLinuxディストリビューションが使用されているため、apt-getを使用していますが、OSが変わればインストールするコマンドが変わるくらいに捉えてもらえればと思います。つまり、DockerHubから持ってきたrubyのイメージがDebian系と呼ばれるOSを基に作られてたんだ〜ということです。
WORKDIR /docker_rails_test
こちらはコンテナ内の作業場所を指定しているくらいの認識で大丈夫です。
COPY Gemfile Gemfile.lock /docker_rails_test/
ローカルからGemfileとGemfile.lockをコピーして、コンテナ内の/docker_rails_testディレクトリに配置させています。これがないとビルド時に次のbundle installができません。
RUN bundle install
bundle installを実行します。これによりコピーしてきたGemfileに記述されたrailsおよびそれに関連するgemをインストールしてきます。
CMD ["rails", "server", "-b", "0.0.0.0"]
これはコンテナ起動時に実行するコマンドとなります。つまりこのアプリケーション用のコンテナが起動するということは「rails s」コマンドでrailsを起動するということです。railsがエラー等でうまく起動しないと、そのコンテナは停止します。コンテナが起動しない時にはrailsが起動するために不足していることがないかを考えていきましょう。
ここまででDockerfileの解説は終了です。
ではrailsが起動できるために更に準備を進めていきましょう。
Railsアプリの作成からコンテナ起動まで
ターミナルで以下を実行します。
$ docker compose run --rm web rails new . --force --no-deps --database=mysql
webコンテナ(アプリケーション用のもの)で「rails new」を実行します。これにより通常の「rails new」同様、railsに必要なたくさんのファイルが自動生成されます。この際先ほどの「rails s」コマンドではなく、上書きされた「rails new」コマンドを実行しており、ファイルを全て作り終えたら動かなくなる→つまり作成したコンテナは停止するわけです(今回はrmオプションでコンテナ停止と共に削除されます)。「rails new」以降のコマンドはdockerではなく、railsに関するものです。
「rails new」によりローカルのディレクトリ内にもちゃんとファイルが出来上がっていることが確認できます。これはcompose.ymlでバインドマウントというものを設定しているからなのですが、このアプリケーションに関するローカルとコンテナ内のディレクトリの中身が同期されているということになります。つまりローカルでファイルを編集すればコンテナ内のファイルも変わるのです。(ちなみに今回だとローカル、コンテナどちらも、docker_rail_testディレクトリ内が同期され、それ以外のファイルは同期されません)
ターミナルで以下を実行し、もう一度イメージをbuildし直します。
$ docker compose build
次にrails newで作成されたdatabase.ymlを修正します。
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: <%= ENV.fetch("DATABASE_PASSWORD") %> #修正
host: db #修正
port: 3306 #修正
「#修正」と記載した部分が修正箇所です。修正部分を簡単に説明すると、以下のようになります。要はrailsアプリが入っているwebコンテナがdbコンテナに接続するための情報をdatabase.ymlに記述するって感じです。
-
「password」
データベースのパスワードを指定。compose.ymlで環境変数を設定しており、ここではその環境変数を参照。 -
「host」
データベースのホスト名。mariadbのコンテナ名(今回はdb)を指定。 -
「port」
データベースのポート番号。mariadbはデフォルトのポート番号が3306なので、その値を指定。
以下コマンドを実行し、アプリケーション用とデータベース用の2つのコンテナを起動します。
$ docker compose up -d
これでコンテナ自体は起動したままの状態になります。
最後に以下コマンドで起動中のアプリケーション用コンテナに接続し、データベースを作成します。
$ docker compose exec web rake db:create
これでlocalhost:3000にアクセスすれば、railsの初期画面が確認できるようになりました。
これにてdockerを用いたrailsの環境構築は終了です。
最後に
説明を省いた部分もあってわかりづらいところもあるかと思いますが、DockerでRailsの環境構築をしたいという人の役に立てれば幸いです。誰かが公開している既存のイメージを利用することで楽をできる部分もありますが、DockerでRailsの環境構築をする場合には、Dockerの知識とRailsの環境構築をする知識のどちらも持っていないと簡単には理解できないという点が難しいですね。
Discussion