<?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>Fargate - CayTech Lab</title>
	<atom:link href="https://caymezon.com/tag/fargate/feed/" rel="self" type="application/rss+xml" />
	<link>https://caymezon.com</link>
	<description></description>
	<lastBuildDate>Sat, 09 May 2026 03:23:21 +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>Fargate - 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 + ECS Fargate で Webアプリをコンテナ化する【EC2 からコンテナへの移行体験】</title>
		<link>https://caymezon.com/aws-handson-cdk-ecs-webapp/</link>
					<comments>https://caymezon.com/aws-handson-cdk-ecs-webapp/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sat, 09 May 2026 03:23:21 +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[CodePipeline]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[ECR]]></category>
		<category><![CDATA[ECS]]></category>
		<category><![CDATA[Fargate]]></category>
		<category><![CDATA[GitHub Actions]]></category>
		<category><![CDATA[GitOps]]></category>
		<category><![CDATA[IaC]]></category>
		<category><![CDATA[Maven]]></category>
		<category><![CDATA[OIDC]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RDS]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[コンテナ]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[ローリングデプロイ]]></category>
		<category><![CDATA[初心者]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20414</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説cdk-asg-webapp との比較ファイル構成と役割使用するAWSサービス前提条件作業順序① プロジェクトのセットアップ② GitHub との接続を設定する（CodeConnections [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-cdk-ecs-webapp/">CDK + ECS Fargate で Webアプリをコンテナ化する【EC2 からコンテナへの移行体験】</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-asg-webapp との比較</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">ALB の URL を確認する</a></li><li><a href="#toc21" tabindex="0">ECS コンソールで確認する</a></li></ol></li><li><a href="#toc22" tabindex="0">⑧ GitHub Actions を設定する（OIDC + IAM ロール）</a><ol><li><a href="#toc23" tabindex="0">OIDC プロバイダーを登録する</a></li><li><a href="#toc24" tabindex="0">IAM ロールを作成する（CloudShell）</a></li><li><a href="#toc25" tabindex="0">GitHub Variables を設定する</a></li><li><a href="#toc26" tabindex="0">ワークフローファイルを push する</a></li></ol></li><li><a href="#toc27" tabindex="0">⑨ アプリを初回デプロイする（GitHub Actions）</a><ol><li><a href="#toc28" tabindex="0">アプリのタイトルを変更する</a></li><li><a href="#toc29" tabindex="0">コミット＆プッシュ</a></li><li><a href="#toc30" tabindex="0">GitHub Actions の進行を確認する</a></li><li><a href="#toc31" tabindex="0">ブラウザで動作確認する</a></li></ol></li><li><a href="#toc32" tabindex="0">⑩ ECS Exec でコンテナに接続する</a><ol><li><a href="#toc33" tabindex="0">実行中のタスク ARN を確認する</a></li><li><a href="#toc34" tabindex="0">コンテナに接続する</a></li><li><a href="#toc35" tabindex="0">コンテナ内で確認する</a></li></ol></li><li><a href="#toc36" tabindex="0">⑪ タスク数スケーリングを体験する</a><ol><li><a href="#toc37" tabindex="0">スケールアウト（1台 → 2台）</a></li><li><a href="#toc38" tabindex="0">スケールイン（2台 → 1台）</a></li></ol></li><li><a href="#toc39" tabindex="0">⑫ リソースを削除する</a><ol><li><a href="#toc40" tabindex="0">1. インフラスタックを削除する</a></li><li><a href="#toc41" tabindex="0">2. パイプラインスタックを削除する</a></li><li><a href="#toc42" tabindex="0">3. GitHub Actions IAM ロールを削除する</a></li><li><a href="#toc43" tabindex="0">4. SSM パラメータを削除する</a></li><li><a href="#toc44" tabindex="0">5. 仮想環境の終了</a></li><li><a href="#toc45" tabindex="0">6. GitHub との接続を削除する（オプション）</a></li><li><a href="#toc46" tabindex="0">7. OIDC プロバイダーを削除する（オプション）</a></li><li><a href="#toc47" tabindex="0">削除確認</a></li></ol></li><li><a href="#toc48" tabindex="0">EC2 → コンテナへの移行ポイント</a></li><li><a href="#toc49" tabindex="0">トラブルシューティング</a></li><li><a href="#toc50" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「EC2 の OS パッチや Tomcat のインストール設定が面倒」「スケールアウト時のインスタンス管理が複雑」——これを解決するのが <strong>ECS Fargate（サーバーレスコンテナ）</strong> です。</p>
<p>この記事では、<a href="https://caymezon.com/aws-handson-cdk-asg-webapp/">ASG ハンズオン（cdk-asg-webapp）</a>で構築した <strong>EC2 + Auto Scaling Group 構成</strong>を、<strong>ECS Fargate + Docker コンテナ</strong>にアップグレードします。EC2 の代わりに Docker コンテナで Spring Boot アプリを動かし、<strong>GitHub Actions</strong> がコンテナイメージをビルドして ECS へ自動デプロイする仕組みを体験します。</p>
<pre><code class="language-plaintext">【インフラ担当】CDK Pipelines
GitHub リポジトリ
  ↓ push（常に起動）
CodePipeline (my-cdk6-pipeline)
  ├── Source:       GitHub (CodeConnections 経由)
  ├── Build(Synth): CodeBuild — cdk synth
  ├── Mutate:       パイプライン自己更新（セルフミューテーション）
  └── InfraDeploy:  CloudFormation — VPC / ECR / ECS / RDS / ALB

【アプリ担当】GitHub Actions（app/ または Dockerfile 変更時のみ起動）
  1. Docker ビルド（Maven → WAR → Tomcat コンテナ）
  2. ECR にイメージをプッシュ
  3. タスク定義を新リビジョンに更新（プレースホルダー → 実イメージ）
  4. ECS サービスをローリングデプロイ（〜2〜3分）
                ↓
       [ALB: my-cdk6-alb]
                ↓
       ECS Fargate Service (my-cdk6-service)
       ・コンテナ: Tomcat 10.1 + Spring Boot WAR
       ・CPU: 256 units / Memory: 512 MiB
                ↓
       [RDS: my-cdk6-rds-mysql]  ← MySQL 8.0</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li>Docker のマルチステージビルド（Maven → WAR → Tomcat コンテナ）</li>
<li>ECR へのイメージプッシュと ECS Fargate でのコンテナ実行</li>
<li>GitHub Actions（OIDC 認証）による Docker ビルド → ECR プッシュ → ECS ローリングデプロイ</li>
<li><strong>インフラ（CDK Pipelines）とアプリ（GitHub Actions）のデプロイを分離した実務パターン</strong></li>
<li>ECS Exec でコンテナ内のシェルに直接接続するデバッグ体験</li>
<li><code>desired_count</code> を変更するだけのシンプルなスケーリング体験</li>
</ul>
<hr>
<blockquote>
<p><strong>この記事は <a href="https://caymezon.com/aws-handson-cdk-asg-webapp/">CDK + Auto Scaling Group ハンズオン（cdk-asg-webapp）</a> の発展記事です。</strong><br />cdk-asg-webapp を体験済みの方向けです（cdk-webapp-pipeline 完了でも OK）。コード詳細は <a href="https://github.com/caymezon/aws-handson/tree/main/cdk-ecs-webapp">GitHub</a> を参照してください。</p>
</blockquote>
<hr>
<p><!-- ![CDK Pipelinesの全ステージ完了とECSコンソールの画面](images/pipeline-ecs-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>Docker / Dockerfile</strong></td>
<td>アプリとその実行環境をひとまとめにした「コンテナ」を作成する仕組み。<code>Dockerfile</code> にビルド手順を記述する</td>
</tr>
<tr>
<td><strong>マルチステージビルド</strong></td>
<td>ビルド環境（Maven）と実行環境（Tomcat）を分離して軽量なイメージを作成するテクニック</td>
</tr>
<tr>
<td><strong>ECR（Elastic Container Registry）</strong></td>
<td>Docker イメージを保管する AWS マネージドレジストリ。EC2 構成での S3 バケットに相当する</td>
</tr>
<tr>
<td><strong>ECS Fargate</strong></td>
<td>EC2 なしでコンテナを実行できるサーバーレス実行環境。OS 管理・パッチ適用が不要</td>
</tr>
<tr>
<td><strong>タスク定義</strong></td>
<td>コンテナの CPU・メモリ・環境変数・IAM ロールなどを定義する設定</td>
</tr>
<tr>
<td><strong>ECS Service</strong></td>
<td>タスクのスケーリング・ヘルスチェック・ALB 連携・ローリングデプロイを管理する</td>
</tr>
<tr>
<td><strong>ローリングデプロイ</strong></td>
<td>旧コンテナを停止しながら新コンテナを順次起動する無停止デプロイ</td>
</tr>
<tr>
<td><strong>ECS Exec</strong></td>
<td>コンテナ内のシェルに AWS CLI から直接アクセスするデバッグ機能。EC2 の SSM Session Manager に相当</td>
</tr>
<tr>
<td><strong>OIDC 認証</strong></td>
<td>アクセスキーをリポジトリに保存せず、GitHub Actions から AWS を操作できるキーレス認証</td>
</tr>
<tr>
<td><strong>インフラ/アプリ分離デプロイ</strong></td>
<td>CDK Pipelines（インフラ）と GitHub Actions（アプリ）で役割を分担する実務パターン</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">cdk-asg-webapp との比較</span></h2>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>cdk-asg-webapp</th>
<th>cdk-ecs-webapp</th>
</tr>
</thead>
<tbody>
<tr>
<td>実行環境</td>
<td>EC2（Launch Template + ASG）</td>
<td><strong>ECS Fargate（サーバーレスコンテナ）</strong></td>
</tr>
<tr>
<td>デプロイ形式</td>
<td>WAR → S3 → CodeDeploy</td>
<td><strong>Docker Image → ECR → ECS タスク更新</strong></td>
</tr>
<tr>
<td>インフラ管理</td>
<td>EC2 OS パッチ・エージェント管理が必要</td>
<td><strong>サーバーレス（EC2 管理不要）</strong></td>
</tr>
<tr>
<td>スケーリング</td>
<td>CPU 自動スケール（ASG ポリシー）</td>
<td><strong><code>desired_count</code> を直接変更（シンプル）</strong></td>
</tr>
<tr>
<td>デバッグ接続</td>
<td>SSM Session Manager（EC2 に接続）</td>
<td><strong>ECS Exec（コンテナに直接接続）</strong></td>
</tr>
<tr>
<td>アプリ設定ファイル</td>
<td><code>appspec.yml</code> + <code>scripts/</code></td>
<td><strong><code>Dockerfile</code> のみ</strong></td>
</tr>
<tr>
<td>アプリデプロイ担当</td>
<td>CDK Pipelines 内の CodeDeploy</td>
<td><strong>GitHub Actions</strong></td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">ファイル構成と役割</span></h2>
<pre><code class="language-plaintext">cdk-ecs-webapp/
├── app.py                     ← CDK アプリ エントリポイント
├── cdk.json                   ← CDK 設定（asg_* → task_cpu / task_memory / desired_count）
├── Dockerfile                 ← NEW: コンテナイメージのビルド手順（cdk-asg-webapp にはない）
├── app/                       ← Spring Boot Webアプリ（Java）
├── pipeline/
│   └── pipeline_stack.py      ← CodePipeline（インフラのみ / アプリは GitHub Actions が担当）
├── stages/
│   └── deploy_stage.py        ← Stage（WebappStack を内包）
├── stacks/
│   └── webapp_stack.py        ← インフラスタック（ECR/ECS の名前を CfnOutput で公開）
└── components/
    └── webapp_construct.py    ← ECS Fargate ベースの L3 Construct</code></pre>
<table>
<thead>
<tr>
<th>ファイル</th>
<th>cdk-asg-webapp との主な違い</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Dockerfile</code></td>
<td>新規追加。マルチステージビルドで Maven → WAR → Tomcat コンテナを作成</td>
</tr>
<tr>
<td><code>webapp_construct.py</code></td>
<td><code>AutoScalingGroup + LaunchTemplate</code> → <code>FargateService + TaskDefinition + ECR</code></td>
</tr>
<tr>
<td><code>webapp_stack.py</code></td>
<td><code>ASGName</code> 等の出力を廃止 → <code>ECRRepoUri / ECSClusterName / ECSServiceName</code> を追加</td>
</tr>
<tr>
<td><code>pipeline_stack.py</code></td>
<td><code>BuildAndDeployApp</code>（CodeDeploy）を廃止 → インフラ変更のみ担当</td>
</tr>
</tbody>
</table>
<p>詳細なコードは <a href="https://github.com/caymezon/aws-handson/tree/main/cdk-ecs-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>ECS Fargate</strong>（0.25 vCPU / 512 MiB）</td>
<td>Spring Boot コンテナを実行するサーバーレス環境</td>
<td>約$0.01/時間（<strong>無料枠なし</strong>）</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>ECR</strong></td>
<td>Docker イメージの保管場所</td>
<td>500MB/月まで無料</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>S3</strong></td>
<td>パイプラインのアーティファクト置き場</td>
<td>無料枠あり</td>
</tr>
<tr>
<td><strong>SSM Parameter Store</strong></td>
<td>DBパスワードの安全な管理・ECS への環境変数注入</td>
<td>スタンダード層無料</td>
</tr>
<tr>
<td><strong>CloudWatch Logs</strong></td>
<td>コンテナのログ出力先</td>
<td>無料枠あり</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>各サービスの権限</td>
<td>無料</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>注意</strong>: ECS Fargate と 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>
<blockquote>
<p><strong>Docker Desktop は不要です</strong>。コンテナのビルドは GitHub Actions runner 上（Ubuntu）で実行されるため、ローカル PC に Docker をインストールする必要はありません。</p>
</blockquote>
<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>
<hr>
<h2><span id="toc7">作業順序</span></h2>
<pre><code class="language-plaintext">① プロジェクトのセットアップ（Python 仮想環境）
      ↓
② GitHub との接続を設定する（CodeConnections）
      ↓
③ cdk.json の設定
      ↓
④ コードを GitHub にプッシュする（重要！）
      ↓
⑤ パイプラインスタックのデプロイ（初回のみ手動）
      ↓
⑥ パイプラインの実行状況を確認する
      ↓
⑦ インフラを確認する
      ↓
⑧ GitHub Actions を設定する（OIDC + IAM ロール）
      ↓
⑨ アプリを初回デプロイする
      ↓
⑩ ECS Exec でコンテナに接続する
      ↓
⑪ タスク数スケーリングを体験する
      ↓
⑫ リソースを削除する</code></pre>
<hr>
<h2><span id="toc8">① プロジェクトのセットアップ</span></h2>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-ecs-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-ecs-webapp
.venv\Scripts\activate</code></pre>
</blockquote>
<hr>
<h2><span id="toc9">② GitHub との接続を設定する（CodeConnections）</span></h2>
<blockquote>
<p><strong>cdk-asg-webapp（または cdk-webapp-pipeline）を実施済みの場合</strong>: 同じリポジトリを扱うため、<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!",
    "task_cpu": 256,
    "task_memory": 512,
    "desired_count": 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-cdk6-xxx</code> という名前になる）</td>
</tr>
<tr>
<td><code>task_cpu</code></td>
<td><code>256</code></td>
<td>Fargate タスクの CPU ユニット（256 = 0.25 vCPU）</td>
</tr>
<tr>
<td><code>task_memory</code></td>
<td><code>512</code></td>
<td>Fargate タスクのメモリ（MiB）</td>
</tr>
<tr>
<td><code>desired_count</code></td>
<td><code>1</code></td>
<td>ECS サービスの起動タスク数</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>task_cpu</code> と <code>task_memory</code> の組み合わせ制限（Fargate の仕様）</strong><br />CPU と Memory には決まった組み合わせがあります。256 CPU の場合、Memory は 512〜2048（512 単位）が有効です。</p>
</blockquote>
<hr>
<h2><span id="toc14">④ コードを GitHub にプッシュする（重要！）</span></h2>
<blockquote>
<p><code>cdk deploy</code> の前に必ず<strong>プロジェクト全体</strong>を push してください。<br />パイプラインが <code>cdk synth</code> を実行する際、GitHub から取得したコードを使うためです。</p>
</blockquote>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects

git add cdk-ecs-webapp/
git commit -m "feat: cdk-ecs-webapp ハンズオンを追加"
git push origin main</code></pre>
<blockquote>
<p><strong>GitHub Actions も同時に起動する場合</strong>: <code>app/</code> または <code>Dockerfile</code> の変更が含まれていると GitHub Actions（<code>Deploy App to ECS</code>）も起動しますが、この時点では ECS サービスがまだ存在しないため失敗します。インフラが完成してから <strong>⑨</strong> で改めてアプリをデプロイします。</p>
</blockquote>
<hr>
<h2><span id="toc15">⑤ パイプラインスタックのデプロイ（初回のみ）</span></h2>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects\cdk-ecs-webapp

.venv\Scripts\activate

cdk synth

cdk deploy</code></pre>
<p>「Do you wish to deploy these changes?」に <code>y</code> を入力します。</p>
<p><code>my-EcsPipelineStack</code> が作成され、以降は GitHub push で自動デプロイされます。</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 / ECR / ECS / RDS / ALB を構築</td>
<td>〜20分</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>初回の InfraDeploy に 20 分程度かかる理由</strong>: RDS の起動と ECS サービスの安定化（プレースホルダーコンテナの起動確認）に時間がかかります。</p>
</blockquote>
<hr>
<h2><span id="toc16">⑥ パイプラインの実行状況を確認する</span></h2>
<ol>
<li>AWS コンソール → <strong>CodePipeline</strong> を開く</li>
<li><code>my-cdk6-pipeline</code> を選択</li>
<li>各ステージが <strong>「成功」</strong> になるまで待つ</li>
</ol>
<h3><span id="toc17">CloudFormation スタックの命名規則</span></h3>
<table>
<thead>
<tr>
<th>要素</th>
<th>このハンズオンでの値</th>
</tr>
</thead>
<tbody>
<tr>
<td>パイプラインスタック</td>
<td><code>my-EcsPipelineStack</code></td>
</tr>
<tr>
<td>インフラスタック</td>
<td><strong><code>my-Deploy-WebappStack</code></strong></td>
</tr>
</tbody>
</table>
<blockquote>
<p><code>my-EcsPipelineStack</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>
<h3><span id="toc20">ALB の URL を確認する</span></h3>
<p><code>ALBEndpoint</code> の URL にブラウザでアクセスします。</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>
<p><strong>この時点では Tomcat のデフォルト画面（または 404）が表示されます。</strong><br />ECS タスクがプレースホルダーイメージ（公式 Tomcat）で起動しているためで、<strong>正常な状態</strong>です。<br />Spring Boot アプリのデプロイは <strong>⑨</strong> で実施します。</p>
<h3><span id="toc21">ECS コンソールで確認する</span></h3>
<p>ECS → クラスター → <code>my-cdk6-cluster</code> → サービス → <code>my-cdk6-service</code></p>
<p>「タスク」タブで 1 タスクが <strong>RUNNING</strong> になっていることを確認します。<br />「タスク定義」タブでリビジョンが <strong>1</strong>（プレースホルダー）になっていることを確認します。</p>
<p><!-- ![ECSコンソールでクラスターとサービスが確認できる画面](images/ecs-service-running.jpg) --></p>
<hr>
<h2><span id="toc22">⑧ GitHub Actions を設定する（OIDC + IAM ロール）</span></h2>
<p>Spring Boot アプリのデプロイを担う <strong>GitHub Actions</strong> を設定します。<br />OIDC 認証によりアクセスキーをリポジトリに保存せずに AWS を操作できます。</p>
<h3><span id="toc23">OIDC プロバイダーを登録する</span></h3>
<p>AWS コンソール → <strong>IAM</strong> → 左メニュー「<strong>IDプロバイダー</strong>」→「<strong>プロバイダーを追加</strong>」</p>
<table>
<thead>
<tr>
<th>項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>プロバイダータイプ</td>
<td><strong>OpenID Connect</strong></td>
</tr>
<tr>
<td>プロバイダー URL</td>
<td><code>https://token.actions.githubusercontent.com</code></td>
</tr>
<tr>
<td>対象者（Audience）</td>
<td><code>sts.amazonaws.com</code></td>
</tr>
</tbody>
</table>
<p>「プロバイダーを追加」ボタンをクリックして完了。</p>
<blockquote>
<p>URL と対象者を入力するだけでよいです（現在の UI ではサムプリントの手動取得は不要）。</p>
</blockquote>
<hr>
<h3><span id="toc24">IAM ロールを作成する（CloudShell）</span></h3>
<p><strong>AWS コンソール</strong> → 右上「<strong>CloudShell</strong>」アイコン → 以下を貼り付けて実行します。<br /><code>GITHUB_OWNER</code> を自分の GitHub ユーザー名に変更してください:</p>
<pre><code class="language-bash">ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
GITHUB_OWNER="your-github-username"   # ← 自分の GitHub ユーザー名に変更
REPO="aws-learning-projects"
ROLE_NAME="my-github-actions-role"

cat &gt; /tmp/trust-policy.json &lt;&lt; EOF
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/token.actions.githubusercontent.com"
    },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": {
        "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
      },
      "StringLike": {
        "token.actions.githubusercontent.com:sub": "repo:${GITHUB_OWNER}/${REPO}:ref:refs/heads/main"
      }
    }
  }]
}
EOF

