仮想マシンの初期設定をするcloud-init

cloud-initとは

OpenStackやAWSのEC2などIaaSを利用しVM(Virtual Machine)の払い出しをした後、ユーザアカウントの作成やソフトウェアのインストールなどの初期設定を自動化したくなる。

構成管理ツールとしてAnsibleやChefが存在し、ロールベースの複雑なセットアップはこういったツールの担当となるが、構成管理ツールを利用するまでの最低限の初期セットアップはどうしても発生してしまう。 そんなときに利用するのがloud-initという仕組みで、これを利用することクラウドプロバイダーから払い出したVMの初期セットアップを自動化することができる。

clud-initは各クラウドプラットフォームに依存することなくVM起動後に対し指定したユーザの作成やssh鍵の設定、任意のコマンドを実行するための共通インターフェースを提供している。

またcloud-initはUbuntuでおなじみのCanonicalが主体となって開発するオープンソースプロジェクトで特定のディストリビューションに依存することなく利用することができる。

処理の流れ

セットアップに使用する情報の入力

cloud-initは対象VMにインストールするOSイメージにcloud-initパッケージが含まれている必要があるが、各ディストリビューションが公開してるcloud imageには最初からインストーされている。

cloud-initは入力となる設定ファイルを何かしらの方法で受け取りそれをもとにセットアッププロセスを実行する。 設定ファイルの取得元(データストアと表現される)は様々でかくクラウドプロバイダに依存したものから、CDROMイメージを利用する汎用的な仕組みまで存在する。

例えばAWSのEC2を例に上げると、インスタンス起動後にcloud-initのプロセスはhttp://169.254.169.254/${EC2-VERSION}/meta-data/にアクセスすることによって、実行に必要なデータを取得する。このあたりの処理はcloud-initの実装ではdatasourceとして抽象化されているため、メイン処理中では意識する必要はない。

入力となるデータは主に3つに分類される cloud-intでは設定内容はユーザから指定されたデータによって具体的にセットアップ内容を指定することができる。そのデータはメタデータ、ユーザデータ、ベンダデータに区別され、それぞれの内容を統合して最終的な実行内容を判断する。 - メタデータ - クラウドプロバイダーによって提示されるデータでVM名やアーキテクチャ、ディストリビューションなどプロパイダによって差異はあるが様々なインスタンス特有のデータがAPIを経由してアクセスできるようになっている。 - ユーザデータ - 実行してほしい指定したシェルスクリプトや、初期セットアップにに必要な引数などがユーザから渡される。 - ベンダデータ - クラウドプロバイダーから提供されているデータ。クラウドプロバイダーで必要となる特定の設定を挿入することができる。ユーザデータでベンダデータで提供されている項目を上書きすることができる。

セットアップの実行

ドキュメントによるとcloud-initは5つのboot stageから構成されており以下の順で実行される。

  1. Generator:
    • systemdの仕組みでcloud-initのGenerator以降の実行の必要があるかを決定する
    • 以下の場合はcloud-initは実行されない
      • /etc/cloud/cloud-init.disableが存在する場合
      • カーネル引数にcloud-init=disabledが指定されている場合
  2. Local
    • local datastorceを検索してネットワーク設定を適用する。
    • 以降の処理でネットワーク利用の利用が可能な状態にする。
  3. Network
    • ユーザデータを読み込みcloud_init_modulesのモジュールを実行する。
    • syslogやホスト名の設定が実施される。
  4. Config
    • cloud_config_modulesを実行する。
    • システムの起動前に必要なssh関連の設定, ディスク構成のセットアップ, タイムゾーンの設定などをが含まれる。
  5. Final
    • cloud_final_modulesを実行する。
    • システムの起動後に実行するスクリプトやパッケージの追加を実施する。

起動スクリプトの確認

上記までのセットアップの流れが実際にどのように記述されているのかをcloud-initをインストールした筐体で確認する。 まずcloud-init関連のサービスとして以下のものが登録されているようだ。

$ systemctl list-unit-files --type=service  |grep cloud-
cloud-config.service                                        enabled         disabled
cloud-final.service                                         enabled         disabled
cloud-init-hotplugd.service                                 static          -
cloud-init-local.service                                    enabled         disabled
cloud-init.service                                          enabled         disabled

上記のサービスは各boot stageに対応する。例えばcloud-init.servicecloud-init-local.serviceの後に実行され/usr/bin/cloud-init initを実行していることがわかる。

# /usr/lib/systemd/system/cloud-init.service
[Unit]
Description=Initial cloud-init job (metadata service crawler)
DefaultDependencies=no
Wants=cloud-init-local.service
Wants=sshd-keygen.service
Wants=sshd.service
After=cloud-init-local.service
After=systemd-networkd-wait-online.service
After=network.service
After=NetworkManager.service
Before=network-online.target
Before=sshd-keygen.service
Before=sshd.service
Before=systemd-user-sessions.service

[Service]
Type=oneshot
ExecStart=/usr/bin/cloud-init init
RemainAfterExit=yes
TimeoutSec=0

# Output needs to appear in instance console output
StandardOutput=journal+console

[Install]
WantedBy=cloud-init.target

また各ステージでの具体的な実行内容については/etc/cloud/cloud.cfgに定義されている。

# The modules that run in the 'init' stage
cloud_init_modules:
 - migrator
 - seed_random
 - bootcmd
 - write-files
 - growpart
 - resizefs
 - disk_setup
 - mounts
 - set_hostname
 - update_hostname
 - update_etc_hosts
 - ca-certs
 - rsyslog
 - users-groups
 - ssh

# The modules that run in the 'config' stage
cloud_config_modules:
 - ssh-import-id
 - keyboard
 - locale
 - set-passwords
 - spacewalk
 - yum-add-repo
 - ntp
 - timezone
 - disable-ec2-metadata
 - runcmd

# The modules that run in the 'final' stage
cloud_final_modules:
 - package-update-upgrade-install
 - write-files-deferred
 - puppet
 - chef
 - mcollective
 - salt-minion
 - reset_rmc
 - refresh_rmc_and_interface
 - rightscale_userdata
 - scripts-vendor
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - scripts-user
 - ssh-authkey-fingerprints
 - keys-to-console
 - install-hotplug
 - phone-home
 - final-message
 - power-state-change

各ステージで実行するモジュールは下記に実装されている。 - https://github.com/canonical/cloud-init/tree/main/cloudinit/config

まとめ

cloud-initは各クラウドプロバイダーを経由しクラウドプロバイダーやユーザからの設定の入力を共通化している。 そして実行タイミングの異なるステージで設定内容を反映した形で、セットアップスクリプトを実行するという動作になっている。

次回は実際にcloud-initを動作させてみる。