alpine+Railsでの ld-linux-x86-64.so.2: No such file or directory 問題について
使っているイメージ: ruby:2.6.5-alpine
この症状と全く同じ。ld-linux-x86-64.soが不足していると言われる。
LoadError: Error loading shared library ld-linux-x86-64.so.2: No such file or directory (needed by /usr/local/bundle/gems/grpc-1.23.0-x86_64-linux/src/ruby/lib/grpc/2.6/grpc_c.so) - /usr/local/bundle/gems/grpc-1.23.0-x86_64-linux/src/ruby/lib/grpc/2.6/grpc_c.so
このときのDockerfileは以下の通り
FROM ruby:2.6.5-alpine ENV LANG C.UTF-8 ENV BUNDLE_JOBS 4 WORKDIR /usr/local/src ... いろいろディレクトリのADDとかやっているところ RUN apk update \ && apk add --update --no-cache \ git \ build-base \ curl \ tzdata \ xz-dev \ mariadb-client \ mariadb-dev \ mariadb-connector-c \ libc6-compat \ libssl1.1 \ && rm -rf /var/lib/apt/lists/* \ && gem update --system \ && gem install bundler \ && RAILS_ENV=$RAILS_ENV CFLAGS="-Wno-cast-function-type" BUNDLE_FORCE_RUBY_PLATFORM=1 bundle install --deployment EXPOSE 3000
ld-linux-x86-64.so.2はlibc6-compatに入っているもので、apk addしているやつに含めている。
配置場所こそlibではなくlib64だが、64bit向けビルドするとシステム的に自動判定されるはず(´・ω・`)
考えても何もわからなかったので、冒頭のリンクで紹介されていた https://hub.docker.com/r/frolvlad/alpine-glibc/dockerfile を試すことに。
ただ、これをDockerfireに適用するのかなり大掛かりな気がして、このdockerfileの中で使われている以下の導入をそのまま実行。
検証なのでなるべくミニマムでな。これ通りやればすんなりdocker-compose build --no-cache name
で、イメージビルド自体は通った。
docker-compose run
でコンテナの中に入り、まずは手動で実行してbundle install。
特に問題なくGemは入る。その後、consoleなりmigrationを実行すると以下のようなエラーが発生してしまう。
/usr/local/src # RAILS_ENV=development bundle exec rails db:migrate /usr/local/bundle/gems/google-protobuf-3.9.2-x86_64-linux/lib/google/protobuf/any_pb.rb:17: [BUG] Segmentation fault at 0x0000000000019266 ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux-musl]
セグフォをくらう(´・ω・`)うーん....
セグフォの情報を元に調査すると、似たような症状を食らっている人が報告しているIssueを見つけた。
これを一通り読んでいった結果、結論、これで問題が解消した。
Segmentation Fault (Segfault) on the ruby gem · Issue #4460 · protocolbuffers/protobuf · GitHub
gem "grpc", "1.21.0", platforms: ["ruby"] gem "google-protobuf", "3.8.0", platforms: ["ruby"]
ただ、確かに問題は解決するんだが、原因が全然わからず気持ち悪い(´・ω・`)で、いろいろ探した結果、以下に行き着いた。
I did a bit of digging and found that it was due to alpine gcc not being able to compile boringssl library due to function type cast error.
alpineのgccだと、boringsslのビルド時にキャストエラーで落ちてしまうらしい。なるほど。
ここで重要なのはおそらくplatforms: ["ruby"]
このオプションを指定することで、強制的にCRuby (MRI)としてビルドするように指定している。そうするとalpine向けでないビルドになるので、Alpineのgcc起因の問題は回避できるのだろうと理解しました。