<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>3層構成 - CayTech Lab</title>
	<atom:link href="https://caymezon.com/tag/3%e5%b1%a4%e6%a7%8b%e6%88%90/feed/" rel="self" type="application/rss+xml" />
	<link>https://caymezon.com</link>
	<description></description>
	<lastBuildDate>Mon, 13 Apr 2026 00:09:11 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://caymezon.com/wp-content/uploads/2026/01/cropped-CayTechLab-32x32.jpg</url>
	<title>3層構成 - CayTech Lab</title>
	<link>https://caymezon.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<atom:link rel='hub' href='https://caymezon.com/?pushpress=hub'/>
	<item>
		<title>AWSコンソールでALB + EC2(Tomcat) + RDS 3層構成を構築する手順【ヘルスチェック / SG-to-SG制御】</title>
		<link>https://caymezon.com/aws-handson-console-alb-ec2-rds/</link>
					<comments>https://caymezon.com/aws-handson-console-alb-ec2-rds/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Mon, 13 Apr 2026 00:09:11 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[3層構成]]></category>
		<category><![CDATA[ALB]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSコンソール]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Parameter Store]]></category>
		<category><![CDATA[RDS]]></category>
		<category><![CDATA[SG参照]]></category>
		<category><![CDATA[SSM]]></category>
		<category><![CDATA[Tomcat]]></category>
		<category><![CDATA[VPC]]></category>
		<category><![CDATA[セキュリティグループ]]></category>
		<category><![CDATA[ターゲットグループ]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[ヘルスチェック]]></category>
		<category><![CDATA[ロードバランサー]]></category>
		<category><![CDATA[初心者]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20358</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説前フェーズとの違い使用するAWSサービス構築するリソース一覧全体の作業順序⓪ 自分のIPアドレスの確認① キーペアの作成② VPCの作成③ サブネットの作成（4つ）④ インターネットゲートウェ [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-console-alb-ec2-rds/">AWSコンソールでALB + EC2(Tomcat) + RDS 3層構成を構築する手順【ヘルスチェック / SG-to-SG制御】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">キーワード解説</a></li><li><a href="#toc3" tabindex="0">前フェーズとの違い</a></li><li><a href="#toc4" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc5" tabindex="0">構築するリソース一覧</a></li><li><a href="#toc6" tabindex="0">全体の作業順序</a></li><li><a href="#toc7" tabindex="0">⓪ 自分のIPアドレスの確認</a></li><li><a href="#toc8" tabindex="0">① キーペアの作成</a></li><li><a href="#toc9" tabindex="0">② VPCの作成</a></li><li><a href="#toc10" tabindex="0">③ サブネットの作成（4つ）</a></li><li><a href="#toc11" tabindex="0">④ インターネットゲートウェイの作成・アタッチ</a><ol><li><a href="#toc12" tabindex="0">作成</a></li><li><a href="#toc13" tabindex="0">VPCへのアタッチ</a></li></ol></li><li><a href="#toc14" tabindex="0">⑤ ルートテーブルの設定</a><ol><li><a href="#toc15" tabindex="0">5-1. パブリック用ルートテーブル</a></li><li><a href="#toc16" tabindex="0">5-2. プライベート用ルートテーブル</a></li></ol></li><li><a href="#toc17" tabindex="0">⑥ セキュリティグループの作成</a><ol><li><a href="#toc18" tabindex="0">6-1. ALB用セキュリティグループ</a></li><li><a href="#toc19" tabindex="0">6-2. EC2用セキュリティグループ</a></li><li><a href="#toc20" tabindex="0">6-3. RDS用セキュリティグループ</a></li></ol></li><li><a href="#toc21" tabindex="0">⑦ IAMロールの作成</a><ol><li><a href="#toc22" tabindex="0">信頼されたエンティティ</a></li><li><a href="#toc23" tabindex="0">許可ポリシー</a></li><li><a href="#toc24" tabindex="0">ロール名</a></li></ol></li><li><a href="#toc25" tabindex="0">⑧ SSM Parameter Storeの作成</a></li><li><a href="#toc26" tabindex="0">⑨ RDS DBサブネットグループの作成</a></li><li><a href="#toc27" tabindex="0">⑩ RDS MySQL インスタンスの作成</a><ol><li><a href="#toc28" tabindex="0">エンジンの選択</a></li><li><a href="#toc29" tabindex="0">テンプレート</a></li><li><a href="#toc30" tabindex="0">設定</a></li><li><a href="#toc31" tabindex="0">インスタンスの設定</a></li><li><a href="#toc32" tabindex="0">ストレージ</a></li><li><a href="#toc33" tabindex="0">接続</a></li><li><a href="#toc34" tabindex="0">追加設定</a></li></ol></li><li><a href="#toc35" tabindex="0">⑪ EC2インスタンスの起動</a><ol><li><a href="#toc36" tabindex="0">基本設定</a></li><li><a href="#toc37" tabindex="0">ネットワーク設定</a></li><li><a href="#toc38" tabindex="0">IAMロール</a></li><li><a href="#toc39" tabindex="0">UserData</a></li><li><a href="#toc40" tabindex="0">タグ</a></li></ol></li><li><a href="#toc41" tabindex="0">⑫ ターゲットグループの作成</a><ol><li><a href="#toc42" tabindex="0">ターゲットタイプとプロトコル</a></li><li><a href="#toc43" tabindex="0">ヘルスチェック</a></li><li><a href="#toc44" tabindex="0">ターゲットの登録</a></li></ol></li><li><a href="#toc45" tabindex="0">⑬ ALBの作成・リスナー設定</a><ol><li><a href="#toc46" tabindex="0">基本的な設定</a></li><li><a href="#toc47" tabindex="0">ネットワークマッピング</a></li><li><a href="#toc48" tabindex="0">セキュリティグループ</a></li><li><a href="#toc49" tabindex="0">リスナーとルーティング</a></li></ol></li><li><a href="#toc50" tabindex="0">⑭ 動作確認</a><ol><li><a href="#toc51" tabindex="0">14-1. ALBのヘルスチェック確認</a></li><li><a href="#toc52" tabindex="0">14-2. ALB経由でWebアクセス確認</a></li><li><a href="#toc53" tabindex="0">14-3. EC2にSSH接続する</a></li><li><a href="#toc54" tabindex="0">14-4. Parameter StoreからDBパスワードを取得する</a></li><li><a href="#toc55" tabindex="0">14-5. RDSへのMySQL接続テスト</a></li><li><a href="#toc56" tabindex="0">14-6. SSH接続を切断する</a></li></ol></li><li><a href="#toc57" tabindex="0">⑮ リソースの削除</a><ol><li><a href="#toc58" tabindex="0">削除順序</a></li><li><a href="#toc59" tabindex="0">1. ALBを削除する</a></li><li><a href="#toc60" tabindex="0">2. ターゲットグループを削除する</a></li><li><a href="#toc61" tabindex="0">3. EC2インスタンスを終了する</a></li><li><a href="#toc62" tabindex="0">4. RDSインスタンスを削除する</a></li><li><a href="#toc63" tabindex="0">5. RDS DBサブネットグループを削除する</a></li><li><a href="#toc64" tabindex="0">6. SSM Parameter Storeのパラメータを削除する</a></li><li><a href="#toc65" tabindex="0">7. セキュリティグループを削除する</a></li><li><a href="#toc66" tabindex="0">8. ルートテーブルを削除する</a></li><li><a href="#toc67" tabindex="0">9. インターネットゲートウェイをデタッチ・削除する</a></li><li><a href="#toc68" tabindex="0">10. サブネットを削除する（4つ）</a></li><li><a href="#toc69" tabindex="0">11. VPCを削除する</a></li><li><a href="#toc70" tabindex="0">12. IAMロールを削除する</a></li><li><a href="#toc71" tabindex="0">13. キーペアを削除する（任意）</a></li></ol></li><li><a href="#toc72" tabindex="0">トラブルシューティング</a></li><li><a href="#toc73" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「EC2のIPが変わるたびに接続先を変えるのは面倒」「EC2を複数台に増やしてトラフィックを分散したい」——これを解決するのが <strong>ALB（Application Load Balancer）</strong> です。</p>
<p>この記事では、<strong>AWSコンソール（GUI）のみ</strong>を使って、ALB・EC2（Tomcat）・RDS MySQLの3層構成をゼロから手動構築するハンズオンを紹介します。</p>
<pre><code class="language-plaintext">インターネット
  ↓ HTTP(80)  ← ALB SGで全IPから許可
ALB（my-alb-alb）
  [パブリックサブネット1: 10.0.1.0/24 AZ-a]
  [パブリックサブネット2: 10.0.2.0/24 AZ-c]  ← ALBの2AZ要件
  ↓ HTTP(8080)  ← EC2 SGでALB SGからのみ許可（SG-to-SG）
EC2（my-alb-ap-instance）
  Tomcat（Javaアプリケーションサーバ）
  [パブリックサブネット1: 10.0.1.0/24 AZ-a]
  ↓ MySQL(3306)  ← RDS SGでEC2 SGからのみ許可（SG-to-SG）
RDS MySQL（my-alb-rds-mysql）
  [プライベートサブネット1: 10.0.3.0/24 AZ-a]

DBサブネットグループ
  ├── プライベートサブネット1（10.0.3.0/24）[AZ-a]
  └── プライベートサブネット2（10.0.4.0/24）[AZ-c]  ← 2AZ必須</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li>ALBのリスナー・ターゲットグループ・ヘルスチェックの概念を理解</li>
<li>EC2（Tomcat）をALBの後ろに隠して直接アクセスを遮断する設計</li>
<li>SG-to-SGを2段階で使う3層制御（インターネット→ALB→EC2→RDS）</li>
<li>ヘルスチェックで「Healthy」になるまでALBがトラフィックを転送しない仕組みを体験</li>
</ul>
<p><strong>このハンズオンのポイント：</strong></p>
<p>前フェーズ（EC2 + RDS 2層構成）ではEC2に直接アクセスしていましたが、今回はALBを前段に追加します。ALBのDNS名でアクセスし、EC2のIPアドレスが変わっても影響を受けない設計になります。</p>
<hr>
<blockquote>
<p><strong>この記事は <a href="https://caymezon.com/aws-handson-cloudformation-alb-ec2-rds/">CloudFormation版ハンズオン</a> の比較記事です。</strong><br />コンソール操作でALB・ターゲットグループ・ヘルスチェックを視覚的に学びたい方向けです。</p>
</blockquote>
<hr>
<p><!-- ![ALBのターゲットグループでHealthy確認後、ブラウザでTomcat画面が表示されている](images/alb-healthy-access.jpg) --></p>
<p><!-- <a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"> --></p>
<p><!-- <!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --> --></p>
<h2><span id="toc2">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>ALB（Application Load Balancer）</strong></td>
<td>HTTP/HTTPSトラフィックをEC2に振り分けるL7ロードバランサー。EC2の死活監視も行う</td>
</tr>
<tr>
<td><strong>ターゲットグループ</strong></td>
<td>ALBのトラフィック転送先（EC2インスタンスなど）をまとめたグループ</td>
</tr>
<tr>
<td><strong>リスナー</strong></td>
<td>ALBがトラフィックを受け付けるポート・プロトコルの設定（今回はHTTP:80）</td>
</tr>
<tr>
<td><strong>ヘルスチェック</strong></td>
<td>ALBがバックエンドEC2に定期的にHTTPリクエストを送り正常性を確認する仕組み。Unhealthyなインスタンスへはトラフィックを転送しない</td>
</tr>
<tr>
<td><strong>Tomcat</strong></td>
<td>JavaアプリケーションサーバーのOSS実装。デフォルトポート8080</td>
</tr>
<tr>
<td><strong>SG-to-SG制御</strong></td>
<td>セキュリティグループのルールでソースにIPでなく別SGを指定する設定</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">前フェーズとの違い</span></h2>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>Phase 2-1（EC2 + RDS）</th>
<th>Phase 2-2（ALB + EC2 + RDS）今回</th>
</tr>
</thead>
<tbody>
<tr>
<td>アクセス方法</td>
<td>EC2のパブリックIPに直接アクセス</td>
<td><strong>ALBのDNS名でアクセス</strong></td>
</tr>
<tr>
<td>Webサーバ</td>
<td>Apache httpd</td>
<td><strong>Tomcat（Java APサーバ）</strong></td>
</tr>
<tr>
<td>ロードバランシング</td>
<td>なし（EC2 1台）</td>
<td><strong>ALBによるHTTP負荷分散</strong></td>
</tr>
<tr>
<td>ヘルスチェック</td>
<td>なし</td>
<td><strong>ALBが定期的にEC2の死活監視</strong></td>
</tr>
<tr>
<td>EC2の直接公開</td>
<td>ポート80で直接公開</td>
<td><strong>ポート8080はALB SGからのみ許可</strong></td>
</tr>
<tr>
<td>サブネット数</td>
<td>3つ</td>
<td><strong>4つ（ALBの2AZ要件のため）</strong></td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">使用するAWSサービス</span></h2>
<table>
<thead>
<tr>
<th>サービス</th>
<th>役割</th>
<th>料金</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>VPC</strong></td>
<td>カスタムネットワーク空間</td>
<td>無料</td>
</tr>
<tr>
<td><strong>EC2</strong>（t2.micro）</td>
<td>APサーバ（Tomcat）</td>
<td>月750時間まで無料枠あり</td>
</tr>
<tr>
<td><strong>RDS MySQL</strong>（db.t3.micro）</td>
<td>マネージドDBサーバ</td>
<td>月750時間まで無料枠あり</td>
</tr>
<tr>
<td><strong>ALB</strong></td>
<td>ロードバランサー</td>
<td>約$0.008/時間 + LCU料金（<strong>無料枠なし</strong>）</td>
</tr>
<tr>
<td><strong>SSM Parameter Store</strong></td>
<td>DBパスワードの安全な保管</td>
<td>スタンダード層は無料</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>EC2にSSM・Parameter Store権限を付与</td>
<td>無料</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>注意</strong>: ALBは無料枠がありません。ハンズオン後は必ず削除してください。</p>
</blockquote>
<hr>
<h2><span id="toc5">構築するリソース一覧</span></h2>
<table>
<thead>
<tr>
<th>順序</th>
<th>リソース</th>
<th>役割</th>
</tr>
</thead>
<tbody>
<tr>
<td>⓪</td>
<td>（確認）自分のIPアドレス</td>
<td>SGの設定に使用</td>
</tr>
<tr>
<td>①</td>
<td>キーペア（<code>my-alb-key</code>）</td>
<td>EC2へのSSH認証鍵</td>
</tr>
<tr>
<td>②</td>
<td>VPC（<code>my-alb-vpc</code>）</td>
<td>独立したネットワーク空間</td>
</tr>
<tr>
<td>③</td>
<td>サブネット × 4</td>
<td>パブリック2 + プライベート2</td>
</tr>
<tr>
<td>④</td>
<td>インターネットゲートウェイ（<code>my-alb-igw</code>）</td>
<td>VPCをインターネットに接続</td>
</tr>
<tr>
<td>⑤</td>
<td>ルートテーブル × 2</td>
<td>パブリック/プライベートの通信経路</td>
</tr>
<tr>
<td>⑥</td>
<td>セキュリティグループ × 3</td>
<td>ALB用・EC2用・RDS用</td>
</tr>
<tr>
<td>⑦</td>
<td>IAMロール（<code>my-alb-ec2-role</code>）</td>
<td>EC2がSSM・Parameter Storeを使う権限</td>
</tr>
<tr>
<td>⑧</td>
<td>SSM Parameter Store</td>
<td>DBパスワードの保管</td>
</tr>
<tr>
<td>⑨</td>
<td>RDS DBサブネットグループ</td>
<td>RDSを配置できるサブネットを登録</td>
</tr>
<tr>
<td>⑩</td>
<td>RDS MySQL インスタンス</td>
<td>マネージドDBサーバ（作成に10〜15分）</td>
</tr>
<tr>
<td>⑪</td>
<td>EC2インスタンス（<code>my-alb-ap-instance</code>）</td>
<td>APサーバ（Tomcat）</td>
</tr>
<tr>
<td>⑫</td>
<td>ターゲットグループ（<code>my-alb-tg</code>）</td>
<td>ALBのトラフィック転送先の定義</td>
</tr>
<tr>
<td>⑬</td>
<td>ALB（<code>my-alb-alb</code>）+ リスナー</td>
<td>ロードバランサー本体</td>
</tr>
<tr>
<td>⑭</td>
<td>動作確認</td>
<td>ALB → EC2 → RDS接続テスト</td>
</tr>
<tr>
<td>⑮</td>
<td>リソース削除</td>
<td>課金停止</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc6">全体の作業順序</span></h2>
<pre><code class="language-plaintext">⓪ 自分のIPアドレスを確認
      ↓
① キーペア作成
      ↓
② VPC作成
      ↓
③ サブネット作成（4つ）
      ↓
④ インターネットゲートウェイ作成・アタッチ
      ↓
⑤ ルートテーブル設定（IGWルート追加 → サブネット関連付け）
      ↓
⑥ セキュリティグループ作成（ALB用・EC2用・RDS用）
      ↓
⑦ IAMロール作成
      ↓
⑧ SSM Parameter Store作成
      ↓
⑨ RDS DBサブネットグループ作成
      ↓
⑩ RDS MySQL インスタンス作成（※約10〜15分かかる）
      ↓
⑪ EC2インスタンス起動（Tomcat）
      ↓
⑫ ターゲットグループ作成
      ↓
⑬ ALB作成・リスナー設定
      ↓
⑭ 動作確認（ALB → EC2 → RDS）
      ↓
⑮ リソース削除</code></pre>
<hr>
<h2><span id="toc7">⓪ 自分のIPアドレスの確認</span></h2>
<p>ブラウザで以下のURLを開くか、コマンドで確認します。</p>
<pre><code class="language-plaintext">https://checkip.amazonaws.com</code></pre>
<p><strong>控えておく情報</strong>: 自分のIPアドレス（例: <code>203.0.113.1</code>）</p>
<blockquote>
<p>セキュリティグループで <code>203.0.113.1/32</code> の形式（末尾に <code>/32</code>）で使用します。</p>
</blockquote>
<hr>
<h2><span id="toc8">① キーペアの作成</span></h2>
<p><strong>AWSコンソール → EC2 → キーペア → 「キーペアを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-alb-key</code></td>
</tr>
<tr>
<td>キーペアのタイプ</td>
<td><strong>RSA</strong></td>
</tr>
<tr>
<td>プライベートキーファイル形式</td>
<td><strong>.pem</strong></td>
</tr>
</tbody>
</table>
<p>「キーペアを作成」をクリック。ダウンロードされた <code>.pem</code> ファイルを保存します。</p>
<pre><code class="language-plaintext">C:\Users\ユーザー名\.ssh\my-alb-key.pem</code></pre>
<hr>
<h2><span id="toc9">② VPCの作成</span></h2>
<p><strong>AWSコンソール → VPC → VPC → 「VPCを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>作成するリソース</td>
<td><strong>VPCのみ</strong></td>
</tr>
<tr>
<td>名前タグ</td>
<td><code>my-alb-vpc</code></td>
</tr>
<tr>
<td>IPv4 CIDR</td>
<td><code>10.0.0.0/16</code></td>
</tr>
</tbody>
</table>
<p>「VPCを作成」をクリック。</p>
<hr>
<h2><span id="toc10">③ サブネットの作成（4つ）</span></h2>
<p><strong>AWSコンソール → VPC → サブネット → 「サブネットを作成」</strong></p>
<p>VPCに <code>my-alb-vpc</code> を選択して、以下の4つを1回の操作で作成します（「新しいサブネットを追加」で追加できます）。</p>
<table>
<thead>
<tr>
<th>名前</th>
<th>AZ</th>
<th>IPv4 CIDR</th>
<th>用途</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>my-alb-public-subnet-1</code></td>
<td>ap-northeast-1<strong>a</strong></td>
<td><code>10.0.1.0/24</code></td>
<td>ALB + EC2</td>
</tr>
<tr>
<td><code>my-alb-public-subnet-2</code></td>
<td>ap-northeast-1<strong>c</strong></td>
<td><code>10.0.2.0/24</code></td>
<td>ALB（2AZ必須）</td>
</tr>
<tr>
<td><code>my-alb-private-subnet-1</code></td>
<td>ap-northeast-1<strong>a</strong></td>
<td><code>10.0.3.0/24</code></td>
<td>RDS配置</td>
</tr>
<tr>
<td><code>my-alb-private-subnet-2</code></td>
<td>ap-northeast-1<strong>c</strong></td>
<td><code>10.0.4.0/24</code></td>
<td>DBサブネットグループ用</td>
</tr>
</tbody>
</table>
<p>「サブネットを作成」をクリック。</p>
<blockquote>
<p><strong>ALBが2AZを必要とする理由</strong>: ALBは高可用性のため複数AZにまたがって配置されます。VPCを選択すると「少なくとも2つのAZのサブネットを指定してください」というバリデーションが入ります。</p>
</blockquote>
<p><!-- ![4つのサブネット作成画面](images/subnet-create.jpg) --></p>
<hr>
<h2><span id="toc11">④ インターネットゲートウェイの作成・アタッチ</span></h2>
<h3><span id="toc12">作成</span></h3>
<p><strong>AWSコンソール → VPC → インターネットゲートウェイ → 「インターネットゲートウェイを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前タグ</td>
<td><code>my-alb-igw</code></td>
</tr>
</tbody>
</table>
<p>「インターネットゲートウェイを作成」をクリック。</p>
<h3><span id="toc13">VPCへのアタッチ</span></h3>
<p>作成したIGWを選択 → 「アクション」→「VPCにアタッチ」→ <code>my-alb-vpc</code> を選択 → 「インターネットゲートウェイのアタッチ」</p>
<hr>
<h2><span id="toc14">⑤ ルートテーブルの設定</span></h2>
<blockquote>
<p><strong>注意</strong>: EC2を起動する前にこの手順を完了させてください。IGWルートがない状態でEC2を起動すると、UserDataのTomcatインストールが失敗します。</p>
</blockquote>
<h3><span id="toc15">5-1. パブリック用ルートテーブル</span></h3>
<p><strong>AWSコンソール → VPC → ルートテーブル → 「ルートテーブルを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-alb-public-rt</code></td>
</tr>
<tr>
<td>VPC</td>
<td><code>my-alb-vpc</code></td>
</tr>
</tbody>
</table>
<p>作成後、<code>my-alb-public-rt</code> を選択 → 「ルート」タブ → 「ルートを編集」→「ルートを追加」</p>
<table>
<thead>
<tr>
<th>送信先</th>
<th>ターゲット</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>0.0.0.0/0</code></td>
<td>インターネットゲートウェイ <code>my-alb-igw</code></td>
</tr>
</tbody>
</table>
<p>「変更を保存」をクリック。</p>
<p>次に「サブネットの関連付け」タブ → 「サブネットの関連付けを編集」→ <strong>パブリックサブネット2つ</strong>にチェック → 保存</p>
<ul>
<li><code>my-alb-public-subnet-1</code></li>
<li><code>my-alb-public-subnet-2</code></li>
</ul>
<h3><span id="toc16">5-2. プライベート用ルートテーブル</span></h3>
<p>同様に「ルートテーブルを作成」</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-alb-private-rt</code></td>
</tr>
<tr>
<td>VPC</td>
<td><code>my-alb-vpc</code></td>
</tr>
</tbody>
</table>
<p>「サブネットの関連付けを編集」→ <strong>プライベートサブネット2つ</strong>にチェック → 保存</p>
<ul>
<li><code>my-alb-private-subnet-1</code></li>
<li><code>my-alb-private-subnet-2</code></li>
</ul>
<hr>
<h2><span id="toc17">⑥ セキュリティグループの作成</span></h2>
<h3><span id="toc18">6-1. ALB用セキュリティグループ</span></h3>
<p><strong>AWSコンソール → EC2 → セキュリティグループ → 「セキュリティグループを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>セキュリティグループ名</td>
<td><code>my-alb-sg</code></td>
</tr>
<tr>
<td>説明</td>
<td><code>ALB SG - HTTP from internet</code></td>
</tr>
<tr>
<td>VPC</td>
<td><code>my-alb-vpc</code></td>
</tr>
</tbody>
</table>
<p>インバウンドルール:</p>
<table>
<thead>
<tr>
<th>タイプ</th>
<th>ポート</th>
<th>ソース</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>HTTP</td>
<td>80</td>
<td><code>0.0.0.0/0</code></td>
<td>HTTP from internet</td>
</tr>
</tbody>
</table>
<p>「セキュリティグループを作成」をクリック。</p>
<blockquote>
<p><strong>なぜ <code>0.0.0.0/0</code>（全開放）なのか</strong>: これまでのハンズオンではEC2が直接インターネットに露出していたため自分のIPだけに制限していました。今回はEC2の前にALBを置く3層構成のため、不特定多数のユーザーが使うWebサービスの入口であるALBは全開放が正しい設計です。</p>
<p>EC2（Tomcat）のセキュリティは次の6-2で設定するEC2 SGの「ALB SGからのみ8080を許可」によって守られます。</p>
</blockquote>
<h3><span id="toc19">6-2. EC2用セキュリティグループ</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>セキュリティグループ名</td>
<td><code>my-alb-ec2-sg</code></td>
</tr>
<tr>
<td>説明</td>
<td><code>EC2 Tomcat SG - Tomcat:8080 from ALB SG, SSH from MyIP</code></td>
</tr>
<tr>
<td>VPC</td>
<td><code>my-alb-vpc</code></td>
</tr>
</tbody>
</table>
<p>インバウンドルール:</p>
<table>
<thead>
<tr>
<th>タイプ</th>
<th>ポート</th>
<th>ソース</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>カスタムTCP</td>
<td>8080</td>
<td><code>my-alb-sg</code>（<strong>SGを選択</strong>）</td>
<td>Tomcat from ALB SG only</td>
</tr>
<tr>
<td>SSH</td>
<td>22</td>
<td><code>自分のIP/32</code></td>
<td>SSH from my IP</td>
</tr>
</tbody>
</table>
<p>アウトバウンドルール（<strong>変更しない</strong>）:</p>
<table>
<thead>
<tr>
<th>タイプ</th>
<th>プロトコル</th>
<th>送信先</th>
</tr>
</thead>
<tbody>
<tr>
<td>すべてのトラフィック</td>
<td>すべて</td>
<td><code>0.0.0.0/0</code></td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>アウトバウンドルールを変更してはいけない理由</strong>: EC2がTomcatのインストール（Javaのダウンロードなど）でインターネットにアクセスするために必要です。誤って削除するとEC2からの通信が遮断されます。</p>
</blockquote>
<blockquote>
<p><strong>SG-to-SG制御</strong>: ポート8080のソースにIPアドレスではなく <code>my-alb-sg</code> のSGを指定します。ALBを経由したトラフィックのみEC2に到達でき、インターネットから直接8080番ポートへのアクセスは不可になります。</p>
</blockquote>
<h3><span id="toc20">6-3. RDS用セキュリティグループ</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>セキュリティグループ名</td>
<td><code>my-alb-rds-sg</code></td>
</tr>
<tr>
<td>説明</td>
<td><code>RDS MySQL SG - MySQL:3306 from EC2 SG only</code></td>
</tr>
<tr>
<td>VPC</td>
<td><code>my-alb-vpc</code></td>
</tr>
</tbody>
</table>
<p>インバウンドルール:</p>
<table>
<thead>
<tr>
<th>タイプ</th>
<th>ポート</th>
<th>ソース</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>MySQL/Aurora</td>
<td>3306</td>
<td><code>my-alb-ec2-sg</code>（<strong>SGを選択</strong>）</td>
<td>MySQL from EC2 SG only</td>
</tr>
</tbody>
</table>
<p><!-- ![3段階のSG設定（ALB SG → EC2 SG → RDS SG）](images/sg-layers.jpg) --></p>
<hr>
<h2><span id="toc21">⑦ IAMロールの作成</span></h2>
<p><strong>AWSコンソール → IAM → ロール → 「ロールを作成」</strong></p>
<h3><span id="toc22">信頼されたエンティティ</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>信頼されたエンティティタイプ</td>
<td><strong>AWSのサービス</strong></td>
</tr>
<tr>
<td>サービス</td>
<td><strong>EC2</strong></td>
</tr>
</tbody>
</table>
<h3><span id="toc23">許可ポリシー</span></h3>
<p>以下の2つのポリシーを検索して追加します。</p>
<table>
<thead>
<tr>
<th>ポリシー名</th>
<th>用途</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>AmazonSSMManagedInstanceCore</code></td>
<td>Session Manager接続用</td>
</tr>
<tr>
<td><code>AmazonSSMReadOnlyAccess</code></td>
<td>Parameter Storeからパスワードを読み取る</td>
</tr>
</tbody>
</table>
<h3><span id="toc24">ロール名</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ロール名</td>
<td><code>my-alb-ec2-role</code></td>
</tr>
</tbody>
</table>
<p>「ロールを作成」をクリック。</p>
<hr>
<h2><span id="toc25">⑧ SSM Parameter Storeの作成</span></h2>
<p><strong>AWSコンソール → Systems Manager → パラメータストア → 「パラメータの作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>/my/alb/db-password</code></td>
</tr>
<tr>
<td>説明</td>
<td><code>RDS MySQL master password for ALB hands-on</code></td>
</tr>
<tr>
<td>層</td>
<td><strong>スタンダード</strong></td>
</tr>
<tr>
<td>タイプ</td>
<td><strong>安全な文字列</strong>（SecureString・推奨）</td>
</tr>
<tr>
<td>KMS キーID</td>
<td><code>alias/aws/ssm</code>（デフォルト）</td>
</tr>
<tr>
<td>値</td>
<td><code>Handson1234!</code></td>
</tr>
</tbody>
</table>
<p>「パラメータの作成」をクリック。</p>
<blockquote>
<p><strong>「安全な文字列」（SecureString）とは</strong>: パスワードなどの機密情報をKMSで暗号化して保存するタイプです。取得時は <code>--with-decryption</code> オプションが必要です。CloudFormation版はString型で作成しますが、コンソールではSecureStringを推奨します。</p>
</blockquote>
<hr>
<h2><span id="toc26">⑨ RDS DBサブネットグループの作成</span></h2>
<p><strong>AWSコンソール → Aurora and RDS → サブネットグループ → 「DBサブネットグループの作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-alb-rds-subnet-group</code></td>
</tr>
<tr>
<td>説明</td>
<td><code>RDS subnet group for ALB hands-on</code></td>
</tr>
<tr>
<td>VPC</td>
<td><code>my-alb-vpc</code></td>
</tr>
</tbody>
</table>
<p>アベイラビリティーゾーンとサブネットの追加:</p>
<table>
<thead>
<tr>
<th>AZ</th>
<th>サブネット</th>
</tr>
</thead>
<tbody>
<tr>
<td>ap-northeast-1a</td>
<td><code>my-alb-private-subnet-1</code></td>
</tr>
<tr>
<td>ap-northeast-1c</td>
<td><code>my-alb-private-subnet-2</code></td>
</tr>
</tbody>
</table>
<p>「作成」をクリック。</p>
<hr>
<h2><span id="toc27">⑩ RDS MySQL インスタンスの作成</span></h2>
<p><strong>AWSコンソール → Aurora and RDS → データベース → 「データベースの作成 ▲」→「フル設定」</strong></p>
<blockquote>
<p><strong>注意</strong>: RDSの作成は<strong>約10〜15分</strong>かかります。</p>
</blockquote>
<h3><span id="toc28">エンジンの選択</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>エンジンのタイプ</td>
<td><strong>MySQL</strong></td>
</tr>
<tr>
<td>エンジンバージョン</td>
<td><strong>MySQL 8.0.x</strong>（最新）</td>
</tr>
</tbody>
</table>
<h3><span id="toc29">テンプレート</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>テンプレート</td>
<td><strong>無料利用枠</strong></td>
</tr>
</tbody>
</table>
<h3><span id="toc30">設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>DBインスタンス識別子</td>
<td><code>my-alb-rds-mysql</code></td>
</tr>
<tr>
<td>マスターユーザー名</td>
<td><code>admin</code></td>
</tr>
<tr>
<td>マスターパスワード</td>
<td><code>Handson1234!</code></td>
</tr>
</tbody>
</table>
<h3><span id="toc31">インスタンスの設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>DBインスタンスクラス</td>
<td><strong>db.t3.micro</strong></td>
</tr>
</tbody>
</table>
<h3><span id="toc32">ストレージ</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ストレージタイプ</td>
<td><strong>汎用SSD (gp2)</strong></td>
</tr>
<tr>
<td>割り当てられたストレージ</td>
<td><code>20</code> GiB</td>
</tr>
<tr>
<td>ストレージの自動スケーリング</td>
<td>チェックを<strong>外す</strong></td>
</tr>
</tbody>
</table>
<h3><span id="toc33">接続</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>コンピューティングリソース</td>
<td><strong>EC2コンピューティングリソースに接続しない</strong></td>
</tr>
<tr>
<td>VPC</td>
<td><code>my-alb-vpc</code></td>
</tr>
<tr>
<td>DBサブネットグループ</td>
<td><code>my-alb-rds-subnet-group</code></td>
</tr>
<tr>
<td>パブリックアクセス</td>
<td><strong>なし</strong></td>
</tr>
<tr>
<td>VPCセキュリティグループ</td>
<td><strong>既存の選択</strong> → <code>my-alb-rds-sg</code>（<code>default</code> は削除）</td>
</tr>
<tr>
<td>アベイラビリティーゾーン</td>
<td><code>ap-northeast-1a</code></td>
</tr>
</tbody>
</table>
<h3><span id="toc34">追加設定</span></h3>
<p>「追加設定」を開きます。</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>最初のデータベース名</td>
<td><code>sampledb</code></td>
</tr>
<tr>
<td>自動バックアップを有効にする</td>
<td>チェックを<strong>外す</strong></td>
</tr>
</tbody>
</table>
<p>「データベースの作成」をクリック。</p>
<p><strong>控えておく情報</strong>: 作成完了後に表示される「エンドポイント」のホスト名</p>
<pre><code class="language-plaintext">my-alb-rds-mysql.xxxxxxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com</code></pre>
<hr>
<h2><span id="toc35">⑪ EC2インスタンスの起動</span></h2>
<blockquote>
<p><strong>注意</strong>: EC2を起動する前に⑤のルートテーブル設定が完了していることを確認してください。IGWルートがない状態で起動するとTomcatのインストールが失敗します。</p>
</blockquote>
<p><strong>AWSコンソール → EC2 → インスタンス → 「インスタンスを起動」</strong></p>
<h3><span id="toc36">基本設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-alb-ap-instance</code></td>
</tr>
<tr>
<td>AMI</td>
<td><strong>Amazon Linux 2023 AMI</strong></td>
</tr>
<tr>
<td>インスタンスタイプ</td>
<td><strong>t2.micro</strong></td>
</tr>
<tr>
<td>キーペア</td>
<td><code>my-alb-key</code></td>
</tr>
</tbody>
</table>
<h3><span id="toc37">ネットワーク設定</span></h3>
<p>「編集」をクリックして以下を設定します。</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>VPC</td>
<td><code>my-alb-vpc</code></td>
</tr>
<tr>
<td>サブネット</td>
<td><code>my-alb-public-subnet-1</code></td>
</tr>
<tr>
<td>パブリックIPの自動割り当て</td>
<td><strong>有効化</strong></td>
</tr>
<tr>
<td>ファイアウォール（セキュリティグループ）</td>
<td><strong>既存のセキュリティグループを選択</strong></td>
</tr>
<tr>
<td>セキュリティグループ</td>
<td><code>my-alb-ec2-sg</code></td>
</tr>
</tbody>
</table>
<h3><span id="toc38">IAMロール</span></h3>
<p>「高度な詳細」→「IAMインスタンスプロファイル」→ <code>my-alb-ec2-role</code> を選択</p>
<h3><span id="toc39">UserData</span></h3>
<p>「高度な詳細」→「ユーザーデータ」に以下を貼り付けます。</p>
<blockquote>
<p><strong>Tomcatバージョンの確認</strong>: <code>TOMCAT_VERSION</code> の値は <a href="https://archive.apache.org/dist/tomcat/tomcat-10/">https://archive.apache.org/dist/tomcat/tomcat-10/</a> で利用可能なバージョンを確認して設定してください。</p>
</blockquote>
<pre><code class="language-bash">#!/bin/bash
set -xe
exec &gt; &gt;(tee /var/log/user-data.log) 2&gt;&amp;1

dnf update -y
dnf install -y java-17-amazon-corretto wget

# https://archive.apache.org/dist/tomcat/tomcat-10/
TOMCAT_VERSION="10.1.28"
cd /opt
wget -q https://archive.apache.org/dist/tomcat/tomcat-10/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz
tar xzf apache-tomcat-${TOMCAT_VERSION}.tar.gz
mv apache-tomcat-${TOMCAT_VERSION} tomcat
chmod +x /opt/tomcat/bin/*.sh

# テスト用Webアプリのデプロイ
cat &gt; /opt/tomcat/webapps/ROOT/index.html &lt;&lt; 'HTMLEOF'
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;body&gt;
&lt;h1&gt;AP Server - Phase 2-2 ALB + Tomcat + RDS&lt;/h1&gt;
&lt;p&gt;This server is load balanced by ALB and connects to RDS MySQL.&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
HTMLEOF

# Tomcat起動
/opt/tomcat/bin/startup.sh</code></pre>
<h3><span id="toc40">タグ</span></h3>
<table>
<thead>
<tr>
<th>キー</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Cost</code></td>
<td><code>（任意）</code></td>
</tr>
</tbody>
</table>
<p>「インスタンスを起動」をクリック。起動完了まで約2〜3分待ちます。</p>
<blockquote>
<p><strong>Tomcatの起動について</strong>: EC2の「実行中」状態になった後、UserDataによるTomcatのインストール・起動に<strong>さらに約5〜10分</strong>かかります。ALBのヘルスチェックが「Healthy」になるまで待ってからアクセスしてください。</p>
</blockquote>
<p><strong>控えておく情報</strong>: インスタンスのパブリックIPアドレス</p>
<hr>
<h2><span id="toc41">⑫ ターゲットグループの作成</span></h2>
<p><strong>AWSコンソール → EC2 → ターゲットグループ → 「ターゲットグループの作成」</strong></p>
<h3><span id="toc42">ターゲットタイプとプロトコル</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ターゲットタイプ</td>
<td><strong>インスタンス</strong></td>
</tr>
<tr>
<td>ターゲットグループ名</td>
<td><code>my-alb-tg</code></td>
</tr>
<tr>
<td>プロトコル</td>
<td><strong>HTTP</strong></td>
</tr>
<tr>
<td>ポート</td>
<td><strong>8080</strong></td>
</tr>
<tr>
<td>VPC</td>
<td><code>my-alb-vpc</code></td>
</tr>
<tr>
<td>プロトコルバージョン</td>
<td><strong>HTTP1</strong></td>
</tr>
</tbody>
</table>
<h3><span id="toc43">ヘルスチェック</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ヘルスチェックプロトコル</td>
<td>HTTP</td>
</tr>
<tr>
<td>ヘルスチェックパス</td>
<td><code>/</code></td>
</tr>
</tbody>
</table>
<p>「次へ」をクリック。</p>
<h3><span id="toc44">ターゲットの登録</span></h3>
<p>「使用可能なインスタンス」から <code>my-alb-ap-instance</code> を選択します。</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ポート</td>
<td><code>8080</code></td>
</tr>
</tbody>
</table>
<p>「保留中として以下を含める」をクリック → 下部の「ターゲットを確認」にインスタンスが表示されたことを確認して「次へ」をクリック。</p>
<p>「ターゲットグループの作成」をクリック。</p>
<blockquote>
<p><strong>ヘルスチェックとは</strong>: ALBが定期的にEC2のポート8080の <code>/</code> にHTTPリクエストを送り、正常（HTTP 200）が返るか確認する仕組みです。ステータスが「Healthy」になるまではALBはそのEC2にトラフィックを転送しません。</p>
</blockquote>
<p><!-- ![ターゲットグループの作成・EC2登録画面](images/target-group-create.jpg) --></p>
<hr>
<h2><span id="toc45">⑬ ALBの作成・リスナー設定</span></h2>
<p><strong>AWSコンソール → EC2 → ロードバランサー → 「ロードバランサーの作成」</strong></p>
<p>「Application Load Balancer」の「作成」をクリック。</p>
<h3><span id="toc46">基本的な設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ロードバランサー名</td>
<td><code>my-alb-alb</code></td>
</tr>
<tr>
<td>スキーム</td>
<td><strong>インターネット向け</strong></td>
</tr>
<tr>
<td>IPアドレスタイプ</td>
<td><strong>IPv4</strong></td>
</tr>
</tbody>
</table>
<h3><span id="toc47">ネットワークマッピング</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>VPC</td>
<td><code>my-alb-vpc</code></td>
</tr>
<tr>
<td>アベイラビリティーゾーン</td>
<td><code>ap-northeast-1a</code>（<code>my-alb-public-subnet-1</code>）と <code>ap-northeast-1c</code>（<code>my-alb-public-subnet-2</code>）の<strong>両方</strong>を選択</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>ALBは必ず2つ以上のAZを選択します。</strong> 1つのAZだけを選ぶとエラーになります。</p>
</blockquote>
<h3><span id="toc48">セキュリティグループ</span></h3>
<p><code>my-alb-sg</code> のみを選択（デフォルトSGは削除）。</p>
<h3><span id="toc49">リスナーとルーティング</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>プロトコル</td>
<td>HTTP</td>
</tr>
<tr>
<td>ポート</td>
<td>80</td>
</tr>
<tr>
<td>デフォルトアクション</td>
<td><code>my-alb-tg</code> に転送</td>
</tr>
</tbody>
</table>
<p>「ロードバランサーの作成」をクリック。</p>
<p><strong>控えておく情報</strong>: 「DNS名」（例: <code>my-alb-alb-1234567890.ap-northeast-1.elb.amazonaws.com</code>）</p>
<p><!-- ![ALB作成完了・DNS名の確認画面](images/alb-created.jpg) --></p>
<hr>
<h2><span id="toc50">⑭ 動作確認</span></h2>
<h3><span id="toc51">14-1. ALBのヘルスチェック確認</span></h3>
<p><strong>EC2 → ターゲットグループ → <code>my-alb-tg</code> → 「ターゲット」タブ</strong></p>
<p><code>my-alb-ap-instance</code> のステータスが <strong>「Healthy」</strong> になるまで待ちます（5〜10分）。</p>
<table>
<thead>
<tr>
<th>ステータス</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>initial</code></td>
<td>初期ヘルスチェック中（待つ）</td>
</tr>
<tr>
<td><code>healthy</code></td>
<td>正常（トラフィック転送される）</td>
</tr>
<tr>
<td><code>unhealthy</code></td>
<td>異常（Tomcatが起動していない可能性）</td>
</tr>
</tbody>
</table>
<blockquote>
<p><code>unhealthy</code> が続く場合はEC2にSSH接続して <code>sudo cat /var/log/user-data.log</code> でUserDataのエラーを確認してください。</p>
</blockquote>
<p><!-- ![ターゲットグループのHealthy確認画面](images/target-healthy.jpg) --></p>
<h3><span id="toc52">14-2. ALB経由でWebアクセス確認</span></h3>
<p>ブラウザで以下のURLにアクセスします。</p>
<pre><code class="language-plaintext">http://（⑬で控えたALBのDNS名）</code></pre>
<p>「AP Server - Phase 2-2 ALB + Tomcat + RDS」と表示されれば正常です。</p>
<blockquote>
<p>EC2のパブリックIPに直接アクセスしても表示されません（ポート8080はALB SGからのみ許可しているため）。これが3層構成のポイントです。</p>
</blockquote>
<h3><span id="toc53">14-3. EC2にSSH接続する</span></h3>
<pre><code class="language-cmd">ssh -i C:\Users\ユーザー名\.ssh\my-alb-key.pem ec2-user@（EC2パブリックIP）</code></pre>
<h3><span id="toc54">14-4. Parameter StoreからDBパスワードを取得する</span></h3>
<pre><code class="language-bash">aws ssm get-parameter \
  --name "/my/alb/db-password" \
  --query "Parameter.Value" \
  --output text \
  --region ap-northeast-1 \
  --with-decryption</code></pre>
<p><code>Handson1234!</code> と表示されれば成功です。</p>
<blockquote>
<p><strong><code>--with-decryption</code> について</strong>: コンソールでSecureStringとして作成した場合は必須です。このフラグがないと暗号化されたままの文字列が返ってきます。</p>
</blockquote>
<h3><span id="toc55">14-5. RDSへのMySQL接続テスト</span></h3>
<p>MySQLクライアントをインストールします（Amazon Linux 2023では <code>mariadb105</code> を使います）。</p>
<pre><code class="language-bash">sudo dnf install -y mariadb105</code></pre>
<pre><code class="language-bash"># 変数にエンドポイントを代入（⑩で控えた値に置き換える）
RDS_ENDPOINT="my-alb-rds-mysql.xxxxxxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com"

# Parameter StoreからDBパスワードを取得して接続
DB_PASSWORD=$(aws ssm get-parameter \
  --name "/my/alb/db-password" \
  --query "Parameter.Value" \
  --output text \
  --region ap-northeast-1 \
  --with-decryption)

mysql -h $RDS_ENDPOINT -u admin -p"$DB_PASSWORD" sampledb</code></pre>
<p>接続成功後、SQL操作を確認します。</p>
<pre><code class="language-sql">-- テーブル作成
CREATE TABLE items (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- データ挿入
INSERT INTO items (name) VALUES ('Apple'), ('Banana');

-- データ確認
SELECT * FROM items;

-- 後片付け
DROP TABLE items;

EXIT;</code></pre>
<p><!-- ![EC2からRDS MySQLへの接続成功画面](images/rds-mysql-connect.jpg) --></p>
<h3><span id="toc56">14-6. SSH接続を切断する</span></h3>
<pre><code class="language-bash">exit</code></pre>
<hr>
<h2><span id="toc57">⑮ リソースの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除します。</strong></p>
<blockquote>
<p><strong>ALBの課金について</strong>: ALBはインスタンスが稼働している間は課金されます（約$0.008/時間 + LCU料金）。不要になったら必ず削除してください。</p>
</blockquote>
<h3><span id="toc58">削除順序</span></h3>
<p>依存関係があるため、<strong>必ずこの順番</strong>で削除します。</p>
<pre><code class="language-plaintext">1. ALBを削除
2. ターゲットグループを削除
3. EC2インスタンスを終了
4. RDSインスタンスを削除（約10〜15分）
5. RDS DBサブネットグループを削除
6. SSM Parameter Storeのパラメータを削除
7. セキュリティグループを削除（RDS用 → EC2用 → ALB用の順）
8. ルートテーブルの関連付け解除・削除
9. インターネットゲートウェイをデタッチ・削除
10. サブネットを削除（4つ）
11. VPCを削除
12. IAMロールを削除
13. キーペアを削除（任意）</code></pre>
<h3><span id="toc59">1. ALBを削除する</span></h3>
<p><strong>EC2 → ロードバランサー → <code>my-alb-alb</code> を選択 → 「アクション」→「削除」</strong></p>
<p>確認フィールドに <code>確認</code> と入力 → 「削除」をクリック。</p>
<blockquote>
<p>ALBを削除するとリスナーも一緒に削除されます。</p>
</blockquote>
<h3><span id="toc60">2. ターゲットグループを削除する</span></h3>
<p><strong>EC2 → ターゲットグループ → <code>my-alb-tg</code> を選択 → 「アクション」→「削除」</strong></p>
<h3><span id="toc61">3. EC2インスタンスを終了する</span></h3>
<p><strong>EC2 → インスタンス → <code>my-alb-ap-instance</code> を選択 → 「インスタンスの状態」→「インスタンスを終了」</strong></p>
<p>「終了済み」になるまで待ちます（2〜5分）。</p>
<h3><span id="toc62">4. RDSインスタンスを削除する</span></h3>
<p><strong>Aurora and RDS → データベース → <code>my-alb-rds-mysql</code> を選択 → 「アクション」→「削除」</strong></p>
<table>
<thead>
<tr>
<th>項目</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>最終スナップショットを作成</td>
<td><strong>チェックを外したまま</strong></td>
</tr>
<tr>
<td>「私は〜を了承します。」</td>
<td><strong>チェックを入れる</strong></td>
</tr>
<tr>
<td>確認フィールド</td>
<td><code>delete me</code> と入力</td>
</tr>
</tbody>
</table>
<p>「削除」をクリック。削除完了まで<strong>約10〜15分</strong>かかります。</p>
<h3><span id="toc63">5. RDS DBサブネットグループを削除する</span></h3>
<p><strong>Aurora and RDS → サブネットグループ → <code>my-alb-rds-subnet-group</code> → 「削除」</strong></p>
<blockquote>
<p>RDSインスタンスが完全に削除されてから行います。</p>
</blockquote>
<h3><span id="toc64">6. SSM Parameter Storeのパラメータを削除する</span></h3>
<p><strong>Systems Manager → パラメータストア → <code>/my/alb/db-password</code> → 「削除」</strong></p>
<h3><span id="toc65">7. セキュリティグループを削除する</span></h3>
<p><strong>EC2 → セキュリティグループ</strong></p>
<p>依存関係があるため以下の順番で削除します。</p>
<ol>
<li><code>my-alb-rds-sg</code> → 「アクション」→「セキュリティグループを削除」</li>
<li><code>my-alb-ec2-sg</code> → 「アクション」→「セキュリティグループを削除」</li>
<li><code>my-alb-sg</code> → 「アクション」→「セキュリティグループを削除」</li>
</ol>
<h3><span id="toc66">8. ルートテーブルを削除する</span></h3>
<p><strong>VPC → ルートテーブル</strong></p>
<ol>
<li><code>my-alb-public-rt</code> → 「サブネットの関連付け」→「編集」→ チェックを全て外す → 「保存」→「アクション」→「ルートテーブルの削除」</li>
<li><code>my-alb-private-rt</code> → 同様に操作</li>
</ol>
<h3><span id="toc67">9. インターネットゲートウェイをデタッチ・削除する</span></h3>
<p><strong>VPC → インターネットゲートウェイ</strong></p>
<ol>
<li><code>my-alb-igw</code> を選択 → 「アクション」→「VPCからデタッチ」→「デタッチ」</li>
<li>「アクション」→「インターネットゲートウェイの削除」</li>
</ol>
<h3><span id="toc68">10. サブネットを削除する（4つ）</span></h3>
<p><strong>VPC → サブネット</strong></p>
<p>4つのサブネットをすべて選択 → 「アクション」→「サブネットの削除」</p>
<ul>
<li><code>my-alb-public-subnet-1</code></li>
<li><code>my-alb-public-subnet-2</code></li>
<li><code>my-alb-private-subnet-1</code></li>
<li><code>my-alb-private-subnet-2</code></li>
</ul>
<h3><span id="toc69">11. VPCを削除する</span></h3>
<p><strong>VPC → お使いのVPC → <code>my-alb-vpc</code> を選択 → 「アクション」→「VPCの削除」</strong></p>
<h3><span id="toc70">12. IAMロールを削除する</span></h3>
<p><strong>IAM → ロール → <code>my-alb-ec2-role</code> を選択 → 「削除」</strong></p>
<h3><span id="toc71">13. キーペアを削除する（任意）</span></h3>
<p><strong>EC2 → キーペア → <code>my-alb-key</code> を選択 → 「アクション」→「削除」</strong></p>
<hr>
<h2><span id="toc72">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>ALBに繋がらない（タイムアウト）</td>
<td>ALB SGのインバウンドルールにHTTP:80がない</td>
<td>ALB SGを確認・修正</td>
</tr>
<tr>
<td>ALBに繋がるが502エラー</td>
<td>TomcatがまだEC2で起動していない</td>
<td>5〜10分待つか <code>sudo cat /var/log/user-data.log</code> 確認</td>
</tr>
<tr>
<td>ALBに繋がるが503エラー</td>
<td>ターゲットグループにHealthyなインスタンスがない</td>
<td>TG → ターゲットのステータスを確認</td>
</tr>
<tr>
<td>Unhealthyが続く</td>
<td>Tomcatの起動失敗</td>
<td>SSH接続して <code>sudo /opt/tomcat/bin/startup.sh</code> を手動実行</td>
</tr>
<tr>
<td>Unhealthyが続く（UserDataも失敗）</td>
<td>EC2 SGのアウトバウンドルールが削除されている</td>
<td>EC2 SG → アウトバウンドルールに「すべてのトラフィック 0.0.0.0/0」を追加</td>
</tr>
<tr>
<td>EC2にSSH接続できない</td>
<td>SGのSSH許可IPが違う</td>
<td>EC2 SGのインバウンドSSH規則を現在のIPに更新</td>
</tr>
<tr>
<td>MySQLに接続できない</td>
<td>RDS SGのソースがEC2 SGのIDでない</td>
<td>RDS SGのインバウンドルールを確認</td>
</tr>
<tr>
<td><code>ERROR 1049: Unknown database &#39;sampledb&#39;</code></td>
<td>RDS作成時にDB名を指定し忘れた</td>
<td>MySQLに接続して <code>CREATE DATABASE sampledb;</code> を実行</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc73">まとめ</span></h2>
<table>
<thead>
<tr>
<th>ステップ</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>①〜⑤</td>
<td>VPC / サブネット4つ / IGW / ルートテーブルの設定</td>
</tr>
<tr>
<td>⑥</td>
<td><strong>3段階のSG</strong>（ALB SG → EC2 SG → RDS SG）でSG-to-SG制御</td>
</tr>
<tr>
<td>⑦⑧</td>
<td>IAMロール + Parameter Store（SecureString）でパスワードを安全に管理</td>
</tr>
<tr>
<td>⑨⑩</td>
<td>DBサブネットグループ + RDS MySQL 8.0</td>
</tr>
<tr>
<td>⑪</td>
<td>EC2起動（UserDataでTomcat自動セットアップ）</td>
</tr>
<tr>
<td>⑫⑬</td>
<td>ターゲットグループ + ALB作成。Healthyになるまで待つ</td>
</tr>
<tr>
<td>⑭</td>
<td>ALB DNS名でアクセス → EC2 → Parameter Store → RDS への接続テスト</td>
</tr>
</tbody>
</table>
<p><strong>前フェーズ（EC2 + RDS）との最大の違い</strong>は、EC2がインターネットに直接露出しない点です。ALBがHTTP:80のトラフィックを受け取り、EC2にはALBを経由したポート8080のみが開放されています。スケールアウト時はターゲットグループにEC2を追加するだけで負荷分散できます。</p>
<p>CloudFormationで同じ構成を自動化したい場合は、<a href="https://caymezon.com/aws-handson-cloudformation-alb-ec2-rds/">CloudFormation版ハンズオン</a>を参照してください。コマンド1本で27リソースを一括デプロイできます。</p><p>The post <a href="https://caymezon.com/aws-handson-console-alb-ec2-rds/">AWSコンソールでALB + EC2(Tomcat) + RDS 3層構成を構築する手順【ヘルスチェック / SG-to-SG制御】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-console-alb-ec2-rds/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CloudFormationでALB + EC2(Tomcat) + RDS 3層構成を自動構築する手順【27リソース一括デプロイ / コンソール版との比較付き】</title>
		<link>https://caymezon.com/aws-handson-cloudformation-alb-ec2-rds/</link>
					<comments>https://caymezon.com/aws-handson-cloudformation-alb-ec2-rds/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Mon, 13 Apr 2026 00:09:05 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[3層構成]]></category>
		<category><![CDATA[ALB]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSCLI]]></category>
		<category><![CDATA[CloudFormation]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[IaC]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Parameter Store]]></category>
		<category><![CDATA[RDS]]></category>
		<category><![CDATA[SSM]]></category>
		<category><![CDATA[Tomcat]]></category>
		<category><![CDATA[VPC]]></category>
		<category><![CDATA[ターゲットグループ]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[ヘルスチェック]]></category>
		<category><![CDATA[ロードバランサー]]></category>
		<category><![CDATA[初心者]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20356</guid>

					<description><![CDATA[<p>目次 はじめにCloudFormation vs コンソール：どれだけ違うかキーワード解説前提条件構築されるリソース（約27個）template.yaml（完全版）作業順序【重要】⓪ 自分のIPアドレスを確認する① キー [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-cloudformation-alb-ec2-rds/">CloudFormationでALB + EC2(Tomcat) + RDS 3層構成を自動構築する手順【27リソース一括デプロイ / コンソール版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">CloudFormation vs コンソール：どれだけ違うか</a></li><li><a href="#toc3" tabindex="0">キーワード解説</a></li><li><a href="#toc4" tabindex="0">前提条件</a></li><li><a href="#toc5" tabindex="0">構築されるリソース（約27個）</a></li><li><a href="#toc6" tabindex="0">template.yaml（完全版）</a></li><li><a href="#toc7" tabindex="0">作業順序</a></li><li><a href="#toc8" tabindex="0">【重要】⓪ 自分のIPアドレスを確認する</a></li><li><a href="#toc9" tabindex="0">① キーペアの作成（コンソールで実施）</a></li><li><a href="#toc10" tabindex="0">② プロジェクトフォルダに移動する</a></li><li><a href="#toc11" tabindex="0">③ スタックの作成</a></li><li><a href="#toc12" tabindex="0">④ 作成完了・Outputsの確認</a><ol><li><a href="#toc13" tabindex="0">作成状況の確認</a></li><li><a href="#toc14" tabindex="0">Outputs（接続情報）の確認</a></li></ol></li><li><a href="#toc15" tabindex="0">⑤ 動作確認</a><ol><li><a href="#toc16" tabindex="0">ALBのヘルスチェック確認</a></li><li><a href="#toc17" tabindex="0">ALB経由でWebアクセス確認</a></li><li><a href="#toc18" tabindex="0">EC2にSSH接続する</a></li><li><a href="#toc19" tabindex="0">Parameter StoreからDBパスワードを取得する</a></li><li><a href="#toc20" tabindex="0">RDSへのMySQL接続テスト</a></li></ol></li><li><a href="#toc21" tabindex="0">⑥ スタックの削除</a><ol><li><a href="#toc22" tabindex="0">削除状況の確認</a></li><li><a href="#toc23" tabindex="0">キーペアの手動削除</a></li></ol></li><li><a href="#toc24" tabindex="0">コンソール版との比較</a></li><li><a href="#toc25" tabindex="0">トラブルシューティング</a><ol><li><a href="#toc26" tabindex="0">失敗時の詳細確認コマンド</a></li></ol></li><li><a href="#toc27" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「コンソールで40〜50分かかったALB + EC2(Tomcat) + RDS環境をコードで再現したい」——それを実現するのが <strong>AWS CloudFormation</strong> です。</p>
<p>この記事では、<code>template.yaml</code> 1ファイルにVPC・サブネット・セキュリティグループ・IAMロール・SSM Parameter Store・RDS・ALB・ターゲットグループ・EC2（約27リソース）を定義し、<strong>コマンド1本で3層構成を一括構築するハンズオン</strong>を紹介します。コンソール版（<a href="https://caymezon.com/aws-handson-console-alb-ec2-rds/">AWSコンソール版ハンズオン</a>）と全く同じ構成をCloudFormationで自動化します。</p>
<pre><code class="language-plaintext">ローカル環境（VSCode）
  ├── template.yaml（約27リソースを定義）
  └── AWS CLI コマンド
        ↓ スタック作成（コマンド1本）
AWS環境
  └── VPC（10.0.0.0/16）
        ├── パブリックサブネット1（10.0.1.0/24 / AZ-a）← ALB + EC2
        ├── パブリックサブネット2（10.0.2.0/24 / AZ-c）← ALB（2AZ必須）
        ├── プライベートサブネット1（10.0.3.0/24 / AZ-a）← RDS配置
        ├── プライベートサブネット2（10.0.4.0/24 / AZ-c）← DBサブネットグループ用
        ├── ALB SG → EC2 SG → RDS SG（3段階のSG-to-SG制御）
        ├── SSM Parameter Store: /my/alb/db-password
        ├── RDS MySQL 8.0（db.t3.micro）
        ├── ALB（HTTP:80 → ターゲットグループ → EC2:8080）
        └── EC2（t2.micro / Tomcat / UserDataで自動セットアップ）</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li>ALB・ターゲットグループ・リスナーを <code>template.yaml</code> で一括定義する方法</li>
<li><code>TomcatVersion</code> パラメータでTomcatのバージョンを切り替える設計</li>
<li>ALBの2AZ要件をCloudFormationでどう表現するか</li>
<li><code>delete-stack</code> 1本でALB・RDS・IAMなど27リソースを自動削除</li>
</ul>
<p><strong>このハンズオンの特徴：</strong></p>
<ul>
<li>コンソール版では40〜50分・13ステップかかった作業が、コマンド1本（RDS待ち15〜20分込み）で完了</li>
<li><code>delete-stack</code> 1本でALBのリスナー含む全リソースの依存関係を自動解決して削除</li>
</ul>
<hr>
<blockquote>
<p><strong>この記事は <a href="https://caymezon.com/aws-handson-console-alb-ec2-rds/">AWSコンソール版ハンズオン</a> の比較記事です。</strong><br />コンソール版でALB・ターゲットグループ・ヘルスチェックを視覚的に学んだ後に読むと理解が深まります。</p>
</blockquote>
<hr>
<p><!-- ![CloudFormationスタック作成完了・Outputs確認画面](images/cfn-create-complete.jpg) --></p>
<p><!-- <a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"> --></p>
<p><!-- <!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --> --></p>
<h2><span id="toc2">CloudFormation vs コンソール：どれだけ違うか</span></h2>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>CloudFormation</th>
<th>コンソール（手動）</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>VPC + サブネット4つ + IGW + ルートテーブル</strong></td>
<td>template.yaml に定義済み</td>
<td>約20〜30分・複数画面</td>
</tr>
<tr>
<td><strong>SG 3つ（ALB/EC2/RDS）の作成</strong></td>
<td>template.yaml に定義済み</td>
<td>3画面で個別設定</td>
</tr>
<tr>
<td><strong>ALB + TG + Listener の作成</strong></td>
<td>template.yaml に定義済み</td>
<td>3つの画面で設定</td>
</tr>
<tr>
<td><strong>Tomcat UserDataの貼り付け</strong></td>
<td>template.yaml に組み込み済み</td>
<td>手動コピペ</td>
</tr>
<tr>
<td><strong>全体のデプロイ</strong></td>
<td>コマンド1本（RDS待ち15〜20分）</td>
<td><strong>約40〜50分</strong></td>
</tr>
<tr>
<td><strong>削除</strong></td>
<td><code>delete-stack</code> 1本（自動解決）</td>
<td><strong>13ステップ手動</strong></td>
</tr>
<tr>
<td><strong>再現性</strong></td>
<td>高い（何度でも同じ構成を再現可能）</td>
<td>低い（手順漏れのリスク大）</td>
</tr>
<tr>
<td><strong>バージョン管理</strong></td>
<td>Gitで管理可能</td>
<td>不可</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>CloudFormation</strong></td>
<td>AWSが提供するIaC（Infrastructure as Code）サービス</td>
</tr>
<tr>
<td><strong>スタック</strong></td>
<td>CloudFormationが管理するリソースのまとまり。今回は約27リソースを1スタックで管理</td>
</tr>
<tr>
<td><strong>AWS::ElasticLoadBalancingV2::LoadBalancer</strong></td>
<td>ALB本体を定義するリソース型</td>
</tr>
<tr>
<td><strong>AWS::ElasticLoadBalancingV2::TargetGroup</strong></td>
<td>ターゲットグループを定義するリソース型</td>
</tr>
<tr>
<td><strong>AWS::ElasticLoadBalancingV2::Listener</strong></td>
<td>ALBのリスナー（受付ルール）を定義するリソース型</td>
</tr>
<tr>
<td><strong>DeletionPolicy: Delete</strong></td>
<td>スタック削除時にRDSも確実に削除する設定</td>
</tr>
<tr>
<td><strong>CAPABILITY_NAMED_IAM</strong></td>
<td>名前付きIAMリソースを含むスタックの作成に必要なフラグ</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">前提条件</span></h2>
<table>
<thead>
<tr>
<th>ツール</th>
<th>確認コマンド</th>
</tr>
</thead>
<tbody>
<tr>
<td>AWS CLI v2</td>
<td><code>aws --version</code></td>
</tr>
</tbody>
</table>
<p>AWS認証確認:</p>
<pre><code class="language-cmd">aws sts get-caller-identity</code></pre>
<hr>
<h2><span id="toc5">構築されるリソース（約27個）</span></h2>
<table>
<thead>
<tr>
<th>カテゴリ</th>
<th>リソース</th>
<th>論理ID</th>
</tr>
</thead>
<tbody>
<tr>
<td>ネットワーク</td>
<td>VPC</td>
<td><code>VPC</code></td>
</tr>
<tr>
<td>ネットワーク</td>
<td>インターネットゲートウェイ</td>
<td><code>InternetGateway</code> + <code>IGWAttachment</code></td>
</tr>
<tr>
<td>ネットワーク</td>
<td>パブリックサブネット × 2</td>
<td><code>PublicSubnet1</code> + <code>PublicSubnet2</code></td>
</tr>
<tr>
<td>ネットワーク</td>
<td>プライベートサブネット × 2</td>
<td><code>PrivateSubnet1</code> + <code>PrivateSubnet2</code></td>
</tr>
<tr>
<td>ネットワーク</td>
<td>パブリックルートテーブル</td>
<td><code>PublicRouteTable</code> + <code>PublicRoute</code> + <code>PublicSubnet1RTA</code> + <code>PublicSubnet2RTA</code></td>
</tr>
<tr>
<td>ネットワーク</td>
<td>プライベートルートテーブル</td>
<td><code>PrivateRouteTable</code> + <code>PrivateSubnet1RTA</code> + <code>PrivateSubnet2RTA</code></td>
</tr>
<tr>
<td>ネットワーク</td>
<td>S3 VPC Gateway Endpoint</td>
<td><code>S3VPCEndpoint</code></td>
</tr>
<tr>
<td>セキュリティ</td>
<td>ALBセキュリティグループ</td>
<td><code>ALBSecurityGroup</code></td>
</tr>
<tr>
<td>セキュリティ</td>
<td>EC2セキュリティグループ</td>
<td><code>EC2SecurityGroup</code></td>
</tr>
<tr>
<td>セキュリティ</td>
<td>RDSセキュリティグループ</td>
<td><code>RDSSecurityGroup</code></td>
</tr>
<tr>
<td>IAM</td>
<td>EC2ロール + インスタンスプロファイル</td>
<td><code>EC2Role</code> + <code>EC2InstanceProfile</code></td>
</tr>
<tr>
<td>パラメータ</td>
<td>SSM Parameter Store</td>
<td><code>DBPasswordParam</code></td>
</tr>
<tr>
<td>データベース</td>
<td>RDS DBサブネットグループ</td>
<td><code>DBSubnetGroup</code></td>
</tr>
<tr>
<td>データベース</td>
<td>RDS MySQLインスタンス</td>
<td><code>RDSInstance</code></td>
</tr>
<tr>
<td>ロードバランサー</td>
<td>ターゲットグループ</td>
<td><code>TargetGroup</code></td>
</tr>
<tr>
<td>ロードバランサー</td>
<td>ALB本体</td>
<td><code>ALB</code></td>
</tr>
<tr>
<td>ロードバランサー</td>
<td>リスナー</td>
<td><code>ALBListener</code></td>
</tr>
<tr>
<td>コンピュート</td>
<td>EC2インスタンス</td>
<td><code>EC2Instance</code></td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc6">template.yaml（完全版）</span></h2>
<p>このファイルをそのまま使ってハンズオンを実施できます。<code>C:\my-aws\aws-learning-projects\alb-ec2-rds\template.yaml</code> として保存してください。</p>
<pre><code class="language-yaml">AWSTemplateFormatVersion: '2010-09-09'
Description: 'ALB + EC2(Tomcat) + RDS 3-tier architecture hands-on (Phase 2-2)'

Parameters:
  EmployeeId:
    Type: String
    Default: '123456'
    Description: Employee ID used as a prefix for resource names

  KeyName:
    Type: String
    Default: 'my-alb-key'
    Description: Name of an existing EC2 KeyPair

  MyIP:
    Type: String
    Default: '203.0.113.1/32'    # [IMPORTANT] Replace with your own IP (check: curl https://checkip.amazonaws.com)
    Description: Your IP address to allow SSH access (CIDR format)

  DBPassword:
    Type: String
    Default: 'Handson1234!'
    NoEcho: true
    Description: Master password for RDS MySQL (also stored in SSM Parameter Store)

  TomcatVersion:
    Type: String
    Default: '10.1.28'
    Description: Apache Tomcat version (check latest at https://archive.apache.org/dist/tomcat/tomcat-10/)

Resources:

  # VPC and Network
  # ============================================================

  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-vpc'
        - Key: Cost
          Value: !Ref EmployeeId

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-igw'
        - Key: Cost
          Value: !Ref EmployeeId

  IGWAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  # Public Subnet 1 (AZ-a): ALB + EC2 Tomcat
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-public-subnet-1'
        - Key: Cost
          Value: !Ref EmployeeId

  # Public Subnet 2 (AZ-b): ALB requires subnets in at least 2 AZs
  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: !Select [1, !GetAZs '']
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-public-subnet-2'
        - Key: Cost
          Value: !Ref EmployeeId

  # Private Subnet 1 (AZ-a): RDS instance is placed here
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.3.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-private-subnet-1'
        - Key: Cost
          Value: !Ref EmployeeId

  # Private Subnet 2 (AZ-b): required for RDS Subnet Group (minimum 2 AZs)
  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.4.0/24
      AvailabilityZone: !Select [1, !GetAZs '']
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-private-subnet-2'
        - Key: Cost
          Value: !Ref EmployeeId

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-public-rt'
        - Key: Cost
          Value: !Ref EmployeeId

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: IGWAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-private-rt'
        - Key: Cost
          Value: !Ref EmployeeId

  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable

  PrivateSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable

  # S3 VPC Gateway Endpoint: free, allows EC2 to reach S3 for dnf package downloads
  S3VPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3'
      VpcEndpointType: Gateway
      RouteTableIds:
        - !Ref PublicRouteTable
        - !Ref PrivateRouteTable

  # ============================================================
  # IAM
  # ============================================================

  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub 'n${EmployeeId}-alb-ec2-role'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        - arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-ec2-role'
        - Key: Cost
          Value: !Ref EmployeeId

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: !Sub 'n${EmployeeId}-alb-ec2-profile'
      Roles:
        - !Ref EC2Role

  # ============================================================
  # Security Groups
  # ============================================================

  # ALB Security Group: accept HTTP:80 from the internet
  ALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub 'n${EmployeeId} ALB SG - HTTP:80 from internet'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
          Description: HTTP from internet
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-sg'
        - Key: Cost
          Value: !Ref EmployeeId

  # EC2 Security Group: Tomcat:8080 from ALB SG only, SSH from MyIP
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub 'n${EmployeeId} EC2 Tomcat SG'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 8080
          ToPort: 8080
          SourceSecurityGroupId: !GetAtt ALBSecurityGroup.GroupId
          Description: Tomcat from ALB SG only (SG-to-SG control)
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref MyIP
          Description: SSH from my IP
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-ec2-sg'
        - Key: Cost
          Value: !Ref EmployeeId

  # RDS Security Group: MySQL:3306 from EC2 SG only
  RDSSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub 'n${EmployeeId} RDS MySQL SG (EC2-to-RDS only)'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          SourceSecurityGroupId: !GetAtt EC2SecurityGroup.GroupId
          Description: MySQL from EC2 SG only (SG-to-SG control)
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-rds-sg'
        - Key: Cost
          Value: !Ref EmployeeId

  # ============================================================
  # SSM Parameter Store
  # NOTE: CloudFormation can only create String type, not SecureString.
  # ============================================================
  DBPasswordParam:
    Type: AWS::SSM::Parameter
    Properties:
      Name: !Sub '/n${EmployeeId}/alb/db-password'
      Type: String
      Value: !Ref DBPassword
      Description: !Sub 'RDS MySQL master password for n${EmployeeId} ALB hands-on'
      Tags:
        Cost: !Ref EmployeeId

  # ============================================================
  # RDS
  # ============================================================

  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: !Sub 'n${EmployeeId} RDS subnet group (private subnets in 2 AZs)'
      SubnetIds:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-rds-subnet-group'
        - Key: Cost
          Value: !Ref EmployeeId

  RDSInstance:
    Type: AWS::RDS::DBInstance
    DeletionPolicy: Delete
    Properties:
      DBInstanceIdentifier: !Sub 'n${EmployeeId}-alb-rds-mysql'
      DBInstanceClass: db.t3.micro
      Engine: mysql
      EngineVersion: '8.0'
      MasterUsername: admin
      MasterUserPassword: !Ref DBPassword
      AllocatedStorage: '20'
      StorageType: gp2
      DBName: sampledb
      DBSubnetGroupName: !Ref DBSubnetGroup
      VPCSecurityGroups:
        - !GetAtt RDSSecurityGroup.GroupId
      MultiAZ: false
      PubliclyAccessible: false
      BackupRetentionPeriod: 0
      DeleteAutomatedBackups: true
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-rds-mysql'
        - Key: Cost
          Value: !Ref EmployeeId

  # ============================================================
  # ALB (Application Load Balancer)
  # ============================================================

  # Target Group: routes traffic to EC2 Tomcat on port 8080
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub 'n${EmployeeId}-alb-tg'
      Protocol: HTTP
      Port: 8080
      VpcId: !Ref VPC
      TargetType: instance
      HealthCheckProtocol: HTTP
      HealthCheckPort: '8080'
      HealthCheckPath: /
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 3
      HealthCheckIntervalSeconds: 30
      HealthCheckTimeoutSeconds: 5
      Targets:
        - Id: !Ref EC2Instance
          Port: 8080
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-tg'
        - Key: Cost
          Value: !Ref EmployeeId

  # ALB: internet-facing, spans 2 public subnets
  ALB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Sub 'n${EmployeeId}-alb-alb'
      Type: application
      Scheme: internet-facing
      IpAddressType: ipv4
      Subnets:
        - !Ref PublicSubnet1
        - !Ref PublicSubnet2
      SecurityGroups:
        - !GetAtt ALBSecurityGroup.GroupId
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-alb'
        - Key: Cost
          Value: !Ref EmployeeId

  # Listener: HTTP:80 -&gt; forward to TargetGroup
  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref ALB
      Protocol: HTTP
      Port: 80
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref TargetGroup

  # ============================================================
  # EC2 (AP Server with Tomcat)
  # ============================================================

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}'
      InstanceType: t2.micro
      KeyName: !Ref KeyName
      SubnetId: !Ref PublicSubnet1
      SecurityGroupIds:
        - !GetAtt EC2SecurityGroup.GroupId
      IamInstanceProfile: !Ref EC2InstanceProfile
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          set -xe
          exec &gt; &gt;(tee /var/log/user-data.log) 2&gt;&amp;1

          dnf update -y
          dnf install -y java-17-amazon-corretto wget

          # Install Tomcat
          # Check latest version at: https://archive.apache.org/dist/tomcat/tomcat-10/
          TOMCAT_VERSION="${TomcatVersion}"
          cd /opt
          wget -q https://archive.apache.org/dist/tomcat/tomcat-10/v${!TOMCAT_VERSION}/bin/apache-tomcat-${!TOMCAT_VERSION}.tar.gz
          tar xzf apache-tomcat-${!TOMCAT_VERSION}.tar.gz
          mv apache-tomcat-${!TOMCAT_VERSION} tomcat
          chmod +x /opt/tomcat/bin/*.sh

          # Deploy simple web application to ROOT context
          cat &gt; /opt/tomcat/webapps/ROOT/index.html &lt;&lt; 'HTMLEOF'
          &lt;!DOCTYPE html&gt;
          &lt;html&gt;
          &lt;body&gt;
          &lt;h1&gt;AP Server - Phase 2-2 ALB + Tomcat + RDS&lt;/h1&gt;
          &lt;p&gt;This server is load balanced by ALB and connects to RDS MySQL in the private subnet.&lt;/p&gt;
          &lt;/body&gt;
          &lt;/html&gt;
          HTMLEOF

          # Start Tomcat
          /opt/tomcat/bin/startup.sh
      Tags:
        - Key: Name
          Value: !Sub 'n${EmployeeId}-alb-ap-instance'
        - Key: Cost
          Value: !Ref EmployeeId

Outputs:
  ALBEndpoint:
    Description: ALB DNS name - access via browser
    Value: !Sub 'http://${ALB.DNSName}'

  EC2PublicIP:
    Description: EC2 Tomcat server public IP (for SSH)
    Value: !GetAtt EC2Instance.PublicIp

  RDSEndpoint:
    Description: RDS MySQL endpoint hostname
    Value: !GetAtt RDSInstance.Endpoint.Address

  DBPasswordParamName:
    Description: SSM Parameter Store path for RDS password
    Value: !Ref DBPasswordParam

  SSHCommand:
    Description: SSH command to EC2 AP server
    Value: !Sub 'ssh -i C:\Users\username\.ssh\${KeyName}.pem ec2-user@${EC2Instance.PublicIp}'

  MySQLConnectCommand:
    Description: MySQL connect command (run FROM the EC2 AP server)
    Value: !Sub 'mysql -h ${RDSInstance.Endpoint.Address} -u admin -pHandson1234! sampledb'</code></pre>
<hr>
<h2><span id="toc7">作業順序</span></h2>
<pre><code class="language-plaintext">⓪ 自分のIPアドレスを確認する
      ↓
① キーペアを作成する（コンソールで実施）
      ↓
② プロジェクトフォルダに移動する
      ↓
③ スタックを作成する（aws cloudformation create-stack）
      ↓
④ 作成完了・Outputsを確認する（RDSは15〜20分かかる）
      ↓
⑤ 動作確認（ALBアクセス・SSH・RDS接続）
      ↓
⑥ スタックを削除する（aws cloudformation delete-stack）</code></pre>
<hr>
<h2><span id="toc8">【重要】⓪ 自分のIPアドレスを確認する</span></h2>
<pre><code class="language-cmd">curl https://checkip.amazonaws.com</code></pre>
<p><strong>控えておく情報</strong>: 自分のIPアドレス（例: <code>203.0.113.1</code>）</p>
<hr>
<h2><span id="toc9">① キーペアの作成（コンソールで実施）</span></h2>
<p>CloudFormationではキーペアのダウンロードができないため、コンソールで先に作成します。</p>
<p><strong>AWSコンソール → EC2 → キーペア → 「キーペアを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-alb-key</code></td>
</tr>
<tr>
<td>キーペアのタイプ</td>
<td><strong>RSA</strong></td>
</tr>
<tr>
<td>プライベートキーファイル形式</td>
<td><strong>.pem</strong></td>
</tr>
</tbody>
</table>
<p>ダウンロードされた <code>my-alb-key.pem</code> を保存します。</p>
<pre><code class="language-plaintext">C:\Users\ユーザー名\.ssh\my-alb-key.pem</code></pre>
<hr>
<h2><span id="toc10">② プロジェクトフォルダに移動する</span></h2>
<p>VSCodeのターミナル（CMD）を開き、プロジェクトフォルダに移動します。</p>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\alb-ec2-rds</code></pre>
<p><code>template.yaml</code> があることを確認します。</p>
<pre><code class="language-cmd">dir template.yaml</code></pre>
<hr>
<h2><span id="toc11">③ スタックの作成</span></h2>
<p>以下のコマンドを実行します。<code>203.0.113.1</code> は⓪で確認した自分のIPアドレスに置き換えます。</p>
<pre><code class="language-cmd">aws cloudformation create-stack ^
  --stack-name my-alb-stack ^
  --template-body file://template.yaml ^
  --region ap-northeast-1 ^
  --capabilities CAPABILITY_NAMED_IAM ^
  --parameters ^
    ParameterKey=EmployeeId,ParameterValue=123456 ^
    ParameterKey=KeyName,ParameterValue=my-alb-key ^
    ParameterKey=MyIP,ParameterValue=203.0.113.1/32 ^
    ParameterKey=DBPassword,ParameterValue=Handson1234!</code></pre>
<blockquote>
<p><strong><code>TomcatVersion</code> パラメータについて</strong>: デフォルト値は <code>10.1.28</code>。変更する場合は <code>ParameterKey=TomcatVersion,ParameterValue=10.1.xx</code> を追加します。利用可能なバージョンは <a href="https://archive.apache.org/dist/tomcat/tomcat-10/">https://archive.apache.org/dist/tomcat/tomcat-10/</a> で確認します。</p>
</blockquote>
<blockquote>
<p><strong><code>CAPABILITY_NAMED_IAM</code> について</strong>: <code>EC2Role</code> のように名前を指定したIAMリソースを作成する場合に必要なフラグです。</p>
</blockquote>
<p>成功すると以下のような StackId が表示されます。</p>
<pre><code class="language-json">{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/my-alb-stack/xxxxx"
}</code></pre>
<hr>
<h2><span id="toc12">④ 作成完了・Outputsの確認</span></h2>
<blockquote>
<p><strong>注意</strong>: RDSの作成には<strong>約15〜20分</strong>かかります。<code>CREATE_IN_PROGRESS</code> が続く間は正常です。</p>
</blockquote>
<h3><span id="toc13">作成状況の確認</span></h3>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name my-alb-stack ^
  --query "Stacks[0].StackStatus" ^
  --output text</code></pre>
<table>
<thead>
<tr>
<th>ステータス</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>CREATE_IN_PROGRESS</code></td>
<td>作成中（待つ）</td>
</tr>
<tr>
<td><code>CREATE_COMPLETE</code></td>
<td>作成完了</td>
</tr>
<tr>
<td><code>CREATE_FAILED</code></td>
<td>作成失敗（後述のトラブルシューティングを参照）</td>
</tr>
<tr>
<td><code>ROLLBACK_COMPLETE</code></td>
<td>失敗してロールバック完了</td>
</tr>
</tbody>
</table>
<h3><span id="toc14">Outputs（接続情報）の確認</span></h3>
<p><code>CREATE_COMPLETE</code> になったら以下を実行します。</p>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name my-alb-stack ^
  --query "Stacks[0].Outputs" ^
  --output table</code></pre>
<pre><code class="language-plaintext">+----------------------+------------------------------------------------------------------+
|  OutputKey           |  OutputValue                                                     |
+----------------------+------------------------------------------------------------------+
|  ALBEndpoint         |  http://my-alb-alb-1234567890.ap-northeast-1.elb.amazonaws.com  |
|  EC2PublicIP         |  x.x.x.x                                                        |
|  RDSEndpoint         |  my-alb-rds-mysql.xxxxx.ap-northeast-1.rds.amazonaws.com        |
|  DBPasswordParamName |  /my/alb/db-password                                             |
|  SSHCommand          |  ssh -i C:\Users\...\.ssh\my-alb-key.pem ec2-user@x.x.x.x       |
+----------------------+------------------------------------------------------------------+</code></pre>
<p><strong>控えておく情報</strong>: <code>ALBEndpoint</code>、<code>EC2PublicIP</code>、<code>RDSEndpoint</code></p>
<p><!-- ![CloudFormation Outputs確認コマンドの実行結果](images/cfn-outputs.jpg) --></p>
<hr>
<h2><span id="toc15">⑤ 動作確認</span></h2>
<h3><span id="toc16">ALBのヘルスチェック確認</span></h3>
<p><strong>EC2 → ターゲットグループ → <code>my-alb-tg</code> → 「ターゲット」タブ</strong></p>
<p>EC2のステータスが <strong>「healthy」</strong> になるまで待ちます（EC2起動後5〜10分）。</p>
<blockquote>
<p>Tomcatの起動はEC2が「実行中」になってからさらに数分かかります。<code>initial</code> や <code>unhealthy</code> が続く場合はしばらく待ちます。</p>
</blockquote>
<p><!-- ![ターゲットグループのHealthy確認画面](images/target-healthy.jpg) --></p>
<h3><span id="toc17">ALB経由でWebアクセス確認</span></h3>
<p>Outputsに表示された <code>ALBEndpoint</code> をブラウザで開きます。</p>
<pre><code class="language-plaintext">http://（ALBEndpointのDNS名）</code></pre>
<p>「AP Server - Phase 2-2 ALB + Tomcat + RDS」と表示されれば正常です。</p>
<h3><span id="toc18">EC2にSSH接続する</span></h3>
<p>Outputsの <code>SSHCommand</code> を実行します（パスは実際のパスに修正します）。</p>
<pre><code class="language-cmd">ssh -i C:\Users\ユーザー名\.ssh\my-alb-key.pem ec2-user@（EC2PublicIP）</code></pre>
<h3><span id="toc19">Parameter StoreからDBパスワードを取得する</span></h3>
<p>EC2に接続した状態で実行します。</p>
<pre><code class="language-bash">aws ssm get-parameter \
  --name "/my/alb/db-password" \
  --query "Parameter.Value" \
  --output text \
  --region ap-northeast-1</code></pre>
<p><code>Handson1234!</code> が表示されれば成功です。</p>
<blockquote>
<p><strong><code>--with-decryption</code> が不要な理由</strong>: CloudFormationで作成したパラメータは <code>Type: String</code>（平文）のため、フラグなしでそのまま値が返ります。コンソールで <strong>SecureString</strong> として作成した場合は <code>--with-decryption</code> が必要です（コンソール版参照）。</p>
</blockquote>
<h3><span id="toc20">RDSへのMySQL接続テスト</span></h3>
<pre><code class="language-bash"># RDSエンドポイントをOutputsの値に置き換える
RDS_ENDPOINT="my-alb-rds-mysql.xxxxxxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com"

# Parameter StoreからDBパスワードを取得して接続（String型のため--with-decryption不要）
DB_PASSWORD=$(aws ssm get-parameter \
  --name "/my/alb/db-password" \
  --query "Parameter.Value" \
  --output text \
  --region ap-northeast-1)

mysql -h $RDS_ENDPOINT -u admin -p"$DB_PASSWORD" sampledb</code></pre>
<p>接続成功後、SQL操作を確認します。</p>
<pre><code class="language-sql">-- テーブル作成
CREATE TABLE items (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- データ挿入
INSERT INTO items (name) VALUES ('Apple'), ('Banana');

-- データ確認
SELECT * FROM items;

-- 後片付け
DROP TABLE items;

EXIT;</code></pre>
<p><!-- ![EC2からRDS MySQLへの接続成功画面](images/rds-mysql-connect.jpg) --></p>
<p>EC2からSSH接続を切断します。</p>
<pre><code class="language-bash">exit</code></pre>
<hr>
<h2><span id="toc21">⑥ スタックの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除します。</strong></p>
<pre><code class="language-cmd">aws cloudformation delete-stack ^
  --stack-name my-alb-stack ^
  --region ap-northeast-1</code></pre>
<blockquote>
<p><strong>注意</strong>: RDS削除には<strong>約10〜15分</strong>かかります。コマンド実行後もしばらく待つ必要があります。</p>
</blockquote>
<h3><span id="toc22">削除状況の確認</span></h3>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name my-alb-stack ^
  --query "Stacks[0].StackStatus" ^
  --output text</code></pre>
<table>
<thead>
<tr>
<th>ステータス</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>DELETE_IN_PROGRESS</code></td>
<td>削除中（待つ）</td>
</tr>
<tr>
<td><code>DELETE_FAILED</code></td>
<td>削除失敗（トラブルシューティングを参照）</td>
</tr>
</tbody>
</table>
<p>削除完了の確認（以下のエラーが表示されれば削除完了）:</p>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name my-alb-stack ^
  --region ap-northeast-1</code></pre>
<pre><code class="language-plaintext">An error occurred (ValidationError) when calling the DescribeStacks operation:
Stack with id my-alb-stack does not exist</code></pre>
<h3><span id="toc23">キーペアの手動削除</span></h3>
<p>キーペアはCloudFormationで管理していないため手動で削除します。</p>
<p><strong>EC2 → キーペア → <code>my-alb-key</code> を選択 → 「アクション」→「削除」</strong></p>
<hr>
<h2><span id="toc24">コンソール版との比較</span></h2>
<table>
<thead>
<tr>
<th>作業</th>
<th>コンソール（手動）</th>
<th>CloudFormation</th>
</tr>
</thead>
<tbody>
<tr>
<td>VPC + サブネット4つ + IGW + ルートテーブル</td>
<td>約20〜30分</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>SG 3つ（ALB/EC2/RDS）の作成</td>
<td>3画面で個別設定</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>ALB + TG + Listener の作成</td>
<td>3つの画面で設定</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>Tomcat UserDataの貼り付け</td>
<td>手動コピペ</td>
<td>template.yaml に組み込み済み</td>
</tr>
<tr>
<td>全体のデプロイ</td>
<td><strong>約40〜50分</strong></td>
<td>コマンド1本（RDS待ち15〜20分）</td>
</tr>
<tr>
<td>削除</td>
<td><strong>13ステップ手動</strong></td>
<td><code>delete-stack</code> 1本</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc25">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>CREATE_FAILED</code> → ROLLBACKになる</td>
<td>パラメータ不正・リソース上限など</td>
<td>コンソールのCloudFormationイベントタブでエラー詳細を確認</td>
</tr>
<tr>
<td>ALBに繋がらない</td>
<td>EC2のTomcatがまだ起動中</td>
<td>TGのヘルスチェックがHealthyになるまで待つ（5〜10分）</td>
</tr>
<tr>
<td>ALBに繋がるが502エラー</td>
<td>Tomcat起動失敗</td>
<td>SSH接続して <code>sudo cat /var/log/user-data.log</code> 確認</td>
</tr>
<tr>
<td><code>ERROR 2003</code>: MySQL接続できない</td>
<td>RDS SGのソース設定ミス</td>
<td>RDS SGのインバウンドルールを確認</td>
</tr>
<tr>
<td>Tomcatバージョンエラー</td>
<td>指定バージョンがアーカイブに存在しない</td>
<td><a href="https://archive.apache.org/dist/tomcat/tomcat-10/">https://archive.apache.org/dist/tomcat/tomcat-10/</a> で確認して <code>TomcatVersion</code> パラメータを更新</td>
</tr>
<tr>
<td><code>DELETE_FAILED</code></td>
<td>リソースの依存関係が残っている</td>
<td>コンソールからALBを手動削除してから <code>delete-stack</code> を再実行</td>
</tr>
<tr>
<td>スタック作成後しばらく <code>CREATE_IN_PROGRESS</code> が続く</td>
<td>RDSの作成に時間がかかっている</td>
<td>正常。約15〜20分待つ</td>
</tr>
</tbody>
</table>
<h3><span id="toc26">失敗時の詳細確認コマンド</span></h3>
<pre><code class="language-cmd">aws cloudformation describe-stack-events ^
  --stack-name my-alb-stack ^
  --query "StackEvents[?ResourceStatus=='CREATE_FAILED'].[ResourceType,ResourceStatusReason]" ^
  --output table</code></pre>
<hr>
<h2><span id="toc27">まとめ</span></h2>
<table>
<thead>
<tr>
<th>ステップ</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>①</td>
<td>キーペアをコンソールで作成</td>
</tr>
<tr>
<td>②③</td>
<td><code>alb-ec2-rds/</code> フォルダに移動し <code>create-stack</code> を実行</td>
</tr>
<tr>
<td>④</td>
<td><code>CREATE_COMPLETE</code> になったらOutputsでALBエンドポイント・EC2IP・RDSエンドポイントを確認</td>
</tr>
<tr>
<td>⑤</td>
<td>ヘルスチェックがHealthyになったらALB → EC2 → RDS MySQL への接続テスト</td>
</tr>
<tr>
<td>⑥</td>
<td><code>delete-stack</code> 1本で27リソースを一括削除</td>
</tr>
</tbody>
</table>
<p>CloudFormation版の最大のメリットは<strong>再現性</strong>と<strong>削除の簡単さ</strong>です。コンソールでは40〜50分・13ステップかかった作業が、コマンド1本（待ち時間込みで約20分）で完了します。</p>
<p>コンソール操作でALB・ターゲットグループ・ヘルスチェックを視覚的に確認したい場合は、<a href="https://caymezon.com/aws-handson-console-alb-ec2-rds/">AWSコンソール版ハンズオン</a>を参照してください。</p><p>The post <a href="https://caymezon.com/aws-handson-cloudformation-alb-ec2-rds/">CloudFormationでALB + EC2(Tomcat) + RDS 3層構成を自動構築する手順【27リソース一括デプロイ / コンソール版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-cloudformation-alb-ec2-rds/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
