CircleCI の設定についてのメモ

CircleCIでビルド・テスト・デプロイパイプラインを作りました。

基本構成

.circleci/config.yml が設定ファイルです。

workflows にワークフローを定義して使います。 ワークフローはトリガーとジョブが組み合わさったものです。トリガーはブランチへのプッシュがデフォルトです。明示的に設定できるのは今のところ cron だけなのでコミット毎に実行したいときは trigers を設定してはいけません。ジョブは実行環境の定義とステップの並びです。

具体例は下のような感じです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
version: 2.1
jobs:
  build:
    docker:
      - image: circleci/openjdk:11-jdk
    environment:
      MESSAGE: "Hi, CircleCI"
    steps:
      - checkout
      - run:
          command: 'echo $MESSAGE'
  deploy:
    docker:
      - image: circleci/python:3.8.4
    steps:
      - checkout
workflows:
  version: 2
  b_and_d:
    jobs:
      - build
          filters:
            tags: &version-tag
              only: 'v.*'
      - wait_approval:
          requires:
            - build
          type: approval
          filters:
            tags:
              <<: *version-tag
            branches:
              ignore: '.*'
      - deploy:
          requires:
            - wait_approval
          filters:
            tags:
              <<: *version-tag
            branches:
              ignore: '.*'

ここでは書いていますが設定ファイルにワークフローが明記されていないときは build ジョブを呼び出すワークフローが実行されます。 またワークフローないのジョブ呼び出しで filters.tags を書かないと次のようなフィルターになるようです。

1
2
3
4
5
filters:
  branches:
    only: '.*'
  tags: &deafult-tags-filter
    ignore: '.*'

そのためタグプッシュで動かしたいときには明記する必要があります。 ここで & で始まるのはアンカーで配下の定義を他の場所で使うときに使います。

例の b_and_d ワークフローでは wait_approval の前に build が完了していることを要求しています。 また wait_approval では type: approval を設定することでUI上で承認しないと開始されないようにしています。 実際のデプロイは deploy で行っており、これは wait_approval を要求することで承認されたらデプロイするという流れを実現しています。

docker, environment で実行環境を指定して steps に様々な処理を記載します。

プロジェクトで使う環境変数はUIなどから設定することができます。 またコンテキストと呼ばれるプロジェクト横断で共有できる環境変数の組み合わせも使えるようです。

ワークフローの構成はこの記事にまとまっています。

状態管理の機能

下の4つがある。

  • 成果物
  • テスト結果
  • ジョブ間での状態管理(ワークフロー内での状態管理)
  • キャッシュ(ワークフロー間での状態管理)

成果物の保存はつぎのように指定する。 指定したパスがそのままジョブの ARTIFACTS タブに表示されダウンロードできるようになる。

1
2
- store_artifacts:
    path: build/libs/something-0.0.1.jar

ref. store_artifacts

テスト結果の保存は次のように指定する。 結果が TESTS タブに保存される。

1
2
- store_test_results:
    path: build/test-results

ジョブは一つの実行環境で実施されるため問題はないのですが、ワークフローのなかでデータを引き継ぎたいことがあると思います。そのためにワークフロー内で使い回せるストレージがあります。

以下のようにすることでジョブ内で作ったデータを保存したり特定パスにストレージ内容をコピーできます。

attach_workspace によって対象パス配下に保存されているデータが全てコピーされる一方で、 persist_to_workspace では root 配下の paths で書かれたファイルのみが保存されます。

1
2
3
4
5
6
- persist_to_workspace:
    root: build/libs/
    paths:
      - something-0.0.1.jar
- attach_workspace:
    at: files/lib

毎回ビルドのたびに同じ依存パッケージをインストールしてるのは無駄なので同じであるとわかっているならばキャッシュを使いたいですね。CircleCIでもキャッシュを使うことができます。

したのように書きます。

1
2
3
4
5
6
7
8
- restore_cache:
    keys:
      - v1-dependencies-{{ checksum "build.gradle" }}
- run: ./gradlew dependencies
- save_cache:
    paths:
      - ~/.gradle
    key: v1-dependencies-{{ checksum "build.gradle" }}

restore_cache でキャッシュ内容を復元します。 復元するキャッシュがなければ何もしません。 キャッシュはkeys属性で指定します。キーにはテンプレート機能を使うことでファイルの内容に応じたキー名を設定できます。これによりキャッシュが有効か判断しています。 キャッシュは save_cache で保存します。やはり key を指定しますがここでもキー名をファイルの内容から作っています。またキャッシュするファイルパスを paths で指定しています。

テンプレートでは他にも色々な値を使えるのでsave_cacheの項を確認してください。

シンプルにつくる機能

CircleCIでの定義をできるだけ簡潔にするために下のようあん機能があります。

  • アンカーとエイリアスとマージ
  • executor
  • command
  • Orb

これらを使うことで重複した記述を避けることができますが、実際に実行されるまえに値が展開されることになります。 最終的にどのように展開されるか知りたいときは circleci config process コマンドによって確認できます。

アンカーとエイリアスとマージ

YAML の記述を確認してください。とても便利です。

executor

2.1から実行環境に名前を与えてジョブで使い回せます。 Executorの説明を読みましょう。簡単です。 ちなみにこのアナウンスによるとCircleCIが管理しているコンテナ環境は circleci/* から cimg/* に変わるようです。 公式イメージに関するドキュメントはこちら

command

2.1からパラメタライズしたステップ列をコマンドとして利用できます。 commandsの説明を確認しましょう。

Orb

2.1から Orb というモジュール機能が追加されてます。 Orbs リファレンス ガイドを読んでみました。まだ使ってみただけで自分では定義、公開したことがないです。

公式の一覧はここにあります。

したのように、使うorbsに名前を与えexecuterやjobを呼び出します。

1
2
orbs:
  slack: circleci/slack@4.1.3
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
## stepsの中でcommandを呼び出す
steps:
  - slack/notify:
      event: pass
      template: success_tagged_deploy_1
# jobsの中でjobを呼び出す
jobs:
  - slack/on-hold:
      filters:
        tags:
          only: '/^v.*/'

おわりに

仕事で必要になり久しぶりに設定しました。 他にもAWSのセキュリティグループに一時的に通信路を許可したり、成果物をセマンティックバージョンで管理したりと考えないといけないことはたくさんありました。時間ができたらメモするかもしれません。 簡単な割りに書こうとすると長くなるし記事は溢れてるのでモチベーションは低いです。 あとはAPIがOpenAPIになっているようで使ってみたいですが他にも勉強したいこともあり後回しかなーと思っています。

comments powered by Disqus