注目キーワード
  1. react
  2. docker
  3. インターン

CircleCIをtagでデプロイできるフローを整える

  • 2019.07.31
  • 2019.07.31
  • 雑記
  • 34回
  • 0件

デプロイのフローでリリースタグをつけたときにだけデプロイしたい、という要件があってやってみたところ意外と詰まるポイントがあったのでまとめてみました。

要件

CI/CD環境を整えるにあたって、

  • mergeのときではなく任意のタイミングでデプロイしたい
  • master mergeのときはstgにあげるだけ(developブランチは存在しない)
  • デプロイ後のトラブルのためにロールバックする方法を準備したい

という要件がありました。

そこで、リリースタグを切ってそれをpushしたタイミングでのみデプロイプロセスを走らせ、かつデプロイの直前でapprovalを要求するという設計にしました。

こんな感じのフローを実現するのがゴールです。(試行錯誤の結果v1.0.12まで到達w)
master mergeの前後でtestは走っていて通っているものという前提かつロールバックのときに迅速に対応できるように、ということでデプロイプロセスではテストは並列で走るようにしています。

 

git tag

特徴

あまり今までちゃんと使ったことがなかったのでこの期にしっかり勉強してみました。git tagは一種の目印のようなもので特定のコミットにつけることができます。特徴として

  • リリースしたタイミングなどを管理しやすい
  • checkoutしてその状態を即座に再現することができる
  • 一つのタグに複数のタグをつけることができる
  • コミットログとは時間軸が異なっても問題ない(ロールバックして最新のタグが昔のコミットでも問題ない)

があげられます。

すなわち、revertや新規のPRなしにロールバックしてその変更を管理できるので、今回の要件にはぴったりです。

 

付け方

何も指定しない場合は現在のブランチの最新のコミットにタグがつきます。

$ git tag <tag名>

ブランチ名やコミットハッシュを指定することで任意のコミットにタグをつけることができます。

$ git tag <tag名> <branch名 or commit hash>

またタグをつけただけでは、リモートのタグは更新されません。タグを公開するには、

$ git push origin <tag名>

とする必要があります。

 

jobの作成


version: 2

defaults: &defaults
  docker:
    - image: circleci/node:8-browsers

jobs:
  build:
    <<: *defaults
    steps:
      - checkout
      - run:
          name: build
          command: echo build

  test:
    <<: *defaults
    steps:
      - checkout
      - run:
          name: test
          command: echo test

  test_for_prd:
    <<: *defaults
    steps:
      - checkout
      - run:
          name: test_for_prd
          command: echo test_for_prd

  deploy:
    <<: *defaults
    steps:
      - checkout
      - run:
          name: deploy
          command: echo deploy

とりあえずこんな感じで、echoするだけのjobを作ってみました。全てダミーのジョブとしてechoしてるだけです。これらのjobを組み立ててフローにしていきます。

 

ワークフローの作成

直感的には、、

要件で求められているものを直感的に記述してみました。

workflows:
  version: 2
  test_and_deploy:
    jobs:
      - test
      - test_for_prd:
          filters:
            tags:
              only: /^v(\.[0-9]){3}.*/
      - deploy:
          requires:
            - test_for_prd

これでpushしてみると、なんとtagがないときにだけデプロイが実行されてしまいます。。!?わけがわからなくてこれで結構時間を食われました。。

 

tagsは全部のjobに記述しないといけない

らしいです。このときは理由がよくわかってなかったのですが、とりあえず記述。

workflows:
  version: 2
  test_and_deploy:
    jobs:
      - test
      - test_for_prd:
          filters:
            tags:
              only: /^v(\.[0-9]){3}.*/
      - deploy:
          requires:
            - test_for_prd
          filters:
            tags:
              only: /^v(\.[0-9]){3}.*/

でも、依然ブランチpushでデプロイが走ってしまいます。。ほんまもんのプロダクトでやってたらえらいこっちゃw

 

CircleCIのデフォルト

いろいろ試したり調べたりしてるうちにわかったのが、

  • filterのbranchesとtagsは無関係
  • ブランチは特に指定しない限り、全てのフローが実行される
  • タグは明示的に宣言しない限り、全てのフローが実行されない

というデフォルトの設定を持っていたのです。すなわち、タグプッシュでのみデプロイしたい場合は、そのフローを「任意のブランチで実行されないように指定し、かつ指定したタグで実行される」ように指定してやる必要があったのです。知らんわそんなもんw

てことで、

workflows:
  version: 2
  test_and_deploy:
    jobs:
      - test
      - test_for_prd:
          filters:
            tags:
              only: /^v(\.[0-9]){3}.*/
            branches:
              ignore: /.*/
      - deploy:
          requires:
            - test_for_prd
          filters:
            tags:
              only: /^v(\.[0-9]){3}.*/
            branches:
              ignore: /.*/

としてやると、思い通りの実装になりました。

理由としては、タグは印にすぎずタグで何かをトリガーしたい!という強い意思でもない限りフローを実行する必要がないので、あえてCircleCIではこのような実装にしてるんじゃないかな〜と思います。逆にCIなので、すべてのブランチに対して処理を実行というのがデフォルトなのも納得の行く気がします。

 

approvalの実装

ふむふむtype: approvalとするといいらしい。

      - deploy:
          type: approval
          requires:
            - approval
          filters:
            tags:
              only: /^v(\d\.){2}\d.*/
            branches:
              ignore: /.*/

これでpushすると、、

おお!それっぽい!、、と思ったのもつかの間。。

このデプロイプロセスのログとかが全く見れなくなってしまいました。どうやら、approvalは単体でフローに入れるべきみたいでした。

     - test_for_prd:
          requires:
            - build
          filters:
            tags:
              only: /^v(\d\.){2}\d.*/
            branches:
              ignore: /.*/

      - approval:
          type: approval
          requires:
            - build
          filters:
            tags:
              only: /^v(\d\.){2}\d.*/
            branches:
              ignore: /.*/

      - deploy:
          requires:
            - approval
          filters:
            tags:
              only: /^v(\d\.){2}\d.*/
            branches:
              ignore: /.*/

これで、思い通りの挙動になりました。

そして、approveすると、、

おお!デプロイできた!!

ま、echo deployしただけですけどねw