AWS Builder Center
Building a Reusable GitHub Actions CI/CD Pipeline to Deploy Websites on Amazon ECS

Building a Reusable GitHub Actions CI/CD Pipeline to Deploy Websites on Amazon ECS

Learn how I built a reusable GitHub Actions workflow to automate website deployments using Docker, Amazon ECR, and Amazon ECS. This project demonstrates how to connect source code changes with an automated container deployment process using AWS.

Automating Website Deployment with GitHub Actions, Amazon ECR, and Amazon ECS

Introduction

Deploying a website manually every time code changes can become repetitive and time-consuming. Developers need to build the application, create a Docker image, push it to a container registry, and update the running application.
To simplify this process, I worked on a CI/CD pipeline using GitHub Actions, Docker, Amazon Elastic Container Registry (Amazon ECR), and Amazon Elastic Container Service (Amazon ECS).
The goal was to automate the deployment process so that changes pushed to the GitHub repository could be built, containerized, and deployed to AWS without performing every step manually.
Another important part of this project was using a reusable GitHub Actions workflow, which helps organize pipeline logic and makes it easier to reuse the same deployment process across projects.

Project Overview

The project uses a React frontend application as the example website.
The pipeline connects GitHub with AWS and automates the journey from source code to a running container.
The main technologies used are:
  • GitHub Actions: Automates the CI/CD pipeline.
  • Docker: Packages the website into a container image.
  • Amazon ECR: Stores and manages Docker images.
  • Amazon ECS: Runs and manages the application containers.
  • AWS IAM: Controls the permissions required for GitHub Actions to access AWS.
  • GitHub reusable workflows: Allows common pipeline steps to be maintained and reused.

Architecture and Workflow

The deployment process follows this sequence:
  1. A developer makes changes to the website.
  2. The changes are committed and pushed to the GitHub repository.
  3. GitHub Actions starts the CI/CD workflow.
  4. The workflow builds the application and creates a Docker image.
  5. The Docker image is tagged and pushed to Amazon ECR.
  6. The deployment workflow updates the Amazon ECS service with the new image.
  7. ECS starts the updated application tasks and maintains the desired running state.
The overall flow looks like this:
Developer → GitHub Repository → GitHub Actions → Docker Build → Amazon ECR → Amazon ECS → Running Website
This removes the need to manually build and upload a new container image for every application change.

Step 1: Preparing the Application

I started with a React frontend application and prepared it for containerization.
The application source code and Dockerfile were maintained in the GitHub repository.
The Dockerfile defines how the application is packaged into a Docker image. This image contains the application and the configuration required to run it.
Containerizing the application makes the deployment process more consistent because the same image can be used across different environments.

Step 2: Creating the GitHub Actions Workflow

GitHub Actions provides an automated way to execute commands in response to repository events.
I configured the workflow to respond to changes pushed to the repository. This allows the deployment process to begin automatically when the configured branch receives a commit.
The workflow is responsible for:
  • Checking out the latest source code.
  • Setting up the required build environment.
  • Building the application.
  • Creating a Docker image.
  • Authenticating with AWS.
  • Pushing the image to Amazon ECR.
  • Triggering the ECS deployment process.
Instead of running these commands manually, GitHub Actions executes the defined steps in the required order.

Step 3: Using a Reusable Workflow

One of the key learning points in this project was understanding reusable workflows in GitHub Actions.
As CI/CD pipelines grow, writing all the build and deployment steps in a single workflow can make the configuration difficult to maintain.
GitHub Actions allows a workflow to call another workflow using the workflow_call trigger.
A reusable workflow can contain common deployment steps, while the main workflow handles the trigger and passes the required inputs.
For example, a main workflow can call a reusable deployment workflow that handles the Docker build, ECR push, and ECS update.
This approach provides several benefits:
  • Code reuse: Common deployment logic can be shared across repositories or applications.
  • Easier maintenance: Changes to shared deployment steps can be made in one place.
  • Consistency: Applications can follow the same deployment process.
  • Simpler workflows: The main workflow can focus on when deployment should run and which configuration it should use.
Reusable workflows are especially useful when managing multiple applications that follow similar deployment patterns.

Step 4: Connecting GitHub Actions to AWS

The pipeline needs permission to interact with AWS services.
For this project, I explored how GitHub Actions can authenticate with AWS and how IAM permissions control access to the required resources.
A more secure approach is to use OpenID Connect (OIDC) instead of storing long-lived AWS access keys as GitHub secrets.
With OIDC, GitHub Actions obtains a temporary identity token. AWS IAM verifies the configured identity and trust conditions before allowing the workflow to assume an IAM role.
The role should have only the permissions needed for the deployment, such as pushing images to the designated ECR repository and updating the appropriate ECS service.
The OIDC trust policy should also restrict which repository and branch or workflow identity can assume the role.
This reduces reliance on long-lived credentials and improves the security of the CI/CD pipeline.

