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

Cdkv2update #5

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0

FROM public.ecr.aws/nginx/nginx:alpine

COPY nginx.conf /etc/nginx/nginx.conf
COPY index.html /usr/share/nginx/html

ENTRYPOINT ["nginx", "-g", "daemon off;"]
101 changes: 2 additions & 99 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,100 +1,3 @@
# ECS blue/ green deployment using CDK
# Static webpage hosted on NGINX

A walkthrough for this example can be found at https://ecsworkshop.com/blue_green_deployments/

#### Table of Contents

* [Outcome](#Outcome)
* [What are we building?](#what-are-we-building)
* [Why do I need this?](#why-do-i-need-this)
* [What are the pre-requisites?](#what-are-the-pre-requisites)
* [How can I deploy the stack?](#how-can-i-deploy-the-stack)
* [Cleanup](#cleanup)
* [Security](#security)
* [License](#license)

## Outcome

ECS blue/ green deployment CDK construct enabling teams to build and deploy pipeline for their workloads.

## What are we building?

* CodePipeline will be used for executing Blue/Green deployment using CodeCommit, CodeBuild and CodeDeploy
* The container images will be stored in the Elastic Container Registry
* NGINX sample application is deployed in AWS Fargate
* The construct uses a custom resource for creating the deployment configuration and builds the end-to-end infrastructure

![Blue-green-pipeline](./blue-green-pipeline.jpg)

## Why do I need this?

* With a blue/green deployment, you provision a new set of containers on which CodeDeploy installs the latest version of your application. CodeDeploy then re-routes load balancer traffic from an existing set of containers running the previous version of your application to the new set of containers running the latest version
* Blue/green deployments allow you to test the new application version before sending production traffic to it without disrupting the existing environment
* If there is an issue with the newly deployed application version, you can roll back to the previous version faster than with in-place deployments
* Switching to the green environment involves no downtime. It only requires the redirecting of user traffic
* Rolling back from the green environment to the blue environment in the event of a problem is easier because you can redirect traffic to the blue environment without having to rebuild it
* You can incorporate the principle of infrastructure immutability by provisioning fresh instances when you need to make changes. In this way, you avoid configuration drift.

## What are the pre-requisites?

```
brew install jq
npm install -g -f [email protected]
cd $HOME && mkdir -p environment && cd environment
git clone https://github.com/aws-containers/ecs-workshop-blue-green-deployments.git
cd $HOME/environment/ecs-workshop-blue-green-deployments
```
* You have configured AWS CLI using `aws configure`
* You have the set the `AWS_REGION` within `aws configure`
* The role being used from CLI has the permissions required for resources being created by CDK
* HTTPS (GRC) is the protocol to use with `git-remote-codecommit` (GRC). This utility provides a simple method for pushing and pulling code from CodeCommit repositories by extending Git. It is the recommended method for supporting connections made with federated access, identity providers, and temporary credentials
* Install `git-remote-codecommit` with `pip install git-remote-codecommit`

## How can I deploy the stack?

* Install dependencies and build
```shell
npm install
npm run build
npm run test
```
* Deploy the CodeCommit and CodeBuild resources
```shell
cd $HOME/environment/ecs-workshop-blue-green-deployments
./bin/scripts/deploy-container-image-stack.sh
```
* Push the source code to CodeCommit
* The source code is available [here](nginx-sample/README.md)
* The [buildspec.yml](nginx-sample/buildspec.yml) has placeholders for the variables
```shell
export AWS_DEFAULT_REGION=$(aws configure get region)
export CODE_REPO_NAME=nginx-sample
export CODE_REPO_URL=codecommit::$AWS_DEFAULT_REGION://$CODE_REPO_NAME
cd $HOME/environment && git clone $CODE_REPO_URL && cd $CODE_REPO_NAME
cp $HOME/environment/ecs-workshop-blue-green-deployments/nginx-sample/* .
git checkout -b main
git remote -v
git add .
git commit -m "First commit"
git push --set-upstream origin main
```
* Deploy the CodePipeline resources
```shell
cd $HOME/environment/ecs-workshop-blue-green-deployments
./bin/scripts/deploy-pipeline-stack.sh
```

## Cleanup

```shell
cd $HOME/environment/ecs-workshop-blue-green-deployments
./bin/scripts/destroy.sh
```

# Security

See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.

# License

This library is licensed under the MIT-0 License. See the [LICENSE](LICENSE) file.
This is a static app, used for the demo purposes only.
12 changes: 12 additions & 0 deletions appspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0

version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: "<TASK_DEFINITION>"
LoadBalancerInfo:
ContainerName: "nginx-sample"
ContainerPort: 80
8 changes: 4 additions & 4 deletions bin/container-image-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
// SPDX-License-Identifier: MIT-0

import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import {CfnParameter, Construct, StackProps} from '@aws-cdk/core';
import {CfnParameter, StackProps, App, Stack} from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as EcsBlueGreen from '../lib';

export class BlueGreenContainerImageStack extends cdk.Stack {
export class BlueGreenContainerImageStack extends Stack {

constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
Expand All @@ -33,7 +33,7 @@ export class BlueGreenContainerImageStack extends cdk.Stack {

}

const app = new cdk.App();
const app = new App();
new BlueGreenContainerImageStack(app, 'BlueGreenContainerImageStack', {
description: 'Builds the blue/green deployment container build stack'
});
8 changes: 4 additions & 4 deletions bin/pipeline-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
// SPDX-License-Identifier: MIT-0

import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import {CfnParameter, Construct, StackProps} from '@aws-cdk/core';
import { Construct } from 'constructs';
import {CfnParameter, StackProps, App, Stack} from 'aws-cdk-lib';
import * as EcsBlueGreen from '../lib';

export class BlueGreenPipelineStack extends cdk.Stack {
export class BlueGreenPipelineStack extends Stack {

constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
Expand Down Expand Up @@ -53,7 +53,7 @@ export class BlueGreenPipelineStack extends cdk.Stack {
}


const app = new cdk.App();
const app = new App();
new BlueGreenPipelineStack(app, 'BlueGreenPipelineStack', {
description: 'Builds the blue/green deployment pipeline stack'
});
5 changes: 5 additions & 0 deletions bin/scripts/deploy-pipeline-stack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ YELLOW="\033[1;33m"
echo -e "${GREEN}Exporting the cloudformation stack outputs...."

export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export CDK_DEFAULT_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
export AWS_DEFAULT_REGION=$(aws configure get region)

export CDK_DEFAULT_REGION=$(aws configure get region)
export AWS_REGION=$(aws configure get region)


export CODE_REPO_NAME=$(aws cloudformation describe-stacks --stack-name BlueGreenContainerImageStack --query 'Stacks[*].Outputs[?ExportName==`repositoryName`].OutputValue' --output text)
export CODE_REPO_URL=$(aws cloudformation describe-stacks --stack-name BlueGreenContainerImageStack --query 'Stacks[*].Outputs[?ExportName==`repositoryCloneUrlHttp`].OutputValue' --output text)
export ECR_REPO_NAME=$(aws cloudformation describe-stacks --stack-name BlueGreenContainerImageStack --query 'Stacks[*].Outputs[?ExportName==`ecrRepoName`].OutputValue' --output text)
Expand Down
36 changes: 36 additions & 0 deletions buildspec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0

version: 0.2

phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws --version
- aws ecr get-login-password | docker login --username AWS --password-stdin $REPOSITORY_URI
- COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
- IMAGE_TAG=${COMMIT_HASH:=latest}
build:
commands:
- echo Docker build and tagging started on `date`
- docker build -t $REPOSITORY_URI:latest -t $REPOSITORY_URI:$IMAGE_TAG .
- echo Docker build and tagging completed on `date`
post_build:
commands:
- echo Build completed on `date`
- echo Pushing the docker images...
- docker push $REPOSITORY_URI:latest
- docker push $REPOSITORY_URI:$IMAGE_TAG
- echo Update the REPOSITORY_URI:IMAGE_TAG in task definition...
- echo Container image to be used $REPOSITORY_URI:$IMAGE_TAG
- sed -i 's@REPOSITORY_URI@'$REPOSITORY_URI'@g' taskdef.json
- sed -i 's@IMAGE_TAG@'$IMAGE_TAG'@g' taskdef.json
- echo update the REGION in task definition...
- sed -i 's@AWS_REGION@'$AWS_REGION'@g' taskdef.json
- echo update the roles in task definition...
- sed -i 's@TASK_EXECUTION_ARN@'$TASK_EXECUTION_ARN'@g' taskdef.json
artifacts:
files:
- "appspec.yaml"
- "taskdef.json"
8 changes: 8 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<head>
<title>Demo Application</title>
</head>
<body style="background-color: cornflowerblue;">
<h1 style="color: white; text-align: center;">
Demo application - hosted with ECS
</h1>
</body>
10 changes: 5 additions & 5 deletions lib/common/roles.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0

import {Effect, ManagedPolicy, Role, ServicePrincipal} from '@aws-cdk/aws-iam';
import * as cdk from '@aws-cdk/core';
import iam = require('@aws-cdk/aws-iam');
import {Effect, ManagedPolicy, Role, ServicePrincipal} from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
import iam = require('aws-cdk-lib/aws-iam');

export class EcsBlueGreenRoles extends cdk.Construct {
export class EcsBlueGreenRoles extends Construct {

public readonly ecsTaskRole: Role;
public readonly codeBuildRole: Role;

constructor(scope: cdk.Construct, id: string) {
constructor(scope: Construct, id: string) {
super(scope, id);

// ECS task execution role
Expand Down
18 changes: 9 additions & 9 deletions lib/ecs/alarms.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0

import * as cdk from '@aws-cdk/core';
import {Duration} from '@aws-cdk/core';
import {ApplicationLoadBalancer, ApplicationTargetGroup} from '@aws-cdk/aws-elasticloadbalancingv2';
import {Alarm, Metric} from '@aws-cdk/aws-cloudwatch';
import cloudWatch = require('@aws-cdk/aws-cloudwatch');
import { Construct } from 'constructs';
import {Duration} from 'aws-cdk-lib';
import {ApplicationLoadBalancer, ApplicationTargetGroup} from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import {Alarm, Metric} from 'aws-cdk-lib/aws-cloudwatch';
import cloudWatch = require('aws-cdk-lib/aws-cloudwatch');

export interface EcsServiceAlarmsProps {
readonly blueTargetGroup?: ApplicationTargetGroup;
Expand All @@ -23,13 +23,13 @@ export class TargetGroupAlarm {
}
}

export class EcsServiceAlarms extends cdk.Construct {
export class EcsServiceAlarms extends Construct {

public readonly targetGroupAlarms?: TargetGroupAlarm[] = [];
private readonly alarms: Alarm[] = [];
private readonly prefix: string;

constructor(scope: cdk.Construct, id: string, props: EcsServiceAlarmsProps = {}) {
constructor(scope: Construct, id: string, props: EcsServiceAlarmsProps = {}) {
super(scope, id);

// Assigning the prefix
Expand Down Expand Up @@ -60,7 +60,7 @@ export class EcsServiceAlarms extends cdk.Construct {
return new cloudWatch.Metric({
namespace: 'AWS/ApplicationELB',
metricName: 'UnHealthyHostCount',
dimensions: {
dimensionsMap: {
TargetGroup: targetGroup.targetGroupFullName,
LoadBalancer: alb.loadBalancerFullName
},
Expand All @@ -73,7 +73,7 @@ export class EcsServiceAlarms extends cdk.Construct {
return new cloudWatch.Metric({
namespace: 'AWS/ApplicationELB',
metricName: 'HTTPCode_Target_5XX_Count',
dimensions: {
dimensionsMap: {
TargetGroup: targetGroup.targetGroupFullName,
LoadBalancer: alb.loadBalancerFullName
},
Expand Down
14 changes: 7 additions & 7 deletions lib/ecs/cluster.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0

import * as cdk from '@aws-cdk/core';
import {IVpc} from '@aws-cdk/aws-ec2';
import {ICluster} from '@aws-cdk/aws-ecs';
import ec2 = require('@aws-cdk/aws-ec2');
import ecs = require('@aws-cdk/aws-ecs');
import { Construct } from 'constructs';
import {IVpc} from 'aws-cdk-lib/aws-ec2';
import {ICluster} from 'aws-cdk-lib/aws-ecs';
import ec2 = require('aws-cdk-lib/aws-ec2');
import ecs = require('aws-cdk-lib/aws-ecs');

export interface EcsBlueGreenClusterProps {
readonly cidr?: string;
}

export class EcsBlueGreenCluster extends cdk.Construct {
export class EcsBlueGreenCluster extends Construct {

public readonly vpc: IVpc;
public readonly cluster: ICluster;

constructor(scope: cdk.Construct, id: string, props: EcsBlueGreenClusterProps = {}) {
constructor(scope: Construct, id: string, props: EcsBlueGreenClusterProps = {}) {
super(scope, id);

this.vpc = new ec2.Vpc(this, 'ecsClusterVPC', {
Expand Down
20 changes: 10 additions & 10 deletions lib/ecs/deployment-group.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0

import * as cdk from '@aws-cdk/core';
import {CustomResource} from '@aws-cdk/core';
import {Effect, ManagedPolicy, ServicePrincipal} from '@aws-cdk/aws-iam';
import { Construct } from 'constructs';
import {CustomResource, Duration} from 'aws-cdk-lib';
import {Effect, ManagedPolicy, ServicePrincipal} from 'aws-cdk-lib/aws-iam';
import * as path from 'path';
import {EcsDeploymentConfig, IEcsDeploymentGroup} from '@aws-cdk/aws-codedeploy';
import {EcsDeploymentConfig, IEcsDeploymentGroup} from 'aws-cdk-lib/aws-codedeploy';
import {TargetGroupAlarm} from './alarms';
import codeDeploy = require('@aws-cdk/aws-codedeploy');
import iam = require('@aws-cdk/aws-iam');
import lambda = require('@aws-cdk/aws-lambda');
import codeDeploy = require('aws-cdk-lib/aws-codedeploy');
import iam = require('aws-cdk-lib/aws-iam');
import lambda = require('aws-cdk-lib/aws-lambda');

export interface EcsBlueGreenDeploymentGroupProps {

Expand Down Expand Up @@ -68,11 +68,11 @@ export interface EcsBlueGreenDeploymentGroupProps {

}

export class EcsBlueGreenDeploymentGroup extends cdk.Construct {
export class EcsBlueGreenDeploymentGroup extends Construct {

public readonly ecsDeploymentGroup: IEcsDeploymentGroup;

constructor(scope: cdk.Construct, id: string, props: EcsBlueGreenDeploymentGroupProps = {}) {
constructor(scope: Construct, id: string, props: EcsBlueGreenDeploymentGroupProps = {}) {
super(scope, id);

// Creating the ecs application
Expand Down Expand Up @@ -119,7 +119,7 @@ export class EcsBlueGreenDeploymentGroup extends cdk.Construct {
role: customLambdaServiceRole,
description: 'Custom resource to create ECS deployment group',
memorySize: 128,
timeout: cdk.Duration.seconds(60)
timeout: Duration.seconds(60)
});

new CustomResource(this, 'customEcsDeploymentGroup', {
Expand Down
Loading