1. はじめに

今回は、ECS FargateをCloudformationで構築する方法を説明していきます。

ECSについて、興味があったのですが、学習できていませんでした。最近時間ができたので、ECS Fargateを構築したので、構築手順をまとめました。

2. ECSとは

ECS(Amazon Elastic Container)とは、コンテナ化されたアプリケーションをデプロイ、管理、スケーリングするためのコンテナ管理サービスです。

2.1 ECSを構成する構成要素

2.1.1 クラスター

クラスターは、サービスとタスクをグループ化する要素です。

2.1.2 サービス

サービスは、コンテナ化されたアプリケーションの実行とスケーリングを容易にする、フルマネージド型のコンテナオーケストレーションサービスです。

  • サービスで設定できる項目
    • クラスター
      • サービスやタスクを実行するクラスターを設定する
    • タスク定義
      • 実行するコンテナのリソースや環境変数など
    • デプロイメント
      • ローリングアップデートやCode
    • ターゲット数
      • サービスが維持するタスク数を設定。
    • ロードバランサ
      • タスクのトラフィックを分散する
    • ヘルスチェック
      • タスクの健全性を監視する
    • AutoScaling
      • タスク数を自動で増減。CPU使用率やメモリの使用率に基づいて増減する。
    • ローンチタイプ
      • ECS2かFargateを設定する

2.1.3 タスク

タスクは、1つ以上のコンテナをまとめて実行する単位です。ECSでは、アプリケーションをデプロイ・実行する最小単位です。

タスクの実行内容は、タスク定義に基づきます。

  • タスクで設定できる項目
    • 使用するDockerイメージ
    • コンテナごとのCPU/メモリ割当て
    • ポートマッピング
    • 環境変数
    • ログ設定

4. 構成図

構成図

5. 構築手順

プライベートサブネットにECSを作成する方法です。

5.1 VPC

VPC:
  Type: AWS::EC2::VPC
  Properties:
    CidrBlock: 192.168.0.0/20
    EnableDnsSupport: true
    EnableDnsHostnames: true
    Tags:
      - Key: Name
        Value: 'vpc'

EcsPrivateSubnetAZ:
  Type: AWS::EC2::Subnet
  Properties:
    VpcId: !Ref VPC
    AvailabilityZone: !Select [0, !GetAZs '']
    CidrBlock: 192.168.0.0/24
    MapPublicIpOnLaunch: false
    Tags:
      - Key: Name
        Value: 'ecs-private-subnet'

SgEcsSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  DependsOn: AlbSecurityGroup
  Properties:
    GroupDescription: 'sg-ecs-security-group'
    GroupName: 'sg-ecs-security-group'
    SecurityGroupEgress:
      - IpProtocol: tcp
        FromPort: 443
        ToPort: 443
        CidrIp: 0.0.0.0/0
    Tags:
      - Key: Name
        Value: 'sg-ecs'
    VpcId: !Ref VPC

EcrVpcEndpointSg:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: Allow HTTPS for VPC Endpoints
    VpcId: !Ref VPC
    SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 443
        ToPort: 443
        CidrIp: 0.0.0.0/0

CloudWatchVpcEndpointSg:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: Allow HTTPS for VPC Endpoints
    VpcId: !Ref VPC
    SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 443
        ToPort: 443
        CidrIp: 0.0.0.0/0
    SourceSecurityGroupId: !Ref SgEcsSecurityGroup

#---------------------------------------------#
# VPC Endpoint                                #
#---------------------------------------------#
# プライベートサブネットのECSからECRからイメージ取得するために必要
ECRApiEndpoint:
  Type: AWS::EC2::VPCEndpoint
  Properties:
    ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.api'
    VpcId: !Ref VPC
    VpcEndpointType: Interface
    SubnetIds:
      - !Ref EcsPrivateSubnetAZ
    PrivateDnsEnabled: true
    SecurityGroupIds:
      - !Ref EcrVpcEndpointSg
    Tags:
      - Key: Name
        Value: 'ecr-api-endpoint'

