CloudFormationでFargateのタスクのスケジューリングを構築する #Fargate

VPC構築済みの環境や、同じVPC内に複数のタスクのスケジューリングのFargateを複数構築するときに使えるCloudFormationテンプレートを作成してみました。 Fargateに関連するCloudwatch Logsの設定も含まれています。自分が使いたいFargateのサンプルが見つからなかったので作成しました。 どなたかのお役に立てれば光栄です。
2019.11.12

こんにちは、コカコーラ大好きカジです。

VPC構築済みの環境や、同じVPC内に複数のタスクのスケジューリングのFargateを複数構築するときに使えるCloudFormationテンプレートを作成してみました。 Fargateに関連するCloudwatch Logsの設定も含まれています。 また、自分が使いたいFargateのサンプルが見つからなかったので作成しました。 どなたかのお役に立てれば光栄です。

前提条件

  • VPC、サブネット、ECS Task用のSecurity Groupが構築済み
  • Fargateを配置するサブネットは、NATゲートウェイ経由でインターネット通信またはPrivate LinkでECRへ通信可能
  • ECRリポジトリが構築済みで、DockerイメージをPushしておくこと、無い場合はこちらのブロクでDockerイメージの作成とECRを構築してください。

スケジューリングのFargateの構築

文末のCloudFormationテンプレートでCreate Stackしてください。

Crate Stack時に、VPC、Subnet、Security Group、ECRを指定するようにしています。そのほかはそのままでOKです。

途中、ECS用のIAM Roleを作成するためIAMの許可にチェックを入れます。

Create Stackが正常に終わると以下のようになります。正常にできない場合は、ネットワーク構成や指定しているVPC、サブネットに誤りがないか確認しましょう。

あと、テスト起動するよう、スケジュールを1dayから、cronの時間指定へ変更して動作させてみます。

起動すると以下の表示になります。

コンテナ側のIPアドレスは以下の部分で確認します。

起動しているコンテナは、nginxのコンテナなので、外部からcurlコマンドでコンテナへアクセスすると、以下のようにnginxが表示されます。

