GCPで冪等性を実現しようと頑張った

試行錯誤の備忘録・日記です
## 結論
- GCPのリソースを自分なりに宣言的に定義できるようになったので、気軽に試行錯誤できるようになった
- 作ったPythonスクリプトは [こちら](https://github.com/kozohosok/gcp-cli-helper)


## 経緯

### 1. GCPを触り始めた

よく使うクラウドはAWSだったが、世の中の風潮はマルチクラウドなのでGCPにも慣れておこうと思った。
（まだまだ勉強し始めた程度）

### 2. コンソールで恐る恐る作業

必要な作業はGCPコンソールで実施できることを体感できた。
しかし、コンソール作業は指が疲れるし間違えやすいので、作業は自動化したい。
（使い慣れていたAWS CloudFormationのありがたみを回想する日々）

### 3. Deployment ManagerでIaCを目指すが

構成管理サービスであるCloud Deployment managerがGCPにはあることに思い至った。
ドキュメントを見ると対応しているサービスがまだあまり多くはなさそうで今後の発展に期待したいという印象だった。
足りないところはgcloudで作る必要がありそうな気がして、それなら最初からgcloud主体の方が自分には良いかもという思いが強くなった。

### 4. gcloudを使うことにした

Google Cloud SDKをインストールした。
[ドキュメント](https://cloud.google.com/sdk/gcloud/reference)を見て右往左往しながらGCPリソースを作成した。

### 5. gcloudにだいぶ慣れてきた

必要な情報を指定すれば必要なリソースが作られることを実感できるようになった。
（当たり前のことを当たり前と感じられるようになった）

### 6. 冪等性はやはり必要と考え始めた

手当たり次第に操作しているとすぐに散らかって手に負えなくなる予感（自信）があった。
コンソールでの確認作業をあまりやらずに済む状態にしないと人間律速になってすぐ飽きてしまいそう。
何か仕掛けを作らねば。。。

### 7. 冪等性を自力で目指す

依存性を管理するちょっとした仕掛けなら作れそうと思い試作した。
（思い浮かべたのはMakefileやAnsibleのplaybook、それとCloudFormationのテンプレート）
基本となるのはgcloudのコマンド引数を生成する機能
- 変更したパラメータを検出して関連するリソースを作成・更新
- 他のリソースの出力結果を参照できるようにすることで実行順序を判断
- 設定ファイルはyaml形式のファイルとして保存
####（設定ファイルと実行コマンドの例）

```sample-config.yml
Parameters:
  PROJECT: myproject-12345
Defaults:
  Parent:
# _sub_: Parametersの値や他のリソースの出力結果を利用して文字列を生成
    Project: {_sub_: '{PROJECT}'}
Resources:
  myServiceAccount:
    Type: [iam, service-accounts]
# service-accountはcreateとupdateで指定するIDがなぜか違うので別のキーを用意
    Name: my-first-serviceaccount
    ID: {_sub_: 'my-first-serviceacount@{PROJECT}.iam.gserviceaccount.com'}
# creatコマンドにしか指定できない引数はCreate:に記載
# create/updateコマンドで指定できる引数はUpdate:に記載
    Update:
      Description: datastore editor
      DisplayName: my-first-seriveaccount
  myServiceAccountRole:
# add-/remove-コマンドで付与する属性は_bindというTypeにより指定
    Type: [_bind, projects, iam-policy-binding]
    ID: mysa-roles
    Parent:
      ID: {_sub_: '{PROJECT}'}
    Tag:
      Member: {_sub_: 'serviceAccount:{myServiceAccount}'}
      Role:
      - roles/datastore.user
      - roles/cloudfunctions.invoker
  myFunction:
    Type: [functions]
    ID: my-first-function
    Parent: {Region: asia-northeast-1}
    Update:
      EntryPoint: handler
      MaxInstances: 1
      Memory: 128MB
      Runtime: python39
# myServiceAccountの情報を参照するのでmyServiceAccountより後に作成する
      ServiceAccount: {_sub_: '{myServiceAccount}'}
      Source: ./function-sorce/
      Timeout: 10s
    Flag:
    - TriggerHttp
    - AllowUnauthenticated
    Tag:
      Labels:
        function-label: read 
      EnvVars:
        func-type: query-event
```

```sh:生成される実行コマンドの例
> gcloud iam service-accounts create my-first-serviceaccount --project=myproject-12345 \
 --quiet --format=yaml --description='datastore editor' --display-name=my-first-serviceaccount
> gcloud projects add-iam-policy-binding myproject-12345 \
 --member=serviceAccount:my-first-serviceaccount@myproject-12345.iam.gserviceaccount.com \
 --quiet --format=yaml --role=roles/datastore.user
> gcloud projects add-iam-policy-binding myproject-12345 \
 --member=serviceAccount:my-first-serviceaccount@myproject-12345.iam.gserviceaccount.com \
 --quiet --format=yaml --role=roles/cloudfunctions.invoker
> gcloud functions deploy my-first-function --project=myproject-12345 --region=asia-northeast-1 \
 --quiet --format=yaml --entry-point=handler --max-instances=1 --memory=128MB \
 --runtime=python39 --service-account=my-first-serviceaccount@myproject-12345.iam.gserviceaccount.com \
 --source=./function-source/ --timeout=10s --trigger-http --allow-unauthenticated \
 --update-labels function-label=read --set-env-vars func-type=query-event
```

```sh:設定ファイル編集後に生成される実行コマンドの例
> gcloud iam service-accounts update my-first-serviceaccount --project=myproject-12345 \
 --quiet --format=yaml --description='datastore editor,function invoker' --display-name=my-first-serviceaccount'
```
### 8. 気軽に試行錯誤！

GCPのリソースを宣言的に定義できるようになったので安心感が高まった。

## 課題
- 現状はあくまで個人向けのお助けツール
    GCPリソースの作業履歴をローカル環境に作っている状態。
    作業履歴をGCPのストレージやGitHubなどに保管してバージョン管理した方がよさそう。

- 条件式を定義できると便利かも
    リソースを作ったり・作らなかったりをパラメータで制御できると試行錯誤がさらにしやすくなるはず

- ロールバックもできるとさらに便利かも

## その他
スクリプトの中身は依存性を把握するためのグラフ(DAG)処理が大半。
おまけでgcloud関連の処理もできるようになったような感じ。
知らないだけで探せば似たようなツールが実はあるのかもしれない。。。
Cloud Deployment Managerが発展して今回のスクリプトが不要になる日を待ち望む気持ちは変わらない。