cloud-initのデフォルト挙動を徹底的に調べてまとめてみた -結果ソースコードを読んだ-

アイキャッチ AWS EC2

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

コンニチハ、千葉です。

AWSを利用していればcloud-initをご存知の方が多いと思います。ただ、「cloud.cfg上から説明して!」とか言われたら困ると思います。

なにせ、ぐぐってもあまり情報がありません。公式のドキュメントを読んでも設定方法やモジュール名は書いているのですがモジュールがデフォルトでどんな挙動するのか読み取れませんでした。なので、ソースコード(主にコメントw)頑張って読んでまとめました。

初期構築等で設定だけしたいのであれば、このページを見ればいけると思います。

cloud-initの実行タイミング

ふわっと、初回起動みたいに覚えている方もいると思います。実際には初回起動以外にも実行タイミングがあります。

  • 一生に?1回だけ実行されるもの
  • インスタンスごとに実行されるもの(AMI作成し、そこからインスタンスを作成した時)
  • 起動時に毎回実行されるもの

ソースで、「frequency」にPER_INSTANCE, PER_ALWAYS, PER_ONCEのいづれかを指定することで挙動が変わるようでした。

また、cloud.cfgではモジュールを複数指定してあり、それぞれ実行タイミングが違います。デフォルトでは以下の順番で実行されます。

  1. cloud_init_modules
  2. cloud_config_modules
  3. cloud_final_modules

表でまとめてみた

デフォルトでの実行される内容、実行タイミングや、挙動(「-」実行されてみ何も変更しない)、パラメータをまとめてみました。

ただしRHEL6.5のcloud.cfgを元にしてるので、amazon linuxなどの別ディストリビューションでは内容が異なる箇所があると思うのでそこは考慮して参照ください!

各モジュールの実行タイミング(RHEL5.6 デフォルト)

※スマフォだと表が切れますので、画面を横にするか、PCで御覧ください

実行タイミング

No

項目

1回のみ

インスタンス毎

boot毎

デフォルト挙動

1

boot時に指定したコマンドを実行

-

2

指定ファイルへの書き込み

-

3

「/」のファイルシステムを拡張

ファイルシステムを拡張

4

ホスト名の設定(/etc/sysconfig/network)

ホスト名を設定

5

ホスト名の設定※モジュールがupdate_hostnameの方(/etc/sysconfig/network)

ホスト名を設定

6

「/etc/hosts」の設定

-

7

rsyslogの設定

-

8

ユーザ・グループ作成

ec2-userを作成する

9

sshでのrootでのログイン設定

rootログイン無効

10

sshのパスワードログイン設定

パスワードログイン無効

11

sshキー(/etc/ssh/ssh_host_*key*)の削除

-

12

sshdのキータイプを指定

-

13

マウントの設定

-

14

言語設定

en_US.UTF-8に設定

15

ユーザーパスワードを設定

-

16

タイムゾーンの設定

-

17

構成管理ツールの設定と起動(puppet)

-

18

構成管理ツールの設定と起動 (chef)

-

19

構成管理ツールの設定と起動(salt-minion)

-

20

構成管理ツールの設定と起動 (mcollective)

-

21

メタデータアクセス制御

アクセス可能

22

指定コマンドの実行

-

23

rightscaleをユーザーデータで設定

-

24

1回だけスクリプトを実行(/var/lib/cloud/scripts/per-once)

-

25

boot毎にスクリプトを実行(/var/lib/cloud/scripts/per-boot)

-

26

インスタンス毎にスクリプトを実行(/var/lib/cloud/scripts/per-instance)

-

27

ユーザー定義のスクリプトを実行(/var/lib/cloud/scripts/vendor)

-

28

sshフィンガープリントをconsole(システムログ)に出力する

システムログに出力

29

sshフィンガープリントをconsole(システムログ)の出力フィルタリング

-

30

boot完了時に指定したURLにリクエストを投げる

-

31

cloud-init完了ログをconsole(システムログ)に出力する

システムログに出力

32

「/var/log/cloud-init.log」のパーミッションを設定

-

モジュール一覧(RHEL5.6 デフォルト)

