CI/CD with GitHub Actions: Building and Pushing Docker Images to Amazon ECR

By Team Algo
Reading Time: 4 minutes

By Padmanabh Manikandan 

In the world of software development, the efficiency of Continuous Integration and Continuous Deployment (CI/CD) pipelines has become crucial. CI/CD automates the process of code integration, testing, and deployment, making it easier for development teams to deliver high-quality software at a rapid pace. One popular CI/CD solution is GitHub Actions, which seamlessly integrates with GitHub repositories. In this blog, we’ll explore a GitHub Actions workflow that automates the building and pushing of Docker images to Amazon Elastic Container Registry (ECR).

GitHub Actions: A Brief Introduction

GitHub Actions is a powerful automation platform provided by GitHub. It allows developers to automate various tasks, from code testing to deployment, directly from their GitHub repositories. By defining workflows in YAML files, developers can create a series of actions that are triggered in response to specific events, such as code pushes or pull requests. In this blog, we’ll focus on building and pushing Docker images to Amazon ECR.

SonarQube Code analysis

SonarQube Community Version is a free, open-source static code analysis tool that helps developers maintain code quality. It detects code smells, vulnerabilities, and offers features like custom rules, IDE integration, multi-language support, security scanning, historical data tracking, and rich visualization. Use it for continuous integration, code reviews, technical debt management, compliance reporting, and open-source projects to improve code quality and software security.

To check out more about how to run a quick scan of your code, check out this blog.

Common workflow for Dev and master branches

We have set up conditions for development and master branches so that we can use specific secrets for Production and Development environments. This allows us to push to development, create a merge request, and upon approval, the workflow is executed and only the steps for the production branch are carried out.

Lets further look into a dummy example

on:
# Triggers the workflow on push request events but only
# for the "main" and "dev" branch
push:
branches:
- main
- dev
# A workflow run is made up of one or more jobs that can
# run sequentially or in parallel
jobs:
# This workflow contains a single job called "build_and_push"
build_and_push:

# The type of runner that the job will run on
runs-on: ubuntu-latest

# Steps represent a sequence of tasks that will be
# executed as part of the job steps:
steps:

# Checks-out your repository under $GITHUB WORKSPACE,
# so your job can access it
- uses: actions/checkout@v3


# Execute if branch is main
- name: Doing stuff for main
if: ${{ contains(github.ref_name, 'main') }}
run: |
echo ${{ github.ref_name }}
echo Executing for main


# Execute if branch is dev
- name: Doing stuff for dev
if: ${{ contains (github.ref_name, 'dev') }}
run: |
echo ${{ github.ref_name}}
echo Executing for dev

So now when we Push into the development branch, only the steps for Dev will be executed and the steps for main will be ignored.

After creating a merge request and getting it approved like the following:

The workflow in the main branch will be triggered automatically and steps for Dev will be ignored:

Workflow Overview

In this GitHub Actions workflow, we’ll focus on a scenario where you want to build and push Docker images to Amazon ECR when code is pushed to a branch. This is a common use case for teams working on containerized applications.

Triggering the Workflow

The workflow is triggered when code is pushed to the development or master branches and specifically when changes occur in the app’s directory. The on section specifies the trigger conditions.

name: Build and push to ECR for <APP_NAME>
on:
push:
branches:
- "master"
- "development"
paths:
- "<APP_FOLDER_NAME>/**"

Setting Up the Environment

We start by running the workflow on an Ubuntu machine (ubuntu-latest). This machine will be responsible for building and pushing the Docker image.

runs-on: ubuntu-latest

Checking Out the Code

The first step is to check out the code from the repository using the actions/checkout action. This step ensures that the latest code is available for the build process.

- name: Check out code
uses: actions/checkout@v2

Credentials Configuration

To interact with Amazon ECR, you need to provide AWS credentials. We use the aws-actions/configure-aws-credentials action to configure the AWS credentials securely using GitHub Secrets.

- name: Configure AWS credentials for production
if: ${{ contains(github.ref_name, 'master') }}
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }}
aws-region: <REGION_NAME_PROD>

- name: Configure AWS credentials for development
if: ${{ contains(github.ref_name, 'development') }}
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_DEV }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_DEV }}
aws-region: <REGION_NAME_DEV>

Logging into Amazon ECR

Before pushing the Docker image to Amazon ECR, we need to log in. The aws-actions/amazon-ecr-login action does this for us.

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1

Building and Pushing Docker Image

The final step is to build and push the Docker image to Amazon ECR. In this step, we specify the ECR registry, repository name, and the image tag. The Docker image is built from the code in the docker-debrief directory.

- name: Build, tag, and push image to Amazon ECR for production
env:
ECR_REGISTRY: <register name for PROD> #from github secrets
ECR_REPOSITORY: <repository name for DEV>
IMAGE_TAG: <tag for PROD>
run: |
cd <APP_FOLDER_NAME>
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

- name: Build, tag, and push image to Amazon ECR for development
env:
ECR_REGISTRY: <register name for DEV> #from github secrets
ECR_REPOSITORY: <repository name for DEV>
IMAGE_TAG: <tag for DEV>
run: |
cd <APP_FOLDER_NAME>
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

The environment variables like ECR_REGISTRYECR_REPOSITORY, and IMAGE_TAG should be replaced with your actual ECR registry, repository, and tag information.

Conclusion

Automating CI/CD processes using GitHub Actions is a powerful way to streamline software development and deployment. In this example, we’ve seen how to create a workflow that builds and pushes Docker images to Amazon ECR in response to code changes in a specific branch and directory. This can significantly improve your team’s development workflow, ensuring that your containerized applications are always up to date and ready for deployment.

Implementing this workflow can be a valuable addition to your development process. If you have any questions or need further assistance, feel free to ask in the comments below! Your feedback and suggestions are also highly appreciated.