LoginSignup
4
5

More than 1 year has passed since last update.

開発/検証環境はFargateSpotを使いましょう

Last updated at Posted at 2022-06-15

概要

Fargate SpotはSpotインスタンスのFargate版です。
予期せぬシャットダウンの可能性があるものの、通常の7割引の料金で使えます。
ほとんどの場合、開発/検証環境ではこれが活用可能ではないでしょうか。

実装

1. ECSクラスターにDefaultCapacityProviderStrategyを設定

ECS-Cluster.yml
AWSTemplateFormatVersion: '2010-09-09'
Description: ECS cluster
Parameters:
  EnvironmentName:
    Type: String
    Default: staging

Resources:
  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub ${EnvironmentName}-ecs-cluster
      CapacityProviders:
        - FARGATE
        - FARGATE_SPOT
      DefaultCapacityProviderStrategy: # schedule only Fargate_Spot
        - CapacityProvider: FARGATE_SPOT
          Weight: 1

Outputs:
  ECSClusterName:
    Description: The Name of the ECS cluster
    Value: !Ref ECSCluster
    Export:
      Name: !Sub ${EnvironmentName}:ECSClusterName
  ECSClusterArn:
    Description: The ARN of the ECS cluster
    Value: !GetAtt ECSCluster.Arn
    Export:
      Name: !Sub ${EnvironmentName}:ECSClusterArn

2. ECSサービスにオートスケーリング設定を追加

サービスのCapacityProviderStrategyおよびにLaunchTypeを指定しない場合、クラスターのDefaultCapacityProviderStrategyが適用されます。

ECS-Service.yml
AWSTemplateFormatVersion: '2010-09-09'
Description: ECS service and auto scaling

Parameters:
  EnvironmentName:
    Type: String
    Default: staging

  ServiceName:
    Type: String
    Default: my-service
  ImageUrl:
    Type: String
    Default: <your-docker-image-url>
    Description: The url of docker image at ECR

  ContainerPort:
    Type: Number
    Default: 3000
    Description: What port number the application inside the docker container is binding to
  ContainerCpu:
    Type: Number
    Default: 256
    Description: How much CPU to give the container. 1024 is 1 CPU
  ContainerMemory:
    Type: Number
    Default: 512
    Description: How much memory in megabytes to give the container
  DesiredCount:
    Type: Number
    Default: 2
    Description: How many copies of the service task to run

  TaskMaxContainerCount:
    Type: Number
    Description: Maximum number of containers to run for the service when auto scaling out
    Default: 10
    MinValue: 1
    ConstraintDescription: Value must be at least one
  ServiceScaleEvaluationPeriods:
    Description: The number of periods over which data is compared to the specified threshold
    Type: Number
    Default: 2
    MinValue: 2
  ServiceCpuScaleOutThreshold:
    Type: Number
    Description: Average CPU value to trigger auto scaling out
    Default: 50
    MinValue: 0
    MaxValue: 100
    ConstraintDescription: Value must be between 0 and 100
  ServiceCpuScaleInThreshold:
    Type: Number
    Description: Average CPU value to trigger auto scaling in
    Default: 25
    MinValue: 0
    MaxValue: 100
    ConstraintDescription: Value must be between 0 and 100

