💨

AWS、React、GolangによるWebアプリ開発~本番環境構築編~

2023/01/19に公開

@nerusanです。
前回の記事では、環境構築の方法とポイントを述べました。

https://zenn.dev/yuki_tu/articles/bcb926b0ebae47

今回は、AWSでの環境構築について述べます。

今回も前回と同様に具体的な手順を述べるのはなく、
具体的なポイントや用語について述べていきます。

ECS/Fargateについて

まず、ECS/Fargateについて軽く述べたいと思います。

Amazon Elastic Container Service(ECS)は、フルマネージドなコンテナオーケストレータです。
つまり、コンテナを管理する機能を提供するものです。

オーケストレーションとしてよく挙げられるのが、kubernetes(k8s)があります。

k8sは、オープンソースとなっており、その特性上、クリティカルな課題が発生した時に自身で解決するか、コミュニティでIssueとして取り上げ、解決するということになります。

その点、ECSは、AWSが提供する独自のオーケストレータなので、AWSのサポートが受けられます。そのため導入のためのハードルが低く、スタートアップ企業などで採用されやすいです。

オーケストレータが解決するのは、コンテナの配置管理であり、具体的には以下のような点があります。

  • コンテナの負荷分散
    • 処理量に応じてリクエストを分散させ、可用性やパフォーマンスを高めます
  • コンテナの状態監視と自動復旧
    • コンテナの状態を監視し、異常発生を検知してコンテナの切り離しや自動復旧によるコンテナ数を維持することでサービスの安定稼働させます
  • コンテナのデプロイ
    • アプリケーションを更新する際、すでに稼働中のアプリケーションを停止しつつ、新しいコンテナに自動に入れ替えることがスムーズにできます

次は、AWS Fargateについて述べます。
AWS Fargate(Fargate)は、ECSで動作するコンテナ向けサーバーレスコンピューティングエンジンです。
つまり、コンテナが実際に動作するサーバーとなります。
Fargate単体で利用することはできず、ECSとセットで利用する必要があります。

Fargateでは、ホストの管理が不要となります。サーバーのスケーリング、パッチ管理、保護など運用上の管理は発生しません。
コンテナが実行されるホストのインフラはAWSによって常に最新の状態に保たれます。

利用者は、ホストの管理から解放され、自分たちのビジネスに注力できるのはメリットです。

バックエンド側ネットワークの構築

公開構築する全体像を示します。

▼図1:全体像

ここで、いろいろな用語が出てきます。

まずは簡単に用語の説明をします。

  • VPC(Virtual Private Cloud)
    • AWSアカウント専用の仮装ネットワーク
  • インターネットゲートウェイ
    • AWS VPC領域から外、つまりインターネット領域へ出るための出入り口の役割を担う
    • 1つのVPCに1つのインターネットゲートウェイをアタッチすることができる
  • パブリックサブネット
    • インターネットゲートウェイにルーティングすることができるサブネット
    • インターネットに繋げる必要があるロードバランサーやNatGatewayはパブリックサブネットに属させる
  • プライベートサブネット
    • ルーティングされておらず、非公開となっているサブネット
    • 外から自由にアクセスさせたくないDBやCache、containerなどはプライベートサブネットに属させる
  • NATGateway(Network Address Transfer Gateway)
  • ECR(Elastic Container Registry)
    • フルマネージドなDockerコンテナレジストリサービス
    • Dockerイメージを管理する

VPCの中にサブネットを配置して、各サブネット間が通信することでアプリケーションを動作させます。
また、外部の通信はインターネットゲートウェイ、NATGatewayを設定することで可能となります。
また、サブネット間の通信経路は、ルートテーブルとセキュリティグループによって制御することができます。

図1のサブネット名の説明は以下です。

  • Ingress
    • インターネットからリクエストを受け付ける Ingress(Application Load Balancer)用サブネット
    • NATGatewayを配置用サブネット
  • container
    • アプリ稼働(go起動サーバー)用サブネット
  • db
    • データベース(MySQL)用サブネット
  • cache
    • キャッシュサーバー(Redis)用サブネット
  • management
    • 運用管理用サブネット
    • キャッシュ、DBに直接アクセスしたりする踏み台サーバーを置く
  • egress
    • ECR など外部にリクエストするインターフェース型 VPC エンドポイント用サブネット

