Accelerate multi-environment application deployment with Amazon CodeCatalyst

Andrea Giacobbe
Storm Reply
Published in
9 min readMay 2, 2024

Abstract

In this blog post, we deep dive into the Amazon CodeCatalyst capabilities in a real scenario where a developer deploys an application in two environments in AWS.

Amazon CodeCatalyst is an integrated software development service for helping developers to build, deploy and scale applications on AWS, therefore adhering to organization best practices using shared blueprints, Git repositories and CI/CD workflows.

In the previous article, Building a Serverless Application with GenAI in AWS [1], we developed and demonstrated how easy is to create a serverless application using Amazon CodeWhisperer, a GenAI AWS tool, and deploying it into an AWS account with Amazon CodeCatalyst that supports the developer to streamline the deployment phase.

This time will be presented how to configure the Amazon CodeCatalyst project to:

  • Allow contributors to collaborate on the project
  • Deploy the application into multiple environments on AWS. The developer (contributor) can only develop using the feature branches, while the deployment in the different environments is handled in the main branch. A manual approval is required to release the application in production, using the recent feature introduced here: Workflow approvals for Amazon CodeCatalyst.

Hands-On

For this demonstration, the Amazon CodeCatalyst space has been set up using AWS Builder ID users. For more details on how to set up the CodeCatalyst space using AWS Builder ID users or identity federation using SSO users and groups in the IAM Identity Center, please read the AWS guide Setting up CodeCatalyst.

Steps:

  1. Creating a development environment in CodeCatalyst
  2. Modifying CodeCatalyst project settings to deploy the application in the production environment
  3. Creating a feature branch and modifying the repository files
  4. Deploying the application in multiple environments in AWS
  5. Clean up
  6. Conclusion

NB: During the following demo we are assuming that CodeCatalyst environment creation and project settings are executed by the project administrator. The contributor will then create the feature branch, make some changes in it and merge them to the main branch to deploy the application to the development and production environment in AWS.

Prerequisites

To follow along with this demonstration, you will need to:

  • Have an AWS Builder ID for signing in to CodeCatalyst
  • Have a CodeCatalyst space created (e.g., blogpost-space) and a space administrator role assigned to you
  • Set up the CodeCatalyst project (e.g., my-sam-project) as shown in the article [1], in particular:
    - Have an AWS account associated with CodeCatalyst space (AWS account connection)
    - Configure the IAM roles and IAM policies used in the CodeCatalyst workflow (e.g., roles test-project-build-role and test-project-deploy-role)
    -
    Use the CodeCatalyst blueprint Serverless application model (SAM) API
    -
    Modify the SAM template template.yaml and the Lambda function SamLambda/hello_world/app.py
  • Invite another user to join the CodeCatalyst project

Make sure the workflow .codecatalyst/workflows/build-and-release.yaml within the main branch of the repository my-sam-project, which is provided by the blueprint and configured during the demo in the article [1], is triggered by a PUSH action to the main branch and deploys to the production environment default_environment, as shown below.

NB: If necessary, make sure to remove the CloudFormation stack as a result of the previous article [1], to avoid any conflict.

Name: build-and-release
...
Triggers:
- Type: PUSH
Branches:
- main
...
Actions:
build_for_default_environment:
...
Environment:
Name: default_environment
Connections:
- Name: "****"
Role: test-project-build-role
deploy_to_default_environment:
...
Environment:
Name: default_environment
Connections:
- Name: "****"
Role: test-project-deploy-role
...

Creating a development environment in CodeCatalyst

A CodeCatalyst environment is where code is deployed to and is configured to be associated with an AWS account using AWS account connections. To get further details about the Amazon CodeCatalyst environment, please consult the AWS guide Working with environments.

As project administrator, in CodeCatalyst, select the project my-sam-project and navigate to CI/CD>Environments and then click on Create environment. Configure the development environment as shown below.

NB: To create the AWS account connection follow this AWS guide Adding an AWS account to a space.

For this CodeCatalyst project, there are two environments: default_environment (Production), created with the blueprint during the demo [1], and development_environment (Non-production) just created.

Modifying CodeCatalyst project settings to deploy the application in the production environment

In this section, we will modify CodeCatalyst project settings so contributors can collaborate and merge the pull requests to the main branch.

Firstly, as project administrator, modify the permissions of the contributor to permit just to merge the pull requests to the main branch. Navigate to Code>Source repositories, select the repository my-sam-project, click on More and then select Manage settings.

Then click on Edit for Branch rules, configure the branch rule as follows and click on Save.

Finally, you will invite a contributor to join the CodeCatalyst project by following the AWS Managing project members guide and making sure to assign the Contributor role to them.

NB: After changing the branch rule, the workflow on branch main could start. You can stop it.

Creating a feature branch and modifying the repository files

Once the contributor is invited to the CodeCatalyst space, first they should clone the project repository my-sam-project locally, as explained in the AWS Cloning a source repository guide. Then open it with VS Code.

In the branch main, the contributor will run the following git commands to create the feature branch feature/contributor locally.

git pull
git checkout -b feature/contributor

Then, they will make the following changes in the repository for the branch feature/contributor.

The contributor will modify the CodeCatalyst workflow build-and-release, as when a push on branch main is executed, the workflow run first deploys the application to the development and then to the production environment after an action of approval, as shown in the diagram below.

The contributor will copy the complete workflow build-and-release below into the file .codecatalyst/workflows/build-and-release.yaml in the local repository and then substitute the account connection. Despite of the previous article, for the action deploy_to_development_environment, we have changed the CloudFormation stack name to my-sam-project-development and introduced the key-value pair “env: dev” for the Parameter overrides section to identify correctly to which environment the application belongs.

