ikuma-t.

登壇 登壇 検索

RubyMine2021.2.3でdocker compose環境のRailsを動かしてみる

動機

昨今の開発において、常識になっているDocker。

私もそろそろ学ばねばということで、書籍を使って概要を掴みました。

仕組みと使い方がわかる Docker&Kubernetesのきほんのきほん (Compass Booksシリーズ)

仕組みと使い方がわかる Docker&Kubernetesのきほんのきほん (Compass Booksシリーズ)

  • 作者:小笠原 種高
  • $1

Amazon

Dockerの仕組み、Dockerfile、Docker Composeの基本はわかったけれど、実際にRailsアプリを動かしてみたらどうなるんだろう?と気になっていたところ、RubyMineの公式がDocker Compose環境でRailsを動かすサンプルRailsを公開していたので、Railsアプリの起動までやってみました。

やること

チュートリアル: リモートインタープリターとしての Docker Compose | RubyMineをやる

サンプル$1:

github.com

やってみる

まずはgit clone

f:id:ikmbear:20211115164149p:plain

f:id:ikmbear:20211115164102p:plain

コマンドでも構いませんが、RubyMineを使用しているので、「Get from VCS」からサンプルVCSのURLを設定して、cloneを実施します。

DB設定をPostgresqlに変更する

cloneした時点ではDB設定がsqlite3になっているようなので、config/database.ymlを開き、使用するDBを変更します。

f:id:ikmbear:20211115170018p:plain

コンテナを起動する

次にdocker-compose.ymlを開いて、ガターにある矢印アイコンを押します。

f:id:ikmbear:20211115164929p:plain

これで/usr/local/bin/docker-compose -f /Users/tadokoroikuma/RubymineProjects/sandbox/sample_rails_app/docker-compose.yml up -dというコマンドが実行されます。

つまりは、このdocker-compose.ymlをベースとして、バックグラウンドでサービス(コンテナ)を起動するわけです。
これでPostgresqlとRubyのコンテナがそれぞれ作成&起動されます。

Rubyーとして、コンテナ上のRubyを指定する

次にRubyMineに対して、コンテナ上のRubyを参照するように設定します。

f:id:ikmbear:20211115184357p:plain

Preferences > Ruby SDK and Gemsを開き、「+」から「New Remote」を選択します。

f:id:ikmbear:20211115184525p:plain

f:id:ikmbear:20211115184601p:plain

続いて、Docker ComposeのwebコンテナのRubyを参照するように設定し、「OK」を押します。

DB作成と$1を行う

次にrails db:createrails db:migrateを実施します。
これに限らずですが、ターミナルからコンテナに入ってコマンドを直接実行する方法と、RubyMineの機能を使って実行する方法の2種類があるので、それぞれ解説します。

ターミナルからコンテナに入ってコマンドを直接実行する方法

# webコンテナを指定してコマンドを実行する(bashを起動する)$ docker-compose exec web bash # DBの作成を行う(rails db:migrateも同様)$ rails db:createCreated database 'sample_rails_app_db'Created database 'sample_rails_app_db_test

RubyMineの機能を使って実行する方法

RubyMineのRunAnythingに包含されている、Rake Taskの実行を用いて起動します。
(rakeタスクのコマンドはrailsコマンドに移管されたのですが、RubyMineの機能を使う場合は、Rakeタスクとして扱う必要があります。というかRailsコマンドで実行しても結局はRakeタスクを叩いているだけなので…)

^を2回押して、RunAnythingを呼び出し、rake --tasksと入力してEnterで実行します。

f:id:ikmbear:20211115185948p:plain

これをしないとどうもDocker環境でRakeタスクが認識できないようで…(これは不便)。

これでRakeタスクが使えるようになったので、RunAnythingからrake db:createを実行します(rake db:migrateも同様)

f:id:ikmbear:20211115190247p:plain

DBが作成されたか確認する

$1にはありませんが、RubyMineのDBクライアント機能を使って作成されたDBを確認してみましょう。