ルートテーブル

ルートテーブルとは、ネットワークの経路を設定するためのリソースです。
新規でルートテーブルを作成した時点では、VPC内のサブネット間の通信は設定されていますが、
インターネットと通信するためのルーティングは設定されていません。
パブリックサブネットがインターネット側と通信できるようにルーティングの設定を行う必要があります。
宛先としてデフォルトゲートウェイ(0.0.0.0/0)が指定された場合にインターネットゲートウェイへ向けるルールを設定します。

セキュリティグループ

アクセスの制御を行います。
アウトバウンドルールは「0.0.0.0/0」を許可し、インバウンドルールは最小限にします。
インバウンドルールを最小にすることで、セキュリティを向上させます。
詳しくは、以下のサイトを見るとわかりやすいです。

https://dev.classmethod.jp/articles/ec2-cacess/

NATGateway

今回GolangのアプリケーションではAmason SES API v1を利用して、メールを送信します。こちらのAPIは、HTTPSを利用して外部インターネットを通して、SESにアクセスし、メール送信を依頼します。つまり、プライベートサブネットであるcontainerからインターネットにアクセスする必要があります。

プライベートサブネットは、インターネットに繋げることができないため、NATGatewayを設定してあげる必要があります。

IaC化

ネットワークの構築は、IaC(Infrastructure as Code)化することで、効率化につながります。
つまり、Dockerfileやdocker-compose.ymlと同様に、インフラ周りの設定などをコードとして残すことで、環境の再利用、人的ミスを減らすことができます。

IaCは有名どころとしてterraformなどがありますが、今回はAWSを利用するということで、Cloud Formationを利用しました。

https://aws.amazon.com/jp/cloudformation/

NAT Gateway以外のIacは以下に示します。VPC,サブネット、ルートテーブル、インターネットゲートウェイ、セキュリティグループの設定をしています。

