glibcを入れたDocker公式イメージ(Alpine)のコンテナによるCI/CDが通らなくなった

前提

  • GitLab-CIの実行コンテナに、公式dockerイメージ(=Alpine)を使っていた
  • AWS CLI v2 のインストールにはglibcが必要
  • Alpineイメージのコンテナにはglibcが入ってないので自前でインストールしていた


2021/8/5木昼 急にCI/CDが通らなくなった

ある日いつものようにコードの反映のためにCI/CDの実行結果を待っていたら、CICDジョブが失敗していました。

CI/CDジョブの実行結果にはこんなエラーが・・・

**ERROR: glibc-2.31-r0: trying to overwrite lib64/ld-linux-x86-64.so.2 owned by libc6-compat-1.2.2-r1.**


環境の説明

ここで環境、特にCI/CDまわりの説明をしておきます。

まず、CI/CDにはGitLab-CI(Shared Runner)を使用していて、その実行コンテナとして公式dockerイメージ(= Alpine)を使っていました。

image: docker:latest   #<- alpineで作られている
services:
  - docker:dind
variables:
  ...


CI/CDでは実行時の最初に環境構築用のシェルを走らせています。ざっと以下の様な感じです。

  • AWS CLI v2 を入れたい
  • AWS CLI v2 にはglibcが必要だが、Alpineにはglibcがないため自前でインストールしている
  • その後、AWS CLI v2をインストールしている
#!/bin/sh
set -eux

GLIBC_VER=2.31-r0

apk --no-cache add binutils curl

curl -sL https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-${GLIBC_VER}.apk
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk

apk add --no-cache glibc-${GLIBC_VER}.apk glibc-bin-${GLIBC_VER}.apk glibc-i18n-${GLIBC_VER}.apk

/usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 C.UTF-8 || true

curl -sL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip
unzip -q awscliv2.zip
aws/install


エラーの確認

最初に記載したエラーが、まずどの部分で起きているのかを確認してみました。

+ apk add --no-cache glibc-2.31-r0.apk glibc-bin-2.31-r0.apk glibc-i18n-2.31-r0.apk
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/community/x86_64/APKINDEX.tar.gz
(1/3) Installing glibc (2.31-r0)
**ERROR: glibc-2.31-r0: trying to overwrite lib64/ld-linux-x86-64.so.2 owned by libc6-compat-1.2.2-r1.**
(2/3) Installing glibc-bin (2.31-r0)
(3/3) Installing glibc-i18n (2.31-r0)
Executing glibc-bin-2.31-r0.trigger
/usr/glibc-compat/sbin/ldconfig: /usr/glibc-compat/lib/ld-linux-x86-64.so.2 is not a symbolic link
1 error; 60 MiB in 31 packages

glibcインストール部分で失敗している

**ERROR: glibc-2.31-r0: trying to overwrite lib64/ld-linux-x86-64.so.2 owned by libc6-compat-1.2.2-r1.**


この挙動の理由としては、libc6-compatというライブラリパッケージと衝突しているようです。 掘り下げると、glibc内の共有オブジェクトファイルをこちらのライブラリパッケージが入れちゃってるようですね。


急にエラーが起きるようになった原因

公式dockerイメージ:バージョン20.10.8で、dockerfileでlibc6-compatが追加されるようになっていた!!

このエラーが起きた半日前(エラー同日!)に新しいcommitがありそこで追加されていた・・・(Goのためのようです)


対処(+不採用候補)

採用案と不採用案を1つずつ載せておきます。

  • 採用案:libc6-compatが入っている場合はシェル内で消す
    • 採用理由
      • 単純に公式のバージョンアップに適応した
    • 採用はしたが理想ではない
      • 入っているものをわざわざ消すという、不格好な対応ではあるので・・・
      • そしたらそもそも使うOS変えるとか、違う入れ方するとかの方が綺麗
      • そんな時間はなかった(影響範囲も大きかった)
    • 対処内容詳細
      • 他のイメージだとlibc6-compatが入っていなかったりするので分岐処理を入れといた
libc6_compat_check=`apk info | grep libc6-compat || true`
if [ -n "${libc6_compat_check}" ]; then
    apk del libc6-compat
fi


  • 不採用案:コンテナイメージのバージョンにlatestを使用せず、今回の更新が入る前のものに固定
    • 不採用理由
      • 本来、長期運用を見越した場合にバージョンは指定するのがセオリーだが、まだインストールするモジュール要件が固まっていなかったのと、開発者側がどんどん新しいパッケージを入れたくなる際にその固定したバージョンのイメージだとインストールできなくなる、などのようなことが想定されたため
        • そのたびに変更していくのが理想だが中々そうもいかず・・・
        • どこかのタイミングで固定します・・・(まだ実はリリース前のプロダクトだったため)
      • また、これからどんどん公式でアップデートされていった際にずっと新しいバージョン使えないのは辛い
        • それならそのプラットフォームに合わせて構築した方がいい


最後に

とりあえず、これで何とか動くようになりました。

CI/CD内でdocker buildするためにdockerのイメージを使用して、かつ AWS CLIも一緒に入れることもあると思うので、このエラーにぶつかってる人も少なくないのではと思います・・・