Config Controller + GitHubでCloud RunのGitOpsを構築してみる

## はじめに
こちらは、HRBrain Advent Calendar 2022 16日目の記事です。

https://qiita.com/advent-calendar/2022/hrbrain

どうもこんにちは、HRBrainでプラットフォームエンジニアとして働いてる東島です。

今回は、Config Controller + GitHubでCloud RunのGitOpsを構築してみます。

## Config Controllerとは
>Config Controller は、Anthos リソースと Google Cloud リソースのプロビジョニングとオーケストレーションを行うホスト型サービスです。Anthos Config Management の一部として Google Cloud リソースのプロビジョニング、有効化、オーケストレーションを行うための API エンドポイントを提供します。

>Config Controller は Config Connector を使用して必要な Google Cloud API 呼び出しを行い、Kubernetes リソースモデル（KRM）のリソースを対応する Google Cloud のリソースにマッピングします。また、Config Sync によって Git リポジトリに接続し、git push と同様に構成の変更を行います。付属の Policy Controller を使用すると、リソース構成にセキュリティとコンプライアンスを適用するカスタム ポリシーを作成できます。

https://cloud.google.com/anthos-config-management/docs/concepts/config-controller-overview?hl=ja

つまり、Config Controllerを設定すればYAMLでGoogle Cloudのリソースが作成できます。
また、Config Syncを設定すればGitリポジトリのYAMLでGitOpsを構築できるのです。

## 実際にやってみた

### Config Controllerの設定
ここは[公式の手順](https://cloud.google.com/anthos-config-management/docs/how-to/config-controller-setup?hl=ja)に従って設定します。
1. APIの有効化
   ```sh
    gcloud services enable krmapihosting.googleapis.com \
        container.googleapis.com \
        cloudresourcemanager.googleapis.com
   ```
1. Config Controllerインスタンスの作成
`krmapihost-config-ctrl`というクラスタが作成されます。ここでは、Autopilotクラスタで作成しましたが、完了まで20分ほどかかりました。
   ```sh
   gcloud alpha anthos config controller create config-ctrl \
       --location=asia-northeast1 \
       --full-management
   ```
1. Config Controllerの認証
   ```sh
   gcloud anthos config controller get-credentials config-ctrl \
    --location asia-northeast1
   ```
1. Config Controllerにリソースを管理する権限を付与
   ```sh
   export SA_EMAIL="$(kubectl get ConfigConnectorContext -n config-control \
       -o jsonpath='{.items[0].spec.googleServiceAccount}' 2> /dev/null)"
   ```
   ```sh
   gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
       --member "serviceAccount:${SA_EMAIL}" \
       --role "roles/owner" \
       --project "${PROJECT_ID}"
   ```

### Cloud NATの作成
Config Controllerで作成したクラスタはプライベートクラスタなのでインターネットにアクセスできません。そのため、GitHubなどのリポジトリと同期するためには[GKEでCloud NATを設定する](https://cloud.google.com/nat/docs/gke-example?hl=ja)必要があります。

```sh
#設定手順
## Cloud Routerを作成します。
gcloud compute routers create nat-router \
    --network default \
    --region asia-northeast1

## ルーターに構成を追加します。
gcloud compute routers nats create nat-config \
    --router-region asia-northeast1 \
    --router nat-router \
    --nat-all-subnet-ip-ranges \
    --auto-allocate-nat-external-ips
```
### Config Syncの設定
Gitリポジトリと接続するためにConfig Syncの設定をします。
Config Controllerのドキュメントでは、リポジトリにCloud Source Repositoriesを使っていますが、今回はGitHubを使います。
リポジトリにGitHubを使うので、Config Syncからリポジトリを読み取れるように[デプロイキー](https://docs.github.com/ja/developers/overview/managing-deploy-keys#deploy-keys)を作成します。
手順は[Config Sync のインストール](https://cloud.google.com/anthos-config-management/docs/how-to/installing-config-sync?hl=ja#custom)を参考にします。

#### sshキーの作成
Config SyncはSSH 認証鍵のパスフレーズをサポートしていないので、パスフレーズなしでSSH認証鍵を作成する必要があります。
id_rsaを既に使っている場合は、上書きされるので注意してください。
```sh
ssh-keygen -t rsa -b 4096 
```
#### シークレットの作成
秘密鍵を保存するためのシークレットを作成します。
```sh
kubectl create secret generic git-creds \
 --namespace=config-management-system \
 --from-file=ssh=<作成した秘密鍵のパス>
```


#### RootSyncの作成
Config Syncを構成するためにRootSyncを作成します。

```yaml
# root-sync.yaml
apiVersion: configsync.gke.io/v1beta1
kind: RootSync
metadata:
  name: root-sync
  namespace: config-management-system
spec:
  sourceType: git
  sourceFormat: unstructured
  git:
    repo: <リポジトリのURL>
    branch: main
    dir: /
    auth: ssh
    secretRef:
      name: git-creds
```
## 完成
これで、Cloud ControllerでGitOpsを構築できました。
リポジトリにYAMLを作成すると、自動的にGoogle Cloudのリソースを作成します。

## Cloud RunのKRMを作成
次は構築したGitOpsでCloud Runのサービスを作成します。
YAMLをリポジトリのルートディレクトリに配置してください。少し待てば自動的に`runservice-sample`というサービスが作成されます。
注意するのはConfig Controllerと同じプロジェクトにリソースを作成する場合は、namespaceで`config-control`を指定する必要があります。
```yaml
apiVersion: run.cnrm.cloud.google.com/v1beta1
kind: RunService
metadata:
  name: runservice-sample
  namespace: config-control
spec:
  ingress: "INGRESS_TRAFFIC_ALL"
  launchStage: "GA"
  location: "asia-northeast1"
  projectRef:
    # Replace ${PROJECT_ID?} with your project ID.
    external: projects/${PROJECT_ID?}
  template:
    containers:
      - env:
          - name: "FOO"
            value: "bar"
        image: "gcr.io/cloudrun/hello"
    scaling:
      maxInstanceCount: 2
  traffic:
    - percent: 100
      type: "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"


```
参考
https://cloud.google.com/config-connector/docs/reference/resource-docs/run/runservice#sample_yamls


## 終わりに
定義ファイルでGoogle Cloudのリソースを作成できることはTerraformやDeployment Managerと変わらないですが、大きな違いはデフォルトでリポジトリをみてリコンサイルすることです。
Cloud Runに絞るとTerraform、Cloud Build、Cloud DeployでのPush型のCDがありますが、Pull型というGitOpsを構築できる点で差別化できていると思います。

HRBrainでは一緒に働く仲間を募集しています。プラットフォームチームに興味ある方は、ぜひご応募ください！！

https://www.hrbrain.co.jp/recruit