aws iam create-role \
  --role-name $ROLE_NAME \
  --assume-role-policy-document file:///tmp/trust-policy.json

# 権限ポリシーを作成（ECR push + ECS deploy に必要な最小権限）
cat &gt; /tmp/permissions.json &lt;&lt; EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["ecr:GetAuthorizationToken"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ecr:BatchCheckLayerAvailability", "ecr:PutImage",
        "ecr:InitiateLayerUpload", "ecr:UploadLayerPart", "ecr:CompleteLayerUpload"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ecs:DescribeTaskDefinition", "ecs:RegisterTaskDefinition",
        "ecs:UpdateService", "ecs:DescribeServices"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["iam:PassRole"],
      "Resource": "*"
    }
  ]
}
EOF

aws iam put-role-policy \
  --role-name $ROLE_NAME \
  --policy-name "${ROLE_NAME}-policy" \
  --policy-document file:///tmp/permissions.json

echo "=== Role ARN（次の手順でコピー）==="
aws iam get-role --role-name $ROLE_NAME --query Role.Arn --output text</code></pre>
<p>出力された <strong>ロール ARN</strong>（<code>arn:aws:iam::...</code>）をコピーしておきます。</p>
<hr>
<h3><span id="toc25">GitHub Variables を設定する</span></h3>
<p>GitHub リポジトリ → <strong>Settings</strong> → <strong>Secrets and variables</strong> → <strong>Actions</strong> → <strong>「Variables」タブ</strong></p>
<p>「New repository variable」で以下の2つを追加します:</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>EMPLOYEE_ID</code></td>
<td><code>my</code>（cdk.json の employee_id と同じ値）</td>
</tr>
<tr>
<td><code>AWS_ROLE_ARN</code></td>
<td>IAM ロール作成で表示された ARN</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>Variables と Secrets の使い分け</strong>: ARN や EMPLOYEE_ID は機密情報ではないため <strong>Variables</strong> に保存します（Secrets は使いません）。</p>
</blockquote>
<hr>
<h3><span id="toc26">ワークフローファイルを push する</span></h3>
<p><code>.github/workflows/ecs-app-deploy.yml</code> は既にリポジトリに含まれています。<br />このファイルを push してワークフローをアクティブにします:</p>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects
git add .github/workflows/ecs-app-deploy.yml
git commit -m "feat: add GitHub Actions ECS deploy workflow"
git push</code></pre>
<blockquote>
<p>このワークフローは <code>paths</code> フィルターにより <code>app/</code> か <code>Dockerfile</code> が変わった時だけ起動します。<br />このコミットでは GitHub Actions はスキップされ、CDK Pipelines のみが起動（インフラ差分なしで数分で完了）します。</p>
</blockquote>
<p><!-- ![GitHub ActionsワークフローがActionsタブに表示されている画面](images/github-actions-workflow.jpg) --></p>
<hr>
<h2><span id="toc27">⑨ アプリを初回デプロイする（GitHub Actions）</span></h2>
<p>GitHub Actions の設定が完了したので、Spring Boot アプリを ECS に初めてデプロイします。</p>
<h3><span id="toc28">アプリのタイトルを変更する</span></h3>
<p><code>cdk-ecs-webapp/app/src/main/resources/templates/index.html</code> を開き、以下の行を変更します:</p>
<p>変更前:</p>
<pre><code class="language-html">&lt;h1&gt;Spring Boot + RDS Item Manager (ECS)&lt;/h1&gt;</code></pre>
<p>変更後:</p>
<pre><code class="language-html">&lt;h1&gt;Spring Boot + RDS Item Manager (ECS v2)&lt;/h1&gt;</code></pre>
<h3><span id="toc29">コミット＆プッシュ</span></h3>
<pre><code class="language-cmd">cd C:\my-aws\aws-learning-projects
git add cdk-ecs-webapp/app/src/main/resources/templates/index.html
git commit -m "feat: initial app deploy via GitHub Actions"
git push</code></pre>
<p><code>app/</code> の変更のため、<strong>GitHub Actions が起動</strong>します（CDK Pipelines も起動しますがインフラ差分なしで数分で完了）。</p>
<h3><span id="toc30">GitHub Actions の進行を確認する</span></h3>
<p>GitHub リポジトリ → <strong>Actions</strong> タブ → <code>Deploy App to ECS</code> ワークフローの進行を確認します。</p>
<table>
<thead>
<tr>
<th>ステップ</th>
<th>内容</th>
<th>時間目安</th>
</tr>
</thead>
<tbody>
<tr>
<td>Checkout</td>
<td>コード取得</td>
<td>〜10秒</td>
</tr>
<tr>
<td>Configure AWS credentials</td>
<td>OIDC 認証</td>
<td>〜10秒</td>
</tr>
<tr>
<td>Login to ECR</td>
<td>ECR ログイン</td>
<td>〜10秒</td>
</tr>
<tr>
<td>Build and push</td>
<td>docker build + ECR push</td>
<td>〜1〜2分</td>
</tr>
<tr>
<td>Update ECS task definition</td>
<td>タスク定義を新リビジョンに更新</td>
<td>〜10秒</td>
</tr>
<tr>
<td>Deploy to ECS</td>
<td>サービス更新 + 安定化待ち</td>
<td>〜2〜3分</td>
</tr>
</tbody>
</table>
<h3><span id="toc31">ブラウザで動作確認する</span></h3>
<p><code>Deploy to ECS</code> ステップが完了したら、ALB の URL にアクセスします。</p>
<p>「<strong>Spring Boot + RDS Item Manager (ECS v2)</strong>」の画面が表示されることを確認します。</p>
<blockquote>
<p><strong>ECS コンソールで確認</strong>: ECS → サービス → 「タスク」タブ<br />タスク定義のリビジョンが <strong>2</strong> 以上（GitHub Actions による更新後）になっていることを確認します。</p>
</blockquote>
<p><!-- ![GitHub Actionsのデプロイが完了してアプリ画面が表示されている画面](images/app-deployed-ecs.jpg) --></p>
<hr>
<h2><span id="toc32">⑩ ECS Exec でコンテナに接続する</span></h2>
<p>cdk-asg-webapp では SSM Session Manager で <strong>EC2</strong> に接続しましたが、ECS Fargate では <strong>ECS Exec</strong> でコンテナ内のシェルに直接接続できます。</p>
<h3><span id="toc33">実行中のタスク ARN を確認する</span></h3>
<pre><code class="language-cmd">aws ecs list-tasks ^
  --cluster my-cdk6-cluster ^
  --service-name my-cdk6-service ^
  --desired-status RUNNING ^
  --region ap-northeast-1 ^
  --query "taskArns" ^
  --output text</code></pre>