IaC(cloud formation)
network.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Network resource template part1
Resources:
  # VPCの設定
  pointAppVpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: pointAppVpc
  
  ############### Subnet, RouteTable, IGW ###############
  # コンテナ周りの設定
  ## コンテナアプリ用のプライベートサブネット
  pointAppSubnetPrivateContainer1A:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.8.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 0
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: point-app-subnet-private-container-1a
        - Key: Type
          Value: Isolated
  pointAppSubnetPrivateContainer1C:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.9.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 1
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: point-app-subnet-private-container-1c
        - Key: Type
          Value: Isolated
  ## コンテナアプリ用のルートテーブル
  pointAppRouteApp:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: pointAppVpc
      Tags:
        - Key: Name
          Value: piint-app-route-app
  ## コンテナサブネットへルート紐付け
  pointAppRouteAppAssociation1A:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: pointAppRouteApp
      SubnetId: !Ref pointAppSubnetPrivateContainer1A
  pointAppRouteAppAssociation1C:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: pointAppRouteApp
      SubnetId:
        Ref: pointAppSubnetPrivateContainer1C

  # DB周りの設定
  ## DB用のプライベートサブネット
  pointAppSubnetPrivateDb1A:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.16.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 0
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: point-app-subnet-private-db-1a
        - Key: Type
          Value: Isolated
  pointAppSubnetPrivateDb1C:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.17.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 1
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: point-app-subnet-private-db-1c
        - Key: Type
          Value: Isolated
  ## DB用のルートテーブル
  pointAppRouteDb:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: pointAppVpc
      Tags:
        - Key: Name
          Value: point-app-route-db
  ## DBサブネットへルート紐付け
  pointAppRouteDbAssociation1A:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: pointAppRouteDb
      SubnetId:
        Ref: pointAppSubnetPrivateDb1A
  pointAppRouteDbAssociation1C:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: pointAppRouteDb
      SubnetId:
        Ref: pointAppSubnetPrivateDb1C

  # Cacheの設定
  # Cache Server用のプライベートサブネット
  pointAppSubnetPrivateCache1A:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.24.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 0
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: point-app-subnet-private-cache-1a
        - Key: Type
          Value: Isolated
  pointAppSubnetPrivateCache1C:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.25.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 1
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: point-app-subnet-private-cache-1c
        - Key: Type
          Value: Isolated
  ## Cache用のルートテーブル
  pointAppRouteCache:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: pointAppVpc
      Tags:
        - Key: Name
          Value: point-app-route-cache
  ## Cacheサブネットへルート紐付け
  pointAppRouteCacheAssociation1A:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: pointAppRouteCache
      SubnetId:
        Ref: pointAppSubnetPrivateCache1A
  pointAppRouteCacheAssociation1C:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: pointAppRouteCache
      SubnetId:
        Ref: pointAppSubnetPrivateCache1C

  # Ingress周りの設定
  ## Ingress用のパブリックサブネット
  pointAppSubnetPublicIngress1A:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.0.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 0
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: point-app-subnet-public-ingress-1a
        - Key: Type
          Value: Public
  pointAppSubnetPublicIngress1C:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.1.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 1
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: point-app-subnet-public-ingress-1c
        - Key: Type
          Value: Public
  ## Ingress用のルートテーブル
  pointAppRouteIngress:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: pointAppVpc
      Tags:
        - Key: Name
          Value: point-app-route-ingress
  ## Ingressサブネットへルート紐付け
  pointAppRouteIngressAssociation1A:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: pointAppRouteIngress
      SubnetId:
        Ref: pointAppSubnetPublicIngress1A
  pointAppRouteIngressAssociation1C:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: pointAppRouteIngress
      SubnetId:
        Ref: pointAppSubnetPublicIngress1C
  ## Ingress用ルートテーブルのデフォルトルート
  ## 0.0.0.0/0が指定されたらインターネットゲートウェイに紐づけるルール
  pointAppRouteIngressDefault:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: pointAppRouteIngress
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId:
        Ref: pointAppIgw
    DependsOn:
      - pointAppVpcgwAttachment

  # 管理用サーバ周りの設定
  ## 管理用のパブリックサブネット
  pointAppSubnetPublicManagement1A:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.240.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 0
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: point-app-subnet-public-management-1a
        - Key: Type
          Value: Public
  pointAppSubnetPublicManagement1C:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.241.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 1
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: point-app-subnet-public-management-1c
        - Key: Type
          Value: Public
  ## 管理用サブネットのルートはIngressと同様として作成する
  pointAppRouteManagementAssociation1A:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: pointAppRouteIngress
      SubnetId:
        Ref: pointAppSubnetPublicManagement1A
  pointAppRouteManagementAssociation1C:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: pointAppRouteIngress
      SubnetId:
        Ref: pointAppSubnetPublicManagement1C

  # インターネットへ通信するためのゲートウェイの作成
  pointAppIgw:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: point-app-igw
  pointAppVpcgwAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId:
        Ref: pointAppVpc
      InternetGatewayId:
        Ref: pointAppIgw

  # VPCエンドポイント周りの設定
  ## VPCエンドポイント(Egress通信)用のプライベートサブネット
  pointAppSubnetPrivateEgress1A:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.248.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 0
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: point-app-subnet-private-egress-1a
        - Key: Type
          Value: Isolated
  pointAppSubnetPrivateEgress1C:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.249.0/24
      VpcId:
        Ref: pointAppVpc
      AvailabilityZone: 
        Fn::Select: 
          - 1
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: point-app-subnet-private-egress-1c
        - Key: Type
          Value: Isolated

  ############### Security groups ###############
  # セキュリティグループの生成
  ## インターネット公開のセキュリティグループの生成
  pointAppSgIngress:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for ingress
      GroupName: ingress
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          Description: Allow all outbound traffic by default
          IpProtocol: "-1"
      SecurityGroupIngress:
        - CidrIp: 0.0.0.0/0
          Description: from 0.0.0.0/0:80
          FromPort: 80
          IpProtocol: tcp
          ToPort: 80
        - CidrIpv6: ::/0
          Description: from ::/0:80
          FromPort: 80
          IpProtocol: tcp
          ToPort: 80
      Tags:
        - Key: Name
          Value: point-app-sg-ingress
      VpcId:
        Ref: pointAppVpc
  ## 管理用サーバ向けのセキュリティグループの生成
  pointAppSgManagement:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security Group of management server
      GroupName: management
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          Description: Allow all outbound traffic by default
          IpProtocol: "-1"
      Tags:
        - Key: Name
          Value: point-app-sg-management
      VpcId:
        Ref: pointAppVpc
  ## バックエンドコンテナアプリ用セキュリティグループの生成
  pointAppSgContainer:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security Group of backend app
      GroupName: container
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          Description: Allow all outbound traffic by default
          IpProtocol: "-1"
      Tags:
        - Key: Name
          Value: point-app-sg-container
      VpcId:
        Ref: pointAppVpc
  ## DB用セキュリティグループの生成
  pointAppSgDb:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security Group of database
      GroupName: database
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          Description: Allow all outbound traffic by default
          IpProtocol: "-1"
      Tags:
        - Key: Name
          Value: point-app-sg-db
      VpcId:
        Ref: pointAppVpc
  ## VPCエンドポイント用セキュリティグループの生成
  pointAppSgEgress:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security Group of VPC Endpoint
      GroupName: egress
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          Description: Allow all outbound traffic by default
          IpProtocol: "-1"
      Tags:
        - Key: Name
          Value: point-app-sg-vpce
      VpcId:
        Ref: pointAppVpc
  ## Cache用セキュリティグループの生成
  pointAppSgCache:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security Group of VPC Endpoint
      GroupName: cache
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          Description: Allow all outbound traffic by default
          IpProtocol: "-1"
      Tags:
        - Key: Name
          Value: point-app-sg-cache
      VpcId:
        Ref: pointAppVpc

  # ルール紐付け
  ## Internet LB -> Back Container
  pointAppSgFrontContainerFromsSgIngress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      Description: HTTPS for Ingress
      FromPort: 80
      GroupId:
        Fn::GetAtt:
          - pointAppSgContainer
          - GroupId
      SourceSecurityGroupId:
        Fn::GetAtt:
          - pointAppSgIngress
          - GroupId
      ToPort: 80
  ## Back container -> DB
  pointAppSgDbFromSgContainerTCP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      Description: MySQL protocol from backend App
      FromPort: 3306
      GroupId:
        Fn::GetAtt:
          - pointAppSgDb
          - GroupId
      SourceSecurityGroupId:
        Fn::GetAtt:
          - pointAppSgContainer
          - GroupId
      ToPort: 3306
  ## Back container -> Cache
  pointAppSgCacheFromSgContainerTCP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      Description: Redis protocol from backend App
      FromPort: 6379
      GroupId:
        Fn::GetAtt:
          - pointAppSgCache
          - GroupId
      SourceSecurityGroupId:
        Fn::GetAtt:
          - pointAppSgContainer
          - GroupId
      ToPort: 6379
  ## Management server -> DB
  pointAppSgDbFromSgManagementTCP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      Description: MySQL protocol from management server
      FromPort: 3306
      GroupId:
        Fn::GetAtt:
          - pointAppSgDb
          - GroupId
      SourceSecurityGroupId:
        Fn::GetAtt:
          - pointAppSgManagement
          - GroupId
      ToPort: 3306
  ## Management Server -> Cache
  pointAppSgCacheFromSgManagementTCP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      Description: Redis protocol from management server
      FromPort: 6379
      GroupId:
        Fn::GetAtt:
          - pointAppSgCache
          - GroupId
      SourceSecurityGroupId:
        Fn::GetAtt:
          - pointAppSgManagement
          - GroupId
      ToPort: 6379
  ## Back container -> VPC endpoint
  pointAppSgVpceFromSgContainerTCP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      Description: HTTPS for Container App
      FromPort: 443
      GroupId:
        Fn::GetAtt:
          - pointAppSgEgress
          - GroupId
      SourceSecurityGroupId:
        Fn::GetAtt:
          - pointAppSgContainer
          - GroupId
      ToPort: 443
  ## Management Server -> VPC endpoint
  pointAppSgVpceFromSgManagementTCP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      Description: HTTPS for management server
      FromPort: 443
      GroupId:
        Fn::GetAtt:
          - pointAppSgEgress
          - GroupId
      SourceSecurityGroupId:
        Fn::GetAtt:
          - pointAppSgManagement
          - GroupId
      ToPort: 443

