LoginSignup
10
15

More than 5 years have passed since last update.

ECS向けのCloudFormationテンプレートを割と簡単にAWS Fargateで動くようにする

Last updated at Posted at 2018-07-12

はじめに

  • AWS Fargateが東京リージョンに対応しましたね。
  • 別件ですが、本日Amazon EFSが東京リージョンに対応しましたね。
  • もろもろ胸熱です。(因みに、現時点ではFargateからEFSのmountは行なえません。
  • 本記事では、 一生懸命作った ECS向けのCloudFormationテンプレートが割と簡単にFargateに対応できたので手順を書いておきます。

概要

対応手順

テンプレート取得

  1. ベースとなるテンプレートをCloneします。

    $ git clone git@github.com:aws-samples/ecs-refarch-cloudformation.git
    $ cd ecs-refarch-cloudformation
    $ code .
    

テンプレート修正

/service/product-service/service.yamlと/service/website-service/service.yamlの修正

AWS::ECS::Serviceセクション

修正後は以下の内容になります。

service.yaml
Service: 
    Type: AWS::ECS::Service
    # Role: !Ref ServiceRole
    DependsOn: ListenerRule
    Properties: 
        Cluster: !Ref Cluster
        DesiredCount: !Ref DesiredCount
        TaskDefinition: !Ref TaskDefinition
        LoadBalancers: 
            - ContainerName: "product-service"
              ContainerPort: 8001
              TargetGroupArn: !Ref TargetGroup
        LaunchType: FARGATE
        NetworkConfiguration:
          AwsvpcConfiguration:
            AssignPublicIp: DISABLED
            SecurityGroups: !Ref ServiceSecurityGroup
            Subnets: !Ref Subnets
  1. サービスのLaunchTypeにFARGATEの指定を追加します。

    LaunchType: FARGATE
    
  2. Fargateタスクはawsvpcネットワーキングモードを利用することになるのでNetworkConfigurationの指定を追加します。ENIが付くのでサービス毎にセキュリティグループが指定出来ます。ここ重要ですね。

    NetworkConfiguration:
      AwsvpcConfiguration:
        AssignPublicIp: DISABLED
        SecurityGroups: !Ref ServiceSecurityGroup
        Subnets: !Ref Subnets
    
  3. You cannot specify an IAM role for services that require a service linked role. と怒られるので、ServiceRoleの指定をコメントアウトします。

    # Role: !Ref ServiceRole
    

AWS::ECS::TaskDefinitionセクション

修正後は以下の内容になります。

service.yaml
TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
        Family: product-service
        Cpu: 256
        Memory: 512
        ContainerDefinitions:
            - Name: product-service
              Essential: true
              Image: 275396840892.dkr.ecr.us-east-1.amazonaws.com/ecs-refarch-cloudformation/product-service:1.0.0
              Cpu: 256
              Memory: 512
              PortMappings:
                - ContainerPort: 8001
              LogConfiguration:
                LogDriver: awslogs
                Options:
                    awslogs-group: !Ref AWS::StackName
                    awslogs-region: !Ref AWS::Region
                    awslogs-stream-prefix: product-service
        TaskRoleArn:
            Fn::If:
            - 'HasCustomTaskRole'
            - !Ref 'TaskRole'
            - !Ref "AWS::NoValue"
        ExecutionRoleArn: !Ref ExecutionRole
        NetworkMode: awsvpc
        RequiresCompatibilities:
            - FARGATE
  1. 起動タイプにFARGATEの指定を追加します。

    RequiresCompatibilities:
        - FARGATE
    
  2. NetworkModeにawsvpcの指定を追加します。

    NetworkMode: awsvpc
    
  3. 必須ではないですが、TaskRoleとExecutionRoleの指定を追加します。

    TaskRoleArn:
        Fn::If:
        - 'HasCustomTaskRole'
        - !Ref 'TaskRole'
        - !Ref "AWS::NoValue"
    ExecutionRoleArn: !Ref ExecutionRole
    
  4. Fargate requires log configuration options to include awslogs-stream-prefix と怒られるので 適当な値で awslogs-stream-prefix の指定を追加します。

    LogConfiguration:
      LogDriver: awslogs
      Options:
          awslogs-group: !Ref AWS::StackName
          awslogs-region: !Ref AWS::Region
          awslogs-stream-prefix: product-service
    
  5. Fargate requires that 'cpu' be defined at the task level.と怒られるので、以下のURLを参考にCPUとついでにメモリの指定を追加します。

    https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-cpu-memory-error.html

    TaskDefinition:
        Type: AWS::ECS::TaskDefinition
        Properties:
            Family: product-service
            Cpu: 256
            Memory: 512
    

AWS::ElasticLoadBalancingV2::TargetGroupセクション

修正後は以下の内容になります。

service.yaml
TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
        VpcId: !Ref VPC
        Port: 80
        Protocol: HTTP
        Matcher: 
            HttpCode: 200-299
        HealthCheckIntervalSeconds: 10
        HealthCheckPath: /products
        HealthCheckProtocol: HTTP
        HealthCheckTimeoutSeconds: 5
        HealthyThresholdCount: 2
        TargetType: ip
  1. awsvpc ネットワークモードを使用する場合、ターゲットグループのターゲットタイプとして ip を指定する必要があります。こちらを参照。そのため、TargetTypeに ip の指定を追加します。

    TargetType: ip
    
  2. 最後に必要なParameters、Conditionsの定義を追加します。

    Parameters:
    ・・・
        ServiceSecurityGroup:
            Description: The ServiceSecurityGroup
            Type: List<AWS::EC2::SecurityGroup::Id>
    
        Subnets:
            Description: Choose which subnets this ECS cluster should be deployed to
            Type: List<AWS::EC2::Subnet::Id>
    
        TaskRole:
            Description: The ECS task role ARN
            Type: String
            Default: ""
    
        ExecutionRole:
            Description: The ECS Fargate Execution role ARN
            Type: String
    
    Conditions:
        HasCustomTaskRole: !Not [ !Equals [!Ref 'TaskRole', ''] ]
    

/infrastructure/ecs-cluster-fargate.yamlの追加

ecs-cluster.yamlから大きく変わるのでecs-cluster-fargate.yamlという新しいファイルを作ります。修正後は、以下リンク先の内容になります。

  1. ECSClusterを指定します。ecs-cluster.yamlと同じ内容です。

    ECSCluster:
        Type: AWS::ECS::Cluster
    
  2. ECSServiceAutoScalingRoleを指定します。ecs-cluster.yamlと同じ内容です。

    ECSServiceAutoScalingRole:
        Type: AWS::IAM::Role
    
  3. タスク定義で設定するためのECSTaskExecutionRole、ECSProductTaskRole、ECSWebsiteTaskRoleを指定します。

    ECSTaskExecutionRole:
        Type: AWS::IAM::Role
    
    ECSProductTaskRole:
        Type: AWS::IAM::Role
    
    ECSWebsiteTaskRole:
        Type: AWS::IAM::Role
    

/master.yamlの修正

修正後は、以下リンク先の内容になります。

  1. ECSクラスター用のスタックのパスをecs-cluster-fargate.yamlに変更します。あと不要なParametersを削除します。

    TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/ecs-cluster-fargate.yaml
    
  2. ProductService、WebsiteService用のスタックに引き渡す必要のあるParametersを追加します。

    ServiceSecurityGroup: !GetAtt SecurityGroups.Outputs.ECSHostSecurityGroup
    Subnets: !GetAtt VPC.Outputs.PrivateSubnets
    TaskRole: !GetAtt ECS.Outputs.ECSProductTaskRole
    ExecutionRole: !GetAtt ECS.Outputs.ECSTaskExecutionRole
    
  3. AutoScaleでホストのDrainingを気にする必要が無くなるので、そこら辺を設定しているLifecycleHookのスタックしていをコメントアウトします。

    # LifecycleHook:
    #     Type: AWS::CloudFormation::Stack
    #     Properties:
    #         TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/lifecyclehook.yaml
    #         Parameters:
    #             Cluster: !GetAtt ECS.Outputs.Cluster
    #             ECSAutoScalingGroupName: !GetAtt ECS.Outputs.ECSAutoScalingGroupName
    

ビルド&デプロイ

  1. CodeBuildで検証とビルドを行うためのbuildspec.ymlが用意されているので、CodeBuildします。
  2. ついでにCodeBuildの環境変数の S3_BUCKET に当該テンプレートを配置するS3バケット名を指定して、ビルド実行すれば当該テンプレートがS3に配置されるよう対応しておきました。こちら
  3. 上記で配置されたテンプレートのmaster.yamlのURLを指定して、CloudFoamationを実行すれば目的の環境が構成されます。
  4. 以下のようなURLがCloudFormationのOutputで確認できるので、アクセスして画面表示されることを確認します。
    http://fargate-xxxxxxxxx.ap-northeast-1.elb.amazonaws.com/
    http://fargate-xxxxxxxxx.ap-northeast-1.elb.amazonaws.com/products

まとめ

  • 割と簡単にFargateに対応できたと思います。
  • このテンプレートを拡張していけば良いわけです。
10
15
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
10
15