<p>出力例:</p>
<pre><code class="language-plaintext">arn:aws:ecs:ap-northeast-1:123456789012:task/my-cdk6-cluster/abcdef1234567890</code></pre>
<blockquote>
<p><strong>複数件表示される場合</strong>: ローリングデプロイ中は新旧2タスクが同時に動きます。<br />ECS コンソール → サービス → 「タスク」タブでリビジョン番号が大きい方（最新）の ARN を使ってください。</p>
</blockquote>
<h3><span id="toc34">コンテナに接続する</span></h3>
<pre><code class="language-cmd">aws ecs execute-command ^
  --cluster my-cdk6-cluster ^
  --task arn:aws:ecs:ap-northeast-1:123456789012:task/my-cdk6-cluster/abcdef1234567890 ^
  --container my-cdk6-app ^
  --interactive ^
  --command "/bin/sh" ^
  --region ap-northeast-1</code></pre>
<blockquote>
<p><strong>Session Manager Plugin が必要</strong>: 接続には AWS CLI の Session Manager Plugin が必要です。<br />インストール手順は <a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html">AWS 公式ドキュメント</a> を参照してください。</p>
</blockquote>
<h3><span id="toc35">コンテナ内で確認する</span></h3>
<pre><code class="language-sh"># 環境変数（DB接続情報）を確認
echo $DB_HOST
echo $DB_PASSWORD

