CDK + ECS Fargate で Webアプリをコンテナ化する【EC2 からコンテナへの移行体験】

AWS Basic
スポンサーリンク
スポンサーリンク
  1. はじめに
  2. キーワード解説
  3. cdk-asg-webapp との比較
  4. ファイル構成と役割
  5. 使用するAWSサービス
  6. 前提条件
  7. 作業順序
  8. ① プロジェクトのセットアップ
  9. ② GitHub との接続を設定する(CodeConnections)
    1. 接続を作成する
    2. GitHub App をインストールする
    3. 接続 ARN を確認する
  10. ③ cdk.json の設定
  11. ④ コードを GitHub にプッシュする(重要!)
  12. ⑤ パイプラインスタックのデプロイ(初回のみ)
  13. ⑥ パイプラインの実行状況を確認する
    1. CloudFormation スタックの命名規則
    2. CloudFormation Outputs の確認
  14. ⑦ インフラを確認する
    1. ALB の URL を確認する
    2. ECS コンソールで確認する
  15. ⑧ GitHub Actions を設定する(OIDC + IAM ロール)
    1. OIDC プロバイダーを登録する
    2. IAM ロールを作成する(CloudShell)
    3. GitHub Variables を設定する
    4. ワークフローファイルを push する
  16. ⑨ アプリを初回デプロイする(GitHub Actions)
    1. アプリのタイトルを変更する
    2. コミット&プッシュ
    3. GitHub Actions の進行を確認する
    4. ブラウザで動作確認する
  17. ⑩ ECS Exec でコンテナに接続する
    1. 実行中のタスク ARN を確認する
    2. コンテナに接続する
    3. コンテナ内で確認する
  18. ⑪ タスク数スケーリングを体験する
    1. スケールアウト(1台 → 2台)
    2. スケールイン(2台 → 1台)
  19. ⑫ リソースを削除する
    1. 1. インフラスタックを削除する
    2. 2. パイプラインスタックを削除する
    3. 3. GitHub Actions IAM ロールを削除する
    4. 4. SSM パラメータを削除する
    5. 5. 仮想環境の終了
    6. 6. GitHub との接続を削除する(オプション)
    7. 7. OIDC プロバイダーを削除する(オプション)
    8. 削除確認
  20. EC2 → コンテナへの移行ポイント
  21. トラブルシューティング
  22. まとめ

はじめに

「EC2 の OS パッチや Tomcat のインストール設定が面倒」「スケールアウト時のインスタンス管理が複雑」——これを解決するのが ECS Fargate(サーバーレスコンテナ) です。

この記事では、ASG ハンズオン(cdk-asg-webapp)で構築した EC2 + Auto Scaling Group 構成を、ECS Fargate + Docker コンテナにアップグレードします。EC2 の代わりに Docker コンテナで Spring Boot アプリを動かし、GitHub Actions がコンテナイメージをビルドして ECS へ自動デプロイする仕組みを体験します。

【インフラ担当】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

このハンズオンで体験できること:

  • Docker のマルチステージビルド(Maven → WAR → Tomcat コンテナ)
  • ECR へのイメージプッシュと ECS Fargate でのコンテナ実行
  • GitHub Actions(OIDC 認証)による Docker ビルド → ECR プッシュ → ECS ローリングデプロイ
  • インフラ(CDK Pipelines)とアプリ(GitHub Actions)のデプロイを分離した実務パターン
  • ECS Exec でコンテナ内のシェルに直接接続するデバッグ体験
  • desired_count を変更するだけのシンプルなスケーリング体験

この記事は CDK + Auto Scaling Group ハンズオン(cdk-asg-webapp) の発展記事です。
cdk-asg-webapp を体験済みの方向けです(cdk-webapp-pipeline 完了でも OK)。コード詳細は GitHub を参照してください。


-->

スポンサーリンク

キーワード解説

