Amazon Linuxのcloud-initの動きについて調べてみた

アイキャッチ AWS EC2

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

はじめに

昨日Amazon Linuxのcloud-init Tips集という記事を書きましたが、他にも色々気になることがあって調べてみましたので、記事にしてみます。

調べてみたこと

実行タイミング

まず、cloud-initがいつ実行されるのかを調べてみました。Amazon Linux AMIでLaunchしたEC2のランレベルを確認すると、

$ runlevel
N 3

なので、/etc/rc3.d/配下を確認してみます。

$ ls -alF /etc/rc3.d/ | grep cloud
lrwxrwxrwx  1 root root   26  8月  5 10:58 S50cloud-init-local -> ../init.d/cloud-init-local*
lrwxrwxrwx  1 root root   20  8月  5 10:58 S51cloud-init -> ../init.d/cloud-init*
lrwxrwxrwx  1 root root   22  8月  5 10:58 S52cloud-config -> ../init.d/cloud-config*
lrwxrwxrwx  1 root root   21  6月 12 01:51 S98cloud-final -> ../init.d/cloud-final*

このように、cloud-initの起動スクリプトは4つのファイルに分かれていました。通常sshやhttpdなどのサービスの起動スクリプトはS52よりも後でS98より先にあります。

lrwxrwxrwx  1 root root   14  7月 22 17:24 S55sshd -> ../init.d/sshd*
lrwxrwxrwx  1 root root   17  6月 12 01:53 S57ntpdate -> ../init.d/ntpdate*
lrwxrwxrwx  1 root root   14  6月 12 01:53 S58ntpd -> ../init.d/ntpd*
lrwxrwxrwx  1 root root   18  6月 12 01:51 S80sendmail -> ../init.d/sendmail*
lrwxrwxrwx  1 root root   15  6月 12 01:51 S90crond -> ../init.d/crond*
lrwxrwxrwx  1 root root   13  6月 12 01:52 S95atd -> ../init.d/atd*

このため実行順序としては

  1. cloud-init-local
  2. cloud-init
  3. cloud-config
  4. 各種サービスの起動
  5. cloud-final

となります。

それぞれの起動スクリプトがやっていること

この4つの起動スクリプトの内容を確認すると、以下のような違いがありました。

$ diff cloud-init-local cloud-init
70c70
<     $cloud_init $CLOUDINITARGS init --local
---
>     $cloud_init $CLOUDINITARGS init

$ diff cloud-init-local cloud-config
70c70
<     $cloud_init $CLOUDINITARGS init --local
---
>     $cloud_init $CLOUDINITARGS modules --mode config

$ diff cloud-init-local cloud-final
70c77
<     $cloud_init $CLOUDINITARGS init --local
---
>     $cloud_init $CLOUDINITARGS modules --mode final

内容はほぼ同一で、$cloud_init(/usr/bin/cloud-init)への引数が違うだけでした。

この引数による違いは、cloud-initの設定ファイルである/etc/cloud/cloud.cfg/etc/cloud/cloud.cfg.d/配下のスクリプトで確認できます。

$ cat /etc/cloud/cloud.cfg.d/00_defaults.cfg
# ### DO NOT MODIFY THIS FILE! ###
# This file will be replaced if cloud-init is upgraded.
# Please put your modifications in other files under /etc/cloud/cloud.cfg.d/
#
# Note that cloud-init uses flexible merge strategies for config options
# http://cloudinit.readthedocs.org/en/latest/topics/merging.html

# The top level settings are used as module
# and system configuration.

# A set of users which may be applied and/or used by various modules
# when a 'default' entry is found it will reference the 'default_user'
# from the distro configuration specified below
users:
  - default

ssh_pwauth: false

# Example datasource config
# datasource:
#   Ec2:
#     metadata_urls: [ 'blah.com' ]
#     timeout: 5 # (defaults to 50 seconds)
#     max_wait: 10 # (defaults to 120 seconds)

locale_configfile: /etc/sysconfig/i18n
mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2']
resize_rootfs: noblock
resize_rootfs_tmp: /dev
ssh_deletekeys: true
ssh_genkeytypes: [ 'rsa', 'dsa', 'ecdsa' ]
syslog_fix_perms: ~

# The modules that run in the 'init' stage
cloud_init_modules:
  - rsyslog
  - migrator
  - bootcmd
  - write-files
  - growpart
  - resizefs
  - set-hostname
  - update-hostname
  - update-etc-hosts
  - users-groups

# The modules that run in the 'config' stage
cloud_config_modules:
  - locale
  - ssh
  - set-passwords
  - mounts
  - yum-configure
  - yum-add-repo
  - package-update-upgrade-install
  - timezone
  - puppet
  - disable-ec2-metadata
  - runcmd

# The modules that run in the 'final' stage
cloud_final_modules:
  - scripts-per-once
  - scripts-per-boot
  - scripts-per-instance
  - scripts-user
  - ssh-authkey-fingerprints
  - keys-to-console
  - phone-home
  - final-message
  - power-state-change

# System and/or distro specific settings
# (not accessible to handlers/transforms)
system_info:
  # This will affect which distro class gets used
  distro: amazon
  distro_short: amzn
  # Default user name + that default users groups (if added/used)
  default_user:
    name: ec2-user
    lock_passwd: true
    gecos: EC2 Default User
    groups: [ wheel ]
    sudo: [ "ALL=(ALL) NOPASSWD:ALL" ]
    shell: /bin/bash
  # Other config here will be given to the distro class and/or path classes
  paths:
    cloud_dir: /var/lib/cloud/
    templates_dir: /etc/cloud/templates/
    upstart_dir: /etc/init/
  package_mirrors:
    - arches: [ i386, x86_64 ]
      search:
        regional:
          - repo.%(ec2_region)s.%(services_domain)s
          - repo.%(ec2_region)s.amazonaws.com
  ssh_svcname: sshd

# vim:syntax=yaml expandtab

cloud-init-localとcloud-initではcloud_init_modulesが、cloud-configではcloud_config_modulesが、cloud-finalではcloud_final_modulesが、それぞれ実行されます。

例えばbootcmdやwrite-filesなどはcloud_init_modulesで実行されますので、cloud_config_modulesで実行されるyum-configureやruncmdなどより前に実行されることが分かりますね。

なお、ここに書いてある各モジュールは/usr/lib/python2.6/site-packages/cloudinit/configにあります。Pythonで書かれていますので、読むとどんな動きをしているのかがわかります。

User-Dataの読み込まれるタイミング

/usr/bin/cloud-initを読むと、以下のように記述されていました。

    # Cloud-init 'init' stage is broken up into the following sub-stages
    # 1. Ensure that the init object fetches its config without errors
    # 2. Setup logging/output redirections with resultant config (if any)
    # 3. Initialize the cloud-init filesystem
    # 4. Check if we can stop early by looking for various files
    # 5. Fetch the datasource
    # 6. Connect to the current instance location + update the cache
    # 7. Consume the userdata (handlers get activated here)
    # 8. Construct the modules object
    # 9. Adjust any subsequent logging/output redirections using the modules
    #    objects config as it may be different from init object
    # 10. Run the modules for the 'init' stage
    # 11. Done!

なので、cloud-initの段階でUser-Dataの内容(/var/lib/cloud/instance/user-data.txt)が読み込まれます。

まとめ

ということで、cloud-initの動きについて少し理解が深まりました。次は各moduleについて色々試してみたいと思います。