# デプロイされた WAR を確認（ROOT.war として配置される）
ls /usr/local/tomcat/webapps/

# 接続を終了
exit</code></pre>
<blockquote>
<p><strong><code>catalina.out</code> は存在しません</strong>: Docker コンテナの Tomcat はファイルにログを書かず、<strong>stdout（標準出力）</strong> に直接出力します。ログは CloudWatch Logs に転送されます。</p>
<pre><code class="language-cmd">aws logs tail /ecs/my-cdk6-app ^
  --follow ^
  --region ap-northeast-1</code></pre>
<p>終了は <code>Ctrl+C</code>。</p>
</blockquote>
<hr>
<h2><span id="toc36">⑪ タスク数スケーリングを体験する</span></h2>
<p>cdk-asg-webapp では <code>stress-ng</code> で CPU 負荷をかけて自動スケールを体験しましたが、<br />ECS Fargate では <strong><code>desired_count</code> を直接変更する</strong>だけでスケールできます。</p>
<h3><span id="toc37">スケールアウト（1台 → 2台）</span></h3>
<pre><code class="language-cmd">aws ecs update-service ^
  --cluster my-cdk6-cluster ^
  --service my-cdk6-service ^
  --desired-count 2 ^
  --region ap-northeast-1</code></pre>
<p>ECS コンソール → サービス → 「タスク」タブで 2 タスクが RUNNING になることを確認します。<br />ALB がどちらのタスクにもリクエストを分散するようになります（ラウンドロビン）。</p>
<h3><span id="toc38">スケールイン（2台 → 1台）</span></h3>
<pre><code class="language-cmd">aws ecs update-service ^
  --cluster my-cdk6-cluster ^
  --service my-cdk6-service ^
  --desired-count 1 ^
  --region ap-northeast-1</code></pre>
