EC2 ユーザーデータと cloud-init の活用完全ガイド
EC2 起動時に走る「ユーザーデータ」と、それを実行する OS 側ツール「cloud-init」の関係を整理。シェルスクリプト形式・cloud-config 形式・MIME マルチパート形式の使い分け、16 KB 制限の回避、毎回実行への切替、Auto Scaling/Golden AMI と組み合わせた現場の定番パターンまでまとめる。
EC2 を「起動した瞬間に使える状態」にするための仕組みがユーザーデータ × cloud-init。Golden AMI で固めるか、起動時に動的に整えるか — 設計の出発点になる二択を整理する。
1. 概要(端的に)
Amazon EC2 を起動するとき、インスタンス初回ブート時に走らせるスクリプトや設定を「ユーザーデータ(user data)」として渡せる。これを実際に解釈・実行する OS 側の常駐ツールが cloud-init。Amazon Linux・Ubuntu・RHEL・SUSE などの公式 AMI には標準搭載されており、追加インストール不要で動く。
二者の関係を一行でまとめると:
- ユーザーデータ = EC2 に「外から渡す指示書」(メタデータサービス経由で取得される)
- cloud-init = OS の中でその指示書を読んで実行する常駐ツール
「インスタンスを叩いて 5 分後にはユーザーが触れる Web サーバーが立っている」「Auto Scaling の新ノードが自動で監視エージェントを入れて ALB に組み込まれる」— こうした体験はほぼすべて、この 2 つの組み合わせで実装されている。
2. ユーザーデータの基本仕様
| 項目 | 仕様 |
|---|---|
| サイズ上限 | 16 KB(Base64 エンコード後 21,847 バイト) |
| 取得経路 | インスタンスメタデータサービス(IMDS)— リンクローカル 169.254.169.254/latest/user-data |
| 実行ユーザー | Linux:root / Windows:Administrator |
| 実行タイミング(既定) | 初回ブートのみ 1 回(cloud-init 側の scripts-user が once) |
| 変更タイミング | 停止 → 編集 → 起動 のサイクル(実行中インスタンスでは編集不可) |
| ログ出力先 | Linux:/var/log/cloud-init.log / /var/log/cloud-init-output.log |
ユーザーデータ自体はただの文字列で、Linux インスタンスでは大きく 3 フォーマットが使える。
2-1. シェルスクリプト形式
#!/bin/bash
yum update -y
yum install -y nginx
systemctl enable --now nginx
echo "Hello from EC2" > /usr/share/nginx/html/index.html
#!/bin/bash で始まる素朴な形式。書きやすさが圧倒的で、トラブル時もシェルとして再実行・デバッグできるのが利点。
2-2. cloud-config 形式
#cloud-config
package_update: true
packages:
- nginx
- amazon-cloudwatch-agent
write_files:
- path: /usr/share/nginx/html/index.html
content: "Hello from cloud-init"
runcmd:
- systemctl enable --now nginx
#cloud-config で始まる YAML。宣言的で、パッケージ導入・ファイル配置・ユーザー追加・SSH キー登録などを順序を意識せず書ける。マルチディストロ対応のレシピを 1 本で共有しやすい。
2-3. MIME マルチパート形式
シェルスクリプトと cloud-config を同時に渡したい場合に使う。EKS の Managed Node Group や Auto Scaling グループの起動テンプレートで実際によく目にする形。
Content-Type: multipart/mixed; boundary="==BOUNDARY=="
MIME-Version: 1.0
--==BOUNDARY==
Content-Type: text/cloud-config; charset="us-ascii"
#cloud-config
cloud_final_modules:
- [scripts-user, always]
--==BOUNDARY==
Content-Type: text/x-shellscript; charset="us-ascii"
#!/bin/bash
echo "boot at $(date)" >> /var/log/boot-marker.log
--==BOUNDARY==--
上の [scripts-user, always] が「毎回ブート時に再実行」へ切り替えるおまじない(後述)。
3. cloud-init の役割
cloud-init はクラウド汎用のインスタンス初期化ツールで、もともとは AWS 向けに Canonical が開発した。AWS では次の流れで動く。
- インスタンス起動 → systemd が
cloud-init-local.service→cloud-init.service→cloud-config.service→cloud-final.serviceの順に呼び出す - cloud-init が IMDS からユーザーデータとメタデータ(ホスト名・リージョン・IAM ロール等)を取得
- ユーザーデータの先頭バイトを見てハンドラを選択(
#!→ シェル、#cloud-config→ YAML パーサ、MIME → 分解) - モジュールを順に実行(パッケージ更新・SSH キー登録・タイムゾーン設定・ホスト名設定・ユーザー作成…)
- 最後に
runcmd/scripts-userでユーザー固有スクリプトを実行
設定ファイル /etc/cloud/cloud.cfg をのぞくと、初回のみ動くモジュール(cloud_init_modules)と毎回動くモジュール(cloud_config_modules / cloud_final_modules)の振り分けが見える。ユーザーデータの再実行制御もここで決まっている。
4. ユーザーデータ × cloud-init:書き方の使い分け
| 評価項目 | シェルスクリプト | cloud-config (YAML) 推奨 | MIME マルチパート |
|---|---|---|---|
| 先頭バイト | `#!/bin/bash` 等 | `#cloud-config` | `Content-Type: multipart/...` |
| 書きやすさ | ◎(手に馴染む) | ○(YAML を覚える必要) | △(境界文字列の管理) |
| 宣言性 | ×(命令的) | ◎ | ○ |
| マルチディストロ対応 | △(パッケージ管理コマンドが異なる) | ◎ | ◎ |
| デバッグ容易性 | ◎(シェルで再実行可) | ○(cloud-init log を読む) | △(分解して確認) |
| 毎回ブート時に再実行 | cloud-init 側設定で可 | cloud-config で明示宣言 | ◎(best practice) |
| 想定ユースケース | アドホック起動・PoC | 本番ブートストラップ | Auto Scaling / EKS Node Group |
5. 現場で多い活用パターン 6 つ
5-1. Web サーバーの即時セットアップ
yum install -y nginx → systemctl enable --now nginx までを 1 本で書く。検証環境やデモ用 EC2 で最初に書く定番。
5-2. CloudWatch エージェントの自動導入
CloudWatch Agent をインストールし、設定 JSON を SSM Parameter Store から取得して amazon-cloudwatch-agent-ctl で起動。Auto Scaling の新ノードでもログ集約が自動でつながる。詳細は CloudWatch Logs も参照。
5-3. ECS / EKS のクラスターノード登録
ECS Optimized AMI なら echo "ECS_CLUSTER=my-cluster" >> /etc/ecs/ecs.config、EKS なら /etc/eks/bootstrap.sh my-cluster --kubelet-extra-args ... をユーザーデータに書く。これでオートスケールしたノードがそのままクラスターに参加する。
5-4. SSM Session Manager 用エージェント有効化
Amazon Linux 2023 では SSM Agent はプリインストールだが、IAM ロール(AmazonSSMManagedInstanceCore)の付与と systemctl enable amazon-ssm-agent だけ書いておくと、SSH 鍵運用を一切やらずに踏み台レス化できる。
5-5. Golden AMI × 差分のみユーザーデータ
EC2 Image Builder で焼いた Golden AMI を使い、ユーザーデータでは環境固有の差分(環境変数、シークレット参照、起動メッセージ)だけを書く。起動時間 1〜2 分で本番投入できる。
5-6. Auto Scaling 起動テンプレートでのブートストラップ
EC2 Auto Scaling の起動テンプレートにユーザーデータを埋め込み、新ノードが「起動 → エージェント導入 → ヘルスチェック合格 → ALB ターゲット組み込み」まで自走する形にする。MIME マルチパートで「毎回実行」にしておくと、停止からの再起動でも整合性が崩れない。
6. つまずきポイントとトラブルシューティング
よくある失敗と対処
| 症状 | 原因 | 対処 |
|---|---|---|
| スクリプトが動いていない | 既定の「初回のみ」設定 | scripts-user: always で毎回実行に切替 |
| 編集を反映できない | 実行中インスタンスでは編集不可 | 停止 → 編集 → 起動 のサイクル |
| 16 KB を超える | スクリプトが肥大化 | S3 に本体を置き、ユーザーデータでは aws s3 cp → 実行に分割 |
| 環境変数が読めない | .bashrc を期待している | cloud-init は非ログインシェル — /etc/profile.d/ に書く |
| IAM 権限不足で失敗 | インスタンスプロファイル未設定 | 起動時に IAM ロール(S3/SSM 等)をアタッチ |
| Windows で動かない | PowerShell 構文が必要 | <powershell></powershell> または <script></script> タグで囲む |
デバッグの第一手
# ユーザーデータの実行出力を確認
sudo less /var/log/cloud-init-output.log
# cloud-init 全体のフェーズログ
sudo less /var/log/cloud-init.log
# IMDS から実際に渡ったユーザーデータを取得
IMDS=169.254.169.254
TOKEN=$(curl -X PUT "$IMDS/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 60")
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
"$IMDS/latest/user-data"
IMDSv2 を強制している環境ではトークンを取ってから user-data エンドポイントを叩く点だけ注意。
7. メリット・デメリット
8. ベストプラクティス
- 「焼くか、起動時に流すか」の境界を最初に決める — 重い処理(依存ライブラリ/カーネルパッチ)は EC2 Image Builder で AMI 化し、ユーザーデータは環境差分だけに絞る。
- 16 KB を超えたら S3 へ逃がす — ユーザーデータは「ブートローダー」と割り切り、本体スクリプトは S3 に置いて
aws s3 cpで取得 → 実行する形にする。 - 必ず IAM ロールをアタッチ — Secrets Manager・Parameter Store・S3 を扱う前提なら、最初から最小権限ロールをセット。
set -euxo pipefailをスクリプト先頭に — エラー時に黙って続行されると後追いが地獄。失敗即停止+ログを残す。cloud-init-output.logを CloudWatch Logs に送る —awslogs.confで常時取り込んでおくと、起動失敗時に SSH 不要で原因が読める。- MIME マルチパートで再実行可能設計 — Auto Scaling や EKS Node Group では「毎回 boot 時に整合性を取り直す」設計が結果として一番安定する。
- 検証は cloud-init を再実行できる状態で —
cloud-init clean --logs→ 再起動で「真の初回ブート」を再現できる。AMI 化前の最終チェックに使う。 - シークレットを直書きしない — ユーザーデータは IMDS で誰でも取得できる(同インスタンス内の任意プロセスから読める)。値は Secrets Manager / Parameter Store の参照に留める。
9. 関連用語
- Amazon EC2 — ユーザーデータが届く対象の仮想サーバー
- AMI — cloud-init を含むベースイメージ(Golden AMI 戦略の基盤)
- EC2 Image Builder — 「焼く側」のマネージドサービス
- EC2 Auto Scaling — ユーザーデータ × 起動テンプレートでスケール時のブートストラップを自動化
- Systems Manager — Parameter Store・Session Manager・RunCommand の連携先
- IAM Role — インスタンスプロファイルとして S3/SSM へのアクセス権限を付与
- CloudWatch Logs —
cloud-init-output.logの集約先 - AWS CloudFormation —
UserDataプロパティで宣言的に管理
10. 関連サイト
AWS 公式
- Run commands when you launch an EC2 instance with user data input(ユーザーガイド)
- Using cloud-init on Amazon Linux 2(公式ドキュメント)
- Run user data after the initial launch of an EC2 instance(re:Post)
- Add new AWS accounts with SSH access to EC2 instance with cloud-init and user data(re:Post)
- cloud-init 公式:Amazon EC2 データソース
参考記事
- Qiita:cloud-init を使った Linux OS の初期設定
- エキサイト Tech Blog:AWS 移行における cloud-init を使った Linux の初期設定
- デロイト DWS:シェルスクリプト・Ansible・cloud-init の特徴と選択肢
- プログラミングマガジン:EC2「ユーザーデータ」「インスタンスメタデータ」について
🎓 試験での出題傾向
| 試験 | 重要度 | 主な出題パターン |
|---|---|---|
| CLF | 中 | EC2 起動時の初期化手段としてユーザーデータが使えることの理解 |
| SAA | 高 | Auto Scaling × ユーザーデータ × Golden AMI の組み合わせ、起動時間短縮設計 |
| DVA | 中 | cloud-config・MIME マルチパートの形式選択、再実行制御 |
| SOA | 高 | 16 KB 制限・トラブルシュート・CloudWatch Logs へのログ集約 |
特に SAA / SOA では「Auto Scaling で新ノードが立ち上がったら自動でエージェントを入れたい」「Golden AMI と組み合わせてスケール時間を最小化したい」場面でユーザーデータ vs Image Builder vs SSM RunCommandの選択を問う問題が頻出する。「重い処理は Image Builder で AMI 化/軽い差分はユーザーデータ/後追い変更は SSM」の三層構造で覚えておくと判断がブレない。