テストに合格したアーティファクトを絶対に再ビルドしてはいけない理由

想像してみてください。あなたのチームはステージング環境でビルドのテストに3時間を費やしました。すべてグリーン。リリースマネージャーが「よし、本番用に再ビルドしよう」と言います。誰かが新しくコンパイルを実行し、パッケージ化し、デプロイします。1時間後、本番環境でステージングでは決して発生しなかったエラーが発生し始めます。コードは同じですが、アーティファクトは異なります。あなたは最も重要な保証を失いました。テストしたものが、実行しているものではないのです。

このシナリオは、ほとんどのチームが認めるよりも頻繁に発生しています。修正方法は、より優れたビルドツールを使うことではありません。パイプラインが開始した瞬間から始まる規律です。

ビルドは1回、どこでも使用

アーティファクト管理の第一のルールはシンプルです。正確に1回だけビルドすることです。その単一のアーティファクトは、開発から本番までのすべての環境を通過します。再コンパイルはしません。再パッケージ化もしません。「本番フラグを付けて再ビルドさせて」もありません。

次のフローチャートは、単一のアーティファクトがプロモーションを通じて環境間を移動し、決して再ビルドされない様子を示しています。

flowchart TD A[ソースコードコミット] --> B[アーティファクトをビルド] B --> C[チェックサムを計算] C --> D[レジストリにプッシュ] D --> E[開発環境にデプロイ] E --> F[開発環境でテスト実行] F --> G{テスト合格?} G -- Yes --> H[レジストリ内でプロモート] G -- No --> I[コード修正 & 再ビルド] H --> J[ステージング環境にデプロイ] J --> K[ステージング環境でテスト実行] K --> L{テスト合格?} L -- Yes --> M[レジストリ内でプロモート] L -- No --> I M --> N[チェックサムを検証] N --> O[本番環境にデプロイ] O --> P[本番環境で稼働] style B fill:#4CAF50,color:#fff style H fill:#FF9800,color:#fff style M fill:#FF9800,color:#fff style N fill:#2196F3,color:#fff

これは怠け者になることではありません。確実性の問題です。再ビルドすると、変数が導入されます。CIサーバーのキャッシュ状態が異なっていたり、ビルド間に依存関係が更新されたり、ビルドエージェントのライブラリバージョンがわずかに異なっていたりする可能性があります。これらのいずれかにより、テストしたものとは異なる動作をするバイナリが生成される可能性があります。

ステージングですべてのチェックに合格したのと同じアーティファクトが、本番環境で実行されるアーティファクトと同じでなければなりません。それが保証できなければ、テストを信頼することはできません。

すべてのアーティファクトに追跡可能なIDを付与する

どのアーティファクトについても、1つの質問に答えられる必要があります。これはどこから来たのか?つまり、すべてのアーティファクトは、正確なソースコード、正確なパイプライン実行、そしてそれが作成された正確な瞬間にリンクするIDを保持しなければなりません。

これを自動化してください。人間にバージョン番号を割り当てさせてはいけません。パイプラインは、以下を組み合わせたビルドIDを生成する必要があります。

  • ビルドが開始されたタイムスタンプ
  • 連続ビルド番号
  • Gitコミットハッシュ

この組み合わせにより、レジストリから任意のアーティファクトを取得して、どのコミットがそれを生成したか、どのパイプラインがそれをビルドしたか、そしていつかを正確に知ることができます。推測は不要です。「これは先週のリリースからのものだと思う」も不要です。

アーティファクトはサーバーではなくレジストリに置く

ビルドが完了したら、アーティファクトはすぐにCIサーバーから移動させる必要があります。ワークスペース、開発者のラップトップ、共有ネットワークフォルダに置いてはいけません。中央のアーティファクトレジストリに直接送られます。

レジストリは単一の情報源となります。どのチーム、どのパイプライン、どの環境も、必要なアーティファクトを正確にどこで見つければよいかを知っています。レジストリがなければ、「現在本番環境で実行されているアーティファクトのバージョンはどれか?」や「先月のリリースから正確なビルドを再現できるか?」といった基本的な質問に答えるのに苦労するでしょう。