<p>数分後に 1 タスクが停止し、1 台構成に戻ります。</p>
<blockquote>
<p><strong>ECS と ASG のスケーリング比較</strong></p>
<ul>
<li>ECS: <code>desired_count</code> を変更するだけ（コマンド一発、秒単位で反映）</li>
<li>ASG: CPU 閾値・CloudWatch アラーム・スケーリングポリシーが必要（設定が複雑）</li>
</ul>
<p>ECS Fargate はコンテナ単位なので起動が速く（30秒〜）、EC2 の起動を待つ ASG より素早くスケールできます。</p>
</blockquote>
<hr>
<h2><span id="toc39">⑫ リソースを削除する</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除します。</strong></p>
<blockquote>
<p><strong>削除順序が重要です</strong>。インフラスタック（<code>my-Deploy-WebappStack</code>）を<strong>先に</strong>削除してから、パイプラインスタック（<code>my-EcsPipelineStack</code>）を削除します。</p>
</blockquote>
<h3><span id="toc40">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="toc41">2. パイプラインスタックを削除する</span></h3>
<pre><code class="language-cmd">aws cloudformation delete-stack ^
  --stack-name my-EcsPipelineStack ^
  --region ap-northeast-1

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

echo EcsPipelineStack 削除完了</code></pre>
<h3><span id="toc42">3. GitHub Actions IAM ロールを削除する</span></h3>
<p>CloudFormation の管理外のため、手動で削除します:</p>
<pre><code class="language-cmd">aws iam delete-role-policy ^
  --role-name my-github-actions-role ^
  --policy-name my-github-actions-role-policy

