🛠️

GitOpsの効率化:commit追跡を簡単にするアイデア集

2024/12/24に公開

本記事は、CyberAgent Group SRE Advent Calendar 2024の24日目の記事になります。

こんにちは、ふじを (@ffjlabo)といいます。

普段はPipeCDというOSSの開発を行っています。
PipeCDは「One CD for All」というビジョンを掲げたGitOpsライクなCDツールです。
Kubernetes、AWS ECS、Cloud Runといった様々なPlatformに対応しています。
https://pipecd.dev/

直近ではプラグイン機構の開発に取り組んでおり、日々奮闘中です。ご興味ある方がいらっしゃいましたら以下の記事を御覧ください。
https://zenn.dev/cadp/articles/pipecd-plugin-intro

今回はPipeCDの開発の中で試行錯誤した内容の一部を記事にしてみました。


GitOpsを実践する上で、アプリケーションコードのcommitを追跡することは重要な課題です。特にインシデント発生時やロールバックが必要な場合、問題のあるコミットを素早く特定することが求められます。本記事では、この課題を解決するための実践的なアプローチを紹介します。

今日話すこと

  • GitOpsで「アプリケーションコードリポジトリ」と「マニフェストリポジトリ」を紐づけることで、アプリケーションコードのcommitまでサクッと辿れるようになるよというお話をします。

前提:対象構成

「アプリケーションコード」と「マニフェストファイル(インフラ構成ファイル)」をそれぞれ別のrepoとして運用している場合を想定してこの記事を書いています。

具体的には以下のような環境を想定しています。

とはいえ、モノレポですべて管理している開発者の方などにも参考になるとは思いますのでぜひご一読ください。

GitOpsのRollbackにおける課題

ズバリ、 「Rollbackする必要があるcommitを見つけるのに時間がかかる。」 だと考えています。

まずは先ほどの例として上げた構成で、DeployからRollbackの流れを見ていきましょう。

アプリケーションをDeployする

新しい機能のリリースに向け、順次開発を進めているとします。

GitOpsのフローとして、以下の流れでデプロイが進むでしょう。

  1. アプリケーションコードを修正
  2. CI上で新しいイメージを作成
  3. マニフェストファイルのimageタグを更新
  4. CDツールがデプロイ

インシデント発生! アプリケーションをRollbackする

いざリリースしてみると、不具合があることがわかりました。

manifestへの修正をrevertしつつ、アプリケーションコードのどの修正かを確認していきます。

この時、アプリケーションコード自体をRollbackするには大まかに以下の3ステップになりそうです。

  1. manifest repoの修正から該当imageを突き止める
  2. imageの作成元のソースコードcommitを突き止める
  3. ソースコード上の該当commitをrevertする

このような環境では、アプリケーションコードのリポジトリとマニフェストのリポジトリが分かれているため、問題が発生した際に原因となったcommitを特定するのが難しいです。

このプロセスを効率的に行うためには、リポジトリ間の紐付けが有効です。

今回はその方法を2パターンに分けて4つご紹介します。

Pattern 1: コンテナイメージに情報を紐づける

[1] コンテナイメージのタグ名にcommit hashを追加する

docker build -t microserviceA:0123456789abcdefg

CI側でコンテナイメージを作る際に、タグにアプリケーションコードのcommit hashを入れ込むパターンです。割とよく見かけるやり方かと思います。

[2] コンテナイメージのlabelを利用する

コンテナイメージはラベルをつけることができます。

この機能を使って、作成されたコンテナイメージになんらかのメタデータを付与する事ができます。

Dockerfile↓

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL revision="0123456789abcdefg"
LABEL description="This text illustrates \\
that label-values can span multiple lines."

Dockerfile reference

特にOCI のspecには、定義済みのannotationとしていくつかLABELが定義されています。

ref: https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys

  • org.opencontainers.image.url URL to find more information on the image (string)
  • org.opencontainers.image.documentation URL to get documentation on the image (string)
  • org.opencontainers.image.source URL to get source code for building the image (string)
  • org.opencontainers.image.version version of the packaged software
  • org.opencontainers.image.revision Source control revision identifier for the packaged software.

今回だと、org.opencontainers.image.source、org.opencontainers.image.revision を付与することで、「アプリケーションrepoとコンテナイメージの紐づけ」をすることができます。

LABEL org.opencontainers.image.source="<https://github.com/pipe-cd/pipecd>"
LABEL org.opencontainers.image.revision="0123456789abcdefg"

Pattern 2. Manifest repoのcommitに情報を紐づける

[1] commit messageに情報を追加する

