armとintelのdocker-compose共通化へ向けて(Ruby on Rails編)
問題
M1macでDockerのrubyイメージを使おうとすると、nokogiriの部分でエラーが出ます。
% docker run --rm -it ruby:3.0.3-buster bashroot@489921d6a766:/# gem i nokogiriFetching nokogiri-1.13.4-aarch64-linux.gemSuccessfully installed nokogiri-1.13.4-aarch64-linux1 gem installedroot@489921d6a766:/# irbirb(main):001:0> require 'nokogiri'ERROR: It looks like you're trying to use Nokogiri as a precompiled native gem on a system with glibc < 2.17:
/lib/aarch64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by /usr/local/bundle/gems/nokogiri-1.13.4-aarch64-linux/lib/nokogiri/3.0/nokogiri.so) - /usr/local/bundle/gems/nokogiri-1.13.4-aarch64-linux/lib/nokogiri/3.0/nokogiri.so
If that's the case, then please install Nokogiri via the `ruby` platform gem: gem install nokogiri --platform=ruby or: bundle config set force_ruby_platform true
Please visit https://nokogiri.org/tutorials/installing_nokogiri.html for more help.
/usr/local/bundle/gems/nokogiri-1.13.4-aarch64-linux/lib/nokogiri/extension.rb:7:in `require_relative': /lib/aarch64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by /usr/local/bundle/gems/nokogiri-1.13.4-aarch64-linux/lib/nokogiri/3.0/nokogiri.so) - /usr/local/bundle/gems/nokogiri-1.13.4-aarch64-linux/lib/nokogiri/3.0/nokogiri.so (LoadError) from /usr/local/bundle/gems/nokogiri-1.13.4-aarch64-linux/lib/nokogiri/extension.rb:7:in `<top (required)>' from /usr/local/bundle/gems/nokogiri-1.13.4-aarch64-linux/lib/nokogiri.rb:10:in `require_relative' from /usr/local/bundle/gems/nokogiri-1.13.4-aarch64-linux/lib/nokogiri.rb:10:in `<top (required)>' from <internal:/usr/local/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:160:in `require' from <internal:/usr/local/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:160:in `rescue in require' from <internal:/usr/local/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:149:in `require' from (irb):1:in `<main>' from /usr/local/lib/ruby/gems/3.0.0/gems/irb-1.3.5/exe/irb:11:in `<top (required)>' from /usr/local/bin/irb:23:in `load' from /usr/local/bin/irb:23:in `<main>'<internal:/usr/local/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require': cannot load such file -- nokogiri (LoadError) from <internal:/usr/local/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require' from (irb):1:in `<main>' from /usr/local/lib/ruby/gems/3.0.0/gems/irb-1.3.5/exe/irb:11:in `<top (required)>' from /usr/local/bin/irb:23:in `load' from /usr/local/bin/irb:23:in `<main>'irb(main):002:0>原因は、Nokogiriが1.11あたりからプリコンパイルされて配布されるようになりました。そのバイナリは、glibc 2.17でコンパイルされています。
しかしながら、arm用にコンパイルされたnokogiriが参照している /lib/aarch64-linux-gnu/libm.so.6が2.29を必要としているっぽくてエラーになります。
解決方法
静的リンクするか、独自でコンパイルするのが良さそうです。静的リンクはバイナリサイズがでかくなりそうなので独自でコンパイルします。
Bundlerを使っている場合
Bundler使っている場合は以下を打って自分でコンパイルするように設定します。
# bundler 2.1以降% bundle config set force_ruby_platform true# bundler 2.0以前% bundle config force_ruby_platform trueそうすると、.bundle/configに以下が入ります。
---BUNDLE_FORCE_RUBY_PLATFORM: "true"もし、.bundleディレクトリを.gitignoreで無視するような設定を書いていたり、ユーザ側で設定した.bundleディレクトリを使うようにしている場合はホームディレクトリの設定ファイルに書き込んであげるのがよいです。
bundle config set --global force_ruby_platform true実行例
% docker run --rm -it ruby:3.0.3-buster bashroot@11a428c7e8da:/# bundle config set force_ruby_platform trueroot@11a428c7e8da:/# bundle initWriting new Gemfile to //Gemfileroot@11a428c7e8da:/# bundle add nokogiriFetching gem metadata from https://rubygems.org/.......Resolving dependencies...Fetching gem metadata from https://rubygems.org/.......Resolving dependencies...Using bundler 2.2.32Fetching racc 1.6.0Fetching mini_portile2 2.8.0Installing racc 1.6.0 with native extensionsInstalling mini_portile2 2.8.0Fetching nokogiri 1.13.4Installing nokogiri 1.13.4 with native extensionsroot@11a428c7e8da:/# bundle exec irbirb(main):002:0> require 'nokogiri'=> trueBundlerを使っていない場合
--platform=ruby オプションをつけてインストールします。
root@b4ca7905b3a5:~# gem install nokogiri --platform=rubyFetching nokogiri-1.13.4.gemBuilding native extensions. This could take a while...Successfully installed nokogiri-1.13.41 gem installedroot@b4ca7905b3a5:~# irbirb(main):001:0> require 'nokogiri'=> trueroot@b4ca7905b3a5:/# gem list|grep nokogirinokogiri (1.13.4)手元での変更
結果的に手元のプロジェクトでは以下のような変更をDockerfileに行いました。
RUN bundle config set --global force_ruby_platform true参考資料
詳細はこちらのissueにかかれています。
Feedback and final to-do items for precompiled native gems on Linux and OSX · Issue #2075 · sparklemotion/nokogiri
This issue exists to capture feedback and action items about the precompiled native gems for Linux and OSX that we're shipping in the Nokogiri v1.11 release candidates (prereleases). (RC4 is out! h...
不確実情報
環境によっては、arm用のbinaryがインストールされたりもするので、これが実現すればコンパイルの時間が取られなくて良いのでどういったときにこのような設定ができるのかを検証中です。