Cloud Buildさわって、気づきを書いてみます。
複数プロジェクトをまたいでPipelineを組む際の権限設定
前提となる構成
GKE上にアプリケーションをデプロイする
Source code repositoryとCloud BuildをホストするCICDプロジェクトと、アプリケーションをホストするプロジェクト(本番、開発、ステージングなど複数環境があることを想定)が存在する
結論
各プロジェクト、各サービスアカウントで適切なRole設定する必要がある
CICDプロジェクト
Cloud Buildのサービスアカウントに必要な権限
Cloud BuildのTrigger実行権限
GCRにImageをPushする権限
GKEのEndpointに対してkubectl applyを実行する権限
アプリケーションをホストするプロジェクト
GKEのワーカーノードのサービスアカウントに必要な権限
GCRからImageをPullしてくる権限
https://cloud.google.com/container-registry/docs/access-control#permissions_and_roles
上記を図にすると以下になります。
注意点としてTriggerは、Cloud Buildのデフォルトのサービスアカウントである必要があります。
ただし、各Build Stepは任意のサービスアカウントが指定可能で、Stepごとに最小権限を付与すべきという観点で、任意のサービスアカウントを使うほうが好ましいです。
https://cloud.google.com/cloud-build/docs/securing-builds/configure-user-specified-service-accounts
以下のようにStepごとにサービスアカウントが定義できます。
steps:
- name: 'bash'
args: ['echo', 'Hello world!']
logsBucket: 'LOGS_BUCKET_LOCATION'
serviceAccount: 'projects/PROJECT_NAME/serviceAccounts/SERVICE_ACCOUNT'
任意のバージョンを連携する方法
いくつかやり方があると思いますが、git tagを使った例を記載します。
詳細は、以下のチュートリアルを参照してください。
https://cloud.google.com/kubernetes-engine/docs/tutorials/gitops-cloud-build
git tagしてPushすると、デフォルト変数の$TAG_NAMEにTAG情報が格納されます。
使用可能な環境変数は以下のマニュアルに記載があります。
https://cloud.google.com/cloud-build/docs/configuring-builds/substitute-variable-values#using_default_substitutions
$ git tag -a 1.0.3 -m 'test'
$ git push google 1.0.3
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 148 bytes | 148.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To https://source.developers.google.com/p/xxx/r/hello-cloudbuild-app
* [new tag] 1.0.3 -> 1.0.3
バージョンをContainer imageのタグとして使用する方法
git tagで指定したタグ名が、デフォルト変数の$TAG_NAMEに格納されるので、cloudbuild.yamlのbuildステップでタグを指定します。
# This step builds the container image.
- name: 'gcr.io/cloud-builders/docker'
id: Build
args:
- 'build'
- '-t'
- 'gcr.io/$PROJECT_ID/hello-cloudbuild:${TAG_NAME}'
- '.'
GKEにデプロイする際のバージョンの指定方法
パターン1
sedなどを使ってkubernetesのマニフェストファイルを置換する方法が可能です。
# This step generates the new manifest
- name: 'gcr.io/cloud-builders/gcloud'
id: Generate manifest
entrypoint: /bin/bash
args:
- '-c'
- |
sed "s/GOOGLE_CLOUD_PROJECT/${PROJECT_Id}/g" kubernetes.yaml.tpl | \
sed "s/COMMIT_SHA/${TAG_NAME}/g" > kubernetes.yaml;
# This step deploys the new version of our container image
# in the hello-cloudbuild Kubernetes Engine cluster.
- name: 'gcr.io/cloud-builders/kubectl'
id: Deploy
args:
- 'apply'
- '-f'
- 'kubernetes.yaml'
- 'CLOUDSDK_COMPUTE_ZONE=asia-northeast1-a'
- 'CLOUDSDK_CONTAINER_CLUSTER=cluster-1'
- 'CLOUDSDK_CORE_PROJECT=xxx'
パターン2
イメージのタグを直接指定することも可能です。
name: 'gcr.io/cloud-builders/kubectl'
args:
- 'set'
- 'image'
- 'deployment/hello-cloudbuild'
- 'hello-cloudbuild=gcr.io/$PROJECT_ID/hello-cloudbuild:${TAG_NAME}''
Cloud Buildの変数の文字操作
以下のBashの機能が使えます。
https://cloud.google.com/cloud-build/docs/configuring-builds/use-bash-and-bindings-in-substitutions#bash-style_string_operations
$ git tag -a prd-1.0.6 -m 'test'
$ git push google prd-1.0.6
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 4 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 433 bytes | 433.00 KiB/s, done.
Total 4 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2)
To https://source.developers.google.com/p/xxx/r/hello-cloudbuild-app
* [new tag] prd-1.0.6 -> prd-1.0.6
以下は、変数の先頭から4文字を削除しています。(${TAG:4})
# This step generates the new manifest
- name: 'gcr.io/cloud-builders/gcloud'
id: Generate manifest
entrypoint: /bin/bash
args:
- '-c'
- |
echo "tag name is ${TAG_NAME}";
TAG=${TAG_NAME};
echo "tag is ${TAG:4}";
sed "s/GOOGLE_CLOUD_PROJECT/${PROJECT_Id}/g" kubernetes.yaml.tpl | \
sed "s/COMMIT_SHA/${TAG:4}/g" > kubernetes.yaml;
先頭4文字が削除されました。
Step #3 - "Generate manifest": tag name is prd-1.0.6
Step #3 - "Generate manifest": tag is 1.0.6
本番環境へのデプロイは、先頭にprd-を付与されたTAGがPushされると起動するTriggerを作成します。実際のデプロイでしているコンテナイメージのTAGは、上記のようにバージョンを文字列操作で取り出すといった事が可能になります。
デフォルト変数とユーザー定義変数に bash 形式の文字列操作を適用できます。
と書いてるけど、デフォルト変数は置換できなかった。。
echo "tag name is ${TAG_NAME}";
TAG=${TAG_NAME};
echo "tag is ${TAG:4}";
echo ${TAG_NAME:4}
sed "s/GOOGLE_CLOUD_PROJECT/${PROJECT_Id}/g" kubernetes.yaml.tpl | \
sed "s/COMMIT_SHA/${TAG_NAME}/g" > kubernetes.yaml;
cat kubernetes.yaml
ログの4行目のように変数の値が削除される。
Step #3 - "Generate manifest": Already have image (with digest): gcr.io/cloud-builders/gcloud
Step #3 - "Generate manifest": tag name is prd-1.0.7
Step #3 - "Generate manifest": tag is 1.0.7
Step #3 - "Generate manifest":
Step #3 - "Generate manifest": # Copyright 2018 Google LLC
yamlファイルをどこまで分けるか?
アプリと同じレポジトリで管理するパターンとアプリと別のレポジトリでマニフェストファイルをまとめて1つのレポジトリで管理するパターンがありますが、
完全に個人の感想ですが、アプリと同じレポジトリで管理するパターンは、マイクロサービス的に向いていて、別に管理するパターンは、一元管理できるのでアプリとインフラ担当に分かれている組織、gitopsなどに向いている。
また、Pipelineの観点だとデプロイ自体は、docker buildが不要なのでマニフェストファイルのみで完結できるので、分けてると、tagを使ってデプロイ先を切り替えるのがより簡単に実装できそう。