パイプラインがデプロイ承認者を決める仕組み

想像してみてください。開発者がドキュメントページのタイポを修正したとします。変更は1行、ロジックへの影響はなく、データベースにも触れていません。しかし、デプロイプロセスでは依然として2名の承認、30分のステージング待機、エンジニアリングマネージャーのサインオフが必要です。本来5分でユーザーに届くはずの修正が、半日かかってしまいます。

今度は逆のケースを想像してください。開発者が本番テーブルをロックしかねないデータベースマイグレーションスクリプトを変更したとします。同じパイプラインは、これをタイポ修正とまったく同じように扱います。追加のレビューも特別なチェックもありません。変更はすり抜け、チームはクエリがタイムアウトし始めて初めて問題に気づきます。

どちらのシナリオも壊れていますが、理由は正反対です。前者は安全な変更を遅らせ、後者は危険な変更をすり抜けさせます。問題は、ほとんどのデプロイパイプラインが、実際に何が変更されたかに関係なく、すべての変更に同じルールを適用していることです。

なぜ一律の承認モデルが機能しないのか

多くのチームはシンプルな承認モデルから始めます。すべてのデプロイにレビューが必要、というものです。チームが小さく、すべての変更が重要な場合、これは機能します。しかし、コードベースが成長するにつれて、このモデルは崩壊します。CSSの微調整と決済モジュールのリファクタリングに、同じサインオフが必要になります。開発者はデプロイ回数を減らすために変更をまとめたり、プロセスが官僚的に感じられるためレビュー自体をスキップしたりし始めます。

本当の問題は、リスクが均一ではないことです。READMEファイルの変更は、運用リスクがほぼゼロです。データベースマイグレーションや認証モジュールの変更は、重大なリスクを伴います。これらを同じように扱うということは、安全な変更には厳しすぎるか、危険な変更には甘すぎるかのどちらかになります。

パイプラインが自動的にリスクを評価する方法

人間がすべての変更を判断する代わりに、どのファイルが変更されたかに基づいてリスクを評価するようパイプラインを教育できます。これはリスクスコアリングと呼ばれ、変更の範囲に基づいてポイントを割り当てるルールを定義することで機能します。

シンプルなルールセットの例は次のようになります:

このロジックをGitLab CIパイプライン設定に変換すると、次のようになります:

stages:
  - test
  - deploy

deploy:
  stage: deploy
  script:
    - echo "Deploying to production..."
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      changes:
        - "db/**/*"
        - "config/**/*"
      when: manual
      allow_failure: false
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      changes:
        - "docs/**/*"
        - "README.md"
      when: on_success
    - when: on_success
  • docs/ または README.md 内のファイル変更:0ポイント
  • 設定ファイル(.envconfig/)の変更:3ポイント
  • src/ 内のビジネスロジックの変更:7ポイント
  • 決済または認証モジュールの変更:20ポイント
  • データベースマイグレーションファイルの変更:25ポイント

パイプラインはプルリクエストまたはコミットをスキャンし、変更された各ファイルをこれらのルールに対してチェックし、合計スコアを算出します。そのスコアが次に何を行うかを決定します。

リスクスコアをデプロイポリシーにマッピングする

パイプラインがリスクスコアを取得したら、結果に基づいて異なるポリシーを適用できます。典型的な設定では、3つのティアがあります:

次のフローチャートは、パイプラインがリスクスコアをデプロイポリシーにマッピングする方法を示しています:

flowchart TD A[変更が提出される] --> B{変更ファイルをスキャン} B --> C[リスクスコアを割り当て] C --> D{スコア <= 5?} D -->|Yes| E[低リスク] E --> F[自動承認] F --> G[本番にデプロイ] D -->|No| H{スコア 6-15?} H -->|Yes| I[中リスク] I --> J[1名のピア承認が必要] J --> G H -->|No| K[高リスク] K --> L[2名の承認が必要] L --> M[ステージングにデプロイ] M --> N[スモークテストと監視を実行] N --> O{チェック合格?} O -->|Yes| G O -->|No| P[デプロイをブロック]

低リスク(スコア0-5): 手動承認なしで直接本番にデプロイできます。パイプラインは自動テストを実行し、合格すればデプロイが進行します。これは、ドキュメント修正、軽微な設定変更、またはクリティカルパスに触れないリファクタリングをカバーします。

