蓝绿部署模板示例 - AWS CloudFormation

蓝绿部署模板示例

以下示例模板设置了 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