メリークリスマス! yucao24hours です。
こちらがおそらく 2021 年最後のアジャイル開発ブログとなります(予定)。今年も一年、私たちのブログに目を通していただきありがとうございました。
さて、今回は自分が関わっている数プロジェクトで発生した、突然の CI のふるまいの変化とその原因について調べた結果を書いてみます。
ことの発端
去る 12 月 8 日の夕方のことです。 GitHub にてとある Pull Request をマージしたところ、main ブランチにて CI が fail したことに気づきました。 CircleCI を使っているプロジェクトでしたので CircleCI の実行画面を見に行ったところ、以下のようなエラーが出ていました。
/bin/bash: line 5: docker-compose: command not found Exited with code exit status 127 CircleCI received exit code 127
ちなみに、対応する .circleci/config.yml の記述は以下のとおりです。
- run: name: Create services command: | if [ -f /tmp/cache/images.tar ]; then docker load -i /tmp/cache/images.tar fi docker images docker-compose up --build --no-start --quiet-pull rails
つまり、最後の行の docker-compose
コマンドが見つからないと言われているのです。
つい昨日まではなにも異常なく実行できていたし、CircleCI の設定も変更していないのに... こんなことってある!?
何が起きたか
状況から察するに、私たちの repository とは直接関係ないどこかでなにかの変更が入ったとみるのが妥当でしょう。
cimg のベースイメージの repository に、まさに今起きていることに関係していそうな issue が。
https://github.com/CircleCI-Public/cimg-base/issues/133
Starting with this month's base image release, Docker Compose is on v2 instead of v1. So instead of running docker-compose you'd run docker compose.
なるほど。今回起きたことに対する答えが、ほぼそのまま書いてありました。
が、せっかくなのでここで一旦立ち止まって、もう少し詳しく各要素のことを調べてみましょう。
cimg とは
まず、今見てきた cimg とはなんなのでしょうか。
cimg は、CircleCI があらかじめ用意している CI/CD 向けの Docker image です。
もともと CircleCI が開発・管理していた、 circleci/
というプレフィックスのついた公式 image を置き換えるものとしてリリースされています。
※ circleci/
からはじまるこのレガシーな CircleCI image は、2021 年 12 月 31 日で廃止となります。もうすぐですね。もしご自分の .circleci/config.yml に circleci/ruby
などと書かれている場合は、移行が必要ですのでお忘れなく!
Git やその他ライブラリのインストールに加え、アプリケーションを動かすのに必要な動作環境をセットアップした状態の image がさまざまな言語向けに用意してあります。
そのため利用者は各 image を .circleci/config.yml に記載するだけで、すぐに CI/CD ワークフローを構築することができるというわけです。
私たちのプロジェクトでは cimg/base
を使い、その Docker コンテナ上で Rails アプリケーション用の Docker コンテナを起動するようにしています。
実際に使いはじめてしばらく経ちますが、このおかげで config.yml の記述量が大幅に減りスッキリ見やすくなりましたし、CI に関するメンテナンス負荷がとても軽くなったと感じています。
なお、今回 issue を見に行った cimg/base
は、その名の通り各種言語向け image のベースとなる image です。
先ほど見た issue のコメントを再掲しますが、
Starting with this month's base image release, Docker Compose is on v2 instead of v1. So instead of running docker-compose you'd run docker compose.
とのことで、このベースイメージ(のうち当時の stable
タグがついたイメージ)で使われる Docker Compose のバージョンが v1 から v2 になったとあります。 1
では、Docker Compose v2 でどのような変更がなされてこのエラーが出たのでしょうか。
docker-compose が docker compose に
Docker Compose v2 についてのすべてを紹介するのは今回の記事の主目的ではないので割愛しますが、今回修正が必要な点は、以下の内容に関連していそうです。
You can test the Compose V2 by simply replacing the dash (-) with a space, and by running docker compose, instead of docker-compose.
即ち、 .circleci/config.yml に記載されている docker-compose
は、 docker compose
に変える必要があるということがわかりました。
コンテナ名の表記が変わった
さて、以上で対応完了!と思って再度 CI を run させたところ、今度は
docker: Error response from daemon: No such container: myapp_rails_1.
というエラーが出ました。
どうやらこれは、v2 で以下の変更が入ったことによるもののようです。
もともと docker-compose が自動生成していた project_service_number
といったコンテナ名は hostname の表記規則に違反しているものであったため、v2 に移行する機会にこの変更が追加されることになったようです。
よって、 .circleci/config.yml に
- run: name: Copy rails dependencies command: | mkdir -p /tmp/cache docker cp myapp_rails_1:/usr/local/bundle/. /tmp/cache/bundle
のようにアンダースコア区切り(旧表記)のコンテナ名を記載している場合、 myapp-rails-1
のようにハイフン区切りに修正する必要があったのでした。
まとめ
今回は CircleCI の cimg がきっかけとなって、Docker Compose v2 の変更について少し触れることができました。
どうしてこういう事が起きるようになったのか?を確認するために、issue や Pull Request 、コード等を探索して影響箇所を突き詰めるのはとても楽しいですね!
この調子で来年も、楽しいエンジニアライフを過ごせたらいいな~と思います。
それではみなさまも、よいお年をお迎えください :D
-
本当は https://circleci.com/developer/images/image/cimg/base#image-tags を見れば、どのタグのイメージにバージョンいくつの Docker Compose が入っているかを調べられるはずなのですが、今見るとちょっとおかしな文字列が入っているようにみえて、ドキュメントの自動更新がうまくいっていないのかな… という状態です。↩