720 文字
4 分
armとintelのdocker-compose共通化へ向けて(Ruby on Rails編)

問題#

M1macでDockerのrubyイメージを使おうとすると、nokogiriの部分でエラーが出ます。

Terminal window
% docker run --rm -it ruby:3.0.3-buster bash
root@489921d6a766:/# gem i nokogiri
Fetching nokogiri-1.13.4-aarch64-linux.gem
Successfully installed nokogiri-1.13.4-aarch64-linux
1 gem installed
root@489921d6a766:/# irb
irb(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使っている場合は以下を打って自分でコンパイルするように設定します。

Terminal window
# bundler 2.1以降
% bundle config set force_ruby_platform true
Terminal window
# bundler 2.0以前
% bundle config force_ruby_platform true

そうすると、.bundle/configに以下が入ります。

---
BUNDLE_FORCE_RUBY_PLATFORM: "true"

もし、.bundleディレクトリを.gitignoreで無視するような設定を書いていたり、ユーザ側で設定した.bundleディレクトリを使うようにしている場合はホームディレクトリの設定ファイルに書き込んであげるのがよいです。

Terminal window
bundle config set --global force_ruby_platform true

実行例

Terminal window
% docker run --rm -it ruby:3.0.3-buster bash
root@11a428c7e8da:/# bundle config set force_ruby_platform true
root@11a428c7e8da:/# bundle init
Writing new Gemfile to //Gemfile
root@11a428c7e8da:/# bundle add nokogiri
Fetching gem metadata from https://rubygems.org/.......
Resolving dependencies...
Fetching gem metadata from https://rubygems.org/.......
Resolving dependencies...
Using bundler 2.2.32
Fetching racc 1.6.0
Fetching mini_portile2 2.8.0
Installing racc 1.6.0 with native extensions
Installing mini_portile2 2.8.0
Fetching nokogiri 1.13.4
Installing nokogiri 1.13.4 with native extensions
root@11a428c7e8da:/# bundle exec irb
irb(main):002:0> require 'nokogiri'
=> true

Bundlerを使っていない場合#

--platform=ruby オプションをつけてインストールします。

Terminal window
root@b4ca7905b3a5:~# gem install nokogiri --platform=ruby
Fetching nokogiri-1.13.4.gem
Building native extensions. This could take a while...
Successfully installed nokogiri-1.13.4
1 gem installed
root@b4ca7905b3a5:~# irb
irb(main):001:0> require 'nokogiri'
=> true
root@b4ca7905b3a5:/# gem list|grep nokogiri
nokogiri (1.13.4)

手元での変更#

結果的に手元のプロジェクトでは以下のような変更をDockerfileに行いました。

RUN bundle config set --global force_ruby_platform true

参考資料#

詳細はこちらのissueにかかれています。

https://github.com/sparklemotion/nokogiri/issues/2075

不確実情報#

環境によっては、arm用のbinaryがインストールされたりもするので、これが実現すればコンパイルの時間が取られなくて良いのでどういったときにこのような設定ができるのかを検証中です。

https://gist.github.com/matsubo/94666cf045af3ad8f91fada59116a1dd/b45e953d224220676898b1b84e7622edde3c1efe

armとintelのdocker-compose共通化へ向けて(Ruby on Rails編)
https://blog.teraren.com/posts/docker-m1-arm-glibc-error-on-nokogiri/
作者
Yuki Matsukura
公開日
2022-04-26
ライセンス
CC BY-NC-SA 4.0

コメント