CI / CD with AWS and Bamboo

Our team consists of one developer and one DevOps engineer. I am responsible for deploying the application to the Amazon ECS cluster. As a CI / CD server, I use Bamboo. In this article, I will describe in detail how I deploy an application in a dev environment.





Build a Docker image


Here I follow these steps:

  • Step 1: Install and configure Docker;
  • Step 2: Configure artifacts in Bamboo;
  • Step 3: Configure Amazon ECR repository;
  • Step 4: Build the Docker image in Bamboo.

Step 1: Install and Configure Docker


First, I upgrade the server where Bamboo is installed, install the necessary packages, and set up the Docker repository. It should be noted here that I installed Bamboo on the CentOS 7 operating system. Information on installing docker on other operating systems can be found at www.docker.com .

$ sudo yum update 
$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2 
$ sudo yum-config-manager --add-repo 
https://download.docker.com/linux/centos/docker-ce.repo 

Then I install the Docker application and start the service:

$ sudo yum install docker-ce docker-ce-cli containerd.io
$ sudo systemctl enable docker 
$ sudo systemctl start docker 

Then I add the bamboo user to the Docker group:

$ sudo usermod -aG docker bamboo 
$ sudo su - bamboo 
$ docker run hello-world

If, after running these commands, docker responds with the message “Hello from Docker!”, Then this means that my installation is working correctly.

Step 2. Configure artifacts in Bamboo


Application development is underway at Grails . When compiling the application, a file with the extension war is created. This file, in Bamboo terminology, is an artifact. Configure Bamboo to use this file in subsequent tasks. To do this, I go to the Tasks tab :



And configure the Grails task, as shown below:



We see that Grails first clears the build folder, then runs the tests and finally creates a war file for the dev environment.

After that, I click the Artifacts tab and the Create artifact button :



I set the artifact as shown below:



Grails places the war file in the build / libs directory . I will tick the option Shared, since I will need this artifact later.

Now I create a deployment project and specify an artifact to use in my build plan:





I also configure the Artifact download task in the deployment project:



Thus, Bamboo is now configured to use the war file.

Step 3. Configure Amazon ECR repository


Amazon ECR is a Docker storage and management service for images. To configure, you need to open the AWS console and select ECR:



Having created the repository, I get the following address:

aws_account_id.dkr.ecr.us-east-2.amazonaws.com/onboard

After completing the configuration, here you can also find instructions on how to log in, how to download an image from the repository and upload the image to the repository.

Step 4: Build the Docker Image in Bamboo


Now I need to configure the trigger to start building the Docker image. To do this, I go to the Triggers tab and click on the Add trigger button :



Here I select the Build after successfully building the plan option so that the Docker image is collected after compiling the project.

Now we need to add the Docker image build task. To do this, go to the Tasks tab , click Add task , select the Docker type . Enter a description and select Build a Docker image from the drop-down menu. In the Repository field, enter

 aws_account_id.dkr.ecr.us-east-2.amazonaws.com/onboard:latest. 

As for the Dockerfile, it can be as shown below:

FROM openjdk:8-jre 
COPY *.war /usr/src/onboard.war 
WORKDIR /usr/src 
CMD ["/bin/bash", "-c", "java -DdataSource.url=$DATASOURCE_URL -DdataSource.username=$DATASOURCE_USERNAME -DdataSource.password=$DATASOURCE_PASSWORD -jar onboard.war"] 

When you start the application, you must specify the database. Environment variables DATASOURCE_URL, DATASOURCE_USERNAME, DATASOURCE_PASSWORD are used to transmit this information to the application, but their values ​​are set when the container starts.

This completes the setup process for assembling the Docker image with the application. The next step is to configure the download of this image to the Amazon ECR repository.



Upload image to Elastic Container Registry


You can use the Elastic Container Registry to store images collected using Bamboo. To achieve this, I follow these steps:

  • Step 1. Install Amazon ECR Docker Credential Helper
  • Step 2. Connect the IAM role to the Bamboo server
  • Step 3: Configure the Docker image boot job

Step 1. Install Amazon ECR Docker Credential Helper


To download Docker images to Amazon ECR, you must have credentials. These credentials can be obtained by running the command

aws ecr get-login

However, these credentials are only valid for 12 hours. Therefore, you can either run the above command each time before uploading the image to the ECR, or install the ECR Docker Credential Helper, which keeps temporary credentials up to date and logs in to the ECR. Follow these steps to install ECR Docker Credential Helper.

