コンテンツにスキップ

Design

Context

現在、プロジェクトは React + Vite で構築された SPA で、Azure Blob Storage の静的ホスティングにデプロイされている。テストやデプロイは手動で行われており、自動化が必要である。プロジェクトは GitHub でホストされており、pnpm をパッケージマネージャーとして使用している。

Goals / Non-Goals

Goals: - GitHub Actions を使用した CI/CD パイプラインの構築 - main ブランチへの push 時に本番環境へ自動デプロイ - Pull Request 作成・更新時に開発環境へ自動デプロイと E2E テスト実行 - OIDC 認証を使用した安全な Azure 認証 - Lint、単体テスト、ビルドの自動実行によるコード品質維持

Non-Goals: - ステージング環境やその他の環境の構築(本番と開発のみ) - パフォーマンステストや負荷テストの自動実行 - 自動ロールバック機能(手動で対応) - デプロイ承認フロー(main への push で即座にデプロイ)

Decisions

1. CI/CD ツールとして GitHub Actions を選択

理由: プロジェクトはすでに GitHub でホストされており、追加のサービス契約や設定が不要。OIDC 認証もネイティブサポート。

代替案: Azure DevOps Pipelines も検討したが、GitHub との統合が追加で必要になるため不採用。

2. Azure 認証に OIDC を使用

理由: アクセスキーやサービスプリンシパルのシークレットを GitHub Secrets に保存する必要がなく、セキュリティリスクを低減。GitHub と Azure 間の信頼関係により、短命なトークンで認証可能。

代替案: サービスプリンシパルとシークレットの組み合わせも可能だが、シークレットのローテーションやリーク時のリスクが高いため不採用。

3. ジョブ構成: 並列実行とデプロイの分離

構成: - test ジョブ: Lint と単体テストを並列実行 - build ジョブ: test 完了後にビルド実行 - deploy-prod / deploy-dev ジョブ: build 完了後にデプロイ - e2e-dev ジョブ(開発環境のみ): deploy-dev 完了後に E2E テスト実行

理由: テストとビルドを明確に分離し、テストが失敗した場合はビルドやデプロイをスキップ。並列実行により CI 時間を短縮。

代替案: すべてを 1 つのジョブにまとめることも可能だが、失敗時の再実行効率が悪くなるため不採用。

4. 環境分離: 本番(main ブランチ)と開発(Pull Request)

本番環境: - トリガー: main ブランチへの push - 処理: Lint → テスト → ビルド → デプロイ - E2E テスト: 実行しない(本番環境へのテストトラフィックを避けるため)

開発環境: - トリガー: Pull Request の作成・更新 - 処理: Lint → テスト → ビルド → デプロイ → E2E テスト - E2E テスト: デプロイ完了後に実行し、実際の環境で動作確認

理由: 本番環境には安定したコードのみをデプロイし、開発環境で E2E テストを含む完全な検証を行う。

5. キャッシュ戦略: pnpm ストアのキャッシュ

actions/setup-nodecache: 'pnpm' を使用し、依存関係のインストール時間を短縮。

理由: pnpm は独自のストア構造を持ち、キャッシュヒット時のインストール時間を大幅に短縮可能。

6. Playwright ブラウザのキャッシュ

E2E テスト実行前に Playwright ブラウザをキャッシュし、毎回のダウンロードを回避。

理由: ブラウザのダウンロードは時間がかかるため、キャッシュすることで CI 時間を短縮。

Risks / Trade-offs

リスク 1: main への直接 push で即座に本番デプロイ

リスク: PR をスキップして main に直接 push した場合、レビューなしで本番にデプロイされる可能性。

対応: GitHub のブランチ保護ルールを設定し、main への直接 push を制限。PR マージのみを許可。

リスク 2: OIDC 認証設定の複雑さ

リスク: Azure 側で OIDC の設定(アプリケーション登録、フェデレーション資格情報、権限付与)が必要で、初期設定が複雑。

対応: 設定手順を README または別ドキュメントに記載し、初回設定時のガイドとする。

リスク 3: E2E テストの不安定性

リスク: E2E テストは環境依存やタイミングの問題で不安定になりがち。

対応: Playwright の retry 機能を活用し、一時的な失敗による false negative を低減。テストが継続的に失敗する場合はテスト自体を見直す。

トレードオフ 1: 開発環境への頻繁なデプロイ

トレードオフ: PR の更新のたびに開発環境へデプロイされるため、Azure ストレージへのアクセスが増加。

受容理由: 開発環境での動作確認は重要であり、Azure Blob Storage のコストは低いため許容可能。

トレードオフ 2: 本番環境で E2E テストを実行しない

トレードオフ: 本番環境で実際に動作するかの確認が自動化されない。

受容理由: 開発環境と本番環境の差異は最小限(静的ファイルのみ)であり、開発環境での E2E テストで十分カバー可能。本番環境へのテストトラフィックを避けることを優先。

Migration Plan

初期設定

  1. Azure 側の OIDC 設定:
  2. Azure Portal でアプリケーション登録を作成
  3. フェデレーション資格情報を追加(GitHub リポジトリと環境を指定)
  4. ストレージアカウントへの権限付与(Storage Blob Data Contributor ロール)

  5. GitHub Secrets の設定:

  6. AZURE_CLIENT_ID: アプリケーション(クライアント)ID
  7. AZURE_TENANT_ID: ディレクトリ(テナント)ID
  8. AZURE_SUBSCRIPTION_ID: サブスクリプション ID
  9. AZURE_STORAGE_ACCOUNT_PROD: 本番環境のストレージアカウント名
  10. AZURE_STORAGE_ACCOUNT_DEV: 開発環境のストレージアカウント名
  11. VITE_BLOB_BASE_URL_PROD: 本番環境の Blob Service Endpoint URL
  12. VITE_BLOB_BASE_URL_DEV: 開発環境の Blob Service Endpoint URL

  13. ワークフローファイルの作成:

  14. .github/workflows/deploy.yml を作成
  15. main ブランチに PR 経由でマージ

デプロイ手順

  1. .github/workflows/deploy.yml を含む PR を作成
  2. PR の CI が成功することを確認(開発環境へのデプロイと E2E テスト)
  3. PR を main にマージ
  4. main へのマージにより本番環境へ自動デプロイ

ロールバック戦略

自動ロールバックは実装しない。問題が発生した場合は以下の手順で手動ロールバック:

  1. Git で前回の安定版のコミットへ git revert を実行、または直接 main へ push する
  2. CI/CD パイプラインが自動的に前回のバージョンをデプロイ

代替案: Azure Blob Storage のバージョニング機能を有効にしておき、Azure Portal から手動にて前回のバージョンを復元。

Open Questions

  • Playwright ブラウザのキャッシュキーをどのように管理するか?(Playwright のバージョンベースでキャッシュ)
  • 開発環境のデプロイ先をブランチごとに分けるか?(初期実装では共通の dev 環境を使用)
  • E2E テストが失敗した場合、PR のマージをブロックすべきか?(初期実装ではブロックしない。required check には含めない)