Config Controller(Config Sync)でGoogle Cloudブループリントを利用してGitOpsなリソース管理を実現する

記事タイトルとURLをコピーする

G-gen の武井です。

Config Controller (Config Sync) で Google Cloud (旧称 GCP) のブループリントを利用して GitOps なリソース管理を実現するための検証を行いました。当記事ではその方法をご紹介します。

Config Controller (Config Sync)

はじめに

当記事の概要

Config Controller で Google Cloud のブループリントを利用すると以下を実現することができます。

  • GitOps パイプライン のデプロイ
  • GitOps パイプライン を用い、ランディングゾーン を始めとする各種 Google Cloud リソース構成のデプロイ・管理

当記事では実際の検証結果をふまえ分かりやすく解説します。

アーキテクチャ

構成

前述の概要を図示すると以下のとおりです。

構成図

構成要素

各構成要素とそれらが担う役割 (処理) の概要を説明します。なお、GitOps パイプライン とは以下表の #3 ~ #5 から構成される CI/CD パイプラインのことを指します。

# 構成要素 役割
1 GitHub Google Cloud ブループリント (テンプレート) を管理する Git リポジトリ
2 setters ブループリント上の設定値を一元管理する機能
3 source-repo setters を定義したブループリントが格納される Git リポジトリ
4 Cloud Build setters から環境固有のマニフェストをレンダリングする kpt 関数
5 deployment-repo レンダリングされたマニフェストが格納される Git リポジトリ
6 Config Sync Config Controller に GitOps サービスを提供するコンポーネント
7 Config Controller マニフェストにもとづきリソースをデプロイ管理するコンポーネント

一連の処理

setters を定義したブループリントを GitOps パイプラインに push すると、Cloud Build による kpt 関数 (レンダリング) が実行され、各環境固有のマニフェストが自動的に生成されます。

Config Sync はレンダリングされたマニフェストが格納されたリポジトリを定期的に参照します。参照結果は Config Controller に連携され、結果に基づくリソースの管理やデプロイを自動実行します。

前提知識 (用語解説)

Google Cloud ブループリント

Google Cloud には ブループリント と呼ばれる、Google Cloud 上のリソースやサービスの構成を宣言的に管理するためのフレームワークが存在します。

ブループリントには ランディングゾーン (後述) を始め、様々な構成に関するベストプラクティスが提供されており、それらを利用することで、企業や組織は Google Cloud の構成を一貫性のある方法でデプロイ・管理することができます。

ランディングゾーン

ランディングゾーン とは、「クラウド上に新しい環境やワークロードを迅速かつ安全にデプロイするための事前定義された設計パターン」を表す概念 (用語) です。

セキュリティ、運用、ネットワーク設計、アクセス管理など、クラウド基盤を構築する上でのベストプラクティスが考慮された形で設計されており、上記ブループリントの landing-zone ディレクトリ配下にはマニフェストファイル一式が用意されています。

Anthos Config Management

Anthos Config Management は、Google Cloud リソースのプロビジョニングとオーケストレーションを行うサービスです。

Config ControllerConfig SyncPolicy Controller という 3つ のコンポーネントから構成されます。

詳細についてはこちらの記事をご確認ください。
blog.g-gen.co.jp

kpt

kpt とは マニフェストファイルを操作(パッケージ化、pull、更新、変更)するための Google が開発したオープンソースツールです。

今回のケースでは、当ツールを使って Google Cloud のブループリントを取得したり、取得したブループリント (テンプレート) から、適用先環境に合わせたマニフェストファイルを レンダリング (後述) したりします。

レンダリング

前述の通り、Config Controller や kpt の文脈におけるレンダリングとは「雛形となるブループリントから各環境固有のマニフェストファイルを生成する処理のこと」を指しており、その処理の中で kpt の setters (後述) という機能が用いられています。

setters

setters とは、「マニフェストファイル内の特定の値を一元的に管理・更新するための機能」のことで、Linux でいう環境変数の概念と同じです。

Google Cloud のブループリントは様々なプロジェクトや環境で再利用することが想定されます。当機能を利用すれば、ブループリント上の初期値をそれぞれの環境やプロジェクト固有の値 (例: プロジェクト ID やリージョン名) に簡単に更新でき、ブループリントを効率的に利用できます。

関連記事

以下の記事でも Config Controller について解説しています。こちらもあわせてご参照ください。
blog.g-gen.co.jp blog.g-gen.co.jp

事前準備

参考ドキュメント

今回の検証は以下の公式ガイドを参考にして実施しています。

参考:ランディング ゾーンのブループリントをデプロイする

実行環境

本設定では gcloud コマンドの他に、kubectlnomoskpt といったコマンドを利用するため、これらがプリインストールされた Cloud Shell を利用します。

# コマンド
which kubectl nomos kpt
  
# 戻り値
/usr/bin/kubectl
/usr/bin/nomos
/usr/bin/kpt

Project / VPC / Subnet の準備

Config Controller (実体は GKE クラスタ) を作成する Project / VPC / Subent を準備します。

※ 作成方法の解説は割愛します。

# リソース リソース名
1 Project (Project ID) sandbox-cc-test-prj
2 VPC sandbox-cc-test-vpc
3 Subnet sandbox-cc-test-subnet

環境変数と gcloud の設定

Cloud Shell で環境変数と gcloud コマンドのプロジェクト設定を行います。

※ 設定途中で Cloud Shell の接続が切れた場合は再度環境変数を設定してください。

# CONFIG_CONTROLLER_NAME は 25 文字以内
export PROJECT_ID=sandbox-cc-test-prj
export CONFIG_CONTROLLER_NAME=config-controller-1
export BILLING_ACCOUNT=$(gcloud alpha billing projects describe $PROJECT_ID \
  '--format=value(billingAccountName)' | sed 's/.*\///')
