Cloud Deployment Managerを少し触ってみて感じた事

この記事は [CyberAgent Developers Advent Calendar 2016](http://www.adventar.org/calendars/1620/) の9日目の記事になります。
8日目は[＠kakerukaeru](https://twitter.com/kakerukaeru)さんの [GitHub Universe 2016 レポート](https://developers.cyberagent.co.jp/blog/archives/3233/) でした。

当初 [re:Invent](https://reinvent.awsevents.com/) の参加レポートを書く予定でしたが、別の事を書く事にしました。

二日連続カンファレンスの参加レポートとか微妙かなとw


最近、仕事でCloud Deployment Managerを触り始めたので、今回は個人的に少し触ってみて感じたこととかを書きたいと思います。
まず初めに、[Cloud Deployment Manager](https://cloud.google.com/deployment-manager/docs/) を知らない人もいると思うので、簡単に説明したいと思います。

## Cloud Deployment Managerとは
GCP上のリソースのデプロイやセットアップをテンプレートを使って定義する事ができるサービスです！
ざっくり言うと、GCP版のCloudFormationみたいなやつです（少し違いますが）

## 特徴
### テンプレートの記述フォーマットは、YAMLになります！
JSONみたいに、括弧をたくさん書かなくていいのは正直嬉しいですw

### テンプレートファイルを、分割してかけます！
こんな感じに書いて、テンプレートファイルを読み込めます。

```
imports:
- path: templates/template.yml
- path: templates/template.jinja
- path: templates/template.py
```

### Python・Jinja2で、記述ができます！
変数・ループ・条件式とかが、使えます！
それによって、冗長的な部分をなくせたり、テンプレートの再利用性を上げる事ができるので、この辺はありがたいです！

### GCPのAPIに対応した記述ができます！
GCPのAPIリソースは、RESTful APIなので、ほぼそのままDeployment Managerの記述に対応されています。

[サポートされるリソースタイプとリソース プロパティ](https://cloud.google.com/deployment-manager/configuration/create-configuration-file#supported_resource_types_and_properties)

```
# 現時点で利用できるリソースタイプは、以下のコマンドで確認できます！
$ gcloud deployment-manager types list

# Cloud SDKのバージョンアップは、以下のコマンドでして下さい！
$ gcloud components update
```

## Cloud Deployment Managerで管理できるもの
- Instance
  - VMインスタンスの設定
  - インスタンステンプレートの設定
- Autoscaling Group
  - オートスケールの設定
- Firewall
  - Firewallの設定
- Network
  - GCPで使うネットワークの設定
- Load Balancing
  - LBの設定
  - Health Check（ヘルスチェックの設定）
  - UrlMapの設定

まーきりがないので全部は書いてませんが、ほぼ全部管理できます＼(^o^)／

## 簡単なデプロイの流れ
### 1.設定をファイル作成する

```
# test.yaml
resources:
- name: test-vm
  type: compute.v1.instance
  properties:
    zone: us-central1-f
    machineType: https://www.googleapis.com/compute/v1/projects/[MY_PROJECT]/zones/us-central1-f/machineTypes/f1-micro
    disks:
    - deviceName: boot
      type: PERSISTENT
      boot: true
      autoDelete: true
      initializeParams:
        sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/family/debian-8
    networkInterfaces:
    - network: https://www.googleapis.com/compute/v1/projects/[MY_PROJECT]/global/networks/default
      accessConfigs:
      - name: External NAT
        type: ONE_TO_ONE_NAT
```

[公式チュートリアル](https://cloud.google.com/deployment-manager/step-by-step-guide/create-a-configuration)
[deploymentmanager-sample](https://github.com/GoogleCloudPlatform/deploymentmanager-samples/tree/master/examples/v2)

### 2.デプロイのプレビューをしてみる
```
$ gcloud deployment-manager deployments create {name} --config {yaml} --preview
```

### 3.マニフェストを確認してみる
```
# manifest-TIMESTAMPの取得を確認する
$ gcloud deployment-manager deployments describe {name}

# マニフェストを確認する
$ gcloud deployment-manager manifests describe {manifest-TIMESTAMP} --deployment {name}
```

### 4.デプロイの作成（更新）をする
```
# もし変更点がある場合はもう一度プレビューする
$ gcloud deployment-manager deployments update {name} --config {yaml} --preview

# デプロイを作成（更新）する
$ gcloud deployment-manager deployments update {name}
```

### 5.リソースリストを確認する
```
$ gcloud deployment-manager resources list --deployment {name}
```

### 6.デプロイを削除する
```
$ gcloud deployment-manager deployments delete {name}
```

### 実際に負荷試験環境の構築で使ったテンプレートファイル構成
以下は、実際に担当サービスで負荷試験環境を構築する際の構成になります。

```
# ディレクトリ構成
.
|-- README.md
|-- helpers
|   `-- common.jinja
|-- templates
|   |-- load-compute-engine.jinja
|   |-- load-disk.jinja
|   |-- load-firewall.jinja
|   |-- load-network.jinja
|   |-- load-vm-external-xfs.jinja
|   `-- load-vm.jinja
`-- load.yaml
```
それぞれのディレクトリ（テンプレートファイル）は以下の様に使い分けています。

#### helpers
共通的に使われるテンプレート

- common.jinja
  - serverのhostname生成用テンプレート
  - test-hoge-web-001（{Env}-{ServiceName}-{ServerType}-{ServerCount}）

```
{%- macro GenerateMachineName(Env='UNKNOWN', ServerGroup='UNKNOWN', ServerType='UNKNOWN', ServerCount=0) -%}
{{ Env }}-ServiceName-{{ ServerType }}{% if ServerGroup != 'common' %}-{{ ServerGroup }}{% endif %}{% if ServerCount > 0 %}-{{ "{0:0>3}".format(ServerCount) }}{% endif %}
{%- endmacro -%}
```

#### templates
各リソース毎のテンプレート

- load-compute-engine.jinja
  - サーバタイプ毎に違う値などをプロパティに記述している（変数として使える様にするため）
  - サーバタイプ毎のインスタンス数などもここで指定している
- load-disk.jinja
  - 外部ディスクの設定
  - `load-compute-engine.jinja` で設定した値を変数として埋め込んでいる
- load-firewall.jinja
  - firewallの設定
  - サーバタイプ毎のアクセス制限などもタグを使ってここで設定する
- load-network.jinja
  - ネットワークの設定
- load-vm-external-xfs.jinja
  - 外部ディスクを使うインスタンスの設定
  - あえて `load-vm.jinja` と分けてます
  - シンプルな記述を意識して分岐を減らすために別にしている
- load-vm.jinja
  - インスタンスはfor文を使って必要な台数を生成する様な記述にしている

#### load.yaml
実行ファイル

- load.yaml
  - 主に各リソーステンプレートのインポートのみ記述している

## まとめ
GCPの場合、Terraformを使う選択肢もあると思いますが、以下の点で今回はCloud Deployment Managerを使う事にしました。

- ほぼ全リソースの設定がファイル管理できる
  - 全リソースをDeployment Managerで管理できますが、すると辛みが増えるので基本静的なリソースのみ管理するのが良いと思います。
- プレビュー機能があり、Webコンソールからも変更点が確認できる
  - terraformでもplan出来るけど、実際applyしたら動かねーよって事があったんで、これは幸せですw
- YAML・Python・Jinja2で記述できるので、冗長的な記述を省く事ができる
  - 条件式とかループは適材適所にしないと、後々最初にテンプレート作った人しか弄れないって事になったりするので、出来る限りシンプルにする事をオススメします。
- 状態管理ファイル（Terraformでいう.tfstate）の管理に悩まなくて済む
  - これは本当にありがたい！！
- Google謹製なんで、最新機能がわりと早めに使える
  - 
まだ正直そこまで需要がないですが、将来的にはあるかもw


<b>個人的には、ハイブリッドな案件でなく、使うのがGCPだけだったら
Cloud Deployment Managerを使うという選択肢も１つとしては、ありかなと思いました。</b>

### ぼやき
構成管理ツールが出てきた事によりインフラ側とアプリ側の境界がなくなっていくのは、とてもいい事だと思ってます。
しかし、だからといって、全部を管理しようとするのは間違い（苦しみが増えるだけ）で、本当にこの辺は適材適所であるべきだと思います。
個人的には、運用フェーズを意識した上で、必要最低限なものだけを管理する事をオススメします！

作り込みすればするほど、その苦しみも増える状況だったりするので。。。
実際に、作り込みしすぎて、逆にコードが読みにくいという事があったりで、何回もテンプレートの構成変更を繰り返してます。（現在も）

Cloud Deployment Managerに関する情報が、他の構成管理ツールに比べはるかに少ないので、今後使い込んでいった上で有益な情報などあれば書く予定です。
長々と書いたわりには、有益な情報がほぼなくて、すいません＞＜

10日目は、sitotkfmさんです。