No

項目

モジュール

1

boot時に指定したコマンドを実行

cloud_init_modules

bootcmd

2

指定ファイルへの書き込み

write-files

3

「/」のファイルシステムを拡張

resizefs

4

ホスト名の設定(/etc/sysconfig/network)

set_hostname

5

ホスト名の設定(/etc/sysconfig/network)

update_hostname

6

「/etc/hosts」の設定

update_etc_hosts

7

rsyslogの設定

rsyslog

8

ユーザ・グループ作成

users-groups

9

sshでのrootでのログイン設定

ssh

10

sshのパスワードログイン設定

ssh

11

sshキー(/etc/ssh/ssh_host_*key*)の削除

ssh

12

sshdのキータイプを指定

ssh

13

マウントの設定

cloud_config_modules

mounts

14

言語設定

locale

15

ユーザーパスワードを設定

set-passwords

16

タイムゾーンの設定

timezone

17

構成管理ツールの設定と起動(puppet)

puppet

18

構成管理ツールの設定と起動 (chef)

chef

19

構成管理ツールの設定と起動 (salt-minion)

salt-minion

20

構成管理ツールの設定と起動 (mcollective)

mcollective

21

メタデータアクセス制御

disable-ec2-metadata

22

指定コマンドの実行

runcmd

23

rightscaleをユーザーデータで設定

cloud_final_modules

rightscale_userdata

24

1回だけスクリプトを実行(/var/lib/cloud/scripts/per-once)

scripts-per-once

25

boot毎にスクリプトを実行(/var/lib/cloud/scripts/per-boot)

scripts-per-boot

26

インスタンス毎にスクリプトを実行(/var/lib/cloud/scripts/per-instance)

scripts-per-instance

27

ユーザー定義のスクリプトを実行(/var/lib/cloud/scripts/vendor)

scripts-user

28

sshフィンガープリントをconsole(システムログ)に出力する

ssh-authkey-fingerprints

29

sshフィンガープリントをconsole(システムログ)の出力フィルタリング

keys-to-console

30

boot完了時に指定したURLにリクエストを投げる

phone-home

31

cloud-init完了ログをconsole(システムログ)に出力する

final-message

32

「/var/log/cloud-init.log」のパーミッションを設定

初期化処理

AMIからEC2をリストアするときに何も変更したくない場合はどうすればよいの?

表を見ると、AMIからEC2を作成した場合にデフォルトで変更される箇所は以下となります。

  • /etc/sysconfig/networkのホスト名がfqdnに書き換えられる(例:ip-12-34-56-78.us-west-2.compute.internal)
  • ec2-userを作成する
  • /etc/ssh/sshd_configを書き換え、パスワードログイン無効、rootログイン無効化を行う
  • localeを「en_US.UTF-8」に設定する

変更させない場合の対応策としては以下2つあります。

userdataで頑張る

userdataに以下を入力してAMIを作成

#cloud-config
preserve_hostname: True # ホスト名を変更させない
disable_root: True # rootログインを有効化したい場合はFalse
ssh_pwauth: False # パスワードログインを有効化したい場合はTrue
locale: ja_JP.UTF-8  # 任意のlocaleを指定

あとは、ec2-userは作成されてしまうので手動で削除を行う

cloud-initの初期化をそもそも実施させない

cloud-initの設定ファイル(/etc/cloud/cloud.cfg)を変更する 以下の個所をコメントアウトする

- set_hostname
- update_hostname
- sers-groups
- ssh
- locale

(参考)ソースコードにコメント入れてみた

## (前半)実行モジュールのパラメータを指定する
### defaultで指定したユーザーを作成
users:
- default

### sshでのrootでのログインを無効にする
disable_root: 1

### sshのパスワードログインを無効化
ssh_pwauth: 0

### locale設定ファイルのパスを指定
locale_configfile: /etc/sysconfig/i18n

### mountsを設定(fstabを設定するエントリ)するときのデフォルトの値(指定しないとこの値が設定される)
mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2']

### /devが存在しない場合、ディレクトリを作成する(ソース読んだのですが自信はないです)
resize_rootfs_tmp: /dev

