追記
各モジュールの動作確認には以下のようなシェルスクリプトを作って行うと捗る。こちら参考になりました。ありがとうございます。
#!/bin/sh rm -rf /var/lib/cloud/* cloud-init init --local cloud-init init cloud-init modules --mode config cloud-init modules --mode final
まず、/var/lib/cloud/
以下をバサッと消す。その後で...
cloud-init init --local
cloud-init init
cloud-init modules --mode config
cloud-init modules --mode final
を実行する。これは /etc/rc3.d/
以下の起動スクリプトの順番に準拠している。
[root@centos-01 cloud]# ls -l /etc/rc3.d/*cloud* lrwxrwxrwx 1 root root 20 Nov 13 21:38 /etc/rc3.d/K50cloud-init -> ../init.d/cloud-init lrwxrwxrwx 1 root root 26 Nov 13 21:38 /etc/rc3.d/K50cloud-init-local -> ../init.d/cloud-init-local lrwxrwxrwx 1 root root 22 Nov 13 21:38 /etc/rc3.d/S50cloud-config -> ../init.d/cloud-config lrwxrwxrwx 1 root root 21 Nov 13 21:38 /etc/rc3.d/S51cloud-final -> ../init.d/cloud-final
tl;dr
いまさらで恐縮ですが cloud-init に迫ってみる
普段、何気なく EC2 を起動していてもあまり意識していなかった cloud-init について、面と向かわないといけないことがあったので、これを機会に cloud-init について勉強してみたいと思う。既に cloud-init については数多くの知見が出回っているが、実際に手を動かして cloud-init に迫ってみたい。
参考
- https://cloudinit.readthedocs.org/en/latest/
- https://help.ubuntu.com/community/CloudInit
- http://brandon.fuller.name/archives/2011/05/02/06.40.57/
- http://blog.suz-lab.com/2013/01/cloud-init.html
- http://blog.suz-lab.com/2012/12/cloud-initec2-cloud-initebscentos6.html
- http://qiita.com/sonots/items/e60261ea28c61e322631
- http://dev.classmethod.jp/tag/cloud-init/
cloud-init を自分なりに紐解いていく
cloud-init とは
「cloud-init とは」について詳しく書かれている資料を見つけることが出来なかったが、こちらのページの冒頭に...
Package provides configuration and customization of cloud instance.
とあるので、(ディストリビュージョンを超えた)クラウドインスタンスの構成やカスタマイズを行うことが出来るパッケージという認識ですすめる。
また、ドキュメントには以下のように書かれている。
- Setting a default locale(デフォルトロケールの設定)
- Setting a instance hostname(インスタンスのホスト名の設定)
- Generating instance ssh private keys(SSH プライベートキーの生成)
- Adding ssh keys to a users .ssh/authorized_keys so they can log in(ユーザーの SSH キーを authorized_keys に追加)
- Setting up ephemeral mount points(マウントポイントの設定)
また、
Cloud-init's behavior can be configured via user-data.
cloud-init の振る舞いは user-data で設定することが出来るとのことで、ドキュメントには EC2 インスタンスを起動する際に利用する例として以下のように記載されている。
This is done via the --user-data or --user-data-file argument to ec2-run-instances for example.
うんちくは程々に
cloud-init の設定ファイルである cloud-init について自分なりに紐解いていく。紐解くにあたっては予算が少ないので Ubuntu 14.04 上に LXC で起動した CentOS 6.7 コンテナを利用する。
$ sudo apt-get install lxc yum $ sudo lxc-create -n centos-01 -t centos $ sudo lxc-start -d -n centos-01 CentOS release 6.7 (Final) Kernel 3.13.0-55-generic on an x86_64 centos-01 login:
尚、LXC についてはこちらの特集記事が大変参考になる。
CentOS コンテナが起動したらログインして cloud-init をインストールする。
# yum install cloud-init
これで準備完了。
cloud-init のディレクトリ構成
前述の設定ファイルではなく、cloud-init によって実行されるスクリプト等が展開されるディレクトリは以下のようになっている。
# tree --charset=x /var/lib/cloud/ -L 2 /var/lib/cloud/ |-- data | |-- instance-id | |-- previous-datasource | |-- previous-hostname | |-- previous-instance-id | |-- result.json | `-- status.json |-- handlers |-- instance -> /var/lib/cloud/instances/iid-datasource-none |-- instances | `-- iid-datasource-none |-- scripts | |-- per-boot | |-- per-instance | |-- per-once | `-- vendor |-- seed `-- sem `-- config_scripts_per_once.once
このディレクトリについてはドキュメントにて言及されているので、ざっくりと拝借させて頂く。
ディレクトリ | 詳細 |
---|---|
/var/lib/cloud | cloud-init 固有のサブディレクトリを含むメインディレクトリで変更することも可能 |
data/ | インスタンス ID やデータソース、ホスト名等の情報が含まれている(以下で全てのファイルを展開してみる) |
handlers/ | part-handler コードを置いておく、ファイル名は part-handler-${ハンドラ番号}(ドキュメントでは XYZ で表現)とする |
instance/ | instances のサブディレクトリのアクティブなインスタンスディレクトリのシンボリックリンクになっている |
instances/ | 同一のインスタンスイメージから作成されたインスタンスの識別子ディレクトリが作成され、アクティブなインスタンスが instance にリンクしている |
scripts/ | ダウンロードしたり作成したスクリプトを配置する |
seed/ | TBD = 未確定 |
sem/ | このディレクトリにはインスタンス ID に関連付けられていないセマフォファイルが含まれており、これらのファイルは各モジュールが確実に実行する為に使用される |
data/ 以下に保存されているファイルを全て展開すると以下のような内容となっている。
# for i in `ls /var/lib/cloud/data/*`; do echo "====== $i ======"; cat $i; echo ""; done ====== /var/lib/cloud/data/instance-id ====== iid-datasource-none ====== /var/lib/cloud/data/previous-datasource ====== DataSourceNone: DataSourceNone ====== /var/lib/cloud/data/previous-hostname ====== # Created by cloud-init v. 0.7.5 on Thu, 12 Nov 2015 14:30:25 +0000 HOSTNAME=centos01.localdomain ====== /var/lib/cloud/data/previous-instance-id ====== iid-datasource-none ====== /var/lib/cloud/data/result.json ====== { "v1": { "errors": [ "'NoneType' object is not iterable", "'NoneType' object is not iterable" ], "datasource": null } } ====== /var/lib/cloud/data/status.json ====== { "v1": { "init": { "start": 1447339866.7182679, "finished": 1447340129.1867039, "errors": [ "'NoneType' object is not iterable" ], "end": null }, "datasource": null, "modules-config": { "start": 1447340129.37832, "finished": 1447340129.4275589, "errors": [ "'NoneType' object is not iterable" ], "end": null }, "modules-final": { "start": 1447368909.2942469, "finished": 1447368909.3693061, "errors": [], "end": null }, "init-local": { "start": 1447339866.4216521, "finished": 1447339866.5258591, "errors": [], "end": null }, "stage": null } }
instance ディレクトリには以下のようなファイルが展開されている。
# tree --charset=x /var/lib/cloud/instance -L 1 /var/lib/cloud/instance |-- boot-finished |-- cloud-config.txt |-- datasource |-- handlers |-- obj.pkl |-- scripts |-- sem |-- user-data.txt |-- user-data.txt.i |-- vendor-data.txt `-- vendor-data.txt.i
sem ディレクトリには以下のようにファイルが展開されている。
# for i in `ls /var/lib/cloud/sem/*`; do echo "====== $i ======"; cat $i; echo ""; done ====== /var/lib/cloud/sem/config_scripts_per_once.once ====== 375: 1447338625.91
cloud-init 設定ファイルのディレクトリ構成
cloud-init をインストールすると以下のように設定ファイルが展開される。
# tree --charset=x /etc/cloud/ /etc/cloud/ |-- cloud.cfg |-- cloud.cfg.d | |-- 05_logging.cfg | `-- README `-- templates |-- chef_client.rb.tmpl |-- hosts.debian.tmpl |-- hosts.redhat.tmpl |-- hosts.suse.tmpl |-- resolv.conf.tmpl |-- sources.list.debian.tmpl `-- sources.list.ubuntu.tmpl 2 directories, 10 files
cloud-init の挙動を制御するのは cloud.cfg となるが、cloud.cfg.d 以下に切り出すことも可能。但し、切り出しについては行わず cloud.cfg のみを見てみる。また、templates ディレクトリには hosts ファイルや resolv.conf のテンプレートとなるファイルが保存されている。例えば、hosts.redhat.tmpl は以下のような内容になっている。
# cat hosts.redhat.tmpl #* This file /etc/cloud/templates/hosts.redhat.tmpl is only utilized if enabled in cloud-config. Specifically, in order to enable it you need to add the following to config: manage_etc_hosts: True *# # Your system has configured 'manage_etc_hosts' as True. # As a result, if you wish for changes to this file to persist # then you will need to either # a.) make changes to the master file in /etc/cloud/templates/hosts.redhat.tmpl # b.) change or remove the value of 'manage_etc_hosts' in # /etc/cloud/cloud.cfg or cloud-config from user-data # # The following lines are desirable for IPv4 capable hosts 127.0.0.1 ${fqdn} ${hostname} 127.0.0.1 localhost.localdomain localhost 127.0.0.1 localhost4.localdomain4 localhost4 # The following lines are desirable for IPv6 capable hosts ::1 ${fqdn} ${hostname} ::1 localhost.localdomain localhost ::1 localhost6.localdomain6 localhost6
また、興味深いのが chef_client.rb.tmpl で展開すると以下のようになっている。
# cat chef_client.rb.tmpl #* This file is only utilized if the module 'cc_chef' is enabled in cloud-config. Specifically, in order to enable it you need to add the following to config: chef: validation_key: XYZ validation_cert: XYZ validation_name: XYZ server_url: XYZ *# log_level :info log_location "/var/log/chef/client.log" ssl_verify_mode :verify_none validation_client_name "$validation_name" validation_key "/etc/chef/validation.pem" client_key "/etc/chef/client.pem" chef_server_url "$server_url" environment "$environment" node_name "$node_name" json_attribs "/etc/chef/firstboot.json" file_cache_path "/var/cache/chef" file_backup_path "/var/backups/chef" pid_file "/var/run/chef/client.pid" Chef::Log::Formatter.show_time = true
このテンプレートを展開して OS 起動時に Chef を使ってプロビジョニングも出来たりするのだろう。(今回は試さないけど)
cloud.cfg について
cloud-init インストール直後の cloud.cfg は以下のようになっている。(長いので gist に...)
cloud.cfg のフォーマットは YAML となっており、各キーに関しての解説がこれまた見つからない...ので以下のファイルのコメントが参考になった。
上記のファイルを参考にさせて頂いて以下のようにコメントを付けてみた。
# インスタンス上に作成するユーザーを定義する。以下の場合には default_user を参照する。 users: - default # root でのログインを無効にする定義。以下の場合には root でのログインを有効にしている。 disable_root: 1 # SSH のパスワードログインを許可する、許可しないの定義。以下の場合には SSH のパスワードログインを有効にしている。 ssh_pwauth: 0 # locale の設定ファイルのパスを定義 locale_configfile: /etc/sysconfig/i18n # fstab の各フィールドを定義 mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2'] # ??? resize_rootfs_tmp: /dev # SSH キーを削除する定義。パブリックなイメージについては有効にしておく必要がある。以下の例では有効にしている。 ssh_deletekeys: 0 # 生成する SSH キーのタイプを定義する ssh_genkeytypes: ~ # syslog のパラメータを定義する syslog_fix_perms: ~ # 起動時に実行されるモジュールを定義する(※S50cloud-init-local/S51cloud-init) cloud_init_modules: - migrator (snip) # 起動時に実行されるモジュールを定義する(※S52cloud-config なので S50cloud-init-local/S51cloud-init の後に実行される) cloud_config_modules: - mounts (snip) # 起動時に実行されるモジュールを定義する(※S53cloud-final なので S50cloud-init-local => S51cloud-init => S52cloud-config => S53cloud-final) cloud_final_modules: - rightscale_userdata (snip) # システム固有の設定等を定義する(???) system_info: # 冒頭の users > default から参照されるユーザー定義 default_user: name: centos lock_passwd: true gecos: Cloud User groups: [wheel, adm] sudo: ["ALL=(ALL) NOPASSWD:ALL"] shell: /bin/bash distro: rhel paths: cloud_dir: /var/lib/cloud templates_dir: /etc/cloud/templates ssh_svcname: sshd # vim:syntax=yaml
ひとまず今日はここまで。
おわり
cloud-init
- 奥深い
- EC2 使っていれば漏れ無く使っているはずなんだけど...情報が少ない気がするのは自分だけかな...
まだまだ
- 全然使いこなせていないよ...(汗