CI/CD の図を頼むと、たいていはビルド、テスト、デプロイの箱が一列に並んだものが出てきます。間違いではありませんが、図を見る人が抱く疑問にはほとんど答えていません。具体的に何がデプロイされるのか? 誰が本番に変更を反映できるのか? 承認はどこにあるのか? どうやってロールバックし、その必要があることを何で判断するのか?
このガイドでは、こうした疑問に答える CI/CD パイプライン図の描き方を、よくある構成を例に説明します。GitHub 形式のプルリクエスト、コンテナレジストリ、そして Argo CD による Kubernetes への GitOps デプロイという構成です。ルールはほかのツールにもそのまま当てはまります。
パイプライン図に描くべきもの
- トリガー。 各部分を何が起動するか。プルリクエスト、main へのマージ、タグ、スケジュールなどです。
- ステージとその順序。 lint、テスト、ビルド、スキャン、デプロイ、検証。
- 成果物。 ステージ間で受け渡されるもので、通常はコンテナイメージです。それをどう識別するかも示しましょう。タグ、できればダイジェストで識別します。
- 環境。 成果物がどこで動き、どの順序でそこに届くか。
- ゲート。 変更を止める手動承認、必須チェック、ポリシー。
- 認証情報。 どのシステムがどの環境を変更できるか。
- フィードバック。 本番のシグナルが、問題のあるリリースをどう止め、どうロールバックするか。
ステージの列で表せるのは最初の 2 つだけです。インシデントや監査が起きるのは、それ以外の部分です。
例: Kubernetes への GitOps
- 開発者がアプリケーションリポジトリでプルリクエストを作成します。
- CI はプッシュのたびに実行され、lint、ユニットテスト、イメージのビルド、イメージのスキャンを行います。main にマージされると、イメージをレジストリにプッシュし、そのダイジェストを記録します。
- 次に CI は、新しいイメージのダイジェストを、別の設定リポジトリにあるステージング用オーバーレイにコミットします。
- ステージングクラスターの Argo CD がそのコミットを検知し、設定を取得してクラスターを同期します。
- 昇格させるときは、誰かがその参照を本番用オーバーレイにコピーするプルリクエストを作成します。必須のレビューが承認ゲートになります。
- マージ後、本番の Argo CD が同期し、クラスター内の別のコントローラーである Argo Rollouts が新しいバージョンをカナリアとしてリリースします。まずトラフィックの一部だけを流し、その後すべてを流します。
- カナリアの間、Argo Rollouts は Prometheus のメトリクスを使って分析を実行します。分析が失敗するとロールアウトは中止されてトラフィックが安定版に戻り、アラートがオンコールのエンジニアを呼び出します。
ダイアグラムの内容
- Developer
- app repo
- CI: lint, test, build, scan
- Image registry
- config repo (GitOps)
- staging
- Argo CD
- staging cluster
- approve
- production
- Argo CD + Argo Rollouts
- production cluster
- Prometheus
- SLO alert
- On-call
- pull request
- on push
- image, by digest
- write image digest
- pull & sync
- apply
- PR: promote
- merge, pull & sync
- canary
- metrics
- failed check stops the canary
- SLO burn
- page
この図には、見落としやすいものの非常に重要な点が 2 つあります。CI はクラスターと一切やり取りしません。イメージをレジストリにプッシュし、Git にコミットするだけです。そして本番は、レビュー済みのコミットを通じてしか変わりません。これはロールバックの方法でもあります。コミットを revert すれば、Argo CD が以前のバージョンを同期します。
プッシュかプルか: 認証情報の置き場所を描く
プッシュ型のパイプラインでは、CI がクラスターの認証情報を持ち、デプロイコマンドを自分で実行します。プル型の GitOps 構成では、各クラスター内のエージェント(Argo CD や Flux など)が Git から望ましい状態を取得して適用するため、クラスターの外にあるものがクラスターへの書き込み権限を持つ必要はありません。
どちらも妥当な選択ですが、図ではどちらを選んだかがはっきりわかるようにします。プッシュ型なら、CI から各クラスターへエッジを描き、使用する認証情報をラベルとして付けます。プル型なら、設定リポジトリから各クラスター内のエージェントへ設定が流れる様子を描き、CI からクラスターへのエッジは 1 本も描きません。そうすればレビュアーは、CI のシークレットが漏洩した場合の影響範囲をひと目で把握できます。
CI がクラウドへのアクセスを必要とする場合(たとえばイメージのプッシュ)、そのアクセスをどう得ているかを書き添えます。図の上では、シークレットとして保存した長期有効なキーよりも、OpenID Connect で取得する短命なトークンのほうがずっと筋の良い構成に見えます。
読みやすいパイプライン図のルール
成果物を見えるようにする
レジストリに入るエッジに、成果物とその識別方法をラベルとして付けます。たとえば image shop-api, by digest です。タグは付け替えられますが、ダイジェストは常に同じイメージを指します。SBOM や署名も生成しているなら、イメージの横に示しましょう。
環境はフレームとして描く
各環境は、デプロイエージェントとクラスターを中に収めたフレームです。フレームの並び順が昇格の経路を示し、フレームを飛ばすものがあればすぐに目立ちます。
ゲートには専用のノードを使う
承認は矢印に付けたラベルではなく、担当者のいるステップです。環境と環境の間にノードとして描き、誰が承認するかを書きます。たとえば approve: release manager や 2 reviews required です。
ループを閉じる
「デプロイ」で終わるパイプラインにはフィードバックがありません。本番を何が監視し、それが何をできるのかを描きます。カナリアを止める、担当者を呼び出す、ロールバックを開始する、といったことです。
ジョブの詳細は CI ファイルに残す
12 個の並列テストジョブは CI の設定に書くものです。図では、短いラベル(lint, test, build, scan)を付けたステージのノードが 1 つあれば十分です。
よくある間違い
- 成果物がない。 箱が矢印でつながっているだけで、矢印は特に何も運んでいません。読み手には何が昇格されるのかわかりません。
- 環境をステージとして描く。 「ステージングにデプロイ」と「本番にデプロイ」を 2 つの箱として並べると、それぞれ権限の異なる別の場所であることが見えなくなります。
- ロールバックの経路がない。 図の上で誰も指し示せないなら、おそらくテストもされていません。
- すべてのジョブをノードにする。 図が CI のログになってしまいます。
- 責務ではなくツールを描く。 製品名をラベルにした箱は、
build and scan imageと書いた箱より伝わる情報が少なくなります。
Archboard で作る
- Google または GitHub でサインインし、図を作成します。
- DevOps パックから、アプリケーション用と設定用のリポジトリとしてリポジトリノードを、CI 用にパイプラインを追加します。Docker パックからはレジストリを追加します。
- 環境ごとに基本パックのフレームを追加し、その中に DevOps パックのデプロイノード(Argo CD 用、本番では Argo Rollouts も)とクラウドパックの Kubernetesクラスター を配置します。
- 承認ゲート用に、基本パックからひし形の図形を追加します。
- DevOps パックのメトリクスとアラートのノード、そして開発者とオンコール担当のエンジニア用に C4 モデルパックの人物ノードを追加します。
- ポート同士を接続し、すべてのエッジに何が流れるかをラベルとして付け、フィードバックのエッジを破線にします。
この例で使うノードは 15 個で、Free プランの上限ちょうどです。オブザーバビリティを組み込んだパイプラインについては /examples/cicd-observability を開いてください。クラスター側については Kubernetes アーキテクチャ図の描き方 を参照してください。
よくある質問
CI のジョブはすべて描くべきですか? いいえ。ジョブはステージにまとめ、詳細は CI ファイルに残します。ジョブを個別に描くのは、リリースをブロックするセキュリティスキャンのように、それ自体がゲートになっている場合だけです。
フィーチャーフラグはどう表せばよいですか? 本番の横に別のシステムとして置き、フラグを読み取るサービスへエッジを引きます。フラグはデプロイなしで動作を変えるため、図の上でも独立した線として描く価値があります。
シークレットは図のどこに描けばよいですか? シークレットそのものではなく、どのシステムがどの認証情報を何のために持っているかを示します。CI については、短命な OIDC トークンを使っているのか、保存されたキーを使っているのかを書き添えます。
リポジトリごとに図が必要ですか? 通常は、デリバリーの経路ごとに 1 枚です。多くのサービスが同じパイプラインを共有しているなら、一度だけ描いて、サービスの一覧をメモに書きます。
図を最新の状態に保つにはどうすればよいですか? CI ファイルと同じように、パイプラインが変わったら図もレビューします。リポジトリの README からライブの図にリンクすれば、コピーは 1 つだけで済みます。