Resources:
  # Service

  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub ${EnvironmentName}-service-${ServiceName}

  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Ref ServiceName
      Cpu: !Ref ContainerCpu
      Memory: !Ref ContainerMemory
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      ExecutionRoleArn: !Ref ECSTaskExecutionRole
      TaskRoleArn: !Ref ECSTaskRole
      ContainerDefinitions:
        - Name: !Ref ServiceName
          Cpu: !Ref ContainerCpu
          Memory: !Ref ContainerMemory
          Essential: true
          Image: !Ref ImageUrl
          PortMappings:
            - ContainerPort: !Ref ContainerPort
          LinuxParameters:
            InitProcessEnabled: true
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Sub ${EnvironmentName}-service-${ServiceName}
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: !Ref ServiceName

  Service:
    Type: AWS::ECS::Service
    Properties:
      ServiceName: !Ref ServiceName
      Cluster:
        Fn::ImportValue: !Sub ${EnvironmentName}:ECSClusterArn
      # LaunchType: FARGATE # omit this to use DefaultCapacityProviderStrategy
      EnableExecuteCommand: true
      DeploymentConfiguration:
        DeploymentCircuitBreaker:
          Enable: true
          Rollback: true
        MaximumPercent: 200
        MinimumHealthyPercent: 75
      DesiredCount: !Ref DesiredCount
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: DISABLED # no public ip is needed
          SecurityGroups:
            - !Ref EcsTaskSecurityGroupId
          Subnets:
            - !Ref PrivateSubnet1
      TaskDefinition: !Ref TaskDefinition
      ServiceRegistries:
        - RegistryArn: !GetAtt ServiceDiscovery.Arn
          Port: !Ref ContainerPort

  # AutoScaling
  ServiceScalingTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    DependsOn:
      - Service
    Properties:
      MinCapacity: !Ref DesiredCount
      MaxCapacity: !Ref TaskMaxContainerCount
      ResourceId: !Sub
        - service/${ECSClusterName}/${ECSServiceName}
        - ECSClusterName:
            Fn::ImportValue: !Sub ${EnvironmentName}:ECSClusterName
          ECSServiceName: !Ref ServiceName
      RoleARN: !Ref AutoscalingRole
      ScalableDimension: ecs:service:DesiredCount
      ServiceNamespace: ecs

  ServiceScaleOutPolicy:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: !Sub ${EnvironmentName}-${ServiceName}-ScaleOutPolicy
      PolicyType: StepScaling
      ScalingTargetId: !Ref ServiceScalingTarget
      StepScalingPolicyConfiguration:
        AdjustmentType: ChangeInCapacity
        Cooldown: 60
        MetricAggregationType: Average
        StepAdjustments:
          - ScalingAdjustment: 1
            MetricIntervalLowerBound: 0
    DependsOn: ServiceScalingTarget

  ServiceScaleInPolicy:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: !Sub ${EnvironmentName}-${ServiceName}-ScaleInPolicy
      PolicyType: StepScaling
      ScalingTargetId: !Ref ServiceScalingTarget
      StepScalingPolicyConfiguration:
        AdjustmentType: ChangeInCapacity
        Cooldown: 60
        MetricAggregationType: Average
        StepAdjustments:
          - ScalingAdjustment: -1
            MetricIntervalUpperBound: 0
    DependsOn: ServiceScalingTarget

  ServiceScaleOutAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub ${EnvironmentName}-${ServiceName}-ScaleOutAlarm
      EvaluationPeriods: !Ref ServiceScaleEvaluationPeriods
      Statistic: Average
      TreatMissingData: notBreaching
      Threshold: !Ref ServiceCpuScaleOutThreshold
      AlarmDescription: Alarm to add capacity if CPU is high
      Period: 60
      AlarmActions:
        - !Ref ServiceScaleOutPolicy
      Namespace: AWS/ECS
      Dimensions:
        - Name: ClusterName
          Value:
            Fn::ImportValue: !Sub ${EnvironmentName}:ECSClusterName
        - Name: ServiceName
          Value: !Ref ServiceName
      ComparisonOperator: GreaterThanThreshold
      MetricName: CPUUtilization
    DependsOn:
      - ServiceScaleOutPolicy

  ServiceScaleInAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub ${EnvironmentName}-${ServiceName}-ScaleInAlarm
      EvaluationPeriods: !Ref ServiceScaleEvaluationPeriods
      Statistic: Average
      TreatMissingData: notBreaching
      Threshold: !Ref ServiceCpuScaleInThreshold
      AlarmDescription: Alarm to reduce capacity if container CPU is low
      Period: 300
      AlarmActions:
        - !Ref ServiceScaleInPolicy
      Namespace: AWS/ECS
      Dimensions:
        - Name: ClusterName
          Value:
            Fn::ImportValue: !Sub ${EnvironmentName}:ECSClusterName
        - Name: ServiceName
          Value: !Ref ServiceName
      ComparisonOperator: LessThanThreshold
      MetricName: CPUUtilization
    DependsOn:
      - ServiceScaleInPolicy

3. 確認

下記コマンドでタスクのcapacityProviderを確認できます。

$ aws ecs describe-tasks 
        --cluster <Cluster_name> \
        --tasks <TaskID> \
        --region <Region>

参考

下記大変参考にさせていただきました。

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5