RubyMineでDocker-Compose経由の開発環境を構築する
業務でRubyMineを使っていて、docker-composeで構築されたアプリをRubyMineでデバッグ実行したくなった。
いきなり実プロジェクトを触るのもアレなので、まずは自前で動かせる環境を構築するところまでを行ったのでここに記しておく。
作業環境
MacOS 10.13.4
RubyMine Build #RM-183.5153.41, built on January 10, 2019
Docker for Mac version 18.09.1, build 4c52b90
docker-compose version 1.23.2, build 1110ad01
構築したい環境
- Dockerfileでアプリのコンテナを作る
- Rubyはコンテナ側のものを使用し、ホスト側のRubyは使わない
- PostgresとRedisも別コンテナで稼働させる
- Bundlerとかのインストール系はローカルにキャッシュさせて高速化したい
- Docker-composeで必要なコンテナをよしなに起動
- RubyMineで動かしたい
構築
まずはじめに
ホスト側のRubyを使用しないと書いたので、Gemfileは適当に書くか、コピペしてくる。
source 'https://rubygems.org' gem 'rails', '~> 5.2.1'
とはいえローカルにRubyとBundlerぐらいは入ってるはずなので、普通に$ bundle init とかでもいいと思う。
Dockerfileの準備
次にRailsアプリのDockerfileを作る。内容は以下の通り。
FROM ruby:2.6
ENV APPDIR /usr/local/myapp
RUN apt-get update && \
apt-get install -y vim less && \
apt-get install -y build-essential libpq-dev && \
apt-get install -y postgresql && \
apt-get install -y nodejs && \
gem install bundler && \
apt-get clean && \
rm -r /var/lib/apt/lists/*
WORKDIR $APPDIR
ENV BUNDLE_GEMFILE=$APPDIR/Gemfile
docker-compose.ymlの準備
そしてdocker-compose.yml
version: '2'
services:
db:
image: postgres:9.4
volumes:
- postgresql:/var/lib/postgresql/data
redis:
image: redis:3.2
app:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- bundle:/usr/local/bundle
- .:/usr/local/myapp:cached
ports:
- "3000:3000"
environment:
POSTGRES_HOST: db
REDIS_HOST: redis
depends_on:
- db
- redis
volumes:
bundle:
postgresql:
named-volumesを設定しておくとコンテナを破棄してもデータが永続化される。今回の例ではbundle,postgresqlが指定されていて、これらのデータは$ docker-compose downをした後も失われない。named-volumesは特定のディレクトリ名を指定する必要がなく、このVolumeはDockerがよしなに管理してくれる。
ちなみに、どんなVolumeが作られているのかを見たい場合は$ docker volume lsで一覧表示できる。
ここまで来ると$docker-compose upで各コンテナが起動できるようになる。
ただし、まだRailsアプリそのものは存在しておらず、Gemfileがただそこにあるだけなので、まずはbundleを実行してやる必要がある。
$ docker-compose run --rm app bundle installを実行すると、新しいコンテナプロセスを生成して、その中でbundle installが実行される。
初めてやったときは「違うコンテナでbundle installしてもちゃんと反映されるの?」と思ったが、bundleボリュームをマウントしていることで、違うコンテナで実行しても同一のボリュームに反映されるので問題ないことに気が付いた。
Railsアプリの準備
$ docker-compose run --rm app bundle installを実行すると、Rails、そしてそれに必要なGemのインストールが始まる。完了したら次はRailsプロジェクトを生成してやる。
$ docker-compose run --rm app bundle exec rails new . -d postgresでRailsプロジェクトを生成する。Gemfileを上書きしようとするので警告が出るが、Yで続行。
そしてdatabase.ymlは以下のように設定する。とりあえずdevelopmentの設定だけ以下に書いておく。
development: <<: *default database: myapp_development username: postgres host: db
ここで注意点が二つあって、一つ目は、DockerHubで提供されているPostgresのイメージはusername: postgresしか存在しておらず、ここを省略した場合コンテナのユーザ名(今回の例ではrootになる)でアクセスしようとしてしまうため、NoDatabaseError: FATAL: role “root” does not existと表示されてPostgresから弾かれてしまう点。
もう一つは、RailsアプリとPostgresのコンテナは分離されているので、hostを明示的に指定してあげないとアプリはlocalhost:5432を探しに行ってしまい、PG::ConnectionBadが出てしまう点。
このdbというのはdocker-compose.ymlで指定しているdepends_on: dbのこと。(多分)
ちなみにPostgresのイメージで作られるユーザがpostgresしか無いのはここを見れば分かる。オープンソース便利。
これで一通りRailsアプリの準備が整った。あとは$ docker-compose run --rm app bundle exec rails db:createをして適当にhttp://localhost:3000あたりにアクセスすることができるようになる。
(もしかしたら$ bundle exec rails db:migrateも必要かも、今回の例では試す前にModelとか作っちゃってたのでmigrateを要求された。)
無事Railsアプリが起動した。
で、ここからが本題
docker-composeで管理したアプリをRubyMineでデバッグ実行したい!
と言ってもここまで来たら大したことはしなくても大丈夫。やり方はここに書いてある通り。
https://pleiades.io/help/ruby/using-docker-compose-as-a-remote-interpreter.html
まず、デバッグ実行に必要なgemをいくつかGemfileに追記する。
group :development do ... gem 'debase' gem 'ruby-debug-ide' end
次にDocker for MacをRubyMineで設定する。
設定場所はPreference>Build,Execution,Deployment>Dockerにある。
次にdocker-composeで管理されているappコンテナのRubyをRubyMine側に認識させてやる。
設定場所はPreference>Language & Framework>Ruby SDK and Gemsから+を押してnew remoteを選択。
そして以下のように設定してやる。
設定が済んだらこのボタンを押してGemをRubyMine側で利用できるようにする。
これを押すとRubyMineの一番下のステータスバーでgemを処理しているプログレスバーが出現する。バーが出なくなったらデバッグ実行可能になるので、適当にブレークポイントを設置して、以下のデバッグボタンを押す。
デバッグ実行のログが出てきて、
docker-compose-initialization-with-rails_db_1 is up-to-date docker-compose-initialization-with-rails_redis_1 is up-to-date Recreating docker-compose-initialization-with-rails_app_1 ... Attaching to docker-compose-initialization-with-rails_app_1 app_1 | Fast Debugger (ruby-debug-ide 0.6.1, debase 0.2.2, file filtering is supported) listens on 0.0.0.0:1234 app_1 | => Booting Puma app_1 | => Rails 5.2.1 application starting in development app_1 | => Run `rails server -h` for more startup options app_1 | Puma starting in single mode... app_1 | * Version 3.12.0 (ruby 2.6.1-p33), codename: Llamas in Pajamas app_1 | * Min threads: 5, max threads: 5 app_1 | * Environment: development app_1 | * Listening on tcp://0.0.0.0:3000 app_1 | Use Ctrl-C to stop
これで、ブレークポイントを張った部分にコードの処理が到達すると一時停止してデバッグができる。
たまにデバッグ実行が開始されず、server is already running...と出るときがある。
この場合は、コンテナ側の${APP_DIR}/tmp/pids/server.pidを削除すれば解決することが多い。
$ docker-compose run --rm app /bin/bashで入って、$ rm tmp/pids/server.pidとするだけで良い。もっと楽な方法もあるかも。
おわりに
今回構築したRailsアプリのサンプルは以下から参照可能。
RubyMineはRailsそのもののコードを追っていくときに結構重宝していたけど、これで業務でもモリモリ使えるようになったのでやっていきたい。