Config Controller(Config Sync)でGitOpsなリソース管理を試してみる

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

G-gen の武井です。当記事では Config Controller (Config Sync) を用いて GitOps で Google Cloud (旧称 GCP) のリソース管理を試してみましたので紹介します。

Config Controller (Config Sync)

はじめに

当記事の概要

Config Controller と Config Sync を併用すると、Google Cloud のリソース管理を GitOps で管理できます。

  • Git リポジトリで管理されるマニフェストファイルを定期的に参照する
  • Google Cloud 環境の現状とマニフェストファイルを比較する
  • マニフェストファイルを正として、環境が本来あるべき姿を維持するようリソースを管理 (作成、変更、削除) する

当記事では上記を実現するための方法をご紹介します。

前提知識

Anthos Config Management

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

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

※ 当記事で Policy Controller の解説は割愛します。

# 機能 概要
1 Config Controller Kubernetes の仕組みを用いて Google Cloud リソースを管理する中核的コンポーネント
2 Config Sync GitHub 等のリポジトリからマニフェストファイルを取得して Google Cloud リソースを管理 (GitOps サービス)
3 Policy Controller Google Cloud リソースのセキュリティとコンプライアンスを維持するためのカスタムポリシーを管理 (ガードレール)

Config Controller

Config Controller は、Config Connector と呼ばれる Kubernetes アドオンを利用してGoogle Cloud リソースのプロビジョニングとオーケストレーションを行うサービスです。

簡単に表すと、Kubernetes の仕組みを利用して、Google Cloud リソースの状態を定義したマニフェストファイルを kubectl で管理します。

Config Sync

Config Sync は GitOps サービスを提供するコンポーネントで、Git リポジトリと連携し、格納されたマニフェストファイルに従いリソースを動的に管理します。

そのため、Config Controller のみの利用 (kubectl による手動実行) とは異なり、一元管理された情報源にもとづきリソースが管理されることとなります。

Config Controller と Terraform の違い

IaC (Infrastructure as Code) という観点で両者に大きな違いはありませんが、Config Controller は Kubernetes の仕組みを用いているため、Reconciliation Loop に基づき管理するリソースをあるべき状態を維持しようと作用します。

つまり、マニフェストファイルで定義された内容が各リソースの ”あるべき状態” となるため、例えばリソースに何らかの変更が手動で加えられたとしても、Config Controller が自動的に検知・是正します (あるべき状態に戻します) 。

関連記事

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

blog.g-gen.co.jp blog.g-gen.co.jp

アーキテクチャ

Config Controller は前述の通り Config Connector と呼ばれる Kubernetes アドオンを使ったサービスで、実体としては GKE クラスタ が使用されています。

GKE クラスタには Config Controller の他にも Config Sync と Policy Controller がプリインストールされていて、今回の例では Config Sync を有効化して GitHub リポジトリと連携します。

これにより、任意のブランチに格納されたマニフェストファイルに従い Google Cloud リソースを管理します。

アーキテクチャ図

設定

実行環境

本設定では gcloudkubectlnomos (Config Sync のオプションツール) などのコマンドを利用するため、これらがプリインストールされた Cloud Shell を利用します。

参考ドキュメント

以下の公式ガイドを参考に Config Controller と Config Sync を設定しています。

参考:Config Controller でリソースを管理する
参考:Config Sync で GitOps を設定する
参考:Git へのアクセス権を付与する

Config Controller

API の有効化

Config Controller を作成するプロジェクト (今回は prj-cc-example) で gcloud services enable コマンドを実行し、必要な API を有効にします。

gcloud services enable krmapihosting.googleapis.com \
    container.googleapis.com  \
    cloudresourcemanager.googleapis.com \
    serviceusage.googleapis.com \
    cloudbilling.googleapis.com

Config Controller クラスタの作成

gcloud anthos config controller create コマンドで Config Controller クラスタを作成します。 --location 以外のオプションについては次のとおりです。

# オプション 役割
1 --network GKE クラスタの VPC を指定 (未指定だと default VPC を選択する)
2 --subnet GKE クラスタのサブネットを指定
3 --full-management Autopilot でクラスタを構成
gcloud anthos config controller create cc-example \
    --location=asia-northeast1 \
    --network=vpc-cc-example \
    --subnet=subnet-cc-example \
    --full-management

クラスタの作成には時間がかかります。完了すると以下の戻り値が表示されます。

Created instance [cc-example].
Fetching cluster endpoint and auth data.
kubeconfig entry generated for krmapihost-cc-example.

gcloud anthos config controller list コマンドでクラスタの作成を確認できます。

gcloud anthos config controller list --location=asia-northeast1  
  