# プライベートサブネットのECSからECRからイメージ取得するために必要
ECRDockerEndpoint:
  Type: AWS::EC2::VPCEndpoint
  Properties:
    ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.dkr'
    VpcId: !Ref VPC
    VpcEndpointType: Interface
    SubnetIds:
      - !Ref EcsPrivateSubnetAZ
    PrivateDnsEnabled: true
    SecurityGroupIds:
      - !Ref EcrVpcEndpointSg
    Tags:
      - Key: Name
        Value: 'dcr-endpoint'

# プライベートサブネットのECSからCloudwatchにログ出力するために必要
CloudWatchEndpoint:
  Type: AWS::EC2::VPCEndpoint
  Properties:
    ServiceName: !Sub 'com.amazonaws.${AWS::Region}.logs'
    VpcId: !Ref VPC
    VpcEndpointType: Interface
    SubnetIds:
      - !Ref EcsPrivateSubnetAZ
    PrivateDnsEnabled: true
    SecurityGroupIds:
      - !Ref CloudWatchVpcEndpointSg
    Tags:
      - Key: Name
        Value: 'logs-vpc-endpoint'

5.2 クラスター作成

ECSCluster:
  Type: AWS::ECS::Cluster
  Properties:
    ClusterName: cluster
    CapacityProviders:
      - FARGATE
    ClusterSettings:
      - Name: containerInsights
        Value: enabled

5.3 サービス作成

ECSService:
  Type: 'AWS::ECS::Service'
  Properties:
    ServiceName: ecs-service
    Cluster: !Ref ECSCluster
    TaskDefinition: !Ref FargateTaskDefinition
    DesiredCount: 1
    LaunchType: FARGATE
    DeploymentController:
      Type: CODE_DEPLOY
    NetworkConfiguration:
      AwsvpcConfiguration:
        AssignPublicIp: DISABLED
        SecurityGroups:
          - !Ref SgEcsSecurityGroup
        Subnets:
          - !Ref EcsPrivateSubnetAZ
    LoadBalancers:
      - ContainerName: dynamo
        ContainerPort: 8080
        TargetGroupArn: !Ref TargetGroup

5.4 タスク定義作成

FargateTaskDefinition:
  Type: AWS::ECS::TaskDefinition
  Properties:
    ContainerDefinitions:
      # ECRのリポジトリを指定する
      - Name: test
        Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/xxxxxxx'
        Cpu: 0
        PortMappings:
          - Name: test
            ContainerPort: 8080
            HostPort: 8080
            Protocol: tcp
            AppProtocol: http
        Essential: true
        LogConfiguration:
          LogDriver: awslogs
          Options:
            awslogs-group: /ecs/tests
            awslogs-region: !Sub ${AWS::Region}
            awslogs-stream-prefix: ecs
    Family: ecs-family-name
    ExecutionRoleArn: !Sub 'arn:aws:iam::${AWS::AccountId}:role/ecs-task-execution-role'
    NetworkMode: awsvpc
    Cpu: 1024
    Memory: 3072

5.5 ECSロール作成

EcsTaskExecutionRole:
  Type: AWS::IAM::Role
  Properties:
    RoleName: 'ecs-task-execution-role'
    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
    Policies:
      - PolicyName: AllowCloudWatchLogsAccess
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - logs:CreateLogStream
                - logs:PutLogEvents
                - logs:DescribeLogStreams
                - logs:CreateLogGroup
              Resource: '*'

6. まとめ

ECSをCloudFormationで構築してみました。以前、AWSマネジメントコンソールで作成したことがありました。

その時は、ハンズオンのカリキュラム通りに構築しただけなので、苦戦はしませんでした。

CloudFormationで構築したところ、多くのエラーを解決したところより一層理解が進んだとおもいます。

また、AWS構築では、CloudFormationなどで構築することが多いので、IaCで構築しておいて損はしないと思います。

7. 参考ページ