

# CloudFormation을 사용하여 CodeDeploy를 통한 ECS 블루/그린 배포 수행
<a name="blue-green"></a>

Amazon Elastic Container Service(Amazon ECS)에서 실행되는 애플리케이션을 업데이트하려면 CodeDeploy 블루/그린 배포 전략을 사용할 수 있습니다. 이 전략은 애플리케이션 버전 변경으로 인한 중단을 최소화하는 데 도움이 됩니다.

****블루/그린 배포에서는 현재의 라이브 환경(블루라고 함)과 함께 새 애플리케이션 환경(그린이라고 함)을 생성합니다. 블루 환경에서 그린 환경으로 라이브 트래픽을 라우팅하기 전에 그린 환경을 모니터링하고 테스트할 수 있습니다. 그린 환경에서 실시간 트래픽을 제공하고 나면 블루 환경을 안전하게 종료할 수 있습니다.

CloudFormation을 사용하여 ECS에서 CodeDeploy 블루/그린 배포를 수행하려면 다음 정보를 스택 템플릿에 포함하세요.
+ `AWS::CodeDeploy::BlueGreen` 후크를 설명하는 `Hooks` 섹션.
+  `AWS::CodeDeployBlueGreen` 변환을 지정하는 `Transform` 섹션.

다음 주제에서는 ECS에서의 블루/그린 배포를 위한 CloudFormation 템플릿을 설정하는 방법을 안내합니다.

**Topics**
+ [블루/그린 배포 관련 정보](about-blue-green-deployments.md)
+ [CloudFormation을 사용하여 ECS 블루/그린 배포를 관리할 때 고려 사항](blue-green-considerations.md)
+ [`AWS::CodeDeploy::BlueGreen` 후크 구문](blue-green-hook-syntax.md)
+ [블루/그린 배포 템플릿 예제](blue-green-template-example.md)

# 블루/그린 배포 관련 정보
<a name="about-blue-green-deployments"></a>

이 주제에서는 CloudFormation을 사용한 블루/그린 배포의 작동 방식에 대한 개요를 제공합니다. 또한 블루/그린 배포를 위해 CloudFormation 템플릿을 준비하는 방법도 설명합니다.