NATGatewayの設定は以下の記事を参考に手動で設定しました。(IaCに落とし込めてなくてすみません。)
https://qiita.com/fkooo/items/a474db0f3c2e72448d36

ECS/Fargateへのデプロイ

デプロイの流れは以下のようになります。

  1. dockerコマンドでdockerイメージを作成しlatestタグを付与して、ECRに登録
  2. ECSのコンテナ定義書を更新
  3. コンテナ定義書に従い、Dockerイメージを取得し、Fargate上にコンテナを配置

今回は、CI/CDツールとしてGitHub ActionとAWS CodePipelineの2種類を採用しました。

CI/CDとは「Continuous Integration(継続的インテグレーション)/ Continuous Delivery(継続的デリバリー)」の略称であり、テストやビルド、デプロイを自動化するツールです。

先ほど述べた、デプロイの流れをCI/CDに置き換えると以下の手順になります。

(GitHubAction)

  1. mainブランチにマージをトリガーとして、Dockerイメージを生成およびlatestタグを付与
  2. ECRに登録

(CodePipeline)
3. ECRにおいてlatestタグのイメージが更新されたことをトリガーに、コンテナ定義書を更新
4. コンテナ定義書に従い、ECRから取得したDockerイメージをFargate上にデプロイ

CodepipelineのみCI/CDを組むことができますが、
今回コードの管理はGitHubで行いたかったため、このような手順でCI/CDを組みました。