aws iam delete-role ^
  --role-name my-github-actions-role</code></pre>
<h3><span id="toc43">4. SSM パラメータを削除する</span></h3>
<pre><code class="language-cmd">aws ssm delete-parameter ^
  --name "/my/cdk6/db-password" ^
  --region ap-northeast-1</code></pre>
<h3><span id="toc44">5. 仮想環境の終了</span></h3>
<pre><code class="language-cmd">deactivate</code></pre>
<h3><span id="toc45">6. GitHub との接続を削除する（オプション）</span></h3>
<p>次のハンズオンでも使う場合はそのままでよいです。</p>
<p><strong>CodePipeline → 設定 → 接続 → <code>my-github-connection</code> → 「削除」</strong></p>
<h3><span id="toc46">7. OIDC プロバイダーを削除する（オプション）</span></h3>
<p>他のリポジトリでも使う場合はそのままでよいです。<br />不要な場合は <strong>IAM → IDプロバイダー → <code>token.actions.githubusercontent.com</code> → 「削除」</strong></p>
<h3><span id="toc47">削除確認</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>
<hr>
<h2><span id="toc48">EC2 → コンテナへの移行ポイント</span></h2>
<pre><code class="language-plaintext">cdk-asg-webapp（EC2 + ASG）          cdk-ecs-webapp（ECS Fargate）
─────────────────────────────       ─────────────────────────────
Launch Template                     Dockerfile
  ↓ UserData（シェルスクリプト）        ↓ マルチステージビルド（20行）
