Rubyと筋肉とギターとわたし

筋トレが仕事です

【docker】alpine ruby imageでgccが入っているのにstdio.h: No such file or directoryになる

f:id:rdwbocungelt5:20180816164743p:plain

どうもてぃ。お久しぶりです。

今日も解決記事です。

ゆっくりしていってね

環境

  • ruby 3.0.0 (alpine image)
  • PostgreSQL v12 (alpine image)
  • rails 6.1.4
  • Docker version 20.10.2, build 20.10.2-0ubuntu1~18.04.2
  • docker-compose version 1.27.4, build 40524192
% cat /ext/lsb-release

DISTRIB_ID=LinuxMint
DISTRIB_RELEASE=19.3
DISTRIB_CODENAME=tricia
DISTRIB_DESCRIPTION="Linux Mint 19.3 Tricia"

一応Dockerfile

FROM ruby:3.0.0-alpine

ENV RUNTIME_PACKAGES="linux-headers build-base libxml2-dev libxslt-dev make gcc libc-dev nodejs yarn tzdata g++ postgresql-dev postgresql git openssl less curl unzip" \
    CHROME_PACKAGES="chromium-chromedriver zlib-dev chromium xvfb wait4ports xorg-server dbus ttf-freefont mesa-dri-swrast udev" \
    DELETE_PACKAGES="build-packages libxml2-dev make gcc curl-dev libc-dev g++ curl unzip" \
    BUILD_PACKAGES="build-base curl-dev" \
    APP_ROOT="/myapp" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

RUN apk update && \
    apk upgrade && \
    apk add --no-cache ${RUNTIME_PACKAGES} && \
    apk add --no-cache ${CHROME_PACKAGES} && \
    apk add --virtual build-packages --no-cache ${BUILD_PACKAGES} && \
    gem install rails -v '6.1.4' && \
    gem install bundler

WORKDIR /tmp
COPY Gemfile* ./