中リスク(スコア6-15): ピアまたはシニアエンジニア1名の承認が必要です。パイプラインはテスト合格後に一時停止し、本番に進む前に手動のサインオフを待ちます。

高リスク(スコア16以上): 2名の承認が必要で、監視チェックに合格した状態で少なくとも1時間ステージングに留まる必要があります。パイプラインはまずステージングにデプロイし、スモークテストを実行し、エラー率とレイテンシをチェックし、その後でのみ本番への最終プロモーションを許可します。

これらのしきい値は固定ではありません。環境が異なれば、異なるルールを設定できます。開発環境では、実際のユーザーがいないため、すべてを低リスクとして扱うかもしれません。ステージングでは、しきい値を少し上げるかもしれません。本番では、最も厳格なルールを適用します。

本当のメリットは完全な正確性ではなく一貫性

リスクスコアリングが完全に正確になることは決してありません。ユーティリティ関数の1行の変更が、その関数が多くの場所で呼び出されている場合、予期せぬ問題を引き起こす可能性があります。多くのファイルに触れる大規模なリファクタリングでも、変数名の変更だけなら実際には安全かもしれません。

しかし、完全な正確性が目標ではありません。目標は、アドホックな人間の判断を、一貫性のある透明なプロセスに置き換えることです。リスクスコアリングがなければ、すべてのデプロイで議論が始まります。「これには承認が必要か?誰がレビューすべきか?ステージング時間をかけるほどのリスクか?」これらの議論は時間を浪費し、一貫性を欠きます。ある週は小さな変更がすんなり通っても、次の週には同じタイプの変更がブロックされます。

リスクスコアリングがあれば、ルールは文書化され、自動的に適用されます。チームはルールを設定するときに一度だけ議論すればよく、個々のデプロイごとに議論する必要はありません。また、ルールが透明であるため、チームは実際に問題を引き起こす変更の種類を学習するにつれて、時間をかけてルールをレビューし調整できます。

これがチームの行動をどう変えるか

リスクベースのデプロイ制御は、承認を自動化するだけではありません。開発者がコード構造について考える方法を変えます。チームが db/migrations/ への変更が自動的に高リスクポリシーをトリガーすることを知っていれば、そのフォルダに何を入れるかについてより慎重になります。データベーススキーマの変更とデータマイグレーションスクリプトを分離し、単純なデータバックフィルがスキーマ変更と同じ精査をトリガーしないようにするかもしれません。

また、より良いモジュール化を促進します。特定のモジュールへの変更が常に高リスクと評価されることにチームが気づけば、そのモジュールをリファクタリングして、本当にセンシティブな部分と日常的な更新を分離するかもしれません。時間が経つにつれて、コードベースはリスク境界を意識して構造化されるようになります。

リスクスコアリング設定の実践的チェックリスト

このアプローチを実装する場合の開始チェックリストは次のとおりです:

  • コードベース内のどのフォルダとファイルパターンが異なるリスクレベルを表すかを特定する
  • 各パターンに明確なポイント値を設定したスコアリングシステムを定義する
  • 各環境の低、中、高リスクのしきい値を設定する
  • 各リスクレベルのデプロイポリシー(必要な承認、ステージング時間、監視チェック)を定義する
  • CI/CDパイプライン設定にリスクスコアリングロジックを実装する
  • すべてのプルリクエストでスコアリングを実行し、結果を可視化のためにログに記録する
  • 1ヶ月後にスコアリングルールをレビューし、学んだことに基づいて調整する

パイプラインが意思決定者になる

リスクベースのデプロイ制御を追加すると、パイプラインは単なるコマンド実行ツールではなくなります。変更を評価し、ルールを適用し、本番への適切なパスを決定する意思決定システムになります。パイプラインは人間の判断を完全に置き換えるわけではありませんが、実際に人間の注意が必要な変更に注意を集中させます。

これは制御を排除することではありません。適切なレベルの制御を適切な変更に適用することです。小さく安全な変更は迅速に進みます。大規模でリスクの高い変更は、それにふさわしい精査を受けます。そしてチームは、自明であるべきことにエネルギーを浪費するのをやめます。