CircleCIで実行バイナリをDLしてCI内でキャッシュしながら使う

CI内でどこかしらから実行バイナリをダウンロードして、それを使うことがあると思います。 最近では僕はOPAのテストをCircleCIで実行したかったので、OPAのバイナリをダウンロードしてテストを実行しました。

kenfdev.hateblo.jp

毎回バイナリをダウンロードしてCircleCIを回すのもコストが高いので、CircleCIのキャッシュを使う方法について共有します!

実行バイナリをDockerイメージに入れてそれをCIで使う方法もありますが、今回は実行バイナリをダウンロードして使う方法でやります!

キャッシュせずにやった場合

まずはキャッシュのことを考えずにCIしてみると、以下のような流れになります。(OPAの例です)

version: 2
jobs:
  build:
    docker:
      - image: circleci/buildpack-deps:jessie

    steps:
      - checkout
      - run:
          name: Download OPA
          command: |
            mkdir .bin
            wget -O .bin/opa https://github.com/open-policy-agent/opa/releases/download/v0.10.6/opa_linux_amd64
            sudo chmod +x .bin/opa
      - run:
          name: Test Policies
          command: .bin/opa test .
  • チェックアウト
  • OPAのバイナリをGitHubからダウンロードして実行権限付与
  • OPAのテスト実行

という感じです。特につまるところは無いと思います。

ただしこれにはパフォーマンスの問題があって、CIの度にOPAのバイナリをGitHubからダウンロードしてくるのが無駄です。 このバイナリもそんなにしょっちゅう変わるものでも無いので、ダウンロードが一度で済ませられたら良いですよね。

そこで使えるのがCircleCIのキャッシュです!

キャッシュして効率化

CircleCIには save_cacherestore_cache という便利な機能があります。

circleci.com

キーを基にCircleCI側にファイルやディレクトリなどをキャッシュしておくことができます。 よく見る場面としては、依存パッケージなどをキャッシュしておくときです。( node_modulesvendors ディレクトリなど)

ポイントとなるのがキャッシュの「キーの決め方」です。

まずはあまり工夫をせずにキャッシュの手順を加えて見ます。

version: 2
jobs:
  build:
    docker:
      - image: circleci/buildpack-deps:jessie

    steps:
      - checkout
      - restore_cache:
          key: opa-cache-0.10.6
      - run:
          name: Download OPA
          command: |
            if [ ! -f .bin/opa ]; then
              mkdir .bin
              wget -O .bin/opa https://github.com/open-policy-agent/opa/releases/download/v0.10.6/opa_linux_amd64
              sudo chmod +x .bin/opa
            fi
      - run:
          name: Test Policies
          command: .bin/opa test .
      - save_cache:
          key: opa-cache-0.10.6
          paths:
            - .bin
  • チェックアウト
  • キャッシュがあれば復元
  • OPAのバイナリが 無ければ GitHubからダウンロードして実行権限付与
  • OPAのテスト実行
  • OPAのバイナリをキャッシュしておく

restore_cachesave_cache のキーには opa-cache-0.10.6 を使っています。

これは、OPAのバイナリのバージョンが変わったらキャッシュもちゃんと変わるようにするためです。 ただし、これってバージョンが変わるたびに少なくとも3箇所( 0.10.6 となってる部分)は変えないといけないので微妙ですよね。

ということでどうにか1箇所に集約できないかと考えてしまいます。

ちょっとトリッキーなのが、環境変数restore_cachesave_cachekey に使えない点です(少なくとも僕の2019/04/19時点での認識では)。

      - restore_cache:
          key: opa-cache-${OPA_VERSION}

上記のように書けるとすっきりしそうなんですけど、これができません。ではどうするかというと、以下のフォーラムでやり方を見つけることができました。

discuss.circleci.com

次のように書き換えることができます。

      - run:
          name: Setup Environment Variables and Version file
          command: |
            echo 'export OPA_VERSION="0.10.6"' >> $BASH_ENV
            echo "${OPA_VERSION}" > _opa_version_
      - restore_cache:
          key: opa-cache-{{ checksum "_opa_version_" }}
  • 環境変数OPA_VERSIONにバージョン番号を入れて
  • バージョン番号を _opa_version_ というファイルにリダイレクト
  • _opa_version_checksum をキャッシュのキーとして使う

言われてみれば「あ、その手があったか!」ってなります。

ということでこの方法で config.yml を書き換えると下のようになります。

version: 2
jobs:
  build:
    docker:
      - image: circleci/buildpack-deps:jessie

    steps:
      - checkout
      - run:
          name: Setup Environment Variables and Version file
          command: |
            echo 'export OPA_VERSION="0.10.6"' >> $BASH_ENV
            echo "${OPA_VERSION}" > _opa_version_
      - restore_cache:
          keys:
            - opa-cache-{{ checksum "_opa_version_" }}
      - run:
          name: Download OPA
          command: |
            if [ ! -f .bin/opa ]; then
              mkdir .bin
              wget -O .bin/opa https://github.com/open-policy-agent/opa/releases/download/v${OPA_VERSION}/opa_linux_amd64
              sudo chmod +x .bin/opa
            fi
      - run:
          name: Test Policies
          command: .bin/opa test .
      - save_cache:
          key: opa-cache-{{ checksum "_opa_version_" }}
          paths:
            - .bin

こうすることで下の一行を変えるだけで、OPAの実行バイナリのバージョンを切り替えることができます!

echo 'export OPA_VERSION="0.10.6"' >> $BASH_ENV

今の所の僕の最適解はこのやり方になるのですが、他にも良い方法があればぜひとも知りたいところです!

おわりに

  • 依存ライブラリ以外にもCircleCIの save_cacheresotre_cache は使える
  • 一工夫すればキャッシュのキーに環境変数で設定したバージョン番号を指定できる

参考

ちょうど「CircleCI 福岡ミートアップ」が開催されて、その中でもキャッシュについて触れている発表があったようです!