しふみんのブログ

しふみんのブログです。

Amazon Linuxでffi gemをnative buildするのに必要な依存パッケージ

AWSが提供しているlambda/rubyのbaseイメージでffi gemをインストールしようとしたら、native buildで失敗しました。

gallery.ecr.aws

再現

Gemfile

# frozen_string_literal: true

source 'https://rubygems.org'

gem 'ffi'

Dockerfile

FROM public.ecr.aws/lambda/ruby:3.2

# 通常はGemfile.lockもコピーするだろうけど再現には必要ないため省略
COPY Gemfile ${LAMBDA_TASK_ROOT}/

RUN gem install bundler && bundle install

こんな環境でdocker buildしてbundle installしようとすると、

$ docker build --platform linux/arm64 -t lambda-ruby-test:test .

[+] Building 2.5s (7/7) FINISHED                                                          
 => [internal] load build definition from Dockerfile                                 0.0s
 => => transferring dockerfile: 263B                                                 0.0s
 => [internal] load .dockerignore                                                    0.0s
 => => transferring context: 2B                                                      0.0s
 => [internal] load metadata for public.ecr.aws/lambda/ruby:3.2                      0.0s
 => CACHED [1/3] FROM public.ecr.aws/lambda/ruby:3.2                                 0.0s
 => [internal] load build context                                                    0.0s
 => => transferring context: 106B                                                    0.0s
 => [2/3] COPY Gemfile /var/task/                                                    0.0s
 => ERROR [3/3] RUN gem install bundler && bundle install                            2.4s                      2.4s
------                                                                                    
 > [3/3] RUN gem install bundler && bundle install:
(略)
#0 1.937 Fetching gem metadata from https://rubygems.org/..
#0 1.976 Resolving dependencies...
#0 1.979 Fetching ffi 1.16.3
#0 2.144 Installing ffi 1.16.3 with native extensions
#0 2.327 Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
#0 2.327 
#0 2.327     current directory: /var/lang/lib/ruby/gems/3.2.0/gems/ffi-1.16.3/ext/ffi_c
#0 2.327 /var/lang/bin/ruby extconf.rb
#0 2.327 checking for ffi.h... *** extconf.rb failed ***
#0 2.327 Could not create Makefile due to some reason, probably lack of necessary
#0 2.327 libraries and/or headers.  Check the mkmf.log file for more details.  You may
#0 2.327 need configuration options.
(略)
#0 2.327 /var/lang/lib/ruby/3.2.0/mkmf.rb:490:in `try_do': The compiler failed to
#0 2.327 generate an executable file. (RuntimeError)
#0 2.327 You have to install development tools first.
#0 2.327 
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:616:in `block in try_compile'
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:565:in `with_werror'
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:616:in `try_compile'
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:1157:in `block in have_header'
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:989:in `block in checking_for'
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:354:in `block (2 levels) in postpone'
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:324:in `open'
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:354:in `block in postpone'
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:324:in `open'
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:350:in `postpone'
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:988:in `checking_for'
#0 2.327        from /var/lang/lib/ruby/3.2.0/mkmf.rb:1156:in `have_header'
#0 2.327        from extconf.rb:10:in `system_libffi_usable?'
#0 2.327        from extconf.rb:46:in `<main>'
#0 2.327 
#0 2.327 To see why this extension failed to compile, please check the mkmf.log which can
#0 2.327 be found here:
#0 2.327 
#0 2.327 /var/lang/lib/ruby/gems/3.2.0/extensions/aarch64-linux/3.2.0/ffi-1.16.3/mkmf.log
#0 2.327 
#0 2.327 extconf failed, exit code 1
(略)
#0 2.327 An error occurred while installing ffi (1.16.3), and Bundler cannot continue.
#0 2.327 
#0 2.327 In Gemfile:
#0 2.327   ffi
------
Dockerfile:8
--------------------
   6 |     COPY Gemfile ${LAMBDA_TASK_ROOT}/
   7 |     
   8 | >>> RUN gem install bundler && bundle install
   9 |     
--------------------
ERROR: failed to solve: process "/bin/sh -c gem install bundler && bundle install" did not complete successfully: exit code: 5

native buildのコンパイルで失敗しておりgemをインストールできません。

必要な依存パッケージ

github.com

リポジトリのRequirementsを見るとCコンパイラlibffi ライブラリが必要だと書いています。
加えて、そもそもmakeができていなかったので make も必要そうでした。

lambda/rubyのbase OSはAmazon Linux 2 なのでパッケージ管理システムはyumです。 したがって、yumで下記のパッケージをインストールすればエラーを解消できそうです。

  • gcc
  • make
  • libffi-devel

Dockerfile(改修後)

FROM public.ecr.aws/lambda/ruby:3.2

# 依存パッケージを追加する
RUN yum update -y && yum install -y gcc make libffi-devel

COPY Gemfile ${LAMBDA_TASK_ROOT}/

RUN gem install bundler && bundle install

無事にbundle installが成功しました。

$ docker build --platform linux/arm64 -t lambda-ruby-test:test .
[+] Building 19.7s (9/9) FINISHED                                                         
 => [internal] load .dockerignore                                                    0.0s
 => => transferring context: 2B                                                      0.0s
 => [internal] load build definition from Dockerfile                                 0.0s
 => => transferring dockerfile: 261B                                                 0.0s
 => [internal] load metadata for public.ecr.aws/lambda/ruby:3.2                      0.0s
 => CACHED [1/4] FROM public.ecr.aws/lambda/ruby:3.2                                 0.0s
 => [internal] load build context                                                    0.0s
 => => transferring context: 28B                                                     0.0s
 => [2/4] RUN yum update -y && yum install -y gcc make libffi-devel                 12.3s
 => [3/4] COPY Gemfile /var/task/                                                    0.0s
 => [4/4] RUN gem install bundler && bundle install                                  6.7s
 => exporting to image                                                               0.7s 
 => => exporting layers                                                              0.6s 
 => => writing image sha256:1234567890                                               0.0s 
 => => naming to docker.io/library/lambda-ruby-test:test                             0.0s