LoginSignup
4
1

More than 1 year has passed since last update.

[社内勉強会資料] CloudFormationで構築する自動デプロイ環境 ~ 3/6

Last updated at Posted at 2022-08-16

第3回CloudFormationテンプレートの実行(ECS)

さて第3回の今回は、本記事に記載のCloudFormationテンプレートを用いて、自動デプロイのデプロイ先となるECSとECRを構築していきます。

前回:[社内勉強会資料] CloudFormationで構築する自動デプロイ環境 ~ 2/6

CloudFormationで作成するリソース

  • CloudFormationテンプレートを使って、以下のAWSリソースを作成します。
    • ECR
    • ALB
      • Listener
      • TargetGroup
    • ECS
      • Cluster
      • Service
      • TaskDefinition
    • IAM
      • Role
    • CloudWatch
      • LogGroup

CloudFormationテンプレート

ecr.yaml

AWSTemplateFormatVersion: '2010-09-09'
Description: ECR template

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "Environment Name"
        Parameters:
          - ProjectEnvironment
      - Label:
          default: "ECR Repository Configuration"
        Parameters:
          - ImageTagMutability

Parameters:
  ProjectEnvironment:
    Type: String
    Default: 'usecase-auto-deploy'
  # 同じタグによる上書きを許可する(デフォルト)
  ImageTagMutability:
    Description: The tag mutability setting for the repository.
    Type: String
    Default: MUTABLE
    AllowedValues:
      - IMMUTABLE
      - MUTABLE

Resources:
  ECRRepository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: !Sub "${ProjectEnvironment}-ecr"
      ImageTagMutability: !Ref ImageTagMutability
      # ライフサイクル : イメージが20個以上になった場合、古い順に削除する
      LifecyclePolicy:
        LifecyclePolicyText: |
          {
            "rules": [
              {
                "rulePriority": 1,
                "description": "Delete more than 20 images",
                "selection": {
                "tagStatus": "any",
                "countType": "imageCountMoreThan",
                "countNumber": 20
              },
                "action": {
                "type": "expire"
                }
              }
            ]
          }

Outputs:
  ECRRepository:
    Value: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepository}"
    Export:
      Name: !Sub "${ProjectEnvironment}-ecr-uri"

fargate.yaml

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

Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "Project Name Prefix"
        Parameters:
          - ProjectName
      - Label:
          default: "InternetALB Configuration"
        Parameters:
          - InternetALBName
          - TargetGroupName
          - CertificateArn
          - HostedZoneName
          - WebsiteDomainName
      - Label:
          default: "Fargate for ECS Configuration"
        Parameters:
          - ECSClusterName
          - ECSTaskName
          - ECSTaskCPUUnit
          - ECSTaskMemory
          - ECSContainerName
          - ECSImageName
          - ECSServiceName
          - ECSTaskDesiredCount
      - Label:
          default: "Scaling Configuration"
        Parameters:
          - TaskMinContainerCount
          - TaskMaxContainerCount

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

Parameters:
  ProjectName:
    Default: usecase-auto-deploy
    Type: String

#InternetALB
  InternetALBName:
    Type: String
    Default: "alb"

#TargetGroupName
  TargetGroupName:
    Type: String
    Default: "tg"

#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"

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

#ECSTaskDesiredCount
  ECSTaskDesiredCount:
    Type: Number
    Default: 1

  TaskMinContainerCount:
    Type: Number
    Description: Minimum number of containers to run for the service
    Default: 1
    MinValue: 1
    ConstraintDescription: Value must be at least one

  TaskMaxContainerCount:
    Type: Number
    Description: Maximum number of containers to run for the service when auto scaling out
    Default: 2
    MinValue: 1
    ConstraintDescription: Value must be at least one

Resources:
  TargetGroup:
    Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
    Properties:
      VpcId:
        Fn::ImportValue: !Sub "${ProjectName}-vpc"
      Name: !Sub "${ProjectName}-${TargetGroupName}"
      Protocol: HTTP
      Port: 80
      TargetType: ip
      HealthCheckEnabled: true
      HealthCheckPath: '/index.html'
      Matcher:
        HttpCode: "302,200"

  InternetALB:
    Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
    Properties:
      Name: !Sub "${ProjectName}-${InternetALBName}"
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-${InternetALBName}"
      Scheme: "internet-facing"
      LoadBalancerAttributes:
        - Key: "deletion_protection.enabled"
          Value: false
        - Key: "idle_timeout.timeout_seconds"
          Value: 60
      SecurityGroups:
        - Fn::ImportValue: !Sub "${ProjectName}-ALBSecurityGroupId"
      Subnets:
        - Fn::ImportValue: !Sub "${ProjectName}-ALBSubnetId1"
        - Fn::ImportValue: !Sub "${ProjectName}-ALBSubnetId2"

  ALBListener:
    Type: "AWS::ElasticLoadBalancingV2::Listener"
    Properties:
      DefaultActions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward
      LoadBalancerArn: !Ref InternetALB
      Port: 80
      Protocol: HTTP

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

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

  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${ProjectName}-ECSTaskExecutionRolePolicy-${AWS::Region}"
      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

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

      ContainerDefinitions:
        - Name: "app"
          Image:
            !Sub
              - "${ECR_URI}:latest"
              - ECR_URI:  {"Fn::ImportValue": !Sub "${ProjectName}-ecr-uri"}
          Command:
            - "/bin/sh -c \"echo '<html> <head> <title>Amazon ECS Sample App</title> <style>body {margin-top: 40px; background-color: #333;} </style> </head><body> <div style=color:white;text-align:center> <h1>Amazon ECS Sample App</h1> <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p> </div></body></html>' >  /var/www/html/index2.html && /root/run_apache.sh\""
          EntryPoint:
            - "sh"
            - "-c"
          Environment:
            - Name: 'AWS_REGION'
              Value: 'ap-northeast-1'
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref ECSLogGroup
              awslogs-region: !Ref "AWS::Region"
              awslogs-stream-prefix: !Ref ProjectName
          MemoryReservation: 128
          Essential: true
          PseudoTerminal: true
          PortMappings:
            - HostPort: 80
              Protocol: tcp
              ContainerPort: 80

  ECSService:
    Type: AWS::ECS::Service
    DependsOn: ALBListener
    Properties:
      Cluster: !Ref ECSCluster
      DesiredCount: !Ref ECSTaskDesiredCount
      LaunchType: FARGATE
      LoadBalancers:
        -
          TargetGroupArn: !Ref TargetGroup
          ContainerPort: 80
          ContainerName: "app"
      NetworkConfiguration:
       AwsvpcConfiguration:
           AssignPublicIp: ENABLED
           SecurityGroups:
            - Fn::ImportValue: !Sub "${ProjectName}-ECSSecurityGroupId"
           Subnets:
            - Fn::ImportValue: !Sub "${ProjectName}-ECSSubnetId1"
            - Fn::ImportValue: !Sub "${ProjectName}-ECSSubnetId2"
      ServiceName: !Sub "${ProjectName}-${ECSServiceName}"
      TaskDefinition: !Ref ECSTaskDefinition

