<?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>自動デプロイ - CayTech Lab</title>
	<atom:link href="https://caymezon.com/tag/%e8%87%aa%e5%8b%95%e3%83%87%e3%83%97%e3%83%ad%e3%82%a4/feed/" rel="self" type="application/rss+xml" />
	<link>https://caymezon.com</link>
	<description></description>
	<lastBuildDate>Thu, 30 Apr 2026 10:14:30 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://caymezon.com/wp-content/uploads/2026/01/cropped-CayTechLab-32x32.jpg</url>
	<title>自動デプロイ - 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>CDK + Auto Scaling Group で Webアプリをオートスケーリング構成にする【CPU負荷でスケールアウト体験】</title>
		<link>https://caymezon.com/aws-handson-cdk-asg-webapp/</link>
					<comments>https://caymezon.com/aws-handson-cdk-asg-webapp/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Thu, 30 Apr 2026 10:14:30 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[ALB]]></category>
		<category><![CDATA[ASG]]></category>
		<category><![CDATA[Auto Scaling Group]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[CDK]]></category>
		<category><![CDATA[CDK Pipelines]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[CodeBuild]]></category>
		<category><![CDATA[CodeDeploy]]></category>
		<category><![CDATA[CodePipeline]]></category>
		<category><![CDATA[GitOps]]></category>
		<category><![CDATA[IaC]]></category>
		<category><![CDATA[Launch Template]]></category>
		<category><![CDATA[Maven]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RDS]]></category>
		<category><![CDATA[Session Manager]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[SSM]]></category>
		<category><![CDATA[WAR]]></category>
		<category><![CDATA[スケーリング]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[自動デプロイ]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20409</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説cdk-webapp-pipeline との比較ファイル構成と役割使用するAWSサービス前提条件作業順序① プロジェクトのセットアップ② GitHub との接続を作成する（CodeConnec [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-cdk-asg-webapp/">CDK + Auto Scaling Group で Webアプリをオートスケーリング構成にする【CPU負荷でスケールアウト体験】</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">cdk-webapp-pipeline との比較</a></li><li><a href="#toc4" tabindex="0">ファイル構成と役割</a></li><li><a href="#toc5" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc6" tabindex="0">前提条件</a></li><li><a href="#toc7" tabindex="0">作業順序</a></li><li><a href="#toc8" tabindex="0">① プロジェクトのセットアップ</a></li><li><a href="#toc9" tabindex="0">② GitHub との接続を作成する（CodeConnections）</a><ol><li><a href="#toc10" tabindex="0">接続を作成する</a></li><li><a href="#toc11" tabindex="0">GitHub App をインストールする</a></li><li><a href="#toc12" tabindex="0">接続 ARN を確認する</a></li></ol></li><li><a href="#toc13" tabindex="0">③ cdk.json の設定</a></li><li><a href="#toc14" tabindex="0">④ コードを GitHub にプッシュする（重要！）</a></li><li><a href="#toc15" tabindex="0">⑤ パイプラインスタックのデプロイ（初回のみ）</a></li><li><a href="#toc16" tabindex="0">⑥ パイプラインの実行状況を確認する</a><ol><li><a href="#toc17" tabindex="0">CloudFormation スタックの命名規則</a></li><li><a href="#toc18" tabindex="0">CloudFormation Outputs の確認</a></li></ol></li><li><a href="#toc19" tabindex="0">⑦ アプリへアクセスする</a><ol><li><a href="#toc20" tabindex="0">ASG インスタンスを確認する</a></li></ol></li><li><a href="#toc21" tabindex="0">⑧ Auto Scaling を体験する</a><ol><li><a href="#toc22" tabindex="0">現在の ASG 状態を確認する</a></li><li><a href="#toc23" tabindex="0">SSM Session Manager でインスタンスに接続する</a></li><li><a href="#toc24" tabindex="0">CPU 負荷をかける（スケールアウトをトリガーする）</a></li><li><a href="#toc25" tabindex="0">スケールアウトを監視する</a></li><li><a href="#toc26" tabindex="0">スケールアウト後の CodeDeploy 自動デプロイを確認する</a></li><li><a href="#toc27" tabindex="0">スケールインを確認する</a></li></ol></li><li><a href="#toc28" tabindex="0">⑨ CI/CD を体験する（アプリ変更を push で自動反映）</a><ol><li><a href="#toc29" tabindex="0">アプリの HTML を変更する</a></li><li><a href="#toc30" tabindex="0">コミット＆プッシュ</a></li><li><a href="#toc31" tabindex="0">パイプラインの自動起動を確認する</a></li></ol></li><li><a href="#toc32" tabindex="0">⑩ リソース削除</a><ol><li><a href="#toc33" tabindex="0">1. インフラスタックを削除する</a></li><li><a href="#toc34" tabindex="0">2. パイプラインスタックを削除する</a></li><li><a href="#toc35" tabindex="0">3. SSM パラメータを削除する</a></li><li><a href="#toc36" tabindex="0">4. 仮想環境の終了</a></li><li><a href="#toc37" tabindex="0">5. GitHub との接続を削除する（オプション）</a></li><li><a href="#toc38" tabindex="0">削除確認</a></li><li><a href="#toc39" tabindex="0">削除されるリソース一覧</a></li></ol></li><li><a href="#toc40" tabindex="0">Auto Scaling のポイント解説</a><ol><li><a href="#toc41" tabindex="0">ASG ライフサイクルフックで新インスタンスへ自動デプロイ</a></li><li><a href="#toc42" tabindex="0">cdk-webapp-pipeline → cdk-asg-webapp の変化</a></li></ol></li><li><a href="#toc43" tabindex="0">トラブルシューティング</a></li><li><a href="#toc44" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「EC2 が 1台では負荷が集中したときに対応できない」「障害で EC2 が落ちたら手動で復旧しなければならない」——これを解決するのが <strong>Auto Scaling Group（ASG）</strong> です。</p>
<p>この記事では、<a href="https://caymezon.com/aws-handson-cdk-webapp-pipeline/">CDK Pipelines + CodeDeploy ハンズオン</a>で構築した <strong>単一 EC2 構成</strong>を、<strong>Auto Scaling Group + Launch Template</strong> にアップグレードします。CPU 負荷をかけて実際にスケールアウトを体験し、新しいインスタンスへ <strong>CodeDeploy が自動で WAR をデプロイ</strong>する様子を確認します。</p>
<pre><code class="language-plaintext">GitHub リポジトリ
  ↓ push（自動トリガー）
CodePipeline (my-cdk5-pipeline)
  ├── Source:        GitHub (CodeConnections 経由)
  ├── Build(Synth):  CodeBuild — cdk synth
  ├── Mutate:        パイプライン自己更新（セルフミューテーション）
  ├── InfraDeploy:   CloudFormation — VPC / ASG / RDS / ALB
  └── BuildAndDeployApp: ← post step
        CodeBuild: mvn package → webapp.war 生成
        CodeDeploy: ASG の全 Tomcat に一括デプロイ
                ↓
       [ALB: my-cdk5-alb]
                ↓
       ┌─────────────────────────────┐
       │  Auto Scaling Group (ASG)   │
       │  my-cdk5-asg                │
       │  ・最小 1台 / 最大 3台      │
       │  ・CPU 60% 超でスケールアウト│
       │  ├── EC2: Tomcat + WAR      │
       │  └── EC2: Tomcat + WAR（追加分）│
       └─────────────────────────────┘
                ↓
       [RDS: my-cdk5-rds-mysql]  ← MySQL 8.0</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li><code>git push</code> するだけで ASG の全インスタンスへ WAR が自動デプロイされる</li>
<li>CPU に負荷をかけてスケールアウトを体験する</li>
<li>スケールアウト後の新インスタンスへ CodeDeploy が<strong>自動で WAR をデプロイ</strong>する（ライフサイクルフック）</li>
<li>キーペア不要で <strong>SSM Session Manager</strong> からブラウザ経由でインスタンスに接続する</li>
</ul>
<hr>
<blockquote>
<p><strong>この記事は <a href="https://caymezon.com/aws-handson-cdk-webapp-pipeline/">CDK Pipelines + CodeDeploy ハンズオン（cdk-webapp-pipeline）</a> の発展記事です。</strong><br />CodeDeploy・CDK Pipelines の基本を体験済みの方向けです。コード詳細は <a href="https://github.com/caymezon/aws-handson/tree/main/cdk-asg-webapp">GitHub</a> を参照してください。</p>
</blockquote>
<hr>
<p><!-- ![CodePipelineとASGが動作している画面](images/pipeline-asg-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">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Auto Scaling Group（ASG）</strong></td>
<td>EC2 インスタンスのグループを自動管理するサービス。負荷に応じてインスタンス数を増減させ、障害時は自動で置き換える</td>
</tr>
<tr>
<td><strong>Launch Template</strong></td>
<td>ASG が新しいインスタンスを起動する際に使う設定テンプレート（AMI・インスタンスタイプ・UserData 等）</td>
</tr>
<tr>
<td><strong>ターゲット追跡ポリシー</strong></td>
<td>メトリクス（CPU 使用率 60%）を目標値として維持するよう自動スケーリングするポリシー</td>
</tr>
<tr>
<td><strong>ASG ライフサイクルフック</strong></td>
<td>スケールアウト時に新しいインスタンスへ CodeDeploy が最新 WAR を自動デプロイする仕組み</td>
</tr>
<tr>
<td><strong>SSM Session Manager</strong></td>
<td>キーペアなしで EC2 インスタンスにブラウザからセキュアに接続できるサービス</td>
</tr>
<tr>
<td><strong>stress-ng</strong></td>
<td>CPU・メモリ等に人工的な負荷をかけるツール。スケーリングのトリガーとして使用する</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">cdk-webapp-pipeline との比較</span></h2>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>cdk-webapp-pipeline</th>
<th>cdk-asg-webapp</th>
</tr>
</thead>
<tbody>
<tr>
<td>EC2 管理方法</td>
<td>単一 Instance リソース</td>
<td><strong>Auto Scaling Group + Launch Template</strong></td>
</tr>
<tr>
<td>EC2 台数</td>
<td>固定 1台</td>
<td><strong>最小 1台〜最大 3台（自動増減）</strong></td>
</tr>
<tr>
<td>スケーリング</td>
<td>なし</td>
<td><strong>CPU 60% 超でスケールアウト</strong></td>
</tr>
<tr>
<td>自己回復</td>
<td>なし（手動対応）</td>
<td><strong>ALB ヘルスチェックで異常インスタンスを自動置換</strong></td>
</tr>
<tr>
<td>接続方法</td>
<td>SSH（キーペア必要）</td>
<td><strong>SSM Session Manager（キーペア不要）</strong></td>
</tr>
<tr>
<td>CodeDeploy ターゲット</td>
<td>名前タグで EC2 を指定</td>
<td><strong>ASG を直接指定</strong></td>
</tr>
<tr>
<td>スケールアウト時</td>
<td>新 EC2 に WAR なし</td>
<td><strong>ライフサイクルフックで自動デプロイ</strong></td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">ファイル構成と役割</span></h2>
<pre><code class="language-plaintext">cdk-asg-webapp/
├── app.py                     ← CDK アプリ エントリポイント
├── cdk.json                   ← CDK 設定（key_name/my_ip なし・asg_* 追加）
├── appspec.yml                ← CodeDeploy: WAR 配置手順とライフサイクルフック
├── scripts/
│   ├── stop_tomcat.sh
│   ├── cleanup.sh
│   └── start_tomcat.sh
├── app/                       ← Spring Boot Webアプリ（Java）
├── pipeline/
│   └── pipeline_stack.py      ← CodePipeline + post step（ASG 対応）
├── stages/
│   └── deploy_stage.py        ← Stage（WebappStack を内包）
├── stacks/
│   └── webapp_stack.py        ← インフラスタック（ASGName を CfnOutput で公開）
└── components/
    └── webapp_construct.py    ← ASG ベースの L3 Construct</code></pre>
<table>
<thead>
<tr>
<th>ファイル</th>
<th>cdk-webapp-pipeline との主な違い</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>webapp_construct.py</code></td>
<td><code>ec2.Instance</code> → <code>autoscaling.AutoScalingGroup</code> + <code>ec2.LaunchTemplate</code></td>
</tr>
<tr>
<td><code>webapp_stack.py</code></td>
<td><code>InstanceId</code> 出力を廃止 → <code>ASGName</code> を CfnOutput で公開</td>
</tr>
<tr>
<td><code>pipeline_stack.py</code></td>
<td><code>INSTANCE_ID</code> → <code>ASG_NAME</code>（インスタンス待機の方法が変わる）</td>
</tr>
</tbody>
</table>
<p>詳細なコードは <a href="https://github.com/caymezon/aws-handson/tree/main/cdk-asg-webapp">GitHub</a> を参照してください。</p>
<hr>
<h2><span id="toc5">使用する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>Auto Scaling Group + EC2</strong>（t2.micro）</td>
<td>APサーバ（Tomcat + Spring Boot）を自動スケール</td>
<td>インスタンス分の EC2 料金</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>CodePipeline</strong></td>
<td>CI/CD パイプライン管理</td>
<td>月1パイプラインまで無料枠あり</td>
</tr>
<tr>
<td><strong>CodeBuild</strong></td>
<td>cdk synth・Maven ビルドを実行するビルド環境</td>
<td>月100分まで無料枠あり</td>
</tr>
<tr>
<td><strong>CodeDeploy</strong></td>
<td>ASG の全インスタンスへの WAR デプロイ</td>
<td>EC2 へのデプロイは<strong>無料</strong></td>
</tr>
<tr>
<td><strong>S3</strong></td>
<td>パイプラインのアーティファクト・デプロイバンドル置き場</td>
<td>無料枠あり</td>
</tr>
<tr>
<td><strong>SSM</strong></td>
<td>Session Manager による EC2 接続・Parameter Store（DBパスワード）</td>
<td>Session Manager 無料・スタンダード層無料</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>各サービスの権限</td>
<td>無料</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>注意</strong>: ALBは無料枠がありません。スケールアウト中はEC2が複数台起動するため料金も増加します。ハンズオン後は必ずリソースを削除してください。</p>
</blockquote>
<hr>
<h2><span id="toc6">前提条件</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>
<tr>
<td>Java 17</td>
<td><code>java -version</code></td>
</tr>
<tr>
<td>Maven</td>
<td><code>mvn -version</code></td>
</tr>
<tr>
<td>Python 3.9 以上</td>
<td><code>python --version</code></td>
</tr>
<tr>
<td>Node.js 18 以上</td>
<td><code>node --version</code></td>
</tr>
<tr>
<td>CDK CLI</td>
<td><code>cdk --version</code></td>
</tr>
<tr>
<td>Git</td>
<td><code>git --version</code></td>
</tr>
</tbody>
</table>
<p>AWS 認証確認:</p>
<pre><code class="language-cmd">aws sts get-caller-identity</code></pre>
<p>CDK Bootstrap 確認:</p>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name CDKToolkit ^
  --query "Stacks[0].StackStatus" ^
  --output text ^
  --region ap-northeast-1</code></pre>
<blockquote>
<p><strong>SSH キーペアは不要です</strong>。このハンズオンでは SSM Session Manager を使って EC2 に接続するため、キーペアの作成・設定は必要ありません。</p>
</blockquote>
<hr>
<h2><span id="toc7">作業順序</span></h2>
<pre><code class="language-plaintext">① プロジェクトのセットアップ（Python 仮想環境）
      ↓
② GitHub との接続を作成する（CodeConnections）
      ↓
③ cdk.json を設定する
      ↓
④ コードを全て GitHub にプッシュする（重要！）
      ↓
⑤ パイプラインスタックをデプロイする（初回のみ手動）
      ↓
⑥ パイプラインの実行状況を確認する
      ↓
⑦ アプリへアクセスする
      ↓
⑧ Auto Scaling を体験する（CPU 負荷 → スケールアウト → 自動デプロイ）
      ↓
⑨ CI/CD を体験する（アプリ変更を push で自動反映）
      ↓
⑩ リソース削除</code></pre>
<hr>
<h2><span id="toc8">① プロジェクトのセットアップ</span></h2>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-asg-webapp

python -m venv .venv

.venv\Scripts\activate

pip install -r requirements.txt</code></pre>
<p>プロンプトの先頭に <code>(.venv)</code> が表示されれば仮想環境が有効になっています。</p>
<blockquote>
<p><strong>重要</strong>: CDK コマンドはすべてこの仮想環境が有効な状態で実行する必要があります。<br />ターミナルを開き直した際は必ず最初に以下を実行してください。</p>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-asg-webapp
.venv\Scripts\activate</code></pre>
</blockquote>
<hr>
<h2><span id="toc9">② GitHub との接続を作成する（CodeConnections）</span></h2>
<blockquote>
<p><strong>cdk-webapp-pipeline を実施済みの場合</strong>: 同じリポジトリ <code>aws-learning-projects</code> を扱うため、<br />既存の接続（<code>my-github-connection</code>）をそのまま<strong>再利用</strong>できます。<br /><strong>② はスキップして、ARN の確認（②-4）から始めてください。</strong></p>
</blockquote>
<p>CodePipeline が GitHub リポジトリを監視するために、<strong>GitHub との接続（CodeConnections）</strong> を作成します。</p>
<blockquote>
<p><strong>重要</strong>: AWS コンソールと GitHub の操作は<strong>同じブラウザ</strong>で行ってください。</p>
</blockquote>
<h3><span id="toc10">接続を作成する</span></h3>
<ol>
<li>AWS コンソール検索（<code>Alt+S</code>）で <code>CodePipeline</code> と入力 → <strong>CodePipeline</strong> を開く</li>
<li>左サイドバー → <strong>「設定」</strong> → <strong>「接続」</strong></li>
<li>リージョンが <strong>東京（ap-northeast-1）</strong> になっていることを確認する</li>
<li>「<strong>接続を作成</strong>」をクリック</li>
<li>プロバイダー: <strong>GitHub</strong> を選択</li>
<li>接続名: <code>my-github-connection</code>（任意）</li>
<li>「<strong>GitHub に接続する</strong>」をクリック</li>
</ol>
<h3><span id="toc11">GitHub App をインストールする</span></h3>
<ol start="8">
<li>「<strong>Authorize</strong>」をクリック → AWS コンソールの「GitHub 接続設定」画面に自動で戻る</li>
<li>「<strong>新しいアプリをインストールする</strong>」をクリック</li>
<li><strong>「Only select repositories」</strong> を選択 → <code>aws-learning-projects</code> を追加</li>
<li>「<strong>Install & Authorize</strong>」をクリック（メール認証コードが求められる場合は入力）</li>
<li>AWS コンソールに自動でリダイレクトされる → 「<strong>接続</strong>」ボタンをクリック</li>
</ol>
<h3><span id="toc12">接続 ARN を確認する</span></h3>
<p>接続一覧から接続の ARN をコピーします。</p>
<pre><code class="language-plaintext">arn:aws:codeconnections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</code></pre>
<blockquote>
<p>ステータスが <strong>「利用可能」</strong> になっていることを確認してから次に進んでください。</p>
</blockquote>
<p><strong>控えておく情報</strong>: 接続 ARN（<code>arn:aws:codeconnections:...</code>）</p>
<hr>
<h2><span id="toc13">③ cdk.json の設定</span></h2>
<p><code>cdk.json</code> の <code>context</code> セクションを自分の環境に合わせて編集します。</p>
<pre><code class="language-json">{
  "context": {
    "employee_id": "my",
    "db_password": "Handson1234!",
    "tomcat_version": "10.1.28",
    "asg_min_capacity": 1,
    "asg_max_capacity": 3,
    "asg_desired_capacity": 1,
    "github_owner": "your-github-username",
    "github_repo": "aws-learning-projects",
    "github_branch": "main",
    "connection_arn": "arn:aws:codeconnections:ap-northeast-1:..."
  }
}</code></pre>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>employee_id</code></td>
<td><code>my</code></td>
<td>リソース名のプレフィックス（<code>my-cdk5-xxx</code> という名前になる）</td>
</tr>
<tr>
<td><code>asg_min_capacity</code></td>
<td><code>1</code></td>
<td>ASG の最小インスタンス数（スケールインの下限）</td>
</tr>
<tr>
<td><code>asg_max_capacity</code></td>
<td><code>3</code></td>
<td>ASG の最大インスタンス数（スケールアウトの上限）</td>
</tr>
<tr>
<td><code>asg_desired_capacity</code></td>
<td><code>1</code></td>
<td>初期起動インスタンス数</td>
</tr>
<tr>
<td><code>github_owner</code></td>
<td>GitHub ユーザー名</td>
<td>リポジトリのオーナー名</td>
</tr>
<tr>
<td><code>connection_arn</code></td>
<td>②で確認した ARN</td>
<td>CodeConnections の接続 ARN</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong><code>key_name</code>・<code>my_ip</code> は不要です</strong>。SSH の代わりに SSM Session Manager を使うため、キーペアやSSH許可IPの設定は必要ありません。</p>
</blockquote>
<hr>
<h2><span id="toc14">④ コードを GitHub にプッシュする（重要！）</span></h2>
<blockquote>
<p><code>cdk deploy</code> の前に必ず<strong>プロジェクト全体</strong>を push してください。<br />パイプラインが <code>cdk synth</code>・Maven ビルドを実行する際、GitHub から取得したコードを使うためです。</p>
</blockquote>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects

git add cdk-asg-webapp/
git commit -m "feat: cdk-asg-webapp ハンズオンを追加"
git push origin main</code></pre>
<hr>
<h2><span id="toc15">⑤ パイプラインスタックのデプロイ（初回のみ）</span></h2>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-asg-webapp

.venv\Scripts\activate

cdk synth

cdk deploy my-AsgPipelineStack</code></pre>
<p>「Do you wish to deploy these changes?」に <code>y</code> を入力します。</p>
<blockquote>
<p><strong>所要時間</strong>: パイプラインスタック自体のデプロイは 3〜5 分。その後パイプラインが自動起動します。</p>
</blockquote>
<p>デプロイ完了後、CodePipeline が自動起動します:</p>
<table>
<thead>
<tr>
<th>ステージ</th>
<th>内容</th>
<th>所要時間</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Source</strong></td>
<td>GitHub から最新コードを取得</td>
<td>〜1分</td>
</tr>
<tr>
<td><strong>Build (Synth)</strong></td>
<td><code>cdk synth</code> でテンプレート生成</td>
<td>〜3分</td>
</tr>
<tr>
<td><strong>UpdatePipeline</strong></td>
<td>パイプライン自己更新（セルフミューテーション）</td>
<td>〜2分</td>
</tr>
<tr>
<td><strong>Deploy > InfraDeploy</strong></td>
<td>CloudFormation で VPC / ASG / RDS / ALB を構築</td>
<td>〜15分</td>
</tr>
<tr>
<td><strong>Deploy > BuildAndDeployApp</strong></td>
<td>Maven ビルド → CodeDeploy で WAR デプロイ</td>
<td>〜10分</td>
</tr>
</tbody>
</table>
<blockquote>
<p>RDS の起動に時間がかかるため、InfraDeploy は 10〜20 分かかることがあります。</p>
</blockquote>
<hr>
<h2><span id="toc16">⑥ パイプラインの実行状況を確認する</span></h2>
<ol>
<li>AWS コンソール → <strong>CodePipeline</strong> を開く</li>
<li><code>my-cdk5-pipeline</code> を選択</li>
<li>各ステージが <strong>「成功」</strong> になるまで待つ</li>
</ol>
<h3><span id="toc17">CloudFormation スタックの命名規則</span></h3>
<pre><code class="language-plaintext">{StageName}-{StackName}</code></pre>
<table>
<thead>
<tr>
<th>要素</th>
<th>このハンズオンでの値</th>
</tr>
</thead>
<tbody>
<tr>
<td>StageName</td>
<td><code>my-Deploy</code></td>
</tr>
<tr>
<td>StackName</td>
<td><code>WebappStack</code></td>
</tr>
<tr>
<td>結果</td>
<td><strong><code>my-Deploy-WebappStack</code></strong></td>
</tr>
</tbody>
</table>
<blockquote>
<p><code>my-AsgPipelineStack</code>（パイプライン）と <code>my-Deploy-WebappStack</code>（インフラ）の <strong>2つが別スタック</strong>として CloudFormation に表示されます。</p>
</blockquote>
<h3><span id="toc18">CloudFormation Outputs の確認</span></h3>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name my-Deploy-WebappStack ^
  --region ap-northeast-1 ^
  --query "Stacks[0].Outputs"</code></pre>
<p><strong>控えておく情報</strong>: <code>ALBEndpoint</code>、<code>RDSEndpoint</code></p>
<p><!-- ![CodePipelineの全ステージが成功している画面](images/pipeline-success.jpg) --></p>
<hr>
<h2><span id="toc19">⑦ アプリへアクセスする</span></h2>
<p><code>BuildAndDeployApp</code> ステージが完了したら、ALB 経由でアプリにアクセスします。</p>
<pre><code class="language-plaintext">http://&lt;ALBEndpoint&gt;/webapp/</code></pre>
<blockquote>
<p><code>http://&lt;ALBEndpoint&gt;/</code>（ルートパス）では Tomcat のデフォルト画面が表示されます。<code>/webapp/</code> が必要です。</p>
</blockquote>
<p>ALB の DNS 名を CLI で確認する場合:</p>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name my-Deploy-WebappStack ^
  --region ap-northeast-1 ^
  --query "Stacks[0].Outputs[?OutputKey=='ALBEndpoint'].OutputValue" ^
  --output text</code></pre>
<h3><span id="toc20">ASG インスタンスを確認する</span></h3>
<p>AWS コンソール → <strong>EC2</strong> → <strong>Auto Scaling グループ</strong> → <code>my-cdk5-asg</code></p>
<ul>
<li><strong>インスタンス</strong> タブを開く</li>
<li>1台の EC2 が <code>InService</code> になっていることを確認する</li>
</ul>
<p><!-- ![アプリ画面とASGインスタンス一覧が表示されている画面](images/webapp-asg-access.jpg) --></p>
<hr>
<h2><span id="toc21">⑧ Auto Scaling を体験する</span></h2>
<p>ASG のスケールアウト・スケールインを実際に体験します。CPU 使用率が <strong>60%</strong> を超えると自動でインスタンスが追加されます。</p>
<h3><span id="toc22">現在の ASG 状態を確認する</span></h3>
<pre><code class="language-cmd">aws autoscaling describe-auto-scaling-groups ^
  --auto-scaling-group-names my-cdk5-asg ^
  --region ap-northeast-1 ^
  --query "AutoScalingGroups[0].{Desired:DesiredCapacity,Min:MinSize,Max:MaxSize,Instances:Instances[*].{Id:InstanceId,State:LifecycleState}}"</code></pre>
<p>出力例（初期状態: 1台が <code>InService</code>）:</p>
<pre><code class="language-json">{
    "Desired": 1,
    "Min": 1,
    "Max": 3,
    "Instances": [{ "Id": "i-0abc123...", "State": "InService" }]
}</code></pre>
<h3><span id="toc23">SSM Session Manager でインスタンスに接続する</span></h3>
<blockquote>
<p>キーペアは不要です。AWS コンソールから直接ブラウザでターミナルを開けます。</p>
</blockquote>
<ol>
<li><strong>EC2</strong> → <strong>インスタンス</strong> → 対象インスタンスを選択</li>
<li>「<strong>接続</strong>」ボタンをクリック</li>
<li>「<strong>Session Manager</strong>」タブ → 「<strong>接続</strong>」をクリック</li>
</ol>
<p>ブラウザでターミナルが開きます。</p>
<p>CLI から接続する場合:</p>
<pre><code class="language-cmd">rem インスタンス ID を取得
aws autoscaling describe-auto-scaling-groups ^
  --auto-scaling-group-names my-cdk5-asg ^
  --region ap-northeast-1 ^
  --query "AutoScalingGroups[0].Instances[0].InstanceId" ^
  --output text

rem 接続（Session Manager Plugin が必要）
aws ssm start-session ^
  --target i-0abc123def456789 ^
  --region ap-northeast-1</code></pre>
<h3><span id="toc24">CPU 負荷をかける（スケールアウトをトリガーする）</span></h3>
<p>インスタンスに接続したターミナルで実行します:</p>
<pre><code class="language-bash">cd /tmp &amp;&amp; stress-ng --cpu 2 --timeout 300s &amp;
echo "CPU stress started (PID: $!)"</code></pre>
<h3><span id="toc25">スケールアウトを監視する</span></h3>
<ol>
<li>AWS コンソール → <strong>CloudWatch</strong> → <strong>メトリクス</strong> → <strong>EC2</strong> → <strong>Auto Scaling グループ別</strong></li>
<li><code>my-cdk5-asg</code> の <code>CPUUtilization</code> を確認</li>
<li>CPU が 60% を超えると、約 1〜3 分後にスケールアウトが始まる</li>
</ol>
<p>ASG のインスタンス数を 10秒ごとに確認:</p>
<pre><code class="language-cmd">:loop
aws autoscaling describe-auto-scaling-groups ^
  --auto-scaling-group-names my-cdk5-asg ^
  --region ap-northeast-1 ^
  --query "AutoScalingGroups[0].Instances[*].{Id:InstanceId,State:LifecycleState}" ^
  --output table
timeout /t 10
goto loop</code></pre>
<p>しばらく待つと 2台目のインスタンスが起動し <code>InService</code> になります。</p>
<h3><span id="toc26">スケールアウト後の CodeDeploy 自動デプロイを確認する</span></h3>
<p>新しいインスタンスが起動すると、<strong>CodeDeploy が自動的に最新の WAR をデプロイします</strong>。</p>
<p>AWS コンソール → <strong>CodeDeploy</strong> → <code>my-cdk5-deploy-app</code><br />→ デプロイグループ → デプロイ履歴</p>
<p>新しいデプロイが自動で実行されていることを確認します。パイプラインを手動実行しなくても、ライフサイクルフックにより新インスタンスへ最新 WAR が自動デプロイされます。</p>
<p><!-- ![ASGインスタンスが2台になり、CodeDeployデプロイが自動実行された画面](images/asg-scaleout-codedeploy.jpg) --></p>
<h3><span id="toc27">スケールインを確認する</span></h3>
<p>CPU 負荷が終了（300秒後）すると CPU 使用率が下がり、スケールインが始まります。</p>
<blockquote>
<p>ターゲット追跡ポリシーのデフォルトのスケールイン保護時間は <strong>300秒</strong>。<br />負荷終了後、約 5〜10 分でインスタンス数が 1台に戻ります。</p>
</blockquote>
<p>途中で手動停止する場合:</p>
<pre><code class="language-bash">pkill stress-ng</code></pre>
<hr>
<h2><span id="toc28">⑨ CI/CD を体験する（アプリ変更を push で自動反映）</span></h2>
<p>アプリのコードを変更して push するだけで、ASG の全インスタンスへ自動デプロイされることを確認します。</p>
<h3><span id="toc29">アプリの HTML を変更する</span></h3>
<p><code>app/src/main/resources/templates/index.html</code> を開き、以下の行を変更します:</p>
<p>変更前:</p>
<pre><code class="language-html">&lt;h1&gt;Spring Boot + RDS Item Manager&lt;/h1&gt;</code></pre>
<p>変更後:</p>
<pre><code class="language-html">&lt;h1&gt;Spring Boot + RDS Item Manager (ASG)&lt;/h1&gt;</code></pre>
<h3><span id="toc30">コミット＆プッシュ</span></h3>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects
git add cdk-asg-webapp/app/src/main/resources/templates/index.html
git commit -m "feat: update webapp UI for ASG"
git push</code></pre>
<h3><span id="toc31">パイプラインの自動起動を確認する</span></h3>
<ol>
<li>AWS コンソール → <strong>CodePipeline</strong> → <code>my-cdk5-pipeline</code></li>
<li>push 後、数十秒以内にパイプラインが<strong>自動起動</strong>することを確認</li>
<li><code>BuildAndDeployApp</code> ステージが完了したらブラウザで <code>/webapp/</code> を更新する</li>
</ol>
<p>「(ASG)」が付いた見出しが表示されれば、ASG 構成での CI/CD が正常に動作しています。</p>
<blockquote>
<p><strong>注意</strong>: <code>InfraDeploy</code> ステージはインフラに変更がない場合は「変更なし」でスキップされます。</p>
</blockquote>
<hr>
<h2><span id="toc32">⑩ リソース削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除します。</strong></p>
<blockquote>
<p>ASG を含むスタックを削除すると、全インスタンスが自動終了されます。</p>
</blockquote>
<blockquote>
<p><strong>削除順序が重要です</strong>。インフラスタック（<code>my-Deploy-WebappStack</code>）を<strong>先に</strong>削除してから、パイプラインスタック（<code>my-AsgPipelineStack</code>）を削除します。</p>
</blockquote>
<h3><span id="toc33">1. インフラスタックを削除する</span></h3>
<pre><code class="language-cmd">aws cloudformation delete-stack ^
  --stack-name my-Deploy-WebappStack ^
  --region ap-northeast-1

aws cloudformation wait stack-delete-complete ^
  --stack-name my-Deploy-WebappStack ^
  --region ap-northeast-1

echo WebappStack 削除完了</code></pre>
<blockquote>
<p>RDS の削除に 10〜15 分かかります。<code>wait</code> コマンドが完了するまでそのまま待ってください。</p>
</blockquote>
<h3><span id="toc34">2. パイプラインスタックを削除する</span></h3>
<pre><code class="language-cmd">aws cloudformation delete-stack ^
  --stack-name my-AsgPipelineStack ^
  --region ap-northeast-1

aws cloudformation wait stack-delete-complete ^
  --stack-name my-AsgPipelineStack ^
  --region ap-northeast-1

echo AsgPipelineStack 削除完了</code></pre>
<h3><span id="toc35">3. SSM パラメータを削除する</span></h3>
<pre><code class="language-cmd">aws ssm delete-parameter ^
  --name "/my/cdk5/db-password" ^
  --region ap-northeast-1</code></pre>
<h3><span id="toc36">4. 仮想環境の終了</span></h3>
<pre><code class="language-cmd">deactivate</code></pre>
<h3><span id="toc37">5. GitHub との接続を削除する（オプション）</span></h3>
<p>次のハンズオンでも使う場合はそのままでよいです。</p>
<p><strong>CodePipeline → 設定 → 接続 → <code>my-github-connection</code> → 「削除」</strong></p>
<h3><span id="toc38">削除確認</span></h3>
<pre><code class="language-cmd">aws cloudformation list-stacks ^
  --region ap-northeast-1 ^
  --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE ^
  --query "StackSummaries[?contains(StackName, 'my-')].StackName"</code></pre>
<p>空のリスト <code>[]</code> が返れば削除完了です。</p>
<h3><span id="toc39">削除されるリソース一覧</span></h3>
<table>
<thead>
<tr>
<th>リソース</th>
<th>削除方法</th>
</tr>
</thead>
<tbody>
<tr>
<td>ALB・ASG・EC2（全インスタンス）・RDS・VPC・S3（アーティファクト）・CodeDeploy</td>
<td><code>delete-stack my-Deploy-WebappStack</code> で削除</td>
</tr>
<tr>
<td>CodePipeline・CodeBuild</td>
<td><code>delete-stack my-AsgPipelineStack</code> で削除</td>
</tr>
<tr>
<td>SSM パラメータ（DBパスワード）</td>
<td><code>aws ssm delete-parameter</code> で手動削除</td>
</tr>
<tr>
<td>GitHub との接続（CodeConnections）</td>
<td>CodePipeline コンソールから手動削除</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc40">Auto Scaling のポイント解説</span></h2>
<h3><span id="toc41">ASG ライフサイクルフックで新インスタンスへ自動デプロイ</span></h3>
<p>CDK で <code>codedeploy.ServerDeploymentGroup(auto_scaling_groups=[self.asg])</code> と指定すると、CodeDeploy が ASG にライフサイクルフックを自動設定します。</p>
<pre><code class="language-plaintext">スケールアウト発生
  ↓
ASG: 新しいインスタンスを Launch Template から起動
  ↓
EC2 UserData: Java・Tomcat・CodeDeploy エージェントをインストール
  ↓
ライフサイクルフック: CodeDeploy が最新 WAR を自動デプロイ
  ↓
ALB ターゲットグループに追加（InService）</code></pre>
<p>これにより、スケールアウト後の新インスタンスでも<strong>ユーザーは何もしなくて済みます</strong>。</p>
<h3><span id="toc42">cdk-webapp-pipeline → cdk-asg-webapp の変化</span></h3>
<pre><code class="language-plaintext">cdk-webapp-pipeline               cdk-asg-webapp
─────────────────────────         ─────────────────────────
EC2 Instance（固定 1台）           Auto Scaling Group（1〜3台）
  ↓                                 ↓
SSH（キーペア必要）                 SSM Session Manager（キーペア不要）
  ↓                                 ↓
CodeDeploy: 名前タグで指定          CodeDeploy: ASG を直接指定
  ↓                                 ↓
スケールアウト不可                  CPU 60% 超で自動スケールアウト
  ↓                                 ↓
新インスタンスに WAR なし          ライフサイクルフックで自動 WAR デプロイ</code></pre>
<hr>
<h2><span id="toc43">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>Source ステージが「失敗」</td>
<td>GitHub との接続が「保留中」</td>
<td>CodePipeline → 設定 → 接続 → 承認して「利用可能」にする</td>
</tr>
<tr>
<td>BuildAndDeployApp が失敗</td>
<td>Java ソースが GitHub に push されていない</td>
<td><code>git add cdk-asg-webapp/</code> で全ファイルを push してから再実行</td>
</tr>
<tr>
<td>CodeDeploy が失敗する</td>
<td>UserData が完了していない</td>
<td>ASG 起動後 2〜3 分待ってから再デプロイ</td>
</tr>
<tr>
<td>スケールアウトが起きない</td>
<td>CPU が 60% に達していない</td>
<td><code>stress-ng --cpu 0 --timeout 300s &amp;</code> でコア全体に負荷をかける</td>
</tr>
<tr>
<td>スケールインが起きない</td>
<td>スケールイン保護時間（300秒）が経過していない</td>
<td>CPU 負荷停止後 5〜10 分待つ</td>
</tr>
<tr>
<td><code>/webapp/</code> で 404</td>
<td>WAR デプロイ未完了</td>
<td><code>BuildAndDeployApp</code> ステージが完了するまで待つ</td>
</tr>
<tr>
<td>ALB ヘルスチェック失敗</td>
<td>Tomcat 起動中</td>
<td>SSM Session Manager で <code>sudo cat /opt/tomcat/logs/catalina.out</code> を確認</td>
</tr>
</tbody>
</table>
<p>CodeDeploy 失敗時のログ確認:</p>
<p><strong>AWS コンソール → CodeDeploy → <code>my-cdk5-deploy-app</code> → デプロイグループ → デプロイ履歴 → 失敗したデプロイ → 「ログの表示」</strong></p>
<hr>
<h2><span id="toc44">まとめ</span></h2>
<table>
<thead>
<tr>
<th>ステップ</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>①</td>
<td>Python 仮想環境のセットアップ</td>
</tr>
<tr>
<td>②</td>
<td>CodeConnections で GitHub との接続を作成・承認（cdk-webapp-pipeline 実施済みなら再利用）</td>
</tr>
<tr>
<td>③</td>
<td><code>cdk.json</code> を設定（<code>key_name</code>・<code>my_ip</code> 不要。<code>asg_min/max/desired_capacity</code> を確認）</td>
</tr>
<tr>
<td>④</td>
<td><strong><code>cdk-asg-webapp/</code> 全体</strong>を GitHub に push</td>
</tr>
<tr>
<td>⑤</td>
<td><code>cdk deploy my-AsgPipelineStack</code>（<strong>初回のみ手動</strong>）</td>
</tr>
<tr>
<td>⑥</td>
<td>CodePipeline が自動起動 → Synth → Mutate → InfraDeploy（15〜20 分）→ BuildAndDeployApp（10 分）</td>
</tr>
<tr>
<td>⑦</td>
<td><code>http://&lt;ALBEndpoint&gt;/webapp/</code> でアクセス確認・ASG インスタンス <code>InService</code> を確認</td>
</tr>
<tr>
<td>⑧</td>
<td><code>stress-ng</code> で CPU 負荷 → スケールアウト → CodeDeploy が新インスタンスへ自動デプロイ</td>
</tr>
<tr>
<td>⑨</td>
<td>HTML を変更して push → パイプライン自動起動 → 変更を確認（ASG 全インスタンスに反映）</td>
</tr>
<tr>
<td>⑩</td>
<td><code>delete-stack my-Deploy-WebappStack</code> → <code>delete-stack my-AsgPipelineStack</code> の順で削除</td>
</tr>
</tbody>
</table>
<p>ASG を導入することで「<strong>単一障害点の排除・自動スケーリング・スケールアウト時の自動デプロイ</strong>」を一度に体験できました。</p>
<p>コンソールで3層構成を視覚的に学びたい場合は <a href="https://caymezon.com/aws-handson-console-alb-ec2-rds/">AWSコンソール版ハンズオン</a>、CDK の基本は <a href="https://caymezon.com/aws-handson-cdk-alb-ec2-rds/">CDK版ハンズオン（cdk-alb-ec2-rds）</a>、カスタム Construct は <a href="https://caymezon.com/aws-handson-cdk-custom-constructs/">CDK カスタム Construct ハンズオン</a>、インフラ CI/CD は <a href="https://caymezon.com/aws-handson-cdk-pipelines/">CDK Pipelines ハンズオン</a>、アプリ CI/CD は <a href="https://caymezon.com/aws-handson-cdk-webapp-pipeline/">CDK + CodeDeploy ハンズオン</a> を参照してください。</p><p>The post <a href="https://caymezon.com/aws-handson-cdk-asg-webapp/">CDK + Auto Scaling Group で Webアプリをオートスケーリング構成にする【CPU負荷でスケールアウト体験】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-cdk-asg-webapp/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CDK Pipelines で Spring Boot を CI/CD 自動デプロイする【CodeDeploy で WAR ホットデプロイ】</title>
		<link>https://caymezon.com/aws-handson-cdk-webapp-pipeline/</link>
					<comments>https://caymezon.com/aws-handson-cdk-webapp-pipeline/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Wed, 29 Apr 2026 04:57:53 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[ALB]]></category>
		<category><![CDATA[appspec.yml]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[CDK]]></category>
		<category><![CDATA[CDK Pipelines]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[CodeBuild]]></category>
		<category><![CDATA[CodeConnections]]></category>
		<category><![CDATA[CodeDeploy]]></category>
		<category><![CDATA[CodePipeline]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[GitOps]]></category>
		<category><![CDATA[IaC]]></category>
		<category><![CDATA[Maven]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RDS]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[WAR]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[ホットデプロイ]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[自動デプロイ]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20404</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説cdk-pipelines との比較ファイル構成と役割使用するAWSサービス前提条件作業順序【重要】⓪ 自分のIPアドレスを確認する① キーペアの作成② プロジェクトのセットアップ③ GitH [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-cdk-webapp-pipeline/">CDK Pipelines で Spring Boot を CI/CD 自動デプロイする【CodeDeploy で WAR ホットデプロイ】</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">キーワード解説</a></li><li><a href="#toc3" tabindex="0">cdk-pipelines との比較</a></li><li><a href="#toc4" tabindex="0">ファイル構成と役割</a></li><li><a href="#toc5" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc6" tabindex="0">前提条件</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">③ GitHub との接続を作成する（CodeConnections）</a><ol><li><a href="#toc12" tabindex="0">接続を作成する</a></li><li><a href="#toc13" tabindex="0">GitHub App をインストールする</a></li><li><a href="#toc14" tabindex="0">接続 ARN を確認する</a></li></ol></li><li><a href="#toc15" tabindex="0">④ cdk.json の設定</a></li><li><a href="#toc16" tabindex="0">⑤ コードを GitHub にプッシュする（重要！）</a></li><li><a href="#toc17" tabindex="0">⑥ パイプラインスタックのデプロイ（初回のみ）</a></li><li><a href="#toc18" tabindex="0">⑦ パイプラインの実行状況を確認する</a><ol><li><a href="#toc19" tabindex="0">CloudFormation スタックの命名規則</a></li><li><a href="#toc20" tabindex="0">CloudFormation Outputs の確認</a></li></ol></li><li><a href="#toc21" tabindex="0">⑧ アプリへアクセスする</a><ol><li><a href="#toc22" tabindex="0">ALB の DNS 名を確認する</a></li><li><a href="#toc23" tabindex="0">アプリの動作確認</a></li><li><a href="#toc24" tabindex="0">EC2 に SSH 接続する（オプション）</a></li><li><a href="#toc25" tabindex="0">EC2 から RDS への接続確認（オプション）</a></li></ol></li><li><a href="#toc26" tabindex="0">⑨ CI/CD を体験する（アプリ変更を push で自動反映）</a><ol><li><a href="#toc27" tabindex="0">アプリの HTML を変更する</a></li><li><a href="#toc28" tabindex="0">コミット＆プッシュ</a></li><li><a href="#toc29" tabindex="0">パイプラインの自動起動を確認する</a></li></ol></li><li><a href="#toc30" tabindex="0">⑩ リソース削除</a><ol><li><a href="#toc31" tabindex="0">1. アプリスタックを削除する</a></li><li><a href="#toc32" tabindex="0">2. パイプラインスタックを削除する</a></li><li><a href="#toc33" tabindex="0">3. SSM パラメータを削除する</a></li><li><a href="#toc34" tabindex="0">4. 仮想環境の終了</a></li><li><a href="#toc35" tabindex="0">5. キーペアの削除</a></li><li><a href="#toc36" tabindex="0">6. GitHub との接続を削除する（オプション）</a></li><li><a href="#toc37" tabindex="0">削除確認</a></li><li><a href="#toc38" tabindex="0">削除されるリソース一覧</a></li></ol></li><li><a href="#toc39" tabindex="0">CDK Pipelines + CodeDeploy のポイント解説</a><ol><li><a href="#toc40" tabindex="0">appspec.yml とライフサイクルフック</a></li><li><a href="#toc41" tabindex="0">env_from_cfn_outputs の仕組み</a></li><li><a href="#toc42" tabindex="0">post step の役割</a></li></ol></li><li><a href="#toc43" tabindex="0">トラブルシューティング</a></li><li><a href="#toc44" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「アプリのコードを push するだけで EC2 の Tomcat に自動デプロイされる仕組みを作りたい」——これを実現するのが <strong>CDK Pipelines + CodeDeploy</strong> の組み合わせです。</p>
<p>この記事では、<a href="https://caymezon.com/aws-handson-cdk-pipelines/">CDK Pipelines ハンズオン</a>で体験した <strong>インフラの CI/CD</strong> をさらに発展させ、<strong>Spring Boot（Java）アプリ（WAR ファイル）の自動デプロイ</strong>まで含めた完全な CI/CD パイプラインを構築します。GitHub に push するだけで Maven ビルドが走り、CodeDeploy が EC2/Tomcat に WAR をホットデプロイします。</p>
<pre><code class="language-plaintext">GitHub リポジトリ
  ↓ push（自動トリガー）
CodePipeline (my-cdk4-pipeline)
  ├── Source:        GitHub (CodeConnections 経由)
  ├── Build(Synth):  CodeBuild — cdk synth
  ├── Mutate:        パイプライン自己更新（セルフミューテーション）
  ├── InfraDeploy:   CloudFormation — VPC / EC2 / RDS / ALB / CodeDeploy 設定
  └── BuildAndDeployApp: ← post step
        CodeBuild: mvn package → webapp.war 生成
        CodeDeploy: EC2/Tomcat に WAR をホットデプロイ
                ↓
       [ALB: my-cdk4-alb]
                ↓
       [EC2: my-cdk4-ap-instance]  ← Tomcat + Spring Boot WAR
                ↓
       [RDS: my-cdk4-rds-mysql]    ← MySQL 8.0</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li><code>git push</code> するだけで Maven ビルド → CodeDeploy → WAR ホットデプロイが自動実行される</li>
<li>インフラ（CloudFormation）とアプリ（CodeDeploy）の両方が push で自動更新される</li>
<li>HTML を変更して push すると、数分でブラウザの表示が変わることを確認できる</li>
</ul>
<hr>
<blockquote>
<p><strong>この記事は <a href="https://caymezon.com/aws-handson-cdk-pipelines/">CDK Pipelines ハンズオン（cdk-pipelines）</a> の発展記事です。</strong><br />CDK Pipelines の基本（セルフミューテーション・Stage・CodeConnections）を体験済みの方向けです。コード詳細は <a href="https://github.com/caymezon/aws-handson/tree/main/cdk-webapp-pipeline">GitHub</a> を参照してください。</p>
</blockquote>
<hr>
<p><!-- ![CodePipelineの全ステージが成功し、アプリが表示されている画面](images/pipeline-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">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>CodeDeploy</strong></td>
<td>EC2 への Webアプリ（WAR/ZIP）のホットデプロイを管理するサービス。Tomcat を再起動せずに WAR を差し替えられる</td>
</tr>
<tr>
<td><strong>appspec.yml</strong></td>
<td>CodeDeploy のデプロイ手順を定義するファイル。ファイル配置先と各フェーズで実行するスクリプト（ライフサイクルフック）を記述する</td>
</tr>
<tr>
<td><strong>デプロイバンドル</strong></td>
<td><code>appspec.yml</code> + WAR ファイル + スクリプトを ZIP にまとめたもの。S3 に置いて CodeDeploy に渡す</td>
</tr>
<tr>
<td><strong>ライフサイクルフック</strong></td>
<td>CodeDeploy デプロイの各フェーズ（ApplicationStop・BeforeInstall・AfterInstall 等）で実行するシェルスクリプト</td>
</tr>
<tr>
<td><strong>env_from_cfn_outputs</strong></td>
<td>CDK Pipelines で CloudFormation スタックの出力値（CfnOutput）をパイプラインの後続ステップへ環境変数として渡す仕組み</td>
</tr>
<tr>
<td><strong>post step</strong></td>
<td>CDK Pipelines でステージ（Stage）のデプロイ完了後に続けて実行するステップ。ここでは InfraDeploy 後にアプリをデプロイする</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">cdk-pipelines との比較</span></h2>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>cdk-pipelines</th>
<th>cdk-webapp-pipeline</th>
</tr>
</thead>
<tbody>
<tr>
<td>何を自動デプロイするか</td>
<td>インフラのみ（Tomcat は空で起動）</td>
<td><strong>インフラ ＋ Spring Boot WAR</strong></td>
</tr>
<tr>
<td>アプリコード</td>
<td>なし</td>
<td><code>app/</code> 配下に Java/Spring Boot</td>
</tr>
<tr>
<td>ビルドステップ</td>
<td><code>cdk synth</code> のみ</td>
<td><code>cdk synth</code> ＋ <strong><code>mvn package</code></strong></td>
</tr>
<tr>
<td>デプロイ手段</td>
<td>CloudFormation のみ</td>
<td>CloudFormation ＋ <strong>CodeDeploy</strong></td>
</tr>
<tr>
<td>push したとき</td>
<td>インフラが更新される</td>
<td>インフラ ＋ <strong>アプリも更新される</strong></td>
</tr>
<tr>
<td>主な学習テーマ</td>
<td>CDK Pipelines の基本</td>
<td><strong>CodeDeploy / WAR デプロイ / env_from_cfn_outputs</strong></td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">ファイル構成と役割</span></h2>
<pre><code class="language-plaintext">cdk-webapp-pipeline/
├── app.py                     ← CDK アプリ エントリポイント
├── cdk.json                   ← CDK 設定・Context 変数
├── appspec.yml                ← CodeDeploy: WAR 配置手順とライフサイクルフック
├── scripts/
│   ├── stop_tomcat.sh         ← CodeDeploy: ApplicationStop フック
│   ├── cleanup.sh             ← CodeDeploy: BeforeInstall フック
│   └── start_tomcat.sh        ← CodeDeploy: AfterInstall フック
├── app/                       ← Spring Boot Webアプリ（Java）
│   ├── pom.xml
│   └── src/main/...           ← ItemController / Item / ItemRepository / templates/
├── pipeline/
│   └── pipeline_stack.py      ← CodePipeline + post step 定義
├── stages/
│   └── webapp_stage.py        ← Stage（WebappStack を内包）
├── stacks/
│   └── webapp_stack.py        ← インフラスタック（CfnOutput で値を公開）
└── components/
    └── webapp_construct.py    ← カスタム L3 Construct（CodeDeploy 設定含む）</code></pre>
<table>
<thead>
<tr>
<th>ファイル</th>
<th>役割</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>appspec.yml</code></td>
<td>CodeDeploy に「どこに WAR を置くか・何を実行するか」を指示する</td>
</tr>
<tr>
<td><code>scripts/*.sh</code></td>
<td>Tomcat の停止・クリーンアップ・起動をフェーズごとに実行する</td>
</tr>
<tr>
<td><code>pipeline_stack.py</code></td>
<td>InfraDeploy の <code>post</code> に <code>BuildAndDeployApp</code> ステップを追加。<code>env_from_cfn_outputs</code> でスタック出力を受け取る</td>
</tr>
<tr>
<td><code>webapp_stack.py</code></td>
<td>CodeDeploy の設定（アプリ名・デプロイグループ名）を <code>CfnOutput</code> で公開する</td>
</tr>
</tbody>
</table>
<p>詳細なコードは <a href="https://github.com/caymezon/aws-handson/tree/main/cdk-webapp-pipeline">GitHub</a> を参照してください。</p>
<hr>
<h2><span id="toc5">使用する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 + Spring Boot）</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>CodePipeline</strong></td>
<td>CI/CD パイプライン管理</td>
<td>月1パイプラインまで無料枠あり</td>
</tr>
<tr>
<td><strong>CodeBuild</strong></td>
<td>cdk synth・Maven ビルドを実行するビルド環境</td>
<td>月100分まで無料枠あり</td>
</tr>
<tr>
<td><strong>CodeDeploy</strong></td>
<td>EC2 への WAR ホットデプロイ</td>
<td>EC2 へのデプロイは<strong>無料</strong></td>
</tr>
<tr>
<td><strong>S3</strong></td>
<td>パイプラインのアーティファクト・デプロイバンドル置き場</td>
<td>無料枠あり</td>
</tr>
<tr>
<td><strong>SSM Parameter Store</strong></td>
<td>DBパスワードの安全な保管</td>
<td>スタンダード層は無料</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>各サービスの権限</td>
<td>無料</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>注意</strong>: ALBは無料枠がありません。ハンズオン後は必ずリソースを削除してください。</p>
</blockquote>
<hr>
<h2><span id="toc6">前提条件</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>
<tr>
<td>Java 17</td>
<td><code>java -version</code></td>
</tr>
<tr>
<td>Maven</td>
<td><code>mvn -version</code></td>
</tr>
<tr>
<td>Python 3.9 以上</td>
<td><code>python --version</code></td>
</tr>
<tr>
<td>Node.js 18 以上</td>
<td><code>node --version</code></td>
</tr>
<tr>
<td>CDK CLI</td>
<td><code>cdk --version</code></td>
</tr>
<tr>
<td>Git</td>
<td><code>git --version</code></td>
</tr>
</tbody>
</table>
<p>AWS 認証確認:</p>
<pre><code class="language-cmd">aws sts get-caller-identity</code></pre>
<p>CDK Bootstrap 確認（<code>CDKToolkit</code> スタックが存在すれば実施済み）:</p>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name CDKToolkit ^
  --query "Stacks[0].StackStatus" ^
  --output text ^
  --region ap-northeast-1</code></pre>
<blockquote>
<p><strong>GitHub アカウントが必要です</strong>。<code>aws-learning-projects</code> リポジトリに push できる状態にしておいてください。</p>
</blockquote>
<hr>
<h2><span id="toc7">作業順序</span></h2>
<pre><code class="language-plaintext">⓪ 自分のIPアドレスを確認する
      ↓
① キーペアを作成する（AWS CLI で実施）
      ↓
② プロジェクトのセットアップ（Python 仮想環境）
      ↓
③ GitHub との接続を作成する（CodeConnections）
      ↓
④ cdk.json を設定する
      ↓
⑤ コードを全て GitHub にプッシュする（重要！）
      ↓
⑥ パイプラインスタックをデプロイする（初回のみ手動）
      ↓
⑦ パイプラインの実行状況を確認する
      ↓
⑧ アプリへアクセスする（/webapp/ 必須）
      ↓
⑨ CI/CD を体験する（アプリ変更を push で自動反映）
      ↓
⑩ リソース削除</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>
<pre><code class="language-cmd">aws ec2 create-key-pair ^
  --key-name my-cdk4-key ^
  --query KeyMaterial ^
  --output text ^
  --region ap-northeast-1 &gt; %USERPROFILE%\.ssh\my-cdk4-key.pem</code></pre>
<blockquote>
<p><code>%USERPROFILE%\.ssh\</code> が存在しない場合は先に <code>mkdir %USERPROFILE%\.ssh</code> を実行してください。</p>
</blockquote>
<hr>
<h2><span id="toc10">② プロジェクトのセットアップ</span></h2>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-webapp-pipeline

python -m venv .venv

.venv\Scripts\activate

pip install -r requirements.txt</code></pre>
<p>プロンプトの先頭に <code>(.venv)</code> が表示されれば仮想環境が有効になっています。</p>
<blockquote>
<p><strong>重要</strong>: CDK コマンド（synth / deploy / destroy）はすべてこの仮想環境が有効な状態で実行する必要があります。<br />ターミナルを開き直した際は必ず最初に以下を実行してください。</p>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-webapp-pipeline
.venv\Scripts\activate</code></pre>
</blockquote>
<hr>
<h2><span id="toc11">③ GitHub との接続を作成する（CodeConnections）</span></h2>
<blockquote>
<p><strong>cdk-pipelines を実施済みの場合</strong>: 同じリポジトリ <code>aws-learning-projects</code> を扱うため、<br />既存の接続（<code>my-github-connection</code>）をそのまま<strong>再利用</strong>できます。<br /><strong>③ はスキップして、ARN の確認（③-4）から始めてください。</strong></p>
</blockquote>
<p>CodePipeline が GitHub リポジトリを監視するために、<strong>GitHub との接続（CodeConnections）</strong> を作成します。</p>
<blockquote>
<p><strong>重要</strong>: AWS コンソールと GitHub の操作は<strong>同じブラウザ</strong>で行ってください。<br />別ブラウザで操作すると、AWS にリダイレクトされた際にデフォルトリージョン（バージニア北部等）でログインされる場合があります。</p>
</blockquote>
<h3><span id="toc12">接続を作成する</span></h3>
<ol>
<li>AWS コンソール検索（<code>Alt+S</code>）で <code>CodePipeline</code> と入力 → <strong>CodePipeline</strong> を開く</li>
<li>左サイドバー → <strong>「設定」</strong> → <strong>「接続」</strong></li>
<li>リージョンが <strong>東京（ap-northeast-1）</strong> になっていることを確認する</li>
<li>「<strong>接続を作成</strong>」をクリック</li>
<li>プロバイダー: <strong>GitHub</strong> を選択</li>
<li>接続名: <code>my-github-connection</code>（任意）</li>
<li>「<strong>GitHub に接続する</strong>」をクリック</li>
</ol>
<h3><span id="toc13">GitHub App をインストールする</span></h3>
<p>クリック後、GitHub の OAuth 認証画面が開きます。</p>
<ol start="8">
<li>「<strong>Authorize</strong>」をクリック → AWS コンソールの「GitHub 接続設定」画面に自動で戻る</li>
<li>「<strong>新しいアプリをインストールする</strong>」をクリック → GitHub の「Install & Authorize」画面が開く</li>
<li><strong>「Only select repositories」</strong> を選択 → <code>aws-learning-projects</code> を追加</li>
<li>「<strong>Install & Authorize</strong>」をクリック（メール認証コードが求められる場合は入力）</li>
<li>AWS コンソールに自動でリダイレクトされる → 「<strong>接続</strong>」ボタンをクリック</li>
</ol>
<h3><span id="toc14">接続 ARN を確認する</span></h3>
<p>接続一覧から接続の ARN をコピーします。</p>
<pre><code class="language-plaintext">arn:aws:codeconnections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</code></pre>
<blockquote>
<p><strong>重要</strong>: ステータスが <strong>「利用可能」</strong> になっていることを確認してから次に進んでください。</p>
</blockquote>
<p><!-- ![CodeConnectionsの接続一覧で「利用可能」になっている画面](images/connections-available.jpg) --></p>
<p><strong>控えておく情報</strong>: 接続 ARN（<code>arn:aws:codeconnections:...</code>）</p>
<hr>
<h2><span id="toc15">④ cdk.json の設定</span></h2>
<p><code>cdk.json</code> の <code>context</code> セクションを自分の環境に合わせて編集します。</p>
<pre><code class="language-json">{
  "context": {
    "employee_id": "my",
    "my_ip": "203.0.113.1/32",
    "db_password": "Handson1234!",
    "key_name": "my-cdk4-key",
    "tomcat_version": "10.1.28",
    "github_owner": "your-github-username",
    "github_repo": "aws-learning-projects",
    "github_branch": "main",
    "connection_arn": "arn:aws:codeconnections:ap-northeast-1:..."
  }
}</code></pre>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>employee_id</code></td>
<td><code>my</code></td>
<td>リソース名のプレフィックス（<code>my-cdk4-xxx</code> という名前になる）</td>
</tr>
<tr>
<td><code>my_ip</code></td>
<td>⓪で確認したIP <code>/32</code></td>
<td>EC2へのSSHを許可するIP</td>
</tr>
<tr>
<td><code>key_name</code></td>
<td><code>my-cdk4-key</code></td>
<td>①で作成したキーペア名</td>
</tr>
<tr>
<td><code>github_owner</code></td>
<td>GitHub ユーザー名</td>
<td>リポジトリのオーナー名（または Org 名）</td>
</tr>
<tr>
<td><code>github_repo</code></td>
<td><code>aws-learning-projects</code></td>
<td>リポジトリ名</td>
</tr>
<tr>
<td><code>github_branch</code></td>
<td><code>main</code></td>
<td>監視するブランチ名</td>
</tr>
<tr>
<td><code>connection_arn</code></td>
<td>③で確認した ARN</td>
<td>CodeConnections の接続 ARN</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>cdk-pipelines（前回）と同時にデプロイしてもリソース名が競合しません</strong>。前回は <code>my-cdk3-xxx</code>、今回は <code>my-cdk4-xxx</code> というプレフィックスになります。</p>
</blockquote>
<hr>
<h2><span id="toc16">⑤ コードを GitHub にプッシュする（重要！）</span></h2>
<blockquote>
<p><strong>cdk-pipelines との重要な違い</strong>: このハンズオンでは <strong><code>cdk.json</code> だけでなくプロジェクト全体を push する必要があります</strong>。</p>
<p>CDK Pipelines は GitHub から取得したコードで <code>cdk synth</code> を実行し、Maven ビルドも行います。<br />Java ソース（<code>app/</code>）・<code>appspec.yml</code>・<code>scripts/</code> がリポジトリに存在しないと、パイプラインの <code>BuildAndDeployApp</code> ステップが失敗します。</p>
<p><strong><code>cdk deploy</code> の前に必ずコード全体を push してください。</strong></p>
</blockquote>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects

git add cdk-webapp-pipeline/
git commit -m "feat: cdk-webapp-pipeline ハンズオンを追加"
git push origin main</code></pre>
<hr>
<h2><span id="toc17">⑥ パイプラインスタックのデプロイ（初回のみ）</span></h2>
<p>CDK Pipelines では<strong>パイプライン自体を最初に1回だけ手動でデプロイ</strong>します。以降はパイプラインが自動的に動作します。</p>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-webapp-pipeline

.venv\Scripts\activate

cdk synth

cdk deploy my-WebappPipelineStack</code></pre>
<p>「Do you wish to deploy these changes?」に <code>y</code> を入力します。</p>
<blockquote>
<p><strong>所要時間</strong>: パイプラインスタック自体のデプロイは 3〜5 分。その後パイプラインが自動起動します。</p>
</blockquote>
<p>デプロイ完了後、CodePipeline が自動起動します:</p>
<table>
<thead>
<tr>
<th>ステージ</th>
<th>内容</th>
<th>所要時間</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Source</strong></td>
<td>GitHub から最新コードを取得</td>
<td>〜1分</td>
</tr>
<tr>
<td><strong>Build (Synth)</strong></td>
<td><code>cdk synth</code> でテンプレート生成</td>
<td>〜3分</td>
</tr>
<tr>
<td><strong>UpdatePipeline</strong></td>
<td>パイプライン自己更新（セルフミューテーション）</td>
<td>〜2分</td>
</tr>
<tr>
<td><strong>Deploy > InfraDeploy</strong></td>
<td>CloudFormation で VPC/EC2/RDS/ALB/CodeDeploy 設定を構築</td>
<td>〜15分</td>
</tr>
<tr>
<td><strong>Deploy > BuildAndDeployApp</strong></td>
<td>Maven ビルド → S3 → CodeDeploy で WAR デプロイ</td>
<td>〜10分</td>
</tr>
</tbody>
</table>
<blockquote>
<p>RDS の起動に時間がかかるため、InfraDeploy は 10〜20 分かかることがあります。</p>
</blockquote>
<hr>
<h2><span id="toc18">⑦ パイプラインの実行状況を確認する</span></h2>
<ol>
<li>AWS コンソール → <strong>CodePipeline</strong> を開く</li>
<li><code>my-cdk4-pipeline</code> を選択</li>
<li>各ステージが <strong>「成功」</strong> になるまで待つ</li>
</ol>
<h3><span id="toc19">CloudFormation スタックの命名規則</span></h3>
<p>CDK Pipelines でステージをデプロイすると、CloudFormation スタック名は以下の形式になります:</p>
<pre><code class="language-plaintext">{StageName}-{StackName}</code></pre>
<table>
<thead>
<tr>
<th>要素</th>
<th>このハンズオンでの値</th>
</tr>
</thead>
<tbody>
<tr>
<td>StageName</td>
<td><code>my-Deploy</code>（<code>pipeline_stack.py</code> でステージを追加した際の名前）</td>
</tr>
<tr>
<td>StackName</td>
<td><code>WebappStack</code>（<code>webapp_stage.py</code> の <code>WebappStack(self, &quot;WebappStack&quot;)</code> のID）</td>
</tr>
<tr>
<td>結果</td>
<td><strong><code>my-Deploy-WebappStack</code></strong></td>
</tr>
</tbody>
</table>
<blockquote>
<p><code>my-WebappPipelineStack</code>（パイプライン）と <code>my-Deploy-WebappStack</code>（インフラ）の <strong>2つが別スタック</strong>として CloudFormation に表示されます。</p>
</blockquote>
<h3><span id="toc20">CloudFormation Outputs の確認</span></h3>
<p>InfraDeploy ステージが完了したら、インフラスタックの Outputs を確認します。</p>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name my-Deploy-WebappStack ^
  --region ap-northeast-1 ^
  --query "Stacks[0].Outputs"</code></pre>
<p><strong>控えておく情報</strong>: <code>ALBEndpoint</code>、<code>EC2PublicIP</code>、<code>RDSEndpoint</code></p>
<p><!-- ![CodePipelineの全ステージが成功している画面](images/pipeline-success.jpg) --></p>
<hr>
<h2><span id="toc21">⑧ アプリへアクセスする</span></h2>
<p><code>BuildAndDeployApp</code> ステージが完了（全ステージが成功）したら、ALB 経由でアプリにアクセスします。</p>
<h3><span id="toc22">ALB の DNS 名を確認する</span></h3>
<p>Outputs の <code>ALBEndpoint</code> をブラウザで開きます。</p>
<blockquote>
<p><strong>重要</strong>: URL のパスに <code>/webapp/</code> が必要です。</p>
</blockquote>
<pre><code class="language-plaintext">http://&lt;ALBEndpoint&gt;/webapp/</code></pre>
<blockquote>
<p><code>http://&lt;ALBEndpoint&gt;/</code>（ルートパス）では Tomcat のデフォルト画面が表示されます。<br />WAR が <code>webapp.war</code> としてデプロイされるため、アプリは <code>/webapp/</code> 以下に配置されます。</p>
</blockquote>
<p>または CLI で ALBEndpoint を確認:</p>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name my-Deploy-WebappStack ^
  --region ap-northeast-1 ^
  --query "Stacks[0].Outputs[?OutputKey=='ALBEndpoint'].OutputValue" ^
  --output text</code></pre>
<h3><span id="toc23">アプリの動作確認</span></h3>
<p>以下が表示されれば正常です:</p>
<ul>
<li>「<strong>Spring Boot + RDS Item Manager</strong>」というタイトルが表示される</li>
<li>アイテムの追加・削除ができる</li>
<li>ブラウザをリロードしてもデータが保持される（RDS への永続化が成功）</li>
</ul>
<p><!-- ![Spring Boot アプリのアイテム管理画面が表示されている様子](images/webapp-access.jpg) --></p>
<h3><span id="toc24">EC2 に SSH 接続する（オプション）</span></h3>
<pre><code class="language-cmd">ssh -i %USERPROFILE%\.ssh\my-cdk4-key.pem ec2-user@（EC2PublicIP）</code></pre>
<p>EC2 接続後にログ確認などを行う場合（以下は EC2 上での操作）:</p>
<pre><code class="language-bash">sudo systemctl status codedeploy-agent   # CodeDeploy エージェントの状態確認

sudo cat /opt/tomcat/logs/catalina.out   # Tomcat のログ確認

sudo ls -la /opt/tomcat/webapps/         # デプロイされた WAR を確認</code></pre>
<h3><span id="toc25">EC2 から RDS への接続確認（オプション）</span></h3>
<p>EC2 に SSH 接続後:</p>
<pre><code class="language-bash">sudo dnf install -y mariadb105

DB_PASSWORD=$(aws ssm get-parameter \
  --name /my/cdk4/db-password \
  --query Parameter.Value \
  --output text \
  --region ap-northeast-1)

mysql -h &lt;RDSEndpoint&gt; -u admin -p${DB_PASSWORD} sampledb

mysql&gt; SHOW TABLES;
mysql&gt; exit</code></pre>
<hr>
<h2><span id="toc26">⑨ CI/CD を体験する（アプリ変更を push で自動反映）</span></h2>
<p>CDK Pipelines + CodeDeploy の醍醐味は「<strong>アプリのコードを push するだけで EC2 の Tomcat に自動デプロイされる</strong>」ことです。</p>
<h3><span id="toc27">アプリの HTML を変更する</span></h3>
<p><code>app/src/main/resources/templates/index.html</code> を開き、以下の行を変更します:</p>
<p>変更前:</p>
<pre><code class="language-html">&lt;h1&gt;Spring Boot + RDS Item Manager&lt;/h1&gt;</code></pre>
<p>変更後:</p>
<pre><code class="language-html">&lt;h1&gt;Spring Boot + RDS Item Manager v2&lt;/h1&gt;</code></pre>
<h3><span id="toc28">コミット＆プッシュ</span></h3>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects
git add cdk-webapp-pipeline/app/src/main/resources/templates/index.html
git commit -m "feat: update webapp UI to v2"
git push</code></pre>
<h3><span id="toc29">パイプラインの自動起動を確認する</span></h3>
<ol>
<li>AWS コンソール → <strong>CodePipeline</strong> → <code>my-cdk4-pipeline</code></li>
<li>push 後、数十秒以内にパイプラインが<strong>自動起動</strong>することを確認</li>
<li><code>BuildAndDeployApp</code> ステージが完了したらブラウザで <code>/webapp/</code> を更新する</li>
</ol>
<p>変更前後の見出しが切り替わっていれば、アプリの CI/CD が正常に動作しています。</p>
<p><!-- ![ブラウザに「v2」の見出しが表示されている様子](images/webapp-v2.jpg) --></p>
<blockquote>
<p><strong>補足</strong>: <code>InfraDeploy</code> ステージはインフラに変更がない場合は「変更なし」でスキップされ、高速に完了します。</p>
<p><strong>注意</strong>: CodePipeline は <code>main</code> ブランチへの全ての push でトリガーされます。<br /><code>.md</code> ファイルだけ変更した場合でもビルド・デプロイが走ります。本番環境ではブランチ戦略や CodePipeline V2 のトリガーフィルターで絞ることができます。</p>
</blockquote>
<hr>
<h2><span id="toc30">⑩ リソース削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除します。</strong></p>
<blockquote>
<p><strong>削除順序が重要です</strong>。パイプラインによってデプロイされたスタック（<code>my-Deploy-WebappStack</code>）を<strong>先に</strong>削除してから、パイプラインスタック（<code>my-WebappPipelineStack</code>）を削除します。</p>
</blockquote>
<h3><span id="toc31">1. アプリスタックを削除する</span></h3>
<pre><code class="language-cmd">aws cloudformation delete-stack ^
  --stack-name my-Deploy-WebappStack ^
  --region ap-northeast-1

aws cloudformation wait stack-delete-complete ^
  --stack-name my-Deploy-WebappStack ^
  --region ap-northeast-1

echo WebappStack 削除完了</code></pre>
<blockquote>
<p>RDS の削除に 10〜15 分かかります。<code>wait</code> コマンドが完了するまでそのまま待ってください。</p>
</blockquote>
<h3><span id="toc32">2. パイプラインスタックを削除する</span></h3>
<pre><code class="language-cmd">aws cloudformation delete-stack ^
  --stack-name my-WebappPipelineStack ^
  --region ap-northeast-1

aws cloudformation wait stack-delete-complete ^
  --stack-name my-WebappPipelineStack ^
  --region ap-northeast-1

echo PipelineStack 削除完了</code></pre>
<h3><span id="toc33">3. SSM パラメータを削除する</span></h3>
<pre><code class="language-cmd">aws ssm delete-parameter ^
  --name "/my/cdk4/db-password" ^
  --region ap-northeast-1</code></pre>
<h3><span id="toc34">4. 仮想環境の終了</span></h3>
<pre><code class="language-cmd">deactivate</code></pre>
<h3><span id="toc35">5. キーペアの削除</span></h3>
<pre><code class="language-cmd">aws ec2 delete-key-pair ^
  --key-name my-cdk4-key ^
  --region ap-northeast-1

del %USERPROFILE%\.ssh\my-cdk4-key.pem</code></pre>
<h3><span id="toc36">6. GitHub との接続を削除する（オプション）</span></h3>
<p>次のハンズオンでも使う場合はそのままでよいです。</p>
<p><strong>CodePipeline → 設定 → 接続 → <code>my-github-connection</code> → 「削除」</strong></p>
<h3><span id="toc37">削除確認</span></h3>
<pre><code class="language-cmd">aws cloudformation list-stacks ^
  --region ap-northeast-1 ^
  --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE ^
  --query "StackSummaries[?contains(StackName, 'my-')].StackName"</code></pre>
<p>空のリスト <code>[]</code> が返れば削除完了です。</p>
<h3><span id="toc38">削除されるリソース一覧</span></h3>
<table>
<thead>
<tr>
<th>リソース</th>
<th>削除方法</th>
</tr>
</thead>
<tbody>
<tr>
<td>ALB・EC2・RDS・VPC・SG・S3（アーティファクト）・CodeDeploy</td>
<td><code>delete-stack my-Deploy-WebappStack</code> で削除</td>
</tr>
<tr>
<td>CodePipeline・CodeBuild</td>
<td><code>delete-stack my-WebappPipelineStack</code> で削除</td>
</tr>
<tr>
<td>SSM パラメータ（DBパスワード）</td>
<td><code>aws ssm delete-parameter</code> で手動削除</td>
</tr>
<tr>
<td>キーペア</td>
<td><code>aws ec2 delete-key-pair</code> で手動削除</td>
</tr>
<tr>
<td>GitHub との接続（CodeConnections）</td>
<td>CodePipeline コンソールから手動削除</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc39">CDK Pipelines + CodeDeploy のポイント解説</span></h2>
<h3><span id="toc40">appspec.yml とライフサイクルフック</span></h3>
<pre><code class="language-yaml">version: 0.0
os: linux
files:
  - source: webapp.war
    destination: /opt/tomcat/webapps/
    overwrite: true
hooks:
  ApplicationStop:
    - location: scripts/stop_tomcat.sh    # Tomcat 停止
  BeforeInstall:
    - location: scripts/cleanup.sh         # 古い WAR・展開ディレクトリを削除
  AfterInstall:
    - location: scripts/start_tomcat.sh    # Tomcat 起動</code></pre>
<p>CodeDeploy はこの順序でフックを実行し、Tomcat の再起動を伴わずに WAR を差し替えます。</p>
<h3><span id="toc41">env_from_cfn_outputs の仕組み</span></h3>
<p>インフラスタック（<code>webapp_stack.py</code>）は CodeDeploy のリソース情報を <code>CfnOutput</code> で公開します:</p>
<pre><code class="language-python">self.deploy_app_name_output = CfnOutput(
    self, "DeployApplicationName",
    value=web.deploy_application.application_name,
)</code></pre>
<p>パイプライン（<code>pipeline_stack.py</code>）はこの出力をアプリデプロイステップの環境変数として受け取ります:</p>
<pre><code class="language-python"># pipeline_stack.py
build_and_deploy = CodeBuildStep(
    "BuildAndDeployApp",
    env_from_cfn_outputs={
        "DEPLOY_APP_NAME": stage.deploy_app_name_output,   # CloudFormation Output → 環境変数
    },
    commands=["aws deploy create-deployment --application-name $DEPLOY_APP_NAME ..."],
)</code></pre>
<p>これにより、パイプラインのコードにリソース名をハードコードせず、CloudFormation が実際に作成したリソース名を動的に参照できます。</p>
<h3><span id="toc42">post step の役割</span></h3>
<pre><code class="language-python">pipeline.add_stage(stage, post=[build_and_deploy])</code></pre>
<p><code>post</code> にステップを渡すことで、ステージ（InfraDeploy）の完了後に続けて <code>BuildAndDeployApp</code> が実行されます。これにより「インフラが確実に存在する状態でアプリをデプロイする」という順序が保証されます。</p>
<hr>
<h2><span id="toc43">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>Source ステージが「失敗」</td>
<td>GitHub との接続が「保留中」のまま</td>
<td>CodePipeline → 設定 → 接続 → 承認して「利用可能」にする</td>
</tr>
<tr>
<td>BuildAndDeployApp が <code>mvn package</code> で失敗</td>
<td>Java ソースが GitHub に push されていない</td>
<td><code>git add cdk-webapp-pipeline/</code> で全ファイルを push してから再実行</td>
</tr>
<tr>
<td>CodeDeploy が失敗する</td>
<td>EC2 の UserData が完了していない</td>
<td>EC2 起動後 1〜2 分待ってから再デプロイ。<code>sudo systemctl status codedeploy-agent</code> で確認</td>
</tr>
<tr>
<td>ALB にアクセスすると 404 or 502</td>
<td>WAR デプロイ未完了 または Tomcat 起動中</td>
<td><code>BuildAndDeployApp</code> ステージが完了するまで待つ</td>
</tr>
<tr>
<td><code>/webapp/</code> で接続できない</td>
<td>URL パスが間違い</td>
<td>ルート URL（<code>/</code>）ではなく <code>/webapp/</code> にアクセスする</td>
</tr>
<tr>
<td>Tomcat の <code>catalina.out</code> に RDS 接続エラー</td>
<td><code>setenv.sh</code> の DB_HOST が未設定</td>
<td>EC2 に SSH して <code>cat /opt/tomcat/bin/setenv.sh</code> を確認する</td>
</tr>
<tr>
<td>パイプラインが自動起動しない</td>
<td>接続が「保留中」または branch 名が違う</td>
<td>接続を承認 / <code>cdk.json</code> の <code>github_branch</code> を確認</td>
</tr>
</tbody>
</table>
<p>CodeDeploy 失敗時のログ確認:</p>
<p><strong>AWS コンソール → CodeDeploy → アプリケーション → デプロイグループ → デプロイ履歴 → 失敗したデプロイ → 「ログの表示」</strong></p>
<hr>
<h2><span id="toc44">まとめ</span></h2>
<table>
<thead>
<tr>
<th>ステップ</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>①②</td>
<td>キーペア作成 + Python 仮想環境のセットアップ</td>
</tr>
<tr>
<td>③</td>
<td>CodeConnections で GitHub との接続を作成・承認（cdk-pipelines 実施済みなら再利用）</td>
</tr>
<tr>
<td>④</td>
<td><code>cdk.json</code> に <code>github_owner</code>・<code>github_repo</code>・<code>connection_arn</code>・<code>key_name</code> を設定</td>
</tr>
<tr>
<td>⑤</td>
<td><strong><code>cdk-webapp-pipeline/</code> 全体</strong>を GitHub に push（Java ソース・appspec.yml も含む）</td>
</tr>
<tr>
<td>⑥</td>
<td><code>cdk deploy my-WebappPipelineStack</code>（<strong>初回のみ手動</strong>）でパイプラインスタックをデプロイ</td>
</tr>
<tr>
<td>⑦</td>
<td>CodePipeline が自動起動 → Synth → Mutate → InfraDeploy（15〜20 分）→ BuildAndDeployApp（10 分）</td>
</tr>
<tr>
<td>⑧</td>
<td><code>http://&lt;ALBEndpoint&gt;/webapp/</code> でアプリにアクセスし、アイテムの追加・削除を確認</td>
</tr>
<tr>
<td>⑨</td>
<td>HTML を変更して push → パイプライン自動起動 → ブラウザで変更を確認（アプリ CI/CD 体験）</td>
</tr>
<tr>
<td>⑩</td>
<td><code>delete-stack my-Deploy-WebappStack</code> → <code>delete-stack my-WebappPipelineStack</code> の順で削除</td>
</tr>
</tbody>
</table>
<p>CDK Pipelines + CodeDeploy を組み合わせることで、「<strong>インフラもアプリも、コードが唯一の変更手段になる</strong>」GitOps の世界を体験できました。インフラ変更は CloudFormation が、アプリ変更は CodeDeploy が、それぞれ自動で EC2 に反映します。</p>
<p>コンソールで3層構成を視覚的に学びたい場合は <a href="https://caymezon.com/aws-handson-console-alb-ec2-rds/">AWSコンソール版ハンズオン</a>、CDK の基本は <a href="https://caymezon.com/aws-handson-cdk-alb-ec2-rds/">CDK版ハンズオン（cdk-alb-ec2-rds）</a>、カスタム Construct は <a href="https://caymezon.com/aws-handson-cdk-custom-constructs/">CDK カスタム Construct ハンズオン</a>、インフラ CI/CD のみは <a href="https://caymezon.com/aws-handson-cdk-pipelines/">CDK Pipelines ハンズオン</a> を参照してください。</p><p>The post <a href="https://caymezon.com/aws-handson-cdk-webapp-pipeline/">CDK Pipelines で Spring Boot を CI/CD 自動デプロイする【CodeDeploy で WAR ホットデプロイ】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-cdk-webapp-pipeline/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CDK Pipelines でインフラの CI/CD を構築する【git push だけで ALB + EC2 + RDS が自動デプロイ】</title>
		<link>https://caymezon.com/aws-handson-cdk-pipelines/</link>
					<comments>https://caymezon.com/aws-handson-cdk-pipelines/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sun, 26 Apr 2026 07:25:39 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[ALB]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[CDK]]></category>
		<category><![CDATA[CDK Pipelines]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[CodeBuild]]></category>
		<category><![CDATA[CodeConnections]]></category>
		<category><![CDATA[CodePipeline]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[GitOps]]></category>
		<category><![CDATA[IaC]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RDS]]></category>
		<category><![CDATA[Stage]]></category>
		<category><![CDATA[セルフミューテーション]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[自動デプロイ]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20401</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説cdk-custom-constructs との比較ファイル構成と役割使用するAWSサービス前提条件作業順序【重要】⓪ 自分のIPアドレスを確認する① キーペアの作成② プロジェクトのセットア [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-cdk-pipelines/">CDK Pipelines でインフラの CI/CD を構築する【git push だけで ALB + EC2 + RDS が自動デプロイ】</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-6" checked><label class="toc-title" for="toc-checkbox-6">目次</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">cdk-custom-constructs との比較</a></li><li><a href="#toc4" tabindex="0">ファイル構成と役割</a></li><li><a href="#toc5" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc6" tabindex="0">前提条件</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">③ GitHub との接続を作成する（CodeConnections）</a><ol><li><a href="#toc12" tabindex="0">接続を作成する</a></li><li><a href="#toc13" tabindex="0">GitHub App をインストールする</a></li><li><a href="#toc14" tabindex="0">接続 ARN を確認する</a></li></ol></li><li><a href="#toc15" tabindex="0">④ cdk.json の設定</a></li><li><a href="#toc16" tabindex="0">⑤ コードを GitHub にプッシュする</a></li><li><a href="#toc17" tabindex="0">⑥ パイプラインスタックのデプロイ（初回のみ）</a></li><li><a href="#toc18" tabindex="0">⑦ パイプラインの実行状況を確認する</a><ol><li><a href="#toc19" tabindex="0">CloudFormation スタックの命名規則</a></li><li><a href="#toc20" tabindex="0">CloudFormation Outputs の確認</a></li></ol></li><li><a href="#toc21" tabindex="0">⑧ 動作確認</a><ol><li><a href="#toc22" tabindex="0">8-1. ALB 経由でWebアクセス確認</a></li><li><a href="#toc23" tabindex="0">8-2. EC2 に SSH 接続する</a></li><li><a href="#toc24" tabindex="0">8-3. EC2 から RDS への接続確認</a></li><li><a href="#toc25" tabindex="0">8-4. SSH 接続を切断する</a></li></ol></li><li><a href="#toc26" tabindex="0">⑨ CI/CD を体験する（インフラ変更を push で自動反映）</a><ol><li><a href="#toc27" tabindex="0">EC2 にタグを追加して CI/CD を確認する</a></li><li><a href="#toc28" tabindex="0">push する</a></li><li><a href="#toc29" tabindex="0">パイプラインの自動起動を確認する</a></li><li><a href="#toc30" tabindex="0">タグが反映されたことを確認する</a></li></ol></li><li><a href="#toc31" tabindex="0">⑩ リソース削除</a><ol><li><a href="#toc32" tabindex="0">1. パイプラインで作成されたスタックを削除する</a></li><li><a href="#toc33" tabindex="0">2. パイプラインスタック自体を削除する</a></li><li><a href="#toc34" tabindex="0">3. アーティファクト S3 バケットを削除する（必要な場合）</a></li><li><a href="#toc35" tabindex="0">4. 仮想環境の終了</a></li><li><a href="#toc36" tabindex="0">5. キーペアの削除（手動）</a></li><li><a href="#toc37" tabindex="0">6. GitHub との接続を削除する（手動）</a></li><li><a href="#toc38" tabindex="0">削除されるリソース一覧</a></li></ol></li><li><a href="#toc39" tabindex="0">CDK Pipelines のポイント解説</a><ol><li><a href="#toc40" tabindex="0">なぜ cdk deploy は初回だけ必要なのか</a></li><li><a href="#toc41" tabindex="0">Stage クラスの役割</a></li><li><a href="#toc42" tabindex="0">モノレポでの primary_output_directory</a></li></ol></li><li><a href="#toc43" tabindex="0">トラブルシューティング</a></li><li><a href="#toc44" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「インフラの変更を反映するたびに <code>cdk deploy</code> を手動実行するのが面倒」「コードをプッシュするだけで AWS リソースが自動更新されるようにしたい」——これを実現するのが <strong>CDK Pipelines</strong> です。</p>
<p>この記事では、<a href="https://caymezon.com/aws-handson-cdk-custom-constructs/">CDK カスタム Construct ハンズオン</a>で構築した <strong>ALB + EC2(Tomcat) + RDS の3層構成</strong>を、<strong>CDK Pipelines（CodePipeline + CodeBuild）</strong> で CI/CD 化します。GitHub にコードをプッシュするだけで自動的にインフラがデプロイ・更新される仕組みを体験します。</p>
<pre><code class="language-plaintext">GitHub リポジトリ
  ↓ push（自動トリガー）
CodePipeline (my-cdk3-pipeline)
  ├── Source:  GitHub (CodeConnections 経由)
  ├── Build:   CodeBuild — cdk synth
  ├── Mutate:  パイプライン自身を自動更新（セルフミューテーション）
  └── Deploy:  CloudFormation — ThreeTierStack
                  ↓
         [ALB: my-cdk3-alb]
                  ↓
         [EC2: my-cdk3-ap-instance]  ← Tomcat
                  ↓
         [RDS: my-cdk3-rds-mysql]    ← MySQL 8.0</code></pre>
<p><strong>このハンズオンで体験できること（インフラの CI/CD）：</strong></p>
<ul>
<li><code>git push</code> するだけで VPC / EC2 / RDS / ALB などのインフラ構築・更新が自動実行される</li>
<li>SG ルール追加・インスタンスタイプ変更などのインフラ変更が push で自動反映される</li>
<li>パイプライン自体の定義変更も自動反映される（<strong>セルフミューテーション</strong>）</li>
</ul>
<p><strong>このハンズオンで体験できないこと（アプリの CI/CD）：</strong></p>
<blockquote>
<p>このハンズオンでは HTML を EC2 の <strong>UserData</strong> に埋め込んでいます。UserData は EC2 の<strong>初回起動時にのみ実行</strong>される仕組みのため、push しても既存 EC2 上のファイルは書き換えられません。<br />Java アプリ（WAR ファイル）を push で自動デプロイしたい場合は、次のハンズオン <code>cdk-webapp-pipeline</code>（CodeDeploy を使用）で体験します。</p>
</blockquote>
<hr>
<blockquote>
<p><strong>この記事は <a href="https://caymezon.com/aws-handson-cdk-custom-constructs/">CDK カスタム Construct ハンズオン（cdk-custom-constructs）</a> の発展記事です。</strong><br />CDK の基本（Bootstrap・synth・deploy）と カスタム Construct を体験済みの方向けです。コード詳細は <a href="https://github.com/caymezon/aws-handson/tree/main/cdk-pipelines">GitHub</a> を参照してください。</p>
</blockquote>
<hr>
<p><!-- ![CodePipelineの実行ステージがすべて「成功」になっている画面](images/pipeline-success.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>CDK Pipelines</strong></td>
<td>CDK アプリの CI/CD を定義する高レベル Construct ライブラリ。内部で CodePipeline + CodeBuild + CloudFormation を組み合わせる</td>
</tr>
<tr>
<td><strong>Stage</strong></td>
<td>パイプラインのデプロイ単位。複数スタックをひとまとめにしてパイプラインに追加できる</td>
</tr>
<tr>
<td><strong>セルフミューテーション</strong></td>
<td>パイプライン自身のコード（<code>pipeline_stack.py</code>）を変更して push するだけで、パイプラインが自動的に自分自身を更新する仕組み</td>
</tr>
<tr>
<td><strong>CodeConnections</strong></td>
<td>GitHub などの外部 SCM と AWS を接続するサービス（旧 CodeStar Connections）。ブラウザからの GitHub App 認証が必要</td>
</tr>
<tr>
<td><strong>Synth Step</strong></td>
<td>CodeBuild で <code>cdk synth</code> を実行し Cloud Assembly（CloudFormation テンプレート一式）を生成するパイプラインのステップ</td>
</tr>
<tr>
<td><strong>セルフミューテーション後のデプロイ</strong></td>
<td>Mutate ステージでパイプラインが更新された後、続けて Deploy ステージが実行される</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">cdk-custom-constructs との比較</span></h2>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>cdk-custom-constructs</th>
<th>cdk-pipelines</th>
</tr>
</thead>
<tbody>
<tr>
<td>デプロイ方法</td>
<td><code>cdk deploy</code>（手動）</td>
<td><strong>GitHub push → 自動</strong></td>
</tr>
<tr>
<td>インフラ変更の反映</td>
<td>毎回 <code>cdk deploy</code> を手動実行</td>
<td><strong>push するだけで自動反映</strong></td>
</tr>
<tr>
<td>パイプライン管理</td>
<td>なし</td>
<td><strong>CodePipeline がデプロイを管理</strong></td>
</tr>
<tr>
<td>セルフミューテーション</td>
<td>なし</td>
<td><strong>パイプライン自体もコードで管理・自動更新</strong></td>
</tr>
<tr>
<td>初回デプロイ</td>
<td><code>cdk deploy</code></td>
<td><code>cdk deploy</code>（<strong>以降は push のみ</strong>）</td>
</tr>
<tr>
<td>アプリデプロイ</td>
<td>EC2 起動時（UserData）</td>
<td>EC2 起動時（UserData）※今回は同じ</td>
</tr>
</tbody>
</table>
<blockquote>
<p>インフラの構成は cdk-custom-constructs と完全に同等です。変わるのは<strong>デプロイの仕組み</strong>（手動 → 自動）です。</p>
</blockquote>
<hr>
<h2><span id="toc4">ファイル構成と役割</span></h2>
<pre><code class="language-plaintext">cdk-pipelines/
├── app.py                    ← CDK アプリ エントリポイント（PipelineStack を生成）
├── cdk.json                  ← CDK 設定・Context 変数（GitHub 接続情報を含む）
├── pipeline/
│   └── pipeline_stack.py     ← CodePipeline + Synth + Stage を定義するスタック
├── stages/
│   └── three_tier_stage.py   ← Stage（ThreeTierStack をデプロイ対象としてまとめる）
├── stacks/
│   └── three_tier_stack.py   ← 3層Web構成スタック（cdk-custom-constructs から流用）
└── components/
    └── three_tier_web.py     ← カスタム L3 Construct（cdk-custom-constructs から流用）</code></pre>
<table>
<thead>
<tr>
<th>ファイル</th>
<th>役割</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>pipeline_stack.py</code></td>
<td>パイプライン本体。Source・Synth Step・Stage を定義する</td>
</tr>
<tr>
<td><code>three_tier_stage.py</code></td>
<td>Stage。<code>ThreeTierStack</code> を内包し、デプロイ対象としてパイプラインに渡す</td>
</tr>
<tr>
<td><code>three_tier_stack.py</code></td>
<td>3層Web構成スタック（cdk-custom-constructs と同じ構造）</td>
</tr>
<tr>
<td><code>three_tier_web.py</code></td>
<td>カスタム Construct。cdk-custom-constructs から流用</td>
</tr>
</tbody>
</table>
<p>詳細なコードは <a href="https://github.com/caymezon/aws-handson/tree/main/cdk-pipelines">GitHub</a> を参照してください。</p>
<hr>
<h2><span id="toc5">使用する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>CodePipeline</strong></td>
<td>CI/CD パイプライン管理</td>
<td>月1パイプラインまで無料枠あり</td>
</tr>
<tr>
<td><strong>CodeBuild</strong></td>
<td>cdk synth を実行するビルド環境</td>
<td>月100分まで無料枠あり</td>
</tr>
<tr>
<td><strong>SSM Parameter Store</strong></td>
<td>DBパスワードの安全な保管</td>
<td>スタンダード層は無料</td>
</tr>
<tr>
<td><strong>S3</strong></td>
<td>パイプラインのアーティファクト置き場</td>
<td>無料枠あり</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>各サービスの権限</td>
<td>無料</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>注意</strong>: ALBは無料枠がありません。ハンズオン後は必ずリソースを削除してください。</p>
</blockquote>
<hr>
<h2><span id="toc6">前提条件</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>
<tr>
<td>Python 3.9 以上</td>
<td><code>python --version</code></td>
</tr>
<tr>
<td>Node.js 18 以上</td>
<td><code>node --version</code></td>
</tr>
<tr>
<td>CDK CLI</td>
<td><code>cdk --version</code></td>
</tr>
<tr>
<td>Git</td>
<td><code>git --version</code></td>
</tr>
</tbody>
</table>
<p>AWS 認証確認:</p>
<pre><code class="language-cmd">aws sts get-caller-identity</code></pre>
<p>CDK Bootstrap 確認（<code>CDKToolkit</code> スタックが存在すれば実施済み）:</p>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name CDKToolkit ^
  --query "Stacks[0].StackStatus" ^
  --output text ^
  --region ap-northeast-1</code></pre>
<blockquote>
<p><strong>GitHub アカウントが必要です</strong>。<code>aws-learning-projects</code> リポジトリに push できる状態にしておいてください。</p>
</blockquote>
<hr>
<h2><span id="toc7">作業順序</span></h2>
<pre><code class="language-plaintext">⓪ 自分のIPアドレスを確認する
      ↓
① キーペアを作成する（AWS CLI で実施）
      ↓
② プロジェクトのセットアップ（Python 仮想環境）
      ↓
③ GitHub との接続を作成する（CodeConnections）
      ↓
④ cdk.json を設定する
      ↓
⑤ コードを GitHub にプッシュする
      ↓
⑥ パイプラインスタックをデプロイする（初回のみ手動）
      ↓
⑦ パイプラインの実行状況を確認する
      ↓
⑧ 動作確認（ALBアクセス・SSH・RDS接続）
      ↓
⑨ CI/CD を体験する（インフラ変更を push で自動反映）
      ↓
⑩ リソース削除</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>
<pre><code class="language-cmd">aws ec2 create-key-pair ^
  --key-name my-cdk3-key ^
  --query KeyMaterial ^
  --output text ^
  --region ap-northeast-1 &gt; %USERPROFILE%\.ssh\my-cdk3-key.pem</code></pre>
<blockquote>
<p><code>%USERPROFILE%\.ssh\</code> が存在しない場合は先に <code>mkdir %USERPROFILE%\.ssh</code> を実行してください。</p>
</blockquote>
<hr>
<h2><span id="toc10">② プロジェクトのセットアップ</span></h2>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-pipelines

python -m venv .venv

.venv\Scripts\activate

pip install -r requirements.txt</code></pre>
<p>プロンプトの先頭に <code>(.venv)</code> が表示されれば仮想環境が有効になっています。</p>
<blockquote>
<p><strong>重要</strong>: CDK コマンド（synth / deploy / destroy）はすべてこの仮想環境が有効な状態で実行する必要があります。<br />ターミナルを開き直した際は必ず最初に以下を実行してください。</p>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-pipelines
.venv\Scripts\activate</code></pre>
</blockquote>
<hr>
<h2><span id="toc11">③ GitHub との接続を作成する（CodeConnections）</span></h2>
<p>CodePipeline が GitHub リポジトリを監視するために、<strong>GitHub との接続（CodeConnections）</strong> を作成します。接続の管理はブラウザから行います。</p>
<blockquote>
<p><strong>重要</strong>: AWS コンソールと GitHub の操作は<strong>同じブラウザ</strong>で行ってください。<br />別ブラウザで GitHub を操作すると、AWS にリダイレクトされた際にデフォルトリージョン（バージニア北部等）でログインされる場合があります。</p>
</blockquote>
<h3><span id="toc12">接続を作成する</span></h3>
<ol>
<li>AWS コンソール検索（<code>Alt+S</code>）で <code>CodePipeline</code> と入力 → <strong>CodePipeline</strong> を開く</li>
<li>左サイドバー → <strong>「設定」</strong> → <strong>「接続」</strong></li>
<li>リージョンが <strong>東京（ap-northeast-1）</strong> になっていることを確認する</li>
<li>「<strong>接続を作成</strong>」をクリック</li>
<li>プロバイダー: <strong>GitHub</strong> を選択</li>
<li>接続名: <code>my-github-connection</code>（任意）</li>
<li>「<strong>GitHub に接続する</strong>」をクリック</li>
</ol>
<h3><span id="toc13">GitHub App をインストールする</span></h3>
<p>クリック後、GitHub の OAuth 認証画面が開きます。</p>
<ol start="8">
<li>「<strong>Authorize</strong>」をクリック → AWS コンソールの「GitHub 接続設定」画面に自動で戻る</li>
<li>「<strong>新しいアプリをインストールする</strong>」をクリック → GitHub の「Install & Authorize」画面が開く</li>
<li><strong>「Only select repositories」</strong> を選択 → <code>aws-learning-projects</code> を追加</li>
<li>「<strong>Install & Authorize</strong>」をクリック（メール認証コードが求められる場合は入力）</li>
<li>AWS コンソールに自動でリダイレクトされる → 「<strong>接続</strong>」ボタンをクリック</li>
</ol>
<h3><span id="toc14">接続 ARN を確認する</span></h3>
<p>接続一覧から作成した接続の ARN をコピーします。</p>
<pre><code class="language-plaintext">arn:aws:codeconnections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</code></pre>
<blockquote>
<p><strong>重要</strong>: ステータスが <strong>「利用可能」</strong> になっていることを確認してから次に進んでください。<br />「保留中」のままの場合は接続を選択して「<strong>保留中の接続を更新する</strong>」をクリックします。</p>
</blockquote>
<p><!-- ![CodeConnectionsの接続一覧で「利用可能」になっている画面](images/connections-available.jpg) --></p>
<p><strong>控えておく情報</strong>: 接続 ARN（<code>arn:aws:codeconnections:...</code>）</p>
<hr>
<h2><span id="toc15">④ cdk.json の設定</span></h2>
<p><code>cdk.json</code> の <code>context</code> セクションを自分の環境に合わせて編集します。</p>
<pre><code class="language-json">{
  "context": {
    "employee_id": "my",
    "my_ip": "203.0.113.1/32",
    "db_password": "Handson1234!",
    "key_name": "my-cdk3-key",
    "tomcat_version": "10.1.28",
    "github_owner": "your-github-username",
    "github_repo": "aws-learning-projects",
    "github_branch": "main",
    "connection_arn": "arn:aws:codeconnections:ap-northeast-1:..."
  }
}</code></pre>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>employee_id</code></td>
<td><code>my</code></td>
<td>リソース名のプレフィックス（<code>my-cdk3-xxx</code> という名前になる）</td>
</tr>
<tr>
<td><code>my_ip</code></td>
<td>⓪で確認したIP <code>/32</code></td>
<td>EC2へのSSHを許可するIP</td>
</tr>
<tr>
<td><code>key_name</code></td>
<td><code>my-cdk3-key</code></td>
<td>①で作成したキーペア名</td>
</tr>
<tr>
<td><code>github_owner</code></td>
<td>GitHub ユーザー名</td>
<td>リポジトリのオーナー名（または Org 名）</td>
</tr>
<tr>
<td><code>github_repo</code></td>
<td><code>aws-learning-projects</code></td>
<td>リポジトリ名</td>
</tr>
<tr>
<td><code>github_branch</code></td>
<td><code>main</code></td>
<td>監視するブランチ名</td>
</tr>
<tr>
<td><code>connection_arn</code></td>
<td>③で確認した ARN</td>
<td>CodeConnections の接続 ARN</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>cdk-custom-constructs（前回）と同時にデプロイしてもリソース名が競合しません</strong>。前回は <code>my-cdk2-xxx</code>、今回は <code>my-cdk3-xxx</code> というプレフィックスになります。</p>
</blockquote>
<hr>
<h2><span id="toc16">⑤ コードを GitHub にプッシュする</span></h2>
<p>パイプラインはリポジトリのコードを監視します。まず現在の変更（<code>cdk.json</code> の更新）を push しておきます。</p>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects
git add cdk-pipelines/cdk.json
git commit -m "chore: cdk-pipelines の cdk.json を設定"
git push origin main</code></pre>
<hr>
<h2><span id="toc17">⑥ パイプラインスタックのデプロイ（初回のみ）</span></h2>
<p>CDK Pipelines では<strong>パイプライン自体を最初に1回だけ手動でデプロイ</strong>します。以降はパイプラインが自動的に動作します。</p>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-pipelines

.venv\Scripts\activate

cdk deploy</code></pre>
<p>「Do you wish to deploy these changes?」に <code>y</code> を入力します。</p>
<blockquote>
<p><strong>所要時間</strong>: パイプラインスタック自体のデプロイは 3〜5 分</p>
</blockquote>
<p>デプロイ完了後、CodePipeline が自動起動します:</p>
<table>
<thead>
<tr>
<th>ステージ</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Source</strong></td>
<td>GitHub から最新コードを取得</td>
</tr>
<tr>
<td><strong>Build</strong></td>
<td>CodeBuild で <code>cdk synth</code> を実行→ Cloud Assembly を生成</td>
</tr>
<tr>
<td><strong>Mutate</strong></td>
<td>パイプライン自身を最新定義に更新（セルフミューテーション）</td>
</tr>
<tr>
<td><strong>Deploy</strong></td>
<td>CloudFormation で ThreeTierStack（ALB + EC2 + RDS）をデプロイ</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>所要時間</strong>: RDS の作成に 15〜20 分かかります。</p>
</blockquote>
<hr>
<h2><span id="toc18">⑦ パイプラインの実行状況を確認する</span></h2>
<ol>
<li>AWS コンソール → <strong>CodePipeline</strong> を開く</li>
<li><code>my-cdk3-pipeline</code> を選択</li>
<li>各ステージが <strong>「成功」</strong> になるまで待つ</li>
</ol>
<blockquote>
<p><strong>実行履歴に「失敗」が表示されている場合</strong>:<br />パイプライン作成直後（GitHub App インストール前）に自動実行された結果が残っている場合があります。<br />確認すべき実行は「<strong>Webhook</strong>」トリガーの最新のもののみです。</p>
</blockquote>
<h3><span id="toc19">CloudFormation スタックの命名規則</span></h3>
<p>CDK Pipelines でステージをデプロイすると、CloudFormation スタック名は以下の形式になります:</p>
<pre><code class="language-plaintext">{StageName}-{StackName}</code></pre>
<table>
<thead>
<tr>
<th>要素</th>
<th>このハンズオンでの値</th>
</tr>
</thead>
<tbody>
<tr>
<td>StageName</td>
<td><code>Deploy</code>（<code>pipeline_stack.py</code> でステージを追加した際の名前）</td>
</tr>
<tr>
<td>StackName</td>
<td><code>ThreeTierStack</code>（<code>three_tier_stack.py</code> のクラス名）</td>
</tr>
<tr>
<td>結果</td>
<td><strong><code>Deploy-ThreeTierStack</code></strong></td>
</tr>
</tbody>
</table>
<blockquote>
<p><code>CdkPipelinesStack</code>（パイプライン）と <code>Deploy-ThreeTierStack</code>（インフラ）の <strong>2つが別スタック</strong>として CloudFormation に表示されます。これは想定通りです。</p>
</blockquote>
<h3><span id="toc20">CloudFormation Outputs の確認</span></h3>
<p>Deploy ステージが完了したら、インフラスタックの Outputs を確認します。</p>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name Deploy-ThreeTierStack ^
  --region ap-northeast-1 ^
  --query "Stacks[0].Outputs"</code></pre>
<p><strong>控えておく情報</strong>: <code>ALBEndpoint</code>、<code>EC2PublicIP</code>、<code>RDSEndpoint</code></p>
<p><!-- ![CodePipelineのステージがすべて成功している画面](images/pipeline-success.jpg) --></p>
<hr>
<h2><span id="toc21">⑧ 動作確認</span></h2>
<h3><span id="toc22">8-1. ALB 経由でWebアクセス確認</span></h3>
<p>Outputs の <code>ALBEndpoint</code> をブラウザで開きます。</p>
<blockquote>
<p><strong>EC2 が作成されてから Tomcat が起動するまで 10〜15 分かかります</strong>（UserData で Java・Tomcat のインストールが実行されるため）。Deploy ステージ完了直後は 502 Bad Gateway が表示されることが多いです。しばらく待ってリトライしてください。</p>
</blockquote>
<p>以下が表示されれば正常です:</p>
<pre><code class="language-plaintext">AP Server - my-cdk3 3-Tier Web
Deployed via AWS CDK Pipelines (auto-deployed on git push).</code></pre>
<p><!-- ![ALB経由でTomcat画面が表示されている様子](images/alb-healthy-access.jpg) --></p>
<h3><span id="toc23">8-2. EC2 に SSH 接続する</span></h3>
<p>Outputs の <code>SSHCommand</code> を実行します。</p>
<pre><code class="language-cmd">ssh -i %USERPROFILE%\.ssh\my-cdk3-key.pem ec2-user@（EC2PublicIP）</code></pre>
<h3><span id="toc24">8-3. EC2 から RDS への接続確認</span></h3>
<p>EC2 に SSH 接続後（以下は EC2 上での操作）:</p>
<pre><code class="language-bash">sudo dnf install -y mariadb105

DB_PASSWORD=$(aws ssm get-parameter \
  --name /my/cdk3/db-password \
  --query Parameter.Value \
  --output text \
  --region ap-northeast-1)

mysql -h &lt;RDSEndpoint&gt; -u admin -p${DB_PASSWORD} sampledb

mysql&gt; SHOW DATABASES;
mysql&gt; exit</code></pre>
<h3><span id="toc25">8-4. SSH 接続を切断する</span></h3>
<pre><code class="language-bash">exit</code></pre>
<hr>
<h2><span id="toc26">⑨ CI/CD を体験する（インフラ変更を push で自動反映）</span></h2>
<p>CDK Pipelines の醍醐味は「<strong>インフラのコードを push するだけで CloudFormation への変更が自動反映される</strong>」ことです。</p>
<blockquote>
<p><strong>注意</strong>: このハンズオンで自動デプロイできるのは<strong>インフラ（CloudFormation リソース）のみ</strong>です。<br />HTML や WAR などのアプリファイルは対象外です（次のハンズオン <code>cdk-webapp-pipeline</code> で体験します）。</p>
</blockquote>
<h3><span id="toc27">EC2 にタグを追加して CI/CD を確認する</span></h3>
<p>EC2 タグの追加は EC2 の置き換えなし（in-place 更新）で行われるため、Tomcat が止まらず 2〜3 分でパイプラインが完了します。EC2 コンソールのタグタブで変更を目視確認できます。</p>
<p><code>stacks/three_tier_stack.py</code> を開き、以下を追加します:</p>
<pre><code class="language-python">from aws_cdk import Tags

Tags.of(web.instance).add("DeployedBy", "CDK Pipelines v2")</code></pre>
<h3><span id="toc28">push する</span></h3>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects
git add cdk-pipelines/stacks/three_tier_stack.py
git commit -m "test: EC2 タグ追加で CDK Pipelines CI/CD を確認"
git push origin main</code></pre>
<h3><span id="toc29">パイプラインの自動起動を確認する</span></h3>
<ol>
<li>AWS コンソール → <strong>CodePipeline</strong> → <code>my-cdk3-pipeline</code></li>
<li>push 後、数十秒以内にパイプラインが<strong>自動起動</strong>することを確認</li>
<li>Deploy ステージが完了するまで待つ（2〜3 分）</li>
</ol>
<h3><span id="toc30">タグが反映されたことを確認する</span></h3>
<p><strong>EC2 コンソール</strong> → インスタンス → <code>my-cdk3-ap-instance</code> → <strong>「タグ」タブ</strong></p>
<p><code>DeployedBy = CDK Pipelines v2</code> が追加されていれば、インフラの CI/CD が正常に動作しています。</p>
<p><!-- ![EC2タグに「DeployedBy = CDK Pipelines v2」が追加されている画面](images/ec2-tag-cicd.jpg) --></p>
<hr>
<h2><span id="toc31">⑩ リソース削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除します。</strong></p>
<blockquote>
<p><strong>削除順序が重要です</strong>。パイプラインによってデプロイされたスタック（<code>Deploy-ThreeTierStack</code>）を<strong>先に</strong>削除してから、パイプラインスタック（<code>CdkPipelinesStack</code>）を削除します。</p>
</blockquote>
<h3><span id="toc32">1. パイプラインで作成されたスタックを削除する</span></h3>
<pre><code class="language-cmd">aws cloudformation delete-stack ^
  --stack-name Deploy-ThreeTierStack ^
  --region ap-northeast-1</code></pre>
<p>削除完了（RDS の削除に 10〜15 分かかります）を確認:</p>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name Deploy-ThreeTierStack ^
  --region ap-northeast-1</code></pre>
<p>「does not exist」エラーが出れば削除完了です。</p>
<h3><span id="toc33">2. パイプラインスタック自体を削除する</span></h3>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-pipelines

.venv\Scripts\activate

cdk destroy</code></pre>
<p>「Are you sure you want to delete?」に <code>y</code> を入力します。</p>
<blockquote>
<p><code>--app is required</code> エラーが出る場合は <code>cdk-pipelines</code> ディレクトリで実行していません。<br />必ず <code>cd C:\my-aws\aws-learning-projects\cdk-pipelines</code> を先に実行してください。</p>
</blockquote>
<h3><span id="toc34">3. アーティファクト S3 バケットを削除する（必要な場合）</span></h3>
<p>CDK Pipelines が自動生成するアーティファクトバケットは手動削除が必要な場合があります。</p>
<pre><code class="language-cmd">aws s3 ls | findstr pipelineartifacts</code></pre>
<p>バケットが残っている場合:</p>
<pre><code class="language-cmd">aws s3 rb s3://&lt;バケット名&gt; --force</code></pre>
<h3><span id="toc35">4. 仮想環境の終了</span></h3>
<pre><code class="language-cmd">deactivate</code></pre>
<h3><span id="toc36">5. キーペアの削除（手動）</span></h3>
<pre><code class="language-cmd">aws ec2 delete-key-pair ^
  --key-name my-cdk3-key ^
  --region ap-northeast-1

del %USERPROFILE%\.ssh\my-cdk3-key.pem</code></pre>
<h3><span id="toc37">6. GitHub との接続を削除する（手動）</span></h3>
<p><strong>CodePipeline → 設定 → 接続 → <code>my-github-connection</code> → 「削除」</strong></p>
<h3><span id="toc38">削除されるリソース一覧</span></h3>
<table>
<thead>
<tr>
<th>リソース</th>
<th>削除方法</th>
</tr>
</thead>
<tbody>
<tr>
<td>ALB・EC2・RDS・VPC・SG・SSM</td>
<td><code>delete-stack Deploy-ThreeTierStack</code> で削除</td>
</tr>
<tr>
<td>CodePipeline</td>
<td><code>cdk destroy</code> で削除</td>
</tr>
<tr>
<td>CodeBuild プロジェクト</td>
<td><code>cdk destroy</code> で削除</td>
</tr>
<tr>
<td>アーティファクト S3 バケット</td>
<td>手動削除が必要な場合あり</td>
</tr>
<tr>
<td>IAM ロール（パイプライン用）</td>
<td><code>cdk destroy</code> で削除</td>
</tr>
<tr>
<td>GitHub との接続（CodeConnections）</td>
<td>CodePipeline コンソールから手動削除</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc39">CDK Pipelines のポイント解説</span></h2>
<h3><span id="toc40">なぜ cdk deploy は初回だけ必要なのか</span></h3>
<p>パイプラインが存在しない状態では GitHub push を検知できません。初回の <code>cdk deploy</code> でパイプライン自体を作成する必要があります。以降はパイプラインが自分自身を更新（<strong>セルフミューテーション</strong>）するため、再度 <code>cdk deploy</code> を手動実行する必要はありません。</p>
<h3><span id="toc41">Stage クラスの役割</span></h3>
<pre><code class="language-python"># stages/three_tier_stage.py
class ThreeTierStage(cdk.Stage):
    def __init__(self, ...):
        super().__init__(...)
        ThreeTierStack(self, "ThreeTierStack")  # ← Stage に含めるスタック</code></pre>
<p>Stage に複数スタックを含めると、パイプラインが順序制御してデプロイします:</p>
<pre><code class="language-python">class MultiStackStage(cdk.Stage):
    def __init__(self, ...):
        super().__init__(...)
        NetworkStack(self, "NetworkStack")  # ← 先にデプロイ
        AppStack(self, "AppStack")          # ← Network の後にデプロイ</code></pre>
<h3><span id="toc42">モノレポでの primary_output_directory</span></h3>
<p>このリポジトリは複数ハンズオンが共存するモノレポ構成のため、<code>cdk synth</code> をサブディレクトリで実行する設定が必要です:</p>
<pre><code class="language-python">CodeBuildStep(
    "Synth",
    commands=[
        "cd cdk-pipelines",        # ← サブディレクトリに移動
        "pip install -r requirements.txt",
        "npx cdk synth",
    ],
    primary_output_directory="cdk-pipelines/cdk.out",  # ← cdk.out の場所を指定
)</code></pre>
<hr>
<h2><span id="toc43">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>connection_arn</code> が見つからないエラー</td>
<td>cdk.json に ARN を設定していない</td>
<td>③で確認した接続 ARN を cdk.json に設定</td>
</tr>
<tr>
<td>Source ステージが「失敗」</td>
<td>GitHub との接続が「保留中」のまま</td>
<td>CodePipeline → 設定 → 接続 → 承認して「利用可能」にする</td>
</tr>
<tr>
<td>Build ステージが失敗</td>
<td><code>github_owner</code>・<code>github_repo</code> が不正</td>
<td>cdk.json の値を確認</td>
</tr>
<tr>
<td>Deploy ステージが失敗</td>
<td>Bootstrap 未実施</td>
<td><code>cdk bootstrap</code> を実行してから再 push</td>
</tr>
<tr>
<td>ALB にアクセスすると 502</td>
<td>UserData でのインストール実行中</td>
<td>10〜15 分待ってリトライ。EC2 に SSH して <code>sudo tail -f /var/log/user-data.log</code> で進捗確認</td>
</tr>
<tr>
<td>パイプラインが自動起動しない</td>
<td>接続が「保留中」または branch 名が違う</td>
<td>接続を承認 / <code>github_branch</code> を確認</td>
</tr>
<tr>
<td><code>cdk destroy</code> で <code>--app is required</code></td>
<td>cdk-pipelines ディレクトリ以外で実行</td>
<td><code>cd C:\my-aws\aws-learning-projects\cdk-pipelines</code> を先に実行</td>
</tr>
</tbody>
</table>
<p>パイプライン失敗時のログ確認（CodeBuild）:</p>
<ol>
<li>AWS コンソール → CodePipeline → <code>my-cdk3-pipeline</code></li>
<li>失敗したステージの「詳細」→「ログを表示」をクリック</li>
<li>CloudWatch Logs でエラーを確認</li>
</ol>
<hr>
<h2><span id="toc44">まとめ</span></h2>
<table>
<thead>
<tr>
<th>ステップ</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>①②</td>
<td>キーペア作成 + Python 仮想環境のセットアップ</td>
</tr>
<tr>
<td>③</td>
<td>CodeConnections で GitHub との接続を作成・承認（「利用可能」を確認）</td>
</tr>
<tr>
<td>④</td>
<td><code>cdk.json</code> に <code>github_owner</code>・<code>github_repo</code>・<code>connection_arn</code> を設定</td>
</tr>
<tr>
<td>⑤</td>
<td>変更を GitHub に push してリポジトリに反映</td>
</tr>
<tr>
<td>⑥</td>
<td><code>cdk deploy</code>（<strong>初回のみ手動</strong>）でパイプラインスタックをデプロイ</td>
</tr>
<tr>
<td>⑦</td>
<td>CodePipeline が自動起動 → Synth → Mutate → Deploy（RDS 待ち 15〜20 分）</td>
</tr>
<tr>
<td>⑧</td>
<td>ALB DNS 名でアクセス → EC2 → RDS への接続テスト</td>
</tr>
<tr>
<td>⑨</td>
<td>EC2 タグ追加を push → パイプライン自動起動 → タグ反映を確認（CI/CD 体験）</td>
</tr>
<tr>
<td>⑩</td>
<td><code>delete-stack Deploy-ThreeTierStack</code> → <code>cdk destroy</code> の順で削除</td>
</tr>
</tbody>
</table>
<p>CDK Pipelines の最大のメリットは「<strong>インフラのコードが唯一の変更手段になる</strong>」点です。誰かが AWS コンソールで手動変更しても、次の push でコードの状態に戻されます。これにより環境の一貫性を保てます。</p>
<p>今回はインフラの CI/CD のみを体験しました。アプリ（Java WAR ファイル）の自動デプロイを体験したい場合は、次のハンズオン <code>cdk-webapp-pipeline</code>（CodeDeploy を使用）で体験できます。</p>
<p>コンソールで3層構成を視覚的に学びたい場合は <a href="https://caymezon.com/aws-handson-console-alb-ec2-rds/">AWSコンソール版ハンズオン</a>、CDK の基本は <a href="https://caymezon.com/aws-handson-cdk-alb-ec2-rds/">CDK版ハンズオン（cdk-alb-ec2-rds）</a>、カスタム Construct は <a href="https://caymezon.com/aws-handson-cdk-custom-constructs/">CDK カスタム Construct ハンズオン</a> を参照してください。</p><p>The post <a href="https://caymezon.com/aws-handson-cdk-pipelines/">CDK Pipelines でインフラの CI/CD を構築する【git push だけで ALB + EC2 + RDS が自動デプロイ】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-cdk-pipelines/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CloudFormationでSpring Boot WebアプリをALB + EC2(Tomcat) + RDS に自動デプロイする手順【S3 + UserData / WAR自動配布】</title>
		<link>https://caymezon.com/aws-handson-cloudformation-alb-ec2-rds-webapp/</link>
					<comments>https://caymezon.com/aws-handson-cloudformation-alb-ec2-rds-webapp/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sat, 18 Apr 2026 04:45:25 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[ALB]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[CloudFormation]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[IaC]]></category>
		<category><![CDATA[JDBC]]></category>
		<category><![CDATA[Maven]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Parameter Store]]></category>
		<category><![CDATA[RDS]]></category>
		<category><![CDATA[S3]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[SSM]]></category>
		<category><![CDATA[Tomcat]]></category>
		<category><![CDATA[UserData]]></category>
		<category><![CDATA[VPC]]></category>
		<category><![CDATA[WAR]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[自動デプロイ]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20363</guid>

					<description><![CDATA[<p>目次 はじめにCloudFormation vs コンソール：どれだけ違うかキーワード解説前提条件構築されるリソース（約30個）作業順序⓪ Webアプリのビルド⓪-2 自分のIPアドレスを確認する① キーペアの作成（コン [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-cloudformation-alb-ec2-rds-webapp/">CloudFormationでSpring Boot WebアプリをALB + EC2(Tomcat) + RDS に自動デプロイする手順【S3 + UserData / WAR自動配布】</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-8" checked><label class="toc-title" for="toc-checkbox-8">目次</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">構築されるリソース（約30個）</a></li><li><a href="#toc6" tabindex="0">作業順序</a></li><li><a href="#toc7" tabindex="0">⓪ Webアプリのビルド</a></li><li><a href="#toc8" tabindex="0">⓪-2 自分のIPアドレスを確認する</a></li><li><a href="#toc9" tabindex="0">① キーペアの作成（コンソールで実施）</a></li><li><a href="#toc10" tabindex="0">② S3バケットの作成とWARのアップロード</a><ol><li><a href="#toc11" tabindex="0">プロジェクトフォルダに移動する</a></li><li><a href="#toc12" tabindex="0">S3バケットを作成する</a></li><li><a href="#toc13" tabindex="0">WARをS3にアップロードする</a></li></ol></li><li><a href="#toc14" tabindex="0">③ スタックの作成</a></li><li><a href="#toc15" tabindex="0">④ 作成完了・Outputsの確認</a><ol><li><a href="#toc16" tabindex="0">作成状況の確認</a></li><li><a href="#toc17" tabindex="0">Outputs（接続情報）の確認</a></li></ol></li><li><a href="#toc18" tabindex="0">⑤ 動作確認</a><ol><li><a href="#toc19" tabindex="0">ALBのヘルスチェック確認</a></li><li><a href="#toc20" tabindex="0">ALB経由でWebアプリにアクセスする</a></li><li><a href="#toc21" tabindex="0">アイテムの追加・削除を試す</a></li><li><a href="#toc22" tabindex="0">（任意）ログでデプロイ過程を確認する</a></li></ol></li><li><a href="#toc23" tabindex="0">⑥ スタックの削除</a><ol><li><a href="#toc24" tabindex="0">スタックを削除する</a></li><li><a href="#toc25" tabindex="0">削除状況の確認</a></li><li><a href="#toc26" tabindex="0">S3バケットを削除する</a></li><li><a href="#toc27" tabindex="0">キーペアを削除する（任意）</a></li></ol></li><li><a href="#toc28" tabindex="0">コンソール版との比較</a></li><li><a href="#toc29" tabindex="0">トラブルシューティング</a><ol><li><a href="#toc30" tabindex="0">失敗時の詳細確認コマンド</a></li></ol></li><li><a href="#toc31" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>前回の<a href="https://caymezon.com/aws-handson-console-alb-ec2-rds-webapp/">AWSコンソール版ハンズオン（Spring Boot Webアプリ）</a>では、コンソールでインフラを手動構築してSCPでWARをデプロイしました。</p>
<p>この記事では、同じ構成を <strong>CloudFormation</strong> で自動化します。<code>template.yaml</code> 1ファイルにVPC・SG・IAM・SSM・RDS・ALB・EC2（約30リソース）を定義し、さらに <strong>EC2のUserDataがS3からWARを自動取得してTomcatにデプロイ</strong>するため、コマンド数本でWebアプリが動く状態まで一気に構築できます。</p>
<pre><code class="language-plaintext">ローカル環境（VSCode）
  ├── app/target/webapp.war（mvn packageでビルド済み）
  ├── template.yaml（約30リソースを定義）
  └── AWS CLI コマンド
        ↓ スタック作成（コマンド1本）
AWS環境
  ├── S3バケット（webapp.war置き場）
  └── VPC（10.0.0.0/16）
        ├── パブリックサブネット1・2（ALB + EC2）
        ├── プライベートサブネット1・2（RDS）
        ├── IGW + ルートテーブル
        ├── IAMロール（SSM + S3読み取り権限）
        ├── ALB SG → EC2 SG → RDS SG（SG-to-SG制御）
        ├── SSM Parameter Store（/my/webapp/db-password）
        ├── RDS MySQL 8.0（db.t3.micro / sampledb）
        ├── ALB（HTTP:80）→ TG（HTTP:8080）
        └── EC2（t2.micro）
              UserDataが自動実行:
              1. Java + Tomcat インストール
              2. SSMからDBパスワード取得 → setenv.sh作成
              3. S3からwebapp.warをダウンロード → ROOT.warとして配置
              4. Tomcat起動（Spring Bootアプリが自動展開）</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li>WARのデプロイをS3 + UserDataで完全自動化する設計</li>
<li>SSMからDB接続情報を取得してsetenv.shを自動作成する仕組み</li>
<li><code>delete-stack</code> 1本でALB・RDS・IAMなど全リソースを自動削除</li>
</ul>
<p><strong>テンプレートとアプリのソースコードはGitHubで公開しています：</strong></p>
<blockquote>

<a rel="noopener" href="https://github.com/caymezon/aws-handson/tree/main/alb-ec2-rds-webapp" title="aws-handson/alb-ec2-rds-webapp at main · caymezon/aws-handson" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img decoding="async" src="https://s.wordpress.com/mshots/v1/https%3A%2F%2Fgithub.com%2Fcaymezon%2Faws-handson%2Ftree%2Fmain%2Falb-ec2-rds-webapp?w=160&h=90" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="160" height="90" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">aws-handson/alb-ec2-rds-webapp at main · caymezon/aws-handson</div><div class="blogcard-snippet external-blogcard-snippet">AWS HANDSON. Contribute to caymezon/aws-handson development by creating an account on GitHub.</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://github.com/caymezon/aws-handson/tree/main/alb-ec2-rds-webapp" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">github.com</div></div></div></div></a>
</blockquote>
<hr>
<blockquote>
<p><strong>この記事は <a href="https://caymezon.com/aws-handson-console-alb-ec2-rds-webapp/">AWSコンソール版ハンズオン</a> の比較記事です。</strong><br />コンソール版でSCPデプロイの仕組みを理解した後に読むと理解が深まります。</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>WARのデプロイ</strong></td>
<td>S3 + UserDataで<strong>自動</strong></td>
<td>SCPで転送 + SSH操作</td>
</tr>
<tr>
<td><strong>DB接続設定（setenv.sh）</strong></td>
<td>UserDataがSSMから<strong>自動</strong>取得・作成</td>
<td>SSH接続して手動作成</td>
</tr>
<tr>
<td><strong>全体のデプロイ</strong></td>
<td>コマンド数本（RDS待ち15〜20分）</td>
<td><strong>約60〜90分</strong></td>
</tr>
<tr>
<td><strong>削除</strong></td>
<td><code>delete-stack</code> 1本</td>
<td><strong>16ステップ手動</strong></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が管理するリソースのまとまり。今回は約30リソースを1スタックで管理</td>
</tr>
<tr>
<td><strong>S3 VPC Gateway Endpoint</strong></td>
<td>EC2からS3にインターネットを経由せずアクセスするための無料エンドポイント</td>
</tr>
<tr>
<td><strong>UserData</strong></td>
<td>EC2初回起動時に自動実行されるシェルスクリプト</td>
</tr>
<tr>
<td><strong>CAPABILITY_NAMED_IAM</strong></td>
<td>名前付きIAMリソースを含むスタック作成に必要なフラグ</td>
</tr>
<tr>
<td><strong>DeletionPolicy: Delete</strong></td>
<td>スタック削除時にRDSも確実に削除する設定</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">前提条件</span></h2>
<pre><code class="language-cmd">aws sts get-caller-identity
aws --version
java -version
mvn -version</code></pre>
<hr>
<h2><span id="toc5">構築されるリソース（約30個）</span></h2>
<p><code>template.yaml</code> の詳細はGitHubを参照してください：</p>
<blockquote>

<a rel="noopener" href="https://github.com/caymezon/aws-handson/tree/main/alb-ec2-rds-webapp/template.yaml" title="aws-handson/alb-ec2-rds-webapp/template.yaml at main ?? caymezon/aws-handson" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img decoding="async" src="https://caymezon.com/wp-content/uploads/cocoon-resources/blog-card-cache/5980334f3509003dcb5664ba60ee6db4.jpg" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="160" height="90" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">aws-handson/alb-ec2-rds-webapp/template.yaml at main ?? caymezon/aws-handson</div><div class="blogcard-snippet external-blogcard-snippet">AWS HANDSON. Contribute to caymezon/aws-handson development by creating an account on GitHub.</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://github.com/caymezon/aws-handson/blob/main/alb-ec2-rds-webapp/template.yaml" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">github.com</div></div></div></div></a>
</blockquote>
<table>
<thead>
<tr>
<th>カテゴリ</th>
<th>リソース</th>
</tr>
</thead>
<tbody>
<tr>
<td>ネットワーク</td>
<td>VPC / IGW / パブリックサブネット×2 / プライベートサブネット×2 / ルートテーブル×2 / S3 VPC Endpoint</td>
</tr>
<tr>
<td>セキュリティ</td>
<td>ALB SG / EC2 SG / RDS SG</td>
</tr>
<tr>
<td>IAM</td>
<td>EC2ロール（SSM + S3読み取り権限）+ インスタンスプロファイル</td>
</tr>
<tr>
<td>パラメータ</td>
<td>SSM Parameter Store（<code>/my/webapp/db-password</code>）</td>
</tr>
<tr>
<td>データベース</td>
<td>RDS DBサブネットグループ / RDS MySQL 8.0</td>
</tr>
<tr>
<td>ロードバランサー</td>
<td>ターゲットグループ / ALB本体 / リスナー</td>
</tr>
<tr>
<td>コンピュート</td>
<td>EC2インスタンス（Tomcat + WAR自動デプロイ）</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc6">作業順序</span></h2>
<pre><code class="language-plaintext">⓪ Webアプリをビルドする（mvn package）
      ↓
⓪-2 自分のIPアドレスを確認する
      ↓
① キーペアを作成する（コンソールで実施）
      ↓
② S3バケットを作成してWARをアップロードする
      ↓
③ スタックを作成する（aws cloudformation create-stack）
      ↓
④ 作成完了・Outputsを確認する（RDS待ち15〜20分）
      ↓
⑤ 動作確認（ALBアクセス・アイテム追加削除）
      ↓
⑥ スタックを削除する（S3バケットも忘れず削除）</code></pre>
<hr>
<h2><span id="toc7">⓪ Webアプリのビルド</span></h2>
<p>アプリのソースコードはGitHubで公開しています：</p>
<blockquote>

<a rel="noopener" href="https://github.com/caymezon/aws-handson/tree/main/alb-ec2-rds-webapp/app" title="aws-handson/alb-ec2-rds-webapp/app at main ?? caymezon/aws-handson" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img decoding="async" src="https://s.wordpress.com/mshots/v1/https%3A%2F%2Fgithub.com%2Fcaymezon%2Faws-handson%2Ftree%2Fmain%2Falb-ec2-rds-webapp%2Fapp?w=160&h=90" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="160" height="90" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">aws-handson/alb-ec2-rds-webapp/app at main ?? caymezon/aws-handson</div><div class="blogcard-snippet external-blogcard-snippet">AWS HANDSON. Contribute to caymezon/aws-handson development by creating an account on GitHub.</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://github.com/caymezon/aws-handson/tree/main/alb-ec2-rds-webapp/app" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">github.com</div></div></div></div></a>
</blockquote>
<pre><code class="language-cmd">cd C:\（プロジェクトフォルダ）\alb-ec2-rds-webapp\app
mvn package -DskipTests
dir target\webapp.war</code></pre>
<p><code>webapp.war</code>（約20〜30MB）が生成されていれば成功です。</p>
<hr>
<h2><span id="toc8">⓪-2 自分の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-webapp-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-webapp-key.pem</code> を保存します。</p>
<pre><code class="language-plaintext">C:\Users\ユーザー名\.ssh\my-webapp-key.pem</code></pre>
<hr>
<h2><span id="toc10">② S3バケットの作成とWARのアップロード</span></h2>
<p>EC2のUserDataがS3から <code>webapp.war</code> をダウンロードするため、<strong>スタック作成より前に</strong>アップロードしておく必要があります。</p>
<h3><span id="toc11">プロジェクトフォルダに移動する</span></h3>
<pre><code class="language-cmd">cd C:\（プロジェクトフォルダ）\alb-ec2-rds-webapp</code></pre>
<h3><span id="toc12">S3バケットを作成する</span></h3>
<p>バケット名はグローバルで一意である必要があります。末尾に任意の識別子を加えてユニークにしてください。</p>
<pre><code class="language-cmd">aws s3 mb s3://my-webapp-bucket-（任意の識別子） --region ap-northeast-1</code></pre>
<h3><span id="toc13">WARをS3にアップロードする</span></h3>
<pre><code class="language-cmd">aws s3 cp app\target\webapp.war s3://my-webapp-bucket-（任意の識別子）/webapp.war</code></pre>
<p>アップロードを確認します。</p>
<pre><code class="language-cmd">aws s3 ls s3://my-webapp-bucket-（任意の識別子）/</code></pre>
<pre><code class="language-plaintext">2026-04-18 10:00:00   26214400 webapp.war</code></pre>
<hr>
<h2><span id="toc14">③ スタックの作成</span></h2>
<p>以下のコマンドを実行します。各パラメータを自分の値に置き換えます。</p>
<pre><code class="language-cmd">aws cloudformation create-stack ^
  --stack-name my-webapp-stack ^
  --template-body file://template.yaml ^
  --region ap-northeast-1 ^
  --capabilities CAPABILITY_NAMED_IAM ^
  --parameters ^
    ParameterKey=KeyName,ParameterValue=my-webapp-key ^
    ParameterKey=MyIP,ParameterValue=（⓪-2で確認したIP）/32 ^
    ParameterKey=DBPassword,ParameterValue=（任意のパスワード） ^
    ParameterKey=WARBucketName,ParameterValue=my-webapp-bucket-（任意の識別子）</code></pre>
<blockquote>
<p><strong><code>CAPABILITY_NAMED_IAM</code> について</strong>: 名前を指定したIAMリソース（EC2ロールなど）を作成する場合に必要なフラグです。</p>
<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>
<p>成功すると以下のような StackId が表示されます。</p>
<pre><code class="language-json">{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/my-webapp-stack/xxxxx"
}</code></pre>
<hr>
<h2><span id="toc15">④ 作成完了・Outputsの確認</span></h2>
<blockquote>
<p><strong>注意</strong>: RDSの作成には<strong>約15〜20分</strong>かかります。EC2のUserDataでWARのデプロイも行うため、さらに数分かかります。</p>
</blockquote>
<h3><span id="toc16">作成状況の確認</span></h3>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name my-webapp-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>ROLLBACK_COMPLETE</code></td>
<td>失敗してロールバック完了（トラブルシューティングを参照）</td>
</tr>
</tbody>
</table>
<h3><span id="toc17">Outputs（接続情報）の確認</span></h3>
<p><code>CREATE_COMPLETE</code> になったら以下を実行します。</p>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name my-webapp-stack ^
  --query "Stacks[0].Outputs" ^
  --output table</code></pre>
<pre><code class="language-plaintext">+--------------------+-------------------------------------------------------------------+
|  OutputKey         |  OutputValue                                                      |
+--------------------+-------------------------------------------------------------------+
|  ALBEndpoint       |  http://my-webapp-alb-1234567890.ap-northeast-1.elb.amazonaws.com |
|  EC2PublicIP       |  x.x.x.x                                                         |
|  RDSEndpoint       |  my-webapp-rds-mysql.xxxxx.ap-northeast-1.rds.amazonaws.com      |
|  DBPasswordParamName |  /my/webapp/db-password                                         |
|  SSHCommand        |  ssh -i ~/.ssh/my-webapp-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="toc18">⑤ 動作確認</span></h2>
<h3><span id="toc19">ALBのヘルスチェック確認</span></h3>
<p><strong>EC2 → ターゲットグループ → <code>my-webapp-tg</code> → 「ターゲット」タブ</strong></p>
<p>EC2のステータスが <strong>「healthy」</strong> になるまで待ちます（EC2起動後5〜10分）。</p>
<blockquote>
<p>Tomcatの起動 + WARのデプロイはEC2「実行中」からさらに数分かかります。<code>initial</code> や <code>unhealthy</code> が続く場合はしばらく待ちます。</p>
</blockquote>
<h3><span id="toc20">ALB経由でWebアプリにアクセスする</span></h3>
<p>Outputsに表示された <code>ALBEndpoint</code> をブラウザで開きます。</p>
<pre><code class="language-plaintext">http://（ALBEndpointのDNS名）</code></pre>
<pre><code class="language-plaintext">Spring Boot + RDS Item Manager
ALB → EC2(Tomcat) → RDS MySQL の3層構成で動作しています。</code></pre>
<p>が表示されれば成功です。</p>
<h3><span id="toc21">アイテムの追加・削除を試す</span></h3>
<ol>
<li>テキストボックスにアイテム名を入力して「追加」をクリック</li>
<li>アイテムが一覧に表示されることを確認</li>
<li>「削除」ボタンでアイテムが削除されることを確認</li>
</ol>
<p>ブラウザをリロードしてもデータが保持されていれば、RDSへの永続化が成功しています。</p>
<h3><span id="toc22">（任意）ログでデプロイ過程を確認する</span></h3>
<p>OutputsのSSHCommandでEC2に接続して確認します。</p>
<pre><code class="language-bash">sudo cat /var/log/user-data.log

# Tomcatのログ（Spring Bootのスタートアップログ）
sudo tail -50 /opt/tomcat/logs/catalina.out

# setenv.shの内容確認（DB接続情報が正しく設定されているか）
sudo cat /opt/tomcat/bin/setenv.sh

exit</code></pre>
<hr>
<h2><span id="toc23">⑥ スタックの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除します。</strong></p>
<h3><span id="toc24">スタックを削除する</span></h3>
<pre><code class="language-cmd">aws cloudformation delete-stack ^
  --stack-name my-webapp-stack ^
  --region ap-northeast-1</code></pre>
<blockquote>
<p><strong>注意</strong>: RDS削除には<strong>約10〜15分</strong>かかります。</p>
</blockquote>
<h3><span id="toc25">削除状況の確認</span></h3>
<pre><code class="language-cmd">aws cloudformation describe-stacks ^
  --stack-name my-webapp-stack ^
  --query "Stacks[0].StackStatus" ^
  --output text</code></pre>
<p>削除完了の確認（以下のエラーが表示されれば削除完了）:</p>
<pre><code class="language-plaintext">An error occurred (ValidationError) when calling the DescribeStacks operation:
Stack with id my-webapp-stack does not exist</code></pre>
<h3><span id="toc26">S3バケットを削除する</span></h3>
<p>S3バケットはCloudFormationで管理していないため手動で削除します。</p>
<pre><code class="language-cmd">aws s3 rm s3://my-webapp-bucket-（任意の識別子） --recursive
aws s3 rb s3://my-webapp-bucket-（任意の識別子）</code></pre>
<h3><span id="toc27">キーペアを削除する（任意）</span></h3>
<p><strong>EC2 → キーペア → <code>my-webapp-key</code> を選択 → 「アクション」→「削除」</strong></p>
<hr>
<h2><span id="toc28">コンソール版との比較</span></h2>
<table>
<thead>
<tr>
<th>作業</th>
<th>コンソール版</th>
<th>CloudFormation版</th>
</tr>
</thead>
<tbody>
<tr>
<td>VPC + サブネット + IGW + RT</td>
<td>約20〜30分</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>SG 3つの作成</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>WARのデプロイ</td>
<td>SCP + SSH操作</td>
<td>S3 + UserDataで<strong>自動</strong></td>
</tr>
<tr>
<td>DB接続設定（setenv.sh）</td>
<td>SSH接続して手動作成</td>
<td>UserDataがSSMから<strong>自動</strong>取得・作成</td>
</tr>
<tr>
<td>全体のデプロイ</td>
<td>約60〜90分</td>
<td>コマンド数本（RDS待ち15〜20分）</td>
</tr>
<tr>
<td>削除</td>
<td>16ステップ手動</td>
<td><code>delete-stack</code> 1本（+S3手動削除）</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc29">トラブルシューティング</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>WARデプロイがまだ完了していない</td>
<td>TGのヘルスチェックがHealthyになるまで待つ（5〜10分）</td>
</tr>
<tr>
<td>ヘルスチェックがUnhealthy</td>
<td>WAR取得失敗 or Spring Boot起動失敗</td>
<td>SSH接続して <code>sudo cat /var/log/user-data.log</code> を確認</td>
</tr>
<tr>
<td><code>NoSuchKey</code> エラー</td>
<td>S3にwebapp.warがない</td>
<td><code>aws s3 ls s3://バケット名/</code> で存在確認</td>
</tr>
<tr>
<td>DB接続エラー（500エラー）</td>
<td>setenv.shのDB_HOSTが空</td>
<td><code>sudo cat /opt/tomcat/bin/setenv.sh</code> で確認</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>
</tbody>
</table>
<h3><span id="toc30">失敗時の詳細確認コマンド</span></h3>
<pre><code class="language-cmd">aws cloudformation describe-stack-events ^
  --stack-name my-webapp-stack ^
  --query "StackEvents[?ResourceStatus=='CREATE_FAILED'].[ResourceType,ResourceStatusReason]" ^
  --output table</code></pre>
<hr>
<h2><span id="toc31">まとめ</span></h2>
<table>
<thead>
<tr>
<th>ステップ</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>⓪</td>
<td>Mavenで <code>webapp.war</code> をビルド</td>
</tr>
<tr>
<td>①</td>
<td>キーペアをコンソールで作成</td>
</tr>
<tr>
<td>②</td>
<td>S3バケット作成 + WARをアップロード</td>
</tr>
<tr>
<td>③</td>
<td><code>create-stack</code> 1本（RDS待ち15〜20分）</td>
</tr>
<tr>
<td>④</td>
<td><code>CREATE_COMPLETE</code> になったらOutputsでALBエンドポイント・EC2IP・RDSエンドポイントを確認</td>
</tr>
<tr>
<td>⑤</td>
<td>ヘルスチェックがHealthyになったらブラウザでCRUD動作確認</td>
</tr>
<tr>
<td>⑥</td>
<td><code>delete-stack</code> 1本 + S3バケット手動削除</td>
</tr>
</tbody>
</table>
<p>CloudFormation版の最大のポイントは<strong>WARデプロイの自動化</strong>です。コンソール版ではSCPでWARを転送してSSHでsetenv.shを作成する必要がありましたが、今回はS3にWARをアップロードするだけでUserDataが全て自動で行います。</p>
<p>コンソール操作でSCPデプロイの仕組みを手を動かして確認したい場合は、<a href="https://caymezon.com/aws-handson-console-alb-ec2-rds-webapp/">AWSコンソール版ハンズオン</a>を参照してください。</p><p>The post <a href="https://caymezon.com/aws-handson-cloudformation-alb-ec2-rds-webapp/">CloudFormationでSpring Boot WebアプリをALB + EC2(Tomcat) + RDS に自動デプロイする手順【S3 + UserData / WAR自動配布】</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-webapp/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>GitHub×AWS実践ハンズオン：ActionsでEC2自動デプロイから始める連携活用術</title>
		<link>https://caymezon.com/github-aws-integration-hands-on/</link>
					<comments>https://caymezon.com/github-aws-integration-hands-on/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Thu, 05 Feb 2026 06:09:58 +0000</pubDate>
				<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[GitHub Actions]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[自動デプロイ]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20070</guid>

					<description><![CDATA[<p>GitHubとAWSを組み合わせることで、強力な自動化基盤を構築できます。この記事では、GitHub ActionsとAWSサービスを連携させた実践的なハンズオンを紹介します。初心者でも確実に実装できるよう、GitHub [&#8230;]</p>
<p>The post <a href="https://caymezon.com/github-aws-integration-hands-on/">GitHub×AWS実践ハンズオン：ActionsでEC2自動デプロイから始める連携活用術</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>GitHubとAWSを組み合わせることで、強力な自動化基盤を構築できます。この記事では、GitHub ActionsとAWSサービスを連携させた実践的なハンズオンを紹介します。初心者でも確実に実装できるよう、GitHub ActionsでのEC2自動デプロイから、S3静的サイト公開、Lambda関数デプロイまで、段階的に解説します。</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-10" checked><label class="toc-title" for="toc-checkbox-10">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">GitHub×AWSで実現できること</a><ol><li><a href="#toc2" tabindex="0">自動化の全体像</a></li><li><a href="#toc3" tabindex="0">できることの例</a></li></ol></li><li><a href="#toc4" tabindex="0">事前準備</a><ol><li><a href="#toc5" tabindex="0">必要なもの</a></li><li><a href="#toc6" tabindex="0">IAMユーザー作成</a></li><li><a href="#toc7" tabindex="0">GitHub Secretsに認証情報を保存</a></li></ol></li><li><a href="#toc8" tabindex="0">ハンズオン1：EC2にNode.jsアプリを自動デプロイ</a><ol><li><a href="#toc9" tabindex="0">システム構成</a></li><li><a href="#toc10" tabindex="0">EC2インスタンスの準備</a></li><li><a href="#toc11" tabindex="0">サンプルアプリ作成</a></li><li><a href="#toc12" tabindex="0">GitHub Actions設定</a></li><li><a href="#toc13" tabindex="0">デプロイ実行</a></li></ol></li><li><a href="#toc14" tabindex="0">ハンズオン2：S3で静的サイトを自動公開</a><ol><li><a href="#toc15" tabindex="0">システム構成</a></li><li><a href="#toc16" tabindex="0">S3バケット作成</a></li><li><a href="#toc17" tabindex="0">サンプルサイト作成</a></li><li><a href="#toc18" tabindex="0">GitHub Actions設定</a></li><li><a href="#toc19" tabindex="0">デプロイ実行</a></li></ol></li><li><a href="#toc20" tabindex="0">ハンズオン3：Lambda関数の自動デプロイ</a><ol><li><a href="#toc21" tabindex="0">システム構成</a></li><li><a href="#toc22" tabindex="0">Lambda関数作成</a></li><li><a href="#toc23" tabindex="0">サンプル関数</a></li><li><a href="#toc24" tabindex="0">GitHub Actions設定</a></li><li><a href="#toc25" tabindex="0">API Gateway設定（オプション）</a></li></ol></li><li><a href="#toc26" tabindex="0">応用パターン</a><ol><li><a href="#toc27" tabindex="0">パターン1：環境別デプロイ</a></li><li><a href="#toc28" tabindex="0">パターン2：ブルーグリーンデプロイ</a></li><li><a href="#toc29" tabindex="0">パターン3：ロールバック機能</a></li></ol></li><li><a href="#toc30" tabindex="0">トラブルシューティング</a><ol><li><a href="#toc31" tabindex="0">問題1：EC2デプロイでSSH接続失敗</a></li><li><a href="#toc32" tabindex="0">問題2：S3デプロイで403エラー</a></li><li><a href="#toc33" tabindex="0">問題3：Lambda関数が更新されない</a></li></ol></li><li><a href="#toc34" tabindex="0">セキュリティベストプラクティス</a><ol><li><a href="#toc35" tabindex="0">1. IAM権限の最小化</a></li><li><a href="#toc36" tabindex="0">2. Secrets管理</a></li><li><a href="#toc37" tabindex="0">3. 監査ログ</a></li></ol></li><li><a href="#toc38" tabindex="0">まとめ</a></li><li><a href="#toc39" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">GitHub×AWSで実現できること</span></h2>
<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":"GitHub CI\/CD実践ガイド――持続可能なソフトウェア開発を支えるGitHub Actionsの設計と運用 (エンジニア選書)","b":"技術評論社","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51rzki71LxL._SL500_.jpg","\/41fAMNJywPL._SL500_.jpg","\/41Dy2qzIwgL._SL500_.jpg","\/31MRBqS4faL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4297141736","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\/4297141736","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\/GitHub%20CI%2FCD%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89%E2%80%95%E2%80%95%E6%8C%81%E7%B6%9A%E5%8F%AF%E8%83%BD%E3%81%AA%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA%E3%82%92%E6%94%AF%E3%81%88%E3%82%8BGitHub%20Actions%E3%81%AE%E8%A8%AD%E8%A8%88%E3%81%A8%E9%81%8B%E7%94%A8%20(%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E9%81%B8%E6%9B%B8)\/","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=GitHub%20CI%2FCD%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89%E2%80%95%E2%80%95%E6%8C%81%E7%B6%9A%E5%8F%AF%E8%83%BD%E3%81%AA%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA%E3%82%92%E6%94%AF%E3%81%88%E3%82%8BGitHub%20Actions%E3%81%AE%E8%A8%AD%E8%A8%88%E3%81%A8%E9%81%8B%E7%94%A8%20(%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E9%81%B8%E6%9B%B8)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"P0azt","s":"s"});</script></p>
<div id="msmaflink-P0azt">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h3><span id="toc2">自動化の全体像</span></h3>
<pre><code class="language-plaintext">コード変更（git push）
  ↓
GitHub Actions自動実行
  ↓
ビルド・テスト
  ↓
AWSへ自動デプロイ
  ↓
本番環境更新</code></pre>
<p><strong>メリット：</strong></p>
<ul>
<li>手動デプロイの排除</li>
<li>ヒューマンエラー削減</li>
<li>リリース時間短縮</li>
<li>一貫性のある環境構築</li>
</ul>
<h3><span id="toc3">できることの例</span></h3>
<table>
<thead>
<tr>
<th>サービス</th>
<th>用途</th>
<th>難易度</th>
</tr>
</thead>
<tbody>
<tr>
<td>EC2</td>
<td>Webアプリ自動デプロイ</td>
<td>⭐⭐</td>
</tr>
<tr>
<td>S3</td>
<td>静的サイト公開</td>
<td>⭐</td>
</tr>
<tr>
<td>Lambda</td>
<td>サーバーレス関数デプロイ</td>
<td>⭐⭐</td>
</tr>
<tr>
<td>ECS</td>
<td>コンテナアプリデプロイ</td>
<td>⭐⭐⭐</td>
</tr>
<tr>
<td>CodeDeploy</td>
<td>ブルーグリーンデプロイ</td>
<td>⭐⭐⭐</td>
</tr>
</tbody>
</table>
<h2><span id="toc4">事前準備</span></h2>
<h3><span id="toc5">必要なもの</span></h3>
<p><strong>GitHub側：</strong></p>
<ul>
<li>GitHubアカウント</li>
<li>リポジトリ（Public/Private）</li>
</ul>
<p><strong>AWS側：</strong></p>
<ul>
<li>AWSアカウント</li>
<li>IAMユーザー（適切な権限）</li>
<li>対象サービス（EC2/S3など）</li>
</ul>
<h3><span id="toc6">IAMユーザー作成</span></h3>
<p><strong>手順：</strong></p>
<pre><code class="language-plaintext">1. AWSコンソール → IAM
2. Users → Add users
3. ユーザー名: github-actions-user
4. Access key - Programmatic access ✅
5. Attach policies directly:
   - AmazonEC2FullAccess（EC2デプロイ用）
   - AmazonS3FullAccess（S3デプロイ用）
6. Create user
7. Access Key ID と Secret Access Key を保存</code></pre>
<p><strong>注意：</strong> 本番環境では最小権限の原則に従い、必要な権限のみ付与してください。</p>
<h3><span id="toc7">GitHub Secretsに認証情報を保存</span></h3>
<pre><code class="language-plaintext">1. GitHubリポジトリ → Settings
2. Secrets and variables → Actions
3. New repository secret

登録する情報：
- AWS_ACCESS_KEY_ID: （IAMのAccess Key ID）
- AWS_SECRET_ACCESS_KEY: （IAMのSecret Access Key）
- AWS_REGION: ap-northeast-1（東京リージョン）</code></pre>
<h2><span id="toc8">ハンズオン1：EC2にNode.jsアプリを自動デプロイ</span></h2>
<h3><span id="toc9">システム構成</span></h3>
<pre><code class="language-plaintext">GitHub Repository
  ↓ git push
GitHub Actions
  ↓ SSH接続
EC2インスタンス
  ↓ アプリ更新
Webアプリ公開</code></pre>
<h3><span id="toc10">EC2インスタンスの準備</span></h3>
<p><strong>1. インスタンス起動：</strong></p>
<pre><code class="language-plaintext">AMI: Amazon Linux 2023
インスタンスタイプ: t2.micro（無料枠）
セキュリティグループ:
  - SSH (22) ← 自分のIP
  - HTTP (80) ← 0.0.0.0/0
  - Custom (3000) ← 0.0.0.0/0（開発用）</code></pre>
<p><strong>2. SSH接続して環境構築：</strong></p>
<pre><code class="language-bash">ssh -i your-key.pem ec2-user@your-ec2-ip

# Node.jsインストール
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
source ~/.bashrc
nvm install 20
nvm use 20

# アプリディレクトリ作成
mkdir ~/myapp
cd ~/myapp

# pm2インストール（プロセス管理）
npm install -g pm2</code></pre>
<p><strong>3. SSH鍵をGitHub Secretsに登録：</strong></p>
<pre><code class="language-plaintext">秘密鍵（your-key.pem）の内容をコピー

GitHub Secrets に登録：
- EC2_SSH_KEY: （秘密鍵の内容）
- EC2_HOST: （EC2のパブリックIP）
- EC2_USER: ec2-user</code></pre>
<h3><span id="toc11">サンプルアプリ作成</span></h3>
<p><strong>package.json：</strong></p>
<pre><code class="language-json">{
  "name": "github-aws-demo",
  "version": "1.0.0",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.18.0"
  }
}</code></pre>
<p><strong>server.js：</strong></p>
<pre><code class="language-javascript">const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.send(`
    <h1>GitHub Actions × AWS EC2</h1>
    <p>自動デプロイ成功！</p>
    <p>デプロイ時刻: ${new Date().toLocaleString('ja-JP')}</p>
  `);
});

app.get('/health', (req, res) => {
  res.json({ status: 'OK' });
});

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});</code></pre>
<h3><span id="toc12">GitHub Actions設定</span></h3>
<p><strong>.github/workflows/deploy-ec2.yml：</strong></p>
<pre><code class="language-yaml">name: Deploy to EC2

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Deploy to EC2
        env:
          SSH_KEY: ${{ secrets.EC2_SSH_KEY }}
          HOST: ${{ secrets.EC2_HOST }}
          USER: ${{ secrets.EC2_USER }}
        run: |
          # SSH秘密鍵を設定
          echo "$SSH_KEY" > private_key.pem
          chmod 600 private_key.pem
          
          # EC2にファイル転送
          scp -i private_key.pem -o StrictHostKeyChecking=no -r \
            server.js package.json ${USER}@${HOST}:~/myapp/
          
          # EC2でアプリ更新
          ssh -i private_key.pem -o StrictHostKeyChecking=no ${USER}@${HOST} << 'EOF'
            cd ~/myapp
            npm install
            pm2 restart myapp || pm2 start server.js --name myapp
            pm2 save
          EOF
          
          # 秘密鍵削除
          rm -f private_key.pem
      
      - name: Verify deployment
        run: |
          sleep 5
          curl -f http://${{ secrets.EC2_HOST }}:3000/health || exit 1
          echo "Deployment successful!"</code></pre>
<h3><span id="toc13">デプロイ実行</span></h3>
<p><strong>1. リポジトリにプッシュ：</strong></p>
<pre><code class="language-bash">git add .
git commit -m "Add EC2 auto deploy"
git push origin main</code></pre>
<p><strong>2. GitHub Actionsで確認：</strong></p>
<pre><code class="language-plaintext">Actions タブ
→ Deploy to EC2 ワークフロー
→ ログ確認
→ ✅ 成功</code></pre>
<p><strong>3. ブラウザでアクセス：</strong></p>
<pre><code class="language-plaintext">http://your-ec2-ip:3000
→ 「自動デプロイ成功！」表示</code></pre>
<p><strong>完了！</strong> コードを変更してpushするたびに自動デプロイされます。</p>
<blockquote>
<p>GitHub Actionsの実践例は「<a href="https://caymezon.com/github-actions-wordpress-403-error-battle/">【試行錯誤の記録】GitHub ActionsでWordPress自動投稿！403エラーとの戦い</a>」でも紹介しています。</p>
</blockquote>
<h2><span id="toc14">ハンズオン2：S3で静的サイトを自動公開</span></h2>
<h3><span id="toc15">システム構成</span></h3>
<pre><code class="language-plaintext">GitHub Repository（HTML/CSS/JS）
  ↓ git push
GitHub Actions
  ↓ AWS CLI
S3バケット
  ↓ 静的Webホスティング
インターネット公開</code></pre>
<h3><span id="toc16">S3バケット作成</span></h3>
<p><strong>1. バケット作成：</strong></p>
<pre><code class="language-plaintext">1. S3コンソール → Create bucket
2. Bucket name: my-github-demo-site（グローバルで一意）
3. Region: ap-northeast-1
4. Block Public Access: すべてOFF（公開用）
5. Create bucket</code></pre>
<p><strong>2. 静的Webホスティング有効化：</strong></p>
<pre><code class="language-plaintext">バケット → Properties
→ Static website hosting → Enable
→ Index document: index.html
→ Error document: error.html
→ Save changes</code></pre>
<p><strong>3. バケットポリシー設定：</strong></p>
<pre><code class="language-json">{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-github-demo-site/*"
    }
  ]
}</code></pre>
<h3><span id="toc17">サンプルサイト作成</span></h3>
<p><strong>index.html：</strong></p>
<pre><code class="language-html"><!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GitHub Actions × S3</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="container">
    <h1>GitHub Actions × S3</h1>
    <p>静的サイトの自動デプロイ成功！</p>
    <p id="timestamp"></p>
  </div>
  <script src="script.js"></script>
</body>
</html></code></pre>
<p><strong>style.css：</strong></p>
<pre><code class="language-css">body {
  font-family: Arial, sans-serif;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  margin: 0;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.container {
  background: white;
  padding: 2rem;
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.3);
  text-align: center;
}

h1 {
  color: #333;
  margin-bottom: 1rem;
}</code></pre>
<p><strong>script.js：</strong></p>
<pre><code class="language-javascript">document.getElementById('timestamp').textContent = 
  `最終デプロイ: ${new Date().toLocaleString('ja-JP')}`;</code></pre>
<h3><span id="toc18">GitHub Actions設定</span></h3>
<p><strong>.github/workflows/deploy-s3.yml：</strong></p>
<pre><code class="language-yaml">name: Deploy to S3

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}
      
      - name: Sync to S3
        run: |
          aws s3 sync . s3://my-github-demo-site \
            --exclude ".git/*" \
            --exclude ".github/*" \
            --delete
      
      - name: Invalidate CloudFront (optional)
        run: |
          echo "CloudFront未使用の場合はスキップ"
          # aws cloudfront create-invalidation \
          #   --distribution-id YOUR_DISTRIBUTION_ID \
          #   --paths "/*"</code></pre>
<h3><span id="toc19">デプロイ実行</span></h3>
<p><strong>1. プッシュ：</strong></p>
<pre><code class="language-bash">git add .
git commit -m "Add S3 static site deploy"
git push origin main</code></pre>
<p><strong>2. S3エンドポイントにアクセス：</strong></p>
<pre><code class="language-plaintext">http://my-github-demo-site.s3-website-ap-northeast-1.amazonaws.com</code></pre>
<p><strong>完了！</strong> HTMLを変更するたびに自動で公開されます。</p>
<h2><span id="toc20">ハンズオン3：Lambda関数の自動デプロイ</span></h2>
<h3><span id="toc21">システム構成</span></h3>
<pre><code class="language-plaintext">GitHub Repository（Lambda関数）
  ↓ git push
GitHub Actions
  ↓ zip & AWS CLI
Lambda関数更新
  ↓ API Gateway
REST API公開</code></pre>
<h3><span id="toc22">Lambda関数作成</span></h3>
<p><strong>1. AWSコンソールでLambda作成：</strong></p>
<pre><code class="language-plaintext">Lambda → Create function
Function name: github-demo-function
Runtime: Node.js 20.x
Create function</code></pre>
<p><strong>2. 環境変数設定（オプション）：</strong></p>
<pre><code class="language-plaintext">Configuration → Environment variables
Key: STAGE
Value: production</code></pre>
<h3><span id="toc23">サンプル関数</span></h3>
<p><strong>index.js：</strong></p>
<pre><code class="language-javascript">exports.handler = async (event) => {
  console.log('Event:', JSON.stringify(event));
  
  const name = event.queryStringParameters?.name || 'World';
  const timestamp = new Date().toISOString();
  
  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*'
    },
    body: JSON.stringify({
      message: `Hello, ${name}!`,
      timestamp: timestamp,
      environment: process.env.STAGE || 'development',
      deployedBy: 'GitHub Actions'
    })
  };
};</code></pre>
<p><strong>package.json：</strong></p>
<pre><code class="language-json">{
  "name": "github-lambda-demo",
  "version": "1.0.0",
  "description": "GitHub Actions Lambda deployment demo"
}</code></pre>
<h3><span id="toc24">GitHub Actions設定</span></h3>
<p><strong>.github/workflows/deploy-lambda.yml：</strong></p>
<pre><code class="language-yaml">name: Deploy to Lambda

on:
  push:
    branches: [main]
    paths:
      - 'lambda/**'

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '20'
      
      - name: Install dependencies
        working-directory: ./lambda
        run: npm install --production
      
      - name: Create deployment package
        working-directory: ./lambda
        run: |
          zip -r function.zip .
      
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}
      
      - name: Deploy to Lambda
        working-directory: ./lambda
        run: |
          aws lambda update-function-code \
            --function-name github-demo-function \
            --zip-file fileb://function.zip
      
      - name: Wait for update
        run: |
          aws lambda wait function-updated \
            --function-name github-demo-function
      
      - name: Test Lambda function
        run: |
          aws lambda invoke \
            --function-name github-demo-function \
            --payload '{"queryStringParameters":{"name":"GitHub"}}' \
            response.json
          cat response.json</code></pre>
<h3><span id="toc25">API Gateway設定（オプション）</span></h3>
<p><strong>REST APIとして公開：</strong></p>
<pre><code class="language-plaintext">1. API Gateway → Create API
2. REST API → Build
3. Create resource: /hello
4. Create method: GET
5. Integration type: Lambda Function
6. Lambda Function: github-demo-function
7. Deploy API → Stage: prod</code></pre>
<p><strong>エンドポイント：</strong></p>
<pre><code class="language-plaintext">https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/hello?name=World</code></pre>
<h2><span id="toc26">応用パターン</span></h2>
<h3><span id="toc27">パターン1：環境別デプロイ</span></h3>
<p><strong>複数環境の管理：</strong></p>
<pre><code class="language-yaml">on:
  push:
    branches:
      - main      # 本番環境
      - develop   # 開発環境

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Set environment
        run: |
          if [ "${{ github.ref }}" == "refs/heads/main" ]; then
            echo "ENVIRONMENT=production" >> $GITHUB_ENV
            echo "LAMBDA_FUNCTION=prod-function" >> $GITHUB_ENV
          else
            echo "ENVIRONMENT=development" >> $GITHUB_ENV
            echo "LAMBDA_FUNCTION=dev-function" >> $GITHUB_ENV
          fi
      
      - name: Deploy
        run: |
          aws lambda update-function-code \
            --function-name ${{ env.LAMBDA_FUNCTION }} \
            --zip-file fileb://function.zip</code></pre>
<h3><span id="toc28">パターン2：ブルーグリーンデプロイ</span></h3>
<p><strong>無停止デプロイ：</strong></p>
<pre><code class="language-yaml">- name: Create new version
  run: |
    VERSION=$(aws lambda publish-version \
      --function-name my-function \
      --query 'Version' --output text)
    echo "VERSION=$VERSION" >> $GITHUB_ENV

- name: Update alias
  run: |
    aws lambda update-alias \
      --function-name my-function \
      --name production \
      --function-version ${{ env.VERSION }}</code></pre>
<h3><span id="toc29">パターン3：ロールバック機能</span></h3>
<p><strong>デプロイ失敗時の自動ロールバック：</strong></p>
<pre><code class="language-yaml">- name: Deploy and test
  id: deploy
  run: |
    # デプロイ
    aws lambda update-function-code ...
    
    # ヘルスチェック
    if ! curl -f https://api.example.com/health; then
      exit 1
    fi

- name: Rollback on failure
  if: failure() && steps.deploy.outcome == 'failure'
  run: |
    aws lambda update-function-code \
      --function-name my-function \
      --s3-bucket backup-bucket \
      --s3-key previous-version.zip</code></pre>
<h2><span id="toc30">トラブルシューティング</span></h2>
<h3><span id="toc31">問題1：EC2デプロイでSSH接続失敗</span></h3>
<p><strong>エラー：</strong></p>
<pre><code class="language-plaintext">Permission denied (publickey)</code></pre>
<p><strong>原因：</strong></p>
<ul>
<li>SSH鍵の改行コードが正しくない</li>
<li>鍵の権限が適切でない</li>
</ul>
<p><strong>解決：</strong></p>
<pre><code class="language-yaml"># 改行コードを明示的に処理
run: |
  echo "$SSH_KEY" | tr -d '\r' > private_key.pem
  chmod 600 private_key.pem</code></pre>
<h3><span id="toc32">問題2：S3デプロイで403エラー</span></h3>
<p><strong>原因：</strong></p>
<ul>
<li>IAMユーザーに権限がない</li>
<li>バケットポリシーが未設定</li>
</ul>
<p><strong>解決：</strong></p>
<pre><code class="language-plaintext">1. IAMユーザーに AmazonS3FullAccess 付与
2. バケットポリシーで PublicReadGetObject 設定
3. ブロックパブリックアクセスを確認</code></pre>
<h3><span id="toc33">問題3：Lambda関数が更新されない</span></h3>
<p><strong>原因：</strong></p>
<ul>
<li>関数名が間違っている</li>
<li>zipファイルサイズ超過（50MB制限）</li>
</ul>
<p><strong>解決：</strong></p>
<pre><code class="language-bash"># 関数名確認
aws lambda list-functions

# zipサイズ確認
ls -lh function.zip

# 大きい場合はS3経由でデプロイ
aws s3 cp function.zip s3://my-bucket/
aws lambda update-function-code \
  --function-name my-function \
  --s3-bucket my-bucket \
  --s3-key function.zip</code></pre>
<h2><span id="toc34">セキュリティベストプラクティス</span></h2>
<h3><span id="toc35">1. IAM権限の最小化</span></h3>
<p><strong>NG（フルアクセス）：</strong></p>
<pre><code class="language-json">{
  "Effect": "Allow",
  "Action": "*",
  "Resource": "*"
}</code></pre>
<p><strong>OK（必要な権限のみ）：</strong></p>
<pre><code class="language-json">{
  "Effect": "Allow",
  "Action": [
    "s3:PutObject",
    "s3:DeleteObject",
    "lambda:UpdateFunctionCode"
  ],
  "Resource": [
    "arn:aws:s3:::my-bucket/*",
    "arn:aws:lambda:ap-northeast-1:*:function:my-function"
  ]
}</code></pre>
<h3><span id="toc36">2. Secrets管理</span></h3>
<p><strong>GitHub Secrets以外の選択肢：</strong></p>
<ul>
<li><strong>AWS Secrets Manager</strong>：より高度な管理</li>
<li><strong>AWS Systems Manager Parameter Store</strong>：無料枠あり</li>
</ul>
<p><strong>GitHub ActionsでSecrets Manager使用：</strong></p>
<pre><code class="language-yaml">- name: Get secrets
  run: |
    SECRET=$(aws secretsmanager get-secret-value \
      --secret-id my-app-secret \
      --query SecretString --output text)
    echo "::add-mask::$SECRET"
    echo "SECRET=$SECRET" >> $GITHUB_ENV</code></pre>
<h3><span id="toc37">3. 監査ログ</span></h3>
<p><strong>CloudTrailで操作履歴記録：</strong></p>
<pre><code class="language-plaintext">CloudTrail → Create trail
→ S3バケットに操作ログ保存
→ GitHub Actionsの操作も記録</code></pre>
<h2><span id="toc38">まとめ</span></h2>
<p>GitHub ActionsとAWSの連携で、強力な自動化基盤を構築できます。</p>
<p><strong>実装したハンズオン：</strong></p>
<ol>
<li><strong>EC2自動デプロイ</strong>：Node.jsアプリをSSH経由でデプロイ</li>
<li><strong>S3静的サイト</strong>：HTML/CSS/JSを自動公開</li>
<li><strong>Lambda関数</strong>：サーバーレス関数の自動更新</li>
</ol>
<p><strong>メリット：</strong></p>
<ul>
<li>手動作業の削減</li>
<li>デプロイミスの防止</li>
<li>一貫性のある環境</li>
<li>リリース時間の短縮</li>
</ul>
<p><strong>コスト：</strong></p>
<ul>
<li>GitHub Actions：パブリックリポジトリは無料</li>
<li>AWS無料枠：1年間または月次制限内</li>
<li>実質コスト：ほぼ無料で始められる</li>
</ul>
<p>まずは簡単なS3デプロイから始めて、徐々に複雑な構成に挑戦してみましょう！</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="toc39">関連記事</span></h2>
<ul>
<li>【試行錯誤の記録】GitHub ActionsでWordPress自動投稿！403エラーとの戦い</li>
</ul>

<a rel="noopener" href="https://caymezon.com/github-actions-wordpress-403-error-battle/" title="【試行錯誤の記録】GitHub ActionsでWordPress自動投稿！403エラーとの戦い" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/01/github-actions-wordpress-403-error-battle-featured-0bdc61-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/01/github-actions-wordpress-403-error-battle-featured-0bdc61-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/01/github-actions-wordpress-403-error-battle-featured-0bdc61-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/01/github-actions-wordpress-403-error-battle-featured-0bdc61-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/01/github-actions-wordpress-403-error-battle-featured-0bdc61-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【試行錯誤の記録】GitHub ActionsでWordPress自動投稿！403エラーとの戦い</div><div class="blogcard-snippet internal-blogcard-snippet">はじめにVSCodeでMarkdownを書いて、git push するだけでWordPressに自動投稿される――そんな夢のようなシステムを作ろうと、GitHub Actions連携に挑戦しました。しかし、待っていたのは 403 Forbi...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.01.12</div></div></div></div></a>
<ul>
<li>GitHub CLI完全ガイド：コマンドラインでGitHub操作を効率化</li>
</ul>

<a rel="noopener" href="https://caymezon.com/github-cli-complete-guide/" title="GitHub CLI完全ガイド：コマンドラインでGitHub操作を効率化" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/01/github-cli-complete-guide-featured-b23a6b-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/01/github-cli-complete-guide-featured-b23a6b-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/01/github-cli-complete-guide-featured-b23a6b-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/01/github-cli-complete-guide-featured-b23a6b-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/01/github-cli-complete-guide-featured-b23a6b-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">GitHub CLI完全ガイド：コマンドラインでGitHub操作を効率化</div><div class="blogcard-snippet internal-blogcard-snippet">GitHub CLI（ghコマンド）は、GitHubの操作をコマンドラインで完結できる公式ツールです。ブラウザを開かずに、リポジトリ作成からIssue管理、Pull Request作成まで、すべてターミナルで行えます。この記事では、実際の導...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.01.31</div></div></div></div></a>
<ul>
<li>VSCodeでGitを使いこなす：初心者から実務まで完全ガイド</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-git-complete-guide/" title="VSCodeでGitを使いこなす完全ガイド｜GUI操作とCLIコマンドを徹底比較" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/vscode-git-complete-guide-featured-ef5df2-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/vscode-git-complete-guide-featured-ef5df2-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/vscode-git-complete-guide-featured-ef5df2-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/vscode-git-complete-guide-featured-ef5df2-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/vscode-git-complete-guide-featured-ef5df2-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCodeでGitを使いこなす完全ガイド｜GUI操作とCLIコマンドを徹底比較</div><div class="blogcard-snippet internal-blogcard-snippet">はじめにVSCodeでアプリケーション開発をしている方の多くが、Gitによるバージョン管理を導入しています。しかし、「CLIコマンドならわかるけど、VSCodeのGUI操作がよくわからない」「どのメニューから操作すればいいのか迷う」といった...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.02</div></div></div></div></a><p>The post <a href="https://caymezon.com/github-aws-integration-hands-on/">GitHub×AWS実践ハンズオン：ActionsでEC2自動デプロイから始める連携活用術</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/github-aws-integration-hands-on/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
