DockerでRails環境構築

デザイン・システム室の大下です。

私は9月に未経験から入社し、弊社のサービスであるミールタイムなどに関わらせてもらっています。入社後、初めにDockerを用いてローカルの環境構築を行うことになったのですが、私自身Dockerというものを使ったことはありませんでした。

ただ先輩社員に言われるがまま、Dockerfileやdocker-compose.ymlといったファイルを受け取り、言われたコマンドを入力することで、なんとか環境構築することは出来ました。しかし、Dockerに関しては訳がわからず困惑していました。

私もまだまだ経験不足ですが、この記事ではDockerで簡単なrails環境を作っていく過程で、初学者にDockerへのイメージをより具体的に認識してもらいたいです!

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環境を作る

実際にDockerfileとDocker Composeを用いてrailsの環境を作っていきたいと思います。しかし、全てを説明するとブログがとても長くなってしまうので、話をかなり絞って説明していきます。

説明の前に1つだけ重要なことをお伝えしたいのですが、Dockerを用いた環境構築はDockerの知識だけがあれば可能というものではありません。PCに環境構築をするための知識がそもそも必要になることが多いため、初学者には理解することが難しい部分もあるということを覚えておいていただきたいです。

ここからDockerはインストール済みの前提で話を進めていきます。

まず新しくdocker_rails_testディレクトリを作成します。

このあとのファイル構成は以下のようになり、ターミナルでのコマンド実行も作成したdocker_rails_testディレクトリ下で実行していきます。

  • docker_rails_testディレクトリ
    • compose.yml
    • Dockerfile
    • Gemfile
    • Gemfile.lock

では、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をディレクトリ内に作成しましょう。

ここではアプリケーション用のイメージを作るために、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'

Dockerfileについては細かく見ていきましょう。

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ディレクトリに配置させています。

RUN bundle install

bundle installを実行します。これによりコピーしてきたGemfileに記述されたrailsおよびそれに関連するgemをインストールしてきます。

CMD ["rails", "server", "-b", "0.0.0.0"]

これはコンテナ起動時に実行するコマンドとなります。つまりこのアプリケーション用のコンテナが起動するということは「rails s」コマンドでrailsを起動するということです。railsがエラー等でうまく起動しないと、そのコンテナは停止します。コンテナが起動しない時にはrailsが起動するために不足していることがないかを考えていきましょう。

ここまででDockerfileの解説は終了です。

では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を用いて環境構築できるんだってことを感じてもらえればと思います。

現在デザイン・システム室では、新しいメンバーを募集しています。
少しでも興味を持たれた方、ぜひご応募ください。
お待ちしております!!