export ORG_ID=$(gcloud projects get-ancestors ${PROJECT_ID} --format='get(id)' | tail -1)
  
# gcloud の設定 (向き先となるプロジェクトの指定)
gcloud config set project ${PROJECT_ID}
  
# 戻り値
Updated property [core/project].

Config Controller の設定

API 有効化

Config Controller APIGKE API を有効にします。

# コマンド
gcloud services enable krmapihosting.googleapis.com container.googleapis.com
  
# 戻り値
Operation "operations/acf.p2-566560710327-a294ce1f-f676-4214-9e8e-1340fe0bee36" finished successfully.

Config Controller クラスタの作成

クラスタを以下の条件で作成します。(この操作には時間がかかる場合があります)

  • Autopilot
  • asia-northeast1 (東京リージョン)
  • 事前準備で作成した VPC / Subnet
# コマンド
gcloud anthos config controller create ${CONFIG_CONTROLLER_NAME} \
  --location=asia-northeast1 \
  --network=sandbox-cc-test-vpc \
  --subnet=sandbox-cc-test-subnet \
  --full-management
  
# 戻り値
Create request issued for: [config-controller-1]
Waiting for operation [projects/sandbox-cc-test-prj/locations/asia-northeast1/operations/operation-1692153896333-6030147e571e0-03bfd650-4d82d756] to comple
te...done.                                                                                                                                                 
Created instance [config-controller-1].
Fetching cluster endpoint and auth data.
kubeconfig entry generated for krmapihost-config-controller-1.

クラスタの作成が正常に完了したことを確認します。

# コマンド
gcloud anthos config controller list --location=asia-northeast1
  
# 戻り値
NAME: config-controller-1
LOCATION: asia-northeast1
STATE: RUNNING

Config Controller クラスタの認証

クラスタの認証情報を取得します。

# コマンド
gcloud anthos config controller get-credentials ${CONFIG_CONTROLLER_NAME} \
  --location=asia-northeast1
  
# 戻り値
Fetching cluster endpoint and auth data.
kubeconfig entry generated for krmapihost-config-controller-1.

Config Controller クラスタへの権限付与

クラスタのサービスアカウント (service-PROJECT_NUMBER@gcp-sa-yakima.iam.gserviceaccount.com) に、プロジェクトおよび組織レベルで管理権限を付与します。

# 環境変数設定
export SA_EMAIL="$(kubectl get ConfigConnectorContext -n config-control \
  -o jsonpath='{.items[0].spec.googleServiceAccount}' 2> /dev/null)"
  
# IAM Policy 設定 (プロジェクトレベル)
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
  --member "serviceAccount:${SA_EMAIL}" \
  --role "roles/owner" \
  --project "${PROJECT_ID}"
  
# 戻り値 (一部のみ抜粋)
Updated IAM policy for project [sandbox-cc-test-prj].
bindings:
- members:
  - serviceAccount:service-566560710327@gcp-sa-yakima.iam.gserviceaccount.com
  - user:user@example.co.jp
  role: roles/owner
etag: BwYDAjdY4F0=
version: 1
  
# IAM Policy 設定 (組織レベル)
gcloud organizations add-iam-policy-binding $ORG_ID \
  --role=roles/resourcemanager.organizationAdmin \
  --condition=None \
  --member="serviceAccount:${SA_EMAIL}"
  
# 戻り値 (一部のみ抜粋)
Updated IAM policy for organization [999999999999].
bindings:
- members:
  - serviceAccount:service-566560710327@gcp-sa-yakima.iam.gserviceaccount.com
  role: roles/resourcemanager.organizationAdmin
etag: BwYDAoGjp8Q=
version: 1

GitOps パイプラインの設定

成果物の確認

このプロセスでは以下のリソースで構成される GitOps パイプラインを作成します。

# リソース 役割
1 source-repo ローカルから push されるファイル一式を格納するリポジトリ
2 Build トリガー 上記からレンダリングされたファイルを deployment-repopush
3 deployment-repo レンダリングされたファイル一式を格納するリポジトリ
4 Config Sync deployment-repo に接続する GitOps サービス

API 有効化

Cloud Source Repositories APIResource Manager API を有効にします。

# コマンド
gcloud services enable sourcerepo.googleapis.com cloudresourcemanager.googleapis.com
  
# 戻り値
Operation "operations/acat.p2-566560710327-99c27c46-29ce-4747-a867-eea8ff811998" finished successfully.

GitOps ブループリントのダウンロード

kpt を使用して GitHub から Cloud Shell に GitOps ブループリント をダウンロードして GitOps パイプラインをデプロイします。

バージョンは GitOps ブループリントの GHANGELOG.md から確認できます。

2023年8月時点の最新バージョンは v0.6.1

# 最新の GitOps ブループリントをダウンロード
kpt pkg get https://github.com/GoogleCloudPlatform/blueprints.git/catalog/gitops@gitops-blueprint-v0.6.1 gitops
  
# 戻り値
Package "gitops":
Fetching https://github.com/GoogleCloudPlatform/blueprints@gitops-blueprint-v0.6.1
From https://github.com/GoogleCloudPlatform/blueprints
 * tag               gitops-blueprint-v0.6.1 -> FETCH_HEAD
Adding package "catalog/gitops".
  
Fetched 1 package(s).

Cloud Shell にダウンロードできたことを確認します。

# コマンド
tree gitops/
  
# 戻り値
gitops/
├── CHANGELOG.md
├── cloudbuild-iam.yaml
├── configsync
│   ├── config-management.yaml
│   ├── configsync-iam.yaml
│   ├── Kptfile
│   ├── README.md
│   ├── rootsync.yaml
│   ├── setters.yaml
│   └── validation.yaml
├── hydration-trigger.yaml
├── Kptfile
├── README.md
├── services.yaml
├── setters.yaml
└── source-repositories.yaml

