はじめに
2019/11に追加されたECSクラスターオートスケーリング(CAS)がなかなか使えそうだったので試してみた。
ECSクラスターオートスケーリング(CAS)とは
2019/11のre:Invent 2019で発表された、ECSのスケーリング管理を楽にしてくれる仕組みです。
本日、AWS ECS Cluster Auto Scalingを発表します。この機能は、スケールアウトを高速化し信頼性を向上させる、クラスター内の空きキャパシティ管理の提供と、スケールイン時に終了されるインスタンスの自動管理を提供し、クラスターの自動スケーリングをより使いやすいものにします。
引用元:新機能 – AWS ECS Cluster Auto ScalingによるECSクラスターの自動スケーリング
これを使うとタスクやサービスとそのホストとなるコンテナインスタンスのスケーリングをまとめてやってくれます。
つい最近まで、ECS クラスター内での EC2 インスタンスの数を、タスクとサービスに合わせてスケーリングさせようとすると、難しい問題の発生することがありました。
引用元:Amazon ECS クラスターの Auto Scaling を深く探る
詳しくは↓でわかりやすく説明してくれてます。
Capacity Providerとは?ECSの次世代スケーリング戦略を解説する
構築
公式ブログを参考に実際に構築していきます。
公式ブログの手順は説明がなかったり、値が誤っていたりするので、適宜補足してあります。
公式の手順だとAmazon Linux2のコンテナでコマンドを実行させるだけなのですが、せっかくなのでWebサーバを動かしてみます。
0. 事前準備
ECS自体利用したことがない場合はまず3つのIAMロールから作成する必要があります。
1. ECSコンテナインスタンス用のロール
下記の「コンテナインスタンスのecsInstanceRole
IAMロールを作成するには」を参考にロールを作成
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/instance_IAM_role.html
2. ECSタスク用のロール
下記の「タスク用の IAM ロールを作成するには」を参考にロールを作成
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task-iam-roles.html
3. ECSタスク実行用のロール
下記の「Creating the task execution IAM role」を参考にロールを作成
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_execution_IAM_role.html
1. 起動設定の作成
まずは、オートスケーリンググループがどんなインスタンスを立ち上げるかを指定する「起動設定」を作成します。
1-1. 起動設定の定義ファイルを作成
ローカルで下記ファイルを作成します。
{
"LaunchConfigurationName": "demo-launchconfig",
"ImageId": "ami-0bea16de11596d6ba",
"KeyName": "xxx_ec2_key",
"SecurityGroups": [
"sg-XXXXXXXXXXXXXXX"
],
"InstanceType": "t2.micro",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/xvdcz",
"Ebs": {
"VolumeSize": 30,
"VolumeType": "gp2",
"DeleteOnTermination": true,
"Encrypted": true
}
}
],
"InstanceMonitoring": {
"Enabled": false
},
"IamInstanceProfile": "arn:aws:iam::XXXXXXXXXXX:instance-profile/ecsInstanceRole",
"AssociatePublicIpAddress": true
}
補足:
1. ImageId
はECS最適化AMIを利用するか、それ以外のAMIを利用する場合はECSコンテナエージェントのインストールが必要になります。今回はECS最適化AMIを利用します。
東京リージョンの最新のECS最適化AMIのAMI IDは下記から取得できます。
https://ap-northeast-1.console.aws.amazon.com/systems-manager/parameters/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id/description?region=ap-northeast-1#
-
KeyName
はインスタンスに埋め込むキーペア名を指定してください。SSHしない場合なくても大丈夫です。 -
SecurityGroups
は事前にマイIPの22と80を許可で作成したものを指定してください。 -
IamInstanceProfile
はこのインスタンスにアタッチするIAMロールを指定します。ここでは手順0で作成したecsInstanceRole
の"インスタンスプロファイルARN"を指定します。
※公式ブログではロールARNを指定していますが誤りです、注意してください。
1-2. ユーザーデータを作成
ローカルで下記ファイルを作成します。
#!/bin/bash
echo ECS_CLUSTER=demo-cluster >> /etc/ecs/ecs.config
補足:
1. 先頭の#!/bin/bash
(シバン)は必須です。
2. echo ECS_CLUSTER=demo-cluster >> /etc/ecs/ecs.config
はECSコンテナインスタンスに必須の設定です。この後作成するクラスター名に紐付きます。
3. もし起動時に実行させたいコマンドがある場合3行目以降に書きます。ECS最適化AMIにはAWC CLIが入っていないので必要な場合インストールのコマンドから書く必要があります。
1-3. 起動設定の作成実行
1-1. 1-2. で作成したファイルがある場所で下記コマンドを実行します。
aws autoscaling create-launch-configuration --cli-input-json file://demo-launchconfig.json --user-data file://demo-userdata.sh
2. オートスケーリンググループの作成
次に先ほどの設定でインスタンスを立ち上げるオートスケーリンググループを作ります。
2-1. オートスケーリンググループの設定ファイルを作成
AWS CLIで指定する設定内容のJSONを作成します。
{
"LaunchConfigurationName": "demo-launchconfig",
"MinSize": 0,
"MaxSize": 2,
"DesiredCapacity": 0,
"DefaultCooldown": 300,
"AvailabilityZones": [
"ap-northeast-1a" ],
"HealthCheckType": "EC2",
"HealthCheckGracePeriod": 300,
"VPCZoneIdentifier": "subnet-abcd1234",
"TerminationPolicies": [
"DEFAULT"
],
"NewInstancesProtectedFromScaleIn": true,
"ServiceLinkedRoleARN": "arn:aws:iam::111122223333:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"
}
補足:
-
MaxSize
はあまり大きくすると消し忘れた時のリスクがあるので2
にしておきます。 -
AbailabilityZones
は東京リージョンap-northeast-1a
を指定します。 -
VPCZoneIdentifier
は自分のアカウント内のVPCにあるサブネットのIDを指定します。 -
ServiceLinkedRoleARN
は111122223333
の部分を自分のアカウントIDに置き換えます。
2-2. オートスケーリンググループ作成実行
2-1. で作成したJSONのある場所で下記コマンドを実行します。
aws autoscaling create-auto-scaling-group --auto-scaling-group-name demo-asg --cli-input-json file://demo-asgconfig.json
4. キャパシティプロバイダーの作成
オートスケーリンググループとクラスターを紐付けるキャパシティプロバイダーを作成します。
4-1. キャパシティプロバイダーの設定ファイルを作成
AWS CLIで指定する設定内容のJSONを作成します。
{
"name": "demo-capacityprovider", "autoScalingGroupProvider": {
"autoScalingGroupArn": "arn:aws:autoscaling:ap-northeast-1:XXXXXXXXXX:autoScalingGroup:XXXXXX-XXXXXXXX-XXXXXXXX:autoScalingGroupName/demo-asg",
"managedScaling": {
"status": "ENABLED",
"targetCapacity": 100,
"minimumScalingStepSize": 1,
"maximumScalingStepSize": 100
},
"managedTerminationProtection": "ENABLED"
}
}
補足:
-
autoScalingGroupArn
は手順2で作成したものオートスケーリンググループのARNを指定します。
4-2. キャパシティプロバイダー作成実行
4-1. で作成したJSONのある場所で下記コマンドを実行します。
aws ecs create-capacity-provider --cli-input-json file://demo-capacityprovider.json
補足:
-
AWS CLI
のバージョンが古いとcreate-capacity-provider
サブコマンドに対応していないので、コマンドが使えない場合はsudo pip install --upgrade awscli
でバージョンアップしてください。
5. クラスターの作成
5-1. クラスター作成実行
下記コマンドでECSのクラスターを作成します。
オプションで先ほどのキャパシティプロバイダーも紐付けます。
aws ecs create-cluster --cluster-name demo-cluster --capacity-providers demo-capacityprovider --default-capacity-provider-strategy capacityProvider=demo-capacityprovider,weight=1
5-2. クラスターのステータスを確認
下記コマンドの結果に"status": "ACTIVE"
が含まれていれば、作成が終わっています。
aws ecs describe-clusters --clusters demo-cluster --include ATTACHMENTS
5. タスク定義の作成
ECS上で実行させるコンテナの情報を「タスク定義」として作成します。
5-1. タスク定義の設定ファイルを作成
AWS CLIで指定する設定内容のJSONを作成します。
{
"family": "demo-web-task",
"taskRoleArn": "arn:aws:iam::XXXXXXXXXX:role/ecsTaskRole",
"executionRoleArn": "arn:aws:iam::XXXXXXXXX:role/ecsTaskExecutionRole",
"networkMode": "bridge",
"containerDefinitions": [
{
"name": "web",
"image": "nginx:latest",
"memory": 512,
"essential": true,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
},
{
"containerPort": 443,
"hostPort": 443,
"protocol": "tcp"
}
]
}],
"requiresCompatibilities": ["EC2"]
}
補足:
-
taskRoleArn
には手順0で作成したタスクロールのARNを指定します。 -
executionRoleArn
には手順0で作成したタスク実行ロールのARNを指定します。 -
containerDefinitions
でコンテナについて定義します。今回はNGINXイメージをメモリ1GiBで実行し、ホストの80ポートをコンテナの80ポートにマッピングします。
5-2. タスク定義作成実行
5-1. で作成したJSONのある場所で下記コマンドを実行します。
aws ecs register-task-definition --cli-input-json file://demo-web-task.json
6. サービスの作成
6-1. サービス定義ファイルを作成
AWS CLIで指定する設定内容のJSONを作成します。
{
"cluster": "demo-cluster",
"serviceName": "demo-web-service",
"taskDefinition": "demo-web-task:1",
"desiredCount": 1,
"capacityProviderStrategy": [
{
"capacityProvider": "demo-capacityprovider",
"weight": 1,
"base": 1
}
]
}
6-2. サービス作成実行
6-1. で作成したJSONのある場所で下記コマンドを実行します。
aws ecs create-service --cli-input-json file://demo-web-service.json
7. 動作確認
これで、キャパシティプロバイダによりサービスを実行するために希望インスタンスサイズが1以上に変更され、インスタンスが立ち上がり、その中でNGINXのコンテナが立ち上がるはず。
初回のインスタンスが立ち上がるまでは少し時間がかかるので、マネジメントコンソールでタスクがPROVISIONING
になっていることとキャパシティプロバイダーの希望するサイズが1以上になっていることを確認し、5分ほど待つ。
タスクがRUNNING
になったら、EC2インスタンスのパブリックDNSの80番ポートへアクセスするとNGINXでホストされているHTMLが表示される。
おわりに
正直、Webサービスの場合ELBかRoute53でエンドポイントをつけないとスケーリングする意味がないのでそこまでやりたかったんですが、コンテナインスタンスの定義で結構はまって時間もかかってしまったので、今回はNGINXの画面が見られてひとまず満足したので、続きは後日。。。正直ユーザーデータとかでいろいろ専用の設定を入れたいという要件がなければ、capacityProvider
はFARGATE
にしたほうが大分楽そう。