NAME: cc-example
LOCATION: asia-northeast1
STATE: RUNNING

gcloud anthos config controller get-credentials コマンドで作成したクラスタを kubectl に紐付けます。

gcloud anthos config controller get-credentials cc-example \
    --location asia-northeast1
  
Fetching cluster endpoint and auth data.
kubeconfig entry generated for krmapihost-cc-example.

Cloud NAT の作成

Config Controller クラスタは 限定公開クラスタ として作成されるため、インターネットに接続できません。

今回 Config Sync を介して GitHub に接続するので Cloud NAT を作成します。

# Cloud NAT ルーターを作成
gcloud compute routers create cc-nat-router \
    --network vpc-cc-example \
    --region asia-northeast1
# NAT ゲートウェイを作成
gcloud compute routers nats create cc-nat-config \
    --router-region asia-northeast1 \
    --router cc-nat-router \
    --nat-all-subnet-ip-ranges \
    --auto-allocate-nat-external-ips

完了すると以下の戻り値が表示されます。

Creating router [cc-nat-router]...done.                                                                                                                    
NAME: cc-nat-router
REGION: asia-northeast1
NETWORK: vpc-cc-example
Creating NAT [cc-nat-config] in router [cc-nat-router]...done.                                                                                             

IAM Policy の設定

Google Cloud リソースを管理する権限を Config Controller が使用するサービスアカウントに付与します。

以下のように組織レベルで権限を付与する場合、gcloud organizations add-iam-policy-binding コマンドを使用します。

PROJECT_NO={プロジェクト番号を入力}
ORG_ID={組織 ID を入力}
SA_EMAIL="service-${PROJECT_NO}@gcp-sa-yakima.iam.gserviceaccount.com"
  
# 組織レベルでオーナーロールを付与
gcloud organizations add-iam-policy-binding ${ORG_ID} \
    --role=roles/owner \
    --member="serviceAccount:${SA_EMAIL}"
  
# 組織レベルでプロジェクト作成者ロールを付与
gcloud organizations add-iam-policy-binding ${ORG_ID} \
    --role=roles/resourcemanager.projectCreator \
    --member="serviceAccount:${SA_EMAIL}"

Config Sync

認証情報の作成

Config Sync には GitHub に対する読み取り権限が必要となるため、認証情報を作成する必要があります。

Config Sync はいくつかの認証方式をサポートしていますが、今回は GitHub が対応している SSH 認証鍵ペア を使って認証方式で設定します。

Config Sync では SSH 認証鍵のパスフレーズをサポートしていない ため、以下のコマンドでパスフレーズなしの SSH 認証鍵ペア (公開鍵と秘密鍵) を作成します。

# ~/.ssh ディレクトリ配下に秘密鍵 (id_rsa) と公開鍵 (id_rsa.pub) をパスフレーズなしで作成
# GIT_REPOSITORY_USERNAME にはConfig Sync がリポジトリへの認証で使用するユーザー名を入力
  
ssh-keygen -t rsa -b 4096 \
-C "GIT_REPOSITORY_USERNAME" \
-N ''

認証情報の紐づけ (GitHub)

先程作成した SSH 認証鍵ペアのうち、GitHub に公開鍵を紐付けるための設定 (デプロイキーの設定) を行います。

  1. GitHub リポジトリにアクセスします。

  2. Settings > Deploy keys と遷移したら Add deploy key をクリックします。

    Settings をクリック
    Deploy keys から キーを作成

  3. Title に任意のタイトル名を入力、Key に公開鍵 (id_rsa.pub) の値を入力したら Add key をクリックします。
    公開鍵の値を入力してデプロイキーを作成
  4. GitHub ユーザーアカウントに MFA 認証が設定されている場合は認証コードを入力します。
    認証コードを入力 (MFA 認証が有効な場合)
  5. デプロイキーが作成されたことを確認します。
    デプロイキーが作成された

認証情報の紐づけ (Config Sync)

先程作成した SSH 認証鍵ペアのうち、クラスタに秘密鍵 (id_rsa)を紐付けるために以下の設定を行います。

  1. Config Sync の Namespace を config-management-system (固定値) で作成します。
  2. Secret を git-creds (固定値) で作成して秘密鍵の値を登録します。
kubectl create ns config-management-system && \
kubectl create secret generic git-creds \
 --namespace=config-management-system \
 --from-file=ssh=~/.ssh/id_rsa

GitHub との連携

GitHub と連携するため、以下のマニフェストファイルを kubectl で適用します。

