rubygemsnokogiriapple-m1

Unable to load nokogiri in docker container on M1 Mac


I am building a linux docker image on an M1 mac (FROM ruby:3.0.2-alpine3.12 if it matters).

When I attempt to perform a bundle exec in my container, ruby complains that it is unable to load nokogiri. If I simply start ruby and try to require nokogiri I get the same result:

bash-5.0# irb
irb(main):001:0> require 'nokogiri'
<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>'

The gem is installed

ls -la /app/vendor/bundle/ruby/3.0.0/gems/

<snip>
drwxr-xr-x    6 root     root          4096 Feb  2 22:43 nokogiri-1.13.1-aarch64-linux
<snip

One somewhat curious thing is

bash-5.0# ruby --version
ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [aarch64-linux-musl]

I don't think the musl platform is causing the mismatch. Our production machines are amd64 and there's a similar amd64/amd64-musl mismatch there, but they run the containers correctly.

Is there a way to get this working?

Workaround

I have been able to work around this by disabling the use of precompiled gems when bundling, but it would be nice to not have to do so. (We have a mixed M1/Intel dev group and the cross compile for the foreign architecture seems to be pretty lengthy).


Solution

  • I had a similar problem with a Rails app that has dependency on Nokogiri running on an Alpine based container on my Macbook M1. Here is what I did:

    1. Reading the Nokogiri documentation, I found out that aarch64-linux (the architecture used inside the Docker container) is actually supported, but it requires glibc >= 2.29.

    2. I am far from being an expert but, as far as I know, Alpine distributions don't include glibc but musl. Fortunately, there are ways to run programs that need glibc in Alpine.

    3. I personally followed the first option, that is, I installed gcompat. I just needed to add gcompat to the list of packages to install in my Dockerfile.

      RUN apk add --no-cache ... gcompat

    4. After that change, things went smoothly and the Rails app started up with no issues.

    Again, I am not an expert and the above might be inaccurate, but it did the magic for me. I hope it can help you too.