$ curl -v http://10.1.21.66
* Rebuilt URL to: http://10.1.21.66/
*   Trying 10.1.21.66...
* TCP_NODELAY set
* Connected to 10.1.21.66 (10.1.21.66) port 80 (#0)
> GET / HTTP/1.1
> Host: 10.1.21.66
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.15.8
< Date: Tue, 12 Nov 2019 06:29:56 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Wed, 26 Dec 2018 23:21:49 GMT
< Connection: keep-alive
< ETag: "5c240d0d-264"
< Accept-Ranges: bytes
<
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
* Connection #0 to host 10.1.21.66 left intact

CloudFormationテンプレート

実行タイミングについては、「ScheduleExpression: rate(1 day)」の部分を変更してください。cron形式でも記載できます。

sample-fargate-schedle.yaml

AWSTemplateFormatVersion: "2010-09-09"
Description:
  Fargate and ALB Create

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "Project Name Prefix"
        Parameters:
          - ProjectName

      - Label:
          default: "Fargate for ECS Configuration"
        Parameters:
          - ECSClusterName
          - ECSTaskName
          - ECSTaskCPUUnit
          - ECSTaskMemory
          - ECSContainerName
          - ECSImageName
          - ECSServiceName
          - ECSTaskDesiredCount
          - ECSScheduleRuleName
          - ECSScheduleTargetName

    ParameterLabels:
      ECSClusterName:
        default: "ECSClusterName"
      ECSTaskName:
        default: "ECSTaskName"
      ECSTaskCPUUnit:
        default: "ECSTaskCPUUnit"
      ECSTaskMemory:
        default: "ECSTaskMemory"
      ECSContainerName:
        default: "ECSContainerName"
      ECSImageName:
        default: "ECSImageName"
      ECSServiceName:
        default: "ECSServiceName"
      ECSTaskDesiredCount:
        default: "ECSTaskDesiredCount"

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
  ProjectName:
    Default: sample-fargate-batch
    Type: String

#VPCID
  VpcId:
    Description : "VPC ID"
    Type: AWS::EC2::VPC::Id

#ECSSecurity Group
  ECSSecurityGroupId:
    Type: AWS::EC2::SecurityGroup::Id

#ECSSubnet1
  ECSSubnetId1:
    Description : "ECS Subnet 1st"
    Type : AWS::EC2::Subnet::Id

#ECSSubnet2
  ECSSubnetId2:
    Description : "ECS Subnet 2st"
    Type : AWS::EC2::Subnet::Id

#ECSClusterName
  ECSClusterName:
    Type: String
    Default: "cluster"

#ECSTaskName
  ECSTaskName:
    Type: String
    Default: "task"

#ECSTaskCPUUnit
  ECSTaskCPUUnit:
    AllowedValues: [ 256, 512, 1024, 2048, 4096  ]
    Type: String
    Default: "256"

#ECSTaskMemory
  ECSTaskMemory:
    AllowedValues: [ 256, 512, 1024, 2048, 4096  ]
    Type: String
    Default: "512"

#ECSContainerName
  ECSContainerName:
    Type: String
    Default: "container"

#ECSImageName
  ECSImageName:
    Type: String
    Default: "xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/kaji-test-ecr:latest"

#ECSServiceName
  ECSServiceName:
    Type: String
    Default: "service"

#ECSTaskDesiredCount
  ECSTaskDesiredCount:
    Type: Number
    Default: 1

#ECSScheduleRuleName
  ECSScheduleRuleName:
    Type: String
    Default: "batch-1day"

#ECSScheduleTargetName
  ECSScheduleTargetName:
    Type: String
    Default: "target"

Resources:

# ------------------------------------------------------------#
# ECS Cluster
# ------------------------------------------------------------#
  ECSCluster:
    Type: "AWS::ECS::Cluster"
    Properties:
      ClusterName: !Sub "${ProjectName}-${ECSClusterName}"

# ------------------------------------------------------------#
#  ECS LogGroup
# ------------------------------------------------------------#
  ECSLogGroup:
    Type: "AWS::Logs::LogGroup"
    Properties:
      LogGroupName: !Sub "/ecs/logs/${ProjectName}-ecs-group"


# ------------------------------------------------------------#
#  ECS Task Role IAM Policy
# ------------------------------------------------------------#
  ECSTaskRoleIAMPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub "${ProjectName}-ECSTaskPolicy"
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - sqs:SendMessage
            Resource: "*"

# ------------------------------------------------------------#
#  ECS Task Role
# ------------------------------------------------------------#
  ECSTaskRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${ProjectName}-ECSTaskRolePolicy"
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - !Ref ECSTaskRoleIAMPolicy

# ------------------------------------------------------------#
#  ECS Task Execution Role
# ------------------------------------------------------------#
  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${ProjectName}-ECSTaskExecutionRolePolicy"
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy

# ------------------------------------------------------------#
#  ECS TaskDefinition
# ------------------------------------------------------------#
  ECSTaskDefinition:
    Type: "AWS::ECS::TaskDefinition"
    Properties:
      Cpu: !Ref ECSTaskCPUUnit
      ExecutionRoleArn: !Ref ECSTaskExecutionRole
      Family: !Sub "${ProjectName}-${ECSTaskName}"
      Memory: !Ref ECSTaskMemory
      NetworkMode: awsvpc
      TaskRoleArn: !Ref ECSTaskRole
      RequiresCompatibilities:
        - FARGATE

#ContainerDefinitions
      ContainerDefinitions:
        - Name: !Sub "${ProjectName}-${ECSContainerName}"
          Image: !Ref ECSImageName
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref ECSLogGroup
              awslogs-region: !Ref "AWS::Region"
              awslogs-stream-prefix: !Ref ProjectName
          MemoryReservation: 128
          PortMappings:
            - HostPort: 80
              Protocol: tcp
              ContainerPort: 80

# ------------------------------------------------------------#
#  ECS Events Rule
# ------------------------------------------------------------#
  ECSSchedule:
    Type: AWS::Events::Rule
    Description: ''
    Properties:
      State: ENABLED
      ScheduleExpression: rate(1 day)
      Name: !Ref ECSScheduleRuleName
      Targets:
      - Id: !Sub "${ECSScheduleRuleName}-${ECSScheduleTargetName}"
        Arn: !GetAtt
          - ECSCluster
          - Arn
        RoleArn: !GetAtt
          - ECSTaskExecutionRole
          - Arn
        EcsParameters:
          TaskDefinitionArn: !Ref ECSTaskDefinition
          TaskCount: !Ref ECSTaskDesiredCount
          LaunchType: FARGATE
          NetworkConfiguration:
            AwsVpcConfiguration:
              AssignPublicIp: DISABLED
              SecurityGroups:
              - !Ref ECSSecurityGroupId
              Subnets:
              - !Ref ECSSubnetId1
              - !Ref ECSSubnetId2