背景
Spring Boot WebアプリをALB + EC2(Tomcat) + RDSに自動デプロイするCloudFormationハンズオンをやりました。コンソール版ではSCPでWARを転送しSSHでデプロイする手作業でしたが、今回はS3とUserDataの組み合わせでこの工程を完全自動化します。
1. WARは事前にS3へアップロードしておく
aws s3 mb s3://my-webapp-bucket-(任意の識別子) --region ap-northeast-1
aws s3 cp app\target\webapp.war s3://my-webapp-bucket-(任意の識別子)/webapp.war
EC2のUserDataがS3からwebapp.warをダウンロードする設計のため、スタック作成より前にS3へのアップロードを済ませておく必要があります。S3バケット自体はCloudFormationのスコープ外(手動作成)という点も、実際に手を動かすと分かるポイントです。
2. UserDataが「インストール→設定→デプロイ→起動」を1つのスクリプトで完結させる
UserDataの自動実行フロー:
1. Java + Tomcat インストール
2. SSMからDBパスワード取得 → setenv.sh作成
3. S3からwebapp.warをダウンロード → ROOT.warとして配置
4. Tomcat起動(Spring Bootアプリが自動展開)
コンソール版では「Tomcatインストール(UserData)」→「SSH接続」→「setenv.sh手動作成」→「別ターミナルでSCP転送」→「Tomcat再起動」という複数ステップに人間が介在していましたが、CloudFormation版はこの全工程を1つのUserDataスクリプトに閉じ込めています。EC2が起動した時点でアプリが動作している状態まで到達します。
3. IAMロールにS3読み取り権限を追加する必要がある
コンソール版のEC2ロールはSSM関連の権限だけで足りていましたが、CloudFormation版ではUserDataがS3からWARを取得するため、IAMロールにS3読み取り権限が追加で必要になります。UserDataの中で行う操作が増えるほど、EC2に付与すべきIAM権限も比例して増える、という設計上の連動を体感できます。
4. デプロイの成否確認はSSH接続後の3種類のログで行う
sudo cat /var/log/user-data.log # UserData全体の実行ログ
sudo tail -50 /opt/tomcat/logs/catalina.out # Tomcat/Spring Bootのログ
sudo cat /opt/tomcat/bin/setenv.sh # DB接続情報が正しく設定されたか
自動化されているとはいえ、UserDataの実行が失敗するケース(S3のNoSuchKeyエラーなど)もあるため、EC2にSSH接続してこの3つのログを確認するデバッグフローはコンソール版と共通です。IaC化しても「最終的に中身を確認する手段」は変わりません。
5. 削除ではS3バケットだけ手動削除が必要
aws cloudformation delete-stack --stack-name my-webapp-stack --region ap-northeast-1
aws s3 rm s3://my-webapp-bucket-(任意の識別子) --recursive
aws s3 rb s3://my-webapp-bucket-(任意の識別子)
S3バケットはCloudFormationのスタックに含まれていないため、delete-stackだけでは削除されません。オブジェクトを空にしてからバケット自体を削除する、という2段階の手動操作が必要な点は覚えておく価値があります。
まとめ
S3 + UserDataによってWARデプロイをEC2起動時の自動処理に組み込めた点が、このハンズオンでの最大の学びでした。コンソール版で必要だったSCP転送とSSH経由でのsetenv.sh手動作成が、IAM権限の追加とUserDataスクリプトの拡張だけで丸ごと自動化されます。
→ CloudFormationでSpring Boot WebアプリをALB + EC2(Tomcat) + RDS に自動デプロイする手順(ブログ)