レジストリはまた、制御も与えます。権限を設定し、保持ポリシーを適用し、誰が何にアクセスしたかを追跡できます。これらの機能は、チームが成長し、複数のパイプラインがアーティファクトを消費し始めるときに重要になります。

プロモートする、再ビルドしない

アーティファクトがステージングですべてのテストに合格したら、パイプラインは本番用に再ビルドしてはいけません。代わりに、既存のアーティファクトをプロモートします。プロモーションとは、メタデータの変更を意味します。ラベルの更新、アーティファクトをレジストリ内の別のフォルダに移動、または「本番準備完了」としてマークすることです。

ファイル自体は同一のままです。すべてのテストを通過した同じバイトが、本番環境で実行される同じバイトです。これが再現可能なデプロイの核心です。

しかし、テストとプロモーションの間にアーティファクトが破損したり改ざんされたりしていないことをどうやって確認するのでしょうか?そこで検証が登場します。

信頼する前に検証する

アーティファクトが本番環境に移行する前に、パイプラインはその整合性を検証する必要があります。最も一般的な方法はチェックサム検証です。

ビルドが完了すると、パイプラインはアーティファクトのチェックサムを計算します。通常はSHA256を使用します。このチェックサムはアーティファクトのメタデータとともに保存されます。プロモーションの前に、パイプラインはチェックサムを再計算し、保存された値と比較します。一致しない場合、何か問題が発生しています。ファイルがストレージ中に破損したか、誰かが許可なくアーティファクトを変更した可能性があります。

より強力な保証のために、署名を使用します。パイプラインはチームの秘密鍵でアーティファクトに署名します。プロモーション中に、レジストリは署名を検証します。署名は整合性をチェックするだけではありません。アーティファクトが実際にあなたの公式パイプラインによってビルドされたものであり、レジストリにアクセスした他の誰かによってビルドされたものではないことを証明します。これは、複数のチームが同じレジストリを共有している場合や、アーティファクトが外部ソースからプルされる場合に重要です。

セーフティネット

これらの4つの規律は、セーフティネットとして連携します。

  • 1回のビルドで環境間の一貫性を確保します。
  • 自動バージョン管理でソースコードへのトレーサビリティを確保します。
  • 中央レジストリですべてのコンシューマーがアクセスできるようにします。
  • 再ビルドなしのプロモーションで再現性を確保します。
  • 検証でアーティファクトの整合性に対する信頼を確保します。

これらのいずれかが弱い場合、パイプラインに穴があります。紙の上では美しいCI/CDセットアップを持っているかもしれませんが、実際には、テストで捕捉されなかった本番インシデントから再ビルド1つ分の距離にいます。

パイプラインのためのクイックチェックリスト

アーティファクト管理を設定またはレビューする場合は、以下を確認してください。

  • パイプラインはコミットごとに各アーティファクトを正確に1回だけビルドしますか?
  • すべてのアーティファクトに自動化された追跡可能なバージョン識別子がありますか?
  • アーティファクトはビルド直後に中央レジストリにプッシュされますか?
  • パイプラインは再ビルドではなくメタデータを変更することでアーティファクトをプロモートしますか?
  • 本番プロモーションの前にチェックサムまたは署名の検証が実行されますか?

これらのいずれかに「いいえ」と答えた場合、次のリリースの前に修正する価値のあるギャップがあります。

チームにとっての意味

チームがこれらの規律を一貫して守ると、パイプラインは予測可能になります。本番環境がテストに合格したのと同じコードを実行しているかどうか疑問に思うことはなくなります。ビルド間の違いを探し回ることもなくなります。デプロイプロセスを信頼し始めます。

そして、その信頼が確立されると、次のレイヤーに集中できます。アーティファクトが環境間をどのように流れるか、誰がプロモートする権限を持つか、ポリシーがどのように自動的に適用されるか。しかし、アーティファクト自体を信頼できなければ、それらはすべて無意味です。1回ビルドする。再ビルドせずにプロモートする。デプロイ前に検証する。他のすべてはその基盤の上に構築されます。