Step 5: Pushing the Docker Image to Amazon ECR

Amazon ECR is a managed container image registry that stores Docker images.
After building the application image, the workflow authenticates with ECR, tags the image, and pushes it to the configured repository.
A new image tag identifies the version that should be deployed. Using a unique tag, such as a Git commit SHA, helps identify exactly which source-code revision produced an image.
For example, an image tag can be based on the commit that triggered the pipeline.
This makes it easier to trace deployments, compare versions, and investigate issues.
ECR acts as the connection between the image-building stage in GitHub Actions and the container-running stage in ECS.

Step 6: Deploying the Application to Amazon ECS

Once the Docker image is available in ECR, the pipeline updates the application deployment in Amazon ECS.
ECS is responsible for running and managing the containers according to the service configuration.
Depending on the deployment configuration, the workflow can update an ECS task definition to reference the new image and then update the ECS service to use that task definition revision.
ECS launches tasks using the updated configuration and manages the service's desired task count.
This is the stage where the newly built version becomes the running application.
For a reliable deployment, the workflow should verify that the ECS service reaches a stable state. Health checks and appropriate deployment settings help identify situations where the new application version fails to start correctly.

Step 7: Testing the Automated Pipeline

After configuring the pipeline, the next step is to test the complete deployment flow.
A typical test involves making a small change to the React application, committing the change, and pushing it to the configured GitHub branch.
The expected process is:
  1. GitHub detects the repository change.
  2. The Actions workflow starts.
  3. The application image is built.
  4. The new image is pushed to ECR.
  5. ECS is updated to use the new image.
  6. The deployment is checked for successful stabilization.
  7. The website serves the updated application.
The GitHub Actions logs help identify failures during the build, authentication, image push, or deployment stages.
This makes troubleshooting easier than manually executing every deployment command.

Important Improvement: Separating CI and CD

An additional improvement is to separate the pipeline into two logical stages.
Continuous Integration (CI) focuses on validating the code, building the application, and producing the container image.
Continuous Deployment (CD) handles publishing the image and updating the running ECS service.
These stages can be organized using separate jobs or reusable workflows, with dependencies ensuring that deployment occurs only after the required build steps succeed.
For production applications, I would also add automated tests, environment-specific configuration, deployment approvals where needed, and a clear rollback strategy.

Security and Best Practices

While building this pipeline, I identified several practices that are important for reliable AWS deployments:
  • Use GitHub OIDC and temporary AWS credentials instead of long-lived access keys where possible.
  • Apply least-privilege IAM permissions.
  • Store container images in private ECR repositories.
  • Use unique image tags rather than relying only on the mutable latest tag.
  • Keep sensitive information out of source code and workflow logs.
  • Use ECS health checks and monitor deployment status.
  • Pin reusable workflows and third-party actions to trusted versions or commit SHAs.
  • Consider image vulnerability scanning and automated tests before deployment.
These practices help make the pipeline more secure, maintainable, and suitable for real-world applications.

What I Learned

This project helped me understand how different AWS services and GitHub Actions work together to automate application delivery.
My key learnings were:
  • How GitHub Actions responds to repository changes.
  • How reusable workflows reduce duplicated pipeline configuration.
  • How Docker packages a frontend application for deployment.
  • How Amazon ECR stores container images.
  • How Amazon ECS runs and updates containerized applications.
  • How IAM permissions and OIDC can secure access from GitHub Actions to AWS.
  • How automated deployments reduce repetitive manual work.
Most importantly, I learned that a CI/CD pipeline is not just about deploying code. It is about building a repeatable process that connects development, security, and infrastructure.

Conclusion

Building this pipeline was a practical step in understanding cloud deployment automation.
By connecting GitHub Actions with Docker, Amazon ECR, and Amazon ECS, I worked toward a deployment process in which a repository change can trigger the steps required to build and release an updated website.
Using reusable workflows makes the design easier to maintain and extend as more applications are added. Combining that approach with OIDC authentication, least-privilege permissions, and deployment health checks can make the pipeline more secure and reliable.
I plan to continue improving my AWS and DevOps skills by exploring better monitoring, automated testing, deployment strategies, and infrastructure automation.
The main takeaway: A well-designed CI/CD pipeline turns repetitive deployment steps into a consistent, automated workflow and provides a strong foundation for delivering applications on AWS.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article