AWS EC2 CI/CD with Github Action and Docker
Run CI/CD pipeline with Github action. Let’s build your own automated deployment on EC2 with Github and Docker.
TL;DR
You would know how to do the following after reading.
-
How to build docker image and push it to docker hub with Github action.
-
How to ssh to your EC2 instance with Github action.
What is CI/CD
CI/CD(Continuous Integration and Continuous Deployment). It is a software engineering practice that aims to reduce the time between writing code and actually releasing it to users. This is achieved through automation of the build, test, and deployment process. In a CI/CD pipeline, code changes are automatically built, tested, and deployed to production.
Why Github Action
GitHub Actions is a CI/CD tool provided with GitHub. It allows us to automate tasks related to their projects, such as building code, running tests, and deploying code to production. Github provides the remote server for us to running the tasks. Github action workflows can be triggered by a variety of events, such as pushing code to a branch, opening a pull request, or a schedule.
SSH Connection to Remote Server
An SSH connection refers to the process of establishing a secure, encrypted connection to a remote machine using the SSH protocol. User could establish an SSH connection with a public key and private key pair to access the remote machine.
Hands-on
Now, let’s get start to make the thing happened! Hands-on source code could be found in this repo, you could clone it to your local machine and by yourself.
git clone https://github.com/yusianglin11010/github-action-ec2
- launch an EC2 instance
- Make sure you have docker installed on your instance
- You could follow this post for installing docker on EC2 instance
- remember to start docker service!
sudo service docker start
Generate SSH Key
- Generate ssh key pair for connection
- For this demo, we leave all ssh-keygen options with default value
- All you need is press “enter” until the key generated
ssh-keygen
- Add public key to authorized_keys
cat id_rsa.pub > authorized_keys
- Add the following content to Github secrets, you could follow this post for setting Github action secret
- ssh private key
- AWS EC2 hostname
- AWS EC2 user name
- Docker Hub user name
- Docker Hub user password
Add Github Action File
- Add the following script in ./github/workflows/workflow.yaml
name: aws-ci-cd
on:
push:
branches:
- 'main'
jobs:
CI:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and Push Image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: devinlin11010/github-action-ec2:latest
CD:
needs: docker
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Deploy in EC2
env:
PRIVATE_KEY: ${{ secrets.AWS_PRIVATE_KEY }}
HOSTNAME : ${{ secrets.AWS_HOSTNAME }}
USER_NAME : ${{ secrets.AWS_USER }}
run: |
echo "$PRIVATE_KEY" > private_key && chmod 600 private_key
ls -a
cat private_key
ssh -o StrictHostKeyChecking=no -i private_key ${USER_NAME}@${HOSTNAME} '
#Now we have got the access of EC2 and we will start the deploy
docker pull devinlin11010/github-action-ec2:latest
docker stop nginx && docker rm nginx
docker run -p 80:80 -d --name="nginx" devinlin11010/github-action-ec2:latest
'
Hold on…let’s break down the code
- Firstly, we need to decide when would the workflow be triggered
- we want the workflow be triggered when some change was push to
main
branch
- we want the workflow be triggered when some change was push to
on:
push:
branches:
- 'main'
- CI Job
- This job section would build docker image and push it to your docker hub
- We would use the github action published by docker community to complete this task
- The most significant parts are:
context
we need to identify our Dockerfilepush
determine if you want topush
image to docker hubtag
add your image tag for pushing
name: Build and Push Image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: devinlin11010/github-action-ec2:latest
-
CD Job
- Note that the CD job has a dependency on CI job(because we want to deploy the latest image), so we have to add
needs: CI
to tell the Github action that CD should be executed after CI completed
CD: needs: CI
- Remembered that we need to write our private key content to a private key file, which is your environment variable
PRIVATAE_KEY
echo "$PRIVATE_KEY" > private_key && chmod 600 private_key ssh -o StrictHostKeyChecking=no -i private_key ${USER_NAME}@${HOSTNAME} '
- Connect to EC2 with this private key as identifier
- Now you could run the command you want to run on EC2
- In the EC2, we first pull the latest image the just pushed to docker hub in CI stage
- Then we may need to delete the existed hosting image on the instance
- Finally run your latest image
ssh -o StrictHostKeyChecking=no -i private_key ${USER_NAME}@${HOSTNAME} ' #Now we have got the access of EC2 and we will start the deploy docker pull devinlin11010/github-action-ec2:latest docker stop nginx && docker rm nginx docker run -p 80:80 -d --name="nginx" devinlin11010/github-action-ec2:latest '
- Note that the CD job has a dependency on CI job(because we want to deploy the latest image), so we have to add
Conclusion
Congrats🎉🎉 Now you could automatically deploy your code to AWS EC2. With the Github action, the process deployment would be much easier. You don’t need to manually deploy the code after some feature have made or changed. If you don’t want to build docker image to docker hub, we actually could connect to instance and fetch the Github repo then build your service. I would post this method in the near feature. Hope you enjoy this article and hands-on, feel free to reach me if you encounter any problem😉.
References
https://phoenixnap.com/kb/ssh-with-key#ftoc-heading-3
https://farhan-tanvir.medium.com/ci-cd-from-github-to-aws-ec2-using-github-action-e18b621c0507