EC2起動時にスクリプトを自動実行する方法 — User Dataで初回起動時にNginxをインストールする
EC2インスタンスを起動するたびに手動でSSH接続してNginxをインストールしていた経験があるなら、User Dataの仕組みを理解することで、その作業を完全に自動化できる。AMIからインスタンスを量産する場面や、Auto Scalingグループで新しいインスタンスが追加される場面では、この自動化が運用品質を左右する。
TL;DR — EC2 User Dataの要点
| 項目 | 内容 |
|---|---|
| 実行タイミング | インスタンスの初回起動時のみ(デフォルト動作) |
| 実行ユーザー | root(sudoなしで実行される) |
| スクリプト形式 | シェルスクリプト(#!/bin/bash)またはcloud-init directive |
| 文字数上限 | 16 KB(Base64エンコード後) |
| ログ出力先 | /var/log/cloud-init-output.log |
| 設定場所 | コンソール起動ウィザード / AWS CLI / Launch Template |
User Dataの仕組みを理解する
EC2インスタンスが初回起動すると、cloud-initというデーモンがインスタンスメタデータサービス(IMDSv2)からUser Dataを取得し、実行する。このフローを理解しておかないと、「スクリプトを貼ったのに動かない」という状況で原因の見当がつかない。
- インスタンス起動 — ハイパーバイザーがEC2インスタンスを起動し、OSが初期化される。
- cloud-initがIMDSにアクセス —
http://169.254.169.254/latest/user-dataエンドポイントからUser Dataを取得する。 - スクリプト判定 — 先頭行が
#!/bin/bashなどのshebangであれば、シェルスクリプトとして実行する。#cloud-configであればYAML形式のcloud-init directiveとして処理する。 - root権限で実行 — スクリプトはrootとして実行されるため、
sudoは不要。 - ログ記録 — 標準出力・標準エラーは
/var/log/cloud-init-output.logに記録される。
cloud-initはLinuxディストリビューションに広く採用されているが、Amazon Linux 2、Amazon Linux 2023、Ubuntu、RHELではバージョンや動作に差異がある。特にAmazon Linux 2023はcloud-initの設定構造が変わっているため、古い記事のサンプルをそのまま流用する際は注意が必要だ。
EC2 User DataにNginxインストールスクリプトを設定する手順
EC2 User Dataを使ってNginxを自動インストールするには、コンソールからインスタンスを起動する際の設定画面、またはLaunch TemplateにスクリプトをペーストするだけでよいI。以下に両方の方法を示す。
方法1: AWSコンソールからインスタンス起動時に設定する
- AWSマネジメントコンソールで EC2 → インスタンス → インスタンスを起動 を選択する。
- AMI、インスタンスタイプ、キーペア、ネットワーク設定を通常通り選択する。
- 画面を下にスクロールし、「高度な詳細」セクションを展開する。
- 最下部にある 「ユーザーデータ」 テキストエリアに、以下のスクリプトをペーストする。
#!/bin/bash
yum update -y
yum install -y nginx
systemctl enable nginx
systemctl start nginx
上記はAmazon Linux 2向けのスクリプトだ。Ubuntuを使う場合はyumの代わりにapt-getを使う。
#!/bin/bash
apt-get update -y
apt-get install -y nginx
systemctl enable nginx
systemctl start nginx
スクリプトを貼り付けたら、そのまま「インスタンスを起動」ボタンをクリックする。インスタンスが起動完了した後、数分待ってからパブリックIPアドレスにブラウザでアクセスすると、NginxのデフォルトページがHTTPで表示される。
方法2: AWS CLIでUser Dataを指定してインスタンスを起動する
コンソール操作を自動化したい場合や、CI/CDパイプラインからインスタンスを起動する場合は、CLIで--user-dataオプションを使う。スクリプトはファイルとして渡すのが確実だ。
# スクリプトをファイルに保存する
cat <<'EOF' > /tmp/userdata.sh
#!/bin/bash
yum update -y
yum install -y nginx
systemctl enable nginx
systemctl start nginx
EOF
# EC2インスタンスを起動する
aws ec2 run-instances \
--image-id ami-0abcdef1234567890 \
--instance-type t3.micro \
--key-name MyKeyPair \
--security-group-ids sg-0123456789abcdef0 \
--subnet-id subnet-0123456789abcdef0 \
--user-data file:///tmp/userdata.sh \
--region us-east-1
--image-idには実際のAMI IDを、--key-nameには既存のキーペア名を指定すること。AMI IDはリージョンとAMIの種類によって異なるため、AWS公式ドキュメントのAMI検索手順で確認する。
方法3: Launch TemplateにUser Dataを組み込む(推奨)
Auto ScalingグループやSpotインスタンスを使う場合、Launch TemplateにUser Dataを定義しておくのが運用上の標準だ。一度テンプレートに設定すれば、そのテンプレートから起動するすべてのインスタンスに同じスクリプトが適用される。
# User DataをBase64エンコードしてLaunch Templateを作成する
USER_DATA=$(base64 -w 0 /tmp/userdata.sh)
aws ec2 create-launch-template \
--launch-template-name nginx-server-template \
--version-description 'v1-nginx-install' \
--launch-template-data "{\"ImageId\":\"ami-0abcdef1234567890\",\"InstanceType\":\"t3.micro\",\"UserData\":\"${USER_DATA}\"}" \
--region us-east-1
CLIでLaunch Templateを作成する場合、User DataはBase64エンコードした文字列を渡す必要がある。コンソールからLaunch Templateを作成する場合は、コンソールが自動的にエンコードするため、プレーンテキストのスクリプトをそのまま貼り付けてよい。
スクリプトが実行されたか確認する方法
「インスタンスは起動したのにNginxが動いていない」という状況は、スクリプトのデバッグ不足が原因であることが多い。User Dataの実行ログを確認する手順を覚えておくことが重要だ。
SSH接続"] --> B["cloud-init status を確認"] B --> C{"status: done?"} C -- "No / running" --> D["スクリプト実行中 or ハング
しばらく待つ"] C -- "Yes" --> E["cloud-init-output.log を確認"] E --> F{"エラーログあり?"} F -- "Yes" --> G["エラー内容を特定
ネットワーク/パッケージ等"] F -- "No" --> H["systemctl status nginx を確認"] H --> I{"Active: running?"} I -- "Yes" --> J["✅ 正常稼働"] I -- "No" --> K["journalctl -u nginx で詳細確認"]
ステップ1: cloud-init出力ログを確認する
インスタンスにSSH接続した後、最初に確認すべきファイルはこれだ。スクリプトの標準出力と標準エラーがすべてここに記録されている。パッケージのインストールに失敗していれば、そのエラーメッセージがここに残る。
sudo cat /var/log/cloud-init-output.log
ステップ2: cloud-initのステータスを確認する
ログを見る前に、cloud-init自体が正常に完了しているかを確認する。ステータスがrunningのままであれば、スクリプトがまだ実行中か、途中でハングしている可能性がある。
cloud-init status
正常に完了していればstatus: doneと表示される。
ステップ3: Nginxのサービス状態を確認する
cloud-initが正常終了しているのにNginxが動いていない場合、スクリプト内のコマンドが失敗している可能性がある。
systemctl status nginx
ステップ4: コンソールからシステムログを確認する(SSH接続できない場合)
SSH接続すら確立できない場合、EC2コンソールからシステムログを取得できる。これはcloud-initの初期化段階のエラーを確認する最後の手段だ。
aws ec2 get-console-output \
--instance-id i-0123456789abcdef0 \
--region us-east-1 \
--output text
実際の現場で起きた誤診パターン
あるチームがAuto ScalingグループのLaunch TemplateにUser Dataを設定したが、新しく起動したインスタンスにNginxがインストールされていなかった。ログを確認するとcloud-init-output.logには正常終了の記録があり、スクリプト自体は実行されていた。
最初の仮説は「スクリプトの構文エラー」だったが、ローカルで同じスクリプトを実行すると問題なく動作した。次に「AMIの問題」を疑ったが、手動でSSH接続して同じコマンドを実行するとNginxはインストールできた。
実際の原因はセキュリティグループのアウトバウンドルールだった。インスタンスが起動した時点でアウトバウンドHTTPS(443番ポート)が制限されており、yum updateがパッケージリポジトリに接続できずタイムアウトしていた。cloud-init-output.logの末尾を注意深く読むと、Could not resolve hostというエラーが記録されていた。
スクリプトの実行は成功しているが、スクリプト内のコマンドが失敗しているというケースは、ログの先頭だけを確認していると見落とす。ログファイルを末尾まで読む習慣が重要だ。
User Dataスクリプトはroot権限で実行されるが、ネットワーク到達性はインスタンスのVPC設定とセキュリティグループに依存する。スクリプトが「動いているのに結果が出ない」場合、まずネットワーク層を疑う。
IAM権限 — S3からスクリプトを取得する場合
User Dataスクリプト自体の実行にIAMは不要だが、スクリプト内でAWS APIを呼び出す場合(例: S3からファイルをダウンロードする、Secrets Managerから認証情報を取得するなど)は、EC2インスタンスにIAMロールをアタッチする必要がある。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::my-config-bucket/nginx/*"
}
]
}
このポリシーをIAMロールにアタッチし、そのロールをEC2インスタンスプロファイルとして設定する。インスタンスプロファイルはインスタンス起動時に指定するか、Launch Templateに組み込む。
よくある失敗パターンと対処法
| 症状 | 原因 | 対処法 |
|---|---|---|
| Nginxが起動していない | アウトバウンド通信がブロックされyumが失敗 | セキュリティグループのアウトバウンドルールを確認する |
cloud-init-output.logが空 | User Dataが正しく設定されていない | インスタンスメタデータで確認: curl http://169.254.169.254/latest/user-data |
| 2回目の起動後にスクリプトが実行されない | デフォルトでは初回起動時のみ実行される | 再実行が必要な場合はcloud-initのモジュール設定を変更するか、別の仕組みを使う |
| スクリプトが途中で止まる | インタラクティブな確認プロンプトが出ている | -yフラグを各コマンドに付与する |
| 文字化けや構文エラー | コンソールのテキストエリアへのコピペで文字が変換された | CLIでfile://形式を使ってファイルから渡す |
まとめとNext Steps — EC2 User Dataで自動化を始める
EC2 User Dataは、インスタンスの初回起動時に任意のシェルスクリプトを実行できる仕組みだ。Nginxのインストール程度であればコンソールのテキストエリアに直接貼り付けるだけで動作する。本番環境ではLaunch Templateにスクリプトを組み込み、Auto Scalingグループと組み合わせることで、インスタンスの追加・置き換えを完全に自動化できる。
次のステップとして、以下を検討する:
- 複数のインスタンスに同じ設定を適用する場合は、AWS Systems Manager State ManagerやAWS CloudFormationとの組み合わせを検討する。
- より複雑な設定管理が必要な場合は、User DataからAnsibleやChefを呼び出す構成も一般的だ。
- 公式ドキュメント: EC2 User Data — AWS公式ドキュメント
用語集
| 用語 | 説明 |
|---|---|
| User Data | EC2インスタンスの起動時に実行されるスクリプトまたはcloud-init設定。コンソールまたはCLIで指定する。 |
| cloud-init | LinuxインスタンスがUser Dataを取得・実行するためのデーモン。多くのLinuxディストリビューションで標準採用されている。 |
| IMDS (Instance Metadata Service) | インスタンス内部から169.254.169.254でアクセスできるメタデータエンドポイント。User Dataもここから取得される。 |
| Launch Template | EC2インスタンスの起動設定をテンプレート化したもの。User DataやIAMロールなどを含め、Auto Scalingグループで再利用できる。 |
| インスタンスプロファイル | EC2インスタンスにIAMロールを関連付けるためのコンテナ。インスタンス上で動くアプリケーションがAWS APIを呼び出す際に使用される。 |
コメント
コメントを投稿