Fargate を使って Docker コンテナを起動する方法

2023年2月21日AWS,コンテナAWS,CloudFormation,Docker,Fargate

Fargate を CloudFormation から構築する手順を整理してみた

Fargate はインフラ部分をAWSに丸投げしてコンテナを利用できる、サーバレスなサービスです。

FargateでNginxを動かすところまでCloudFormationを使って構築していきます。

この記事で触れる内容

  • CloudFormationでリソースを作成する
  • Fargate でNginxを動かす

この記事で作成する環境

今回のゴールは以下の構成です。

完成品はこちらのリポジトリにあります。

作成するリソース

ざっくり以下のリソースです。

サービス名リソース用途
VPCVPCECSを起動するためのネットワーク
VPCSubnetECSを起動するためのネットワーク
EC2SecurityGroupALB用・ECS用
EC2ApplicationLoadBalancerコンテナの負荷分散用
IAMRoleECSのタスク実行ロール
ECSTaskDefinitionコンテナ起動用のタスク定義
ECSServiceサービス
ECSClusterクラスター

ネットワーク部分作成

まずは、Fargateが動作するためのネットワーク部分を作成していきます。

メインのコンテンツではないので解説は割愛します。

AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  CidrIp:
    Type: String
    Description: secondary octet ip addr
  Project:
    Type: String 

  Vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Sub '10.${CidrIp}.0.0/16'
      EnableDnsHostnames: True
      Tags:
        - Key: Name
          Value: !Ref Project
        - Key: Project
          Value: !Ref Project
  Igw:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Ref Project
        - Key: Project
          Value: !Ref Project
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref Vpc
      InternetGatewayId: !Ref Igw

  ##----------------------------------##
  # Subnets
  ##----------------------------------##
  SubnetPublic1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      VpcId: !Ref Vpc
      CidrBlock: !Sub 10.${CidrIp}.10.0/24
      MapPublicIpOnLaunch: 'true'
      Tags:
        - Key: Name
          Value: !Ref Project
        - Key: Project
          Value: !Ref Project
  SubnetPublic2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1c
      VpcId: !Ref Vpc
      CidrBlock: !Sub 10.${CidrIp}.20.0/24
      MapPublicIpOnLaunch: 'true'
      Tags:
        - Key: Name
          Value: !Ref Project
        - Key: Project
          Value: !Ref Project

  ##----------------------------------##
  # RouteTable
  ##----------------------------------##
  RouteTableForPublicSubnet:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref Vpc
      Tags:
        - Key: Name
          Value: !Ref Project
        - Key: Project
          Value: !Ref Project
  DefaultRouteForPublicSubnet:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref RouteTableForPublicSubnet
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref Igw    
  RouteAssocPubSubnet1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetPublic1
      RouteTableId: !Ref RouteTableForPublicSubnet
  RouteAssocPubSubnet2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetPublic2
      RouteTableId: !Ref RouteTableForPublicSubnet

構成としてはとてもシンプルなネットワーク部分だけ構築されます。

また、上記のテンプレートはこちらのリポジトリをベースに作成しています。

タスク実行ロール作成

次にタスク実行ロールを作成する記述をご紹介します。

  ##----------------------------------##
  # Task Execute Role                 
  ##----------------------------------##
  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub '${Project}-task-role'
      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が利用するロールになります。

セキュリティーグループの作成

次にセキュリティグループを作成する記述です。

セキュリティグループは、インターネットからのhttpアクセスを許可するALB用と、ALB経由のhttpアクセスのみ許可するECS用の2つを作成します。

  ##----------------------------------##
  # Security Group            
  ##----------------------------------##
  AlbSg:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub "${Project}-alb-sg"
      GroupDescription: allowed http access from internet.
      VpcId: !Ref Vpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Ref Project
        - Key: Project
          Value: !Ref Project

  EcsSg:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub "${Project}-ecs-sg"
      GroupDescription: allowed http access from alb.
      VpcId: !Ref Vpc
      SecurityGroupIngress:
        - SourceSecurityGroupId: !Ref AlbSg
          IpProtocol: tcp
          FromPort: 80
          ToPort: 80
      Tags:
        - Key: Name
          Value: !Ref Project
        - Key: Project
          Value: !Ref Project

ALBの作成

次にALBを作成する記述をご紹介します。