1 directory, 15 files

主要なマニフェストファイルの役割は以下の通りです。

# gitops/ 以下 役割
1 Kptfile kpt の設定ファイル
2 setters.yaml gitops/ 以下の各マニフェストファイルの設定値を一元管理
3 services.yaml パイプラインが使用するサービス API を管理
4 source-repositories.yaml リポジトリ (Cloud Source Repositories, CSR) を管理
5 cloudbuild-iam.yaml Cloud Build サービスアカウントの IAM Policy を管理
6 hydration-trigger.yaml リポジトリ間で行われる処理 (Cloud Build トリガー) を管理
# gitops/configsync 以下 役割
1 configsync-iam.yaml Config Sync と CSR 間の認証 (Workload Identity 方式) を管理
2 rootsync.yaml Config Sync (CSR に対する GitOps サービス) を管理

setters の定義

ダウンロードしたブループリントを setters (セッター) を使って自身の環境向けにカスタマイズします。

setters とは kpt の機能の一つで、マニフェスト内の特定の値を一元的に変更・設定するための役割を提供します。簡単に表すとマニフェスト内の変数を管理するイメージです。

これにより、マニフェスト内の初期値が setters を介して一意の値に置き換えられます。settersgitops/setters.yaml ファイル内で管理されていますので、そちらを編集します。

# 変更前
  
apiVersion: v1
kind: ConfigMap
metadata: # kpt-merge: /setters
  name: setters
  annotations:
    config.kubernetes.io/local-config: "true"
    internal.kpt.dev/upstream-identifier: '|ConfigMap|default|setters'
data:
  # This should be the project where you deployed Config Controller
  project-id: project-id
  project-number: "1234567890123"
  # This should be the name of your Config Controller instance
  cluster-name: cluster-name
  # You can leave these defaults
  namespace: config-control
  deployment-repo: deployment-repo
  source-repo: source-repo
# 変更後、cluster-name / project-id / project-number を環境固有の値に置換
  
apiVersion: v1
kind: ConfigMap
metadata: # kpt-merge: /setters
  name: setters
  annotations:
    config.kubernetes.io/local-config: "true"
    internal.kpt.dev/upstream-identifier: '|ConfigMap|default|setters'
data:
  # This should be the project where you deployed Config Controller
  project-id: sandbox-cc-test-prj
  project-number: "566560710327"
  # This should be the name of your Config Controller instance
  cluster-name: config-controller-1
  # You can leave these defaults
  namespace: config-control
  deployment-repo: deployment-repo
  source-repo: source-repo

レンダリング

定義した setters を使ってブループリントをレンダリングします。

レンダリングとは、setters.yaml で定義した内容にもどづきマニフェストを完成 (カスタマイズ) させる という意味に近しいです。

# コマンド
kpt fn render gitops/
  
# 戻り値
Package "gitops/configsync": 
[RUNNING] "gcr.io/kpt-fn/apply-setters:v0.1"
[PASS] "gcr.io/kpt-fn/apply-setters:v0.1" in 4.1s
  Results:
    [info] spec.clusterName: set field value to "cluster-name"
    [info] metadata.name: set field value to "sync-cluster-name"
    [info] metadata.namespace: set field value to "config-control"
    [info] metadata.annotations.cnrm.cloud.google.com/project-id: set field value to "project-id"
    ...(14 line(s) truncated, use '--truncate-output=false' to disable)
[RUNNING] "gcr.io/kpt-fn/starlark:v0.4"
[PASS] "gcr.io/kpt-fn/starlark:v0.4" in 4.4s

Package "gitops": 
[RUNNING] "gcr.io/kpt-fn/apply-setters:v0.1"
[PASS] "gcr.io/kpt-fn/apply-setters:v0.1" in 300ms
  Results:
    [info] spec.clusterName: set field value to "config-controller-1"
    [info] metadata.name: set field value to "sync-config-controller-1"
    [info] metadata.namespace: set field value to "config-control"
    [info] metadata.annotations.cnrm.cloud.google.com/project-id: set field value to "sandbox-cc-test-prj"
    ...(38 line(s) truncated, use '--truncate-output=false' to disable)

Successfully executed 3 function(s) in 2 package(s).

レンダリング実行後、例えば gitops/source-repositories.yaml を確認すると project-id が定義した値に置換されたことが分かります。

# 変更前
  
apiVersion: sourcerepo.cnrm.cloud.google.com/v1beta1
kind: SourceRepoRepository
metadata: # kpt-merge: config-control/source-repo
  name: source-repo # kpt-set: ${source-repo}
  namespace: config-control # kpt-set: ${namespace}
  annotations:
    cnrm.cloud.google.com/blueprint: cnrm/gitops/v0.6.1,kpt-pkg
    cnrm.cloud.google.com/project-id: project-id # kpt-set: ${project-id}
    internal.kpt.dev/upstream-identifier: 'sourcerepo.cnrm.cloud.google.com|SourceRepoRepository|config-control|source-repo'
---
apiVersion: sourcerepo.cnrm.cloud.google.com/v1beta1
kind: SourceRepoRepository
metadata: # kpt-merge: config-control/deployment-repo
  name: deployment-repo # kpt-set: ${deployment-repo}
  namespace: config-control # kpt-set: ${namespace}
  annotations:
    cnrm.cloud.google.com/blueprint: cnrm/gitops/v0.6.1,kpt-pkg
    cnrm.cloud.google.com/project-id: project-id # kpt-set: ${project-id}
    internal.kpt.dev/upstream-identifier: 'sourcerepo.cnrm.cloud.google.com|SourceRepoRepository|config-control|deployment-repo'