GitHubActionでのみでも、CI/CDを組むことはできますが、ワークフローが複雑になる上、実際に動作するのかを確認するのがいちいちマージしないといけないので、大変になります。

なので、今回採用した方法が一番簡単かなって思う、かつ、一番採用されている方法ではないでしょうか。

▼参考
https://zenn.dev/reireias/articles/8e987af2762eaa#3.-image-buildのみgithub-actionsでやる

以下、環境構築した際のメモを残しております。

https://zenn.dev/link/comments/b898404cf8930c

Blue/Greenデプロイ

デプロイ方法は、Blue/Greenデプロイを採用しました。
こちらは、既存のアプリケーションからスムーズに切り替えるためのデプロイ方法になります。
リリース用コンテナ(Blue側)と既存コンテナ(Green側)を両方起動させた状態で、トラフィックの転送を行うので、切り替えのダウンタイムがすごく少ないです。
また、切り替え後もある一定期間は、切り替え前のコンテナも起動しているので切り戻しもダウンタイムなしで切り替えることが可能になります。
リリース後すぐに不具合が起きても安心ですね。

▼Blue/Greenデプロイ(以下の参考記事より参照)

詳しくは以下の記事がわかりやすいかったです。

▼参考
https://tech.isid.co.jp/entry/2022/01/11/CodeDeploy_によるECS_でのBlue/Greenデプロイの話

フロントエンド側のデプロイ環境

フロントエンド側のデプロイ環境はAmplifyを利用することでバックエンドで比較にならないほど簡単にデプロイを行うことができます。

https://aws.amazon.com/jp/amplify/

デプロイ環境だけではなく、CI/CDの構築もGUIベースで簡単に行ってくれます。
GUIベースで設定ファイルを記述することができます。

▼ビルド設定

環境変数の設定もGUIベースで簡単に設定できます。

▼環境変数設定

また、プレビューも用意されており、PR中の動作確認もローカルで確認する必要がないため、かなりDXが上がるかなって思います。

また、ステージング環境を構築する際は、そのURLは誰でも見られないようにすべきです。
その際のペーシック認証の設定も簡単にできます。

構築方法も公式のチュートリアル参考にすると良いでしょう。

https://aws.amazon.com/jp/getting-started/hands-on/build-react-app-amplify-graphql/

本番の環境も30分もかからず構築できると思います。

まとめ

本番環境の構築を簡単にまとめてみました。
みなさんの参考になれば幸いです。

参考

https://tech-dive.xyz/2018/10/22/post-65/

https://www.sbbit.jp/article/cont1/81640

GitHubで編集を提案

Discussion