RUN curl -O -L https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip && \
    unzip NotoSansCJKjp-hinted.zip -d . && \
    mkdir -p /usr/share/fonts/noto && \
    cp ./*.otf /usr/share/fonts/noto/ && \
    chmod 644 /usr/share/fonts/noto/*.otf && \
    fc-cache -fv

RUN bundle install -j4 && \
    bundle clean --force && \
    apk del ${DELETE_PACKAGES} ${BUILD_PACKAGES} && \
    cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    rm -rf /usr/local/share/.cache/* /var/cache/* /tmp/*

WORKDIR $APP_ROOT
COPY . ${APP_ROOT}/

CMD ["rails", "server", "-b", "0.0.0.0"]

fontを入れてるのはスクレイピング用です。

他は何の変哲もない(自分では)しっかりと作り込んだ(つもりでいた)愛を全力で注ぎ込んだDockerfileです。

やりたかったこと

  • rails apiモードで環境構築
  • どうせなら今まで使ってたDockerfileとdocker-compose.ymlを利用する(ruby alpineベース)

上記2点。

今まで別のプロジェクトでも何の問題もなく動いていたので、Dockerfiledocker-compose.ymlrails apiモード用にちょっといじってビルドしました。

事件はおこった

その1: gemのコンパイルgccとmakeが必要だった

まあ、よくあるやつ。

これはDockerfileのDELETE_PACKAGEから除外すれば直りました。

修正したDockerfileが以下。

FROM ruby:3.0.0-alpine

# don't delete make and gcc
ENV RUNTIME_PACKAGES="linux-headers build-base libxml2-dev libxslt-dev make gcc libc-dev nodejs yarn tzdata g++ postgresql-dev postgresql git openssl less curl unzip" \
    CHROME_PACKAGES="chromium-chromedriver zlib-dev chromium xvfb wait4ports xorg-server dbus ttf-freefont mesa-dri-swrast udev" \
    DELETE_PACKAGES="build-packages libxml2-dev curl-dev libc-dev g++ curl unzip" \
    BUILD_PACKAGES="build-base curl-dev" \
    APP_ROOT="/myapp" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

RUN apk update && \
    apk upgrade && \
    apk add --no-cache ${RUNTIME_PACKAGES} && \
    apk add --no-cache ${CHROME_PACKAGES} && \
    apk add --virtual build-packages --no-cache ${BUILD_PACKAGES} && \
    gem install rails -v '6.1.4' && \
    gem install bundler

WORKDIR /tmp
COPY Gemfile* ./

RUN curl -O -L https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip && \
    unzip NotoSansCJKjp-hinted.zip -d . && \
    mkdir -p /usr/share/fonts/noto && \
    cp ./*.otf /usr/share/fonts/noto/ && \
    chmod 644 /usr/share/fonts/noto/*.otf && \
    fc-cache -fv

RUN bundle install -j4 && \
    bundle clean --force && \
    apk del ${DELETE_PACKAGES} ${BUILD_PACKAGES} && \
    cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    rm -rf /usr/local/share/.cache/* /var/cache/* /tmp/*

WORKDIR $APP_ROOT
COPY . ${APP_ROOT}/

CMD ["rails", "server", "-b", "0.0.0.0"]

その2: msgpackのインストールでコケる

まずはエラーメッセージ。

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /usr/local/bundle/gems/msgpack-1.4.2/ext/msgpack
/usr/local/bin/ruby -I /usr/local/lib/ruby/3.0.0 -r ./siteconf20210630-1-7hbtci.rb extconf.rb
checking for ruby/st.h... *** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
    --with-opt-dir
    --without-opt-dir
    --with-opt-include
    --without-opt-include=${opt-dir}/include
    --with-opt-lib
    --without-opt-lib=${opt-dir}/lib
    --with-make-prog
    --without-make-prog
    --srcdir=.
    --curdir
    --ruby=/usr/local/bin/$(RUBY_BASE_NAME)
    --with-ruby-dir
    --without-ruby-dir
    --with-ruby-include
    --without-ruby-include=${ruby-dir}/include
    --with-ruby-lib
    --without-ruby-lib=${ruby-dir}/lib
/usr/local/lib/ruby/3.0.0/mkmf.rb:471:in `try_do': The compiler failed to generate an executable file. (RuntimeError)
You have to install development tools first.
    from /usr/local/lib/ruby/3.0.0/mkmf.rb:613:in `try_cpp'
    from /usr/local/lib/ruby/3.0.0/mkmf.rb:1124:in `block in have_header'
    from /usr/local/lib/ruby/3.0.0/mkmf.rb:971:in `block in checking_for'
    from /usr/local/lib/ruby/3.0.0/mkmf.rb:361:in `block (2 levels) in postpone'
    from /usr/local/lib/ruby/3.0.0/mkmf.rb:331:in `open'
    from /usr/local/lib/ruby/3.0.0/mkmf.rb:361:in `block in postpone'
    from /usr/local/lib/ruby/3.0.0/mkmf.rb:331:in `open'
    from /usr/local/lib/ruby/3.0.0/mkmf.rb:357:in `postpone'
    from /usr/local/lib/ruby/3.0.0/mkmf.rb:970:in `checking_for'
    from /usr/local/lib/ruby/3.0.0/mkmf.rb:1123:in `have_header'
    from extconf.rb:3:in `<main>'

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /usr/local/bundle/extensions/x86_64-linux-musl/3.0.0/msgpack-1.4.2/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /usr/local/bundle/gems/msgpack-1.4.2 for inspection.
Results logged to /usr/local/bundle/extensions/x86_64-linux-musl/3.0.0/msgpack-1.4.2/gem_make.out

An error occurred while installing msgpack (1.4.2), and Bundler cannot continue.
Make sure that `gem install msgpack -v '1.4.2' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  bootsnap was resolved to 1.7.5, which depends on
    msgpack

例のごとく最後に書いてる gem install msgpack -v '1.4.2' --source 'https://rubygems.org/' を実行してもダメ。

なのでmkmf.logを確認(docker containerに入ってから実行してます)。

/myapp # cat /usr/local/bundle/extensions/x86_64-linux-musl/3.0.0/msgpack-1.4.2/mkmf.log

"gcc -o conftest -I/usr/local/include/ruby-3.0.0/x86_64-linux-musl -I/usr/local/include/ruby-3.0.0/ruby/backward -I/usr/local/include/ruby-3.0.0 -I.    -O3 -ggdb3 -Wall -Wextra -Wdeprecated-declarations -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable  -fPIC conftest.c  -L. -L/usr/local/lib -Wl,-rpath,/usr/local/lib -L. -fstack-protector-strong -rdynamic -Wl,-export-dynamic     -Wl,-rpath,/usr/local/lib -L/usr/local/lib -lruby  -lm   -lc"
In file included from /usr/local/include/ruby-3.0.0/ruby/ruby.h:23,
                 from /usr/local/include/ruby-3.0.0/ruby.h:38,
                 from conftest.c:1:
/usr/local/include/ruby-3.0.0/ruby/defines.h:16:10: fatal error: stdio.h: No such file or directory
   16 | #include <stdio.h>
      |          ^~~~~~~~~
compilation terminated.
checked program was:
/* begin */
1: #include "ruby.h"
2: 
3: int main(int argc, char **argv)
4: {
5:   return !!argv[argc];
6: }
/* end */

