无法在 M1 Mac 上的 docker 容器中加载 nokogiri

Unable to load nokogiri in docker container on M1 Mac

我正在 M1 mac 上构建 linux docker 图像(如果重要,来自 ruby:3.0.2-alpine3.12)。

当我尝试在我的容器中执行 bundle exec 时,ruby 抱怨它无法加载 nokogiri。如果我只是开始 ruby 并尝试要求 nokogiri,我会得到相同的结果:

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>'

安装了gem

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

一件有点奇怪的事情是

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

我不认为 musl 平台导致了不匹配。我们的生产 mac 内核是 amd64,那里有类似的 amd64/amd64-musl 不匹配,但它们 运行 容器是正确的。

有没有办法让它工作?

解决方法

我已经能够通过在捆绑时禁用预编译的 gems 来解决这个问题,但如果不必这样做就好了。 (我们有一个混合的M1/Intel开发组,外国架构的交叉编译似乎很长)。

我有一个 Rails 应用程序有类似的问题,它依赖于我的 Macbook M1 上基于 Alpine 的容器上的 Nokogiri 运行。这是我所做的:

  1. 看了Nokogiri documentation,发现其实支持aarch64-linux(Docker容器内部使用的架构),但是需要glibc >= 2.29.

  2. 我远不是专家,但据我所知,Alpine 发行版不包括 glibcmusl。还好有are ways to run programs that need glibc in Alpine.

  3. 我个人是按照第一种方式安装的gcompat。我只需要将 gcompat 添加到要在我的 Dockerfile.

    中安装的软件包列表中

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

  4. 更改之后,一切顺利,Rails 应用程序启动没有问题。

同样,我不是专家,以上内容可能不准确,但它对我来说很神奇。希望对你也有帮助。