# 変更後
  
apiVersion: sourcerepo.cnrm.cloud.google.com/v1beta1
kind: SourceRepoRepository
metadata: # kpt-merge: config-control/source-repo
  name: source-repo # kpt-set: ${source-repo}
  namespace: config-control # kpt-set: ${namespace}
  annotations:
    cnrm.cloud.google.com/blueprint: cnrm/gitops/v0.6.1,kpt-pkg-fn
    cnrm.cloud.google.com/project-id: sandbox-cc-test-prj # kpt-set: ${project-id}
    internal.kpt.dev/upstream-identifier: 'sourcerepo.cnrm.cloud.google.com|SourceRepoRepository|config-control|source-repo'
---
apiVersion: sourcerepo.cnrm.cloud.google.com/v1beta1
kind: SourceRepoRepository
metadata: # kpt-merge: config-control/deployment-repo
  name: deployment-repo # kpt-set: ${deployment-repo}
  namespace: config-control # kpt-set: ${namespace}
  annotations:
    cnrm.cloud.google.com/blueprint: cnrm/gitops/v0.6.1,kpt-pkg-fn
    cnrm.cloud.google.com/project-id: sandbox-cc-test-prj # kpt-set: ${project-id}
    internal.kpt.dev/upstream-identifier: 'sourcerepo.cnrm.cloud.google.com|SourceRepoRepository|config-control|deployment-repo'

また、gitops/source-repositories.yaml ファイル以外も setters によってレンダリングされており、これらレンダリングされたファイル一式を使って GitOps パイプラインをデプロイします。

GitOps パイプラインのデプロイ

kubectl apply でレンダリングしたファイル一式を適用し、GitOps パイプラインをデプロイします。

# コマンド
kubectl apply --wait -f gitops/ --recursive
  
# 戻り値
iampartialpolicy.iam.cnrm.cloud.google.com/deployment-repo-cloudbuild-write created
iampartialpolicy.iam.cnrm.cloud.google.com/source-repo-cloudbuild-read created
configmanagement.configmanagement.gke.io/config-management configured
iamserviceaccount.iam.cnrm.cloud.google.com/sync-config-controller-1 created
iampartialpolicy.iam.cnrm.cloud.google.com/sync-config-controller-1 created
iampartialpolicy.iam.cnrm.cloud.google.com/source-reader-sync-config-controller-1-sandbox-cc-test-prj created
rootsync.configsync.gke.io/root-sync created
configmap/setters created
cloudbuildtrigger.cloudbuild.cnrm.cloud.google.com/source-repo-cicd-trigger created
service.serviceusage.cnrm.cloud.google.com/sourcerepo.googleapis.com created
service.serviceusage.cnrm.cloud.google.com/cloudbuild.googleapis.com created
configmap/setters configured
sourcereporepository.sourcerepo.cnrm.cloud.google.com/source-repo created
sourcereporepository.sourcerepo.cnrm.cloud.google.com/deployment-repo created
error: resource mapping not found for name: "validate-cluster-name-length" namespace: "" from "gitops/configsync/validation.yaml": no matches for kind "StarlarkRun" in version "fn.kpt.dev/v1alpha1"
ensure CRDs are installed first

リポジトリを作成します。

# コマンド
kubectl wait --for=condition=READY -f gitops/source-repositories.yaml
  
# 戻り値
sourcereporepository.sourcerepo.cnrm.cloud.google.com/source-repo condition met
sourcereporepository.sourcerepo.cnrm.cloud.google.com/deployment-repo condition met

上記実行後、source-repodeployment-repo の 2つのリポジトリが作成されました。

# コマンド
gcloud source repos list
  
# 戻り値
REPO_NAME: deployment-repo
PROJECT_ID: sandbox-cc-test-prj
URL: https://source.developers.google.com/p/sandbox-cc-test-prj/r/deployment-repo
  
REPO_NAME: source-repo
PROJECT_ID: sandbox-cc-test-prj
URL: https://source.developers.google.com/p/sandbox-cc-test-prj/r/source-repo

source-repo と deployment-repo の 2つのリポジトリが作成

また、以下のコマンドで Build トリガーと Config Sync が作成されたことを確認できます。

# コマンド
kubectl get gcp -n config-control -o yaml \
  | grep "^    name: \\|message"
  
# 戻り値
    name: source-repo-cicd-trigger
      message: The resource is up to date
    name: deployment-repo-cloudbuild-write
      message: The resource is up to date
    name: source-reader-sync-config-controller-1-sandbox-cc-test-prj
      message: The resource is up to date
    name: source-repo-cloudbuild-read
      message: The resource is up to date
    name: sync-config-controller-1
      message: The resource is up to date
    name: sync-config-controller-1
      message: The resource is up to date
    name: projects/sandbox-cc-test-prj/serviceAccounts/sync-config-controller-1@sandbox-cc-test-prj.iam.gserviceaccount.com
    name: cloudbuild.googleapis.com
      message: The resource is up to date
    name: sourcerepo.googleapis.com
      message: The resource is up to date
    name: deployment-repo
      message: The resource is up to date
    name: source-repo
      message: The resource is up to date

source-repo リポジトリへの Push

source-repo リポジトリに GitOps パイプラインのデプロイに使用したファイル一式を push します。

まず、リポジトリのデフォルトブランチを main に設定します。

# コマンド (戻り値なし)
git config --global init.defaultBranch main

次に、gcloud source repos clone コマンドで source-repo リポジトリを Cloud Shell にクローンします。

# コマンド
gcloud source repos clone source-repo
  
# 戻り値
Cloning into '/home/user/gitops_test_20230816/source-repo'...
warning: You appear to have cloned an empty repository.
Project [sandbox-cc-test-prj] repository [source-repo] was cloned to [/home/user/gitops_test_20230816/source-repo].

