JSONなアレに疲れたアナタに贈るGoogle Cloud Deployment Managerのススメ


この記事はGoogle Cloud Platform Advent Calendar 2015の１７日目です。

全国のAWSユーザの皆さん、いつもJSON業お疲れ様です。
全国のGCPユーザの皆さん、これからYAML業頑張りましょう。

はい。

ということ（？）で、「アレ」とは[CloudFormation](https://aws.amazon.com/jp/cloudformation/)のことです。

AWSの割りとヘビーユーザである私がGCPを使ってみて特に気に入ったサービスの一つである、テンプレートによる一括デプロイメントができる[Google Cloud Deployment Manager](https://cloud.google.com/deployment-manager/)を同種のサービスである[AWS CloudFormation](https://aws.amazon.com/jp/cloudformation/)と比べてどこが気に入っているかまとめてみたいと思います。

# CloudFormationは素晴らしい
では、ここで素晴らしいと思う点を挙げてみましょう。

- インフラをテンプレート化
- 再利用可能な再現性のあるインフラ
- 自動化された一括デプロイメント
- 大量にあるAWSのサービス・機能のほとんどをカバー
- 最近ではGUIで図から作れる機能なんかも出ましたね

いや、ほんとオンプレでは真似できないクラウドを象徴するサービスの一つだと思います。素晴らしいですね。

・・・・・
・・・・
・・・
・・
・

**自分で書かなければな！！１**

# CloudFormationは何がつらいか
主観です。個人差は大いにあります。

- JSON
- テンプレートファイルの分割ができない[^1] [^2]
- スタック内での記述の再利用できないため同じような記述が頻出することがある（コピペ地獄）[^2]
- 独自リソースや特殊な記述法  
「API→操作中心」「CFn→リソース中心」の設計となっており、対応付いていないため指定方法が異なる
- そして、出来上がる千行を超えるJSON・・・

しかしながら、それを改善するツールなんかもあって、特に[kumogata先生](http://kumogata.codenize.tools/)に私はいつもお世話になっております。とはいえ、やはりツラい面はある。。。

# Cloud Deployment Managerの特徴

### テンプレートの記述フォーマットはYAML  
好みの問題もありますが、JSONよりは人間に優しいですね。
閉じ括弧が必要ないとか、単純に行数も減ります。

### テンプレートの分割が可能
以下のように書きます。

```yaml
imports:
- path: path/to/template.yml
- path: path/to/template.jinja
- path: path/to/template.py
```

### jinja2[^3]とPythonによる記述もサポート
テンプレートエンジンを利用して変数やコードを埋め込んだり、動的にYAMLを組み立てることで冗長な表現を避けたり、可変な部分を外部から受け取るようにすることで再利用性を高めたりすることができます。

### APIに対応付いた記述
GCPのAPIはリソース指向でRESTfulなAPIであり、APIへの引数の与え方が大筋でそのままDeployment Managerの記述に対応付くような感じになっています。実際、Deployment Managerのドキュメントを辿っていくと気が付くと別のサービスのAPIリファレンスに到達しますｗ
https://cloud.google.com/deployment-manager/configuration/create-configuration-file

### ドキュメントは（比べると）少なめ
[CloudFormationの公式ドキュメント](http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/Welcome.html)を読むと、豊富なサンプルと各リソースの細かな説明が乗っています。
[Deployment Manaegrの公式ドキュメント](https://cloud.google.com/deployment-manager/overview)は（比べると）少なめです。ですが、上述したようにAPIリファレンスが大筋でそのまま対応付くので書いていて特に問題にはならないです。この辺りはそこまで使い込んでいないのでまだ遭遇していませんが、複雑な構成や依存関係が出てきたりすると苦労するかもしれませんね。

# 記述を比べてみる
では、一例として似たようなサービスであるRDS(MySQL)とCloudSQLのテンプレートの記述を比べてみましょう。

インスタンスの立ち上げと`utf8mb4`で使うための設定だけを行う記述になります。

## RDS

```json
{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "sample",
  "Resources" : {
    "MyDB" : {
      "Type" : "AWS::RDS::DBInstance",
      "Properties" : {
        "DBName" : "DBName" ,
        "AllocatedStorage" : "5",
        "DBInstanceClass" : "db.t2.small",
        "Engine" : "MySQL",
        "EngineVersion" : "5.6.19",
        "MasterUsername" : "DBUser",
        "MasterUserPassword" : "DBPassword",
        "DBParameterGroupName" : { "Ref" : "MyRDSParamGroup" }
      }
    },
    "MyRDSParamGroup" : {
      "Type": "AWS::RDS::DBParameterGroup",
      "Properties" : {
        "Family" : "MySQL5.6",
        "Description" : "CloudFormation Sample Database Parameter Group",
          "Parameters" : {
            "character-set-server" : "utf8mb4",
            "collation-server": "utf8mb4_general_ci"
        }
      }
    }
  }
}
```

## CloudSQL
※一部誤りがありましたので修正しました。
<ins>
2015/12/17追記：
`database`の記述が他のリソースを参照する表記（`$(ref.sample-cloudsql.name)`の所）になっていなかったので修正しました。参照表記を使用して依存関係を明示しないとインスタンスが作られる前にデータベースを作ろうとして失敗します。また、`database`の`name`もそのままMySQLのDB名になるのでハイフンが使えませんのでアンダースコアに修正しました。
</ins>

```yaml
resources:
- name: sample-cloudsql
  type: sqladmin.v1beta4.instance
  properties:
    region: us-central
    instanceType: CLOUD_SQL_INSTANCE
    settings:
      tier: D1
      activationPolicy: ON_DEMAND
- name: sample_database
  type: sqladmin.v1beta4.database
  properties:
    instance: $(ref.sample-cloudsql.name)
    charset: utf8mb4
    collation: utf8mb4_general_ci
```

## 比べて分かる特徴
なんとなくDeployment Managerが簡潔であることがお分かりいただけるかと思いますが、もう一つの事実も見えてきます。

これは、サービスとしての特性の違いでもあるのですが、`RDS`は文字コードを指定するための内容が`DBParameterGroup`として独立した機能となっており、指定方法は`MySQL`のパラメータ名そのままで、実際`MySQL`のパラメータの多くが弄れます。ですが、`CloudSQL`は`database`を作る際に一緒に指定する項目となっており、`charset`や`collation`と独自に省略されていて、実際文字コードくらいしか弄れません。[^4]

サービスとしての自由度（≒複雑度）が違います。なので、**一概にCloudFormationが複雑でDeployment Managerは簡潔で勝っているとは言えない面はあります。他のサービスやプラットフォーム全体としても然りです。**

# 私見なまとめ
- 人が書くならJSONよりYAML
- Deployment Managerつらくない（主観）
- 公式でjinja2やPythonをサポートしているのは嬉しい
- APIとかを見てると各社の思想の違いみたいなのが垣間見えて面白い

最終的には好みもあるので、参考までに。
Deployment Managerは動的な記述ができるので、もっと使う人が増えれば色々な便利な使い方が出てくるんじゃないかと思ってます。是非使ってみてください :-)



[^1]: もちろん複数のスタックに分ければできる。一つのスタックを分割することはできないということ。
[^2]: [kumogata](http://kumogata.codenize.tools/)とかプログラミング言語で記述できる支援ツールを使えばできる
[^3]: http://jinja.pocoo.org/docs/dev/
[^4]: 最近出た第２世代のCloudSQLはもっと弄れるんだろうか？