ECR構築

まずはDockerコンテナの実体となるイメージを配置するためのECRの構築から進めましょう。

ECR構築:ecr.yamlの実行 ステップ1

  1. テンプレートの準備で「テンプレートの準備完了」を選択
  2. テンプレートの指定で「テンプレートファイルのアップロード」を選択
  3. テンプレートファイルのアップロードで「ecr.yaml」(上記) をアップロード
  4. [次へ」をクリック
    image.png

ECR構築:ecr.yamlの実行 ステップ2

  1. スタック名に「usecase-auto-deploy-ecr」を指定する
    1. パラメータは変更不要
  2. [次へ」をクリック
    image.png

ECR構築:ecr.yamlの実行 ステップ3

  1. すべてデフォルトのまま「次へ」をクリック
    image.png

ECR構築:ecr.yamlの実行 ステップ4

  1. そのまま「スタックの作成」をクリック
    image.png

ECR構築:スタック作成の結果を確認

  1. スタックの作成が成功すると、「CREATE_COMPLETE」のステータスになる
    image.png

ECR構築:リソースの確認

  1. テンプレートによって作成されたリソースを「リソース」タブで確認する
    image.png

ECR構築:コンテナイメージのPush

  1. コマンドプロンプト (ここではPowerShellを前提としています。) を開き、下記コマンドを実行します

Docker Desktopは起動しておいてください。

# 各自 GitHubの auto-deploy を git cloneしたディレクトリに移動します
PS cd C:\git\auto-deploy
# 各自リージョンで置換してください
PS $region=“リージョン ( : ap-northeast-1)
PS $account_id=ECRを作成したAWSアカウントID ( : 1234567)
# Macの場合
$ region=“リージョン ( : ap-northeast-1)
$ account_id=ECRを作成したAWSアカウントID ( : 1234567)
# ECRへログイン
PS aws ecr get-login-password --region $region | docker login --username AWS --password-stdin  "$account_id.dkr.ecr.$region.amazonaws.com"
# コンテナイメージをビルド
PS docker build -t "$account_id.dkr.ecr.$region.amazonaws.com/usecase-auto-deploy-ecr:latest" .
# コンテナイメージをECRへプッシュ
PS docker push "$account_id.dkr.ecr.$region.amazonaws.com/usecase-auto-deploy-ecr:latest"

ECRへのログイン時、必要に応じてプロファイルを指定してください。

# プロファイルの指定方法
PS aws ecr get-login-password --region $region --profile handson | 

ECR構築:ECRの確認

  1. ECR > リポジトリ > usecase-auto-deploy-ecr から内容を確認することができます
    image.png

ECSの構築

続けて、直前の手順でECRにPushしたコンテナを起動するためのECSの構築を行います。

ECSの構築:fargate.yamlの実行 ステップ1

  1. テンプレートの準備で「テンプレートの準備完了」を選択
  2. テンプレートの指定で「テンプレートファイルのアップロード」を選択
  3. テンプレートファイルのアップロードで「fargate.yaml」(添付ファイル参照) をアップロード
  4. [次へ」をクリック
    image.png

ECSの構築:fargate.yamlの実行 ステップ2

  1. スタック名に「usecase-auto-deploy-fargate」を指定する
  2. [次へ」をクリック
    image.png

ECSの構築:fargate.yamlの実行 ステップ3

  1. チェックボックスにチェックを入れ、「スタックの作成」をクリック
    image.png

ECS構築:スタック作成の結果を確認

  1. スタックの作成が成功すると、「CREATE_COMPLETE」のステータスになる
    image.png

  2. ECSのタスクが起動すると「RUNNING」のステータスになる
    image.png

連載の第3回となる今回はここまで。

次回第4回は、自動デプロイの実行に必要な権限(IAMロール)を構築していきます。

次回:[社内勉強会資料] CloudFormationで構築する自動デプロイ環境 ~ 4/6

4
1
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
1