Published in


CI/CD Hands-On : Github Actions+Docker Hub+AWS EC2

CI/CD Pipeline — Opensource.com


In this story, we are gonna talk about how to build a CI/CD pipeline with a set of tools, which mainly includes Github Actions, Docker Hub, and AWS EC2. Before we get started, let’s figure out the concept of CI/CD and why it matters to the modern application development cycle.

The Concept of CI/CD

CI/CD has come from the problems so many developers have meet in integrating new code. The main concepts attributed to CI/CD are continuous integration, continuous delivery and continuous deployment. With ongoing automation and continuous monitoring throughout the lifecycle of apps, development and operations teams can work together in an agile way, where multiple developers can work simultaneously on different features of the same app.

The Difference Between Those Steps

Image: https://www.redhat.com/

Continuous Integration normally means the stage to build, test and finally merge to a main repository linked to your app. This will prevent potential conflicts from having too many branches merged at once.

Continuous delivery refers to the stage to automate uploading your application to a repository(like Github or a container registry), where they can then be deployed to a live production environment. Its purpose is to ensure that it takes minimal effort to deploy new code.

Continuous deployment is the stage automatically releasing code changes to production. It addresses the problem of overloading operation teams with manual processes that slow down app delivery. And your app can be delivered to customers either more frequently or more reliably.


  1. Buildable code
  2. Valid EC2 instance (w/ ssh .pem key)
  3. Docker Hub account

CI/CD Pipeline Hands-on

Build Your Code

First of all, we need to build your application. I’m using Gradle, which is an open-source build automation tool as my project is based on Java, specifically with the Spring Boot. But you can apply this tutorial to any project no matter what language you use. After source code is built, a build file will be created in the root directory like the below.

Make a docker image

A Docker image is made up of a collection of files that build together all the essentials — such as installations, application code, and dependencies — required to configure a fully operational container environment. Dockerfile is one of the ways to create a Docker image.

If you execute the Docker build command, the Docker daemon finds the Dockerfile and build the image from the files and folders in the current working directory. We can see the newly-created image with the Docker images command. To find the meaning of the Dockerfile, see “Dockerfile reference”.

Push the docker image to Docker Hub

We are pushing the image to Docker Hub, which is the central repository having a collection of container images. You can also push and pull all the images you’ve made anywhere and anytime. With the docker push command.

Pull the image in AWS EC2

Since our image is now being managed by Docker Hub, we are simply able to bring it to the EC2 instance that we have. Get access to the instance and install docker with the sudo yum install docker command. Once it is done, login to your Docker Hub repository, pull the image similarly as we’ve done in the IDE(or on the CLI) and run it with the name and port that you want. Then, you will see your application starts sooner or later.

Wrap up the whole process in Github Actions

The final step is to write down what we have been doing so far in Github Actions. Github Actions is a CI/CD platform that allows you to automate your build, test, deployment pipeline. A Github Actions workflow is trigged when an event occurs in your repository. The workflow in Github Actions is a configurable automated process that will run one or more jobs in sequential order or parallel order. All the configurations are set by YAML syntax and each workspace is stored in your repository, in a directory called .github/workflows.

create a workflow file to make a complete CI/CD pipeline. This workflow should automatically trigger a series of code whenever code is pushed to main branch.

Add a job named build-and-deploy and configurations on the job to run on the latest version of an Ubuntu Linux Runner. And group all the necessary items under steps keyword. Each item is a separate action or a shell script. In most cases, steps start from checking out your repository on the runner with the use command, allowing you to run scripts or other actions against your code.

Once done, it moves on the steps to build and test with Gradle. The setup-java step configures the Java 11 JDK and the validate-gradle-wrapper step validates the checksums of Gradle Wrapper JAR files present in the source tree. Build actions comes next on the steps, using the preset action called gralde-build-action provided by the Gradle organization.

Next, we login to Docker Hub, following the command with the account information stored secretly in your repository secrets as environment variables. Configure a step where the runner execute docker commands to build and push your image to Hub.

Lastly, let your instance be handled by the workflow to pull and run the image automatically. To permit that the Github Actions get access to your instance through a ssh connection, you need to set up a ssh key pair and register its public key in your instance, on the file called ~/.ssh/authorized_keys

We execute then a group of docker commands in a step as a shell script, using the private key. For details about a remote ssh commands, see “ssh-actions

All is done! Now you will see that the workflow is triggered when code is pushed to your main branch and your application is running very soon.

Great Job! 👍🏽






Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Minho Jang

Minho Jang

Backend Developer, Writer, and Lifelong Learner