フロントエンド刷新プロジェクトの開発サイクルを加速するデプロイパイプラインの改善

フロントエンド刷新プロジェクトの開発サイクルを加速するデプロイパイプラインの改善

OGP画像

この記事は Cybozu Advent Calendar 2022 の 19 日目の記事です。

こんにちは!! kintone フロントエンドリアーキテクチャプロジェクト (フロリア)のAppShell チームでプロダクトオーナーをしている tasshi です。

kintone フロントエンドリアーキテクチャプロジェクト (フロリア)、およびAppShellチームについてはこちらの記事をご覧ください。

今回はフロリアの開発で利用しているテスト環境へのデプロイパイプラインを紹介します。


目次


概要

フロリアでは kintone の動作確認に自社インフラ上のテスト環境を利用しています。

従来のテスト環境へのデプロイ手順には手作業や待ち時間が多く、開発メンバーの負担になっていました。
そのためPull Request (PR) から簡単にテスト環境へデプロイできるパイプラインを整備し、開発サイクルを改善しました。

旧デプロイ作業の課題点

2022 年 1 月のフロリア発足当初、テスト環境へのデプロイは次の手順で行っていました。

  1. kintone リポジトリ1に commit を push
  2. CircleCI Server 上のアーカイブ作成ジョブの完了を待機
  3. CircleCI Server のジョブ画面からアーカイブをダウンロード
  4. SSH サーバにアーカイブをアップロード
  5. SSH サーバでデプロイ用コマンドを実行

従来のデプロイ手順
従来のデプロイ手順

これには次のような課題がありました

  • PR からアーカイブ作成ジョブを探すのが面倒
  • SSH サーバ上で作業する必要がある

PR からアーカイブ作成ジョブを探すのが面倒

アーカイブを取得するにはコミットに紐づくアーカイブ作成ジョブを探す必要があります。
kintone リポジトリでは push に紐づく CI が 60 個以上あり、その中から該当のジョブを探すのは地味に面倒な作業でした。

60個以上のCIステータスからアーカイブ作成ジョブを探すのは難しい
60個以上のCIステータスからアーカイブ作成ジョブを探すのは難しい

SSH サーバ上で作業する必要がある

フロリアのメンバーはフロントエンドエンジニアが多く、SSH サーバでの作業に不慣れなメンバーもいました。 また、作業にはデプロイの全体的な仕組みや内製コマンドラインツールの使い方などの多くのドメイン知識が必要になっていました。

改善後のデプロイパイプライン

現在、フロリアでは次のようなデプロイ手順を採用しています。

  1. PR の本文にチェックボックスを表示
  2. PR のチェックボックスをクリック
  3. (デプロイ開始)
  4. PR と Slack 上でデプロイの開始が通知される

チェックボックスからデプロイ
チェックボックスからデプロイ
Slack への通知
Slack への通知

チェックボックスからデプロイするというアイデアは AppShell チームの開発メンバーが出してくれました。 2

パイプラインの解説

パイプラインは GitHub Actions 上の4つのジョブで構成されます。