クローンしたリポジトリに gitops/ ディレクトリを移動します。

# 移動前の状態確認
ls -l
  
total 8
drwx------ 3 user user 4096 Aug 16 12:52 gitops
drwxr-xr-x 3 user user 4096 Aug 16 14:46 source-repo
  
# 移動とその後の状態確認
mv gitops/ source-repo/ && ls -l
  
total 4
drwxr-xr-x 4 user user 4096 Aug 16 14:51 source-repo

最後にファイル一式を commit / push します。

# コマンド (git commit まで)
cd source-repo/
git add gitops/
git commit -m "Add GitOps blueprint"
  
[main (root-commit) f989115] Add GitOps blueprint
 15 files changed, 726 insertions(+)
 create mode 100644 gitops/CHANGELOG.md
 create mode 100644 gitops/Kptfile
 create mode 100644 gitops/README.md
 create mode 100644 gitops/cloudbuild-iam.yaml
 create mode 100644 gitops/configsync/Kptfile
 create mode 100644 gitops/configsync/README.md
 create mode 100644 gitops/configsync/config-management.yaml
 create mode 100644 gitops/configsync/configsync-iam.yaml
 create mode 100644 gitops/configsync/rootsync.yaml
 create mode 100644 gitops/configsync/setters.yaml
 create mode 100644 gitops/configsync/validation.yaml
 create mode 100644 gitops/hydration-trigger.yaml
 create mode 100644 gitops/services.yaml
 create mode 100644 gitops/setters.yaml
 create mode 100644 gitops/source-repositories.yaml
  
# コマンド (git push)
git push
  
[main (root-commit) f989115] Add GitOps blueprint
 15 files changed, 726 insertions(+)
 create mode 100644 gitops/CHANGELOG.md
 create mode 100644 gitops/Kptfile
 create mode 100644 gitops/README.md
 create mode 100644 gitops/cloudbuild-iam.yaml
 create mode 100644 gitops/configsync/Kptfile
 create mode 100644 gitops/configsync/README.md
 create mode 100644 gitops/configsync/config-management.yaml
 create mode 100644 gitops/configsync/configsync-iam.yaml
 create mode 100644 gitops/configsync/rootsync.yaml
 create mode 100644 gitops/configsync/setters.yaml
 create mode 100644 gitops/configsync/validation.yaml
 create mode 100644 gitops/hydration-trigger.yaml
 create mode 100644 gitops/services.yaml
 create mode 100644 gitops/setters.yaml
 create mode 100644 gitops/source-repositories.yaml

source-repo リポジトリの main ブランチにファイル一式が格納されました。

push されたブループリント

ランディングゾーンのデプロイ

概要

以下の手順でランディングゾーンをデプロイします。

  1. ランディングゾーンのブループリントをダウンロードする
  2. setters を定義して source-repopush する

kpt によるレンダリング、deployment-repo への push はパイプラインが行いますので、上記手順を実行するだけでランディングゾーンがデプロイされます。

ランディングゾーンブループリントのダウンロード

kpt を使って ランディングゾーンのブループリント を Cloud Shell にダウンロードします。

# コマンド、@main でリポジトリの main ブランチから取得する
kpt pkg get https://github.com/GoogleCloudPlatform/blueprints.git/catalog/landing-zone@main ./landing-zone
  
# kpt pkg の戻り値は先程と同様のため割愛

Cloud Shell にダウンロードできたことを確認します。

# コマンド
tree -a landing-zone/
  
# 戻り値
landing-zone/
├── CHANGELOG.md
├── iam.yaml
├── Kptfile
├── logging
│   └── .gitkeep # 空ディレクトリを維持するためのファイル
├── namespaces
│   ├── hierarchy.yaml
│   ├── logging.yaml
│   ├── networking.yaml
│   ├── policies.yaml
│   └── projects.yaml
├── network
│   └── .gitkeep # 空ディレクトリを維持するためのファイル
├── policies
│   ├── deletion-policy-required-template.yaml
│   ├── disable-guest-attributes.yaml
│   ├── disable-iam-grants-default-sa.yaml
│   ├── disable-nested-virtualization.yaml
│   ├── disable-sa-key-creation.yaml
│   ├── disable-serial-port.yaml
│   ├── disable-vm-external-ip.yaml
│   ├── enforce-uniform-bucket-lvl-access.yaml
│   ├── folder-naming-constraint-template.yaml
│   ├── restrict-cloud-sql-public-ip.yaml
│   ├── restrict-lien-removal.yaml
│   └── skip-default-network.yaml
├── projects
│   └── .gitkeep # 空ディレクトリを維持するためのファイル
├── README.md
├── services.yaml
└── setters.yaml
  
5 directories, 26 files

主要なマニフェストファイルの役割は以下の通りです。

# landing-zone/ 以下 役割
1 Kptfile kpt の設定ファイル
2 setters.yaml landing-zone/ 以下の各マニフェストファイルの設定値を一元管理
3 services.yaml ランディングゾーンが使用するサービス API を管理
4 iam.yaml グループアカウントの IAM Policy (組織レベル) を管理

namespaces ディレクトリには Config Controller が使用するネームスペース、policies ディレクトリは組織ポリシーに関するマニフェストファイルが格納されています。

loggingnetworkprojects ディレクトリは現時点で空ディレクトリを維持するためのファイルしかないためデプロイされるリソースはありませんが、別途拡張・カスムすることができます。

setters の定義

landing-zone/setters.yaml ファイルを編集して setters を定義します。

その前に上記ファイルの編集差分を後ほど確認できるよう、git commit まで実行します。

# コマンド
ls -l
  
# 戻り値
total 8
drwx------ 3 user user 4096 Aug 16 12:52 gitops
drwx------ 7 user user 4096 Aug 17 05:56 landing-zone
  
