Deploy a Docker Container to Amazon ECS using GitHub Actions
In this project, we will set up a GitHub Actions CI/CD pipeline that runs each time new changes are pushed to the main GitHub branch. When this action is triggered, a new docker image is built, pushed to Docker Hub, and then deployed to an Amazon ECS cluster.
This guide assumes you already have some knowledge in AWS, ECS, Docker, and GitHub Actions as the goal is to provide a template you can modify to meet the specific needs of your project.
Requirements
To follow along with this project, you should have an AWS Account, GitHub account, Docker Hub account(you can optionally use Amazon ECR), and certain software installed in your local environment like:
Git
Docker
VS Code(or any text editor you prefer)
Lastly, we will need an ECS cluster/ ECS Service up and running that GitHub actions will deploy the updated image to. I already wrote out this infrastructure using Terraform and you can get it here from my GitHub repo => https://github.com/ajimbong/terraform-ecs-cicd-project. If you are familiar with Terraform, you can use that to automatically create the infrastructure or do it manually. But these are the resources that the Terraform code will create:
A VPC with 2 public and private subnets distributed across 2 availability zones.
An Internet Gateway and Two NAT Gateways, one in each availability zone.
A Fargate ECS Cluster and ECS Service.
An Application Load Balancer.
And a Route53 record which you can optionally leave out.
Implementation
Clone the Application Code
The application used here is a Simple Notes Taking app that was developed using React, it's purely a frontend application and doesn't have a backend. Here is the link to clone the code from my repo => https://github.com/ajimbong/novo-notes. Optionally, you could still skip this step by using your project.
Modify the Workflow file.
In this GitHub repo => https://github.com/ajimbong/novo-notes, navigate to the directory .github/workflows/
and you will find a main.yml
file. This file is a declaration of the tasks GitHub Actions will perform when a "defined event" is triggered.
name: Deploy to Amazon ECS
on:
push:
branches:
- "main"
workflow_dispatch:
# secrets:
# DOCKER_HUB_USERNAME:
# DOCKER_HUB_PASSWORD:
# AWS_ACCESS_KEY_ID:
# AWS_SECRET_ACCESS_KEY:
env:
IMAGE_NAME: novo-notes
AWS_REGION: us-east-1
ECS_SERVICE: ecs-cicd-ecs-service
ECS_CLUSTER: ecs-cicd-ecs-cluster
ECS_TASK_DEFINITION: aws/td.json
CONTAINER_IMAGE: ajimbong/novo-notes
CONTAINER_NAME: novo-notes
defaults:
run:
shell: bash
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:latest
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: ${{ env.ECS_TASK_DEFINITION }}
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ env.CONTAINER_IMAGE }}
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true
Starting from the top and moving down:
The
on:
keyword species the events that should trigger the workflow. The events defined here are:push:
that runs anytime we push changes to the main branchworkflow_dispatch:
that allows us to manually run the workflow.
The secrets that have been commented out refer to the secrets we manually have to create in our GitHub repository. Ensure that you set them up before proceeding.
env:
is the set of environment variables that will be used during the execution of the workflow. You want to make sure you set the values that are appropriate to your project.IMAGE_NAME:
is the name of the docker container image.AWS_REGION:
refers to the AWS region where your resources are deployed to.ECS_SERVICE:
is the name of your ECS ServiceECS_CLUSTER:
is the name of your ECS clusterECS_TASK_DEFINITION:
is the directory to a JSON file containing your task definition template. This JSON code can easily be gotten from your AWS ECS console under Task Definitions, and it should be a Task Definition that was already created.CONTAINER_IMAGE:
is the URL to your docker container image.CONTAINER_NAME:
is the name of your docker image. Same as IMAGE_NAME.
defaults:
we're just defining the default Linux shell that should be used.jobs:
this is where we define all the execution steps. Again, I already assume you have some familiarity with GitHub actions so I'm not going to explain all the steps as this will be very lengthy.
Run the Workflow
Now that we're done modifying the workflow file, it's time to run it by pushing the changes to the main GitHub branch to trigger the workflow, or we can manually run it from the Actions
tab in the GitHub repo.
Watch closely to ensure that everything goes properly(which I hope it does), else you can try to troubleshoot any failures that occur.
This is where I will wrap things up, and I hope you found this article helpful!
Subscribe to my newsletter
Read articles from Ajimsimbom Bong M directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Ajimsimbom Bong M
Ajimsimbom Bong M
I'm Ajim, a Cloud DevOps Engineer from Cameroon. I'm really into Cloud Native Solutions involving Microservices, Containers, and Kubernetes. Feel free to reach out to me if you wish to connect or collaborate on a project.