# 項目 説明
1 metadata.name リソース名 (任意)
2 metadata.namespace Config Sync の Namespace (固定)
3 spec.git.repo 参照先リポジトリ名 (SSH 形式)
4 spec.git.branch 参照先ブランチ名
5 spec.git.dir 参照先ディレクトリ名 (ルートディレクトリから見た相対パス)
# root-sync.yaml
  
apiVersion: configsync.gke.io/v1beta1
kind: RootSync
metadata:
  name: prj-cc-example-root-sync
  namespace: config-management-system
spec:
  sourceType: git
  sourceFormat: unstructured
  git:
    repo: git@github.com:repo-owner/repo-name.git
    branch: main
    dir: sample/
    auth: ssh
    secretRef:
      name: git-creds

spec.git.reporepo-ownerrepo-name は GitHub リポジトリの URL に表示される値を入力します。

GitHub リポジトリの URL

# kubectl で適用
  
kubectl apply -f root-sync.yaml

マニフェストファイルの準備

Config Sync の構成にあわせ、Google Cloud のリソースを定義したマニフェストファイルを GitHub リポジトリの main ブランチに用意します。

コードの編集にはコードスペースを使用しており、/workspaces/sample-repo-name がルートディレクトリに相当します。

@username ➜ /workspaces/sample-repo-name (main) $ pwd
/workspaces/sample-repo-name
@username ➜ /workspaces/sample-repo-name (main) $ tree
.
└── sample
    └── test.yaml

今回準備したマニフェストファイルでは プロジェクトStorage バケット を定義しています。

# test.yaml
  
# テスト用プロジェクト
apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
kind: Project
metadata:
  annotations:
    cnrm.cloud.google.com/auto-create-network: "false"
  name: cc-test-prj
  namespace: config-control
spec:
  # name (プロジェクト名、ディスプレイ表示) と resourceID (プロジェクトID) は一致させる
  name: cc-test-prj
  resourceID: cc-test-prj
  folderRef:
    # フォルダID
    external: "1111111111111"
  billingAccountRef:
    # 請求先アカウントID
    external: "222222-222222-222222"
---
# テスト用 Storage バケット
apiVersion: storage.cnrm.cloud.google.com/v1beta1
kind: StorageBucket
metadata:
  annotations:
    cnrm.cloud.google.com/project-id: cc-test-prj
    cnrm.cloud.google.com/state-into-spec: absent
  name: cc-test-prj-demo-bucket
  namespace: config-control
spec:
  storageClass: STANDARD
  location: asia-northeast1
  uniformBucketLevelAccess: true
---

動作確認

nomos コマンド

nomos コマンドは Config Sync のオプションツールで、コマンドラインで Config Sync のステータスを確認できます。

GitHub リポジトリの main ブランチにマニフェストファイルを格納 (Merge) した後、nomos status コマンドを実行した際の出力は以下のとおりです。

ステータスが Current の場合、リソースの状態が目的の状態と一致することを意味します。

nomos status
  
<一部省略>
  
*gke_prj-cc-example_asia-northeast1_krmapihost-cc-example
  --------------------
  <root>:prj-cc-example-root-sync     git@github.com:sample-repo-owner/sample-repo-name.git/sample@main   
  SYNCED @ 2023-08-12 23:26:39 +0900 JST   71888b401ee6b76ec0a0b94c8c012123c8406ed1                             
  Managed resources:
     NAMESPACE        NAME                                                                                                   STATUS    SOURCEHASH
     config-control   project.resourcemanager.cnrm.cloud.google.com/cc-test-prj                                              Current   71888b4
     config-control   storagebucket.storage.cnrm.cloud.google.com/cc-test-prj-demo-bucket                                    Current   71888b4

Cloud コンソール

Config Sync のステータスは Cloud コンソールからも確認可能です。

Cloud コンソール > Anthos > Config の順に遷移するとダッシュボードが閲覧できます。

ダッシュボード

nomos コマンド同様、プロジェクトと Storage バケットがマニフェストファイルで定義した状態と同じ状態にあることがわかります。

目的の状態であることを示す Current が表示

Reconciliation Loop

リソースの状態を意図的に変更した場合の動作も確認してみます。

Cloud コンソールから Storage バケットを削除します。

Storage バケットを削除する
削除後の状態

しばらくして Cloud コンソールを確認すると、Storage バケットが再作成されています。

バケットが自動的に再作成されている

マニフェストファイルに記載された内容で Storage バケットが存在している状態こそが 本来のあるべき姿 となるため、削除された状態は本来あるべき姿ではありません。

そのため、Reconciliation Loop が働き、結果として削除前と同じ状態で Storage バケットが復元されました。

武井 祐介 (記事一覧)

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

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

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