Amazon EC2 の cloud-init の初期構成とカスタマイズを調査しました

Amazon EC2 の cloud-init の初期構成とカスタマイズについて調査しました。

cloud-init については、cloud-init のリファレンスガイドを参照してください。

https://cloudinit.readthedocs.io/en/latest/index.html

cloud-init の実践的な概要については、RedHat のページを参照してください。

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/configuring_and_managing_cloud-init_for_rhel_8/index

調査をおこなった環境は、次の通りです。

| Parameter | Value                                               |
|:----------|:----------------------------------------------------|
| OS        | Amazon Linux 2                                      |
| AMI       | ami-07b4f72c4c356c19d                               |
| AMI Name  | amzn2-ami-kernel-5.10-hvm-2.0.20220218.1-x86_64-gp2 |

# cloud-init の EC2 インスタンス上の配置

設定:

```console
/etc/cloud
├─cloud.cfg                       # 基本設定
├─cloud.cfg.d
│ ├─05_logging.cfg                # cloud-init のロギング設定
│ ├─10_aws_yumvars.cfg            # AWS の yum 変数設定
│ ├─20_amazonlinux_repo_https.cfg # Amazon Linux の yum リポジトリ設定
│ └─README
└─templates
```

ログ:

```console
/var/log
├─cloud-init.log
└─cloud-init-output.log
```

情報:

```console
/var/lib/cloud
├─data
│ ├─instance-id
│ ├─previous-datasource
│ ├─previous-hostname
│ ├─previous-instance-id
│ ├─result.json
│ ├─set-hostname
│ └─status.json
├─handlers
├─instance -> /var/lib/cloud/instances/i-xxxxxxxxxxxxxxxx # 現在のインスタンスへのシンボリックリンク
├─instances # インスタンス単位の制御情報の格納先
│ └─i-xxxxxxxxxxxxxxxx
├─scripts
│ ├─per-boot     # インスタンスの起動の度に実行するスクリプト格納先 (空)
│ ├─per-instance # インスタンスの初回起動時、及びインスタンスの変更後の初回起動にのみ実行するスクリプト格納先 (空)
│ ├─per-once     # インスタンスの作成時に 1 回だけ実行するスクリプト格納先 (空)
│ └─vendor       # ベンダー固有の per-instance と同じ実行頻度のスクリプト格納先 (空)
├─seed
└─sem
```

# cloud-init の設定の内容

## /etc/cloud/cloud.cfg 

```yaml
# WARNING: Modifications to this file may be overridden by files in
# /etc/cloud/cloud.cfg.d

users:
 - default

disable_root: true
ssh_pwauth:   false

mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2']
resize_rootfs: noblock
resize_rootfs_tmp: /dev
ssh_deletekeys:   true
ssh_genkeytypes:  ~
syslog_fix_perms: ~

datasource_list: [ Ec2, None ]
repo_upgrade: security
repo_upgrade_exclude:
 - kernel
 - nvidia*
 - cuda*

# Might interfere with ec2-net-utils
network:
  config: disabled

cloud_init_modules: # cloud-init の network ブートステージで実行するモジュール群
 - migrator
 - bootcmd
 - write-files
 - write-metadata
 - amazonlinux_repo_https
 - growpart
 - resizefs
 - set-hostname
 - update-hostname
 - update-etc-hosts
 - rsyslog
 - users-groups
 - ssh
 - resolv-conf

cloud_config_modules: # cloud-init の config ブートステージで実行するモジュール群
 - disk_setup
 - mounts
 - locale
 - set-passwords
 - yum-configure
 - yum-add-repo
 - package-update-upgrade-install
 - timezone
 - disable-ec2-metadata
 - runcmd

cloud_final_modules: # cloud-init の final ブートステージで実行するモジュール群
 - 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_info:
  # This will affect which distro class gets used
  distro: amazon
  distro_short: amzn
  default_user:
    name: ec2-user
    lock_passwd: true
    gecos: EC2 Default User
    groups: [wheel, adm, systemd-journal]
    sudo: ["ALL=(ALL) NOPASSWD:ALL"]
    shell: /bin/bash
  paths:
    cloud_dir: /var/lib/cloud
    templates_dir: /etc/cloud/templates
  ssh_svcname: sshd

mounts:
 - [ ephemeral0, /media/ephemeral0 ]
 - [ swap, none, swap, sw, "0", "0" ]
# vim:syntax=yaml
```

概ね RHEL のデフォルトの cloud.cfg の設定を踏襲しています。

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html-single/configuring_and_managing_cloud-init_for_rhel_8/index#ftn.CO1-2

cloud-init のブートステージの詳細は、リファレンスガイドに掲載されています。

https://cloudinit.readthedocs.io/en/latest/topics/boot.html

各モジュールの詳細は、リファレンスガイドに掲載されています。

https://cloudinit.readthedocs.io/en/latest/topics/modules.html

# cloud-init のカスタマイズ

EC2 インスタンス起動前にユーザーデータをカスタマイズすることで、cloud-init の挙動をカスタマイズできます。

初期作成時にセットアップするためのみならず、事前にカスタマイズした AMI やバックアップした AMI から EC2 インスタンスを起動する際に予め設定した値を維持するためにカスタマイズが必要です。

カスタマイズは、ユーザーデータを使用して適用します。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/user-data.html

例えば、起動時に yum のアップデートを実行しないカスタマイズが Amazon Linux AMI の FAQ に掲載されています。
尚、Amazon Linux 2 の AMI の FAQ には掲載がありませんでした。

https://aws.amazon.com/jp/amazon-linux-ami/faqs/

## Amazon Linux 2 の cloud-init のデフォルト動作

Amazon Linux 2 のデフォルト動作は、次に記載されています。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/amazon-linux-ami-basics.html#amazon-linux-cloud-init

記載されている動作の箇条書きを引用します。

> * Set the default locale.
> * Set the hostname.
> * Parse and handle user data.
> * Generate host private SSH keys.
> * Add a user's public SSH keys to .ssh/authorized_keys for easy login and administration.
> * Prepare the repositories for package management.
> * Handle package actions defined in user data.
> * Execute user scripts found in user data.
> * Mount instance store volumes, if applicable.

「Handle package actions defined in user data.」では、インスタンス起動時点で有効なセキュリティアップデートが yum により適用されます (`yum update` が実行されます)。

よくあるユーザーデータの指定例は、次の通りです。
ユーザーデータに日本語が含まれると意図しない挙動となるため、コピペ利用する際にはコメントを削除してください。

```yaml
#cloud-config
locale: ja_JP.UTF-8     # ロケールを日本語 UTF-8 に変更します。
preserve_hostname: true # 予め設定しているホスト名を維持します。
repo_update: true       # yum リポジトリの状態を最新にアップデートします。
repo_upgrade: none      # yum 管理下のパッケージを一切アップデートしません。
```

ホスト名の維持は、EC2 ユーザーガイドの指示に従った方法で適切に設定しておく必要があります。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/set-hostname.html