f:id:ikmbear:20211115190656p:plain

まずはDatabaseツールウィンドウを開いて、「+」ボタンからDataSourceとしてPostgreSQLを選択します。

f:id:ikmbear:20211115191120p:plain

次に接続に必要な情報を以下の通り設定していきます。

項目設定説明
Port54333docker-compose.ymlで設定したポート$1ードにもとづき、54333を指定します。
AuthenticationUser & Passwordpostgresのコンテナの設定にしたがい、この認証方法を指定します。
Userpostgresdatabase.ymlで定義した内容に従って、postgresを指定します
Password<空欄>docker-compose.ymlで指定した内容にて、パスワード不要のオプションを設定しているため、空欄にします
Databasesample_rails_app_dbdatabase.ymlで指定した内容に基づき、この名前のDBへの接続を指定します

入力が完了したら、TestConnectionを行い、問題なければOKを押してください。

f:id:ikmbear:20211115191635p:plain

うまくいけばこのようにDatabaseの中身を確認することができます。

Railsアプリケーションの実行

f:id:ikmbear:20211115191735p:plain

RAILSの実行対象に「DEVELOPMENT:SAMPLE_RAILS_APP」を指定し、再生ボタンを押します。

f:id:ikmbear:20211115191943p:plain

ブラウザを開き、http://0.0.0.0:3000/にアクセスするとサンプルアプリが起動します。

なおターミナルから実行する場合は以下のようにします。

$ docker-compose exec web bash$ bin/rails s -b 0.0.0.0

バインドマウントがされているか確認してみる

後述のdocker-composeの設定で、node_modulesを除くすべてのファイルの変更がコンテナ上に反映されます。
実際にソースを少し改変して、反映されることを確認してみましょう。

app/views/static_pages/home.html.erbを開き、23行目にある内容を書き換えてみましょう。

<h2> BindMountTest This is the home page for the <a href="https://www.railstutorial.org/">Ruby on Rails Tutorial</a> sample application. </h2>

この状態でアプリをリロードします。

f:id:ikmbear:20211115192819p:plain

たしかに内容が変更されていることが確認できました。

定義ファイルを確認する

ここまでで実際にRailsアプリを立ち上げることができました。ここからはこの環境を作成した定義ファイルを確認していきたいと思います。

docker-compose.yml

まずはdocker-compose.ymlからです。

version: '3'services: db: image: postgres volumes: - ./tmp/db:/var/lib/postgresql/data environment: POSTGRES_HOST_AUTH_METHOD: trust ports: - "54333:5432" web: build: . command: tail -f /dev/null volumes: - .:/sample_rails_application - /sample_rails_application/node_modules ports: - "3000:3000" # Ports required for debugging - "1234:1234" - "26166:26168" depends_on: - db

順番に見ていきます。

version: '3'

これは使用するDocker Composeのバージョンを指定しているだけです。
今回はバージョン3を指定しています。

services: db: # 略 web: # 略

次にservices、つまり使用するコンテナの設定です。今回はdbというコンテナとwebというコンテナの2種類を立てます。
順を追ってみてみましょう。まずはdbコンテナです。

db: image: postgres volumes: - ./tmp/db:/var/lib/postgresql/data environment: POSTGRES_HOST_AUTH_METHOD: trust ports: - "54333:5432"

以下各定義内容の説明です。

定義意味
image:postgresdbコンテナではpostgresqlをイメージとします
volumesdocker-compose.ymlからみた$1でvar/lib/postgresql/dataが呼び出されたら、ホストの./tmp/dbに読み取り、書き込みを行います。これによりデータが永続化できます
environmentPostgresqlとして、POSTGRES_HOST_AUTH_METHODを定義し、その値にtrustを指定します。このオプションはPostgresqlのパスワードが不要になるもので、推奨はされていません(今回は検証用のPostgresqlなので…)
portsホストのポート54333を5432にポート$1ードします。

volumesの指定は、Dockerの2つある方法のうちの「バインドマウント(Dockerエンジン上ではなく、ホストの指定した箇所に保存する)」の指定で、:を境にホスト:コンテナのように指定されています。

