次のサンプルテンプレートは、ECS 上に CodeDeploy ブルー/グリーンデプロイを設定し、トラフィックルーティングの進行状況をステップごとに 15 % に、各ステップ間の安定化期間を 5 分に設定します。
テンプレートを使用してスタックを作成すると、デプロイの初期構成がプロビジョニングされます。その後、リソースの置き換えを必要とする BlueTaskSet
リソースのプロパティに変更を加えた場合、CloudFormation はスタック更新の一環としてグリーンのデプロイを開始します。
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