Setup a CI/CD Pipeline for AWS CDK Applications
CDK Pipelines is a high-level construct library that makes it easy to set up a continuous deployment pipeline for your CDK applications. The pipeline is powered by a popular Continuous Integration (CI) and Continuous Delivery (CD) tool called AWS CodePipeline.
A brief overview of the infrastructure we will create:
- GitHub repository that contains source code for a lambda function and the pipeline itself.
- The CI/CD pipeline will be defined though an AWS CDK stack that uses TypeScript programming language.
- Each commit to the repo will publish the lambda function to a test environment.
- We will have a manual approval step to deploy the lambda function code to a production environment.
Note: The solution just deploys a lambda but you can add some other configuration/resources that you want, this is just a starter template!
A pipeline consists of several stages, which represent logical phases of the deployment. Each stage contains one or more actions that describe what to do in that particular stage.
The pipeline created by CDK pipelines is self-mutating. This means you only need to run cdk deploy
one time to get the pipeline started. After that, the pipeline automatically updates itself if you add new CDK applications or stages in the source code.
Prerequisites
We need to create a relationship between AWS and GitHub, this will be a token that has permissions (AWS can leverage) for access to a repository. We have to go into GitHub and generate an access token, then we will create a secret in AWS that will contain that token so that CodePipeline/CDK can use:
- Click Settings on your GitHub profile
- Scroll all the way to the bottom the click Developer Settings option
- Choose Personal access tokens and click Generate token button
- Name the token whatever you want, "AWS Access" in my case
- Check the
repo
andadmin:repo_hook
scopes for the token - Click the Generate token button to get a string that will be the secret in AWS
- Visit Secrets Manager on the AWS Console to create a
github-token
secret for setting up link to CDK and GitHub - Click Store a new secret, then choose Other type of secret option
- Choose Plaintext and remove the content provided
- Paste your GitHub token in plain text
- Click on Next then fill out all options. Make sure to set secret name as
github-token
otherwise you will get errors during deployment step.
Step 1: Initialize a CDK project
Navigate to the directory that you want to create the project and run the below commands:
The CDK Pipelines construct library does not work with CDK version 2.9.0 as there seems to be compatibility issues. After we have successfully initialized the project, we need to check the version we are using in the package.json file:
- Modify the aws-cdk and aws-cdk-lib dependencies to version 2.8.0
- Update project's dependencies by running
npm install
in the root directory
At the root level of the application there's a bin folder, which contains your pipeline boiler plate code. Modify the file to look like this:
The code above just creates an instance of our application and stack, we are passing environment variables (AWS Account ID and Region) that we will be using for the stack. The app.synth()
just bootstraps the entire process.
Step 2: Defining CI/CD pipeline
At the root level of our project, there's a lib folder that has a cdk-cicd-pipeline-stack.ts file that basically defines our infrastructure. Lets do some modifications:
Let's go over the code above will provision in our cloud environment:
- We are using a construct library to create a
TestPipeline
for our application. - We added a synthesis shell step pointing to our GitHub repository, the source follows
gitHub('OWNER/REPO','main')
format. - The build step will install dependencies, build the application, and synthesize the infrastructure to generate a self mutating pipeline.
Step 3: Deploy CI/CD pipeline
Assuming you have setup the token/secret correctly, we can provision the pipeline in AWS. Let's go the the terminal and run cdk deploy
command, please ensure you have committed the code to GitHub already:
Everything got created successfully, let's go to CodePipeline to see the changes
Step 4: Create a Lambda stack
Go to the lib directory and create lambda-stack.ts file that defines the AWS Lambda function for our application:
Lets go over what the code will provision:
- A lambda function that takes a
stageName
that defines either test or production environment for the lambda function. This configuration can enable the function to communicate with specific resources when in a test/prod environment. - The lambda function code is stored inside the src directory, in a handler file named index. The name of the exported function is called handler.
Lets create the lambda code in src/index.ts
file:
Step 5: Setup Test & Production stages
We have provisioned a pipeline that's not currently deploying the application (lambda function). We need to create a lambda function for each stage, lets create a lib/pipeline-app-stage.ts
file that encapsulates this behaviour:
The above code snippet just creates a lambda function based on the stageName
provided when using this custom construct.
Let's update our cdk-cicd-pipeline-stack.ts to add the stages we want to deploy. Here are the changes required:
import { ManualApprovalStep } from 'aws-cdk-lib/pipelines';
import { PipelineAppStage } from './pipeline-app-stage';
// ...
const testingStage = pipeline.addStage(new PipelineAppStage(this, "test", {
env: { account: "your_account_id", region: "us-east-1" }
}));
testingStage.addPre(new ShellStep("Run Unit Tests", { commands: ['npm install', 'npm test'] }));
testingStage.addPost(new ManualApprovalStep('Manual approval before production'));
const prodStage = pipeline.addStage(new PipelineAppStage(this, "prod", {
env: { account: "your_account_id", region: "us-east-1" }
}));
Step 6: Trigger stages deployment
Now we all we have to do is to commit and push the latest changes to the repo, and the pipeline automatically reconfigures itself to add the new stages and deploys the lambda function:
The Pipeline will build again, and when it gets to the UpdatePipeline
we should see some changes (Test and Production stages). The pipeline should be on Waiting for approval step for the production deployment:
Once approved, the lambda function should be deployed to the production stage. You can also checkout the lambda function that was deployed, the configuration details will contain the stageName
for the specific function:
Summary
That was quite a lot of information shared on how to deploy CDK applications using a CI/CD pipeline. You can also view the cdk-cicd-pipeline repo on GitHub to check your code against mine.
It's also important to note that we can deploy an application to a different account and region using CDK pipeline, best practice when you have multiple stages.
To cleanup/destroy the resources, log into the AWS console of the different accounts you used, go to the AWS CloudFormation console and select and click Delete on the following stacks: CdkCicdPipelineStack, test-LambdaStack, prod-LambdaStack.