ECS B/Gデプロイについて –CloudFormation Hooks編–

初めまして、7月に入社した関根です。 初めましてから急ですが、2026


初めまして、7月に入社した関根です。

初めましてから急ですが、2026/8/13の主に千葉県で降った大雨で車が水没しました^^
なんでも、千葉県?千葉市?で観測史上1位の記録的大雨だったようですね。
もうしっかり契約している駐車場が水没していました。
形跡から見て、筆者の腰の高さくらいまで水が溜まっていたみたいです。
車検に出した直後での被災だったなので普通にムカついてます。
※ブログを執筆した2026/8/26現在でも車は移動できていません。

非常にむしゃくしゃしているのでECS B/Gデプロイに関して検証していきたいと思います。
現状ECSをB/Gデプロイしようと思ったらCodeDeployによるデプロイが主流になっていると思います。
ですが、昨今CloudFormation(以降Cfn)によるHooksや、ECSに実装されたネイティブ機能によるB/Gデプロイなど、意外と選択肢が出始めています。

そんななか今回は上記で上げた2つの手法、Hooks、ECSネイティブ機能によるB/Gデプロイについて検証、比較していきたいと思います。(比較は最後にまとめてやると思います。やらなかったらごめんなさい🙇)
※従来のCodeDeployを活用した方式は既に大量に出回っているのと、皆さん当たり前のように実装したことがあると思っているので検証はしません+触れません。

恐らく長くなると思っているので、分割してブログを掲載したいと思います。
もしかしたらすぐ更新するかもしれないし、まったく更新しないかもしれないですが気長に見てください。

それでは、今回はCfn HooksによるB/Gデプロイについて検証をしていきたいと思います。


1.目次

  • 1.目次
  • 2.Cfnテンプレート作成
  • 3.検証環境作成
  • 4.検証環境リソース確認
  • 5.B/Gデプロイ検証
  • 6.Hookを試してみた感想とか、なんとか
  • 7.まとめ
  • 8.最後に

2.Cfnテンプレート作成

今回は以下のような内容のテンプレートを作成しました。

AWSTemplateFormatVersion: 2010-09-09

# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
Parameters:
  #デプロイ種類を指定(初期構築はblue)
  DeployType:
    Type: String
    Default: blue
    AllowedValues:
      - blue
      - green
  RepositoryName:
    Type: String
    Default: bg-test

  #実リソースの値を利用するようパラメータを定義
  Vpc:
    Type: 'AWS::EC2::VPC::Id'
  Subnet1:
    Type: 'AWS::EC2::Subnet::Id'
  Subnet2:
    Type: 'AWS::EC2::Subnet::Id'

# ------------------------------------------------------------#
# Transform
# ------------------------------------------------------------#
Transform:
  - 'AWS::CodeDeployBlueGreen'

# ------------------------------------------------------------#
# Hooks
# ------------------------------------------------------------#
Hooks:
#CodeDeployを介したBlue/Greenデプロイのトリガー定義
  # ------------------------------------------------------------#
  # CodeDeploy:BlueGreen
  # ------------------------------------------------------------#
  CodeDeployBlueGreenHook:
    Type: 'AWS::CodeDeploy::BlueGreen'
    Properties:
      #トラフィックルーティング構成
      TrafficRoutingConfig:
        #デプロイ構成で使用されるトラフィックシフトのタイプ(AllAtOnce | TimeBasedCanary | TimeBasedLinear)
        #TimeBasedCanary:デプロイの1つのバージョンから別のバージョンにトラフィックを2つずつシフトする構成
        Type: TimeBasedCanary
        TimeBasedCanary:
          #デプロイの最初の増分でシフトするトラフィックの割合(14%以上で指定すること)
          StepPercentage: 99
          #トラフィックシフト時間(分)
          BakeTimeMins: 1
      #ブルー/グリーンデプロイの追加オプション
      #AdditionalOptions
        #ブルー環境削除までの待機時間(分)
        #TerminationWaitTimeInMinutes
      #Blue/Green実行時に使用するロール
      #ServiceRole
      #ECSアプリケーションのプロパティ
      Applications:
        - Target:
            Type: 'AWS::ECS::Service'
            LogicalID: ECSService
          #ECSアプリケーションの属性
          ECSAttributes:
            #タスク定義
            TaskDefinitions:
              - BlueTaskDefinition
              - GreenTaskDefinition
            #タスクセット
            TaskSets:
              - BlueTaskSet
              - GreenTaskSet
            #ルーティングに使用するリソースを指定
            TrafficRouting:
              #ターゲットグループにトラフィックを指示するためのロードバランサーにより使用されるリスナー
              ProdTrafficRoute:
                #リソースタイプ
                Type: 'AWS::ElasticLoadBalancingV2::Listener'
                #リソース論理ID
                LogicalID: ALBListener
              #登録されたターゲットにトラフィックをルーティングするためのターゲットグループとして使用するリソースの論理ID
              TargetGroups:
                - ALBTargetGroupBlue
                - ALBTargetGroupGreen

# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
#Blue/Greenデプロイ環境を構成する各リソースを定義
  # ------------------------------------------------------------#
  # IAM:ロール
  # ------------------------------------------------------------#
  ECSTaskExecutionRole:
    Type: 'AWS::IAM::Role'
    Properties:
      #ロール名
      RoleName: "BGTEST-ECSTaskExecutionRole"
      #ポリシードキュメント
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: ''
            Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: 'sts:AssumeRole'
      #ロールに付与するポリシーのArn
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'

  # ------------------------------------------------------------#
  # SG
  # ------------------------------------------------------------#
  SecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      #SGの説明
      GroupDescription: Security group for ec2 access
      #VPCのID
      VpcId: !Ref Vpc
      #インバウンドルール
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 8080
          ToPort: 8080
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: "Name"
          Value: "BGTEST-sg"

  # ------------------------------------------------------------#
  # ALB:ターゲットグループ(Blue環境)
  # ------------------------------------------------------------#
  ALBTargetGroupBlue:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      #ヘルスチェック間隔(秒)
      HealthCheckIntervalSeconds: 5
      #ヘルスチェックパス
      HealthCheckPath: /
      #ヘルスチェックに利用するポート
      HealthCheckPort: '80'
      #ヘルスチェックに利用するプロトコル
      HealthCheckProtocol: HTTP
      #ヘルスチェックのタイムアウト時間(秒)
      HealthCheckTimeoutSeconds: 2
      #ターゲットが正常であると判断するために必要なヘルスチェックの連続成功回数
      HealthyThresholdCount: 2
      #ヘルスチェック正常時に利用するコード
      Matcher:
        HttpCode: '200'
      #ターゲットの受信ポート
      Port: 80
      #ターゲットへの通信に利用するプロトコル
      Protocol: HTTP
      #タグ
      Tags:
        - Key: Name
          Value: BGTEST-ALB-TG-Blue
      #ターゲットのタイプ
      TargetType: ip
      #ターゲットが異常であると判断するために必要なヘルスチェックの連続失敗回数
      UnhealthyThresholdCount: 4
      #VPCのID
      VpcId: !Ref Vpc

  # ------------------------------------------------------------#
  # ALB:ターゲットグループ(Green環境)
  # ------------------------------------------------------------#
  ALBTargetGroupGreen:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      #ヘルスチェック間隔(秒)
      HealthCheckIntervalSeconds: 5
      #ヘルスチェックパス
      HealthCheckPath: /
      #ヘルスチェックに利用するポート
      HealthCheckPort: '80'
      #ヘルスチェックに利用するプロトコル
      HealthCheckProtocol: HTTP
      #ヘルスチェックのタイムアウト時間(秒)
      HealthCheckTimeoutSeconds: 2
      #ターゲットが正常であると判断するために必要なヘルスチェックの連続成功回数
      HealthyThresholdCount: 2
      #ヘルスチェック正常時に利用するコード
      Matcher:
        HttpCode: '200'
      #ターゲットの受信ポート
      Port: 80
      #ターゲットへの通信に利用するプロトコル
      Protocol: HTTP
      #タグ
      Tags:
        - Key: Name
          Value: BGTEST-ALB-TG-Green
      #ターゲットのタイプ
      TargetType: ip
      #ターゲットが異常であると判断するために必要なヘルスチェックの連続失敗回数
      UnhealthyThresholdCount: 4
      #VPCのID
      VpcId: !Ref Vpc

  # ------------------------------------------------------------#
  # ALB
  # ------------------------------------------------------------#
  ALB:
    Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
    Properties:
      #ロードバランサーの属性
      #LoadBalancerAttributes
      #スキーマ
      Scheme: internet-facing
      #関連付けるSG
      SecurityGroups:
        - !Ref SecurityGroup
      #関連付けるサブネット
      Subnets:
        - !Ref Subnet1
        - !Ref Subnet2
      #タグ
      Tags:
        - Key: Name
          Value: BGTEST-ALB
      #ロードバランサーのタイプ
      Type: application
      #IPのタイプ
      IpAddressType: ipv4

  # ------------------------------------------------------------#
  # ALB:リスナー
  # ------------------------------------------------------------#
  ALBListener:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      #デフォルトルールのアクション
      DefaultActions:
          #アクションのタイプ
        - Type: forward
          #フォワード設定
          ForwardConfig:
            #対象ターゲットグループ
            TargetGroups:
              - TargetGroupArn: !Ref ALBTargetGroupBlue
                Weight: 1
      #紐づけ先ALBのArn
      LoadBalancerArn: !Ref ALB
      #ロードバランサーがリッスンしているポート
      Port: 80
      #ロードバランサーへの接続に使用するプロトコル
      Protocol: HTTP

  # ------------------------------------------------------------#
  # ALB:リスナールール
  # ------------------------------------------------------------#
  ALBListenerProdRule:
    Type: 'AWS::ElasticLoadBalancingV2::ListenerRule'
    Properties:
      #リスナールールのアクション
      Actions:
          #アクションのタイプ
        - Type: forward
          #フォワード設定
          ForwardConfig:
            #対象ターゲットグループ
            TargetGroups:
              - TargetGroupArn: !Ref ALBTargetGroupBlue
                Weight: 1
      #ルールの条件
      Conditions:
          #HTTPリクエスト内のフィールド
        - Field: http-header
          #HTTPヘッダー条件の情報
          HttpHeaderConfig:
            #HTTPヘッダーフィールドの名前
            HttpHeaderName: User-Agent
            #HTTPヘッダーの値と比較する文字列
            Values:
              - Mozilla
      #紐づけ先リスナーのArn
      ListenerArn: !Ref ALBListener
      #ルールの優先度
      Priority: 1

  # ------------------------------------------------------------#
  # ECS:タスク定義
  # ------------------------------------------------------------#
  BlueTaskDefinition:
    Type: 'AWS::ECS::TaskDefinition'
    Properties:
      #タスク実行時に使用するロールのArn
      ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn
      #タスクを構成するコンテナを記述するJSON形式のコンテナ定義リスト
      ContainerDefinitions:
          #コンテナ名
        - Name: DemoApp
          #コンテナの起動に使用するイメージ
          Image: 
            !Join
              - ":"
              - - !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${RepositoryName}"
                - !Sub "Dockerfile_${DeployType}"
          #コンテナ失敗、停止した際の挙動を指定
          Essential: true
          #コンテナのポートマッピング
          PortMappings:
              #コンテナ用に予約するコンテナ インスタンス上のポート
            - HostPort: 80
              #ポートマッピングに使用するプロトコル
              Protocol: tcp
              #動的にマッピングされたホストポート範囲にバインドされているコンテナ上のポート
              ContainerPort: 80
      #タスク定義が検証されたタスク起動タイプ
      RequiresCompatibilities:
        - FARGATE
      #タスク内のコンテナに使用するDockerネットワークモード
      NetworkMode: awsvpc
      #タスクで使用されるCPUユニット数
      Cpu: '256'
      #タスクで使用されるメモリの量(MiB単位)
      Memory: '512'
      #タスク定義が登録されているファミリーの名前
      Family: ecs-demo

  # ------------------------------------------------------------#
  # ECS:クラスタ
  # ------------------------------------------------------------#
  ECSCluster:
    Type: 'AWS::ECS::Cluster'
    Properties: {}

  # ------------------------------------------------------------#
  # ECS:サービス
  # ------------------------------------------------------------#
  ECSService:
    Type: 'AWS::ECS::Service'
    Properties:
      #紐づけ先ECSクラスタ
      Cluster: !Ref ECSCluster
      #サービス内に配置し、実行を継続する指定されたタスク定義のインスタンス化の数
      DesiredCount: 1
      #サービスに使用するデプロイメントコントローラー
      DeploymentController:
        Type: EXTERNAL

  # ------------------------------------------------------------#
  # ECS:タスクセット
  # ------------------------------------------------------------#
  BlueTaskSet:
    Type: 'AWS::ECS::TaskSet'
    Properties:
      #紐づけ先ECSクラスタ
      Cluster: !Ref ECSCluster
      #タスクセット内の新しいタスクが使用する起動タイプ
      LaunchType: FARGATE
      #タスクセットのネットワーク構成
      NetworkConfiguration:
        #タスクに関連付けられているVPCサブネットとセキュリティグループ
        AwsVpcConfiguration:
          #パブリックIPの受信許可
          AssignPublicIp: ENABLED
          #タスクorサービスに関連付けるSG
          SecurityGroups:
            - !Ref SecurityGroup
          #タスクorサービスに関連付けるサブネット
          Subnets:
            - !Ref Subnet1
            - !Ref Subnet2
      #タスクセット内のタスクが使用するプラットフォームバージョン
      PlatformVersion: 1.4.0
      #タスクセットに配置して実行し続けるタスクの希望数の浮動小数点パーセンテージ
      Scale:
        #スケール値の測定単位
        Unit: PERCENT
        #タスクセットをスケールするための値
        Value: 100
      #関連付けるECSサービス
      Service: !Ref ECSService
      #関連付けるタスク定義
      TaskDefinition: !Ref BlueTaskDefinition
      #タスクセットで使用するロードバランサー
      LoadBalancers:
          #ロードバランサーに関連付けるコンテナーの名前
        - ContainerName: DemoApp
          #ロードバランサーに関連付けるコンテナのポート
          ContainerPort: 80
          #タスクセットに関連付けるターゲットグループ
          TargetGroupArn: !Ref ALBTargetGroupBlue

  # ------------------------------------------------------------#
  # ECS:プライマリタスクセット
  # ------------------------------------------------------------#
  PrimaryTaskSet:
    Type: 'AWS::ECS::PrimaryTaskSet'
    Properties:
      #タスクセットが存在するサービスをホストするECSクラスタ
      Cluster: !Ref ECSCluster
      #タスクセットが存在するサービス
      Service: !Ref ECSService
      #デプロイメント内のプライマリタスクセットとして設定するタスクセット
      TaskSetId: !GetAtt BlueTaskSet.Id

アホみたいに長いテンプレートができました^^;
簡単に説明すると、以下みたいな感じになります。
・あたりまえだけど、hook文宣言してます←こいつがCodeDeployを呼び出すキーマン
・IAM、SG、LB、ECSを作成
・IAMはタスク定義の中で使ってる
・SGはALB、タスクセットの中で使ってる
・ALB、ECS周りは当たり前の話なので割愛
・初手トラフィック移行の割合は99%
・ベイク時間は1分
・タスクセット、プライマリタスクセット作ってます!
・「AWS::ECS::TaskDefinition」、「AWS::ECS::TaskSet」の更新を契機にB/Gデプロイを実行
 ※更新に置換を必要とするプロパティ変更が含まれていない場合は、B/Gデプロイは実行されない。

今回はお手軽に検証をしたいので、パラメータ「DeployType」の値を変更することで置換を伴う変更を発生させています。(やっていることはBlue環境用からGreen環境用のDockerfileに置き換えてるだけ)


コメントを残す

メールアドレスが公開されることはありません。