あれー?gccを最後削除するパッケージ対象から外してるんすけど。意味わからん。

msgpack関連をめちゃくちゃ検索してましたが、もしかしたらOSに何かあったのかもと思い、「docker alpine gcc stdio.h~~~~」みたいな感じで検索したら原因発覚。

alpineのgccとlibc-devの依存関係が非推奨で無くなってしまったとのこと。

別の記事では(ちょっとリンク忘れちゃった)、代わりに musl-dev入れたら最強になれるみたいなこと書いてました。

gitlab.alpinelinux.org

なので更に修正したDockerfileが以下。

FROM ruby:3.0.0-alpine

# don't delete make and gcc
ENV RUNTIME_PACKAGES="linux-headers build-base libxml2-dev libxslt-dev make gcc musl-dev nodejs yarn tzdata g++ postgresql-dev postgresql git openssl less curl unzip" \
    CHROME_PACKAGES="chromium-chromedriver zlib-dev chromium xvfb wait4ports xorg-server dbus ttf-freefont mesa-dri-swrast udev" \
    DELETE_PACKAGES="build-packages libxml2-dev curl-dev libc-dev g++ curl unzip" \
    BUILD_PACKAGES="build-base curl-dev" \
    APP_ROOT="/myapp" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

RUN apk update && \
    apk upgrade && \
    apk add --no-cache ${RUNTIME_PACKAGES} && \
    apk add --no-cache ${CHROME_PACKAGES} && \
    apk add --virtual build-packages --no-cache ${BUILD_PACKAGES} && \
    gem install rails -v '6.1.4' && \
    gem install bundler

WORKDIR /tmp
COPY Gemfile* ./

RUN curl -O -L https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip && \
    unzip NotoSansCJKjp-hinted.zip -d . && \
    mkdir -p /usr/share/fonts/noto && \
    cp ./*.otf /usr/share/fonts/noto/ && \
    chmod 644 /usr/share/fonts/noto/*.otf && \
    fc-cache -fv

RUN bundle install -j4 && \
    bundle clean --force && \
    apk del ${DELETE_PACKAGES} ${BUILD_PACKAGES} && \
    cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    rm -rf /usr/local/share/.cache/* /var/cache/* /tmp/*

WORKDIR $APP_ROOT
COPY . ${APP_ROOT}/

CMD ["rails", "server", "-b", "0.0.0.0"]

libc-devを外してmusl-devを入れてます。

以上で無事ビルドとbundle installが通りましたとさ。

おわり

alpineイメージを使うメリットあまり感じてないので、slim-busterか普通のやつに変えようかなと模索中。

前見たときgithub actionで使うimageにalpineなかったからなー(もしかしたらもうあるかも)。

docker-compose v3.8のキャッチアップと一緒にプロジェクトのimage見直しやってみようと思います。

おつでした。