Tip: To validate the syntax of the workflow, the CodeCatalyst YAML editor can be used with a temporary branch different from main, as the contributor cannot push changes directly into it.

NB: For simplicity, for this demo we will keep using the same AWS Connections properties defined in the blog post [1] to deploy in the same AWS account.

Name: build-and-release
SchemaVersion: "1.0"
Triggers:
- Type: PUSH
Branches:
- main
Compute:
Type: EC2
Fleet: Linux.x86-64.Large
Actions:
build_for_default_environment:
Identifier: aws/build@v1
Inputs:
Sources:
- WorkflowSource
Outputs:
AutoDiscoverReports:
Enabled: true
ReportNamePrefix: rpt
Artifacts:
- Name: build_result
Files:
- "**/*"
Configuration:
Steps:
- Run: . ./.codecatalyst/scripts/bootstrap.sh
- Run: . ./.codecatalyst/scripts/run-tests.sh
- Run: sam build --template-file template.yaml --use-container --build-image public.ecr.aws/sam/build-python3.9:$(sam --version | sed "s/.* //")
- Run: cd .aws-sam/build/
- Run: sam package --output-template-file packaged.yaml --resolve-s3 --template-file template.yaml --region us-west-2
Environment:
Connections:
- Role: test-project-build-role
Name: "***"
Name: default_environment
deploy_to_development_environment:
Identifier: aws/cfn-deploy@v1
Configuration:
capabilities: CAPABILITY_IAM,CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND
template: .aws-sam/build/packaged.yaml
region: us-west-2
name: my-sam-project-development
parameter-overrides: env=dev
Environment:
Connections:
- Role: test-project-deploy-role
Name: "***"
Name: development_environment
Inputs:
Artifacts:
- build_result
Sources: []
approval:
# Identifies the action. Do not modify this value.
Identifier: aws/approval@v1
Configuration:
ApprovalsRequired: 1
DependsOn:
- deploy_to_development_environment
deploy_to_default_environment:
Identifier: aws/cfn-deploy@v1
Configuration:
capabilities: CAPABILITY_IAM,CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND
no-fail-on-empty-changeset: "1"
template: .aws-sam/build/packaged.yaml
region: us-west-2
name: my-sam-project
Environment:
Connections:
- Role: test-project-deploy-role
Name: "***"
Name: default_environment
DependsOn:
- approval
Inputs:
Artifacts:
- build_result
Sources: []

Once the workflow will be committed in the branch main, it will be shown as below.

Also, the contributor will modify the SAM template template.yaml and the Lambda function SamLambda/hello_world/app.py as follows to create and access the AWS resources based on the environment you are deploying to.

#./template.yaml
...
Parameters:
env:
Type: String
Default: "prod"
...
Resources:
...
#Lambda function
SamLambdaFunction:
Type: AWS::Serverless::Function
Properties:
Environment:
Variables:
DynamoDB: !Sub '${env}-my-dynamodb-table'

#DynamoDB table
MyDynamoDBTable:
Type: AWS::Serverless::SimpleTable
Properties:
...
TableName: !Sub '${env}-my-dynamodb-table'

#IAM policy to access DynamoDB
MyDynamoDBPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
...
ManagedPolicyName: !Sub '${env}-my-dynamodb-policy'

# IAM role
SamLambdaFunctionRole:
Type: AWS::IAM::Role
Properties:
...
RoleName: !Sub '${env}-my-lambda-role'
...
#./SamLambda>hello_world>app.py
...
import os

def lambda_handler(event, context):
...
table = dynamodb.Table(os.environ['DynamoDB'])

In the terminal, the contributor will run the following commands to commit the changes to the branch feature/contributor.

git add --all
git commit -m "feature/contributor branch creation"
git push origin feature/contributor

The branch feature/contributor is now created with the changes.

Finally, the repository my-sam-project has two branches: feature/contributor with the changes and main as the default branch to deploy the application to the development and then to the production environment in AWS.

Deploying the application in multiple environments in AWS

To start the deploy of the application in both AWS environments, development and production, the contributor should merge the branch feature/contributor into main under Code>Pull requests and then click on Create pull request. They should insert the values as shown below and then click on Create.

They click on Merge to merge the pull request.

Then they select Fast forward merge and Delete the source branch after merging this pull request, as the feature branch is not a permanent branch, and then they click on Merge.

When the pull request is merged to main, the workflow build-and-release starts and deploys the application first to the development environment in AWS.

At this point, the workflow run will require the approval to deploy the application to the production environment.

NB: As you can see, users with contributor, project administrator or space administrator role can approve the gate.

As project administrator, approve the deploy to production by selecting Approve under Review decision, clicking on Submit and then clicking on Confirm.

Once the workflow run is completed, it should appear like this:

Now the application is deployed on both AWS environments and here you can find the CloudFormation stacks:

  • my-sam-project-development including the development resources
  • my-sam-project including the production resources

Test the application in both environments as done in the mentioned article [1].

Clean up

At the end of this demo, if you wish to remove the AWS resources, delete the CloudFormation stacks (making sure to empty the S3 bucket before) and delete the IAM roles used for the workflow from the IAM AWS console. To delete the CodeCatalyst project, you just need to select Delete project under Project settings of the project my-sam-project and finally confirm the deletion.

Conclusion

In conclusion, this demonstration has shown how to collaborate on a CodeCatalyst project to deploy applications across multiple environments, as commonly seen in AWS landing zones, using branch strategy and integrating it into a customizable and scalable workflow.

--

--