First you need to install git and then clone the github repository:

$ sudo yum install git 
$ sudo su - bamboo 
$ git clone 
https://github.com/awslabs/amazon-ecr-credential-helper.git 
$ make docker 

Then you need to put the following lines in the /home/bamboo/.docker/config.json file :

{ 
        "credsStore": "ecr-login" 
} 

And copy the compiled application to the / usr / bin directory :

$ exit 
$ sudo cp /home/bamboo/docker-credential-ecr-login /usr/bin/ 

Step 2. Connect the IAM role to the Bamboo server


In order for the Bamboo server to be able to use ECR, you need to create a role, add the AmazonEC2ContainerRegistryPowerUser policy to this role , and then attach this role to the EC2 Bamboo instance. Open the AWS console and select IAM. Next, click the Create role button , select AWS service and EC2 , as shown below:



Then click the Next: Permissions button and on the next screen we find and select the AmazonEC2ContainerRegistryPowerUser policy . After that, we finish creating the role and attach it to our Bamboo server.

Step 3: Configure the Docker image boot job


The application we built and put together a Docker image with a war file. Now you need to upload this image to the repository. To do this, I add another Docker task, this time to upload the image to the ECR repository. I go to the Tasks tab , click Add task , select the Docker type . I enter a description and select Push a Docker image to a Docker registry from the drop-down menu. I select Custom registry and enter the repository address in the Repository field . For the Authentication type, I select Use the agent's native credentials .

This completes the setup process for loading the Docker image to the Amazon ECR repository. The following steps describe the process of configuring a cluster and service to launch a container application. But before that, you need to configure the launch options for the container. This is what we will do now.



Create Amazon ECS Task Definition


Task Definition - container execution parameters are written here. Our application uses a database whose parameters are specified when the container starts, so in this section we will also create a database. I use Amazon RDS as the database , and I store the password for accessing the database in encrypted form in AWS Systems Manager Parameter Store . The following steps I follow in order to create a Task Definition:

  • Step 1. Creating a database on an Amazon RDS instance;
  • Step 2. Configuring AWS Systems Manager Parameter Store;
  • Step 3. Create Task Definition.

Step 1. Create a database on an Amazon RDS instance


Our application uses the PostgreSQL database. To create a database, open the AWS console, select the Amazon RDS service, click the Create database button , then select PostgreSQL as the database engine . On the next page, I select Dev / Test as the working environment and click Next . Then I designate DB instance identifier as onboard-dev-db , and master username as devdbadmin . Then I go to the next page to configure the VPC, subnet group, and security group. This database will be used on a private network, so for the parameter Public accessibility I chooseNo . I enter devdb in the Database name field and click the Create database button .

Step 2. Configuring AWS Systems Manager Parameter Store


I store the database password in encrypted form. To do this, open the AWS console and go to AWS Systems Manager → Shared Resources → Parameter Store → Create Parameter. I enter devdbpassword as the parameter name and select SecureString for the parameter type, then I enter the database password in the Value field .

Step 3. Create Task Definition


Amazon ECS is the cluster where container applications run. It uses Task Definition to specify execution parameters for a container application. To set such parameters, click the Create new Task Definition button . Then I select Fargate as the startup type and move on to the next step. Here I set the name as onboard-dev-taskdef . For the Task execution IAM role field parameter, select Create new role . As for the resources allocated for this application, I designate 2 GB of memory and 1 vCPU. Now you need to add container launch options. I will name the container onboard-dev-container . I will name the image name like this:

aws_account_id.dkr.ecr.us-east-2.amazonaws.com/onboard:latest . Amazon ECR Docker Credential Helper will take care of ECR ​​authentication, so I leave the Private repository authentication option unchecked. In the dev environment, the application is available on port 8080, so for the port mappings parameter I write 8080 and select the tcp protocol . Database URL parameters, username and password are passed to the container using environment variables. I set these parameters in the section Environment variables. In order to get the value of the devdbpassword parameter from the Parameter Store, I specify the type ValueFrom . The last thing I configure is Log configuration , here I selectAuto-configure CloudWatch Logs . Now the creation of Task Definition is complete.

However, the ecsTaskExecutionRole role needs a policy to get devdbpassword from the Parameter Store. To do this, go to IAM Roles and select ecsTaskExecutionRole, click Add inline policy . In this case, I am adding using a visual editor. Therefore, in the Service field I enter Systems Manager , in the Actions field - GetParameters . Then I click Add ARN for the Resources field and fill in my values:



