Skip to content
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

feat(codedeploy): CodeDeploy deployment config constructs for Lambda and ECS #22159

Merged
merged 14 commits into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 106 additions & 37 deletions packages/@aws-cdk/aws-codedeploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ AWS CodeDeploy is a deployment service that automates application deployments to
Amazon EC2 instances, on-premises instances, serverless Lambda functions, or
Amazon ECS services.

The CDK currently supports Amazon EC2, on-premise and AWS Lambda applications.
The CDK currently supports Amazon EC2, on-premise, AWS Lambda, and Amazon ECS applications.

## EC2/on-premise Applications

Expand Down Expand Up @@ -143,7 +143,7 @@ const deploymentGroup = new codedeploy.ServerDeploymentGroup(this, 'DeploymentGr
});
```

## Deployment Configurations
## EC2/on-premise Deployment Configurations

You can also pass a Deployment Configuration when creating the Deployment Group:

Expand Down Expand Up @@ -226,41 +226,6 @@ In order to deploy a new version of this function:
2. Re-deploy the stack (this will trigger a deployment).
3. Monitor the CodeDeploy deployment as traffic shifts between the versions.


### Create a custom Deployment Config

CodeDeploy for Lambda comes with built-in configurations for traffic shifting.
If you want to specify your own strategy,
you can do so with the CustomLambdaDeploymentConfig construct,
letting you specify precisely how fast a new function version is deployed.

```ts
const config = new codedeploy.CustomLambdaDeploymentConfig(this, 'CustomConfig', {
type: codedeploy.CustomLambdaDeploymentConfigType.CANARY,
interval: Duration.minutes(1),
percentage: 5,
});

declare const application: codedeploy.LambdaApplication;
declare const alias: lambda.Alias;
const deploymentGroup = new codedeploy.LambdaDeploymentGroup(this, 'BlueGreenDeployment', {
application,
alias,
deploymentConfig: config,
});
```

You can specify a custom name for your deployment config, but if you do you will not be able to update the interval/percentage through CDK.

```ts
const config = new codedeploy.CustomLambdaDeploymentConfig(this, 'CustomConfig', {
type: codedeploy.CustomLambdaDeploymentConfigType.CANARY,
interval: Duration.minutes(1),
percentage: 5,
deploymentConfigName: 'MyDeploymentConfig',
});
```

### Rollbacks and Alarms

CodeDeploy will roll back if the deployment fails. You can optionally trigger a rollback when one or more alarms are in a failed state:
Expand Down Expand Up @@ -327,3 +292,107 @@ const deploymentGroup = codedeploy.LambdaDeploymentGroup.fromLambdaDeploymentGro
deploymentGroupName: 'MyExistingDeploymentGroup',
});
```

## Lambda Deployment Configurations

CodeDeploy for Lambda comes with built-in configurations for traffic shifting.
If you want to specify your own strategy,
you can do so with the LambdaDeploymentConfig construct,
letting you specify precisely how fast a new function version is deployed.

```ts
const config = new codedeploy.LambdaDeploymentConfig(this, 'CustomConfig', {
trafficRoutingConfig: new codedeploy.TimeBasedCanaryTrafficRoutingConfig({
interval: cdk.Duration.minutes(15),
percentage: 5,
}),
});

declare const application: codedeploy.LambdaApplication;
declare const alias: lambda.Alias;
const deploymentGroup = new codedeploy.LambdaDeploymentGroup(this, 'BlueGreenDeployment', {
application,
alias,
deploymentConfig: config,
});
```

You can specify a custom name for your deployment config, but if you do you will not be able to update the interval/percentage through CDK.

```ts
const config = new codedeploy.LambdaDeploymentConfig(this, 'CustomConfig', {
trafficRoutingConfig: new codedeploy.TimeBasedCanaryTrafficRoutingConfig({
interval: cdk.Duration.minutes(15),
percentage: 5,
}),
deploymentConfigName: 'MyDeploymentConfig',
});
```

To import an already existing Deployment Config:

```ts
const deploymentConfig = codedeploy.LambdaDeploymentConfig.fromLambdaDeploymentConfigName(
this,
'ExistingDeploymentConfiguration',
'MyExistingDeploymentConfiguration',
);
```

## ECS Applications
clareliguori marked this conversation as resolved.
Show resolved Hide resolved

To create a new CodeDeploy Application that deploys an ECS service:

```ts
const application = new codedeploy.EcsApplication(this, 'CodeDeployApplication', {
applicationName: 'MyApplication', // optional property
});
```

To import an already existing Application:

```ts
const application = codedeploy.EcsApplication.fromEcsApplicationName(
this,
'ExistingCodeDeployApplication',
'MyExistingApplication',
);
```

## ECS Deployment Configurations