# git commit まで実行 (レンダリング後の差分を diff するため push はしない)
git add landing-zone/
git commit -m "Add landing zone"
  
# git の戻り値は先程と同様のため割愛

あらためて landing-zone/setters.yaml ファイルを編集します。

# 変更前
  
apiVersion: v1
kind: ConfigMap
metadata: # kpt-merge: /setters
  name: setters
  annotations:
    config.kubernetes.io/local-config: "true"
    internal.kpt.dev/upstream-identifier: '|ConfigMap|default|setters'
data:
  # Organization ID and billing account
  org-id: "123456789012"
  billing-account-id: AAAAAA-BBBBBB-CCCCCC
  # Groups to use for org-level roles
  group-org-admins: gcp-organization-admins@example.com
  group-billing-admins: gcp-billing-admins@example.com
  # The project where Config Controller is deployed
  management-project-id: management-project-id
  # This default is safe to keep
  management-namespace: config-control
# 変更後、org-id / billing-account-id / management-project-id / group-org-admins / group-billing-admins を変更
  
apiVersion: v1
kind: ConfigMap
metadata: # kpt-merge: /setters
  name: setters
  annotations:
    config.kubernetes.io/local-config: "true"
    internal.kpt.dev/upstream-identifier: '|ConfigMap|default|setters'
data:
  # Organization ID and billing account
  org-id: "999999999999" # 
  billing-account-id: 00000B-66666E-DDDD77
  # Groups to use for org-level roles
  group-org-admins: ggen@sandbox.co.jp
  group-billing-admins: ggen@sandbox.co.jp
  # The project where Config Controller is deployed
  management-project-id: sandbox-cc-test-prj
  # This default is safe to keep
  management-namespace: config-control

landing-zone/setters.yaml ファイル編集後の差分は git diff コマンドでも確認できます。

# コマンド
git diff
  
# 戻り値
diff --git a/landing-zone/setters.yaml b/landing-zone/setters.yaml
index 398cbcb..0905af7 100644
--- a/landing-zone/setters.yaml
+++ b/landing-zone/setters.yaml
@@ -20,12 +20,12 @@ metadata: # kpt-merge: /setters
     internal.kpt.dev/upstream-identifier: '|ConfigMap|default|setters'
 data:
   # Organization ID and billing account
-  org-id: "123456789012"
-  billing-account-id: AAAAAA-BBBBBB-CCCCCC
+  org-id: "999999999999"
+  billing-account-id: 00000B-66666E-DDDD77
   # Groups to use for org-level roles
-  group-org-admins: gcp-organization-admins@example.com
-  group-billing-admins: gcp-billing-admins@example.com
+  group-org-admins: ggen@sandbox.co.jp
+  group-billing-admins: ggen@sandbox.co.jp
   # The project where Config Controller is deployed
-  management-project-id: management-project-id
+  management-project-id: sandbox-cc-test-prj
   # This default is safe to keep
   management-namespace: config-control

source-repo リポジトリへの Push

変更内容を確認したら source-repo リポジトリに push します。

# コマンド
git commit -a -m "Customize landing zone blueprint"
git push
  
# git の戻り値は先程と同様のため割愛

その後、上記をトリガーとして GitOps パイプラインが以下のように動作し、最終的にランディングゾーンがデプロイされます。

  • landing-zone/setters.yaml ファイルにもとづきレンダリングが行われる
  • レンダリングされたファイル一式が deployment-repopush される
  • Config Sync が deployment-repo を参照する
  • Config Controller が 参照結果にもとづきランディングゾーンをデプロイする

トラブルシューティング

想定エラー

参考ドキュメントをベースに進めてきましたが、nomos status (Config Sync が管理するリソースの状態確認) コマンドを実行すると KNV1069: SelfManageError が発生するものと思われます。

# コマンド
nomos status
  
# 戻り値 (エラーのみ抜粋)
KNV1069: RootSync config-management-system/root-sync must not manage itself in its repo

エラー原因

原因は Config Sync が、自身のマニフェストファイル (rootsync.yaml) を含め、リポジトリ全体を参照するように設定されている からです。

Config Sync は 管理対象リソースのマニフェストファイル だけを参照すべきで、自身の状態を定義したマニフェストファイルを参照させてはいけません。

ファイル確認

パイプラインをデプロイした際のファイル (gitops/configsync/rootsync.yaml) を確認します。

dirconfig になっています。config とは source-repo リポジトリ上のルートディレクトリ名を指しており、すなわち Config Sync の設定を含むリポジトリ全体 を参照するようになっています。

apiVersion: configsync.gke.io/v1beta1
kind: RootSync
metadata: # kpt-merge: config-management-system/root-sync
  name: root-sync
  namespace: config-management-system
  annotations:
    internal.kpt.dev/upstream-identifier: 'configsync.gke.io|RootSync|config-management-system|root-sync'
spec:
  sourceFormat: unstructured
  git:
    repo: https://source.developers.google.com/p/sandbox-cc-test-prj/r/deployment-repo # kpt-set: https://source.developers.google.com/p/${project-id}/r/${deployment-repo}
    revision: HEAD
    branch: main
    dir: config # kpt-set: ${configsync-dir}
    auth: gcpserviceaccount
    gcpServiceAccountEmail: sync-config-controller-1@sandbox-cc-test-prj.iam.gserviceaccount.com # kpt-set: sync-${cluster-name}@${project-id}.iam.gserviceaccount.com

対処方法

ランディングゾーンに関するマニフェストだけを参照するよう設定を修正します。

  • Cloud Shell 上にある gitops/configsync/setters.yaml を開き、configsync-dir の値を config/landing-zone に変更します。
# 変更後
  
