ねこものがたり

いちにちいっぽ

docker-composeで動いてるrailsにローカルにあるgemをインストールしたい

これは備忘録です(きりり)

やりたいことと状況

  • 社内rubygemを作った!
  • コンテナ化してないrails newしたrailsアプリでは動作確認済み
  • テストも書いたけど社内gemなので社のrailsアプリに入れて動作確認したい
  • それらは全部コンテナ化されている

何に困っていたか

  • コンテナ化してないrailsアプリと同じ要領でGemfileでpath指定したら以下のように「そんなものはない」と言われて失敗する
# Gemfile

gem 'mygem', path: '/path/to/mygem'


$ docker-compose up 
 -> The path  '/path/to/mygem' does not exist.
 -> railsコンテナ起動しない

docker起動後にGemfile追記してbundle installしても同様のエラーメッセージが出ます。(まあ、それはそう)

やったこと

1. docker-compose.ymlでgemのあるディレクトリをvolumesでマウント

# docker-compose.yml
services:
  rails:
   (略)
     volumes:
      - /path/to/mygem:/lib/mygem

2. この状態でコンテナを起動

$ docker-compose up

3. railsのコンテナの中を確認

コマンドで確認したり

$docker inspect rails

{
  "Type": "bind",
  "Source": "/path/to/mygem",
  "Destination": "/lib/mygem",
  "Mode": "rw",
  "RW": true,
   "Propagation": "rprivate"
},

コンテナに入って確認したり。

$ docker exec -it rails bash
# ls /lib/mygem
-> mygemの中身がある

4. gemを追加

Gemfileにgemを追加してbundle installしたりdocker-composeを立ち上げ直したり。

# Gemfile
gem 'mygem', path: '/lib/mygem' # コンテナ側のパス

できたけど良くなかったやり方

良くない方法

  1. docker-compose.ymlでgemのあるディレクトリをvolumesで指定(上と一緒)
  2. コンテナでgem install mygem-1.0.0.gemして追加

良くない理由

  • Gemfileで管理してないgemができてしまう

  • Gemfileにないということはbundlerの管轄の外になってしまう(ということはBundler is an exit from dependency hellの恩恵も受けれられない)

これを調べていてわかったこと

  • docker-compose fileではvolumesでホストのパスを指定しマウントできるが、DockerfileのVOLUMEではホストのパスを指定できないこと。Dockerfile reference | Docker Documentationによると、ホストのディレクトリはホストに依存するのでdocker runコマンドの実行時にhost-dirディレクトリを宣言するようにとのことです。これはDockerfileを共有することで同じ環境を複数の開発者で共有するというDockerの良さを殺さないためだそうです。こちらのブログも参考にしました。

感想

最初自分ではマウント後gem installしてしまっていて「これでいいのかなー(もやもや)」とした状態でした。

よく考えたらその時点でコンテナ側のpathを指定したら良かったのに、「これ以上何もわからん。。。」って冷静じゃなかった気がします。

冷静になれなかった理由は”マウントしてるって言うことはどういうことか”とか"Gemfileのpath指定はどの世界の話か"っていうのをちゃんとわかってなかったり、そこを思考停止状態で日頃操作しているからかなって思いました。

Twitterで助言くださった@t_tonchimさん@udzuraさん、調べてわからんことを解説してくれた@naoty_kありがとうございました!