CodeDeploy for ECS comes with built-in configurations for traffic shifting.
If you want to specify your own strategy,
you can do so with the EcsDeploymentConfig construct,
letting you specify precisely how fast an ECS service is deployed.

```ts
new codedeploy.EcsDeploymentConfig(this, 'CustomConfig', {
trafficRoutingConfig: new codedeploy.TimeBasedCanaryTrafficRoutingConfig({
interval: cdk.Duration.minutes(15),
percentage: 5,
}),
});
```

You can specify a custom name for your deployment config, but if you do you will not be able to update the interval/percentage through CDK.

```ts
const config = new codedeploy.EcsDeploymentConfig(this, 'CustomConfig', {
trafficRoutingConfig: new codedeploy.TimeBasedCanaryTrafficRoutingConfig({
interval: cdk.Duration.minutes(15),
percentage: 5,
}),
deploymentConfigName: 'MyDeploymentConfig',
});
```

Or import an existing one:

```ts
const deploymentConfig = codedeploy.EcsDeploymentConfig.fromEcsDeploymentConfigName(
this,
'ExistingDeploymentConfiguration',
'MyExistingDeploymentConfiguration',
);
```
95 changes: 80 additions & 15 deletions packages/@aws-cdk/aws-codedeploy/lib/ecs/deployment-config.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,109 @@
import { ArnFormat, Resource } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { arnForDeploymentConfig } from '../utils';
import { CfnDeploymentConfig } from '../codedeploy.generated';
import { AllAtOnceTrafficRoutingConfig, ITrafficRoutingConfig } from '../traffic-routing-config';
import { arnForDeploymentConfig, validateName } from '../utils';

/**
* The Deployment Configuration of an ECS Deployment Group.
*
* If you're managing the Deployment Configuration alongside the rest of your CDK resources,
* use the {@link EcsDeploymentConfig} class.
*
* If you want to reference an already existing deployment configuration,
* or one defined in a different CDK Stack,
* use the {@link EcsDeploymentConfig#fromEcsDeploymentConfigName} method.
*
* The default, pre-defined Configurations are available as constants on the {@link EcsDeploymentConfig} class
* (for example, `EcsDeploymentConfig.AllAtOnce`).
*
* Note: CloudFormation does not currently support creating custom ECS configs outside
* of using a custom resource. You can import custom deployment config created outside the
* CDK or via a custom resource with {@link EcsDeploymentConfig#fromEcsDeploymentConfigName}.
*/
export interface IEcsDeploymentConfig {
/** @attribute */
readonly deploymentConfigName: string;

/** @attribute */
readonly deploymentConfigArn: string;
}

/**
* Construction properties of {@link EcsDeploymentConfig}.
*/
export interface EcsDeploymentConfigProps {
/**
* The physical, human-readable name of the Deployment Configuration.
* @default - automatically generated name
*/
readonly deploymentConfigName?: string;

/**
* The configuration that specifies how traffic is shifted from the 'blue'
* target group to the 'green' target group during a deployment.
* @default AllAtOnce
*/
readonly trafficRoutingConfig?: ITrafficRoutingConfig;
}

