systemd管理の cloud-init を手動で再実行する

systemd から起動される cloud-init を手動で再実行したいときの手順。

# 環境
 * CentOS 8.2.2004
   * (CentOS-8-GenericCloud-8.1.1911-20200113.3.x86_64.qcow2 をベースに dnf update したもの)
 * cloud-init-19.4-1.el8.7.noarch


# 再実行の手順

```shell-session:cloud-init再実行の手順
$ sudo systemctl stop cloud\*
$ sudo cloud-init clean
$ sudo systemctl start cloud-init.target
```

これだけで良さそう。状態確認の手順やもう少し詳細な動きについては以下を参照。



# 背景

とあるプロビジョニングツールでプロビジョニングをしようとしていたところ、cloud-init のユーザスクリプトの途中でよくわからない処理失敗が出ていたので、解析のために手動で再実行したい、というのが発端。

手動でcloud-initを再実行する手順は[参考情報](#参考情報)に情報があり、シェルから cloud-init コマンドを直接実行する手順が紹介されていたが、自分の場合 systemd 経由で再実行させたかった。

その理由は、プロビジョニングツールが systemd の環境変数に追加設定を行っているようで、シェルから実行した場合と環境変数設定が異なっているため。具体的には PATH とか。

```shell-session:シェルの環境変数
# env | grep PATH
PATH=/sbin:/bin:/usr/sbin:/usr/bin
```
```shell-session:systemdの環境変数
# systemctl show-environment | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
```

もちろんこれだけならシェルのPATH環境変数を設定するだけで良いのだけど、他にもどこで差異の影響が出てくるかわからなかったので、「systemdさんから実行してもらいたいなあ」と思った次第。

# 再実行例と確認手順

再実行前の段階では cloud-init 関連のサービスの状態は以下となっていた。
すべて Type=oneshot で実行されているらしい。

```shell-session:再実行前の状態確認
$ systemctl list-units --all cloud\*
UNIT                     LOAD   ACTIVE   SUB    DESCRIPTION
cloud-config.service     loaded active   exited Apply the settings specified in cloud-config
cloud-final.service      loaded active   exited Execute cloud user/final scripts
cloud-init-local.service loaded active   exited Initial cloud-init job (pre-networking)
cloud-init.service       loaded active   exited Initial cloud-init job (metadata service crawler)
cloud-config.target      loaded active   active Cloud-config availability
cloud-init.target        loaded inactive dead   Cloud-init target
```

cloud-init関連のサービスをいったん全部停止する。

```shell-session:cloud-init関連のサービス停止および状態確認
$ sudo systemctl stop cloud\*
$ systemctl list-units --all cloud\*
UNIT                     LOAD   ACTIVE   SUB  DESCRIPTION
cloud-config.service     loaded inactive dead Apply the settings specified in cloud-config
cloud-final.service      loaded inactive dead Execute cloud user/final scripts
cloud-init-local.service loaded inactive dead Initial cloud-init job (pre-networking)
cloud-init.service       loaded inactive dead Initial cloud-init job (metadata service crawler)
cloud-config.target      loaded inactive dead Cloud-config availability
cloud-init.target        loaded inactive dead Cloud-init target
```

次に cloud-init 実行状態を初期化する。

cloud-initの実行状態は ```/var/lib/cloud```配下に保存されおり、ここをクリアしないと再実行されないらしい。[参考情報](#参考情報)ではこのディレクトリ配下を全部消したり instance だけ消したりする方法も紹介されているが、 ```cloud-init clean```コマンドが一番お行儀が良さそうなのでこれを採用。

```shell-session:cloud-init実行状態のクリア
$ ls /var/lib/cloud
data  handlers  instance  instances  scripts  seed  sem
$ sudo cloud-init clean
$ ls /var/lib/cloud
seed
$
```

そして cloud-init サービスを再実行する。再実行中の実行ログは ```/var/log/cloud-init-output.log```で確認できる。

```shell-session:cloud-initの再実行および状態確認
$ sudo systemctl start cloud-init.target
$ systemctl list-units --all cloud\*
UNIT                     LOAD   ACTIVE SUB    DESCRIPTION
cloud-config.service     loaded active exited Apply the settings specified in cloud-config
cloud-final.service      loaded active exited Execute cloud user/final scripts
cloud-init-local.service loaded active exited Initial cloud-init job (pre-networking)
cloud-init.service       loaded active exited Initial cloud-init job (metadata service crawler)
cloud-config.target      loaded active active Cloud-config availability
cloud-init.target        loaded active active Cloud-init target
```
```shell-session:cloud-init実行ログの確認
$ tail -f /var/log/cloud-init-output.log
(...)
Cloud-init v. 19.4 running 'modules:final' at Thu, 27 Aug 2020 02:35:46 +0000. Up 88132.66 seconds.
Cloud-init v. 19.4 finished at Thu, 27 Aug 2020 02:36:33 +0000. Datasource DataSourceConfigDrive [net,ver=2][source=/dev/sda2].  Up 88180.39 seconds
```

# cloud-init 関連サービスの補足

cloud-init 関連サービスは以下の依存関係の順序で起動されている模様。それぞれの処理を個別に確認したい場合にはサービスを順番に一つ一つ起動していけば良さそう(今回はそこまではやっていない)。

 1. ```cloud-init-local.service```
 2. ```cloud-init.service ```
 3. ```cloud-config.target ```
 4. ```cloud-config.service ```
 5. ```cloud-final.service ```
 6. ```cloud-init.target ```

```shell-session:サービス依存関係の関連設定
$ (cd /usr/lib/systemd/system/; grep "^After=.*cloud" cloud-* )
cloud-config.service:After=network-online.target cloud-config.target
cloud-config.target:After=cloud-init-local.service cloud-init.service
cloud-final.service:After=network-online.target cloud-config.service rc-local.service
cloud-init.service:After=cloud-init-local.service
$ (cd /usr/lib/systemd/system/; grep "^WantedBy=.*cloud" cloud-* )
cloud-config.service:WantedBy=cloud-init.target
cloud-final.service:WantedBy=cloud-init.target
cloud-init-local.service:WantedBy=cloud-init.target
cloud-init.service:WantedBy=cloud-init.target
$
```


# 参考情報

* [cloud-init のスクリプトを reboot せずに再実行するには](https://qiita.com/sonots/items/e60261ea28c61e322631)
* [How to re-run cloud-init without reboot](https://stackoverflow.com/questions/23065673/how-to-re-run-cloud-init-without-reboot)