In my previous post we deployed the Docker example voting app using the AWS Copilot CLI. We created a test environment and deployed the individual components. In this post I will show you how to implement a CI/CD pipeline in AWS CodeDeploy, using the Copilot CLI.

Step 1 - Creating a deployment pipeline

Copilot can easily create CI/CD pipelines using AWS CodePipeline and AWS CodeBuild. But before we can do that we first need to give AWS CodePipeline access to our GitHub repository. Go to the settings page of your GitHub profile and create a personal access token. AWS CodePipeline will need that token to clone the repository from GitHub. When you create the token, make sure to select the repo scope, if your repository is private. Once you have generated your token, run the following command to create the pipeline configuration. You can omit --git-branch option, but since I’m using a separate branch for this blog post I need to specify it.

$ copilot pipeline init \
 --github-url \
 --github-access-token <github-token> \
 --git-branch copilot/part-2 \
 --environments "test"

Copilot CLI

As you can see, Copilot has now created two new files, copilot/pipeline.yml and copilot/buildspec.yml. The copilot/pipeline.yml-file is a Copilot manifest with configuration options for the pipeline. The copilot/buildspec.yml-file is used by AWS CodePipeline and contains all the steps needed to deploy the application. If you want to run some tests before or after the build, you can configure the required steps in copilot/buildspec.yml. After reviewing the files, commit and push them to your repository.

$ git add copilot/buildspec.yml
$ git add copilot/pipeline.yml
$ git commit -m "Add initial pipeline definition"
[copilot/part-2 8371964] Add initial pipeline definition
 2 files changed, 122 insertions(+)
 create mode 100644 copilot/buildspec.yml
 create mode 100644 copilot/pipeline.yml
$ git push origin copilot/part-2
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 8 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 2.50 KiB | 2.50 MiB/s, done.
Total 5 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
   e73d697..8371964  copilot/part-2 -> copilot/part-2

Once the files are committed and pushed to your repository, run the following command to create and execute the pipeline.

$ copilot pipeline update --yes

Copilot CLI

You can now view the status of the pipeline by running:

$ copilot pipeline status

Copilot CLI Or, if you prefer a more visual overview, open up the AWS CodePipeline Console.

AWS CodePipeline

You can now update the application code to your liking. When ready, push the changes to the repository, and CodePipeline will automatically run the build and deployment to the test environment.

Step 2 - Creating additional environments

As the final step in this post I’m now going to create an additional environment, which will server as the production environment.

$ copilot env init -n prod --profile default --default-config

Copilot CLI

I also create an additional SSM parameter, named /voting-app/prod/POSTGRES_PASSWORD, as I don’t want to use the same passwords for the database across the environments.

$ aws ssm put-parameter --name /voting-app/prod/POSTGRES_PASSWORD --value supersecretpassword --type SecureString --tags Key=copilot-environment,Value=prod Key=copilot-application,Value=voting-app
    "Version": 1,
    "Tier": "Standard"

To make the various application components use the right secret, we need to update the manifest files for our vote, db, worker and result service. In the manifests files, located in the copilot folder, we need to replace the secrets section.




    count: 2
    memory: 1024
    cpu: 512

As you see, the environment section allows you to set different options for specific environments. As shown in the example above, the application will have 2 containers running in production, both configured with more CPU and memory and it will reference different SSM parameters, depending on the environment. Futhermore, the test environment will use the defaults specified in the file.

When you are done updating the manifest files, it’s time to add the production environment to our deployment pipeline. Note that at this point we still haven’t deployed a single service to the production environment.

Open the copilot/pipeline.yml-file and add the prod environment to the stages section:

# The deployment section defines the order the pipeline will deploy
# to your environments.
    - name: test
    - name: prod

Save the file, commit and push to your repository.

$ git add copilot/db/manifest.yml
$ git add copilot/result/manifest.yml
$ git add copilot/vote/manifest.yml
$ git add copilot/worker/manifest.yml
$ git add copilot/pipeline.yml
$ git commit -m "Add production environment"
[copilot/part-2 26c1ace] Add production environment
 5 files changed, 38 insertions(+), 9 deletions(-)
$ git push origin copilot/part-2
Enter passphrase for key '/Users/maartenbruntink/.ssh/id_rsa':
Enumerating objects: 23, done.
Counting objects: 100% (23/23), done.
Delta compression using up to 8 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (12/12), 1.18 KiB | 1.18 MiB/s, done.
Total 12 (delta 6), reused 0 (delta 0)
remote: Resolving deltas: 100% (6/6), completed with 5 local objects.
   8371964..26c1ace  copilot/part-2 -> copilot/part-2

Finally, to update the pipeline in AWS CodePipeline run:

$ copilot pipeline update --yes

Copilot CLI

AWS CodePipeline will now deploy the application to production. CodePipeline


In this post I have shown you how you can create a deployment pipeline in AWS CodePipeline by running a few simple AWS Copilot commands. Refer to the copilot/part-2 branch in my repository to see the changes I’ve made compared to the previous post. To clean up all the deployed resources and save some money run copilot app delete. In an upcoming post I want to explore how to integrate other AWS services in the application, so stay stuned for more AWS Copilot posts!

Thank you for reading! I hope you enjoyed this post.

Photo by Franz Harvin Aceituna on Unsplash

comments powered by Disqus