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そのもののコードを追っていくときに結構重宝していたけど、これで業務でもモリモリ使えるようになったのでやっていきたい。