※パイプラインのジョブ名、内容は説明のために簡略化しています。

  • PR にチェックボックスを追加するジョブ (init-checkbox)
  • PR のチェックボックスを確認するジョブ (check-if-checkbox-checked)3
  • デプロイ開始ジョブ(launch-deploy-jp or launch-deploy-us
  • デプロイ結果を通知するジョブ(notify-success or notify-failure

現在のデプロイパイプライン
現在のデプロイパイプライン
GitHub 上のパイプライン
GitHub 上のパイプライン

今回は PR へのチェックボックス追加からデプロイ開始までの処理を紹介します。

PR にチェックボックスを追加するジョブ (init-checkbox)

PR が作成・編集されるとトリガーされ、PR の本文にチェックボックスを付与します。 PR 本文の編集には GitHub CLI を使用しています。

# プルリクエストの本文末尾にデプロイ用チェックボックスを追加するジョブ
on:
  pull_request:
    types: [ opened, reopened, ready_for_review, labeled, edited ]

  init-checkbox:
    # 本文にデプロイ用チェックボックスがない場合に実行される
    if: "!contains(github.event.pull_request.body , '<!-- deploy-to-test -->')"
    steps:
      # プルリク本文の末尾にチェックボックスを追加して保存する
      - name: Add deployment checkbox to PR body
        env:
          NEW_PR_BODY: |
            ${{ github.event.pull_request.body }}

            ---
            - [ ] <!-- deploy-to-test --><!-- target-test-1 --> **Deploy this branch to test-1.**
            - [ ] <!-- deploy-to-test --><!-- target-test-2 --> **Deploy this branch to test-2.**
            - [ ] <!-- deploy-to-test --><!-- target-test-us --> **Deploy this branch to test-us.**
        run: gh pr edit ${{ github.event.pull_request.number }} --body "${NEW_PR_BODY}"

チェックボックスには機械的に判別可能なフラグメントを追加します。 これは後続の処理でどのチェックボックスがクリックされたか判別する際に使用します。

- [ ] <!-- deploy-to-test --><!-- target-test-1 --> Deploy this branch to test-1.
- [ ] <!-- deploy-to-test --><!-- target-test-2 --> Deploy this branch to test-2.

この実装は Renovate の PR 本文から Rebase する仕組みを参考にしました。

github.com

PR のチェックボックスを確認するジョブ (check-if-checkbox-checked)

PR が作成・変更されるとトリガーされ、PR 本文が先ほどのフラグメントを含むかをチェックします。 また、後続の処理のため、デプロイ先ごとに固有の情報をジョブの出力(jobs.<job_id>.outputs)に追加します。

  check-if-checkbox-checked:
    # デプロイ用チェックボックスがチェックされている場合に実行される
    if: "contains(github.event.pull_request.body, '- [x] <!-- deploy-to-test -->')"
    outputs:
      TARGET: ${{ steps.deployment-target.outputs.TARGET }}
      IS_US: ${{ steps.deployment-target.outputs.IS_US }} # US環境はデプロイ方法が異なる
    steps:
      # デプロイ先を決める
      - run: |
          echo "TARGET=test-1" >> $GITHUB_ENV
          echo "IS_US=false" >> $GITHUB_ENV
        if: "contains(github.event.pull_request.body, '- [x] <!-- deploy-to-test --><!-- target-test-1 -->')"
      - run: |
          echo "TARGET=test-2" >> $GITHUB_ENV
          echo "IS_US=false" >> $GITHUB_ENV
        if: "contains(github.event.pull_request.body, '- [x] <!-- deploy-to-test --><!-- target-test-2 -->')"
      - run: |
          echo "TARGET=test-3" >> $GITHUB_ENV
          echo "IS_US=true" >> $GITHUB_ENV
        if: "contains(github.event.pull_request.body, '- [x] <!-- deploy-to-test --><!-- target-test-us -->')"
      - name: Determine deployment target
        id: deployment-target
        run: |
          echo "::set-output name=TARGET::$TARGET"
          echo "::set-output name=IS_US::IS_US"
      # デプロイ用チェックボックスのチェックを外す
      - name: Uncheck deployment checkbox on PR body
        run: |
          echo '${{ github.event.pull_request.body }}' \
          | sed -e 's/- \[x\] <!-- deploy-to-test -->/- [ ] <!-- deploy-to-test -->/' \
          | gh pr edit ${{ github.event.pull_request.number }} --body-file -

デプロイ開始ジョブ(launch-deploy-jp or launch-deploy-us

PR のチェックボックスを確認するジョブの後に実行されます。 ターゲットのテスト環境ごとに適切なデプロイジョブを呼び出しています。 実際のデプロイに関する処理は切り出して Reusable Workflow 化しています。

Reusable Workflow は既存のワークフローを他のワークフローから再利用できる仕組みです。 通常のワークフローと同じように記述できるためアクションを作成するより学習コストが低く、既存のワークフローから Reusable Workflow への書き換えも簡単なため採用しました。 また、デプロイの実処理は抽象化されている状態なので、今後デプロイを GitHub Actions に置き換えていく際にも、内部処理のみ変更できることが期待できます。

  ## CircleCIのデプロイジョブを起動する
  launch-deploy-jp:
    needs: check-if-checkbox-checked
    if: "needs.check-if-checkbox-checked.outputs.IS_US == 'false'"
    uses: ./.github/workflows/launch-deploy-jp-reusable.yml
    with:
      commit_sha: ${{ github.event.pull_request.head.sha }}
      target: ${{ needs.check-if-checkbox-checked.outputs.TARGET }}
    secrets: inherit

  ## CircleCIのデプロイジョブを起動する(US環境)
  launch-deploy-us:
    needs: check-if-checkbox-checked
    if: "needs.check-if-checkbox-checked.outputs.IS_US == 'true'"
    uses: ./.github/workflows/launch-deploy-us-reusable.yml
    with:
      commit_sha: ${{ github.event.pull_request.head.sha }}
      target: ${{ needs.check-if-checkbox-checked.outputs.TARGET }}
    secrets: inherit

パイプライン改善における制約

アーカイブ作成やデプロイの実処理は CircleCI 上で行なっています。

フロリアではフロントエンド部分について GitHub Actions 上に新たに CI/CD パイプラインを構築していました。
そのため、デプロイについても GitHub Actions 上に新たに構築することを検討したのですが、次のような制約から GitHub Actions から CircleCI 上の既存のパイプラインを利用する形を採用することになりました。

  • アーカイブ作成やデプロイ処理が CircleCI 上での実行に最適化されている
  • kintone開発チーム全体で利用されているため、CircleCI 上のパイプラインの変更にはコミュニケーションコストがかかる

成果

このパイプライン改善で達成したかった「PR の画面から直接デプロイできる」という状態を作ることができました。 またこれに付随してアーカイブのダウンロードやSSH サーバ接続などの手作業が大幅に削減されました。

開発メンバーからも好評で「めっちゃ便利」「神」などのフィードバックをいただきました。

メンバーからのフィードバック1 メンバーからのフィードバック2

今後について

今回のパイプライン改善によって、デプロイ中の手作業を大幅に減らすことができました。
一方で、次の課題は引き続き残っています。

  • アーカイブが作成されるまでチェックボックスを押してもデプロイ開始できない
  • デプロイ完了のタイミングで通知がこない

今後はこれらの問題を解決しつつ、CircleCI を含めた CI/CD パイプライン全体の最適化を進められればと思います。

まとめ

フロリアでのデプロイパイプライン改善を通して、開発プロセス上の不要な手作業・待ち時間を取り除いていくことはメンバーのモチベーションを保ち、開発速度を上げていくために必要なことだと実感しました。
この記事が手動でのデプロイ作業に煩わされている開発者の方の助けになれば幸いです。

フロリアでは絶賛メンバーを募集しています。 フロントエンド刷新に興味がある、開発環境を一緒に良くしていきたいという方からの応募をお待ちしています!


  1. リポジトリは GitHub Enterprise (GHE) 上にあります。
  2. 当初は workflow_dispatch からデプロイできるようにしようと思っていたのですが、PR の画面だけで完結したいと言われたため頑張りました。
  3. check-checkbox としたかったのですが、チェックボックスをチェックするジョブなのかチェックボックスにチェックを入れるジョブなのか分かりづらかったためこのようにしました。