Setting up a build pipeline with GitlabCI and AWS ECS

45 min

Description

You were recently hired as a Junior Devops Engineer at the startup FlyEasy. They’re building a pretty cool nodejs application with docker. Now they’re thinking about automating the process as much as possible from the integration to the deployment phase. Your challenge is to build a new pipeline with GitlabCI.
The docker image will be stored in a private repository ECR and the container executed on a ECS Cluster.

Learning Objectives

Step 1 : Create an AWS Account

We need to create an AWS account for Gitlab with the required permissions to :

– Push the docker image to the private ECR repository
– Register the task definition and update the service

1. Open the IAM console, and select Add user

2.
Username : gitlabci-user

then select Programmatic access , click Next permissions

3. Add these 2 policies :

-AmazonEC2ContainerRegistryFullAccess
-AmazonEC2ContainerServiceFullAccess


and click on “Next

4. Check that you have the 2 policies attached, then select “Create user”

5. Save the Access key ID and Secret access key, we will need later to set up Gitlab.

Step 2 : Create ECS IAM Roles

First things first, let’s create 2 IAM roles, these roles will be used later.

EcsInstanceRole
EcsTaskExecutionRole

1. Open the IAM console, and select Create role

2. Select AWS service > EC2 > Next Permissions

3. Select AmazonEC2ContainerServiceforEC2Role and click on “Next

4. Name your role “EcsInstanceRole” , then click on “Create role”

Repeat the same steps (1->4) to create the second role EcsTaskExecutionRole

At step 3, select AmazonECSTaskExecutionRolePolicy

Step 3 : Create a private repository on ECR

1. Open the console Elastic Container Registry > Create repository

2. 
Repository name : nodejs-demo-app-ecs

then, Create repository

Step 4 : Create a new ECS Cluster

1. Open the Elastic Container Service, then select “Create Cluster”

2. Select EC2 Linux + Networking

3.

Cluster name: “Preproduction”
Number of instances : 1
Key pair : “Select your key pair”

4. Select an existing VPC or create a new one 

5. Select the role we’ve created earlier “EcsInstanceRole” , then click on “Next”

Step 5 : Create a task definition

1. Select Create new Task Definition

2. Select EC2

3. 

Task Definition Name : nodejs-demo-app

4. Select the 2nd role we’ve created earlier “EcsTaskExecutionRole” , then click on “Add container”

5. In the container section:

Container name: nodejs-demo-app-ecs

Image: ikubelabs/nodejs-demo-app-ecs:1.0

Memory Limits: 200

Port mappings
Host port : 80
Container port : 8080

 

6. Scroll down and add this environment variable

Key: ENVAPP
Value: STAGING

Then click on “Add”

7. Set the task size to 500

8. Scroll down and select “Create” ,

Step 6 : Create a service

1. Select “Actions > Create Service

2.

Launch Type : EC2
Cluster: Preproduction
Service name: node-demo-app-service
Number of tasks: 1
Minimum healthy percent : 0

3. Leave the options by defaulit, then “Next step”

4.  Select “None” then “Next step”

5. Leave the default option, then “Next step”

6. Select “Create Service

 

7. Back to the console, select “Tasks” tab, see the task in execution, it should be in “PENDING” state, wait until it shows “RUNNING”

Then click on the Task id to see more details

8. Scroll down and expand the container for more details

9. Open the URL to access the application

10. This webpage is displayed.

Step 7 : Add environment variables on Gitlab

1. On your Gitlab project repository , select Settings > CI/CD > Variables

2. Add these variables :

AWS_ACCESS_KEY_ID (see – Step 1)

AWS_SECRET_ACCESS_KEY (see – Step 1)

AWS_DEFAULT_REGION (default region where the application is deployed)

Step 8 : Update the task-definition.json

1. On your Gitlab project repository , Update the file task-definition.json 

2.
Replace image value with your Elasctic Container Registry URI you created earlier (Step 3)

Make sure to keep :build

