Dockerで外部依存のあるgemを試す
概要
開発中、使っているgem
が原因であろう事象が発生したときに、github
でホスティングされているgem
の場合そのgem
のソースを調べますよね。
で、調べた結果どうもおかしいからもっと詳細に確認してみたいということでcloneしてきてtest実行なども行おうとすると、ライブラリによってはとても大変な時があります。
代表的なのは外部依存があるパターンです。
ruby
のライブラリレベルであれば、bundler
で依存関係含めてインストールできるので問題ないですが、外部のミドルウェアに依存しているようなライブラリになると結構大変です。
ライブラリの挙動を調査、確認したいだけなのにその都度ミドルウェアをローカルPCにインストールして・・・なんてやってられないですよね。
最近たまたまそういうケースがあって、docker
を使って非常にうまく対処できたのでそのメモです。
また、OSSのライブラリにプルリク送ってみたのは始めただったのでその部分も書いてみます。
背景
今関わっているプロジェクトでは、既存のシステムをrails
に乗せ換える必要があったので、DBは新規構築でなく既存のスキーマをそのまま使う要件となっていました。なので、ActiveRecord wayなid
カラムが主キーになるテーブル以外に複合主キーのテーブルがたくさんあります。
それをサロゲートキーを追加してActive Recordに合う形にする方式もあると思いますがsqlの変更や既存データの移行含めて大変そうなので、今のスキーマのまま移行したいというのが要件です。
そこでrails
で複合主キーを扱うために有名なcomposit-primary-keyを導入しています。
このライブラリはとても良く出来ていてoracle
, mysql
, postgresql
, sqlite3
などメジャーなDBMS
に対応していて、業務系のシステムをrailsで扱う場合とても重宝します。
今回発生した問題
つい先日, rails
の rc1 が出ましたね!
上記のプロジェクトはrails5
で構築しようとしているので早速導入しました。するとエッジなrails
の常だと思いますが、composit-primary-key
がまだrc1
に対応しておらず、v5.0.0.beta3まで正常に動いていたコードがエラーになりました。
composit-primary-key
のサイトを見てみると導入していたバージョンはrails5
対応版である v9.0.0.0.beta1 なので、これでエラーが起こっているということはrails5
のbeta3
からrc1
の間にはいった変更のせいでエラーになっているのであろうと推測できます。
具体的な問題
rails
をrc1
に変更すると、下記のエラーで起動すらできませんでした。
ArgumentError: wrong number of arguments (given 2, expected 1)
/var/data/vendor/bundle/ruby/2.3.0/gems/activerecord-5.0.0.rc1/lib/active_record/connection_adapters/abstract/connection_pool.rb:842:in `establish_connection'
/var/data/vendor/bundle/ruby/2.3.0/bundler/gems/composite_primary_keys-9ff65e55df48/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb:25:in `establish_connection'
ArgumentError
ですので、composit-primary-key
がrails
のAPI
の変更においついていないんだろうなと推測できます。
composit-primary-keyの調査
さて、アタリはついたので、実際にcomposit-primary-key
を確認してみます。
git clone
して該当のブランチをテストしてみましょう。
% git clone git@github.com:composite-primary-keys/composite_primary_keys.git
で、該当のタグからブランチを切ります。
% git checkout -b v9.0.0.0.beta1 refs/tags/v9.0.0.0.beta1
多くのgithub
プロジェクトでは、TOPレベルのREADME.md
にテストの仕方を書いているので確認してみると
と書いてあったので、test/README
を見てみます。
すると、上記のようになっていたので、実際にテストするためにはbundle install
での依存ライブラリだけでなく、dbms
本体が必要なようです。
Dockerで環境構築
以下%
で始まっているのはホスト側、root@
で始まっているのはコンテナ内のシェルです。
bundle install
で済むなら簡単なんですが、テストするためにmysql
だのpostgresql
だのをローカルにインストールなんてやってられません。
そこでDocker
です。 ruby
のライブラリなので、公式のruby
のコンテナ上でmysql
やpostgresql
をインストールして確認して見ます。
rubyのdockerコンテナ
composit-primary-key
のトップレベルのファイルに.ruby-version
があったので確認して見ると
% cat .ruby-version
2.2.2
とのことなので、2.2.2
の環境を使います。
その際、clone
してきたホスト側の内容はそのまま使いたい(ファイルの編集はホストでしたい)ので-v
でマウントします。
コンテナ実行
% docker run -it -v $(pwd):/var/ruby ruby:2.2.2 bash
Unable to find image 'ruby:2.2.2' locally
2.2.2: Pulling from library/ruby
4d2e9ae40c41: Already exists
a3ed95caeb02: Already exists
7c8152785df5: Already exists
8b04aafd7cd8: Already exists
412dfc97bdb3: Already exists
4d2a6e278593: Already exists
1fce3d6a0fe1: Already exists
79aaa3ae3986: Already exists
Digest: sha256:76059222ec07aa8b9dc6fe2ff097a359ded336c98c664911bb3bd6545604ad5f
Status: Downloaded newer image for ruby:2.2.2
root@0f4fa7cb0443:/#
マウントした/var/ruby
に移動してホスト側でclone
した内容を確認します。
root@581d9cc2d677:/# cd /var/ruby; ls
Gemfile History.rdoc README.rdoc README_DB2.rdoc Rakefile composite_primary_keys.gemspec lib log scripts tasks test website
きちんと見えていますね。
では、とりあえずmysql
でテストしてみましょう。docker公式のruby
はdebian
ベースなので、apt
でインストールします。
root@581d9cc2d677:/var/ruby# apt-get update; apt-get install mysql-server
途中mysql
のroot
のパスワードを入力させられました。運用するわけでは無いので何でもいいです。今回はroot
としました
インストールしたmysql
を起動します。
root@581d9cc2d677:/var/ruby# /etc/init.d/mysql start
[ ok ] Starting MySQL database server: mysqld ..
[info] Checking for tables which need an upgrade, are corrupt or were
not closed cleanly..
次に、test/README
に従ってホスト側でテンプレートを元にdatabase.yml
を編集します。
% cp test/connections/databases.example.yml test/connections/databases.yml
% vi test/connections/databases.yml
mysql
の設定のところに、インストール時に設定したパスワード, root
を設定して保存します
mysql:
adapter: mysql2
username: root
password: root # <= ここを追加
database: composite_primary_keys_unittest
これで設定は整ったので、コンテナ内でbundle install
します。(ここではプロジェクトローカルにgem
をインストールするために--path
を指定してます)
root@581d9cc2d677:/var/ruby# bundle install --path=vendor/bundle
〜中略〜
Installing activesupport 5.0.0.rc1
問題になっているrails rc1
がインストールされたことは確認しときます。
さて、これで実行出来るようになりました。引き続きtest/README
に従ってテストを実行します。
root@581d9cc2d677:/var/ruby# bundle exec rake mysql:build_database
rake aborted!
ArgumentError: wrong number of arguments (2 for 1)
/var/ruby/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.0.rc1/lib/active_record/connection_adapters/abstract/connection_pool.rb:842:in `establish_connection'
/var/ruby/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb:25:in `establish_connection'
バッチリ同じエラーが再現しました!
さて、ココからはひたすら直すだけです。特に言語、ライブラリ依存でないので省略します(プルリク出したので内容は後述の内容参照)。エラー箇所とrails rc1
になって変わったところをいろいろ確認して直します。
修正後の確認
さて、修正前はそもそもテストの実行すら出来なかったので、テストの実行箇所までログを残しておきます。
修正後のソースツリーでtest/README
に従ってテストしていきます。
# DB構築
root@581d9cc2d677:/var/ruby# bundle exec rake mysql:build_database
Using native MySQL
# テスト実行
root@581d9cc2d677:/var/ruby# bundle exec rake mysql:test
# 〜中略〜
176 runs, 437 assertions, 0 failures, 0 errors, 0 skips
すべてのテストが通りました。
同じ要領で、postgresql
とsqlite3
もapt
でインストールして確認しました。詳細は各dbms
依存になるので省略します。
プルリク
さて、ここまで来たら自分のプロジェクトだけに適用(Gemfile
で自分のリポジトリを指定する)してもいいですが、せっかくなのでプルリクして本家に取り込んでもらいましょう。
いざプルリクしようとすると、やっぱり生粋の日本人だと英語がネックですよね。私もかなりネックです。
まぁ、無視されて特に被害をうけるわけでもないので、中学生時代の記憶やらgoogle翻訳とかを駆使してカタコトの英語でpull request
やissue
を出してみましょう。
僕が出したissue
とpull request
はこちら。
https://github.com/composite-primary-keys/composite_primary_keys/issues/356
https://github.com/composite-primary-keys/composite_primary_keys/pull/357
まとめ
というわけで、なんとか今のプロジェクトで発生していたバグが直りました。「2016-05-13現在のrails rc1
でcomposit-primary-key
が動かない!」という方は、Gemfile
で
gem 'composite_primary_keys', github: 'composite-primary-keys/composite_primary_keys', branch: 'master'
にすると動くと思います。