決めろ最強のECS! 〜起動タイプ × 負荷分散 × デプロイ方法で自分だけのアーキテクチャ〜
※このノートはJAWS DAYS 2019懇親会LTの発表の詳細です!
アジェンダ
- 起動タイプ
- 負荷分散
- デプロイ方法
- 実際のシナリオ
- まとめ
起動タイプ
- ec2
- fargate
ec2
Pros:
- コスト面でfargateに勝る
Cons:
- インスタンスの死活を気にする必要が出てくる
fargate
Pros:
- EC2インスタンスを作成しないため、環境構築の手順を減らせる!
- インスタンスに物理的に入ることができないため、監査が楽(と思われます)!
Cons: - 2019年2月時点ではドキュメントがそこまで多くなく、
ecs-cli
との組み合わせなど応用的(?)なことを試すと事例が探しづらい。 - IPアドレスを固定できないため、何らかの負荷分散方法と組み合わせないとインターネットからアクセスできるようにできない
負荷分散
- ALB
- API Gateway + NLB
- サービスディスカバリ
ALB
Pros:
- パスベースマッピングが重宝する
- WAFをセットできる
Cons:
- 普通はALBで十分だと思われるが...API Gatewayにある機能がこちらにも欲しくなる!
API Gateway + NLB
Pros:
- APIを構築する上ではとても便利!
- カスタムオーソライザーの提供
- ex) アクセストークンをみてリクエストヘッダーを書き換える)
- マネージドなAPIのバージョン管理
- カスタムオーソライザーの提供
- VPC_LINKでNLBをプライベートサブネットに置くことができる。
- API Gatewayをプロキシ統合にすれば、ルーティングは実質アプリのフレームワークで握ることができる → 開発者に嬉しい!!!
Cons:
- パスベースのマッピングができない。
- 複数のECSサービスをインターネットと接続する場合、一つのNLBではそれらのサービスをインターネットに接続することができない。
- 内部にロードバランサーを置く、NLBより手前でポート番号を変換するなど方法は考えられる
サービスディスカバリ
Pros:
- あくまで名前解決なので、gRPCやWebSocketを使いたい場合にも便利
- 名前で参照するため、サーバー間の参照方法が環境・デプロイ結果に依存しない
Cons:
- 2019年2月時点ではドキュメントが多くない
デプロイ方法
- CloudFrmation
- ecs-cli
- Terraform(今回は対象外)
- CDK(今回は対象外)
CloudFormation
Pros:
- 先行事例が多い
- ロードバランサーやサブネットの指定時に
!Ref
で参照できる
Cons:
- タスク定義を更新した場合、サービスを自前で再起動する必要がある
- justInCaseではsilinternational/ecs-deployを利用しています
ecs-cli
Pros:
-
docker-compose.yml
を利用できる - タスク定義を更新した場合のサービスの再起動について考慮が不要になる
- ECRとECSのサービスがクロススタック参照で依存しないので、スタックを削除するときにテンプレートをごにょごにょしないてOK
Cons:
- コマンドの癖が若干強い
- ex) サービス作成時と更新時でサービスディスカバリを利用するオプションが異なる
- ...もしかして、CIでヘビーにデプロイすることは想定されていない???
- CloudFormationではないので、クロススタック参照を使ってリソースを参照できない
ecs-cliでサブネットやロードバランサーを動的に指定するとちょっと大変でした。次のページを参照。
SAMPLE: ecs-cliでサブネットやロードバランサーを動的に指定する
AWS_ACCOUNT_ID=$(aws sts get-caller-identity | jq -r .Account)
export IMAGE="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${ENV}-app"
export LOGS_GROUP="/aws/ecs/task/${ENV}-App"
export LOGS_REGION="${AWS_DEFAULT_REGION}"
export TASK_ROLE_ARN="$(aws cloudformation describe-stacks --stack-name ${ENV}-infrastracture --query 'Stacks[0].Outputs[?OutputKey==`TaskRoleArn`].OutputValue' --output text)"
export EXECUTION_ROLE_ARN="$(aws cloudformation describe-stacks --stack-name ${ENV}-infrastracture --query 'Stacks[0].Outputs[?OutputKey==`TaskExecutionRoleArn`].OutputValue' --output text)"
export TARGET_GROUP_ARN="$(aws cloudformation describe-stacks --stack-name ${ENV}-infrastracture --query 'Stacks[0].Outputs[?OutputKey==`TargetGroupArn`].OutputValue' --output text)"
export VPC_ID="$(aws cloudformation describe-stacks --stack-name ${ENV}-infrastracture --query 'Stacks[0].Outputs[?OutputKey==`VpcId`].OutputValue' --output text)"
export SUBNET1="$(aws cloudformation describe-stacks --stack-name ${ENV}-infrastracture --query 'Stacks[0].Outputs[?OutputKey==`ECSSubnet1aId`].OutputValue' --output text)"
export SUBNET2="$(aws cloudformation describe-stacks --stack-name ${ENV}-infrastracture --query 'Stacks[0].Outputs[?OutputKey==`ECSSubnet1cId`].OutputValue' --output text)"
export SECURITY_GROUP="$(aws cloudformation describe-stacks --stack-name ${ENV}-infrastracture --query 'Stacks[0].Outputs[?OutputKey==`ECSSecurityGroupId`].OutputValue' --output text)"
export MYSQL_HOST=${MYSQL_HOST}
export MYSQL_USERNAME=${MYSQL_USERNAME}
export MYSQL_PASSWORD=${MYSQL_PASSWORD}
[ $(aws ecs list-services --cluster ${ENV}-ECSCluster --query 'serviceArns' | grep \".*/app\") ] && export SERVICE_DISCOVERY_DEPLOYMENT_OPTION="--update-service-discovery" || export SERVICE_DISCOVERY_DEPLOYMENT_OPTION="--enable-service-discovery"
# ↑↑ ecs-cliでサービスディスカバリを有効にする場合、初回起動では `--enable-service-discovery`オプションを、更新では `--update-service-discovery`オプションを有効にする必要がある...
ecs-cli compose --project-name app -f ecs/docker-compose.yml --ecs-params ecs/ecs-params.yml service up \
${SERVICE_DISCOVERY_DEPLOYMENT_OPTION} --private-dns-namespace local --vpc ${VPC_ID} \
--container-name app --container-port 8080 --cluster ${ENV}-ECSCluster --target-group-arn ${TARGET_GROUP_ARN} --launch-type FARGATE --timeout 10
実際のシナリオ
- toBでAPIを提供する
- 認証はCognito Userpoolを使うが、認可サーバーは自前/サードパーティのものを使う
- ECSサーバーはプライベートサブネットに置きたい
- ECSサーバー同士の相互参照がありえる
- 構築初期なので、スタックの削除もそこそこやる可能性がある
→ API Gateway + NLB + ECS on fargate w/ ecs-cliで構築
まとめ
要件によって起動タイプ x 負荷分散 x デプロイ方法 を使い分けて、自分だけのECSのアーキテクチャを見つけ出そう!