3.
Replace the taskRoleArn value with the ecs task role you created earlier (Step 2)

 

Step 9 : Update the gitlab-ci.yml

1. On your Gitlab project repository , Update the file gitlab-ci.yml

image: docker:latest

variables:
  AWS_REGION: eu-central-1
  ECR_REGISTRY: 618925041282.dkr.ecr.eu-central-1.amazonaws.com
  ECR_REPO: 618925041282.dkr.ecr.eu-central-1.amazonaws.com/nodejs-demo-app-ecs
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA
  IMAGE_NAME: nodejs-demo-app-ecs
  CI_AWS_ECS_CLUSTER: Preproduction
  CI_AWS_ECS_SERVICE: nodejs-demo-app-service
  CI_AWS_ECS_TASK_DEFINITION_FILE: task-definition.json
AWS_REGION: 
the region where you set your ECR repository
ECR_REGISTRY:
the ECR default registry
ECR_REPO:
the ECR repository uri
IMAGE_TAG:
the commit id in short format

IMAGE_NAME
:
the name of your docker image

CI_AWS_ECS_CLUSTER
:
the ECS Cluster name
CI_AWS_ECS_SERVICE:
the service name
CI_AWS_ECS_TASK_DEFINITION_FILE:
the task definition file
stages:
  – Build
  – Deploy

 

services:
  – docker:dind
 

In the first section we declare the 2 stages of our pipeline : Build and Deploy
We declare services (docker:dind), as we need to access the service image of Docker during the build.

before_script:
  – apk add –no-cache curl jq py3-pip sed
  – pip3 install awscli
 

Before the execution of the script, we need to install the packages (curl, jq, py3-pip and sed)

Build:
  stage: Build
  script:
    # Login to the ecr repository
    – aws ecr get-login-password –region $AWS_REGION | docker login –username AWS –password-stdin $ECR_REGISTRY
    # Build the docker image with the Dockerfile
    – docker build -t $IMAGE_NAME:$IMAGE_TAG .
    # Tag the image, note that the image will take the commit revision (short format)
    – docker tag $IMAGE_NAME:$IMAGE_TAG $ECR_REPO:$IMAGE_TAG
    # Push the docker image to the ECR repository
    – docker push $ECR_REPO:$IMAGE_TAG
 

During the Build stage :

1. We log into the ecr erpository
2. We use the docker command to build the image
3. We tag the image (note that the image will be tagged with the commit short format id)
4. We push the tagged image to the ECR repo

Deploy:
  stage: Deploy
  script:
    #Create a new task definition for this build
    – sed -i s/build/$IMAGE_TAG/g task-definition.json
    – aws ecs register-task-definition –cli-input-json file://task-definition.json
    #Update the service with the new task definition and desired count
    – REV=$(aws ecs register-task-definition –cli-input-json file://task-definition.json | jq ‘.taskDefinition.taskDefinitionArn’)
    – aws ecs update-service –cluster $CI_AWS_ECS_CLUSTER –service $CI_AWS_ECS_SERVICE –task-definition nodejs-demo-app –desired-count 1

During the Deploy stage :

1. We create a new task definition for the build
 – We replace the chain of characters “build” by the “$IMAGE_TAG”  in the task-definition.json file
 – We register a new task definition

2. We update the service with the new task definition
– We register the new task definition, we parse the response (json ) to retrieve the task definition arn and we assign the result to the variable REV
– We update the service

2. Once completed it should this page, with the commit id and the successfull Build and Deploy stages.

3. Note that the commit id matches with the docker image tag in your ECR repo;
This might be useful if there is any issue with the deployment.

Step 10 : Test the application access

1. Back to the console, select “Tasks” tab, see the task in execution, it should be in “PENDING” state, wait until it shows “RUNNING”

Then click on the Task id to see more details

2. Scroll down and expand the container for more details

3. Open the URL to access the application

Congratulations

Enter the key to download the certificate

** To find the key you have to deploy the application first **

Protected: Certificate of completion AWS ECS
Scroll to Top