0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

インフラのコード化:CloudFormationを使ったECRとECSの自動化とCI/CDパイプライン設計

Last updated at Posted at 2024-11-16

はじめに

この記事では、前回手動で作成したリソースをCloudFormationを使ってコード化する方法について解説します。

具体的には、ECRにDockerイメージをプッシュした後、そのイメージをECSでデプロイし、実際に動作させる流れをCloudFormationを使って実装します。

記事内容は将来の自分への備忘録として記録したものであるため、ご了承ください。

前回のおさらい

前回の記事では、ECRのプライベートリポジトリに以下のような構成のDockerfileと簡単なHTMLファイルを準備し、そのDockerイメージをECRにプッシュしました。

プロジェクト構成

├── Dockerfile
└── html/
    └── index.html

このDockerイメージをECRにプッシュした後、そのイメージをECSでデプロイし、実際に動作させました。

本記事では、VPCなどのシンプルなネットワーク構成からECS周りの設定までをCloudFormationでコード化し、より簡単にデプロイする方法を紹介します。

CloudFormationによるECSとECRの設定

以下のCloudFormationテンプレートを使用して、ECSの設定をコードで管理していきます。これにより、手動での設定作業を減らし、インフラの再現性を高めることができます。

test.yaml
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  # VPCの作成
  VPC:
    Type: "AWS::EC2::VPC"
    Properties:
      CidrBlock: "10.0.0.0/16"
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: "Name"
          Value: "honda-vpc"

  # サブネットの作成
  PublicSubnet1:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.0.0/20"
      AvailabilityZone: "ap-northeast-1a"
      Tags:
        - Key: "Name"
          Value: "honda-subnet-public1-ap-northeast-1a"

  # インターネットゲートウェイの設定
  InternetGateway:
    Type: "AWS::EC2::InternetGateway"
    Properties:
      Tags:
        - Key: "Name"
          Value: "honda-igw"

  AttachInternetGateway:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

  # ルートテーブルの設定
  PublicRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: "Name"
          Value: "honda-rtb-public"

  PublicRoute:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway

  SubnetRouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  # ECS用セキュリティグループ
  SecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      GroupDescription: "Allow HTTP traffic"
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: "tcp"
          FromPort: 80
          ToPort: 80
          CidrIp: "0.0.0.0/0"

  # ECSクラスターの作成
  ECSCluster:
    Type: "AWS::ECS::Cluster"
    Properties:
      ClusterName: "my-ecs-cluster"

  # ECSタスク定義
  ECSTaskDefinition:
    Type: "AWS::ECS::TaskDefinition"
    Properties:
      Family: "my-app-task"
      RequiresCompatibilities:
        - FARGATE
      NetworkMode: "awsvpc"
      Cpu: "256"
      Memory: "512"
      ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn
      ContainerDefinitions:
        - Name: "my-app-container"
          Image: "xxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-app-repo:latest"
          PortMappings:
            - ContainerPort: 80
              HostPort: 80
              Protocol: "tcp"

  # ECSタスク実行ロール
  ECSTaskExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service: "ecs-tasks.amazonaws.com"
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: "ecsTaskExecutionPolicy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "ecr:GetAuthorizationToken"
                  - "ecr:GetDownloadUrlForLayer"
                  - "ecr:BatchGetImage"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                  - "s3:GetObject"
                Resource: "*"

  # ECSサービスの作成
  ECSService:
    Type: "AWS::ECS::Service"
    Properties:
      Cluster: !Ref ECSCluster
      TaskDefinition: !Ref ECSTaskDefinition
      DesiredCount: 1
      LaunchType: "FARGATE"
      NetworkConfiguration:
        AwsvpcConfiguration:
          Subnets:
            - !Ref PublicSubnet1
          SecurityGroups:
            - !Ref SecurityGroup
          AssignPublicIp: "ENABLED"

# ECSタスク定義Image: "xxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-app-repo:latest"の部分は、実際のECRのURIに置き換えて修正してください。

CloudFormationテンプレートの説明

AWS::ECS::Cluster リソースを使って、Fargateを使ったECSクラスターを作成します。

  # ECSクラスターの作成
  ECSCluster:
    Type: "AWS::ECS::Cluster"
    Properties:
      ClusterName: "my-ecs-cluster"

AWS::ECS::TaskDefinition リソースを使って、コンテナの設定(イメージ、メモリ、CPUなど)を記述したタスク定義を作成します。

  # ECSタスク定義
  ECSTaskDefinition:
    Type: "AWS::ECS::TaskDefinition"
    Properties:
      Family: "my-app-task"
      RequiresCompatibilities:
        - FARGATE
      NetworkMode: "awsvpc"
      Cpu: "256"
      Memory: "512"
      ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn
      ContainerDefinitions:
        - Name: "my-app-container"
          Image: "340823193247.dkr.ecr.ap-northeast-1.amazonaws.com/my-app-repo:latest"
          PortMappings:
            - ContainerPort: 80
              HostPort: 80
              Protocol: "tcp"

AWS::ECS::Service リソースで、作成したクラスター上にタスクを実行するためのサービスを作成します。ネットワーキング設定には、必要なVPCやセキュリティグループを設定します。

  # ECSサービスの作成
  ECSService:
    Type: "AWS::ECS::Service"
    Properties:
      Cluster: !Ref ECSCluster
      TaskDefinition: !Ref ECSTaskDefinition
      DesiredCount: 1
      LaunchType: "FARGATE"
      NetworkConfiguration:
        AwsvpcConfiguration:
          Subnets:
            - !Ref PublicSubnet1
          SecurityGroups:
            - !Ref SecurityGroup
          AssignPublicIp: "ENABLED"

実際にやってみた

上記のCloudFormationテンプレートを使って、ECSクラスターを作成し、タスク定義とサービスを設定しました。

CloudFormationのサービス画面からスタックの作成に進み、作成したyamlファイルをアップロードします。

image.png

スタック名は任意で設定できます。ここでは私の名前「honda」としています。

image.png

画面遷移後のスタックオプション設定については、個々の設定に依存するため、私は設定せずに進めていきます。

ただ、スタックの中でIAMを使う場合は、以下のように確認が求められますでの、✅を入れて進んでください。

スクリーンショット 2024-11-13 20.19.18.png

最後に確認を行い、問題がなければ最下部までスクロールし、「送信」をクリックして完了です。

image.png

スタックを実行後、イベントタブで成功したことが確認できました(しばらく時間がかかります)。

image.png

デプロイ後の動作確認

デプロイが完了したら、タスクが正常に実行されていることを確認します。

image.png

ECSページの「クラスター」→「タスク」タブから、実行中のタスクを選択し、タスクのパブリックIPを確認します。

image.png

ここで、タスクが使用しているパブリックIP(例:18.183.70.246)を確認したら、ブラウザでアクセスしてみます。

http://18.183.70.246/

実際に、前回ECRにプッシュしたindex.htmlファイルの内容が表示されていることを確認できました。この確認をもって、検証は大成功です!

image.png

今回は検証のため、ホストポートとコンテナポートを両方 80 に設定しているため、HTTP通信で接続しています。

まとめ

ECSなどのコンテナをコード化するのは、思った以上に手間がかかり、何度もエラーに直面しました。

特に、CloudFormationを使ったリソースの設定には多くの調整が必要で、時間がかかりました。

最初は手動で設定した方が早いと思いましたが、最終的にはコード化することで再利用性が高まり、運用面での効率化が実現できました。

関連記事

CloudFormationによるインフラのコード化についても過去の記事で解説しているため、より深く知りたい方は読んでみてください!

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?