用語意味
Docker / Dockerfileアプリとその実行環境をひとまとめにした「コンテナ」を作成する仕組み。Dockerfile にビルド手順を記述する
マルチステージビルドビルド環境(Maven)と実行環境(Tomcat)を分離して軽量なイメージを作成するテクニック
ECR(Elastic Container Registry)Docker イメージを保管する AWS マネージドレジストリ。EC2 構成での S3 バケットに相当する
ECS FargateEC2 なしでコンテナを実行できるサーバーレス実行環境。OS 管理・パッチ適用が不要
タスク定義コンテナの CPU・メモリ・環境変数・IAM ロールなどを定義する設定
ECS Serviceタスクのスケーリング・ヘルスチェック・ALB 連携・ローリングデプロイを管理する
ローリングデプロイ旧コンテナを停止しながら新コンテナを順次起動する無停止デプロイ
ECS Execコンテナ内のシェルに AWS CLI から直接アクセスするデバッグ機能。EC2 の SSM Session Manager に相当
OIDC 認証アクセスキーをリポジトリに保存せず、GitHub Actions から AWS を操作できるキーレス認証
インフラ/アプリ分離デプロイCDK Pipelines(インフラ)と GitHub Actions(アプリ)で役割を分担する実務パターン

スポンサーリンク

cdk-asg-webapp との比較

比較項目cdk-asg-webappcdk-ecs-webapp
実行環境EC2(Launch Template + ASG)ECS Fargate(サーバーレスコンテナ)
デプロイ形式WAR → S3 → CodeDeployDocker Image → ECR → ECS タスク更新
インフラ管理EC2 OS パッチ・エージェント管理が必要サーバーレス(EC2 管理不要)
スケーリングCPU 自動スケール(ASG ポリシー)desired_count を直接変更(シンプル)
デバッグ接続SSM Session Manager(EC2 に接続)ECS Exec(コンテナに直接接続)
アプリ設定ファイルappspec.yml + scripts/Dockerfile のみ
アプリデプロイ担当CDK Pipelines 内の CodeDeployGitHub Actions

ファイル構成と役割

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
ファイルcdk-asg-webapp との主な違い
Dockerfile新規追加。マルチステージビルドで Maven → WAR → Tomcat コンテナを作成
webapp_construct.pyAutoScalingGroup + LaunchTemplateFargateService + TaskDefinition + ECR
webapp_stack.pyASGName 等の出力を廃止 → ECRRepoUri / ECSClusterName / ECSServiceName を追加
pipeline_stack.pyBuildAndDeployApp(CodeDeploy)を廃止 → インフラ変更のみ担当

詳細なコードは GitHub を参照してください。


使用するAWSサービス

サービス役割料金
VPCカスタムネットワーク空間無料
ECS Fargate(0.25 vCPU / 512 MiB)Spring Boot コンテナを実行するサーバーレス環境約$0.01/時間(無料枠なし
RDS MySQL(db.t3.micro)マネージドDBサーバ月750時間まで無料枠あり
ALBロードバランサー約$0.008/時間 + LCU料金(無料枠なし
ECRDocker イメージの保管場所500MB/月まで無料
CodePipelineCI/CD パイプライン管理(インフラ側)月1パイプラインまで無料枠あり
CodeBuildcdk synth を実行するビルド環境月100分まで無料枠あり
S3パイプラインのアーティファクト置き場無料枠あり
SSM Parameter StoreDBパスワードの安全な管理・ECS への環境変数注入スタンダード層無料
CloudWatch Logsコンテナのログ出力先無料枠あり
IAM各サービスの権限無料

注意: ECS Fargate と ALB は無料枠がありません。ハンズオン後は必ずリソースを削除してください。


前提条件

ツール確認コマンド
AWS CLI v2aws --version
Java 17java -version
Mavenmvn -version
Python 3.9 以上python --version
Node.js 18 以上node --version
CDK CLIcdk --version
Gitgit --version

Docker Desktop は不要です。コンテナのビルドは GitHub Actions runner 上(Ubuntu)で実行されるため、ローカル PC に Docker をインストールする必要はありません。

AWS 認証確認:

aws sts get-caller-identity

CDK Bootstrap 確認:

aws cloudformation describe-stacks ^
  --stack-name CDKToolkit ^
  --query "Stacks[0].StackStatus" ^
  --output text ^
  --region ap-northeast-1

作業順序

① プロジェクトのセットアップ(Python 仮想環境)
      ↓
② GitHub との接続を設定する(CodeConnections)
      ↓
③ cdk.json の設定
      ↓
④ コードを GitHub にプッシュする(重要!)
      ↓
⑤ パイプラインスタックのデプロイ(初回のみ手動)
      ↓
⑥ パイプラインの実行状況を確認する
      ↓
⑦ インフラを確認する
      ↓
⑧ GitHub Actions を設定する(OIDC + IAM ロール)
      ↓
⑨ アプリを初回デプロイする
      ↓
⑩ ECS Exec でコンテナに接続する
      ↓
⑪ タスク数スケーリングを体験する
      ↓
⑫ リソースを削除する

① プロジェクトのセットアップ

cd C:\my-aws\aws-learning-projects\cdk-ecs-webapp

python -m venv .venv

.venv\Scripts\activate

pip install -r requirements.txt

プロンプトの先頭に (.venv) が表示されれば仮想環境が有効になっています。

重要: CDK コマンドはすべてこの仮想環境が有効な状態で実行する必要があります。
ターミナルを開き直した際は必ず最初に以下を実行してください。

cd C:\my-aws\aws-learning-projects\cdk-ecs-webapp
.venv\Scripts\activate

② GitHub との接続を設定する(CodeConnections)

cdk-asg-webapp(または cdk-webapp-pipeline)を実施済みの場合: 同じリポジトリを扱うため、
既存の接続(my-github-connection)をそのまま再利用できます。
② はスキップして、ARN の確認(②-4)から始めてください。

CodePipeline が GitHub リポジトリを監視するために、GitHub との接続(CodeConnections) を作成します。

重要: AWS コンソールと GitHub の操作は同じブラウザで行ってください。

接続を作成する

  1. AWS コンソール検索(Alt+S)で CodePipeline と入力 → CodePipeline を開く
  2. 左サイドバー → 「設定」「接続」
  3. リージョンが 東京(ap-northeast-1) になっていることを確認する
  4. 接続を作成」をクリック
  5. プロバイダー: GitHub を選択
  6. 接続名: my-github-connection(任意)
  7. GitHub に接続する」をクリック

GitHub App をインストールする

  1. Authorize」をクリック → AWS コンソールの「GitHub 接続設定」画面に自動で戻る
  2. 新しいアプリをインストールする」をクリック
  3. 「Only select repositories」 を選択 → aws-learning-projects を追加
  4. Install & Authorize」をクリック
  5. AWS コンソールに自動でリダイレクトされる → 「接続」ボタンをクリック

接続 ARN を確認する

接続一覧から接続の ARN をコピーします。

arn:aws:codeconnections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

ステータスが 「利用可能」 になっていることを確認してから次に進んでください。

控えておく情報: 接続 ARN(arn:aws:codeconnections:...


③ cdk.json の設定

cdk.jsoncontext セクションを自分の環境に合わせて編集します。

{
  "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:..."
  }
}
設定項目説明
employee_idmyリソース名のプレフィックス(my-cdk6-xxx という名前になる)
task_cpu256Fargate タスクの CPU ユニット(256 = 0.25 vCPU)
task_memory512Fargate タスクのメモリ(MiB)
desired_count1ECS サービスの起動タスク数
github_ownerGitHub ユーザー名リポジトリのオーナー名
connection_arn②で確認した ARNCodeConnections の接続 ARN

task_cputask_memory の組み合わせ制限(Fargate の仕様)
CPU と Memory には決まった組み合わせがあります。256 CPU の場合、Memory は 512〜2048(512 単位)が有効です。


④ コードを GitHub にプッシュする(重要!)

cdk deploy の前に必ずプロジェクト全体を push してください。
パイプラインが cdk synth を実行する際、GitHub から取得したコードを使うためです。

cd C:\my-aws\aws-learning-projects

git add cdk-ecs-webapp/
git commit -m "feat: cdk-ecs-webapp ハンズオンを追加"
git push origin main

GitHub Actions も同時に起動する場合: app/ または Dockerfile の変更が含まれていると GitHub Actions(Deploy App to ECS)も起動しますが、この時点では ECS サービスがまだ存在しないため失敗します。インフラが完成してから で改めてアプリをデプロイします。


⑤ パイプラインスタックのデプロイ(初回のみ)

cd C:\my-aws\aws-learning-projects\cdk-ecs-webapp

.venv\Scripts\activate

cdk synth

cdk deploy

「Do you wish to deploy these changes?」に y を入力します。

my-EcsPipelineStack が作成され、以降は GitHub push で自動デプロイされます。

所要時間: パイプラインスタック自体のデプロイは 3〜5 分。その後パイプラインが自動起動します。

デプロイ完了後、CodePipeline が自動起動します:

ステージ内容所要時間
SourceGitHub から最新コードを取得〜1分
Build (Synth)cdk synth でテンプレート生成〜3分
UpdatePipelineパイプライン自己更新(セルフミューテーション)〜2分
Deploy > InfraDeployCloudFormation で VPC / ECR / ECS / RDS / ALB を構築〜20分

初回の InfraDeploy に 20 分程度かかる理由: RDS の起動と ECS サービスの安定化(プレースホルダーコンテナの起動確認)に時間がかかります。


⑥ パイプラインの実行状況を確認する

  1. AWS コンソール → CodePipeline を開く
  2. my-cdk6-pipeline を選択
  3. 各ステージが 「成功」 になるまで待つ

CloudFormation スタックの命名規則

要素このハンズオンでの値
パイプラインスタックmy-EcsPipelineStack
インフラスタックmy-Deploy-WebappStack

my-EcsPipelineStack(パイプライン)と my-Deploy-WebappStack(インフラ)の 2つが別スタックとして CloudFormation に表示されます。

CloudFormation Outputs の確認

aws cloudformation describe-stacks ^
  --stack-name my-Deploy-WebappStack ^
  --region ap-northeast-1 ^
  --query "Stacks[0].Outputs"

控えておく情報: ALBEndpointRDSEndpoint


⑦ インフラを確認する

ALB の URL を確認する

ALBEndpoint の URL にブラウザでアクセスします。

aws cloudformation describe-stacks ^
  --stack-name my-Deploy-WebappStack ^
  --region ap-northeast-1 ^
  --query "Stacks[0].Outputs[?OutputKey=='ALBEndpoint'].OutputValue" ^
  --output text

この時点では Tomcat のデフォルト画面(または 404)が表示されます。
ECS タスクがプレースホルダーイメージ(公式 Tomcat)で起動しているためで、正常な状態です。
Spring Boot アプリのデプロイは で実施します。

ECS コンソールで確認する

ECS → クラスター → my-cdk6-cluster → サービス → my-cdk6-service

「タスク」タブで 1 タスクが RUNNING になっていることを確認します。
「タスク定義」タブでリビジョンが 1(プレースホルダー)になっていることを確認します。


⑧ GitHub Actions を設定する(OIDC + IAM ロール)

Spring Boot アプリのデプロイを担う GitHub Actions を設定します。
OIDC 認証によりアクセスキーをリポジトリに保存せずに AWS を操作できます。

OIDC プロバイダーを登録する

AWS コンソール → IAM → 左メニュー「IDプロバイダー」→「プロバイダーを追加

項目
プロバイダータイプOpenID Connect
プロバイダー URLhttps://token.actions.githubusercontent.com
対象者(Audience)sts.amazonaws.com

「プロバイダーを追加」ボタンをクリックして完了。

URL と対象者を入力するだけでよいです(現在の UI ではサムプリントの手動取得は不要)。


IAM ロールを作成する(CloudShell)

AWS コンソール → 右上「CloudShell」アイコン → 以下を貼り付けて実行します。
GITHUB_OWNER を自分の GitHub ユーザー名に変更してください:

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 > /tmp/trust-policy.json << 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 > /tmp/permissions.json << 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

出力された ロール ARNarn:aws:iam::...)をコピーしておきます。


GitHub Variables を設定する

GitHub リポジトリ → SettingsSecrets and variablesActions「Variables」タブ

「New repository variable」で以下の2つを追加します:

NameValue
EMPLOYEE_IDmy(cdk.json の employee_id と同じ値)
AWS_ROLE_ARNIAM ロール作成で表示された ARN

Variables と Secrets の使い分け: ARN や EMPLOYEE_ID は機密情報ではないため Variables に保存します(Secrets は使いません)。


ワークフローファイルを push する

.github/workflows/ecs-app-deploy.yml は既にリポジトリに含まれています。
このファイルを push してワークフローをアクティブにします:

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

このワークフローは paths フィルターにより app/Dockerfile が変わった時だけ起動します。
このコミットでは GitHub Actions はスキップされ、CDK Pipelines のみが起動(インフラ差分なしで数分で完了)します。


⑨ アプリを初回デプロイする(GitHub Actions)

GitHub Actions の設定が完了したので、Spring Boot アプリを ECS に初めてデプロイします。

アプリのタイトルを変更する

cdk-ecs-webapp/app/src/main/resources/templates/index.html を開き、以下の行を変更します:

変更前:

<h1>Spring Boot + RDS Item Manager (ECS)</h1>

変更後:

<h1>Spring Boot + RDS Item Manager (ECS v2)</h1>

コミット&プッシュ

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

app/ の変更のため、GitHub Actions が起動します(CDK Pipelines も起動しますがインフラ差分なしで数分で完了)。

GitHub Actions の進行を確認する

GitHub リポジトリ → Actions タブ → Deploy App to ECS ワークフローの進行を確認します。

ステップ内容時間目安
Checkoutコード取得〜10秒
Configure AWS credentialsOIDC 認証〜10秒
Login to ECRECR ログイン〜10秒
Build and pushdocker build + ECR push〜1〜2分
Update ECS task definitionタスク定義を新リビジョンに更新〜10秒
Deploy to ECSサービス更新 + 安定化待ち〜2〜3分

ブラウザで動作確認する

Deploy to ECS ステップが完了したら、ALB の URL にアクセスします。

Spring Boot + RDS Item Manager (ECS v2)」の画面が表示されることを確認します。

ECS コンソールで確認: ECS → サービス → 「タスク」タブ
タスク定義のリビジョンが 2 以上(GitHub Actions による更新後)になっていることを確認します。


⑩ ECS Exec でコンテナに接続する

cdk-asg-webapp では SSM Session Manager で EC2 に接続しましたが、ECS Fargate では ECS Exec でコンテナ内のシェルに直接接続できます。

実行中のタスク ARN を確認する

aws ecs list-tasks ^
  --cluster my-cdk6-cluster ^
  --service-name my-cdk6-service ^
  --desired-status RUNNING ^
  --region ap-northeast-1 ^
  --query "taskArns" ^
  --output text

出力例:

arn:aws:ecs:ap-northeast-1:123456789012:task/my-cdk6-cluster/abcdef1234567890

複数件表示される場合: ローリングデプロイ中は新旧2タスクが同時に動きます。
ECS コンソール → サービス → 「タスク」タブでリビジョン番号が大きい方(最新)の ARN を使ってください。

コンテナに接続する

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

Session Manager Plugin が必要: 接続には AWS CLI の Session Manager Plugin が必要です。
インストール手順は AWS 公式ドキュメント を参照してください。

コンテナ内で確認する

# 環境変数(DB接続情報)を確認
echo $DB_HOST
echo $DB_PASSWORD

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

# 接続を終了
exit

catalina.out は存在しません: Docker コンテナの Tomcat はファイルにログを書かず、stdout(標準出力) に直接出力します。ログは CloudWatch Logs に転送されます。

aws logs tail /ecs/my-cdk6-app ^
  --follow ^
  --region ap-northeast-1

終了は Ctrl+C


⑪ タスク数スケーリングを体験する

cdk-asg-webapp では stress-ng で CPU 負荷をかけて自動スケールを体験しましたが、
ECS Fargate では desired_count を直接変更するだけでスケールできます。

スケールアウト(1台 → 2台)

aws ecs update-service ^
  --cluster my-cdk6-cluster ^
  --service my-cdk6-service ^
  --desired-count 2 ^
  --region ap-northeast-1

ECS コンソール → サービス → 「タスク」タブで 2 タスクが RUNNING になることを確認します。
ALB がどちらのタスクにもリクエストを分散するようになります(ラウンドロビン)。

スケールイン(2台 → 1台)

aws ecs update-service ^
  --cluster my-cdk6-cluster ^
  --service my-cdk6-service ^
  --desired-count 1 ^
  --region ap-northeast-1

数分後に 1 タスクが停止し、1 台構成に戻ります。

ECS と ASG のスケーリング比較

  • ECS: desired_count を変更するだけ(コマンド一発、秒単位で反映)
  • ASG: CPU 閾値・CloudWatch アラーム・スケーリングポリシーが必要(設定が複雑)

ECS Fargate はコンテナ単位なので起動が速く(30秒〜)、EC2 の起動を待つ ASG より素早くスケールできます。


⑫ リソースを削除する

課金を止めるために、ハンズオン完了後は必ず削除します。

削除順序が重要です。インフラスタック(my-Deploy-WebappStack)を先に削除してから、パイプラインスタック(my-EcsPipelineStack)を削除します。

1. インフラスタックを削除する

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 削除完了

RDS の削除に 10〜15 分かかります。wait コマンドが完了するまでそのまま待ってください。

2. パイプラインスタックを削除する

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 削除完了

3. GitHub Actions IAM ロールを削除する

CloudFormation の管理外のため、手動で削除します:

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

4. SSM パラメータを削除する

aws ssm delete-parameter ^
  --name "/my/cdk6/db-password" ^
  --region ap-northeast-1

5. 仮想環境の終了

deactivate

6. GitHub との接続を削除する(オプション)

次のハンズオンでも使う場合はそのままでよいです。

CodePipeline → 設定 → 接続 → my-github-connection → 「削除」

7. OIDC プロバイダーを削除する(オプション)

他のリポジトリでも使う場合はそのままでよいです。
不要な場合は IAM → IDプロバイダー → token.actions.githubusercontent.com → 「削除」

削除確認

aws cloudformation list-stacks ^
  --region ap-northeast-1 ^
  --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE ^
  --query "StackSummaries[?contains(StackName, 'my-')].StackName"

空のリスト [] が返れば削除完了です。


EC2 → コンテナへの移行ポイント

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 を変更(コマンド一発)

appspec.yml / scripts/*.sh / UserData の複雑な設定が、Dockerfile の 20 行に集約されます。


トラブルシューティング

症状原因対処
Source ステージが「失敗」GitHub との接続が「保留中」CodePipeline → 設定 → 接続 → 承認して「利用可能」にする
ECS タスクが STOPPED を繰り返すプレースホルダーイメージの pull 失敗ECS コンソール → 停止タスク → 「停止理由」を確認
GitHub Actions が失敗(OIDC エラー)IAM ロールの信頼ポリシーが不正GitHub Variables の AWS_ROLE_ARN と信頼ポリシーの sub を確認
GitHub Actions が失敗(ECR push)ecr:GetAuthorizationToken 権限不足IAM ロールのポリシーを確認
アプリ画面が表示されない(404)GitHub Actions がまだ実行されていないActions タブで Deploy App to ECS が完了するまで待つ
ECS Exec が接続できないenable_execute_command が未設定ECS サービスの設定を確認(CDK で有効化済み)
Session Manager Plugin is not foundPlugin 未インストールAWS 公式ドキュメントからインストール
RDS 接続エラーDB_HOST / DB_PASSWORD が不正CloudWatch Logs → /ecs/my-cdk6-app でログを確認

まとめ

ステップ内容
Python 仮想環境のセットアップ
CodeConnections で GitHub との接続を作成(cdk-asg-webapp 実施済みなら再利用)
cdk.json を設定(task_cpu / task_memory / desired_count
cdk-ecs-webapp/ 全体を GitHub に push
cdk deploy初回のみ手動)→ my-EcsPipelineStack 作成
CodePipeline → my-cdk6-pipeline が自動起動 → InfraDeploy(20分)完了まで待つ
ALB URL にアクセス(Tomcat のデフォルト画面)・ECS サービスが RUNNING を確認
OIDC プロバイダー登録 → IAM ロール作成 → GitHub Variables 設定 → workflow push
app/index.html を変更して push → GitHub Actions が Docker build → ECR push → ECS deploy
ecs execute-command でコンテナ内シェルに接続・環境変数や WAR を確認
update-service --desired-count 2 でスケールアウト → 1 に戻してスケールイン
delete-stack my-Deploy-WebappStackdelete-stack my-EcsPipelineStack → IAM ロール・SSM 削除

EC2 + CodeDeploy から ECS Fargate + GitHub Actions への移行で、EC2 の OS 管理・エージェント管理から解放され、Dockerfile 1ファイルにデプロイ設定が集約されることを体験できました。

コンソールで3層構成を視覚的に学びたい場合は AWSコンソール版ハンズオン、CDK の基本は CDK版ハンズオン(cdk-alb-ec2-rds)、インフラ CI/CD は CDK Pipelines ハンズオン、アプリ CI/CD は CDK + CodeDeploy ハンズオン、ASG でのオートスケーリングは CDK + ASG ハンズオン を参照してください。

コメント