### sshの「/etc/ssh/ssh_host_*key*」を削除※default無効
ssh_deletekeys: 0

### 「ssh-keygen -t」で利用するキータイプ(rsa,dsa,ecdsa)を指定
ssh_genkeytypes: ~

### 「/var/log/cloud-init.log」のユーザー:グループを指定
syslog_fix_perms: ~

## (後半)実行するモジュールを指定する(前半戦)

cloud_init_modules:

### ブートプロセス時にコマンドを実行
#### コマンドを指定する場合の指定例
####bootcmd:
####- echo 192.168.1.130 us.archive.ubuntu.com > /etc/hosts
####- [ cloud-init-per, once, mymkfs, mkfs, /dev/vdb ]
- bootcmd

### ファイル書き込み
- write-files

### /のファイルシステムを拡張する
- resizefs

### ホスト名を設定する(/etc/sysconfig/networkのホスト名を書き換える)
- set_hostname

### ホスト名を設定する(/etc/hostnameのホスト名を書き換える)※起動時に毎回実行されるはずだがRHEL6.5では動いてない模様?
- update_hostname

### ホスト名を設定する(テンプレートでの指定やlocalhost等の指定が可能)
- update_etc_hosts

### rsyslogの設定変更を行う(デフォルトでは何もしない)
- rsyslog

### ユーザー・グループの作成を行う(デフォルトではdefaultで指定されているec2-userを作成する)
- users-groups

### sshの設定を行う(デフォルトではrootログイン、パスワードログインの無効化)
- ssh

cloud_config_modules:

### fstabの設定を行う(エフェメラル等やswapの設定を行うがrhelの場合デフォルトでは何もしない)
- mounts

### localeの設定を行う(デフォルトはen_US.UTF-8に初期化される)
- locale

### ユーザーのパスワードを設定(デフォルトは何も実施しない)
- set-passwords

### タイムゾーンの設定(デフォルトでは何も実施しない)
- timezone

### 構成管理ツールの設定と起動を行う。デフォルトでは何も実施しない
- puppet
- chef
- salt-minion
- mcollective

### メタデータアクセスを拒否ができないように設定する(デフォルトfalseでメタデータにアクセスできる状態)
- disable-ec2-metadata

### 指定したコマンドを実行する(デフォルト何もしない)
- runcmd

cloud_final_modules:

### rightscaleをユーザーデータで設定
- rightscale_userdata

### 一回だけスクリプトを実行(/var/lib/cloud/scripts/per-onceのスクリプト)
- scripts-per-once

### 起動毎に実行(/var/lib/cloud/scripts/per-bootのスクリプト)
- scripts-per-boot

### AMIからインスタンス作成時の初回起動時だけスクリプトを実行(/var/lib/cloud/scripts/per-instanceのスクリプト)
- scripts-per-instance

### AMIからインスタンス作成時の初回起動時だけスクリプトを実行(/var/lib/cloud/scripts/vendorのスクリプト)
- scripts-user

### sshフィンガープリントをconsoleに出力する
- ssh-authkey-fingerprints

### ssh時のフィンガープリントを出力をする、しないの制御をする(デフォルトでは何もしない)
- keys-to-console

### boot完了時に指定したURLにリクエストを投げる※デフォルトでは何もしない
- phone-home

### 完了ログをconsoleに出力する
- final-message

system_info:

### ディストリビューションを指定
distro: rhel

### 初回起動時に作成するユーザーを指定
default_user:
name: ec2-user

### cloud-initのディレクトリ設定
paths:
cloud_dir: /var/lib/cloud
templates_dir: /etc/cloud/templates

### sshdの再起動を行う
ssh_svcname: sshd

# vim:syntax=yaml

### cloud-iniが利用するデータソースを指定(EC2の場合はmetadataを利用するようになる)
datasource:
Ec2:
timeout: 10
max_wait: 30

まとめ

これで、AMI作成時や起動時に何が設定変更されるのか把握することができました。また、cloud.cfgを理解することでuserdataを利用して初期構築も楽になるのではないかなーと思います。

参考資料