

# Perform ECS blue/green deployments through CodeDeploy using CloudFormation
Perform ECS blue/green deployments

To update an application running on Amazon Elastic Container Service (Amazon ECS), you can use a CodeDeploy blue/green deployment strategy. This strategy helps minimize interruptions caused by changing application versions. 

In a blue/green deployment, you create a new application environment (referred to as *green*) alongside your current, live environment (referred to as *blue*). This allows you to monitor and test the green environment before routing live traffic from the blue environment to the green environment. After the green environment is serving live traffic, you can safely terminate the blue environment.

To perform CodeDeploy blue/green deployments on ECS using CloudFormation, you include the following information in your stack template:
+ A `Hooks` section that describes a `AWS::CodeDeploy::BlueGreen` hook.
+  A `Transform` section that specifies the `AWS::CodeDeployBlueGreen` transform.

The following topics guide you through setting up a CloudFormation template for a blue/green deployment on ECS.

**Topics**
+ [

# About blue/green deployments
](about-blue-green-deployments.md)
+ [

# Considerations when managing ECS blue/green deployments using CloudFormation
](blue-green-considerations.md)
+ [

# `AWS::CodeDeploy::BlueGreen` hook syntax
](blue-green-hook-syntax.md)
+ [

# Blue/green deployment template example
](blue-green-template-example.md)

# About blue/green deployments
About blue/green deployments

This topic provides an overview of how performing blue/green deployments with CloudFormation works. It also explains how to prepare your CloudFormation template for blue/green deployments.

