[CircleCI]requiresとfiltersの指定を適切に組み合わせてapprove通知を適正にした記録

ManualApproveを適切なタイミングで通知するように調整しつつ、異なるfilter構成のjobを一つのWorkflow内に収めてみた過程をまとめました。
2019.10.31

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

はじめに

CICD実行時に更新を含まないbuildやdeployを避ける目的で、buildとdeployの発生直前にManual Approveを挟んでみました。結果として無意味なbuildやdeployにリソースを浪費することはなくなったのですが、今度は伴って発生するSlackへの通知が過多になってしまいました。

勿論必要なApproval通知もあるのですが、明らかに自動処理を寸止めするためだけのApproval通知の方が多く、操作を誤ると事故の原因となります。

  • 必要な時にはApprove通知を飛ばす
  • 寸止めしたい時にはApprove通知を飛ばす以前にWorkflowをそのものを終わらせる

という形を目指して、試行錯誤ながらも試してみた内容が期待通りの結果となったため、備忘録としてまとめてみました。

Approve通知に関する要件

ベースは以下のエントリーです。当時は開発環境のみの設定でしたが、現在は本番環境の設定も含んでいます。

自動化と時短を目的にCircleCIで暫定のCICD環境を作成した記録

まず、「通知が必要な時」と「通知が必要ではない時」の2つに分けました。その上で、それぞれのjobを動かすための前提をfilterとして当てはめます。

github-flowを利用しており、tag作成はmasterブランチから行われます。

CICDの処理 フックとなる更新 通知 環境
build masterブランチ更新 開発
deploy masterブランチ更新 開発
deploy tag作成 本番
test masterブランチ更新 不要 開発
test 作業ブランチ更新 不要 開発

ワークフローに関する要件

Approveの通知の構成から、それぞれ以下の流れとなります。

作業ブランチ更新
test
masterブランチ更新
test + build + development deploy
tag作成
production deploy

WorkFlowのrequires設定

すでに組まれているbatch test、build、deployのjobに対して、requiresとfiltersを更新します。

test

作業ブランチ更新の際のフローです。branchはどんな命名パターンでも受け付けます。承認通知は送られません。

    jobs:
      - test:
          python-version: "3.6"
          filters:
            tags:
              ignore: /.*/
            branches:
              only: /.*/
          context: xxxx

test + build + development deploy

masterブランチ更新の際には、testフローに加えて以下のフローが走ります。buildと開発環境deploy時に承認通知が送られます。

      - slack/approval-notification:
          message: ${CIRCLE_BRANCH}をbuildするためにはApproveが必要です。
          requires:
            - test
          context: xxxx
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master
      - approve_build:
          type: approval
          requires:
            - test
          context: xxxx
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master
      - aws-ecr/build-and-push-image:
          requires:
            - approve_build
          context: xxxx
          dockerfile: 'docker/Dockerfile'
          repo: 'XXXX'
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master
      - slack/approval-notification:
          message: ${CIRCLE_BRANCH}を開発環境へdeployするためにはApproveが必要です。
          requires:
            - aws-ecr/build-and-push-image
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master
          context: xxxx
      - approve_deploy_dev:
          type: approval
          requires:
            - aws-ecr/build-and-push-image
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master
          context: xxxx
      - deploy_dev:
          requires:
            - approve_deploy_dev
          python-version: "3.6"
          context: xxxx
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master

production deploy

tag作成の際には以下のフローが走ります。tagはどんな命名パターンでも受け付けます。本番環境deployの承認通知が送られます。

      - slack/approval-notification:
          message: ${CIRCLE_TAG}を本番環境へdeployするためにはApproveが必要です。
          filters:
            tags:
              only: /.*/
            branches:
              ignore: /.*/
          context: xxxx
      - approve_deploy_prod:
          type: approval
          filters:
            tags:
              only: /.*/
            branches:
              ignore: /.*/
          context: xxxx
      - deploy_prod:
          requires:
            - approve_deploy_prod
          python-version: "3.6"
          filters:
            tags:
              only: /.*/
            branches:
              ignore: /.*/
          context: xxxx

通して一つのconfigにする

上記の各jobsを一つのワークフローにまとめます。最初は「本当にこれで問題ないのだろうか」と思いましたが、実際に走らせてみるとfilterに応じてworkflowが変化していました。

workflows:
  version: 2
  cicd_pipeline:
    jobs:
      - test:
          python-version: "3.6"
          filters:
            tags:
              ignore: /.*/
            branches:
              only: /.*/
          context: xxxx
      - slack/approval-notification:
          message: ${CIRCLE_BRANCH}をbuildするためにはApproveが必要です。
          requires:
            - test
          context: xxxx
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master
      - approve_build:
          type: approval
          requires:
            - test
          context: xxxx
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master
      - aws-ecr/build-and-push-image:
          requires:
            - approve_build
          context: xxxx
          dockerfile: 'docker/Dockerfile'
          repo: 'XXXX'
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master
      - slack/approval-notification:
          message: ${CIRCLE_BRANCH}を開発環境へdeployするためにはApproveが必要です。
          requires:
            - aws-ecr/build-and-push-image
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master
          context: xxxx
      - approve_deploy_dev:
          type: approval
          requires:
            - aws-ecr/build-and-push-image
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master
          context: xxxx
      - deploy_dev:
          requires:
            - approve_deploy_dev
          python-version: "3.6"
          context: xxxx
          filters:
            tags:
              ignore: /.*/
            branches:
              only: master
      - slack/approval-notification:
          message: ${CIRCLE_TAG}を本番環境へdeployするためにはApproveが必要です。
          filters:
            tags:
              only: /.*/
            branches:
              ignore: /.*/
          context: xxxx
      - approve_deploy_prod:
          type: approval
          filters:
            tags:
              only: /.*/
            branches:
              ignore: /.*/
          context: xxxx
      - deploy_prod:
          requires:
            - approve_deploy_prod
          python-version: "3.6"
          filters:
            tags:
              only: /.*/
            branches:
              ignore: /.*/
          context: xxxx

あとがき

全く条件が異なるfilterを持つjobを混在させた場合に、正常に動作するのか不安でしたが、いずれの前提の場合も問題ありませんでした。

ただ、filterの条件が複雑になってくると、CICDの要件が増えた際にミスが発生しやすくなります。その場合はConfigのパッケージ化を検討してみましょう。