**Topics**
+ [작동 방식](#blue-green-how-it-works)
+ [그린 배포를 개시하는 리소스 업데이트](#blue-green-resources)
+ [템플릿 준비](#blue-green-setup)
+ [블루/그린 배포 모델링](#blue-green-required)
+ [변경 세트](#blue-green-changesets)
+ [스택 이벤트 모니터링](#blue-green-events)
+ [IAM 권한](#blue-green-iam)

## 작동 방식
<a name="blue-green-how-it-works"></a>

CloudFormation을 사용하여 CodeDeploy를 통해 ECS 블루/그린 배포를 수행하는 경우 사용할 트래픽 라우팅 및 안정화 설정 지정을 포함해 블루 및 그린 애플리케이션 환경 모두에 리소스를 정의하는 스택 템플릿을 먼저 생성합니다. 다음으로 해당 템플릿에서 스택을 생성합니다. 그러면 블루(현재) 애플리케이션이 생성됩니다. CloudFormation은 스택 생성 중에만 블루 리소스를 생성합니다. 그린 배포에 대한 리소스는 필요할 때까지 생성되지 않습니다.

따라서 향후 스택 업데이트에서 블루 애플리케이션의 작업 정의 또는 작업 세트 리소스를 업데이트하는 경우 CloudFormation은 다음을 수행합니다.
+ 필요한 모든 그린 애플리케이션 환경 리소스 생성
+ 지정된 트래픽 라우팅 파라미터를 기반으로 트래픽 이동
+ 블루 리소스 삭제

그린 배포가 성공하고 완료되기 전에 오류가 발생하면 CloudFormation은 전체 그린 배포가 시작되기 전의 상태로 스택을 롤백합니다.

## 그린 배포를 개시하는 리소스 업데이트
<a name="blue-green-resources"></a>

특정 ECS 리소스의 특정 속성을 업데이트하는 스택 업데이트를 수행하면 CloudFormation에서 그린 배포 프로세스를 개시합니다. 이 프로세스를 개시하는 리소스는 다음과 같습니다.
+ [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) 

하지만 이러한 리소스에 대한 업데이트에 교체가 필요한 속성 변경이 포함되지 않는 경우 그린 배포가 개시되지 않습니다. 자세한 내용은 [스택 리소스의 업데이트 동작 이해](using-cfn-updating-stacks-update-behaviors.md) 섹션을 참조하세요.

동일한 스택 업데이트에서 다른 리소스에 대한 업데이트와 함께 위의 리소스에 대한 업데이트를 포함시킬 수 없다는 점이 중요합니다. 나열된 리소스와 동일한 스택 내의 다른 리소스를 모두 업데이트해야 하는 경우 다음 두 가지 옵션을 사용할 수 있습니다.
+ 두 개의 별도 스택 업데이트 작업을 수행합니다. 즉, 위의 리소스에 대한 업데이트만 포함시키는 작업과 기타 리소스에 대한 변경 사항을 포함시키는 별도의 스택 업데이트 작업을 수행합니다.
+ 템플릿에서 `Transform` 및 `Hooks` 섹션을 제거한 다음 스택 업데이트를 수행합니다. 이 경우 CloudFormation이 그린 배포를 수행하지 않습니다.

## ECS 블루/그린 배포를 수행하기 위한 템플릿 준비
<a name="blue-green-setup"></a>

스택에서 블루/그린 배포를 활성화하려면, 스택 업데이트를 수행하기 전에 다음 섹션을 스택 템플릿에 포함시키십시오.
+ `AWS::CodeDeployBlueGreen` 변환에 대한 참조를 템플릿에 추가합니다.

  ```
  "Transform": [
    "AWS::CodeDeployBlueGreen"
  ],
  ```
+ `AWS::CodeDeploy::BlueGreen` 후크를 호출하고 배포에 대한 속성을 지정하는 `Hooks` 섹션을 추가합니다. 자세한 내용은 [`AWS::CodeDeploy::BlueGreen` 후크 구문](blue-green-hook-syntax.md) 섹션을 참조하세요.
+ `Resources` 섹션에서 배포에 대한 블루 및 그린 리소스를 정의합니다.

템플릿을 처음으로 생성할 때(즉, 스택 자체를 만들기 전에) 이러한 섹션을 추가하거나 스택 업데이트를 수행하기 전에 기존 템플릿에 추가할 수 있습니다. 새 스택에 블루/그린 배포를 지정하는 경우 CloudFormation은 스택 생성 중에 블루 리소스만 생성하며 그린 배포에 대한 리소스는 스택 업데이트 중에 필요할 때까지 생성되지 않습니다.

## CloudFormation 리소스를 사용하여 블루/그린 배포 모델링
<a name="blue-green-required"></a>

ECS에서 CodeDeploy 블루/그린 배포를 수행하려면 CloudFormation 템플릿에 Amazon ECS 서비스 및 로드 밸런서와 같이 배포를 모델링하는 리소스를 포함해야 합니다. 이러한 리소스 의미에 대한 자세한 내용을 알아보려면 *AWS CodeDeploy 사용 설명서*의 [Amazon ECS 배포를 시작하기 전에](https://docs.aws.amazon.com/codedeploy/latest/userguide/deployment-steps-ecs.html#deployment-steps-prerequisites-ecs)를 참조하세요.


| 요구 사항 | 리소스 | 필수/선택 | 바뀌는 경우 블루/그린 배포 개시? | 
| --- | --- | --- | --- | 
| Amazon ECS 클러스터 | [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) | 선택 사항. 기본 클러스터를 사용할 수 있습니다. | 아니요 | 
| Amazon ECS 서비스 | [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) | 필수 사항입니다. | 아니요 | 
| 애플리케이션 또는 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) | 필수 사항입니다. | 아니요 | 
| 프로덕션 리스너 | [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) | 필수 사항입니다. | 아니요 | 
| 테스트 리스너  | [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) | 선택 사항. | 아니요 | 
| 대상 그룹 두 개 | [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) | 필수 사항입니다. | 아니요 | 
| Amazon ECS 작업 정의  | [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) | 필수 사항입니다. | 예 | 
| Amazon ECS 애플리케이션의 컨테이너 | [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) | 필수 사항입니다. | 아니요 | 
| 대체 작업 세트의 포트 | [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) | 필수 사항입니다. | 아니요 | 

## 변경 세트
<a name="blue-green-changesets"></a>

그린 배포를 시작할 스택 업데이트를 수행하기 전에 변경 세트를 생성하는 것이 좋습니다. 이렇게 하면 스택 업데이트를 수행하기 전에 스택에 이루어질 실제 변경 사항을 확인할 수 있습니다. 리소스 변경 사항은 스택 업데이트 중에 수행되는 순서대로 나열되지 않을 수 있습니다. 자세한 내용은 [변경 세트를 사용하여 CloudFormation 스택 업데이트](using-cfn-updating-stacks-changesets.md) 섹션을 참조하세요.

## 스택 이벤트 모니터링
<a name="blue-green-events"></a>

**Stack**(스택) 페이지의 **Events**(이벤트) 탭에서 AWS CLI를 사용하여 ECS 배포의 각 단계에서 생성된 스택 이벤트를 볼 수 있습니다. 자세한 내용은 [스택 진행 상황 모니터링](monitor-stack-progress.md) 섹션을 참조하세요.

## 블루/그린 배포를 위한 IAM 권한
<a name="blue-green-iam"></a>

CloudFormation에서 블루-그린 배포를 성공적으로 수행하려면 다음 CodeDeploy 권한이 있어야 합니다.
+ `codedeploy:Get*`
+ `codedeploy:CreateCloudFormationDeployment`

자세한 내용은 **서비스 권한 부여 참조에서 [CodeDeploy에 사용되는 작업, 리소스 및 조건 키](https://docs.aws.amazon.com/service-authorization/latest/reference/list_awscodedeploy.html)를 참조하세요.

# CloudFormation을 사용하여 ECS 블루/그린 배포를 관리할 때 고려 사항
<a name="blue-green-considerations"></a>

CloudFormation을 사용하여 CodeDeploy를 통해 ECS 블루/그린 배포를 수행하는 프로세스는 CodeDeploy만 사용하는 표준 ECS 배포와는 다릅니다. 차이점을 자세히 알아보려면 **AWS CodeDeploy 사용 설명서의 [CodeDeploy와 CloudFormation을 통한 Amazon ECS 블루/그린 배포 간 차이점](https://docs.aws.amazon.com/codedeploy/latest/userguide/deployments-create-ecs-cfn.html#differences-ecs-bg-cfn)을 참조하세요.

CloudFormation을 사용하여 블루/그린 배포를 관리할 때는 다음과 같은 특정 제한 사항 및 고려 사항을 염두에 두어야 합니다.
+ 특정 리소스에 대한 업데이트만 그린 배포를 트리거합니다. 자세한 내용은 [그린 배포를 개시하는 리소스 업데이트](about-blue-green-deployments.md#blue-green-resources) 섹션을 참조하세요.
+ 그린 배포를 트리거하는 리소스에 대한 업데이트와 다른 리소스에 대한 업데이트를 동일한 스택 업데이트에 포함할 수 없습니다. 자세한 내용은 [그린 배포를 개시하는 리소스 업데이트](about-blue-green-deployments.md#blue-green-resources) 섹션을 참조하세요.
+ 하나의 ECS 서비스만 배포 대상으로 지정할 수 있습니다.
+ CloudFormation에 의해 난독화된 값이 있는 파라미터는 그린 배포 중에 CodeDeploy에서 업데이트할 수 없으며 오류 및 스택 업데이트 실패로 이어질 수 있습니다. 다음이 포함됩니다.
  + `NoEcho` 속성으로 정의된 파라미터
  + 동적 참조를 사용하여 외부 서비스에서 해당 값을 검색하는 파라미터 동적 참조에 대한 자세한 내용은 [동적 참조를 사용하여 다른 서비스에 저장된 값 가져오기](dynamic-references.md)의 내용을 참조하세요.
+ 아직 진행 중인 그린 배포를 취소하려면 CodeDeploy 또는 ECS가 아니라 CloudFormation에서 스택 업데이트를 취소하세요. 자세한 내용은 [스택 업데이트 취소](using-cfn-stack-update-cancel.md) 섹션을 참조하세요. 업데이트가 완료된 후에는 업데이트를 취소할 수 없습니다. 하지만 이전 설정을 사용하여 스택을 다시 업데이트할 수 있습니다.
+ 다음 CloudFormation 기능은 현재 ECS 블루/그린 배포를 정의하는 템플릿에서 지원되지 않습니다.
  + [출력](outputs-section-structure.md) 선언 또는 [Fn::ImportValue](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-importvalue.html) 사용으로 다른 스택에서 값 가져오기.
  + 리소스 가져오기. 리소스 가져오기에 대한 자세한 내용은 [CloudFormation 스택에 AWS 리소스 가져오기](import-resources.md)의 내용을 참조하세요.
  + 중첩 스택 리소스가 포함된 템플릿에 `AWS::CodeDeploy::BlueGreen` 후크 사용하기. 중첩 스택에 대한 자세한 내용은 [중첩 스택을 사용하여 템플릿을 재사용 가능한 조각으로 분할](using-cfn-nested-stacks.md) 섹션을 참조하세요.
  + 중첩 스택에서 `AWS::CodeDeploy::BlueGreen` 후크 사용하기.

# `AWS::CodeDeploy::BlueGreen` 후크 구문
<a name="blue-green-hook-syntax"></a>

다음 구문은 ECS 블루/그린 배포를 위한 `AWS::CodeDeploy::BlueGreen` 후크 구조를 설명합니다.

## 구문
<a name="cfn-blue-green-hook-syntax"></a>

```
"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)"
              ]
            }
          }
        }
      ]
    }
  }
}
```

## 속성
<a name="cfn-blue-green-hook-properties"></a>

논리적 ID(**논리명이라고도 함)  
템플릿의 `Hooks` 섹션에서 선언된 후크의 논리적 ID입니다. 논리적 ID는 영숫자(A-Za-z0-9)여야 하며 템플릿 내에서 고유해야 합니다.  
*필수 항목 여부:* 예    
`Type`  
후크의 유형입니다. `AWS::CodeDeploy::BlueGreen`   
*필수 항목 여부:* 예  
`Properties`  
후크의 속성  
*필수 항목 여부:* 예    
`TrafficRoutingConfig`  
트래픽 라우팅 구성 설정  
*필수 항목 여부*: 아니요  
기본 구성은 시간 기반 카나리 트래픽 이동으로 15% 단계 비율 및 5분 베이크 시간입니다.    
`Type`  
배포 구성에 사용되는 트래픽 이동 유형  
유효한 값: AllAtOnce \$1 TimeBasedCanary \$1 TimeBasedLinear  
*필수 항목 여부:* 예    
`TimeBasedCanary`  
배포의 한 버전에서 다른 버전으로 트래픽을 2씩 증분하여 이동하는 구성을 지정합니다.  
*필수*: 조건부: 트래픽 라우팅 유형으로 `TimeBasedCanary`를 지정하는 경우 `TimeBasedCanary` 파라미터를 포함시켜야 합니다.    
`StepPercentage`  
`TimeBasedCanary` 배포의 첫 번째 증분에서 이동할 트래픽의 비율입니다. 단계 비율은 14% 이상이어야 합니다.  
*필수 항목 여부*: 아니요  
`BakeTimeMins`  
`TimeBasedCanary` 배포의 첫 번째와 두 번째 트래픽 이동 사이의 시간(분)입니다.  
*필수 항목 여부*: 아니요  
`TimeBasedLinear`  
동일한 증분(각 증분 사이에 동일한 시간(분) 지정)을 사용하여 배포의 한 버전에서 다른 버전으로 트래픽을 이동하는 구성을 지정합니다.  
*필수*: 조건부: 트래픽 라우팅 유형으로 `TimeBasedLinear`를 지정하는 경우 `TimeBasedLinear` 파라미터를 포함시켜야 합니다.    
`StepPercentage`  
`TimeBasedLinear` 배포의 각 증분이 시작될 때 이동되는 트래픽의 비율. 단계 비율은 14% 이상이어야 합니다.  
*필수 항목 여부*: 아니요  
`BakeTimeMins`  
`TimeBasedLinear` 배포의 각 증분 트래픽 이동 사이의 시간(분)  
*필수 항목 여부*: 아니요  
`AdditionalOptions`  
블루/그린 배포를 위한 추가 옵션  
*필수 항목 여부*: 아니요    
`TerminationWaitTimeInMinutes`  
블루 리소스를 종료하기 전에 대기할 시간(분)을 지정합니다.  
*필수 항목 여부*: 아니요  
`LifecycleEventHooks`  
수명 주기 이벤트 후크를 사용하여 CodeDeploy가 배포를 검증하기 위해 호출할 수 있는 Lambda 함수를 지정합니다. 배포 수명 주기 이벤트에 동일한 함수 또는 다른 함수를 사용할 수 있습니다. 검증 테스트가 완료되면 Lambda `AfterAllowTraffic` 함수는 CodeDeploy를 다시 호출하고 `Succeeded` 또는 `Failed` 결과를 전달합니다. 자세한 내용을 알아보려면 *AWS CodeDeploy 사용 설명서*의 [AppSpec '후크' 섹션](https://docs.aws.amazon.com/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html)을 참조하세요.  
*필수 항목 여부*: 아니요    
`BeforeInstall`  
대체 작업 세트가 생성되기 전에 작업을 실행할 때 사용하는 함수  
*필수 항목 여부*: 아니요  
`AfterInstall`  
대체 작업 세트가 생성되었고 대상 그룹 중 하나가 연결된 후 작업을 실행할 때 사용하는 함수  
*필수 항목 여부*: 아니요  
`AfterAllowTestTraffic`  
테스트 리스너가 대체 작업 세트에 트래픽을 제공한 후 작업을 실행할 때 사용하는 함수  
*필수 항목 여부*: 아니요  
`BeforeAllowTraffic`  
트래픽이 대체 작업 세트로 이동되기 전에 두 번째 대상 그룹이 대체 작업 세트와 연결된 후 작업을 실행할 때 사용하는 함수  
*필수 항목 여부*: 아니요  
`AfterAllowTraffic`  
두 번째 대상 그룹이 대체 작업 세트에 트래픽을 제공한 후 작업을 실행할 때 사용하는 함수  
*필수 항목 여부*: 아니요  
`ServiceRole`  
블루 그린 배포를 수행할 때 사용하는 CloudFormation에 대한 실행 역할. 필요한 권한의 목록은 [블루/그린 배포를 위한 IAM 권한](about-blue-green-deployments.md#blue-green-iam) 섹션을 참조하세요.  
*필수 항목 여부*: 아니요  
`Applications`  
Amazon ECS 애플리케이션의 속성을 지정합니다.  
*필수 항목 여부:* 예    
`Target`  
  
*필수 항목 여부:* 예    
`Type`  
리소스의 유형.  
*필수 항목 여부:* 예  
`LogicalID`  
리소스의 논리적 ID  
*필수 항목 여부:* 예  
`ECSAttributes`  
Amazon ECS 애플리케이션 배포의 다양한 요구 사항을 나타내는 리소스  
*필수 항목 여부:* 예    
`TaskDefinitions`  
Amazon ECS 애플리케이션이 포함된 Docker 컨테이너를 실행하기 위한 [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) 리소스의 논리적 ID  
*필수 항목 여부:* 예  
`TaskSets`  
애플리케이션의 작업 세트로 사용할 [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) 리소스의 논리적 ID  
*필수 항목 여부:* 예  
`TrafficRouting`  
트래픽 라우팅에 사용되는 리소스를 지정합니다.  
*필수 항목 여부:* 예    
`ProdTrafficRoute`  
대상 그룹으로 트래픽을 보내는 데 로드 밸런서에서 사용할 리스너  
*필수 항목 여부:* 예    
`Type`  
리소스의 유형입니다. `AWS::ElasticLoadBalancingV2::Listener`   
*필수 항목 여부:* 예  
`LogicalID`  
리소스의 논리적 ID  
*필수 항목 여부:* 예  
`TestTrafficRoute`  
대상 그룹으로 트래픽을 보내는 데 로드 밸런서에서 사용할 리스너  
*필수 항목 여부:* 예    
`Type`  
리소스의 유형입니다. `AWS::ElasticLoadBalancingV2::Listener`   
*필수 항목 여부:* 예  
`LogicalID`  
리소스의 논리적 ID  
*필수 항목 여부*: 아니요  
`TargetGroups`  
트래픽을 등록된 대상으로 라우팅하기 위해 대상 그룹으로 사용할 리소스의 논리적 ID  
*필수 항목 여부:* 예

# 블루/그린 배포 템플릿 예제
<a name="blue-green-template-example"></a>

다음 예제 템플릿에서는 ECS에서의 CodeDeploy 블루/그린 배포를 설정합니다. 여기에서 단계당 트래픽 라우팅 진행률은 15%이고 각 단계 사이의 안정화 기간은 5분입니다.

템플릿을 이용해 스택을 생성하면 배포의 초기 구성이 프로비저닝됩니다. 따라서 `BlueTaskSet` 리소스(대체해야 하는 리소스)의 속성을 변경한 경우 CloudFormation은 스택 업데이트의 일부로 그린 배포를 시작합니다.

## JSON
<a name="blue-green-template-example.json"></a>

```
{
  "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
<a name="blue-green-template-example.yaml"></a>

```
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
```