docker-composeでrakeタスクを実行した際にcannot open shared object fileと言われたときの対処法
スポンサーリンク

どうも、ウェブ系ウシジマくんです。

既存の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のバージョンを変えたときにハマりやすいので、信頼できる公式ドキュメントを参考にしつつ、対応していきたいですね。

スポンサーリンク
おすすめの記事