メッセージに情報を埋め込むパターンです。
特定のフォーマットを決めて必要な情報を埋め込むことイメージです。

git commit -m "[0123456789abcdefg] Test commit"

[2] commit bodyにTrailerを追加する

gitにはTrailerという機能があります。

commit時に、commit bodyにkey: value の形でメタデータを追加する機能です。

ref: https://github.com/git/git/blob/master/Documentation/RelNotes/2.32.0.txt#L55

git commit -m "Test commit" --trailer "Fixed-by=fujiwo" --trailer "Co-authored-by=GitHub Copilot"
% git show                                                                                                  (git)-[main]
commit a4e9512970826960398ccc8859e1f6d32161fb20 (HEAD -> main)
Author: fujiwo <ffjlabo@gmail.com>
Date:   Wed Dec 4 14:05:33 2024 +0900

    Test commit

    Fixed-by: fujiwo
    Co-authored-by: GitHub Copilot

% git log -1 --pretty="format:%(trailers)"                                                            (git)-[main]
Fixed-by: fujiwo
Co-authored-by: GitHub Copilot

この機能を利用し、マニフェストリポジトリへのcommit時に「アプリケーションコードのリポジトリURL」と「commit hash」を追加することで、紐づけを行います。

git commit -m "Test commit" --trailer "Source-code=https://github.com/dp/microserviceA" --trailer "Commit-hash=0123456789abcdefg"

PipeCDでの応用事例

PipeCDでも同様の課題に直面し、ユーザーからの要望を受けて対応を行いました。

https://github.com/pipe-cd/pipecd/issues/5028

採用した解決策

「Pattern 2の[2] commit bodyにTrailerを追加する方法」を以下の理由で採用しました:

  • コンテナイメージのラベル確認にはイメージのpullが必要だった
  • 複数の情報(commit hash、リポジトリURL等)を紐付ける必要があった

Event Watcher機能での実装

PipeCDのEvent Watcher機能を活用して実装を行いました。この機能は以下のように動作します:

  • アプリケーションコード側のCIでイメージが作成されると、PipeCDに通知
  • PipeCDがイベントを検知し、対応するマニフェストを更新するcommitを作成

[イメージ図]

これにより、CIとCDの責務を分離したCD/CDパイプラインが構築できます。
詳細にご興味ある方は、以下のdocsを確認ください。
Connect between CI and CD with event watcher

今回は、Event Watcherがマニフェストリポジトリへのcommit時に、イベント情報に含まれるアプリケーションコードの情報をTrailerとして追加してみました。

具体的には、pipectl というcliツールを用いてイベント登録をする際に、--context オプションで任意の値を設定します。
すると、PipeCDがそれらをTrailerとしてマニフェストリポジトリへcommitしてくれます。

pipectl event register --address=xxx --api-key=xxx --name=simple --data="gcr.io/pipecd/helloworld:v0.49.0" --contexts=Source-Commit-Hash= 6512b1f3fcba7342c11cf96968e753c78e66561b,Source-URL=https://github.com/pipe-cd/pipecd/commit/6512b1f3fcba7342c11cf96968e753c78e66561b,PipeCD-Official-Docs=https://pipecd.dev/


https://github.com/pipe-cd/pipecd/pull/5295#issuecomment-2443121932

commitへのリンクをbodyに埋め込んでおくと、マニフェストリポジトリからアプリケーションコードのcommitページへ飛べるので便利です。

デプロイのトレーサビリティについて

少し話は逸れますが、Rollbackの問題も本質的には「ユーザの変更がデプロイされるまでのステップが確認しづらい」という問題につながるのかなと思っています。
なので、今回のcommitに情報を付与するのは、あくまで一つの手段です。

PipeCDチームでは現在アプリケーションコードを修正からデプロイが走るまでのフローを一元的に確認できるようなデプロイのトレーサビリティを向上させる方法を模索中です。

ご興味ある方はぜひissueが作られているので、コメントなどいただけると嬉しいです。
https://github.com/pipe-cd/pipecd/issues/5444

まとめ

アプリケーションコードとマニフェストファイルのリポジトリが別れている環境でのGitOpsについて、Rollback対象のcommitを探すために以下の方法を紹介しました。

Pattern 1: コンテナイメージに情報を紐づける
[1] コンテナイメージのタグ名にcommit hashを追加する
[2] コンテナイメージのlabelを利用する

Pattern 2. Manifest repoのcommitに情報を紐づける
[1] commit messageに情報を追加する
[2] commit bodyにTrailerを追加する

なんらかの参考になれば幸いです。

サイバーエージェント Developer Productivity室

Discussion