少し前、アプリケーションをAPI Gateway + Lambda構成からELB(ALB) + ECS on Fargate構成に置き換えました。理由は、Lambdaの同時実行数を超えるほどのトラフィックが発生して、より安定したスケーリングが必要になったからです。
ECS on Fargateへの移行後、負荷への耐性は向上したのですが、Lambdaと比べると常時課金されるELBやFargateのコストが増加し、新しい悩みの種になってしまいました。
今回の記事では、コスト削減のために行ったいくつかの施策をまとめました。
1. 開発環境のリソースを最小限に抑える
Fargateの料金は、使用するvCPUとメモリのサイズに応じて課金されます。そのため、トラフィックが少ない開発環境では、リソースを最小限に抑えることでコスト削減が可能です。今回は、最低限のスペックとして256(.25 vCPU), 512 MiB
を設定しました。
設定例:
タスク定義のcpu
とmemory
を以下のように設定します。
"cpu": 256,
"memory": 512,
開発環境のリソース要件が軽い場合、これにより大幅なコスト削減が期待できます。
2. Fargate Spotを利用する
Fargate Spotは通常のFargateよりも最大70 %安く利用できるため、開発環境ではFargate Spotを採用しました。本番環境では安定性を重視して通常のFargateを引き続き使用していますが、非本番環境でのコスト削減にはFargate Spotが有効です。
ECSサービスのコンピューティング設定で、以下のようにキャパシティープロバイダーを設定します。
設定例:
- キャパシティープロバイダー:
FARGATE_SPOT
- ベース:
1
- ウエイト:
2
- ベース:
- キャパシティープロバイダー:
FARGATE
- ベース:
0
- ウエイト:
1
- ベース:
設定の意図
Fargate Spotは通常のFargateに比べて大幅にコスト削減が可能ですが、SpotインスタンスはAWSの判断で突然停止する可能性があります。このため、開発環境など安定性をあまり重視しない環境ではFargate Spotのみで十分です。しかし、必要に応じて安定性を担保するために通常のFargateをフォールバックとして設定しています。
以上の設定例では、Spotインスタンスを優先的に使用し、万が一Spotが利用できない場合には通常のFargateを自動的に使用するようにしています。ベースの値を0
に設定することで、Spotが利用できない際にのみ通常のFargateが利用されるようになります。
もしリスクを許容できるなら、Fargate Spotのみを使う設定にして、さらにコスト削減を狙うことも可能です。
- キャパシティープロバイダー:
FARGATE_SPOT
- ベース:
1
- ウエイト:
1
- ベース:
この設定では、Fargate Spotのみを使用し、Spotインスタンスの停止リスクを完全に許容する構成となります。
3. 開発環境の夜間・休日停止
Fargateは使用時間に応じて課金されるため、開発環境のように稼働時間が限定される場合は、夜間や休日にタスクを停止することがコスト削減に直結します。
ECSタスクのスケジューリングには、EventBridgeとLambdaを使用したスケジュール設定を活用しました。この方法を使えば、稼働しない時間帯に自動でタスクを停止し、コストを削減することができます。
以下が以前書いた記事です。
4. コンテナアーキテクチャのArm化
Fargateでの料金はアーキテクチャにも依存します。x86_64
からGravitonベースのArm
に変更することで、料金を約20 %削減することが可能です。
Gravitonは、AWSが独自に開発したArmベースのプロセッサで、より低コストで優れたパフォーマンスを提供します。
さらに、2024/9からはFargate SpotでもArmが利用可能になったので、開発環境でもArm
アーキテクチャを採用しました。
CI/CDパイプラインでのクロスコンパイル設定:
CI/CDワークフローにおいて、docker buildx
を使ったクロスコンパイルを行うことで、簡単にArm
アーキテクチャに対応したDockerイメージをビルドできます。以下が設定例です。
- name: Set up QEMU
run: docker run --privileged --rm tonistiigi/binfmt --install all
- name: Set up Docker Buildx
run: docker buildx create --use
- name: Build Docker Image
run: docker buildx build --platform linux/arm64 --build-arg ENV=${{ env.ENV }} -t ${{ env.REPOSITORY_URI }}:${{ github.sha }} -f ./backend/Dockerfile.ecs ./backend --load
ここで、--platform linux/arm64
オプションを指定することで、Arm
アーキテクチャ向けにビルドされます。docker buildx
は異なるアーキテクチャ向けのコンテナイメージを効率的にビルドできるため、x86_64
とArm
の両方に対応したイメージを作成し、柔軟に運用できます。
タスク定義でのアーキテクチャ指定:
"runtimePlatform": {
"cpuArchitecture": "ARM64",
"operatingSystemFamily": "LINUX"
},
この変更により、Armアーキテクチャの利点を最大限活用し、コストを抑えられます。
5. Compute Savings Plansの利用(未対応)
まだ導入はしていませんが、将来的にCompute Savings Plansを利用する予定です。このプランを利用することで、EC2、Lambda、Fargate全体のコンピューティングコストを大幅に削減できます。1年または3年の期間契約で、一定のコンピューティング使用量に対する割引が提供されます。