CircleCI 2.0 で CIで使うイメージを変えたら ブランチ名がHEADになった話

2017.12.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。齋藤です。 今回は趣向を変え、社内への共有を含めて、ブログを書いています。

今回ブログに書く内容は実際に開発しているプロジェクトで起きました。 CircleCI 2.0 で使うDockerイメージを変えたところ、ブランチ名を取得すると なぜかHEADになってしまうという現象が起きたので、その調査の過程と解決方法をブログにします。

内容としては以下の内容について書いていきます。

  • はじめに
  • 何をやったか
  • 何が起きたか
  • もう少し調べてみる
  • まとめと解決方法

はじめに

現在、自分たちのチームでは ECSを使っており、各マイクロサービスのCIで アプリケーションのDockerイメージを作っています。 この際、ブランチ名をイメージのタグとして利用しています。 また、CIのサービスとして、CircleCI 2.0を使っており、Dockerイメージを利用してCIを行なっています。

今回の問題が起きた原因は、「アプリケーションのDockerイメージのアップデートとイメージを小さくしよう」 から始まりました。

なにをやったか

今回のアプリケーションはJavaだったので、アプリケーションのDockerイメージを小さくしようというと DockerHubのopenjdkリポジトリにある、debianベースの 8-jdk-slim か alpineベースの 8-jdk-alpine が 移行先に検討されました。

まぁ小さい方がいいだろう、ということで alpine を選択しました。 この alpineのイメージは最小構成と言う形になっており gitなどの ソースコード管理ツールが入っていないものになります。 debian ベースの 8-jdk というバージョンだと現状は gitなどが入っています。

で、この際に CIで動かす イメージも小さい方が CIの イメージの pullが早くなって良さそう、という気持ちになったので alpineにしました。

何が起きたか

冒頭にも書いた通り、CircleCI上に git のリポジトリから git のjavaライブラリを使って ブランチ名を取得すると HEAD になっているようです。 (ブランチ名が取れてない)

原因を調べたところ、次のようなメッセージが出ていることに気づきました。 「git がイメージにないから、CircleCI の gitのnative クライアントを使うよ」といったメッセージでした。

しかし、これだけでは何もわかりません。 また、次のように CIで、コードのcheckoutをする前に alpineに gitとssh を入れて見たらどうなるか というのを試してみたところ、ブランチ名の取得がうまくいっているようでした。 個人的には、git cloneしているバイナリが変わったところで、何も変わらないという思い込みがありました。

もう少し調べてみる

キャッシュを入れるにしても、CIの初めに gitとsshを インストールするのは避けたいところです。 また、キャッシュのステップを増やすのも避けたいところです。

そこで、 CircleCI では rebuild with SSH という機能があって 実際にCIが動いているコンテナにSSHして中に入ることができるので 実際に中に入って色々調べてみました。

実際に使っているコードでブランチ名を取得して確かめる

実際に使っているコードでは、grgitを使っているので、それに倣って、gradleのタスクに 次のようなコードを追加しました。(実際には少し違いますが)

task showBranch  {
  def git = org.ajoberstar.grgit.Grgit.open(file('.'))
  println git.branch.current.name
}

実行してみます。

$ ./gradle showBranch
HEAD

OMG。確かに HEADが帰ってきています。 うーん、でもこれだけではいまいち情報が足りないので git コマンドを入れて試してみます。

git をインストールして確かめる

gitを追加します。(一応sshも)

apk update && apk upgrade && apk add --no-cache git openssh

gitをインストールしたので、git branchしてみます。 次のような結果になりました。

なるほど、 (no branch) 。。。 ちなみに (no branch) ではありますが git logしたところ、pushしたコミットハッシュの位置の状態ではあるようです。

このような結果になった理由としては、推測で申し訳ないのですが、 先ほど冒頭の方であった、CircleCIの native の git クライアントを使った結果だと思われます。

つまり、 CircleCIのクライアントの場合は何らかの理由でブランチ名が取れない状態で cloneされる、という結果になりました。

まとめと解決方法

長々と書きましたが、今回は それは次の3つです。

  • CircleCI で git の入っているイメージを使う → CircleCIで使う Docker イメージはでかくなる
  • CircleCI で git の入っていないイメージを使うなら
    • 環境変数 CIRCLE_BRANCH を使う
    • code の checkout する前に、gitとsshを入れる → 毎回するのもキャッシュするのもあんまりしたくない

という訳で、 CIで使うDockerイメージのサイズも下げたい場合は CIRCLE_BRANCH を使いましょう。

また、今回は話しませんでしたが、CIのイメージとアプリケーションのベースイメージが別れてもいいなら CIは gitの入っているイメージ、アプリケーションのベースイメージは gitの入っていないイメージという形になるでしょう。

CIをもっとよくしていきたい。 それでは、次の記事を楽しみにしていただければ。