今回は、複数のコンテナを作成してALBで負荷分散する構成になります。

  ##----------------------------------##
  # ALB            
  ##----------------------------------##
  Alb:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      Type: application
      SecurityGroups:
        - !Ref AlbSg
      Subnets:
        - !Ref SubnetPublic1
        - !Ref SubnetPublic2
      Tags:
        - Key: Name
          Value: !Ref Project
        - Key: Project
          Value: !Ref Project
  AlbTg:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      VpcId: !Ref Vpc
      Name: !Sub "${Project}-tg"
      Protocol: HTTP
      Port: 80
      TargetType: ip
      Tags:
        - Key: Name
          Value: !Ref Project
        - Key: Project
          Value: !Ref Project

  AlbListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref Alb
      Protocol: HTTP
      Port: 80
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref AlbTg

ここまでのリソースを作成すると以下のような構成になります。

ALBを作成したところまで

タスク定義の作成

ここからがECSに関連するリソースです。

タスク定義とは、ECSでコンテナを起動させる時に必要な定義です。

例えばコンテナように確保するリソースや動作させるイメージを指定します。

  ##----------------------------------##
  # TaskDefinition            
  ##----------------------------------##
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Sub "${Project}-ecs-task"
      RequiresCompatibilities:
        - FARGATE
      NetworkMode: awsvpc
      ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn
      Cpu: 256
      Memory: 512
      ContainerDefinitions:
        - Name: !Sub "${Project}-container"
          Image: nginx:latest
          PortMappings:
            - HostPort: 80
              Protocol: tcp
              ContainerPort: 80

「タスク実行ロール」と「タスクロール」

ECSタスク定義には、「タスク実行ロール」と「タスクロール」があります。

前者は必須でECSが実行するために必要なロール、後者は起動したコンテナに付与される任意のロールで、例えば起動したコンテナにS3操作をさせる場合に必要です。

サービスの作成

次にサービスを作成する記述を紹介します。

サービスとは、起動したコンテナをまとめるためのグループです。

起動するコンテナの個数、紐づけるセキュリティーグループ、負荷分散に使うALBなどの設定を行います。

  Service:
    Type: AWS::ECS::Service
    DependsOn: Alb
    Properties:
      Cluster: !Ref Cluster
      LoadBalancers:
        - TargetGroupArn: !Ref AlbTg
          ContainerPort: 80
          ContainerName: !Sub "${Project}-container"
      LaunchType: FARGATE
      DesiredCount: 3
      TaskDefinition: !Ref TaskDefinition
      ServiceName: !Sub "${Project}-service"
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - !Ref EcsSg
          Subnets:
            - !Ref SubnetPublic1
            - !Ref SubnetPublic2

ポイントは、DependsOnです。

テンプレートを実行するとき、CloudFormationがわでよしなに順番を決めて事項してくれますが、依存関係を解決しきれないこともあります。

今回の場合、ServiceとALBの関係がそれに当たります。

ALBがまだ作成されていない状態でServiceを作成しようとしているので「参照しているターゲットグループがALBに紐づいていない」みたいなエラーになります。

DependsOnをつけることでServiceの作成順をALBよりも後にできます。

クラスターの作成

最後にクラスターを作成する記述の紹介です。

クラスターは、サービスをまとめる論理的なグループです。

ここまでの解説で、「タスク定義」を包括するのが「サービス」のイメージですが、クラスターはそのサービスを包括するというものになります。

  ##----------------------------------##
  # Cluster          
  ##----------------------------------##
  Cluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub "${Project}-cluster"

稼働確認

fgt_稼働確認

では、ALBのDNS名にアクセスしてコンテナが起動しているかを確認します。

問題なく動いていますね。

ここから先は、自分でビルドしDockerイメージを使うためにECRを使ったり、AutoScalingの設定を入れたりとご自身で調整してみてください。

CodePipelineの基本的な内容もご紹介しているので、コンテナのCICDにもぜひ挑戦してみてください。

1人で進めるのが難しい?

私は、AWSに関するスキルをRaiseTechのAWSフルコースからスタートさせました。

入会&受講後の感想はコチラ

コース受講後も、半永久的に質問し放題なので転職後の今も技術的な悩みを相談しています。

RaiseTechは毎週金曜日20時から無料説明会を開催しています。

IT業界や転職について「本当に無料?」というくらいボリュームのある内容でしたのでぜひみてみてください!

AWS,コンテナAWS,CloudFormation,Docker,Fargate

Posted by kotaro