**Topics**
+ [

## How it works
](#blue-green-how-it-works)
+ [Resource updates that initiate green deployments](#blue-green-resources)
+ [Preparing your template](#blue-green-setup)
+ [Modeling your blue/green deployment](#blue-green-required)
+ [Change sets](#blue-green-changesets)
+ [Monitoring stack events](#blue-green-events)
+ [IAM permissions](#blue-green-iam)

## How it works


When using CloudFormation to perform ECS blue/green deployments through CodeDeploy, you start by creating a stack template that defines the resources for both your blue and green application environments, including specifying the traffic routing and stabilization settings to use. Next, you create a stack from that template. This generates your blue (current) application. CloudFormation only creates the blue resources during stack creation. Resources for a green deployment aren't created until they're required.

Then, if in a future stack update you update the task definition or task set resources in your blue application, CloudFormation does the following:
+ Generates all the necessary green application environment resources
+ Shifts the traffic based on the specified traffic routing parameters
+ Deletes the blue resources

If an error occurs at any point before the green deployment is successful and finalized, CloudFormation rolls the stack back to its state before the entire green deployment was initiated.

## Resource updates that initiate green deployments
Resource updates that initiate green deployments

When you perform a stack update that updates certain properties of specific ECS resources, CloudFormation initiates a green deployment process. The resources that initiate this process are:
+ [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html)
+ [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskset.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskset.html) 

However, if the updates to these resources don't involve property changes that require replacement, a green deployment won't be initiated. For more information, see [Understand update behaviors of stack resources](using-cfn-updating-stacks-update-behaviors.md).

It's important to note that you can't combine updates to the above resources with updates to other resources in the same stack update operation. If you need to update both the listed resources and other resources within the same stack, you have two options:
+ Perform two separate stack update operations: one that includes only the updates to the above resources, and a separate stack update that includes changes to any other resources.
+ Remove the `Transform` and `Hooks` sections from your template and then perform the stack update. In this case, CloudFormation won't perform a green deployment.

## Preparing your template to perform ECS blue/green deployments
Preparing your template

To enable blue/green deployments on your stack, include the following sections in your stack template before performing a stack update.
+ Add a reference to the `AWS::CodeDeployBlueGreen` transform to your template:

  ```
  "Transform": [
    "AWS::CodeDeployBlueGreen"
  ],
  ```
+ Add a `Hooks` section that invokes the `AWS::CodeDeploy::BlueGreen` hook and specifies the properties for your deployment. For more information, see [`AWS::CodeDeploy::BlueGreen` hook syntax](blue-green-hook-syntax.md).
+ In the `Resources` section, define the blue and green resources for your deployment.

You can add these sections when you first create the template (that's, before creating the stack itself), or you can add them to an existing template before performing a stack update. If you specify the blue/green deployment for a new stack, CloudFormation only creates the blue resources during stack creation — resources for the green deployment aren't created until they're required during a stack update.

## Modeling your blue/green deployment using CloudFormation resources
Modeling your blue/green deployment

To perform CodeDeploy blue/green deployment on ECS, your CloudFormation template needs to include the resources that model your deployment, such as an Amazon ECS service and load balancer. For more details on what these resources represent, see [Before you begin an Amazon ECS deployment](https://docs.aws.amazon.com/codedeploy/latest/userguide/deployment-steps-ecs.html#deployment-steps-prerequisites-ecs) in the *AWS CodeDeploy User Guide*.


| Requirement | Resource | Required/Optional | Initiates blue/green deployment if replaced? | 
| --- | --- | --- | --- | 
| Amazon ECS cluster | [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-cluster.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-cluster.html) | Optional. The default cluster can be used. | No | 
| Amazon ECS service | [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-service.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-service.html) | Required. | No | 
| Application or Network Load Balancer | [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-service-loadbalancer.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-service-loadbalancer.html) | Required. | No | 
| Production listener | [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-listener.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-listener.html) | Required. | No | 
| Test listener  | [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-listener.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-listener.html) | Optional. | No | 
| Two target groups | [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html) | Required. | No | 
| Amazon ECS task definition  | [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html) | Required. | Yes | 
| Container for your Amazon ECS application | [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-taskdefinition-containerdefinition.html#cfn-ecs-taskdefinition-containerdefinition-name](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-taskdefinition-containerdefinition.html#cfn-ecs-taskdefinition-containerdefinition-name) | Required. | No | 
| Port for your replacement task set | [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-taskdefinition-portmapping.html#cfn-ecs-taskdefinition-portmapping-containerport](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-ecs-taskdefinition-portmapping.html#cfn-ecs-taskdefinition-portmapping-containerport) | Required. | No | 

## Change sets
Change sets

We strongly recommend that you create a change set before performing a stack update that will initiate a green deployment. This allows you to see the actual changes that will be made to your stack before performing stack update. Be aware that resource changes may not be listed in the order in which they will be performed during the stack update. For more information, see [Update CloudFormation stacks using change sets](using-cfn-updating-stacks-changesets.md).

## Monitoring stack events
Monitoring stack events

You can view the stack events generated at each step of the ECS deployment on the **Events** tab of the **Stack** page, and using the AWS CLI. For more information, see [Monitor stack progress](monitor-stack-progress.md).

## IAM permissions for blue/green deployments
IAM permissions

In order for CloudFormation to successfully perform the blue-green deployments, you must have the following CodeDeploy permissions:
+ `codedeploy:Get*`
+ `codedeploy:CreateCloudFormationDeployment`

For more information, see [Actions, resources, and condition keys for CodeDeploy](https://docs.aws.amazon.com/service-authorization/latest/reference/list_awscodedeploy.html) in the *Service Authorization Reference*.

# Considerations when managing ECS blue/green deployments using CloudFormation
Considerations

The process of using CloudFormation to perform your ECS blue/green deployments through CodeDeploy is different from a standard ECS deployment using just CodeDeploy. For a detailed understanding of these differences, see [Differences between Amazon ECS blue/green deployments through CodeDeploy and CloudFormation](https://docs.aws.amazon.com/codedeploy/latest/userguide/deployments-create-ecs-cfn.html#differences-ecs-bg-cfn) in the *AWS CodeDeploy User Guide*. 

When managing your blue/green deployment using CloudFormation, there are certain limitations and considerations to keep in mind:
+ Only updates to certain resources will initiate a green deployment. For more information, see [Resource updates that initiate green deployments](about-blue-green-deployments.md#blue-green-resources).
+ You can't include updates to resources that initiate green deployments and updates to other resources in the same stack update. For more information, see [Resource updates that initiate green deployments](about-blue-green-deployments.md#blue-green-resources).
+ You can only specify a single ECS service as the deployment target.
+ Parameters whose values are obfuscated by CloudFormation can't be updated by CodeDeploy during a green deployment, and will lead to an error and stack update failure. These include:
  + Parameters defined with the `NoEcho` attribute.
  + Parameters that use dynamic references to retrieve their values from external services. For more information about dynamic references, see [Get values stored in other services using dynamic references](dynamic-references.md).
+ To cancel a green deployment that's still in progress, cancel the stack update in CloudFormation, not CodeDeploy or ECS. For more information, see [Cancel a stack update](using-cfn-stack-update-cancel.md). After an update has finished, you can't cancel it. However, you can update a stack again with any previous settings.
+ The following CloudFormation features are not currently supported for templates that define ECS blue/green deployments:
  + Declaring [outputs](outputs-section-structure.md) or using [Fn::ImportValue](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-importvalue.html) to import values from other stacks.
  + Importing resources. For more information about importing resources, see [Import AWS resources into a CloudFormation stack](import-resources.md).
  + Using the `AWS::CodeDeploy::BlueGreen` hook in a template that includes nested stack resources. For more information about nested stacks, see [Split a template into reusable pieces using nested stacks](using-cfn-nested-stacks.md).
  + Using the `AWS::CodeDeploy::BlueGreen` hook in a nested stack.

# `AWS::CodeDeploy::BlueGreen` hook syntax
Hook syntax

The following syntax describes the structure of an `AWS::CodeDeploy::BlueGreen` hook for ECS blue/green deployments.

## Syntax


```
"Hooks": {
  "Logical ID": {
    "Type": "AWS::CodeDeploy::BlueGreen",
    "Properties": {
      "TrafficRoutingConfig": {
        "Type": "Traffic routing type",
        "TimeBasedCanary": {
          "StepPercentage": Integer,
          "BakeTimeMins": Integer
        },
        "TimeBasedLinear": {
          "StepPercentage": Integer,
          "BakeTimeMins": Integer
        }
      },
      "AdditionalOptions": {"TerminationWaitTimeInMinutes": Integer},
      "LifecycleEventHooks": {
        "BeforeInstall": "FunctionName",
        "AfterInstall": "FunctionName",
        "AfterAllowTestTraffic": "FunctionName",
        "BeforeAllowTraffic": "FunctionName",
        "AfterAllowTraffic": "FunctionName"
      },
      "ServiceRole": "CodeDeployServiceRoleName",
      "Applications": [
        {
          "Target": {
            "Type": "AWS::ECS::Service",
            "LogicalID": "Logical ID of AWS::ECS::Service"
          },
          "ECSAttributes": {
            "TaskDefinitions": [
              "Logical ID of AWS::ECS::TaskDefinition (Blue)",
              "Logical ID of AWS::ECS::TaskDefinition (Green)"
            ],
            "TaskSets": [
              "Logical ID of AWS::ECS::TaskSet (Blue)",
              "Logical ID of AWS::ECS::TaskSet (Green)"
            ],
            "TrafficRouting": {
              "ProdTrafficRoute": {
                "Type": "AWS::ElasticLoadBalancingV2::Listener",
                "LogicalID": "Logical ID of AWS::ElasticLoadBalancingV2::Listener (Production)"
              },
              "TestTrafficRoute": {
                "Type": "AWS::ElasticLoadBalancingV2::Listener",
                "LogicalID": "Logical ID of AWS::ElasticLoadBalancingV2::Listener (Test)"
              },
              "TargetGroups": [
                "Logical ID of AWS::ElasticLoadBalancingV2::TargetGroup (Blue)",
                "Logical ID of AWS::ElasticLoadBalancingV2::TargetGroup (Green)"
              ]
            }
          }
        }
      ]
    }
  }
}
```

## Properties


Logical ID (also called *logical name*)  
The logical ID of a hook declared in the `Hooks` section of the template. The logical ID must be alphanumeric (A-Za-z0-9) and unique within the template.  
*Required*: Yes    
`Type`  
The type of hook. `AWS::CodeDeploy::BlueGreen`  
*Required*: Yes  
`Properties`  
Properties of the hook.  
*Required*: Yes    
`TrafficRoutingConfig`  
Traffic routing configuration settings.  
*Required*: No  
The default configuration is time-based canary traffic shifting, with a 15% step percentage and a five minute bake time.    
`Type`  
The type of traffic shifting used by the deployment configuration.  
Valid values: AllAtOnce \$1 TimeBasedCanary \$1 TimeBasedLinear  
*Required*: Yes    
`TimeBasedCanary`  
Specifies a configuration that shifts traffic from one version of the deployment to another in two increments.  
*Required*: Conditional: If you specify `TimeBasedCanary` as the traffic routing type, you must include the `TimeBasedCanary` parameter.    
`StepPercentage`  
The percentage of traffic to shift in the first increment of a `TimeBasedCanary` deployment. The step percentage must be 14% or greater.  
*Required*: No  
`BakeTimeMins`  
The number of minutes between the first and second traffic shifts of a `TimeBasedCanary` deployment.  
*Required*: No  
`TimeBasedLinear`  
Specifies a configuration that shifts traffic from one version of the deployment to another in equal increments, with an equal number of minutes between each increment.  
*Required*: Conditional: If you specify `TimeBasedLinear` as the traffic routing type, you must include the `TimeBasedLinear` parameter.    
`StepPercentage`  
The percentage of traffic that's shifted at the start of each increment of a `TimeBasedLinear` deployment. The step percentage must be 14% or greater.  
*Required*: No  
`BakeTimeMins`  
The number of minutes between each incremental traffic shift of a `TimeBasedLinear` deployment.  
*Required*: No  
`AdditionalOptions`  
Additional options for the blue/green deployment.  
*Required*: No    
`TerminationWaitTimeInMinutes`  
Specifies time to wait, in minutes, before terminating the blue resources.  
*Required*: No  
`LifecycleEventHooks`  
Use lifecycle event hooks to specify a Lambda function that CodeDeploy can call to validate a deployment. You can use the same function or a different one for deployment lifecyle events. Following completion of the validation tests, the Lambda `AfterAllowTraffic` function calls back CodeDeploy and delivers a result of `Succeeded` or `Failed`. For more information, see [AppSpec 'hooks' section](https://docs.aws.amazon.com/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html) in the *AWS CodeDeploy User Guide.*  
*Required*: No    
`BeforeInstall`  
Function to use to run tasks before the replacement task set is created.  
*Required*: No  
`AfterInstall`  
Function to use to run tasks after the replacement task set is created and one of the target groups is associated with it.  
*Required*: No  
`AfterAllowTestTraffic`  
Function to use to run tasks after the test listener serves traffic to the replacement task set.  
*Required*: No  
`BeforeAllowTraffic`  
Function to use to run tasks after the second target group is associated with the replacement task set, but before traffic is shifted to the replacement task set.  
*Required*: No  
`AfterAllowTraffic`  
Function to use to run tasks after the second target group serves traffic to the replacement task set.  
*Required*: No  
`ServiceRole`  
The execution role for CloudFormation to use to perform the blue-green deployments. For a list of the necessary permissions, see [IAM permissions for blue/green deployments](about-blue-green-deployments.md#blue-green-iam).  
*Required*: No  
`Applications`  
Specifies properties of the Amazon ECS application.  
*Required*: Yes    
`Target`  
  
*Required*: Yes    
`Type`  
The type of the resource.  
*Required*: Yes  
`LogicalID`  
The logical id of the resource.  
*Required*: Yes  
`ECSAttributes`  
The resources that represent the various requirements of your Amazon ECS application deployment.  
*Required*: Yes    
`TaskDefinitions`  
The logical ID of the [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskdefinition.html) resource to run the Docker container that contains your Amazon ECS application.  
*Required*: Yes  
`TaskSets`  
The logical IDs of the [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskset.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ecs-taskset.html) resources to use as task sets for the application.  
*Required*: Yes  
`TrafficRouting`  
Specifies resources used for traffic routing.  
*Required*: Yes    
`ProdTrafficRoute`  
The listener to be used by your load balancer to direct traffic to your target groups.  
*Required*: Yes    
`Type`  
The type of the resource. `AWS::ElasticLoadBalancingV2::Listener`  
*Required*: Yes  
`LogicalID`  
The logical ID of the resource.  
*Required*: Yes  
`TestTrafficRoute`  
The listener to be used by your load balancer to direct traffic to your target groups.  
*Required*: Yes    
`Type`  
The type of the resource. `AWS::ElasticLoadBalancingV2::Listener`  
*Required*: Yes  
`LogicalID`  
The logical ID of the resource.  
*Required*: No  
`TargetGroups`  
Logical ID of resources to use as target groups to route traffic to the registered target.  
*Required*: Yes

# Blue/green deployment template example
Template example

The following example template sets up a CodeDeploy blue/green deployment on ECS, with a traffic routing progress of 15 percent per step and a stabilization period of 5 minutes between each step. 

Creating a stack with the template will provision the initial configuration of the deployment. If you then made any changes to properties in the `BlueTaskSet` resource that require that resource be replaced, CloudFormation will then initiate a green deployment as part of the stack update.

## JSON


```
{
  "AWSTemplateFormatVersion":"2010-09-09",
  "Parameters":{
    "Vpc":{ "Type":"AWS::EC2::VPC::Id" },
    "Subnet1":{ "Type":"AWS::EC2::Subnet::Id" },
    "Subnet2":{ "Type":"AWS::EC2::Subnet::Id" }
  },
  "Transform":[ "AWS::CodeDeployBlueGreen" ],
  "Hooks":{
    "CodeDeployBlueGreenHook":{
      "Type":"AWS::CodeDeploy::BlueGreen",
      "Properties":{
        "TrafficRoutingConfig":{
          "Type":"TimeBasedCanary",
          "TimeBasedCanary":{
            "StepPercentage":15,
            "BakeTimeMins":5
          }
        },
        "Applications":[
          {
            "Target":{
              "Type":"AWS::ECS::Service",
              "LogicalID":"ECSDemoService"
            },
            "ECSAttributes":{
              "TaskDefinitions":[ "BlueTaskDefinition","GreenTaskDefinition" ],
              "TaskSets":[ "BlueTaskSet","GreenTaskSet" ],
              "TrafficRouting":{
                "ProdTrafficRoute":{
                  "Type":"AWS::ElasticLoadBalancingV2::Listener",
                  "LogicalID":"ALBListenerProdTraffic"
                },
                "TargetGroups":[ "ALBTargetGroupBlue","ALBTargetGroupGreen" ]
              }
            }
          }
        ]
      }
    }
  },
  "Resources":{
    "ExampleSecurityGroup":{
      "Type":"AWS::EC2::SecurityGroup",
      "Properties":{
        "GroupDescription":"Security group for ec2 access",
        "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"
          }
        ]
      }
    },
    "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":"Group","Value":"Example" }],
        "TargetType":"ip",
        "UnhealthyThresholdCount":4,
        "VpcId":{ "Ref":"Vpc" }
      }
    },
    "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":"Group","Value":"Example" }],
        "TargetType":"ip",
        "UnhealthyThresholdCount":4,
        "VpcId":{ "Ref":"Vpc" }
      }
    },
    "ExampleALB":{
      "Type":"AWS::ElasticLoadBalancingV2::LoadBalancer",
      "Properties":{
        "Scheme":"internet-facing",
        "SecurityGroups":[{ "Ref":"ExampleSecurityGroup" }],
        "Subnets":[{ "Ref":"Subnet1" },{ "Ref":"Subnet2" }],
        "Tags":[{ "Key":"Group","Value":"Example" }],
        "Type":"application",
        "IpAddressType":"ipv4"
      }
    },
    "ALBListenerProdTraffic":{
      "Type":"AWS::ElasticLoadBalancingV2::Listener",
      "Properties":{
        "DefaultActions":[
          {
            "Type":"forward",
            "ForwardConfig":{
              "TargetGroups":[
                {
                  "TargetGroupArn":{ "Ref":"ALBTargetGroupBlue" },
                  "Weight":1
                }
              ]
            }
          }
        ],
        "LoadBalancerArn":{ "Ref":"ExampleALB" },
        "Port":80,
        "Protocol":"HTTP"
      }
    },
    "ALBListenerProdRule":{
      "Type":"AWS::ElasticLoadBalancingV2::ListenerRule",
      "Properties":{
        "Actions":[
          {
            "Type":"forward",
            "ForwardConfig":{
              "TargetGroups":[
                {
                  "TargetGroupArn":{ "Ref":"ALBTargetGroupBlue" },
                  "Weight":1
                }
              ]
            }
          }
        ],
        "Conditions":[
          {
            "Field":"http-header",
            "HttpHeaderConfig":{
              "HttpHeaderName":"User-Agent",
              "Values":[ "Mozilla" ]
            }
          }
        ],
        "ListenerArn":{ "Ref":"ALBListenerProdTraffic" },
        "Priority":1
      }
    },
    "ECSTaskExecutionRole":{
      "Type":"AWS::IAM::Role",
      "Properties":{
        "AssumeRolePolicyDocument":{
          "Version": "2012-10-17",		 	 	 
          "Statement":[
            {
              "Sid":"",
              "Effect":"Allow",
              "Principal":{
                "Service":"ecs-tasks.amazonaws.com"
              },
              "Action":"sts:AssumeRole"
            }
          ]
        },
        "ManagedPolicyArns":[ "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" ]
      }
    },
    "BlueTaskDefinition":{
      "Type":"AWS::ECS::TaskDefinition",
      "Properties":{
        "ExecutionRoleArn":{
          "Fn::GetAtt":[ "ECSTaskExecutionRole","Arn" ]
        },
        "ContainerDefinitions":[
          {
            "Name":"DemoApp",
            "Image":"nginxdemos/hello:latest",
            "Essential":true,
            "PortMappings":[
              {
                "HostPort":80,
                "Protocol":"tcp",
                "ContainerPort":80
              }
            ]
          }
        ],
        "RequiresCompatibilities":[ "FARGATE" ],
        "NetworkMode":"awsvpc",
        "Cpu":"256",
        "Memory":"512",
        "Family":"ecs-demo"
      }
    },
    "ECSDemoCluster":{
      "Type":"AWS::ECS::Cluster",
      "Properties":{}
    },
    "ECSDemoService":{
      "Type":"AWS::ECS::Service",
      "Properties":{
        "Cluster":{ "Ref":"ECSDemoCluster" },
        "DesiredCount":1,
        "DeploymentController":{ "Type":"EXTERNAL" }
      }
    },
    "BlueTaskSet":{
      "Type":"AWS::ECS::TaskSet",
      "Properties":{
        "Cluster":{ "Ref":"ECSDemoCluster" },
        "LaunchType":"FARGATE",
        "NetworkConfiguration":{
          "AwsVpcConfiguration":{
            "AssignPublicIp":"ENABLED",
            "SecurityGroups":[{ "Ref":"ExampleSecurityGroup" }],
            "Subnets":[{ "Ref":"Subnet1" },{ "Ref":"Subnet2" }]
          }
        },
        "PlatformVersion":"1.4.0",
        "Scale":{
          "Unit":"PERCENT",
          "Value":100
        },
        "Service":{ "Ref":"ECSDemoService"},
        "TaskDefinition":{ "Ref":"BlueTaskDefinition" },
        "LoadBalancers":[
          {
            "ContainerName":"DemoApp",
            "ContainerPort":80,
            "TargetGroupArn":{ "Ref":"ALBTargetGroupBlue" }
          }
        ]
      }
    },
    "PrimaryTaskSet":{
      "Type":"AWS::ECS::PrimaryTaskSet",
      "Properties":{
        "Cluster":{ "Ref":"ECSDemoCluster" },
        "Service":{ "Ref":"ECSDemoService" },
        "TaskSetId":{ "Fn::GetAtt":[ "BlueTaskSet","Id" ]
        }
      }
    }
  }
}
```

## YAML


```
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  Vpc:
    Type: AWS::EC2::VPC::Id
  Subnet1:
    Type: AWS::EC2::Subnet::Id
  Subnet2:
    Type: AWS::EC2::Subnet::Id
Transform:
  - 'AWS::CodeDeployBlueGreen'
Hooks:
  CodeDeployBlueGreenHook:
    Type: AWS::CodeDeploy::BlueGreen
    Properties:
      TrafficRoutingConfig:
        Type: TimeBasedCanary
        TimeBasedCanary:
          StepPercentage: 15
          BakeTimeMins: 5
      Applications:
        - Target:
            Type: AWS::ECS::Service
            LogicalID: ECSDemoService
          ECSAttributes:
            TaskDefinitions:
              - BlueTaskDefinition
              - GreenTaskDefinition
            TaskSets:
              - BlueTaskSet
              - GreenTaskSet
            TrafficRouting:
              ProdTrafficRoute:
                Type: AWS::ElasticLoadBalancingV2::Listener
                LogicalID: ALBListenerProdTraffic
              TargetGroups:
                - ALBTargetGroupBlue
                - ALBTargetGroupGreen
Resources:
  ExampleSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for ec2 access
      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
  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: Group
          Value: Example
      TargetType: ip
      UnhealthyThresholdCount: 4
      VpcId: !Ref Vpc
  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: Group
          Value: Example
      TargetType: ip
      UnhealthyThresholdCount: 4
      VpcId: !Ref Vpc
  ExampleALB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      SecurityGroups:
        - !Ref ExampleSecurityGroup
      Subnets:
        - !Ref Subnet1
        - !Ref Subnet2
      Tags:
        - Key: Group
          Value: Example
      Type: application
      IpAddressType: ipv4
  ALBListenerProdTraffic:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          ForwardConfig:
            TargetGroups:
              - TargetGroupArn: !Ref ALBTargetGroupBlue
                Weight: 1
      LoadBalancerArn: !Ref ExampleALB
      Port: 80
      Protocol: HTTP
  ALBListenerProdRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - Type: forward
          ForwardConfig:
            TargetGroups:
              - TargetGroupArn: !Ref ALBTargetGroupBlue
                Weight: 1
      Conditions:
        - Field: http-header
          HttpHeaderConfig:
            HttpHeaderName: User-Agent
            Values:
              - Mozilla
      ListenerArn: !Ref ALBListenerProdTraffic
      Priority: 1
  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: ''
            Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'
  BlueTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ExecutionRoleArn: !GetAtt 
        - ECSTaskExecutionRole
        - Arn
      ContainerDefinitions:
        - Name: DemoApp
          Image: 'nginxdemos/hello:latest'
          Essential: true
          PortMappings:
            - HostPort: 80
              Protocol: tcp
              ContainerPort: 80
      RequiresCompatibilities:
        - FARGATE
      NetworkMode: awsvpc
      Cpu: '256'
      Memory: '512'
      Family: ecs-demo
  ECSDemoCluster:
    Type: AWS::ECS::Cluster
    Properties: {}
  ECSDemoService:
    Type: AWS::ECS::Service
    Properties:
      Cluster: !Ref ECSDemoCluster
      DesiredCount: 1
      DeploymentController:
        Type: EXTERNAL
  BlueTaskSet:
    Type: AWS::ECS::TaskSet
    Properties:
      Cluster: !Ref ECSDemoCluster
      LaunchType: FARGATE
      NetworkConfiguration:
        AwsVpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - !Ref ExampleSecurityGroup
          Subnets:
            - !Ref Subnet1
            - !Ref Subnet2
      PlatformVersion: 1.4.0
      Scale:
        Unit: PERCENT
        Value: 100
      Service: !Ref ECSDemoService
      TaskDefinition: !Ref BlueTaskDefinition
      LoadBalancers:
        - ContainerName: DemoApp
          ContainerPort: 80
          TargetGroupArn: !Ref ALBTargetGroupBlue
  PrimaryTaskSet:
    Type: AWS::ECS::PrimaryTaskSet
    Properties:
      Cluster: !Ref ECSDemoCluster
      Service: !Ref ECSDemoService
      TaskSetId: !GetAtt 
        - BlueTaskSet
        - Id
```