参考:Postgres - Official Image | Docker Hub

続いてwebコンテナを確認します。

web: build: . command: tail -f /dev/null volumes: - .:/sample_rails_application - /sample_rails_application/node_modules ports: - "3000:3000" # Ports required for debugging - "1234:1234" - "26166:26168" depends_on: - db

こちらも同様に各定義内容の説明です。

定義意味
builddocker-composeから見た$1で.つまり、カレント$1リにあるDockerfileをベースにしてコンテナを作成します。
commandコンテナ起動時のコマンドを指定する。tail -f /dev/nullは何もしないで起動を続けるためのコマンドで、RubyMine側でRailsを起動する際に、コンテナ内でRailsが立ち上がっているとプロセスが重複して起動できなくなることを回避するために、このようにしています。
volumes一行目は、コンテナの./sample_rails_applicationに対して、ホストの.(カレント$1リ)をバインドマウントしています。2行目はコンテナ上のnode_modules$1リを名前なしボリュームとしてマウントしています
portsポート$1ードを定義しています
depends_ondbコンテナに依存することを定義しています

結構ややこしいのが、node_modulesの名前なしボリュームでのマウントです。
まず先の通り、手元のソースの反映はバインドマウントによって、すべてコンテナ上と同期されます。
こうすると、ホスト上とコンテナ上のnode_modulesがそれぞれ同期されてしまうのですが、せっかくコンテナ上で固定したnodeが、ホストによって破壊されることになってしまいます。

そのため、node_modulesのみはバインドの対象外とするのですが、コンテナが破棄されたのちもデータを永続化するため、DockerEngine上に名前なしボリュームとしてマウントする手段をとっています。

参考:VSCode&Docker Volumeにおけるnode_modules問題を解決する

ここまでに記述した内容でたしかにコンテナが起動しているかは、コマンドでも確認することができますが、RubyMineのServicesタブを使って確認することができます。

f:id:ikmbear:20211115182514p:plain webコンテナのポート$1ード設定を確認

Dockerfile

つづいて、Dockerfileです。

# ruby2.7.2のイメージを使用するFROM ruby:2.7.2# yarnのリポジトリを追加します(apt-key add -は標準入力の内容を追加します。つまりcurlで取得した内容を追加します)RUN curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -# teeコマンドを使ってyarnのAPTパッケージレポジトリを自分のシステムに追加しますRUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list# 必要なパッケージをインストールしますRUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs postgresql-client yarn# RUN CMD ENTRYPOINT ADD COPYの際の作業ディレクトリを`/sample_rails_application`に指定RUN mkdir /sample_rails_applicationWORKDIR /sample_rails_application# 必要な初期設定系ファイルのコピーCOPY Gemfile /sample_rails_application/GemfileCOPY Gemfile.lock /sample_rails_application/Gemfile.lockCOPY package.json /sample_rails_application/package.jsonCOPY yarn.lock /sample_rails_application/yarn.lock# 初期設定系のインストールRUN gem install bundler -v '2.2.15'RUN bundle installRUN yarn install --check-files# イメージに`. /sample_rails_application`の内容を追加するCOPY . /sample_rails_application# ポート3000で通信するEXPOSE 3000

このimageを元に、docker-composeのwebコンテナは作成されるようです。

感想

素晴らしい書籍のおかげでDockerの基礎を理解できたのはよいものの、実際にRailsアプリを一から起動するとなると、ややハードルが高かったです。
しかしながら、この$1はすでに出来上がっている$1を使ってアプリを動かすので、その中継点として非常にちょうどいい題材だと思いました。

一点気になったのが、node_modulesはVolumeTrickを使って名前なしボリュームにマウントしているのに、Gemfileはいいのか?というところです。
なんか同じような類なので、Gemfileもボリュームマウントした方がいい気がするんですが、その話はまた別の機会に調べようと思います。

ikuma-t

ikuma-t

about

9割笑顔、1割 (´・ω・)