Java インストール                     Maven → WAR → Tomcat（イメージ内）
Tomcat インストール
CodeDeploy エージェントインストール
  ↓                                   ↓
appspec.yml + scripts/*.sh           Dockerfile のみ
S3 → CodeDeploy → WAR デプロイ       ECR → ECS タスク更新 → ローリングデプロイ
  ↓                                   ↓
SSM Session Manager（EC2 に接続）     ECS Exec（コンテナに直接接続）
  ↓                                   ↓
CPU 自動スケール（ASG ポリシー）        desired_count を変更（コマンド一発）</code></pre>
<p><code>appspec.yml</code> / <code>scripts/*.sh</code> / UserData の複雑な設定が、<code>Dockerfile</code> の 20 行に集約されます。</p>
<hr>
<h2><span id="toc49">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Source</code> ステージが「失敗」</td>
<td>GitHub との接続が「保留中」</td>
<td>CodePipeline → 設定 → 接続 → 承認して「利用可能」にする</td>
</tr>
<tr>
<td>ECS タスクが <code>STOPPED</code> を繰り返す</td>
<td>プレースホルダーイメージの pull 失敗</td>
<td>ECS コンソール → 停止タスク → 「停止理由」を確認</td>
</tr>
<tr>
<td>GitHub Actions が失敗（OIDC エラー）</td>
<td>IAM ロールの信頼ポリシーが不正</td>
<td>GitHub Variables の <code>AWS_ROLE_ARN</code> と信頼ポリシーの <code>sub</code> を確認</td>
</tr>
<tr>
<td>GitHub Actions が失敗（ECR push）</td>
<td><code>ecr:GetAuthorizationToken</code> 権限不足</td>
<td>IAM ロールのポリシーを確認</td>
</tr>
<tr>
<td>アプリ画面が表示されない（404）</td>
<td>GitHub Actions がまだ実行されていない</td>
<td>Actions タブで <code>Deploy App to ECS</code> が完了するまで待つ</td>
</tr>
<tr>
<td>ECS Exec が接続できない</td>
<td><code>enable_execute_command</code> が未設定</td>
<td>ECS サービスの設定を確認（CDK で有効化済み）</td>
</tr>
<tr>
<td><code>Session Manager Plugin is not found</code></td>
<td>Plugin 未インストール</td>
<td>AWS 公式ドキュメントからインストール</td>
</tr>
<tr>
<td>RDS 接続エラー</td>
<td>DB_HOST / DB_PASSWORD が不正</td>
<td>CloudWatch Logs → <code>/ecs/my-cdk6-app</code> でログを確認</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc50">まとめ</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-asg-webapp 実施済みなら再利用）</td>
</tr>
<tr>
<td>③</td>
<td><code>cdk.json</code> を設定（<code>task_cpu / task_memory / desired_count</code>）</td>
</tr>
<tr>
<td>④</td>
<td><code>cdk-ecs-webapp/</code> 全体を GitHub に push</td>
</tr>
<tr>
<td>⑤</td>
<td><code>cdk deploy</code>（<strong>初回のみ手動</strong>）→ <code>my-EcsPipelineStack</code> 作成</td>
</tr>
<tr>
<td>⑥</td>
<td>CodePipeline → <code>my-cdk6-pipeline</code> が自動起動 → InfraDeploy（20分）完了まで待つ</td>
</tr>
<tr>
<td>⑦</td>
<td>ALB URL にアクセス（Tomcat のデフォルト画面）・ECS サービスが RUNNING を確認</td>
</tr>
<tr>
<td>⑧</td>
<td>OIDC プロバイダー登録 → IAM ロール作成 → GitHub Variables 設定 → workflow push</td>
</tr>
<tr>
<td>⑨</td>
<td><code>app/index.html</code> を変更して push → GitHub Actions が Docker build → ECR push → ECS deploy</td>
</tr>
<tr>
<td>⑩</td>
<td><code>ecs execute-command</code> でコンテナ内シェルに接続・環境変数や WAR を確認</td>
</tr>
<tr>
<td>⑪</td>
<td><code>update-service --desired-count 2</code> でスケールアウト → 1 に戻してスケールイン</td>
</tr>
<tr>
<td>⑫</td>
<td><code>delete-stack my-Deploy-WebappStack</code> → <code>delete-stack my-EcsPipelineStack</code> → IAM ロール・SSM 削除</td>
</tr>
</tbody>
</table>
<p>EC2 + CodeDeploy から ECS Fargate + GitHub Actions への移行で、<strong>EC2 の OS 管理・エージェント管理から解放</strong>され、<code>Dockerfile</code> 1ファイルにデプロイ設定が集約されることを体験できました。</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>、インフラ 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>、ASG でのオートスケーリングは <a href="https://caymezon.com/aws-handson-cdk-asg-webapp/">CDK + ASG ハンズオン</a> を参照してください。</p><p>The post <a href="https://caymezon.com/aws-handson-cdk-ecs-webapp/">CDK + ECS Fargate で Webアプリをコンテナ化する【EC2 からコンテナへの移行体験】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-cdk-ecs-webapp/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
