Terraformの代わりにGCP Config Connectorを使った

GKE上で色々構築してる時に Static IP や Firewall など、GCPリソースを作りたい時があります。
AWSではTerraformで構築していたのですが、GCPでも同じようにTerraformで作るの面倒だなーと思って、Operatorなるものが無いのか調べたら、ありました。

# Config Connector 

Config Connector is GPC Operator for Kubernetes

https://cloud.google.com/blog/products/containers-kubernetes/config-connector-bridges-kubernetes-gcp-resources


Kuberenetsでいうところの**Operator**。簡単に言うとGCPリソースをyamlで作成・削除できるやつ。
TerraformはHCLで書きますが、Config ConnectorはKubernetesの拡張定義なので**yamlで書きます**。
なお、中身はkubebuilderでした。

Static IPを作りたい場合はこのように書くだけです。

Terraformみたいに、tfstateの場所（権限）どうしようとか、dev, stg, prodでディレクトリ構成どうするとか考えなくて良いです。

```:static-ip.yaml
apiVersion: compute.cnrm.cloud.google.com/v1beta1
kind: ComputeAddress
metadata:
  name: sample-ip
spec:
  location: global
```

### 作成可能なリソース

最新情報は[こちら](https://cloud.google.com/config-connector/docs/reference/resources?hl=ja#storagebucket)で確認ください。先日GAになったみたいですが、頻繁にドキュメントは更新されています。
2020年2月時点で75種類のリソースが作成可能で、かなり多いです。
Terraformで作れるやつはだいたい作れそうで、APIの叩いているのでパラメータはほぼ同じでした。

### メリット

kubernetes の Service や Deployment と一緒にyamlで管理できて同じライフサイクルに入れられます。
ちょっと使いたいだけでTerraformは少し重たいので、Config Connectorはライトでかなり楽です。
（ちょっとしたリソース作りたいだけでTerraformを渡したくない）

# インストール手順

### インストール
[インストールマニュアルはここ](https://cloud.google.com/config-connector/docs/how-to/install-upgrade-uninstall?hl=ja)

更新頻度高いので最新情報は公式ドキュメントを参照ください。
インストールすること自体はそんなに難しくないです。
以降はGCP Identityベースの手順になります。

```
$ gcloud iam service-accounts create cnrm-system

$ gcloud projects add-iam-policy-binding [PROJECT_ID] \
--member serviceAccount:cnrm-system@[PROJECT_ID].iam.gserviceaccount.com \
--role roles/owner

$ gcloud iam service-accounts keys create --iam-account \
cnrm-system@[PROJECT_ID].iam.gserviceaccount.com key.json

$ kubectl create namespace cnrm-system

$ kubectl create secret generic gcp-key --from-file key.json --namespace cnrm-system

$ rm key.json

$ gsutil cp gs://cnrm/latest/release-bundle.tar.gz release-bundle.tar.gz

$ tar zxvf release-bundle.tar.gz

$ kubectl apply -f install-bundle-gcp-identity/
```

### 動作確認
動作確認は以下のコマンドを発行し `condition met` が表示されればOKです。

```
$ kubectl wait -n cnrm-system --for=condition=Initialized pod cnrm-controller-manager-0
pod/cnrm-controller-manager-0 condition met
```

### 注意点

GCPのプロジェクト名とNameSpaceが一致していることが前提となっているため、Project名とNameSpaceが違う環境（たいがいそうじゃない？）では以下のようにNameSpaceにAnnotationを付ける必要があります。

```
kind: Namespace
apiVersion: v1
metadata:
  name: oreno-cluster
  annotations:
    cnrm.cloud.google.com/project-id: oreno-project
  labels:
    name: oreno-cluster
```


# 使い方

先程の作成したyamlを適用するだけです。

```
kubectl apply -f static-ip.yaml
```

### Config Connector で作成されている全てのリソースを見る

以下のコマンドで全てのリソースを確認できますが、 **全てのリソースを確認しにいく** のでめちゃ時間かかります。

```
kubectl get gcp
```

# うまく作成されない時の調べ方

作るのは簡単です。でもうまく作成されなかった時にどこを調べればいいか

### Controllerのログを見る

```
$ kubectl logs -n cnrm-system cnrm-controller-manager-0
```

正常であれば `"level": "info"` になっています

```
{"level":"info","ts":1582015233.6663573,"logger":"computesecuritypolicy-controller","msg":"successfully finished reconcile","resource":{"namespace":"default","name":"sample-ip"}}
```

異常であれば `"level": "Error"` になっています。
見るべきポイントは、errorのvalueです。この場合はあ403でアクセス権が無いとのことでした。
よくやるのは「APIの有効化忘れ」です。それもログ見れば出てきます。

**なので、リソースが作成されない場合、もしくはリソースを作成した際にはログを見ることをオススメします。**

```
{"level":"error","ts":1581951213.6494515,"logger":"kubebuilder.controller","msg":"Reconciler error","controller":"storagebucket-controller","request":"default/storagebucket-sample","error":"Update call failed: error fetching live state: error reading underlying resource: Error reading Storage Bucket \"storagebucket-sample\": googleapi: Error 403: cnrm-system@xxxxxxx.iam.gserviceaccount.com does not have storage.buckets.get access to storagebucket-sample., forbidden","xxxxxxxxxxxxxxxxxxxxxxx"}
```

### 作成されたリソースを見る

以下のように作成されたリソースをdescribeすることで、eventsにerror情報が記載されていることもあります。
kindで指定した `ComputeAddress` や `StorageBucket` などが指定できます。

```
kubectl describe ComputeAddress xxxx
```

# まとめ
- Config Connector は Kubernetes の GCP Operator (GAしている）
- Terraform を置き換えることも可能
- Kubernetes の yaml と一緒に管理することができる