/**
* A custom Deployment Configuration for an ECS Deployment Group.
*
* Note: This class currently stands as namespaced container of the default configurations
* until CloudFormation supports custom ECS Deployment Configs. Until then it is closed
* (private constructor) and does not extend {@link Construct}
*
* @resource AWS::CodeDeploy::DeploymentConfig
*/
export class EcsDeploymentConfig {
export class EcsDeploymentConfig extends Resource implements IEcsDeploymentConfig {
clareliguori marked this conversation as resolved.
Show resolved Hide resolved
public static readonly ALL_AT_ONCE = deploymentConfig('CodeDeployDefault.ECSAllAtOnce');
public static readonly LINEAR_10PERCENT_EVERY_1MINUTES = deploymentConfig('CodeDeployDefault.ECSLinear10PercentEvery1Minutes');
clareliguori marked this conversation as resolved.
Show resolved Hide resolved
public static readonly LINEAR_10PERCENT_EVERY_3MINUTES = deploymentConfig('CodeDeployDefault.ECSLinear10PercentEvery3Minutes');
public static readonly CANARY_10PERCENT_5MINUTES = deploymentConfig('CodeDeployDefault.ECSCanary10Percent5Minutes');
public static readonly CANARY_10PERCENT_15MINUTES = deploymentConfig('CodeDeployDefault.ECSCanary10Percent15Minutes');

/**
* Import a custom Deployment Configuration for an ECS Deployment Group defined outside the CDK.
*
* @param _scope the parent Construct for this new Construct
* @param _id the logical ID of this new Construct
* @param scope the parent Construct for this new Construct
* @param id the logical ID of this new Construct
* @param ecsDeploymentConfigName the name of the referenced custom Deployment Configuration
* @returns a Construct representing a reference to an existing custom Deployment Configuration
*/
public static fromEcsDeploymentConfigName(_scope: Construct, _id: string, ecsDeploymentConfigName: string): IEcsDeploymentConfig {
public static fromEcsDeploymentConfigName(scope: Construct, id: string, ecsDeploymentConfigName: string): IEcsDeploymentConfig {
ignore(scope);
clareliguori marked this conversation as resolved.
Show resolved Hide resolved
ignore(id);
return deploymentConfig(ecsDeploymentConfigName);
clareliguori marked this conversation as resolved.
Show resolved Hide resolved
}

private constructor() {
// nothing to do until CFN supports custom ECS deployment configurations
/**
* The name of the deployment config
* @attribute
*/
public readonly deploymentConfigName: string;

/**
* The arn of the deployment config
* @attribute
*/
public readonly deploymentConfigArn: string;

public constructor(scope: Construct, id: string, props?: EcsDeploymentConfigProps) {
super(scope, id, {
physicalName: props?.deploymentConfigName,
});

// Construct the traffic routing configuration for the deployment group
const routingConfig = props && props.trafficRoutingConfig ? props.trafficRoutingConfig : new AllAtOnceTrafficRoutingConfig();
clareliguori marked this conversation as resolved.
Show resolved Hide resolved

const resource = new CfnDeploymentConfig(this, 'Resource', {
deploymentConfigName: this.physicalName,
computePlatform: 'ECS',
trafficRoutingConfig: routingConfig.renderTrafficRoutingConfig(),
});

this.deploymentConfigName = this.getResourceNameAttribute(resource.ref);
this.deploymentConfigArn = this.getResourceArnAttribute(arnForDeploymentConfig(resource.ref), {
service: 'codedeploy',
resource: 'deploymentconfig',
resourceName: this.physicalName,
arnFormat: ArnFormat.COLON_RESOURCE_NAME,
});

this.node.addValidation({ validate: () => validateName('Deployment config', this.physicalName) });
}
}

Expand All @@ -50,3 +113,5 @@ function deploymentConfig(name: string): IEcsDeploymentConfig {
deploymentConfigArn: arnForDeploymentConfig(name),
};
}

function ignore(_x: any) { return; }
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-codedeploy/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './rollback-config';
export * from './traffic-routing-config';
export * from './ecs';
export * from './lambda';
export * from './server';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,66 +6,77 @@ import { ILambdaDeploymentConfig } from './deployment-config';

/**
* Lambda Deployment config type
* @deprecated Use `LambdaDeploymentConfig`
*/
export enum CustomLambdaDeploymentConfigType {
/**
* Canary deployment type
* @deprecated Use `LambdaDeploymentConfig`
*/
CANARY = 'Canary',

/**
* Linear deployment type
* @deprecated Use `LambdaDeploymentConfig`
*/
LINEAR = 'Linear'
}

/**
* Properties of a reference to a CodeDeploy Lambda Deployment Configuration.
* @deprecated Use `LambdaDeploymentConfig`
*/
export interface CustomLambdaDeploymentConfigProps {

/**
* The type of deployment config, either CANARY or LINEAR
* @deprecated Use `LambdaDeploymentConfig`
*/
readonly type: CustomLambdaDeploymentConfigType;

/**
* The integer percentage of traffic to shift:
* - For LINEAR, the percentage to shift every interval
* - For CANARY, the percentage to shift until the interval passes, before the full deployment
* @deprecated Use `LambdaDeploymentConfig`
*/
readonly percentage: number;

/**
* The interval, in number of minutes:
* - For LINEAR, how frequently additional traffic is shifted
* - For CANARY, how long to shift traffic before the full deployment
* @deprecated Use `LambdaDeploymentConfig`
*/
readonly interval: Duration;

/**
* The verbatim name of the deployment config. Must be unique per account/region.
* Other parameters cannot be updated if this name is provided.
* @default - automatically generated name
* @deprecated Use `LambdaDeploymentConfig`
*/
readonly deploymentConfigName?: string;
}

/**
* A custom Deployment Configuration for a Lambda Deployment Group.
* @resource AWS::CodeDeploy::DeploymentGroup
* @deprecated CloudFormation now supports Lambda deployment configurations without custom resources. Use {@link LambdaDeploymentConfig}.
*/
export class CustomLambdaDeploymentConfig extends Resource implements ILambdaDeploymentConfig {

/**
* The name of the deployment config
* @attribute
* @deprecated Use `LambdaDeploymentConfig`
*/
public readonly deploymentConfigName: string;

/**
* The arn of the deployment config
* @attribute
* @deprecated Use `LambdaDeploymentConfig`
*/
public readonly deploymentConfigArn: string;

Expand Down
Loading