はじめに
従来の構成ではタスク数が固定のため、
- アクセスが増えると処理が追いつかず、レスポンスが遅くなる
- タスクが停止すると、そのままサービスが止まる
といった問題があります。
本記事では、ECS ServiceにAuto Scalingを設定し、
アクセス負荷に応じてタスク数を自動で増減できる構成を作成します。
本シリーズの構成
1. VPC編
2. Route53 独自ドメイン編
3. ACM HTTPS化編
4. WAFセキュリティ編
5. ECS Auto Scaling編(本記事)
6. CI/CD編
Auto Scaling適用後の構成
- 負荷に応じてECSタスク数が増減します
- ALBは複数のECSタスクにリクエストを分散します
前提条件
本記事は、本シリーズの前回までの手順を実施し、
以下の状態になっていることを前提としています。
- ECS Service が作成されている
- ALB 経由でアプリにアクセスできる
5-1. ServiceStackを修正する
対象ファイル
lib/service-stack.ts
ECS ServiceにAuto Scaling設定を追加します。
今回はCPU使用率を基準としたスケーリングを設定します。
const scalableTarget = service.autoScaleTaskCount({
minCapacity: 1,
maxCapacity: 3,
});
ポイント
- 最小1台(ゼロにはしない)
- 最大3台までスケール
- 無制限に増やすとコストが増えるため、必ず上限を設定します
続いて、CPUベースのスケーリングポリシーを追加します。
scalableTarget.scaleOnCpuUtilization('CpuScaling', {
targetUtilizationPercent: 50,
scaleInCooldown: cdk.Duration.seconds(60),
scaleOutCooldown: cdk.Duration.seconds(60),
});
ポイント
-
targetUtilizationPercent
CPU使用率50%を維持するように調整 -
scaleInCooldown / scaleOutCooldown
連続スケーリングを防ぐための待機時間を設定
5-2. デプロイ
cdk deploy NextjsInfraServiceStack --profile <プロファイル名>
本記事で作成したスタックに含まれるAWSリソースは、削除するまで料金が発生します。
検証が不要になった場合は、以下のコマンドでスタックを削除してください。
cdk destroy <スタック名> --profile <プロファイル名>
5-3. 確認
設定が正しく反映されていることの確認を行います。
Auto Scaling設定の確認
AWSコンソール → ECS → 対象のクラスター → 対象のサービスを選択し、
「サービスの自動スケーリング」タブを開きます。
① タスク数を確認
以下のように、タスク数の範囲が表示されていることを確認します。
<サービス名> の実行タスク数
1 - 3
最小タスク数(minCapacity):1
最大タスク数(maxCapacity):3
② スケーリングポリシーを確認
「スケーリングポリシー」欄に、以下の内容が表示されていればOKです。
タイプ:ターゲット追跡
ステータス:アクティブ
ターゲットメトリクス:ECSServiceAverageCPUUtilization(50%)
ターゲット追跡ポリシーは、CPU使用率(今回は50%)を維持するように、
タスク数を自動で増減させる仕組みです。
最終コード(今回追加・修正したファイル)
lib/service-stack.ts
コード全体
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
interface ServiceStackProps extends cdk.StackProps {
cluster: ecs.Cluster;
taskDefinition: ecs.FargateTaskDefinition;
targetGroup: elbv2.ApplicationTargetGroup;
vpc: ec2.IVpc;
albSecurityGroup: ec2.SecurityGroup;
}
export class ServiceStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: ServiceStackProps) {
super(scope, id, props);
const serviceSg = new ec2.SecurityGroup(this, 'ServiceSecurityGroup', {
vpc: props.vpc,
allowAllOutbound: true,
});
serviceSg.addIngressRule(
props.albSecurityGroup,
ec2.Port.tcp(3000),
'Allow traffic from ALB'
);
const service = new ecs.FargateService(this, 'NextjsService', {
cluster: props.cluster,
taskDefinition: props.taskDefinition,
desiredCount: 1,
assignPublicIp: false,
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
securityGroups: [serviceSg],
});
service.attachToApplicationTargetGroup(props.targetGroup);
const scalableTarget = service.autoScaleTaskCount({
minCapacity: 1,
maxCapacity: 3,
});
scalableTarget.scaleOnCpuUtilization('CpuScaling', {
targetUtilizationPercent: 50,
scaleInCooldown: cdk.Duration.seconds(60),
scaleOutCooldown: cdk.Duration.seconds(60),
});
}
}
ここまでの成果
負荷に応じてタスク数を自動で増減できるようになりました。
これにより、スケーラブルな構成となり、負荷増加にも対応できる基盤が整いました。
次回
次回はCI/CDを構築し、コード変更を自動でデプロイできるようにします。