CircleCIを使うときに気をつけていること

 ツイート 0  シェア 0  Hatena 1

CircleCI2.0 を使うようになって 1 年くらい経ちました。ノウハウがたまってきたのでまとめておきます。

目次

  1. Docker Executorを使う
  2. ダウンロードしたファイルをキャッシュする
  3. ビルドを並列化する
  4. Workflows はできるだけ使わない

Docker Executorを使う

CircleCI には実行環境として Docker ExecutorMachine Executor がありますが、可能な限り Docker Executor を利用するようにしています。

Docker Executor はローカル開発用の CLI ツールを利用できる

Docker Executor は ローカル開発用の CLI ツール を利用できます。ワークフローやキャッシュに対応していなかったりしますが、大抵のことをローカル環境で試すことができます。

.circleci/config.yml があるディレクトリで、こんな感じで使います。オプションでブランチや環境変数を指定できます。


$ circleci build \
  --branch develop \
  -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \
  -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \
  -e AWS_REGION=${AWS_DEFAULT_REGION}

構文エラーのチェックもできます。


$ circleci config validate

Docker Executor はビルドのリソースを変更できる

Machine Executor のリソースは固定ですが Docker Executor は resource_class を使用してビルドのリソースをある程度コントロールできます。

以下のように resource_class を指定します。


version: 2
jobs:
  build:
    docker:
     - image: circleci/ruby:2.5
    resource_class: medium+

Machine Executor はビルドの開始に時間がかかることがある

Docker Executor と Machine Executor の比較にも書かれていますが、Machine Executor はビルドの開始までに 1 分くらい待たされることがあります。多くの場合はすぐにビルドが開始されるので、CircleCI の混み具合によるようです。

Machine Executor を使うのは Docker イメージをビルドする時だけにする

Machine Executor はなるべく使わないようにしていますが、Docker イメージをビルドするときだけは Machine Executor を使うしかありません。Docker イメージのビルドは CircleCI でやらず、外部のサービスに任せられないかも検討します。たとえば AWS であれば Code Builde を使います。

docker-compose を CircleCI で使うのは諦める

docker-compose は Machine Executor でしか利用できません。docker-compose を CircleCI で使うのは諦め、docker-compose.yml の内容を .circleci/config.yml に移植するようにしています。

ダウンロードしたファイルをキャッシュする

ビルドに必要なファイルを毎回ダウンロードしているとビルドが遅くなるので、一度ダウンロードしたファイルはキャッシュして再利用するようにします。

パッケージマネージャー編

以下は Ruby の Gem パッケージをキャッシュする例です。


version: 2
jobs:
  build:
    steps:
      - checkout

      # Restore cache
      - restore_cache:
          key: bundle-{{ checksum "Gemfile.lock" }}

      # Install package
      - run: bundle install --path vendor/bundle

      # Save cache
      - save_cache:
          key: bundle-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle

checksum "Gemfile.lock" のようにしてキャッシュのキーを作成することで、Gemfile.lock ファイルに変更があった場合はキャッシュを利用せず、新しくファイルを取得するようになっているのがポイントです。checksum 以外にも利用できる変数は Using Keys and Templates から確認できます。言語ごとのサンプルは Caching Dependencies Bundler(Ruby) から確認できます。

wget curl 編

jq のようにパッケージマネージャーを使用せず wget で取得したファイルをキャッシュする例です。

まず、.jq-version ファイルにバージョン番号を書いて Git にコミットしておきます。


$ cat .jq-version

1.5

.jq-version ファイルの checksum をキーに、ダウンロードしたファイルをキャッシュします。


version: 2
jobs:
  build:
    steps:
      - checkout

      # Restore cache
      - restore_cache:
          name: Restore jq
          keys:
            - jq-{{ checksum ".jq-version" }}

      # Download package
      - run:
          name: Download jq
          command: |
            if [ ! -e /usr/local/bin/jq ]; then
              version=$(cat .jq-version)
              wget https://github.com/stedolan/jq/releases/download/jq-${version}/jq-linux64 -O /usr/local/bin/jq
              chmod +x /usr/local/bin/jq
            fi

      # Save cache
      - save_cache:
          name: Save jq
          key: jq-{{ checksum ".jq-version" }}
          paths:
            - "/usr/local/bin/jq"

ビルドを並列化する

Rails で RSpec のテストを 3 並列で実行する例です。詳しくは Running Tests in Parallel – CircleCI を参照。


version: 2
jobs:
  build:
    docker:
      - image: circleci/ruby:2.5
    parallelism: 3
    steps:
      - checkout
      - run: circleci tests glob "spec/**/*.rb" | circleci tests split | xargs bundle exec rspec

Workflows はできるだけ使わない

CircleCI2.0から使えるようになったWorkflowsですが、ビルドを並列させる時とcronを使う時以外は使わないようにしています。.circleci/config.ymlが長くなって保守性が落ちることが多いです。ローカルのCLIツールがWorkflowに対応していないのもデメリットです。条件分岐をしたくなったときは、Workflows で条件分岐 せず、まずは if 文でやりたいことが実現できないか考えるようにしています。

ブランチ名でデプロイ先を分岐させるケース。


version: 2
jobs:
  build:
    steps:
      - deploy:
        command: |
          if [ "${CIRCLE_BRANCH}" == "master" ]; then
            # deploy to production environment
          elif [ "${CIRCLE_BRANCH}" == "develop" ]; then
            # deploy to development environment
          fi

0.0.1 の形式でタグが打たれているときにデプロイするケース。


version: 2
jobs:
  build:
    steps:
      - deploy:
          command: |
            if [[ "${CIRCLE_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
              # deploy to production environment
            fi

 ツイート 0  シェア 0  Hatena 1