apiVersion: v1
kind: ConfigMap
metadata: # kpt-merge: /setters
  name: setters
  annotations:
    config.kubernetes.io/local-config: "true"
    internal.kpt.dev/upstream-identifier: '|ConfigMap|default|setters'
data:
  namespace: config-control
  # cluster-name must not exceed 25 characters in length
  cluster-name: cluster-name
  configsync-dir: config/landing-zone
  deployment-repo: deployment-repo
  project-id: project-id
  • レンダリングを実行して gitops/configsync/rootsync.yamldir に反映させます。
# レンダリング実行場所の確認 (gitops ディレクトリが表示されること) 
ls -l
  
# レンダリング (戻り値は割愛)
kpt fn render gitops/
# レンダリング後
  
apiVersion: configsync.gke.io/v1beta1
kind: RootSync
metadata: # kpt-merge: config-management-system/root-sync
  name: root-sync
  namespace: config-management-system
  annotations:
    internal.kpt.dev/upstream-identifier: 'configsync.gke.io|RootSync|config-management-system|root-sync'
spec:
  sourceFormat: unstructured
  git:
    repo: https://source.developers.google.com/p/sandbox-cc-test-prj/r/deployment-repo # kpt-set: https://source.developers.google.com/p/${project-id}/r/${deployment-repo}
    revision: HEAD
    branch: main
    dir: config/landing-zone # kpt-set: ${configsync-dir}
    auth: gcpserviceaccount
    gcpServiceAccountEmail: sync-config-controller-1@sandbox-cc-test-prj.iam.gserviceaccount.com # kpt-set: sync-${cluster-name}@${project-id}.iam.gserviceaccount.com
  • kubectl apply で Config Sync の設定を適用 (変更) します。
# 適用 (戻り値は割愛)
kubectl apply --wait -f gitops/ --recursive
  • レンダリングしたファイルを source-repo リポジトリに push します。
# コマンド (戻り値は割愛)
git add .
git commit -m "update rootsync"
git push

nomos status の再確認

再度 nomos status を実行しエラーが解消されたことを確認します。

各リソースのステータスが Current になっていればデプロイが完了しています。

# コマンド
nomos status
  
# 戻り値
*gke_sandbox-cc-test-prj_asia-northeast1_krmapihost-config-controller-1
  --------------------
  <root>:root-sync                         https://source.developers.google.com/p/sandbox-cc-test-prj/r/deployment-repo/config/landing-zone@main   
  SYNCED @ 2023-08-18 10:47:07 +0000 UTC   2f1935299502189667f71e2c4d03de46728447e2                                                                
  Managed resources:
     NAMESPACE        NAME                                                                                                  STATUS    SOURCEHASH
                      constrainttemplate.templates.gatekeeper.sh/gcpenforcenamingv2                                         Current   2f19352
                      constrainttemplate.templates.gatekeeper.sh/gcprequiredeletionpolicy                                   Current   2f19352
                      namespace/hierarchy                                                                                   Current   2f19352
                      namespace/logging                                                                                     Current   2f19352
                      namespace/networking                                                                                  Current   2f19352
                      namespace/policies                                                                                    Current   2f19352
                      namespace/projects                                                                                    Current   2f19352
     config-control   iampartialpolicy.iam.cnrm.cloud.google.com/hierarchy-sa-workload-identity-binding                     Current   2f19352
     config-control   iampartialpolicy.iam.cnrm.cloud.google.com/logging-sa-workload-identity-binding                       Current   2f19352
     config-control   iampartialpolicy.iam.cnrm.cloud.google.com/networking-sa-workload-identity-binding                    Current   2f19352
     config-control   iampartialpolicy.iam.cnrm.cloud.google.com/policies-sa-workload-identity-binding                      Current   2f19352
     config-control   iampartialpolicy.iam.cnrm.cloud.google.com/projects-sa-workload-identity-binding                      Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/billing-admins-iam                                          Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/hierarchy-sa-folderadmin-permissions                        Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/logging-sa-bigqueryadmin-permissions                        Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/logging-sa-logadmin-permissions                             Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/networking-sa-dns-permissions                               Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/networking-sa-networkadmin-permissions                      Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/networking-sa-security-permissions                          Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/networking-sa-service-control-permissions                   Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/networking-sa-xpnadmin-permissions                          Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/org-admins-iam                                              Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/policies-sa-orgpolicyadmin-permissions                      Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/projects-sa-billinguser-permissions                         Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/projects-sa-projectcreator-permissions                      Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/projects-sa-projectdeleter-permissions                      Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/projects-sa-projectiamadmin-permissions                     Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/projects-sa-projectmover-permissions                        Current   2f19352
     config-control   iampolicymember.iam.cnrm.cloud.google.com/projects-sa-serviceusageadmin-permissions                   Current   2f19352
     config-control   iamserviceaccount.iam.cnrm.cloud.google.com/hierarchy-sa                                              Current   2f19352
     config-control   iamserviceaccount.iam.cnrm.cloud.google.com/logging-sa                                                Current   2f19352
     config-control   iamserviceaccount.iam.cnrm.cloud.google.com/networking-sa                                             Current   2f19352
     config-control   iamserviceaccount.iam.cnrm.cloud.google.com/policies-sa                                               Current   2f19352
     config-control   iamserviceaccount.iam.cnrm.cloud.google.com/projects-sa                                               Current   2f19352
     config-control   service.serviceusage.cnrm.cloud.google.com/sandbox-cc-test-prj-cloudbilling                           Current   2f19352
     config-control   service.serviceusage.cnrm.cloud.google.com/sandbox-cc-test-prj-cloudresourcemanager                   Current   2f19352
     config-control   service.serviceusage.cnrm.cloud.google.com/sandbox-cc-test-prj-serviceusage                           Current   2f19352
     hierarchy        configconnectorcontext.core.cnrm.cloud.google.com/configconnectorcontext.core.cnrm.cloud.google.com   Current   2f19352
     hierarchy        rolebinding.rbac.authorization.k8s.io/allow-resource-reference-from-hierarchy                         Current   2f19352
     logging          configconnectorcontext.core.cnrm.cloud.google.com/configconnectorcontext.core.cnrm.cloud.google.com   Current   2f19352
     networking       configconnectorcontext.core.cnrm.cloud.google.com/configconnectorcontext.core.cnrm.cloud.google.com   Current   2f19352
     policies         configconnectorcontext.core.cnrm.cloud.google.com/configconnectorcontext.core.cnrm.cloud.google.com   Current   2f19352
     policies         resourcemanagerpolicy.resourcemanager.cnrm.cloud.google.com/disable-guest-attributes                  Current   2f19352
     policies         resourcemanagerpolicy.resourcemanager.cnrm.cloud.google.com/disable-iam-grants-default-sa             Current   2f19352
     policies         resourcemanagerpolicy.resourcemanager.cnrm.cloud.google.com/disable-nested-virtualization             Current   2f19352
     policies         resourcemanagerpolicy.resourcemanager.cnrm.cloud.google.com/disable-sa-key-creation                   Current   2f19352
     policies         resourcemanagerpolicy.resourcemanager.cnrm.cloud.google.com/disable-serial-port                       Current   2f19352
     policies         resourcemanagerpolicy.resourcemanager.cnrm.cloud.google.com/disable-vm-external-ip                    Current   2f19352
     policies         resourcemanagerpolicy.resourcemanager.cnrm.cloud.google.com/enforce-uniform-bucket-lvl-access         Current   2f19352
     policies         resourcemanagerpolicy.resourcemanager.cnrm.cloud.google.com/restrict-cloud-sql-public-ip              Current   2f19352
     policies         resourcemanagerpolicy.resourcemanager.cnrm.cloud.google.com/restrict-lien-removal                     Current   2f19352
     policies         resourcemanagerpolicy.resourcemanager.cnrm.cloud.google.com/skip-default-network                      Current   2f19352
     projects         configconnectorcontext.core.cnrm.cloud.google.com/configconnectorcontext.core.cnrm.cloud.google.com   Current   2f19352
     projects         rolebinding.rbac.authorization.k8s.io/allow-resource-reference-from-logging                           Current   2f19352
     projects         rolebinding.rbac.authorization.k8s.io/allow-resource-reference-from-networking                        Current   2f19352

