G-gen の武井です。当記事では Config Controller (Config Sync) を用いて GitOps で Google Cloud (旧称 GCP) のリソース管理を試してみましたので紹介します。
はじめに
当記事の概要
Config Controller と Config Sync を併用すると、Google Cloud のリソース管理を GitOps で管理できます。
- Git リポジトリで管理されるマニフェストファイルを定期的に参照する
- Google Cloud 環境の現状とマニフェストファイルを比較する
- マニフェストファイルを正として、環境が本来あるべき姿を維持するようリソースを管理 (作成、変更、削除) する
当記事では上記を実現するための方法をご紹介します。
前提知識
Anthos Config Management
Anthos Config Management は、Google Cloud リソースのプロビジョニングとオーケストレーションを行うサービスです。
Config Controller、Config Sync、Policy 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 リソースを管理します。
設定
実行環境
本設定では gcloud
、kubectl
、nomos
(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 に公開鍵を紐付けるための設定 (デプロイキーの設定) を行います。
GitHub リポジトリにアクセスします。
Settings > Deploy keys
と遷移したらAdd deploy key
をクリックします。Title
に任意のタイトル名を入力、Key
に公開鍵 (id_rsa.pub) の値を入力したらAdd key
をクリックします。- GitHub ユーザーアカウントに MFA 認証が設定されている場合は認証コードを入力します。
- デプロイキーが作成されたことを確認します。
認証情報の紐づけ (Config Sync)
先程作成した SSH 認証鍵ペアのうち、クラスタに秘密鍵 (id_rsa)を紐付けるために以下の設定を行います。
- Config Sync の Namespace を
config-management-system
(固定値) で作成します。 - 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.repo
の repo-owner
と repo-name
は 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 バケットがマニフェストファイルで定義した状態と同じ状態にあることがわかります。
Reconciliation Loop
リソースの状態を意図的に変更した場合の動作も確認してみます。
Cloud コンソールから Storage バケットを削除します。
しばらくして Cloud コンソールを確認すると、Storage バケットが再作成されています。
マニフェストファイルに記載された内容で Storage バケットが存在している状態こそが 本来のあるべき姿 となるため、削除された状態は本来あるべき姿ではありません。
そのため、Reconciliation Loop が働き、結果として削除前と同じ状態で Storage バケットが復元されました。
武井 祐介 (記事一覧)
クラウドソリューション部所属。G-gen唯一の山梨県在住エンジニア
Google Cloud Partner Top Engineer 2024 に選出。IaC や CI/CD 周りのサービスやプロダクトが興味分野です。
趣味はロードバイク、ロードレースやサッカー観戦です。
Follow @ggenyutakei