AWS CDK と ecspresso の組合せで AutoScaling までうまいことやる
CDK大好きちゃちいです。こんにちは。
これまではECS(Fargate)のデプロイもCDKで行っていたんですが、依存やら時間やらが気になるため、ecspressoを組み合わせてみたのですが、AutoScalingで躓いたのでその解決までの記録です
もし、もっといいやり方があるぞ!!という場合はお知らせください…
2023/08/10 時点
構成
- Fargate クラスタはCDK、サービスとタスクはecspressoでデプロイしたい
- AutoScalingはややこしいのでCDKで定義したい
- インフラ構築リポジトリ (AWS CDK)
- CloudFront, Fargateクラスタ, ECR その他諸々を構築
- ecspressoでデプロイするために SSM Parameter Store に必要な情報を出力する
- アプリケーションリポジトリ
- Dockerコンテナで実行
- こちらからインフラ構築リポジトリで用意したECRへPushしecspressoでサービスとタスクをデプロイしたい
- ecspressoのSSMプラグインを使い、Paramter Storeから読み込んでテンプレートファイルで呼び出す
躓いたところ
CDKのみで構築するのであれば、FargateService
(サービス) の autoScaleTaskCount()
メソッドから ScalableTaskCount
を作り、scaleOnSchedule()
やscaleOnMetric()
を使います。
今回は、サービスはecspressoでデプロイするため、FargateService.fromFargateServiceArn()
を使えばええやろ、と思っていました。
IFargateService
には AutoScale のメソッドは無い
つまり、以下のようなことはできません。
// ecspresso でデプロイされるサービスを取得
const serviceArn = `arn:aws:ecs:ap-northeast-1:${props.account}:service/${cluster.clusterName}/hoge-service`;
const service = FargateService.fromFargateServiceArn(this, 'FargateService', serviceArn);
// オートスケールの設定(をしたかった)
const autoScale = service.autoScaleTaskCount({
maxCapacity: 4,
minCapacity: 2,
});
// ...略 autoScale.scaleOnSchedule() など
ではどうするか?
autoScaleTaskCount()
がどこにどう実装されているか見てみる
基底クラスの BaseService
に実装されていました
どうも ScalableTaskCount
を new してあげれば良さそうで、パラメータも特別なものは無さそうです
コピーしてペー
makeAutoScalingRole()
によってロールも作成しているので、該当の実装も持ってきてしまいます
// ecspresso でデプロイされるサービスを取得
const serviceArn = `arn:aws:ecs:ap-northeast-1:${props.account}:service/${cluster.clusterName}/v2web`;
const service = FargateService.fromFargateServiceArn(this, 'FargateService', serviceArn);
const autoScale = new ScalableTaskCount(this, 'AutoScaling', {
maxCapacity: 4,
minCapacity: 2,
serviceNamespace: ServiceNamespace.ECS,
dimension: 'ecs:service:DesiredCount',
resourceId: `service/${cluster.clusterName}/hoge-service`,
role: iam.Role.fromRoleArn(this, 'ScalingRole', Stack.of(this).formatArn({
region: '',
service: 'iam',
resource: 'role/aws-service-role/ecs.application-autoscaling.amazonaws.com',
resourceName: 'AWSServiceRoleForApplicationAutoScaling_ECSService',
})),
})
// ...略 autoScale.scaleOnSchedule() など
これで ScalableTaskCount
の作成ができました
なお、お察しかと思いますが、サービスが作成されていない場合には 「そんな resourceId
ないぞ」というエラーでデプロイできないため、ecspressoで1回はサービスを作る必要があります
「初回実行かどうか(サービスが無いものとみなす)」オプション(--context
)などを用意すると良いでしょう
メトリックによるオートスケール
scaleOnMetric()
というメトリックに応じたオートスケールを定義できるメソッドがあります
props に metric
があり、CDKでサービスを定義した場合、以下のように指定できます
const service = new FargateService(/*...略...*/);
const autoScale = service.autoScaleTaskCount(/*...略...*/);
// CPU使用率を見てスケール
autoScale.scaleOnMetric('ScaleOnMetricByCpuUtilization', {
metric: serivce.metricCpuUtilization({
statistic: 'Maximum',
// 注: 名前空間が AWS/ から始まるメトリクスは1分以上でないといけない
period: cdk.Duration.seconds(60),
}),
// ... 略
});
CPU使用率の metricMemoryUtilization()
とメモリ使用率の metricMemoryUtilization()
が定義されていますが、前述のオートスケール周りと同様に、IFargateService
には実装されていません
metricCpuUtilization()
がどこにどう実装されているか見てみる
こちらも、BaseService
に実装されています
metric()
メソッドを呼び出しているだけで、この実装をコピペでいけそうです
コピーしてペー
// CPU使用率を見てスケール
autoScale.scaleOnMetric('ScaleOnMetricByCpuUtilization', {
metric: new aws_cloudwatch.Metric({
namespace: 'AWS/ECS',
metricName: 'CPUUtilization',
dimensionsMap: {
ClusterName: cluster.clusterName,
ServiceName: 'hoge-service'
},
statistic: 'Maximum',
// 注: 名前空間が AWS/ から始まるメトリクスは1分以上でないといけない
period: Duration.seconds(60),
}).attachTo(this),
// ... 略
});
これで、CDKだけで構築したときと同等になったはずです
まとめ
- もうちょっと整理して実装もできると思うのですが、動くもの(デプロイできるもの)としてはこれくらいでいいかなと
- AWS CDKはいいぞ
- ecspressoはいいぞ
Discussion