いまさらで物凄く恐縮ですが、cloud-initについて勉強してみた

# はじめに
本稿は、`cloud-init`　に関して、`ふわ` っとしたイメージしか持っていなかった私が、自身の記録用にまとめたノートを投稿しているだけですので、エキスパートの方は参考にしないでください。初学者の方にとっては、比較的わかりやすい内容にまとめているつもりです。

# cloud-initとは

cloud-initは、cloud instanceの初期化メソッドで、様々なクラウドベンダーをサポートしています。
元々、EC2用に作成されたもので、`ec2-init` というパッケージ名だったそうです。
ドキュメントは、[こちら](https://cloudinit.readthedocs.io/en/latest/)です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133151/bd93827e-48a4-5dc4-9c32-3a8ea47a6673.png)

インスタンスの初期設定に必要な、アカウント、リポジトリ設定、パッケージのインストールなど様々な機能もありますし、任意のスクリプトを実行する事も可能です。（CA証明書インストール作業とか、結構楽かも。）
cloud-initは `#cloud-config`で始まる、`ユーザーデータ` などを受け取り、初期セットアップを行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133151/4c1be9dc-a7b8-abfb-9d73-8a78588f292c.png)

cloud-configは、YAML形式で記述します。
例えば、以下でユーザーを作成します。

```
#cloud-config
users:
  - default
  - name: foobar
    gecos: Foo B. Bar
    primary_group: foobar
    groups: users
    selinux_user: staff_u
    expiredate: 2012-09-01
    ssh_import_id: foobar
    lock_passwd: false
    passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYC
```


# 使い分け
構成管理ツールとして、ChefやAnsible、puppetなどがありますが、それらの使い分けに関してまとめてみました。
以下の画像がわかりやすいと思います。
AnsibleやChefなどと被るところがありますが、`初期セットアップ` という観点で使う場合は、 `cloud-init` を利用すればいいのではないかと考えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133151/17565010-9d5f-0267-6e30-ac77d6aaf13b.png)

terraformで、新たにインスタンスをプロビジョニング、cloud-initで初期セットアップ、Ansibleで構成管理といった連携など考えられます。

# Boot Stage
cloud-initのboot stageは以下、5つに分かれています。

- Generator
- Local
- Network
- Config
- Final

`Generator` では、cloud-initを実行するか否かの決定をします。実行する場合、`Local`ではメタデータに格納されているネットワーク情報を適用します。`Network`ではdisk_setupを実行しmodulesをマウントします。`Config`では、config_moduleのみをrunします。`Final`は一番最後に実行されます。ユーザーログイン後にRunする必要のあるスクリプトはここに記述する必要があります。

それぞれのステージは、以下のコマンドで確認できます。

```
$ cloud-init status --long
status: running
time: Fri, 26 Jan 2018 21:39:43 +0000
detail:
Running in stage: init-local
```

[モジュール郡](https://cloudinit.readthedocs.io/en/latest/topics/modules.html)はそれぞれが上記のStageに紐づいています。例えば、`Bootcmd` は、`cloud_init_modules`に属しており、boot毎に実行されます。
`scripts-per-boot`では、`cloud_final_modules`に属しており、こちらもboot毎に実行されます。これらは実行のタイミングが異なるので、それを意識した上での記述が必要です。
ドキュメントには、

> ブートプロセスの後半で実行できない処理にのみ使用してください。

と書いてあったので、上記でない限りは、 `cloud_init_modules` 内で処理をした方が良いみたいです。

注意としては、再起動プロセスは `runcmd` で記述の記述がおすすめ。（runcmdは、config_modulesですが、Final Stageで実行されます。）

# デバッグ
まず、cloud-initのディレクトリ情報は以下の通りになっていました。

```
$ tree --charset=x /var/lib/cloud/ -L 2
/var/lib/cloud/
|-- data
|   |-- instance-id
|   |-- previous-datasource
|   |-- previous-instance-id
|   |-- result.json
|   |-- set-hostname
|   `-- status.json
|-- handlers
|-- instance -> /var/lib/cloud/instances/ocid1.instance.oc1.iad.***********
|-- instances
|   `-- ocid1.instance.oc1.iad.***********
|-- scripts
|   |-- per-boot
|   |-- per-instance
|   |-- per-once
|   `-- vendor
|-- seed
`-- sem
```

instanceのcloud-config.txtには、cloud-configの情報が格納されていました。
（これってプロビジョニング後からruncmdなどの記述を変更をしていいのかな。）

```
$ cat cloud-config.txt 

#cloud-config

# from 1 files
# part-001

---
cloud_final_modules:
-   - scripts-user
    - always
locale: ja_JP.utf8
package_upgrade: true
packages:
- man-pages-ja
- multitail
- nmap
- nc
- tmux
- tree
runcmd:
-   - sh
    - -c
    - echo $(date) >> /tmp/testfile.txt
timezone: Asia/Tokyo

```

また実行ログは、`/var/log/cloud-init.log` に格納されます。基本的に実行確認などは、ここを見ればOKだと思います。

```
$ cat /var/log/cloud-init.log | grep config-timezone
2020-05-17 16:28:37,630 - handlers.py[DEBUG]: start: modules-config/config-timezone: running config-timezone with frequency once-per-instance
2020-05-17 16:28:37,635 - helpers.py[DEBUG]: Running config-timezone using lock (<FileLock using file '/var/lib/cloud/instances/ocid1.instance.oc1.iad.anuwcljrejk3llyct26xrjijj74qh5i6cgtd33i7575zupmk5g74hk4o7cqa/sem/config_timezone'>)
2020-05-17 16:28:37,636 - handlers.py[DEBUG]: finish: modules-config/config-timezone: SUCCESS: config-timezone ran successfully
```

もしくは以下のような形で、ログ情報を出力する事も可能です。

```
runcmd:
-   - sh
    - -c
    - echo $(date) >> /tmp/testfile.txt
```

```
$ cat /tmp/testfile.txt
Mon May 18 01:28:38 JST 2020
2020年 5月 18日 月曜日 01:36:08 JST
```

# 最後に
初学者としてのcloud-initの私なりの理解をまとめました。
windowsOSをサポートしているcloudbase-initに関してのドキュメントは充実していないようなので、今後そのあたりのまとめ記事など投稿したいなと考えています。

# 参考情報
[Amazon Linuxのcloud-initの実行順番を確認する](https://dev.classmethod.jp/articles/probe-cloud-init-exec-timing/)
[cloud-initを使ったLinux OSの初期設定](https://qiita.com/yamada-hakase/items/40fa2cbb5ed669aaa85b)
[cloud-initをデバッグする Part 1](https://qiita.com/yamada-hakase/items/b42aed68e5623ed74024)