-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Blue Green ECS Deployment #1559
Comments
Blue/Green deployment for ECS is a supported feature, but I'm not sure it's available through CloudFormation yet, and we definitely don't have support for it in the CDK as of yet. You will have to set it up by hand for now.
It's not the class name, it's the second parameter that you pass to stack: new MyStack(app, "ThisIsTheName"); CloudFormation orients itself around the concept of "stacks" and stacks must have a name to identify them.
Classes (which you would combine through inheritance) give you a "kind of stack". You instantiate a class to get an object, which represents a real Stack. For example: class MyStack extends cdk.Stack {
// ...
}
// MyStack is not deployable yet. It might take parameters that we haven't filled in.
// To make it real, let's instantiate it:
new MyStack(app, 'Stack1', { flavor: 'banana' });
new MyStack(app, 'Stack2, { flavor: 'raspberry' });
// In fact, I can even instantiate multiple CloudFormation stacks from the same class!
// But they must have different names. This is a long way to say, once you have an object you can access attributes of it and pass those around, potentially as input arguments to another stack. It works just the same as in a regular programming language. Here's an example of defining an S3 bucket in one stack, and using it in another:
I wouldn't recommend you put class MyStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
if (this.requireAccountId() !== '12345678') {
throw new Error('You must deploy this in account 12345678!');
}
}
}
I'm sorry, I do not understand the question. Could you explain a bit more? |
@rix0rrr thanks for your quick response.
In my use case I have the same stack being used for UAT and PROD . In this case what would you suggest?
I am sorry for the lack of explanation. Imagine a stack for UAT and PROD in the same account . |
Related: #2056 |
Reopened to track support for blue-green deployments |
So looks like starting with the L2s we can add an option to TaskDefinition to enable/blue green. We can do this by outputting the hook and transform detailed in the docs here https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/blue-green.html Some experimentation may be required to get this working properly with a nice API. It could constitute a new "pattern". I haven't seen a lot of examples of using the L1s to achieve this but it should be possible. |
The "considerations" section of the user guide has some details that look like they are going to complicate implementation.
|
As mentioned by @shamhub in #6605 there is a construct out there supporting this that may provide some guidance for implementation. https://www.npmjs.com/package/@cloudcomponents/cdk-blue-green-container-deployment |
What is the status of Blue Green ECS Deployment for AWS CDK? |
+1 it would be great to see support for blue/green deployments in ECS/Fargate in CDK since it's available in CloudFormation already (since 19th May) |
We are investigating how to integrate this in CDK and provide an idiomatic experience. This is not a trivial task because of the limitations of the feature in cloudformation as mentioned above. We are considering a number of options including custom resources and/or magically splitting out blue/green resources into their own stack and somehow hiding the limitations around export/import mechanics. I would encourage anyone who really wants to leverage this feature now to check out third party construct libraries, e.g. https://www.npmjs.com/package/@cloudcomponents/cdk-blue-green-container-deployment An RFC is likely required to flesh out the design of an implementation that could be included in the core library. |
I spent the last 2 weeks trying to get this to work. I did find that npm package but I really didn't want to use Lambdas for this as I don't need them when I manually set this up. So glad I found this ticket ❤️ I will use the npm package above to get this working and will refactor once this is properly supported by the CDK. I am just glad to see I wasn't incompetent in this. I thought I was just missing something but glad to see it's not me. Looking forward to the update and support of Fargate Blue/Green deployments in the CDK. Is there any ETA for this? (next 6 months, over a year) Just wondering as using the npm package will suffice for now, it's not ideal. |
This construct is really shaky and with unpredictable behavior.. The author is not even following issues and request too |
I really doubt CDK can natively support this properly. the CloudFormation implementation for Blue/Green deployment have lot of restriction. One of the big issue I have with it is that the CloudFormation will fail at transform if you modify any resources that is not part of Blue/Green resources. e.g. I have one CloudFormation with ECS service, Blue/Green, IAM such as ECS task role and execution role. Sound normally right? so what if one day I think I need to expand the ECS task role permission to allow to perform certain task such as SQS? now the CloudFormation will immediately fail to update the stack because you can't update any resources that is not also part of the Blue/Green. The fundamental design of the whole blue/green implementation is purely wrong and it doesn't seem like it should be used in current state. |
@peterwoodworth - Thanks for bringing up my issue here. Article 2 : https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/blue-green.html
Error: Here I am using "FargetService" Construct, I am not passing any NetworkConfiguration , but CDK is assuming by itself while creating the template and I had a confirmation from CDK support team in AWS, even they confirmed that the creation of NetworkConfiguration inside the "ECS Service" was initiated during CDK Synth. When I deploy the Template using "CDK Deploy", I am facing the above error.
Error : I am working for Farget Service, If I don't pass the LaunchType it is assuming the launch type as "EC2" which is irrevelant for Fargate Service and If I pass the launchType the stack fails returning the above error. Implementations: Implementation 1 : const Service = new FargateService(this, "Service", { I tried to remove the assignPublicIp, vpcSubnets, securityGroup and see if that is causing the NetworkConfiguration in the Service but the result is still the same. Implementation 2 : const Service = new CfnService(this, 'Service', { can someone help me with this? |
You would specify the See the highlighted portions from the trivia game sample you linked:
|
@dillon-odonovan - I think you might have misunderstood my question.
The above mentioned is my implementation which while deployment throws an error below : Resource handler returned message: "Invalid request provided: CreateService error: NetworkConfiguration must be null. (Service: AmazonECS; Status Code: 400; Error Code: InvalidParameterException; Request ID: f3d3b359-32f3-4dad-bf56-abd2552af518; Proxy: null)" (RequestToken: 73935952-e726-0020-a399-c6518da2c124, HandlerErrorCode: InvalidRequest) Here I am not passing any value related to NetworkConfiguration but it is somehow initiating NetworkConfiguration inside "Service" Resource of ECS Template and even the CDK Support with AWS has tried to replicate and they also faced the same issue. This initiation of "NetworkConfiguration" inside the Template is from CDK which is creating the error during the deployment. Please let me know if there is any way to stop "NetworkConfiguration" initiation as part of the "Service" resource of the ECS Template during CDK Synth.
When I used the above construct it was creating "Service" with "EC2" as the "launchType" whereas I am looking for "Fargate" based Service. It is taking the defaults which is EC2.
The above-mentioned implementation which while deployment throws an error below : Resource handler returned message: "Invalid request provided: CreateService error: LaunchType must be blank. (Service: AmazonECS; Status Code: 400; Error Code: InvalidParameterException; Request ID: 0e1f6d38-d0e8-4438-af67-68e0bf5caa48; Proxy: null)" (RequestToken: 3aab09c2-6cfa-3674-8ea0-300d2be1c4e3, HandlerErrorCode: InvalidRequest) If I remove launchType it is creating Service with "EC2" and if I add the launchType it is throwing the above error during deployment. I am basically looking for the L2 construct-based implementation, so if there is anything we can do with the first case please help me with that. If that is not possible then please help me in finding a solution with the second use case using L1. I am also attaching my code in the attach file section please have a look at that. I hope this clears what I am looking for. |
You can't specify the launchType on the CfnService, it needs to be set on the TaskSet. If you follow the AWS sample closely you should not have issues. Currently you can't use an L2 construct for the service, you have to use the L1 CfnService. Your service will deploy on Fargate if you TaskSet and Blue Green hook are configured correctly despite not specifying Fargate as the launchType on the L1/L2 service construct. If it attempts to deploy on EC2 then you have an issue elsewhere (most likely in the Blue Green hook with the logical IDs). Your implementation 2 looks pretty close, just remove the launchType from that construct. It also appears like you're not properly referencing the ECS Service logical ID in the Blue/Green hook - it looks like you're providing the name of the service. Try changing those two things and see if it works for you. |
@dillon-odonovan - Thanks for the support, I have made the respective changes it is working fine now. |
Hi all, I've been working on this for weeks, but I continue to encounter problems. new CfnCodeDeployBlueGreenHook(this.stack, 'CodeDeployBlueGreenHook', {
trafficRoutingConfig: {
type: CfnTrafficRoutingType.TIME_BASED_CANARY,
timeBasedCanary: {
// Shift 20% of prod traffic, then wait 15 minutes
stepPercentage: 20,
bakeTimeMins: 15,
},
},
additionalOptions: {
terminationWaitTimeInMinutes: 30,
},
// TODO: usefull to invoke a function after test traffic is routed, but before prod traffic
lifecycleEventHooks: {},
serviceRole: getCodeDeployRoleName(this.stage), // retrieves the correct role
applications: [
{
target: {
type: service.cfnResourceType,
logicalId: this.stack.getLogicalId(service),
},
ecsAttributes: {
taskDefinitions: [taskDefLogicalId, `${taskDefLogicalId}Green`],
taskSets: [taskSetLogicalId, `${taskSetLogicalId}Green`],
trafficRouting: {
prodTrafficRoute: {
type: CfnListener.CFN_RESOURCE_TYPE_NAME,
logicalId: this.stack.getLogicalId(listener4prod.node.defaultChild as CfnListener),
},
testTrafficRoute: {
type: CfnListener.CFN_RESOURCE_TYPE_NAME,
logicalId: this.stack.getLogicalId(listener4test.node.defaultChild as CfnListener),
},
targetGroups: [
this.stack.getLogicalId(blueTargetGroup.node.defaultChild as CfnTargetGroup),
this.stack.getLogicalId(greenTargetGroup.node.defaultChild as CfnTargetGroup),
],
},
},
},
],
}); Given that it deploys perfectly the first time, as soon as I update anything inside the application code, this hook throws an error: The produced JSON is: "Hooks": {
"CodeDeployBlueGreenHook": {
"Type": "AWS::CodeDeploy::BlueGreen",
"Properties": {
"ServiceRole": "becky-code-deploy-test",
"Applications": [
{
"Target": {
"Type": "AWS::ECS::Service",
"LogicalID": "RedisLoggerService"
},
"ECSAttributes": {
"TaskDefinitions": [
"RedisLoggerTaskDefinition73152CDA",
"RedisLoggerTaskDefinition73152CDAGreen"
],
"TaskSets": [
"TaskSet",
"TaskSetGreen"
],
"TrafficRouting": {
"ProdTrafficRoute": {
"Type": "AWS::ElasticLoadBalancingV2::Listener",
"LogicalID": "BeckyApplicationLoadBalancerListenerForProduction4293A970"
},
"TestTrafficRoute": {
"Type": "AWS::ElasticLoadBalancingV2::Listener",
"LogicalID": "BeckyApplicationLoadBalancerListenerForTest9DD6276D"
},
"TargetGroups": [
"ServiceTargetGroupBlue9182D76F",
"ServiceTargetGroupGreen10661C6D"
]
}
}
}
],
"TrafficRoutingConfig": {
"Type": "TimeBasedCanary",
"TimeBasedCanary": {
"StepPercentage": 20,
"BakeTimeMins": 15
}
},
"AdditionalOptions": {
"TerminationWaitTimeInMinutes": 30
}
}
}
} TBH I don't know where the problem can be: every logicalId reference something real (even What else should I look for?? Thanks a lot! |
Just wanted to check I've understood right will we be able to describe BlueGreen CodeDeploy deployments using CDK, to the same extent as we can in cloud formation (I.E with target groups and services) once PR #22295 get merged in ? |
@RichardChester Correct. You can use the L1 construct today in CDK (working example here), but PR #22295 will make it easier through an L2 construct. |
closes #1559 *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
|
The new L2 construct is now available in version 2.50.0. You can see an example here: |
@clareliguori We have followed the example you posted and when we change the tag on a task definition, we see that the current revision becomes inactive. However, we do not see any revisions created in ECS console. If we create a revision manually in ECS console, we see the code deploy project begin the blue/green deployment. Do you know what we might be missing? Is this possible without codepipeline? Note: Using c# |
@cplee have you seen this behavior? I haven't had an opportunity to try to reproduce it. |
@dsdavis4 - how are you trying to trigger new CodeDeploy deployments outside of CodePipeline? Are you using the |
I'm able to partially reproduce this, except I do see a new revision created while the old one is marked as inactive. Steps with my example:
Marking the previous task definition revision as inactive is typical CloudFormation behavior, as it assumes that you will immediately update an ECS service in the same stack with the new active revision. In this case though, because the service will be updated with the new revision outside of CloudFormation with CodeDeploy, I think we need the previous revision to stay active. For example, if CodeDeploy needs to do a rollback deployment to the ECS service (attempting to re-deploy a previous revision), it will not be able to if the previous revision is inactive. In order to keep the previous task def revision active, an UpdateReplacePolicy of "Retain" needs to be set on the task definition resource. I have updated my example with this code:
|
@clareliguori This is the behavior we are seeing as well. It's possible we might have had a misunderstanding of the expected outcome. We expected the @cplee We are not using code pipeline, we are using the L2 construct |
Correct, the construct added for this issue does not automatically start a new CodeDeploy deployment, it only sets up the CodeDeploy deployment group resource. @cplee's PR #22455 covers kicking off deployments with |
For those looking for a way to start CodeDeploy deployments for ECS services within CDK, take a look at the new construct on Construct Hub to provide this functionality: declare const deploymentGroup: codeDeploy.IEcsDeploymentGroup;
declare const taskDefinition: ecs.ITaskDefinition;
new EcsDeployment({
deploymentGroup,
targetService: {
taskDefinition,
containerName: 'mycontainer',
containerPort: 80,
},
}); |
@cplee Do you know if there are any plans to add this to the official cdk library? |
Hi ,
I am referencing this video from the 2018 Re:Invent .https://www.youtube.com/watch?v=01ewawuL-IY.
I am struggling to get and blue green deployment setup where I have Infrastructure stack with fargate and another stack with multiple microservice on which run on fargate.
Can some examples be provided on how to do blue green deployment with ECR as an source?
The confusing part here is how to pass the docker image tag, target and task to the cdk pipeline or as a cloudformtation template to support Blue/Green Deployment.
It makes sense if the stack name defaults to the TS class name but then what is the use of stack name when its being provided in the cloudformtation service.
How to access other stacks without having to do an TS way of logical inheritance?
Are there any examples where based on aws accounts i can put a specific VPC or provision differently ? I know there is a conditional function for TS but I didnt find a good way to write condition based on aws account .
Is there any examples on how to append the export functionality with the parameters provided to CFT at compile time? I get an TS error when I try to an optional variable to the export name @
The text was updated successfully, but these errors were encountered: