CircleCIでトリガーに応じて直列になったり並列になったりするWorkflowを作ってみた

2020.05.16

こんにちは、CX事業本部の若槻です。

今回は、CircleCIでトリガーに応じて直列になったり並列になったりするWorkflowを作ってみたのでご紹介します。

作成したもの

早速ですが、今回作成した.circleci/config.ymlファイルは以下となります。(jobsの内容は省略のため簡易化しています。)

version: 2

references:
  omitted_process: &omitted_process
    docker:
      - image: circleci/hello
    steps:
      - run: echo 'hello'

jobs:
  build_and_test_unit:
    <<: *omitted_process
  deploy_in_dev:
    <<: *omitted_process
  deploy_in_integ:
    <<: *omitted_process
  deploy_in_staging:
    <<: *omitted_process
  deploy_in_pre_prod:
    <<: *omitted_process
  deploy_in_prod:
    <<: *omitted_process

workflows:
  version: 2
  deploy_workflow:
    jobs:
      - build_and_test_unit:
          filters:
            tags:
              only: /v([0-9]+\.){2}[0-9]+/
      - deploy_in_dev:
          requires:
            - build_and_test_unit
          filters:
            branches:
              only:
                - master
            tags:
              ignore: /.*/
      - approve_for_integ:
          type: approval
          requires:
            - deploy_in_dev
          filters:
            branches:
              only:
                - master
            tags:
              ignore: /.*/
      - deploy_in_integ:
          requires:
            - approve_for_integ
          filters:
            branches:
              only:
                - master
            tags:
              ignore: /.*/
      - approve_for_staging:
          type: approval
          requires:
            - build_and_test_unit
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /v([0-9]+\.){2}[0-9]+/
      - deploy_in_staging:
          requires:
            - approve_for_staging
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /v([0-9]+\.){2}[0-9]+/
      - approve_for_pre_prod:
          type: approval
          requires:
            - build_and_test_unit
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /v([0-9]+\.){2}[0-9]+/
      - deploy_in_pre_prod:
          requires:
            - approve_for_pre_prod
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /v([0-9]+\.){2}[0-9]+/
      - approve_for_prod:
          type: approval
          requires:
            - build_and_test_unit
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /v([0-9]+\.){2}[0-9]+/
      - deploy_in_prod:
          requires:
            - approve_for_prod
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /v([0-9]+\.){2}[0-9]+/

上記のconfigから構成されるWorkflowにより、以下のような開発フローを実現することができます。(デプロイ先の環境は「開発」「結合試験」「ステージング」「プレ本番」「本番」の5つです。)

  • 開発フロー
  1. masterブランチから作業用ブランチをCheckoutする
  2. 作業用ブランチで作業を行い、作業内容をCommitしてPushする
  3. ブランチのPushをトリガーにして、「ビルド・単体テスト」を実施するWorkflowがCircleCIで開始される
  4. Pushされた作業用ブランチをもとにPull Requestを作成する
  5. Pull Requestに対するレビューが承認されれば、masterブランチへMergeする
  6. masterブランチへのMergeをトリガーにして、「ビルド・単体テスト」「開発環境へのデプロイ」「承認」「結合試験環境へのデプロイ」を直列で実施するWorkflowがCircleCIで開始される
  7. 結合試験環境をもとに最終レビューを実施する
  8. 最終レビューが承認されれば、承認されたCommitにタグ(例v1.2.3)を付けてPushする
  9. タグのPushをトリガーにして、「ビルド・単体テスト」の後に「承認」および「ステージング環境へのデプロイ」「プレ本番環境へのデプロイ」「本番環境へのデプロイ」を並列で実施するWorkflowがCircleCIで開始される

と言っても、実際のWorkflowの画面を見ていただいた方が分かりやすいかと思います。

ブランチPushで開始されるWorkflow

開発フロー3.にてブランチのPushをトリガーにして開始されるWorkflowの実行時の画面です。 image.png

build_and_test_unitジョブによるビルド・単体テストのみを実施することにより、Pushされた作業用ブランチが少なくとも単体テストをPASSすることをPull Requestでのレビュー前に確認できるようにしています。

masterブランチへのMergeで開始されるWorkflow

開発フロー6.にてmasterブランチへのMergeをトリガーにして開始されるWorkflowの実行時の画面です。 image.png

開発環境へ正常にデプロイされることを確認できた上で、承認を経て結合試験環境にデプロイを行いたいため、build_and_test_unitdeploy_in_devapprove_for_integdeploy_in_integと直列にジョブを実施するWorkflowとしています。

タグPushで開始されるWorkflow

開発フロー9.にてタグのPushをトリガーにして開始されるWorkflowの実行時の画面です。 image.png

基本的にはビルド・単体テストを実施した上で、ステージング環境、プレ本番環境、本番環境の順でそれぞれ承認を経た上でデプロイを行うのでWorkflowは直列でも良いのですが、デプロイ失敗時やhotfix適用時など「ステージングとプレ本番を飛ばしていきなり本番環境にデプロイしたい!」という状況を考慮し、build_and_test_unitの後にapprove_for_stagingdeploy_in_stagingapprove_for_pre_proddeploy_in_pre_prodapprove_for_proddeploy_in_prodと並列にジョブを配置したWorkflowとしています。

最後に、[Piplines]画面からの各Workflowの見え方はこんな感じです。 image.png

おわりに

今回のWorkflowを作るにあたっては、workflowsfilters部分をどのように記載すれば良いかを悩みましたが、configの組み方によりWorkflowがカクカク変わるのを見ながら検証するのは結構楽しかったです。

参考