Rails on Docker - Ignoring GEM because extensions are not built

Viewed 482

I've been going crazy with this error for the past two days. I am attempting to Dockerize a Rails 6 application

As per this I am doing my Dockerfile in two stages to minimize the size of the resulting image. Everything seems to work as expected: I bundle install and yarn install in the build stage and then copy it over to the final stage. However, when attempting to actually start the server (via bundle exec rails s) I get the following error:

Could not find nokogiri-1.10.9 in any of the sources

When running bash in the relevant container, we can inspect bundle for the gems that it knows about. However, bundle list fails with the above error. Just running bundle gives us a clue:

Ignoring bcrypt-3.1.13 because its extensions are not built. Try: gem pristine bcrypt --version 3.1.13
Ignoring bootsnap-1.4.6 because its extensions are not built. Try: gem pristine bootsnap --version 1.4.6
Ignoring ffi-1.12.2 because its extensions are not built. Try: gem pristine ffi --version 1.12.2
Ignoring msgpack-1.3.3 because its extensions are not built. Try: gem pristine msgpack --version 1.3.3
Ignoring nio4r-2.5.2 because its extensions are not built. Try: gem pristine nio4r --version 2.5.2
Ignoring nokogiri-1.10.9 because its extensions are not built. Try: gem pristine nokogiri --version 1.10.9
Ignoring pg-1.2.3 because its extensions are not built. Try: gem pristine pg --version 1.2.3
Ignoring puma-4.3.3 because its extensions are not built. Try: gem pristine puma --version 4.3.3
Ignoring sassc-2.2.1 because its extensions are not built. Try: gem pristine sassc --version 2.2.1
Ignoring websocket-driver-0.7.1 because its extensions are not built. Try: gem pristine websocket-driver --version 0.7.1

In the build stage, bundle install was run with the deployment option set to true, which means that all of the gems were installed in the local vendor/bundle. Indeed, we can see that nokogiri and the rest of the missing gems, along with their built extensions, are actually in that folder:

/usr/src/app> ls -R vendor/bundle/ruby/2.6.0/extensions/x86_64-linux-musl/2.6.0/
# ...
vendor/bundle/ruby/2.6.0/extensions/x86_64-linux-musl/2.6.0/nokogiri-1.10.9:
gem.build_complete  gem_make.out        mkmf.log            nokogiri

vendor/bundle/ruby/2.6.0/extensions/x86_64-linux-musl/2.6.0/nokogiri-1.10.9/nokogiri:
nokogiri.so
# ...

Of course, the problem can be fixed in the final image by installing the relevant build dependencies and then running bundle install. Before doing it we can see where nokogiri's compiled libraries are, which bundle can't find:

/usr/src/app > find / -name nokogiri.so
/usr/src/app/vendor/bundle/ruby/2.6.0/extensions/x86_64-linux-musl/2.6.0/nokogiri-1.10.9/nokogiri/nokogiri.so
/usr/src/app/vendor/bundle/ruby/2.6.0/gems/nokogiri-1.10.9/ext/nokogiri/nokogiri.so
/usr/src/app/vendor/bundle/ruby/2.6.0/gems/nokogiri-1.10.9/lib/nokogiri/nokogiri.so

After running bundle install, bundle is able to find nokogiri just fine. But where is it?

/usr/src/app > find / -name nokogiri.so
/usr/src/app/vendor/bundle/ruby/2.6.0/extensions/x86_64-linux-musl/2.6.0/nokogiri-1.10.9/nokogiri/nokogiri.so
/usr/src/app/vendor/bundle/ruby/2.6.0/extensions/x86_64-linux/2.6.0/nokogiri-1.10.9/nokogiri/nokogiri.so
/usr/src/app/vendor/bundle/ruby/2.6.0/gems/nokogiri-1.10.9/ext/nokogiri/nokogiri.so
/usr/src/app/vendor/bundle/ruby/2.6.0/gems/nokogiri-1.10.9/lib/nokogiri/nokogiri.so

Aha! So, in the build stage, we need to build for the x86_64-linux platform instead of the x86_64-linux-musl platform, whatever that is. The question: how do we accomplish this?

bundle config set specific_platform x86_64-linux

I've already tried setting the above during the build, and it does not work. Any ideas?

This post is lengthy enough: so here is a link to my Dockerfile. If you'd like to try it yourself, make sure to use docker-compose up in order to launch the necessary psql server.

0 Answers
Related