At the end, I look at the values ​​of the parameters that are set by clicking Review policy, give it a name and finish working with the ecsTaskExecutionRole configuration.

This completes the configuration of the launch container application settings. Now you need to create an ECS cluster and service.



Create Amazon ECS Service


Our container application runs as a service in an ECS cluster. To configure, you must perform the following steps:

  • Step 1. Create an Amazon ECS cluster;
  • Step 2: Creating a Service

Step 1. Create an Amazon ECS Cluster


To create an ECS cluster, go to the AWS console and select the ECS service. Then click Create Cluster and select the Networking only cluster template . On the next page, I name the cluster as onboard-dev-cluster and complete the cluster. Now I have a Fargate based ECS cluster .

Step 2: Creating a Service


To create a service, I click on the onboard-dev-cluster link , then go to the Services tab and click the Create button . For launch type I select Fargate, for Task Definition I select onboard-dev-taskdef. In addition, I select onboard-dev-cluster in the Cluster field. In the Service name field, I write onboard-dev. I set the Number of tasks parameter to zero, since I do not want to start the application right now. I leave the Minimum healthy percent parameter values to 100, and the Maximum percent parameter to 200. For the Deployment type parameter, select Rolling updateand move on to the next step.

On the Configure Network page, for the Cluster VPC parameter, I select a previously created VPC called Development VPC . The application under development is only available on the private network, so I choose two private subnets. To configure security groups, I click the Edit button , then select Select existing security group , then the default security group and click the Save button . For the Auto-assign public IP parameter, I select Disabled . Next, for the Load balancer type parameter, I select Noneand leave the Enable service discovery integration option unchecked . Then I click Next, Next and Create service .

Now I have a service in which the number of running jobs is zero. We will configure the application launch in the next step.



Service Update


As soon as the developer updates the application code, our deployment goes through creating a Docker image, uploading it to the Elastic Container Registry, and finally launching the container application as a service in the ECS Fargate cluster. At the moment, the number of jobs running in the cluster is zero. In order for the application to start, you need to update the service, indicating the quantity equal to one. I follow these steps to achieve this:

  • Step 1. Installing the Tasks for AWS Bamboo plugin;
  • Step 2. Updating the ECS Service

Step 1. Installing the Tasks for AWS Bamboo plugin


Tasks for AWS Bamboo is a plugin that simplifies the preparation and operation of AWS resources from Bamboo build and deployment projects. To install this plugin , I go to the deployment project, click Add task , go to the Atlassian Marketplace and install Tasks for AWS (Bamboo) .

Step 2. Updating the ECS Service


Now in the deployment project, I am adding the Amazon ECS Service job . Then I write in the job description field Update Service for onBoard-dev . In the Action field, select Update Service and Force new deployment . Then I select US East (Ohio) as the launch region. Then I write in the appropriate fields ARN (Amazon Resource Name) for Task Definiton, cluster and service. In this task, I update the desired number of running tasks to one. Next, I populate the deployment configuration text box with the following values:

{ 
  "maximumPercent": 200, 
  "minimumHealthyPercent": 100 
} 

I am setting up a network without a public IP as follows:

{ 
   "awsvpcConfiguration": { 
        "assignPublicIp": "DISABLED", 
        "subnets": ["subnet-ID1", "subnet-ID2"], 
        "securityGroups": ["sg-ID"] 
    } 
} 

In the Source section for AWS Security Credentials, I select IAM Role for EC2 .

I need to be able to update ECS, so I am attaching the AmazonECS_FullAccess policy to my Bamboo EC2 instance. To do this, open the AWS console, select IAM. Then I select the role that I use for my Bamboo server. I click the Attach policies button , I find the AmazonECS_FullAccess policy, I select the checkbox on the left and finish attaching the policy.

This concludes the CI / CD setup using AWS and Bamboo. Thus, when the developer updates the application code, uploads this code to the repository, testing and assembly of the application are launched. Then the Docker image is built with the war file of the application, and this image is copied to the Amazon ECR repository. Next, in the Amazon ECS cluster, a container application is launched as a service, which updates the current application if it has not been stopped. If the application was stopped to save resources, then the application simply starts. After checking the application in the dev environment, you can stop the application by specifying the number of jobs running in the cluster to zero.

If you liked the article and have ideas for improvement, write in the comments.

Also popular now: