どうも、ウェブ系ウシジマくんです。
既存のRailsプロジェクトにおいて、開発環境をDocker化してしたのですが、rake db:migrate
実行時に
LoadError: libruby.so.2.3: cannot open shared object file: No such file or directory
というようなエラーが発生してしまいました。
小一時間くらいハマったので、その解消法を今回のエントリーとしたいと思います。
開発環境
- ruby 2.3.0
- rails 4.2.6
解決法
解決の結論としては、docker-compose run --rm <コンテナ名> /bin/bash
としてコンテナ内に侵入して、
gem pristine --all
上記コマンドを実行するだけです。
gem pristine --allの挙動
Bundlerの公式ドキュメントによると、次のように書かれています。
原文
pristine restores the installed gems in the bundle to their pristine condition using the local gem cache from RubyGems. For git gems, a forced checkout will be performed.
google翻訳
pristineはRubyGemsのローカルgemキャッシュを使ってバンドルにインストールされているgemを元の状態に復元します。 Git Gemでは、強制チェックアウトが実行されます。
要するに実行することでgemを初期化するということですね。
似たようなコマンドに、bundle pristine
というものがあります。
こっちは、Gemfile.lockにかかれているキャッシュを元に、gem同士の依存関係をすべて初期化するコマンド。
Bundler公式ではこちらを推奨しているようですが、DockerのrunコマンドではCould not find command "pristine".
となってしまい実行できませんでした。。
このあたりはもしかすると設定不足かもしれないので、知見が溜まり次第追記しますね。
原因
cannot open shared object
が発生した背景として、DockerfileとGemfileで指定しているRubyのバージョンを変更したのがありました。
docker build
を実行後にdocker-compose run
を実行したところ、
Ignoring bcrypt-3.1.12 because its extensions are not built. Try: gem pristine bcrypt --version 3.1.12
こんな感じのログが吐き出されたので、Ignoring because its extensions are not built
でググった結果、今回記事化した方法で解決できました。
なお、RubyGemsにおけるnative extentionsとは、次のようなものを指すようです。
gemのnative extenstionは、主にCやC++などで書かれるライブラリを必要とするRubyのコードあたりを指す。
参考
Rubyのgemをインストールしている際に他のライブラリのインストールを要求してくるnative extensionとは何者か
ここからは推測ですが、buildした際に以前のバージョンのgem同士の依存関係がうまく変更後のバージョンに適用されていなかったのかもしれません。
まとめ
Gemの依存関係は、結構Rubyのバージョンを変えたときにハマりやすいので、信頼できる公式ドキュメントを参考にしつつ、対応していきたいですね。