Continuous Delivery Pipeline for Amazon ECS Using Jenkins, GitHub, and Amazon ECR
How the architecture looks like
This getting started guide is intended to help you set up and configure a continuous delivery pipeline for Amazon EC2 Container Service (Amazon ECS) using Jenkins, GitHub, and the Amazon EC2 Container Registry (Amazon ECR). The pipeline builds Docker images from a GitHub repository, pushes those images to an ECR registry, creates an ECS task definition, and then uses that task definition to create a service on the ECS cluster. We use Jenkins to orchestrate the different steps in the workflow.
Prerequisites
In this project, you must have the following software components installed:
- Python — a prerequisite for the AWS CLI
- PIP — a prerequisite for the AWS CLI
- AWS CLI
- Homebrew (OS X only)
Note: Homebrew is the package manager for OS X. You will need homebrew to install jq.
- Chocolatey NuGet (Windows only) — a package manager for Windows
Note: when installing Chocolatey, you might have to launch command window as Administrator. Once you have Chocolatey installed on your machine, you can use it to install the remaining prerequisites.
- jq — a command line utility for parsing JSON output
- Git command line tools — used to clone and push files to and from GitHub
- Docker for Mac, Docker for Windows or Docker Toolbox
I am using a mac, so all the installation following will be exclusive for Mac user. For Windows user, you may go through instructions above to install required components.
Installing Homebrew
Open terminal and type in
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
.
.
.
==> Installation successful!
==> Homebrew has enabled anonymous aggregate formulae and cask analytics.
Read the analytics documentation (and how to opt-out) here:
https://docs.brew.sh/Analytics
No analytics data has been sent yet (or will be during this `install` run).
==> Homebrew is run entirely by unpaid volunteers. Please consider donating:
https://github.com/Homebrew/brew#donations
==> Next steps:
- Run `brew help` to get started
- Further documentation:
https://docs.brew.sh
Verify Homebrew installation
$ brew --version
Homebrew 2.4.16
Homebrew/homebrew-core (git revision 23bea; last commit 2020-09-04)
Homebrew/homebrew-cask (git revision 5beb1; last commit 2020-09-05)
Once you’ve installed Homebrew, insert the Homebrew directory at the top of your PATH
environment variable. You can do this by adding the following line at the bottom of your ~/.profile
file
export PATH="/usr/local/opt/python/libexec/bin:$PATH"
Installing Python3
Now, we can install Python 3:
$ brew install python
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/cask).
==> Updated Casks
session
Warning: python@3.8 3.8.5 is already installed and up-to-date
### my python was preinstalled, you may see different installation process. And it may take a while before python is fully installed
Verify is your python3 is installed
$ python3 --version
Python 3.8.5
Notes: you may set your default python as latest version by applying following code
$ unlink /usr/local/bin/python
$ ln -s /usr/local/bin/python3.8 /usr/local/bin/python
Installing pip
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 1840k 100 1840k 0 0 4672k 0 --:--:-- --:--:-- --:--:-- 4660k$ python get-pip.py
Defaulting to user installation because normal site-packages is not writeable
Collecting pip
Downloading pip-20.2.2-py2.py3-none-any.whl (1.5 MB)
|████████████████████████████████| 1.5 MB 2.7 MB/s
Successfully installed pip-20.2.2
Verify pip installation
$ pip -V
pip 20.2.2 from /usr/local/lib/python3.8/site-packages/pip (python 3.8)
Installing AWS CLI
Visit here and download Mac packer
To verify your aws cli installation
$ aws --version
aws-cli/2.0.46 Python/3.7.4 Darwin/19.6.0 exe/x86_64
Installing jq
$ brew install jq
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 2 taps (homebrew/core and homebrew/cask).
==> Updated Formulae
Updated 45 formulae.
==> New Casks
gotomeeting koodo-reader phd2
==> Updated Casks
aleph-one duo-connect pritunl
amd-power-gadget fm3-edit profind
appium free-download-manager screenflick
aspera-connect gns3 signal
aviatrix-vpn-client hydrogen swiftformat-for-xcode
axe-edit-iii jaxx-liberty universal-media-server
balenaetcher joplin vassal
betterzip keepingyouawake virtualbox
blizz kext-updater virtualbox-extension-pack
boostnote marathon vnote
burp-suite marathon-infinity xlink-kai
chromium marathon2 yinxiangbiji
cookie netron
digikam openphone
==> Deleted Casks
ghost
==> Downloading https://homebrew.bintray.com/bottles/oniguruma-6.9.5-rev1.catali
==> Downloading from https://d29vzk4ow07wi7.cloudfront.net/15241cccbb727a11200b6
######################################################################## 100.0%
==> Downloading https://homebrew.bintray.com/bottles/jq-1.6.catalina.bottle.1.ta
==> Downloading from https://d29vzk4ow07wi7.cloudfront.net/820a3c85fcbb63088b160
######################################################################## 100.0%
==> Installing dependencies for jq: oniguruma
==> Installing jq dependency: oniguruma
==> Pouring oniguruma-6.9.5-rev1.catalina.bottle.tar.gz
🍺 /usr/local/Cellar/oniguruma/6.9.5-rev1: 16 files, 1.3MB
==> Installing jq
==> Pouring jq-1.6.catalina.bottle.1.tar.gz
🍺 /usr/local/Cellar/jq/1.6: 18 files, 1MB
To verify jq installation
$ jq --version
jq-1.6
Step 1: Build an ECS Cluster
1 Create an AWS access key and secret key by opening a terminal window, and then typing the following:
$ aws iam create-access-key --user-name <user_name>
<user_name>
is an IAM user with AdministratorAccess.
$ aws iam create-access-key --user-name adminuser
{
"AccessKey": {
"UserName": "adminuser",
"AccessKeyId": "AKIAXXXXXXXXDOWD",
"Status": "Active",
"SecretAccessKey": "etjWNQPyXXXXXXXXXXXXyf3ul",
"CreateDate": "2020-09-05T13:42:16+00:00"
}
}
Notes: You may have only limit of 2 for AcceessKeysPerUser
An error occurred (LimitExceeded) when calling the CreateAccessKey operation: Cannot exceed quota for AccessKeysPerUser: 2
2 Copy and paste the output from the previous command to a text file
Note: AdministratorAccess is a managed policy that allows attached entities to perform all actions against all resources. Although we’re using it here for convenience, you should remove the AdministratorAccess policy should be removed from your IAM user when it’s no longer needed.
3 Create an AWS profile on your local machine. From a command prompt, type:
$ aws configure
AWS Access Key ID [****************WX4W]: AKIAXXXXXXDOWD
AWS Secret Access Key [****************XL2m]: etjWNQXXXXXXXXyf3ul
Default region name [us-east-1]: us-east-1
Default output format [json]: json
At the prompts, paste your aws access key ID, aws secret key ID, the preferred region (us-east-1), and json as the output format.
4 Create an SSH key in the us-east-1 region. We will use this SSH key to login to the Jenkins server to retrieve the administrator password.
(1) Open the EC2 console
(2) Under the Networking & Security, choose Key Pairs
(3) Choose Create Key Pair
(4) Assign a name to the key pair by typing a name in the Key pair name field, then click the Create button
A file will be downloaded to your default download directory
5 (OS X only) Change the working directory to your download directory and change permission so only the current logged in user can read it. <file_name>
is the name of the .pem file you downloaded earlier:
$ cd Downloads/
$ chmod 400 jenkinskeypair.pem
Verifying file privilege
$ ls -lah jenkinskeypair.pem
-r--------@ 1 paulzhao staff 1.6K 6 Sep 10:28 jenkinskeypair.pem
6 Clone the git repository that contains the CloudFormation templates to create the infrastructure we’ll use to build our pipeline.
(1) Open a command prompt and clone the Github repository that has the template.
$ git clone https://github.com/jicowan/hello-world
(2) Change the working directory to the directory that was created when you cloned the repository. At the command prompt, type or paste the following. Where <key_name>
is the name of an SSH key in the region where you're creating the ECS cluster:
$ cd hello-world/
$ aws cloudformation create-stack --template-body file://ecs-cluster.template --stack-name EcsClusterStack --capabilities CAPABILITY_IAM --tags Key=Name,Value=ECS --region us-west-2 --parameters ParameterKey=KeyName,ParameterValue=<key_name> ParameterKey=EcsCluster,ParameterValue=getting-started ParameterKey=AsgMaxSize,ParameterValue=2
Note: Do not proceed to the next step until the Stack Status shows CREATE_COMPLETE. To get the status of the stack at a command prompt, type aws cloudformation describe-stacks --stack-name EcsClusterStack --query 'Stacks[*].[StackId, StackStatus]'
$ aws cloudformation describe-stacks --stack-name EcsClusterStack --query 'Stacks[*].[StackId, StackStatus]'
[
[
"arn:aws:cloudformation:us-east-1:464392538707:stack/EcsClusterStack/275572b0-f051-11ea-8fa5-0a28f59d0ab4",
"CREATE_COMPLETE"
]
]
You can double check in AWS console
Step 2: Create a Jenkins Server
Jenkins is a popular server for implementing continuous integration and continuous delivery pipelines. In this project, you’ll use Jenkins to build a Docker image from a Dockerfile, push that image to the Amazon ECR registry that you created earlier, and create a task definition for your container. Finally, you’ll deploy and update a service running on your ECS cluster.
1 Change the current working directory to the root of the cloned repository, and then execute the following command:
$ aws cloudformation create-stack --template-body file://ecs-jenkins-demo.template --stack-name JenkinsStack --capabilities CAPABILITY_IAM --tags Key=Name,Value=Jenkins --region us-east-1 --parameters ParameterKey=EcsStackName,ParameterValue=EcsClusterStack
{
"StackId": "arn:aws:cloudformation:us-east-1:464392538707:stack/JenkinsStack/baa65970-f052-11ea-8033-0e28043c5c55"
}
Note: Do not proceed to the next step until the Stack Status shows CREATE_COMPLETE. To get the status of the stack type aws cloudformation describe-stacks --stack-name JenkinsStack --query 'Stacks[*].[StackId, StackStatus]'
at a command prompt.
$ aws cloudformation describe-stacks --stack-name JenkinsStack --query 'Stacks[*].[StackId, StackStatus]'
[
[
"arn:aws:cloudformation:us-east-1:464392538707:stack/JenkinsStack/baa65970-f052-11ea-8033-0e28043c5c55",
"CREATE_COMPLETE"
]
]
2 Retrieve the public hostname of the Jenkins server. Open a terminal window and type the following command:
$ aws ec2 describe-instances --filters "Name=tag-value","Values=JenkinsStack" | jq .Reservations[].Instances[].PublicDnsName
3 Copy the public hostname
"ec2-3-86-189-99.compute-1.amazonaws.com"
4 SSH into the instance, and then copy the temp password from /var/lib/jenkins/secrets/initialAdminPassword
.
(1) On OS X, use the following command:
$ ssh -i <full_path_to_key_file> ec2-user@<public_hostname>
Last login: Sun Sep 6 15:19:49 2020 from 99.225.158.153
__| __|_ )
_| ( / Amazon Linux AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-ami/2017.09-release-notes/
26 package(s) needed for security, out of 64 available
Run "sudo yum update" to apply all updates.
Amazon Linux version 2018.03 is available.
For Windows instructions, see Connecting to your Linux Instance from Windows Using PuTTY
(2) Run the following command:
$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword
ff5badXXXXXXXX470a211
(3) Copy the output and logout of the instance by typing the following command:
$ logout
Step 3: Create an ECR Registry
Amazon ECR is a private Docker container registry that you’ll use to store your container images. For this example, we’ll create a repository named hello-world in the us-east-1 (N. Virginia) region.
1 Create a ECR registry by running the following command:
$ aws ecr create-repository --repository-name hello-world --region us-east-1
{
"repository": {
"repositoryArn": "arn:aws:ecr:us-east-1:464392538707:repository/hello-world",
"registryId": "464392538707",
"repositoryName": "hello-world",
"repositoryUri": "464392538707.dkr.ecr.us-east-1.amazonaws.com/hello-world",
"createdAt": "2020-09-06T11:26:43-04:00",
"imageTagMutability": "MUTABLE",
"imageScanningConfiguration": {
"scanOnPush": false
},
"encryptionConfiguration": {
"encryptionType": "AES256"
}
}
}
2 Record the value of the URL of this repository because you will need it later.
464392538707.dkr.ecr.us-east-1.amazonaws.com/hello-world
3 Verify that you can log in to the repository you created (optional).
Because the Docker CLI doesn’t support the standard AWS authentication methods, you need to authenticate the Docker client in another way so ECR knows who is trying to push an image. Using the AWS CLI, you generate an authorization token that you pass into the Docker login command.
- If you’re using OS X, type:
$(aws ecr get-login)
Notes: If you’re using AWS CLI 2, aws ecr get-login-password
replaces aws ecr get-login
- If you’re running Windows, type:
aws ecr get-login | cmd
$ aws ecr get-login-password \
> --region us-east-1 | docker login \
> --username AWS \
> --password-stdin 464392538707.dkr.ecr.us-east-1.amazonaws.com
Login Succeeded
Note: This command will not succeed unless you have the Docker client tools installed on your machine and the Docker Virtual Machine is running. The output should say Login Succeeded.
Step 4: Install Jenkins in AWS EC2
1 Login to AWS EC2 Server
$ ssh -i ~/Downloads/jenkinskeypair.pem ec2-user@ec2-3-86-189-99.compute-1.amazonaws.com
Last login: Sun Sep 6 17:45:59 2020 from 99.225.158.153
__| __|_ )
_| ( / Amazon Linux AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-ami/2017.09-release-notes/
26 package(s) needed for security, out of 64 available
Run "sudo yum update" to apply all updates.
Amazon Linux version 2018.03 is available.
2 To ensure that your software packages are up to date on your instance, use the following command to perform a quick software update:
$ sudo yum update –y
Loaded plugins: priorities, update-motd, upgrade-helper
amzn-main | 2.1 kB 00:00
amzn-updates | 3.8 kB 00:00
No Match for argument: –y
No packages marked for update
3 Add the Jenkins repo using the following command:
$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
--2020-09-06 18:11:51-- http://pkg.jenkins-ci.org/redhat/jenkins.repo
Resolving pkg.jenkins-ci.org (pkg.jenkins-ci.org)... 52.202.51.185
Connecting to pkg.jenkins-ci.org (pkg.jenkins-ci.org)|52.202.51.185|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 71
Saving to: ‘/etc/yum.repos.d/jenkins.repo’
/etc/yum.repos.d/je 100%[===================>] 71 --.-KB/s in 0s
2020-09-06 18:11:51 (17.0 MB/s) - ‘/etc/yum.repos.d/jenkins.repo’ saved [71/71]
4 Import a key file from Jenkins-CI to enable installation from the package:
$ sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key
5 Install Jenkins:
$ sudo yum install jenkins -y
Loaded plugins: priorities, update-motd, upgrade-helper
Resolving Dependencies
--> Running transaction check
---> Package jenkins.noarch 0:2.255-1.1 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
jenkins noarch 2.255-1.1 jenkins 64 M
Transaction Summary
================================================================================
Install 1 Package
Total size: 64 M
Installed size: 64 M
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : jenkins-2.255-1.1.noarch 1/1
Verifying : jenkins-2.255-1.1.noarch 1/1
Installed:
jenkins.noarch 0:2.255-1.1
Complete!
6 Start Jenkins as a service:
$ sudo service jenkins start
Starting Jenkins [ OK ]
Step 5: Configure Jenkins First Run
1 Paste the public hostname of the Jenkins server from step 2.3 into a browser.
2 Paste the password you copied from the /var/lib/jenkins/secrets
directory from Step 2: Create a Jenkins Server (step 2.4) in the password field, and then choose Next.
3 Choose Install suggested plugins.
4 Create your first admin user by providing the following information:
5 Instance Configuration page
6 Jenkins is ready!
7 Jenkins interface
8 Install Jenkins plugins.
In this step, you install the Amazon ECR plugin and the Cloudbees Docker build and publish plugin. You use the Amazon ECR plugin to push Docker images to an Amazon ECR repository. You use the Cloudbees Docker build and publish plugin to build Docker images.
(1) Log in to Jenkins with your username and password.
(2) On the main dashboard, click Manage Jenkins.
(3) Choose the Manage plugins tab.
(4) Choose the Available tab.
(5) Select the Cloudbees Docker build and publish plugin and the Amazon ECR plugin.
(6) Choose Download now and install after restart.
(7) Choose Restart Jenkins when installation is complete and no jobs are running.
Step 6: Create and import SSH keys for Github
In this step, you create an SSH key and import it into GitHub so we can login into Github over SSH.
1 If you’re running OS X, open terminal window. If you’re running Windows open a Git Bash shell. Run the following command:
$ ssh-keygen -t rsa -b 4069 -C your_email@company.comEnter file in which to save the key (/Users/paulzhao/.ssh/id_rsa):Your identification has been saved in /Users/paulzhao/.ssh/id_rsa.
Your public key has been saved in /Users/paulzhao/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:4uCnqjOEX/o21KiquDAYDtuxr4v4vIPYjdu1gGA5p8c your_email@company.com
The key's randomart image is:
+---[RSA 4069]----+
| |
| |
| |
| . |
|=+...o. S |
|**==+o.. |
|B*+Eo + |
|O+Oo+= . |
|XBOX=.. |
+----[SHA256]-----+
2 Accept the file location and type a passphrase.
3 Ensure ssh-agent
is enabled by running the following command:
$ eval "$(ssh-agent -s)"
Agent pid 64094
4 Add the SSH key to agent:
$ ssh-add ~/.ssh/id_rsa
Identity added: /Users/paulzhao/.ssh/id_rsa (your_email@company.com)
Note: If you already have a key called id_rsa, choose another name.
5 Copy the contents of the id_rsa.pub
file to the clipboard. On OS X you can use the following command:
$ pbcopy < ~/.ssh/id_rsa.pub
Notes: This command enables you to copy the credentials. (Like command + c)
6 Login to Github. If you don't have a Github account, follow the instructions posted here, https://help.github.com/articles/signing-up-for-a-new-github-account/.
(1) In the top right corner of any page, choose your profile picture, then choose settings.
(2) In the user settings sidebar, choose SSH and GPG keys.
(3) Choose New SSH key or Add SSH key.
(4) Type a title for the key.
(5) Paste your key in the key field.
(6) Click Add SSH key.
(7) If prompted, confirm your GitHub password.
Step 7: Create a Github Repository
In this step you create a repository to store your dockerfile and all its dependencies.
1 Create a repository
2 Push code to your repository
(1) change to the root of hello-world
directory
$ cd hello-world/
(2) Delete the hidden .git directory If you’re running OSX, type rm -fR .git
. Otherwise, type del /S /F /Q .git
$ rm -fR .git
(3) Reinitialize the repository and push the contents to your new GitHub repository using SSH by running the following command:
$ git init
Initialized empty Git repository in /Users/paulzhao/hello-world/.git/
(4) Stage your files:
$ git add .
$ git commit -m "Initial commit"
[master (root-commit) b0a167b] Initial commit
14 files changed, 2517 insertions(+)
create mode 100644 Dockerfile
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100644 docker-cloud.yml
create mode 100644 docker-compose.yml
create mode 100644 ecs-cluster.template
create mode 100644 ecs-jenkins-demo.template
create mode 100644 ecs-jenkins-demo.template.old
create mode 100644 newfile.txt
create mode 100644 nginx.conf
create mode 100644 php-fpm.conf
create mode 100644 taskdef.json
create mode 100644 www/index.php
create mode 100644 www/logo.png
(5) Set your remote origin.
If you are using SSH, run the following command:
$ git remote add origin 'git@github.com:<your_repo>.git'
If you are using HTTPS, run the following command:
$ git remote add origin 'https://github.com/<your_repo>.git'
e.g.
$ git remote add origin 'https://github.com/lightninglife/jenkinsproject.git'
Note: If you created the SSH key for GitHub on your machine, you can use either method. The HTTPS method requires that you to enter your GitHub username and password at the prompts.
Push your code to GitHub by running the following command:
$ git push -u origin master
Username for 'https://github.com/lightninglife/jenkinsproject.git': lightninglife
Password for 'https://lightninglife@github.com/lightninglife/jenkinsproject.git':
Enumerating objects: 17, done.
Counting objects: 100% (17/17), done.
Delta compression using up to 8 threads
Compressing objects: 100% (15/15), done.
Writing objects: 100% (17/17), 33.36 KiB | 6.67 MiB/s, done.
Total 17 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), done.
To https://github.com/lightninglife/jenkinsproject.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
This project includes a file called taskdef.json. You can view it in the GitHub interface or with a text editor on your local machine. This file is the JSON representation of your ECS task definition.
Note: You must supply values for the family and name keys. These are used used later in the Jenkins execution scripts. You have to set the value of the image key to %REPOSITORY_URI%:v_%BUILD_NUMBER%
. You will use this mechanism to add the Jenkins build number as a tag to the Docker image.
3 Enable webhooks on your repo so Jenkins is notified when files are pushed
(1) In GitHub repo, click settings
(2) Under settings, select Webhooks
(3) Add webhook
(4) Check pushes and pull requests under let me sleect individual events to trigger this webhook
(5) Check active box before click add webhook
(6) Webhook added successfully
Step 8: Grant permissions to Jenkins to gain access to docker
1 Login to your AWS console and find EC2 instance named Jenkins that we previously provisioned
2 Click connect to connect to the instance from your Mac terminal
3 Type in following command line to access to Jenkins instance
$ ssh -i "jenkinskeypair.pem" ec2-user@ec2-3-86-189-99.compute-1.amazonaws.com
Last login: Tue Sep 8 12:20:40 2020 from 99.225.158.153
__| __|_ )
_| ( / Amazon Linux AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-ami/2017.09-release-notes/
26 package(s) needed for security, out of 64 available
Run "sudo yum update" to apply all updates.
Amazon Linux version 2018.03 is available.
4 Grant permissions to Jenkins to gain access to docker
$ sudo groupadd docker
$ sudo usermod -aG docker $USER
$ chmod 777 /var/run/docker.sock
Step 9: Configure Jenkins
In this step you will create a Jenkins Freestyle project to automate the tasks in your pipeline.
In this step you will create a Jenkins Freestyle project to automate the tasks in your pipeline.
1 Create a freestyle project in Jenkins
2 Under source code management, select git and type the name of your GitHub repository, https://github.com/<repo>.git
. Also GitHub credentials need to be added as well with */master provided for branch
3 Under build triggers, select Github hook trigger for GITScm polling in order to connect with Github webhook (as soon as we push our script from local environment to Github, jenkins will be triggered sponteneously). Besides, delete workspace before build starts checked under build environment
4 Select execute shell under add a build step. In the command field, type or paste the following text:
#!/bin/bash
set -x
sudo groupadd docker
sudo usermod -aG docker $USER
chmod 777 /var/run/docker.sock
PATH=$PATH:/usr/local/bin; export PATH
REGION=us-east-1
ECR_REPO="464392538707.dkr.ecr.us-east-1.amazonaws.com/hello-world"
#$(aws ecr get-login --region ${REGION})
aws ecr get-login --no-include-email --region ${REGION}>>login.sh
sh login.sh
5 Select docker build and publish under add a build step. In the repository name field enter the name of your ECR repository. In the tag field, enter v_$BUILD_NUMBER
In the Docker registry URL, type the URL of your Docker registry. Use only the fully qualified domain name (FQDN) of the ECR repository you created earlier in Step 3: Create an ECR Registry. http://464392538707.dkr.ecr.us-east-1.amazonaws.com/hello-world
6 Select execute shell under add a build step. In the command field, type or paste the following text:
#!/bin/bash
set -x
#ConstantsPATH=$PATH:/usr/local/bin; export PATH
REGION=us-east-1
REPOSITORY_NAME=hello-world
CLUSTER=getting-started
FAMILY=`sed -n 's/.*"family": "\(.*\)",/\1/p' taskdef.json`
NAME=`sed -n 's/.*"name": "\(.*\)",/\1/p' taskdef.json`
SERVICE_NAME=${NAME}-service
env
aws configure list
echo $HOME#Store the repositoryUri as a variable
REPOSITORY_URI=`aws ecr describe-repositories --repository-names ${REPOSITORY_NAME} --region ${REGION} | jq .repositories[].repositoryUri | tr -d '"'`#Replace the build number and respository URI placeholders with the constants above
sed -e "s;%BUILD_NUMBER%;${BUILD_NUMBER};g" -e "s;%REPOSITORY_URI%;${REPOSITORY_URI};g" taskdef.json > ${NAME}-v_${BUILD_NUMBER}.json#Register the task definition in the repository
aws ecs register-task-definition --family ${FAMILY} --cli-input-json file://${WORKSPACE}/${NAME}-v_${BUILD_NUMBER}.json --region ${REGION}
SERVICES=`aws ecs describe-services --services ${SERVICE_NAME} --cluster ${CLUSTER} --region ${REGION} | jq .failures[]`#Get latest revision
REVISION=`aws ecs describe-task-definition --task-definition ${NAME} --region ${REGION} | jq .taskDefinition.revision`#Create or update service
if [ "$SERVICES" == "" ]; then
echo "entered existing service"
DESIRED_COUNT=`aws ecs describe-services --services ${SERVICE_NAME} --cluster ${CLUSTER} --region ${REGION} | jq .services[].desiredCount`
if [ ${DESIRED_COUNT} = "0" ]; then
DESIRED_COUNT="1"
fi
aws ecs update-service --cluster ${CLUSTER} --region ${REGION} --service ${SERVICE_NAME} --task-definition ${FAMILY}:${REVISION} --desired-count ${DESIRED_COUNT}
else
echo "entered new service"
aws ecs create-service --service-name ${SERVICE_NAME} --desired-count 1 --task-definition ${FAMILY} --cluster ${CLUSTER} --region ${REGION}
fi
7 Now we’re almost there
Before we make it, make sure you have your AWS credentials in your local machine
Firstly, check out config
$ ~/.aws/config
config
file shows below
[default]
region = us-east-1
output = json
Secondly, check out credentials
[default]
aws_access_key_id = AKIAWYH7TZJJ34OXDOWD
aws_secret_access_key = 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
If you don’t have aws credentials configured, please type in following texts to configure it
$ aws configure
Step 10: Moment of truth
1 Type following git command to push it to Github
$ git add .
$ git commit -m "initial commit"
[master 545bde6] initial commit
1 file changed, 0 insertions(+), 0 deletions(-)
rename READ.md => README.md (100%)
$ git push
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 232 bytes | 232.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/lightninglife/jenkinsproject.git
63a9b85..545bde6 master -> master
Notes: In case you did not set up your git remote, please following texts to set it up
$ git remote add my_awesome_new_remote_repo git@git.assembla.com:portfolio/space.space_name.git
my_awesome_new_remote_repo
: name of the repo
git@git.assembla.com:portfolio/space.spacee_name.git
: your GitHub repo
Step 11: Glory to be
1 Let me check out our Jenkins build
2 Check out in AWS console
(1) Log in to the AWS Management Console
(2) Under compute, choose EC2 Container Service.
(3) Choose the name of the cluster your created earlier, for example, getting-started
(4) On the services tab, choose the name of the service your created, for example, hello-world-service
(5) On the task tab, choose the RUNNING task
(6) Under Containers, click on the twisty next to the container name
(7) Under the Container Instance, choose the IP address in the External Link column
Voila!
Conclusion:
To recap our project, it’s vital to reiterate our insfrastructure using Jenkins as the CI/CD tools. As push our script from our local environment (in my case, mac) to Github, Jenkins will be triggered to push script from Github to AWS ECR registry, then ECS task difinition starts to build up our ECS cluster.
At the very beginning of this project, we went through installations, it’s tedious and dry, but it’s essential to install tools required before we even get started to build up our project.
Then, we moved on to accomplish 10 steps including
Step 1: Build an ECS Cluster
Step 2: Create a Jenkins Server
Step 3: Create an ECR Registry
Step 4: Install Jenkins in AWS EC2
Step 5: Configure Jenkins First Run
Step 6: Create and import SSH keys for Github
Step 7: Create a Github Repository
Step 8: Grant permissions to Jenkins to gain access to docker
Step 9: Configure Jenkins
Step 10: Moment of truth
In the end, I’d like to share a little bit of my troubleshooting experience in regards to this project.
One of the biggest challenges I faced in this project was this error below
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.40/auth: dial unix /var/run/docker.sock: connect: permission denied
I did plenty of research on this error, and attempted more than 30 times in Jenkins. I thought it was permission on my local machine. Ultimately, I figured out it was rather AWS EC2 instance needs to have permission to allow jenkins to have access to docker. This mystery was then resolved in no time.
From this troubleshooting, I learned we must be clear about the infrastructure we were utilizing. Say, in this case, the jenkins is not built locally but in AWS EC2. Therefore, permission should be given to jenkins in AWS EC2.
Last but not least, this jenkins project can be used as a template to deploy any scripting to ECS.