特に、インフラ関連のサービスは比較的小さな単位で複数作成される傾向にあるので、そのサービス1つ1つにリポジトリを作っていくのはあまり現実的ではないし、管理が煩雑になる。なので、モノレポが適していると思う。
ここで問題となるのはどのようにCI/CDパイプラインを組むかということ。業務で使用する上で自分なりの案が出せたので1つのサンプルを本記事では紹介する。
プロジェクト構成
ソースコードの管理にGithub、CI/CDパイプライン構築にCloud Build、Cloud Functions等で作成された複数のマイクロサービスが存在するとする。例えば想定するディレクトリ構造は以下の通り
- project-root-dir
- micro-service-one
- src
- cloudbuld.yaml
- micro-service-two
- src
- cloudbuld.yaml
- micro-service-three
- src
- cloudbuld.yaml
- micro-service-one
- cloudbuld.yaml
- README.md
CI/CDパイプライン構築
すでにお気づきだとは思うが、上記のディレクトリにはcloudbuild.yamlが複数存在する。順序としては、まずCloud Buildのトリガーを作成(developに対してfeatureがマージされたら等)しトリガーが実行されたら、プロジェクトルートのcloudbuild.yamlが走るようにしておく。
これに関しては、デフォルトでルートのyamlを見るようになっているので特に何か設定をしないといけないというわけではないので、確認だけしておく
プロジェクトルートのcloudbuild.yamlの役割は、「gitで差分のあるファイルからそのディレクトリを特定し、該当のディレクトリに存在するcloudbuild.yamlを使ってトリガーを実行する」という内容。
これによって、ソースコードに変更のあったサービスのみをデプロイするということが実現できるようになる。
プロジェクトルートのcloudbuild.yaml
全体像
大きくは2ステップに分かれる
steps:
- name: 'gcr.io/cloud-builders/git'
entrypoint: /bin/bash
args:
- -c
- |
git fetch --depth=2 origin main
git log
git --no-pager diff --name-only HEAD^ HEAD | grep "/" | cut -d/ -f1 | sort | uniq > /workspace/diff.txt
- name: 'gcr.io/cloud-builders/gcloud'
entrypoint: /bin/bash
args:
- -c
- |
while read line
do
config="${line}/cloudbuild.yaml"
echo $config
if [[ ! -f "${config}" ]]; then
echo "no such file"
continue
fi
gcloud builds submit $line --config=${config}
done < /workspace/diff.txt
ポイント
ステップ1
まず、Gitビルダーを使用して、git diffを行い、変更のあったディレクトリ名のみを抽出してテキストファイルに書き出す。例えば、micro-service-two内のsrcに対して変更があれば、micro-service-twoというディレクトリ名が書き出されることになる。
steps:
- name: 'gcr.io/cloud-builders/git'
entrypoint: /bin/bash
args:
- -c
- |
git fetch --depth=2 origin main
git --no-pager diff --name-only HEAD^ HEAD | grep "/" | cut -d/ -f1 | sort | uniq > /workspace/diff.txt
リモートのmainブランチを取得(最新のコミットから2つのコミットの履歴のみを取得しローカルリポジトリに反映)
↓
最新のコミット (HEAD) とその前のコミット (HEAD^) の間の差分情報を取得。--name-only オプションを使用して、差分されたファイルの名前のみを表示
↓
`grep "/"` を使用して、ディレクトリ階層があるファイルのみをフィルタリング。`cut -d/ -f1` を使用して、ファイルパスの最初のセグメント (ディレクトリ名) を抽出
↓
`sort` を使用して、ディレクトリ名をアルファベット順にソート。`uniq` を使用して、重複したディレクトリ名を削除。最後にテキストに書き出す
ステップ2
次に、書き出したテキストファイルを読み取り、ディレクトリ名を取得。例えばmicro-service-twoというディレクトリ内のソースコードに変更があった場合はmicro-service-two/cloudbuild.yamlということになり、これが存在していればそのディレクトリにあるソースはgcloud builds submitによりビルド処理が実行される
steps:
# ・・・割愛・・・
- name: 'gcr.io/cloud-builders/gcloud'
entrypoint: /bin/bash
args:
- -c
- |
while read line
do
config="${line}/cloudbuild.yaml"
echo $config
if [[ ! -f "${config}" ]]; then
echo "no such file"
continue
fi
gcloud builds submit $line --config=${config}
done < /workspace/diff.txt
各サービス内のyamlファイルは以下の通り。これはデプロイしたいサービスの内容により異なるが、今回はCloud Functionsとしている
micro-service-two/bloudbuild.yaml
steps:
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
args:
- gcloud
- functions
- deploy
# デプロイするfunction名
- sample_func
- --region=asia-northeast1
# 関数のソースコードの場所
- --source=.
# ソースコード内に存在する関数名または完全修飾クラス名
- --entry-point=main
まとめ
いかがでしたでしょうか。本記事では、GCPのインフラのマイクロサービスをモノレポ構成でCI/CD環境を構築する方法について紹介しました。ぜひ参考にしてみて下さい。