安易に軽量DockerイメージにAlpineを採用するのをやめよう

ありのまま起こったことを話します。

**＿人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人人＿
＞　何もしてないのに急にdockerイメージのビルドに失敗するようになった　＜
￣Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^^Y^^Y^^Y^￣**

# 事件

先日あるプロジェクトでphp:7.4-fpm-alpineを使っていたらこんなエラーを吐いてdockerのイメージビルドがコケました。

```shell
make: *** [Makefile:195: gd.lo] Error 127
```

エラーを吐いたのはこのスクリプトだったのですが、こいつをこねくり回しても意味がなかったです。

```Dockerfile
RUN docker-php-ext-configure gd ~~~
```

以下で議論されていますがalpine3.14固有の現象のようです。

https://gitlab.alpinelinux.org/alpine/aports/-/issues/12396
https://github.com/docker-library/php/issues/1130

幸い3.13に固定したところビルドは通るようになりました。

# なんでこうなった？

musl-libcには一般的な互換性が不足しているらしいです。
Ruby, Python, Node.js, phpあたりなどはネイティブでモジュールをバンドルしてるアプリケーションの場合、パフォーマンス劣化や互換性の問題にぶち当たる可能性があるそうです。
[superuser.com](https://superuser.com/questions/1219609/why-is-the-alpine-docker-image-over-50-slower-than-the-ubuntu-image)

確認例

最新のphp:7.4-fpm-alpine

```shell
/var/www/html # ldd $(which php)
	/lib/ld-musl-x86_64.so.1 (0x7fe7cfb34000)
	libargon2.so.1 => /usr/lib/libargon2.so.1 (0x7fe7ce915000)
	libxml2.so.2 => /usr/lib/libxml2.so.2 (0x7fe7ce7eb000)
	libssl.so.1.1 => /lib/libssl.so.1.1 (0x7fe7ce76a000)
	libcrypto.so.1.1 => /lib/libcrypto.so.1.1 (0x7fe7ce4e9000)
	libsqlite3.so.0 => /usr/lib/libsqlite3.so.0 (0x7fe7ce3fb000)
	libz.so.1 => /lib/libz.so.1 (0x7fe7ce3e1000)
	libcurl.so.4 => /usr/lib/libcurl.so.4 (0x7fe7ce367000)
	libonig.so.5 => /usr/lib/libonig.so.5 (0x7fe7ce2dd000)
	libedit.so.0 => /usr/lib/libedit.so.0 (0x7fe7ce2ab000)
	libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7fe7cfb34000)
	liblzma.so.5 => /usr/lib/liblzma.so.5 (0x7fe7ce288000)
	libnghttp2.so.14 => /usr/lib/libnghttp2.so.14 (0x7fe7ce260000)
	libbrotlidec.so.1 => /usr/lib/libbrotlidec.so.1 (0x7fe7ce253000)
	libncursesw.so.6 => /usr/lib/libncursesw.so.6 (0x7fe7ce1f7000)
	libbrotlicommon.so.1 => /usr/lib/libbrotlicommon.so.1 (0x7fe7ce1d4000)
```

Debian10 

```shell
root@743553942da7:/# ldd $(which php)
	linux-vdso.so.1 (0x00007ffc13565000)
	libargon2.so.1 => /usr/lib/x86_64-linux-gnu/libargon2.so.1 (0x00007f5156c2f000)
	libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f5156c15000)
	libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f51569f7000)
	librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f51569ed000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f515686a000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5156865000)
	libxml2.so.2 => /usr/lib/x86_64-linux-gnu/libxml2.so.2 (0x00007f51566b8000)
	libssl.so.1.1 => /usr/lib/x86_64-linux-gnu/libssl.so.1.1 (0x00007f5156626000)
	libcrypto.so.1.1 => /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 (0x00007f515633d000)
	libpcre2-8.so.0 => /usr/lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007f51562b8000)
	libsodium.so.23 => /usr/lib/x86_64-linux-gnu/libsodium.so.23 (0x00007f5156261000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f51560a0000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f515607d000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f51570ea000)
	libicui18n.so.63 => /usr/lib/x86_64-linux-gnu/libicui18n.so.63 (0x00007f5155da2000)
	libicuuc.so.63 => /usr/lib/x86_64-linux-gnu/libicuuc.so.63 (0x00007f5155bd3000)
	libicudata.so.63 => /usr/lib/x86_64-linux-gnu/libicudata.so.63 (0x00007f51541e3000)
	liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007f51541bb000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f5154035000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f515401b000)
```


# まとめ

**何もしてないのに壊れたってあるんだなぁ**

他のベースイメージの軽量化も進んでおり、Alpineが軽量イメージの定番というのは違うのかなと言う気がしています。
安直にAlpineに走らず、最初は言語の標準イメージを使って見るなどしてみるといいと思います。
※Debian Slim等の軽量化されてイメージがそこそこあるので安易にApineを採用せず他のDockerイメージと比較検討したほうがいいかもしれません。

- Alpineで採用されているmuslにはglibcと比較した際に互換性上の問題があることがある
- muslを採用したイメージを使った際には思わぬパフォーマンス劣化に遭遇することがあるので、該当しないかどうかよく確認した方が良い
- glibcを後から入れる手もあるが、それなら言語の標準イメージなどDebian Slimをベースに作られてるイメージを使った方が合理的と思われる
- 開発前にデリメリをよく把握した上で選定しよう

# 参考文献

- [軽量Dockerイメージに安易にAlpineを使うのはやめたほうがいいという話](https://blog.inductor.me/entry/alpine-not-recommended)