動作確認

リソース

nomos status でリソース状況を確認しましたが、実際に組織ポリシーがデプロイされたことを確認してみます。

Cloud コンソール > IAM と管理 > 組織のポリシー と遷移したら、スコープを 組織 に切り替え、フィルタに constraints/sql.restrictPublicIp と入力します。

組織ポリシーを確認

ポリシー名をクリックすると、Cloud SQL にパブリック IP アドレスの付与を禁止するポリシーが有効化されていました。

組織ポリシーが適用されている

Reconciliation Loop が働くことを確認するため、このポリシーを手動で削除します。

ポリシーを管理 > 親のポリシーを継承する を選択し、ポリシーを設定 をクリックします。これにより、組織ポリシーの設定が初期化されます。

組織ポリシーを初期化する
ステータスが [未適用] に変わった (初期化された)

しばらく時間をおいて再確認すると、組織ポリシーが再適用されています。Reconciliation Loop が働きリソースがあるべき状態に戻りました。

Reconciliation Loop によりリソースがあるべき状態に自動的に戻る

GitOps パイプライン

リポジトリ

リポジトリは Cloud コンソール > Source Repositories から確認できます。

source-repo にはローカルリポジトリから push したブループリント一式が格納されています。

source-repo リポジトリはローカルから push したブループリント一式が格納

対する deployment-repo は、Cloud Build トリガーによるレンダリングで生成されたマニフェストファイルのみが格納されます。

Config Sync はこれら deployment-repo に格納されたマニフェストファイルを参照しリソースをデプロイ・管理します。

deployment-repo はレンダリングされたマニフェストファイルのみ格納

Cloud Build トリガー

Cloud Build トリガーはグローバルリージョンにデプロイされています。

内容としては、source-repopush をトリガーに、レンダリングされたファイルを deployment-repopush する処理を実行します。

source-repo への push をトリガーに、レンダリングされたファイルを deployment-repo に push

詳細は Build 履歴 から確認できます。

Cloud Build トリガーによって実行された処理の詳細

Config Sync

nomos status だけでなく、Cloud コンソールからも Config Sync のステータスを確認できます。

Cloud コンソール > Anthos > Config と遷移すると、Config Sync のダッシュボードが確認可能です。

Config Sync ダッシュボード

パッケージタブに切り替えると、nomos status 同様 Config Sync によってデプロイされたリソースの状態が確認できます。

パッケージタブからリソースの状態が確認可能

さいごに

公式ガイドではこの後フォルダやプロジェクトといったランディングゾーンリソースのデプロイへと続いていきますが、当記事では一旦ここで終了とします。

所感として、GitOps パイプラインでは Cloud Source Repositories を使用していますが、2023年8月時点ではプルリクエスト機能が搭載されていないため、GitHub をミラーしたリポジトリにカスタムすることでより利便性が向上すると思います。

今回の続きやリポジトリのカスタマイズについては今後記事にできればと思っています。

武井 祐介 (記事一覧)

2022年4月にジョイン。クラウドソリューション部所属。G-gen唯一の山梨県在住エンジニア

Google Cloud Partner Top Engineer 2024 に選出。IaC や CI/CD 周りのサービスやプロダクトが興味分野です。

趣味はロードバイク、ロードレースやサッカー観戦です。