1. はじめに
クラウドでComputeインスタンス作成時にUserd Data(cloud-init)を指定すると、OS設定をカスタマイズできる。ただし設定が終わるまでには、タイムラグがあることを理解する必要がある。今回はその理由を探ってみる。
なおcloud-initの内部動作の詳細は次のエントリで説明している。
1-1. 検証環境
今回はOracle Cloud InfrastructureでOracle Linux 7を使用しているが、Linuxであれば他のクラウドでもほとんど同じだ。
- Oracle Cloud Infrastructure Compute
- Oracle Linux 7.6
- cloud-init-18.4-1.el7.x86_64
2. User Dataが実行される仕組み
User Dataの内容を実行しているのはcloud-initで、OSのサービスとして実装されている。その内容を調べてみる。
2-1. cloud-initを構成するサービス群
サービスを確認するとcloudで始まる4つのサービスがある。この中でも中心となるのはcloud-config.service
である。
$ systemctl list-unit-files --type service| grep ^cloud
cloud-config.service enabled ★これ
cloud-final.service enabled
cloud-init-local.service enabled
cloud-init.service enabled
2-2. cloud-config.serviceの中身を確認する
サービスの内容を定義したユニットファイルを確認する。systemctl cat
で表示できるが、実体のファイルは/usr/lib/systemd/system/
配下に存在する。
$ systemctl cat cloud-config.service
ここで重要なのはAfter
である。After
は起動順序を定義するディレクティブで、指定したユニットがアクティブになってから起動することを表す。またnetwork-online.target
は特別なターゲットで、ネットワークサービスがオンラインになったことを表す。
# /usr/lib/systemd/system/cloud-config.service
[Unit]
Description=Apply the settings specified in cloud-config
After=network-online.target cloud-config.target ★
Wants=network-online.target cloud-config.target
ConditionPathExists=!/etc/cloud/cloud-init.disabled
ConditionKernelCommandLine=!cloud-init=disabled
[Service]
Type=oneshot
ExecStart=/usr/bin/cloud-init modules --mode=config
RemainAfterExit=yes
TimeoutSec=0
# Output needs to appear in instance console output
StandardOutput=journal+console
[Install]
WantedBy=multi-user.target
つまり以下のように定義した場合、ネットワークが完全にオンラインになったあとにcloud-config.service
を実行することを表す。
After=network-online.target cloud-config.target
2-3. sshd.serviceの中身を確認する
さらにsshd.service
の中身を確認する。するとAfter
ディレクティブにはnetwork.target sshd-keygen.service
が設定されている。
$ systemctl cat sshd
# /usr/lib/systemd/system/sshd.service
[Unit]
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target sshd-keygen.service ★
Wants=sshd-keygen.service
[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target
2-4. cloud-initとsshdではどちらが早い
両方のAfter
ディレクティブの内容は似ているが、わずかに違いがある。詳細はwiki/Software/systemd/NetworkTargetを参照のこと。
- network.target:ネットワークスタックが起動したこと(sshd.serviceで指定)
- network.online:ネットワークスタックが起動し、IPアドレスが割り当てられたこと(cloud-config.serviceで指定)
つまり起動順序としては、sshdのほうがわずかに早いか、ほぼ同時に起動されることになる。
3. User Dataの実行が遅れる理由
ここまで来て、理由がわかったと思う。User Dataの内容はcloud-initのサービス群で設定される。ネットワークが起動したあとに実行されるので、
「パッケージのアップデート」のような時間のかかる処理を含んでいると、sshログインしてもUser Dataの内容が反映されていない
ということが起こりえる。しかし実行中なので、いずれ設定される。
またわずかにsshdのほうが起動順序は早いが、これは誤差の範囲だろう。User Dataに重い処理が含まれているかどうかがポイントになる。
3-1. Kickstartとの違いを理解する
今回の件はKickstartに慣れていると戸惑う人も多いだろう。Linuxインストール時に設定をカスタマイズする手段としてはKickstartが標準的だ。あらかじめ作成した設定したファイル(Kickstartファイル)をOSのインストーラーに食わせることで、自動的に設定を済ませる機能である。サイレントインストールの仕組みと言い換えてもいいだろう。
つまりKickstartはインストールプロセスで使用するため、OSが起動した段階で、設定したすべての内容が有効になっている。それに対してcloud-initは、ネットワークが起動したあとに実行されるので、sshログインできても、まだ設定中の可能性がある。
なおKickstartファイルは、RHEL系のディストリビューションであれば、/root/anakonda-ks.cfg
にある。ただしクラウドベンダ提供のイメージでは削除されていることもある。
3-2. cloud-initが終わったことを知る方法
cloud-initは/var/log/cloud-init.log
にログを出力する。大量に出力されるので、内容を理解するのは困難だが、次のように finish: modules-final
の行が表示されれば終了している。
# tail -f /var/log/cloud-init.log
★ここから下は画面の出力★
2019-05-16 13:04:25,343 - util.py[DEBUG]: Read 14 bytes from /proc/uptime
2019-05-16 13:04:25,343 - util.py[DEBUG]: cloud-init mode 'modules' took 0.208 seconds (0.21)
2019-05-16 13:04:25,344 - handlers.py[DEBUG]: finish: modules-final: SUCCESS: running modules for final
4. まとめ
- クラウドのCompute(IaaS)でUser Dataを指定したとき、起動直後には設定内容がすぐに反映されないことがある
- 遅れる原因は、User Dataの基盤となるcloud-initはLinuxのサービスとして実装されているので、ネットワークが起動したあとに設定が実行されるから
- User Dataで時間のかかる処理を記述したときは、ある程度待ってから設定を確認する
- Kickstartとは、まったく違う仕組みであることを理解する