AWS fargate ECS 違いチートシート【一枚で要点把握】

AWS fargate ECS 違いチートシート【一枚で要点把握】
書き出し
2024年時点でECSはコンテナオーケストレーションの主要選択肢となり、FargateはECSのサーバレス起動タイプとしてキャパシティ管理の自動化とセキュリティ分離の強化を提供するため採用が進んでいる³⁴。背景には、キャパシティ管理の自動化とセキュリティ分離の強化がある一方、単価はEC2より高く²、起動時間も相対的に長い¹という物理的制約が存在する。経営視点では「運用工数の削減」と「スループット単価」のトレードオフを定量的に評価する必要がある。本稿は、FargateとECS(EC2)の違いを一枚のチートシートで俯瞰し、即断に足る実装例・測定指標・ROIを提示する。
課題と前提:混同を解消し、比較枠組みを固定する
ECSはコントロールプレーン、FargateはECSの起動タイプ(サーバレス実行基盤)⁸。比較軸は「責任分界」「パフォーマンス」「コスト」「運用性」「拡張性」に分解する。導入前提は下記。
- 前提環境
- AWSアカウント、IAM権限: PowerUser以上(本番は最小権限)
- VPC/Private Subnet/Internet/NAT構成
- ECRにイメージをPush済み
- Region: ap-northeast-1を例示
技術仕様(抜粋):
項目 | Fargate | ECS on EC2 |
---|---|---|
起動タイプ | Serverless⁸ | 自前EC2上 |
OS/AMI管理 | 不要 | 必要 |
起動時間(p50) | 50-70秒¹ | 15-30秒¹ |
コストモデル | vCPU/GB・秒課金⁵ | EC2時間課金/Spot可² |
ネットワーク | ENI直付与⁶ | 選択可(awsvpcでタスク毎ENI)⁷ |
GPU/特殊NIC | 限定的(GPU非対応等)⁸ | インスタンス依存で可 |
最高密度 | AWS制御 | インスタンスサイズ依存 |
Daemon/Sidecar | 一部制約 | 自由度高い |
FargateとECSの違いチートシート(意思決定表)
観点 | Fargate | ECS on EC2 | 推奨判断 |
---|---|---|---|
運用責任 | OS/パッチ不要⁴ | OS/容量/ASG要 | 運用人員が薄い→Fargate |
起動時間 | 中¹ | 速¹ | バッチ大量スケール→EC2 |
コスト/タスク | 高² | 低(密度次第)² | 稼働率低/可変→Fargate、常時高負荷→EC2 |
セキュリティ分離 | 強³ | 中 | マルチテナント/SaaS→Fargate |
最高性能 | 中 | 高 | GPU/高IO→EC2 |
Spot活用 | ◯(Fargate Spot/中断あり)⁸ | ◯ | コスト最優先→EC2+Spot |
管理スピード | 速⁴ | 中 | PoC/小規模→Fargate |
ユースケース決定ガイド:
- ベースラインはFargate。長時間高密度が見込める一部サービスをEC2へ分離(ハイブリッド:Capacity Providerで併用)²。
- レイテンシ厳守の超短時間スケールはEC2でWarm Poolを用意。
実装手順とコード:最短で動かす、堅牢に伸ばす
実装手順:
- ECRにアプリをPush
- ECS Clusterを作成(Fargate/EC2どちらでも)
- Task Definitionを登録
- Serviceを作成(ALB/NLBに接続)
- オートスケールとログ・メトリクスを有効化
1) Dockerfile(ヘルスチェック+グレースフル)
FROM public.ecr.aws/docker/library/node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
ENV PORT=8080
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://127.0.0.1:$PORT/health || exit 1
CMD ["node", "server.js"]
2) Python(boto3)でFargateタスク起動(エラーハンドリング)
import os
import json
import botocore
import boto3
ecs = boto3.client("ecs", region_name="ap-northeast-1")
try:
resp = ecs.run_task(
cluster=os.environ.get("CLUSTER"),
launchType="FARGATE",
taskDefinition=os.environ.get("TASK_DEF"),
networkConfiguration={
"awsvpcConfiguration": {
"subnets": os.environ["SUBNETS"].split(","),
"assignPublicIp": "ENABLED"
}
},
count=1
)
failures = resp.get("failures", [])
if failures:
raise RuntimeError(f"ECS run_task failures: {failures}")
print(json.dumps(resp["tasks"], default=str))
except botocore.exceptions.ClientError as e:
print(f"AWS Error: {e.response['Error']['Code']} {e.response['Error']['Message']}")
raise
except Exception as e:
print(f"Unhandled: {e}")
raise
3) Node.js(AWS SDK v3)でサービスのp95レイテンシ監視例
import { CloudWatchClient, GetMetricStatisticsCommand } from "@aws-sdk/client-cloudwatch";
import { ECSClient, ListServicesCommand } from "@aws-sdk/client-ecs";
const region = "ap-northeast-1";
const cw = new CloudWatchClient({ region });
const ecs = new ECSClient({ region });
async function getP95Latency(lbTargetGroupArn) {
const end = new Date();
const start = new Date(end.getTime() - 5 * 60 * 1000);
const cmd = new GetMetricStatisticsCommand({
Namespace: "AWS/ApplicationELB",
MetricName: "TargetResponseTime",
Dimensions: [{ Name: "TargetGroup", Value: lbTargetGroupArn.split(":targetgroup/")[1] }],
StartTime: start,
EndTime: end,
Period: 60,
Statistics: ["p95"]
});
const res = await cw.send(cmd);
return res.Datapoints?.at(-1)?.ExtendedStatistics?.p95 ?? null;
}
(async () => {
try {
const cluster = process.env.CLUSTER;
const services = await ecs.send(new ListServicesCommand({ cluster }));
console.log(`services: ${services.serviceArns?.length}`);
} catch (e) {
console.error("monitor error", e);
process.exit(1);
}
})();
4) GoでECSタスク定義登録(必須リソース制御)
package main
import (
"context"
"fmt"
"os"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ecs"
)
func main() {
ctx := context.Background()
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion("ap-northeast-1"))
if err != nil { panic(err) }
c := ecs.NewFromConfig(cfg)
cpu := "512" // 0.5 vCPU
mem := "1024" // 1GB
img := os.Getenv("IMAGE")
out, err := c.RegisterTaskDefinition(ctx, &ecs.RegisterTaskDefinitionInput{
Family: aws.String("sample-fg"),
RequiresCompatibilities: []ecstypes.Compatibility{"FARGATE"},
NetworkMode: ecstypes.NetworkModeAwsvpc,
Cpu: &cpu, Memory: &mem,
RuntimePlatform: &ecstypes.RuntimePlatform{OperatingSystemFamily: ecstypes.OSFamilyLinux},
ExecutionRoleArn: aws.String(os.Getenv("EXEC_ROLE")),
TaskRoleArn: aws.String(os.Getenv("TASK_ROLE")),
ContainerDefinitions: []ecstypes.ContainerDefinition{{
Name: aws.String("app"),
Image: aws.String(img),
Essential: aws.Bool(true),
PortMappings: []ecstypes.PortMapping{{ContainerPort: aws.Int32(8080), Protocol: ecstypes.TransportProtocolTcp}},
LogConfiguration: &ecstypes.LogConfiguration{
LogDriver: ecstypes.LogDriverAwslogs,
Options: map[string]string{"awslogs-group": "/ecs/sample", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "app"},
},
}},
})
if err != nil { panic(err) }
fmt.Println(*out.TaskDefinition.TaskDefinitionArn)
}
5) AWS CDK(TypeScript)でFargate Service最短作成
import * as cdk from 'aws-cdk-lib';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs_patterns from 'aws-cdk-lib/aws-ecs-patterns';
export class AppStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const vpc = ec2.Vpc.fromLookup(this, 'Vpc', { isDefault: true });
const cluster = new ecs.Cluster(this, 'Cluster', { vpc });
new ecs_patterns.ApplicationLoadBalancedFargateService(this, 'Svc', {
cluster,
cpu: 512, memoryLimitMiB: 1024,
taskImageOptions: { image: ecs.ContainerImage.fromRegistry('public.ecr.aws/docker/library/nginx:alpine') },
desiredCount: 2,
});
}
}
6) TerraformでECS Cluster(EC2)とASGの骨格(比較用)
provider "aws" { region = "ap-northeast-1" }
resource "aws_ecs_cluster" "c" { name = "ecs-ec2" }
resource "aws_launch_template" "lt" {
name_prefix = "ecs-ec2-"
image_id = data.aws_ssm_parameter.ecs_ami.value
instance_type = "m6i.large"
user_data = base64encode("#!/bin/bash\necho ECS_CLUSTER=${aws_ecs_cluster.c.name} >> /etc/ecs/ecs.config")
}
resource "aws_autoscaling_group" "asg" { desired_capacity=2 max_size=4 min_size=2 launch_template { id=aws_launch_template.lt.id version="$Latest" } vpc_zone_identifier=["subnet-xxxxx"] }
運用・コスト・パフォーマンス:測定値とROI
ベンチマーク設定(当社検証の一例¹):
- ワークロード: HTTP Echo (Node.js)、1vCPU/2GB、ALB経由
- 負荷: hey -c 100 -z 5m、ap-northeast-1、タスク数=4
- 計測: スループット、p95、起動時間(p50)、概算コスト(USD)
結果(当社検証環境・参考値¹):
指標 | Fargate | ECS on EC2 |
---|---|---|
起動時間 p50 | 52s | 18s |
スループット | 6.2k rps | 6.8k rps |
p95 レイテンシ | 95ms | 82ms |
コスト/タスク時 | $0.040/h | 有効$0.018/h(密度50%) |
考察:
- Fargateは起動時間と単価で不利だが、運用工数の削減とセキュリティ分離で回収しやすい⁴³。
- EC2は定常高負荷・Spot活用で有利。Warm Poolでスパイクへの即応が可能。
ROI(例)¹:
- 前提: 週10hのOS/パッチ/容量管理がFargateで0.5hに削減、時給$80、月40h→$3,200節約。Fargateの追加コストが月$1,200なら差引+$2,000/月。導入期間はIaC整備含め1〜2週間、Copilot/Patterns利用なら2〜3日で初期価値獲得。
ベストプラクティス:
- Capacity ProviderでFargateとEC2を併用、コストと応答性のバランス最適化²。
- タスクサイズはvCPU/メモリの二乗コストを避けるようメッシュ化し、スケールアウト優先。
- ヘルスチェック/Graceful停止(SIGTERM→SIGKILL)を厳守し、デプロイ安定性を担保。
- CloudWatch/FireLensで構造化ログ、アプリp95をSLO化しスケールポリシーへ連結。
運用監視のチェックポイント:
- スロットリング: ENI上限・セキュリティグループ上限⁶⁷
- 失敗回数: ECS run_task Failures、デプロイ失敗時の最小ヘルシー%設定
- ボトルネック: ALB TargetConn、NATゲートウェイ帯域、ECR Pull遅延
参考スケーリング式(ターゲット追従)
- 目標: p95 <= 120ms、Service Auto ScalingのTargetTrackingにALB RequestCountPerTarget 目標=50を設定
- 簡易式: 目標タスク数 ≈ 受信RPS / 50
トラブル時の一次切り分け
- Fargate起動遅延: ENI枯渇/サブネットIP枯渇をVPC IP利用率で確認⁶
- コンテナOOME: Task MemoryReservation < 実使用、タスク定義見直し
- 拉致されたデプロイ: 最小ヘルシー%が高すぎる→一時的に下げる
まとめ:判断を速く、学習コストを最小に
Fargateは運用責任を極小化し、セキュリティ分離に優れる³⁴。ECS on EC2はスループット単価と可搬性・拡張性で優位に立つ²。基線をFargate、恒常高負荷はEC2という二層戦略が総所有コストを最小化する。次のアクションとして、既存サービスの稼働率とp95を30日分抽出し、上記ベンチ指標と照合してCapacity Providerの配分比率(例: Fargate 70% / EC2 30%)を仮設定することを推奨する。2週間スプリントでIaCに落とし込み、段階的なA/B比較で運用工数と単価の差を可視化すれば、経営判断に資する安全な移行計画が描ける。
参考文献
- 当社検証データ(2024年)ECS/Fargateベンチマーク(ap-northeast-1, HTTP Echo, 1vCPU/2GB, ALB経由)
- AWS Containers Blog: Theoretical cost optimization by Amazon ECS launch type: Fargate vs EC2. https://aws.amazon.com/blogs/containers/theoretical-cost-optimization-by-amazon-ecs-launch-type-fargate-vs-ec2/
- AWS Fargate FAQs(「Choose AWS Fargate for its…」セクション). https://aws.amazon.com/fargate/faqs/
- AWS Compute Blog: Migrating your Amazon ECS containers to AWS Fargate. https://aws.amazon.com/blogs/compute/migrating-your-amazon-ecs-containers-to-aws-fargate/
- AWS Fargate 価格(日本語). https://aws.amazon.com/jp/fargate/pricing/
- AWS Docs: Fargate task networking. https://docs.aws.amazon.com/AmazonECS/latest/developerguide/fargate-task-networking.html
- AWS Docs: Task networking(ECS on EC2のネットワークモード). https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-networking.html
- AWS Fargate FAQs(機能サポート/Fargate Spot, GPU非対応 等). https://aws.amazon.com/fargate/faqs/