ビルド成果物の置き場所:すべてのアーティファクトにホームが必要な理由
こんな状況を想像してみてください。CIパイプラインがグリーンになりました。ある開発者が「ステージングにデプロイするビルドはどれ?」と尋ねます。誰かが「昨日の実行結果のやつだと思う」と答え、別の人が「いや、今朝ローカルでリビルドした。俺のを使え」と割って入ります。
このような会話は、チームが認めたがる以上に頻繁に発生します。アーティファクトがラップトップ、CIのワークスペースフォルダ、誰かの共有ドライブに散らばっていると、実際にデプロイ可能な状態のものを一貫して把握する能力を失います。ステージングにはあるバージョン、本番には別のバージョンがデプロイされ、午前2時のインシデントの原因となったアーティファクトを誰も追跡できなくなります。
解決策は概念としてはシンプルですが、実践上は極めて重要です。すべてのビルド結果を格納する単一の集中管理された場所が必要です。DevOpsの用語では、その場所をレジストリまたはリポジトリマネージャと呼びます。
アーティファクトにはさまざまな種類がある
まず、よく知られているタイプのアーティファクトから始めましょう。JARファイル、ZIPアーカイブ、コンパイル済みバイナリ、NuGetパッケージなどです。これらは単一ファイルのアーティファクトです。Nexus、Artifactory、または各言語エコシステムの組み込みパッケージレジストリ(npm registry、Maven Central、PyPIなど)がこれらを適切に処理します。これらのツールはファイルを保存し、バージョンを追跡し、パイプラインや開発者が正確な依存関係をプルできるようにします。
次にコンテナイメージを考えてみましょう。コンテナイメージは単一のファイルではありません。複数のレイヤーが積み重なって構成されています。通常のアーティファクトリポジトリにコンテナイメージを保存することはできません。コンテナレジストリ(Docker Hub、Amazon ECR、Google Container Registry、Harborなど)が必要です。コンテナレジストリはレイヤー構造を理解しています。イメージをプルするとき、レジストリはターゲットマシンにまだ存在しないレイヤーのみを送信します。これによりデプロイが高速化され、帯域幅を節約できます。
コンテナイメージは、現代のCI/CDパイプラインで最も一般的なアーティファクトタイプになりました。しかし、原則はフォーマットに関係なく同じです。レジストリは、ビルドとテストに合格したすべてのアーティファクトの信頼できる唯一の情報源(シングルソースオブトゥルース)です。
レジストリはCIとCDの間のハンドオフポイント
パイプラインにおけるレジストリの最も重要な機能は、継続的インテグレーション(CI)と継続的デリバリー(CD)の境界を示すことです。
次の図は、正しいフローと、レジストリがない場合の壊れたフローを対比しています。
フローを見てください。CIの役割は、アーティファクトが明確なバージョンタグとともにレジストリに格納された時点で終了します。ビルドは完了し、テストはパスし、アーティファクトは保存されました。CIの責任はそこで終わりです。
CDはレジストリから始まります。CDはアーティファクトを再ビルドしません。CIが保存したまったく同じアーティファクトをプルし、それをターゲット環境にデプロイします。再コンパイルはありません。異なる依存関係はありません。「これと同じビルドだと思う」という推測もありません。
この分離は技術的な問題だけではありません。所有権の問題です。CIはビルドの正確性を担当し、CDはデプロイの正確性を担当します。本番で何かが壊れた場合、レジストリ内の正確なアーティファクトまでトレースバックします。そのバージョン、コミットハッシュ、ビルドタイムスタンプがわかります。推測は不要です。
変更を加えないプロモーション
優れたレジストリは、アーティファクトのプロモーションも可能にします。プロモーションとは、特定のアーティファクトを次の環境に準備完了としてマークするプロセスです。アーティファクト自体は変更しません。メタデータを追加するだけです。
例えば、CIが 1.2.3-build.45 というタグの付いたアーティファクトを生成したとします。そのアーティファクトはレジストリに置かれます。ステージングテストに合格すると、staging タグを追加します。本番検証に合格すると、さらに production タグを追加します。基盤となるアーティファクトは同一です。ステータスのみが変更されます。
これは、クリーンな監査証跡を維持するために重要です。どのバージョンがいつどの環境にプロモーションされたかを常に確認できます。このメカニズムがないと、チームは環境ごとに再ビルドすることになり、テストされたものと本番で実行されているものの間に微妙な違いが生じます。
レジストリがないとどうなるか
適切なレジストリのセットアップを怠ったチームは、繰り返し同じ問題に直面します。
- 開発者がどのビルドをデプロイすべきか互いに尋ね合う。
- ステージングと本番で異なるバージョンが実行される。
- ロールバックが推測作業になる。なぜなら、以前実際に何が実行されていたのか誰も知らないから。
- セキュリティスキャンが一部のビルドにしか実行されない。なぜなら、一元管理されたインベントリがないから。
- コンプライアンス監査が、6か月前に何がデプロイされたかを再構築するための手動のメールチェーンと化す。
レジストリはこれらすべてを排除します。それは贅沢品ではありません。規律あるパイプラインを可能にする基盤です。
レジストリセットアップの実践的チェックリスト
初めてレジストリをセットアップする場合、または現在のセットアップを見直す場合の短いチェックリストです。
- 適切なタイプを選択する:イメージにはコンテナレジストリ、バイナリやパッケージにはアーティファクトリポジトリ。HarborやArtifactoryのように両方を処理できるツールもあります。
- イミュータビリティ(不変性)を強制する:バージョンタグを付けてアーティファクトを保存したら、上書きを許可しないでください。新しいビルドには新しいバージョンを割り当てます。
- 保持ポリシーを設定する:すべてのビルドを永久に保存する必要はありません。最新のNビルド、または過去M日間のビルドを保持し、残りはアーカイブまたは削除します。
- アクセスを制御する:パイプラインには書き込みアクセスを、開発者とCDパイプラインには読み取りアクセスを付与します。共有パスワードではなく、IAMロールまたはトークンを使用します。
- プロモーションを明示的にタグ付けする:メタデータまたはタグを使用して、ステージング、本番、ロールバック中のアーティファクトをマークします。これをCDパイプラインで自動化します。
具体的な要点
レジストリは単なるストレージではありません。ビルドプロセスとデプロイプロセスの間の契約です。ビルドされたものがそのままデプロイされることを保証します。問題が発生したときにチームが確認する単一の場所を提供します。プロモーションをトレーサブルにし、ロールバックを信頼性のあるものにします。
次のデプロイの前に、レジストリをセットアップしてください。真夜中にインシデントのデバッグをしている未来の自分が、感謝することでしょう。