In the fast-paced world of software development, automation is the key to delivering high-quality applications quickly and reliably. One of the most powerful and accessible tools for implementing CI/CD workflows is GitHub Actions. In this 2025 guide, weβll walk through creating a CI/CD pipeline with GitHub Actions and show you how to take it a step further by automatically deploying Docker images to AWS ECS (Elastic Container Service) after pushing them to ECR (Elastic Container Registry).
Whether you’re deploying a personal project or managing a production-ready application in a corporate environment, this guide will help you streamline your DevOps workflow from end to end.
What Is GitHub Actions?
GitHub Actions is a built-in automation service in GitHub that lets you define custom workflows triggered by events in your repository. These workflows are written in YAML and can automate tasks such as building, testing, and deploying your applications.
Key Features in 2025:
- Seamless integration with GitHub repositories
- Extensive marketplace for reusable actions
- Secure secrets management
- OIDC support for short-lived cloud credentials
- Support for all major languages and frameworks
π§ Prerequisites
Before you begin, for creating CI/CD Pipeline with GitHub Actions youβll need:
- A GitHub account
- A repository to test (public or private)
- Basic knowledge of Git and YAML
- A deployment target
π± Personal Project : GitHub Pages or Docker Hub Deployment
Not every project needs the complexity of AWS. If you’re working on a personal or hobby project, you can still take full advantage of GitHub Actions for automated deployments.
β Option 1: Deploy to GitHub Pages (Static Sites)
Perfect for frontend apps (React, Vue, etc.) or documentation sites (e.g., with MkDocs or Docusaurus).
Example:
name: Deploy to GitHub Pages
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Static Site
run: |
npm install
npm run build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build
β Option 2: Push Docker Image to Docker Hub
If you prefer Docker Hub for simplicity:
name: Build and Push to Docker Hub
on:
push:
branches: [main]
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Log in to Docker Hub
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
- name: Build and Push
run: |
docker build -t yourusername/myapp:${{ github.sha }} .
docker push yourusername/myapp:${{ github.sha }}
CI/CD Pipeline with GitHub Actions Workflow with AWS ECR and ECS (Corporate Environment)
While Docker Hub is great for public images, corporate environments often require secure, private registries. Amazon ECR offers private container image storage integrated with AWS IAM, and ECS provides scalable deployment options for microservices, either using EC2 instances or Fargate.
Using a CI/CD Pipeline with GitHub Actions, we can fully automate the entire development workflow:
- Build a Docker image
- Push it to Amazon ECR
- Update the ECS task definition
- Deploy the new task to an ECS service
Prerequisites
- AWS account with ECR and ECS permissions
- ECS cluster and service set up
- GitHub repository for your project
- GitHub Secrets or OIDC authentication configured
Project Example: Python API with ECS Deployment
Letβs use a simple Python FastAPI application as our example.
Project Structure
my-fastapi-app/
βββ app/
β βββ main.py
βββ requirements.txt
βββ Dockerfile
βββ .github/
β βββ workflows/
β βββ ci-cd.yml
βββ ecs-task-def.json
Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY ./app ./app
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
requirements.txt
fastapi
uvicorn
GitHub Actions Workflow (ci-cd.yml)
name: CI/CD to AWS ECS
on:
push:
branches: [ "main" ]
jobs:
deploy:
name: Build & Deploy to ECS
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Login to Amazon ECR
uses: aws-actions/amazon-ecr-login@v2
- name: Build, Tag, and Push Image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: my-fastapi-repo
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
- name: Render Task Definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: ecs-task-def.json
container-name: fastapi-container
image: ${{ steps.login-ecr.outputs.registry }}/my-fastapi-repo:${{ github.sha }}
- name: Deploy to ECS
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
cluster: my-cluster
service: my-fastapi-service
task-definition: ${{ steps.task-def.outputs.task-definition }}
ecs-task-def.json (Demo)
{
"family": "fastapi-task",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "fastapi-container",
"image": "PLACEHOLDER_IMAGE",
"essential": true,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
]
}
]
}
π You can find the complete CI/CD workflow code and project folder structure in the linked GitHub repository.
π For more on DevOps workflows, check out AWS Lambda cost-saving tips and the DevOps Maturity Model guide.
Security Considerations
- Use GitHub Secrets to store AWS credentials if not using OIDC
- Restrict repo write access to trusted team members
- Enable branch protection rules to prevent workflow tampering
- Prefer OIDC authentication to avoid long-lived secrets
- Rotate credentials periodically
FAQ on CI/CD Pipeline with GitHub Actions
β Are GitHub Secrets Secure?
Yes β they are encrypted and masked during runtime. However, any user with write access to the repo can modify workflows and misuse secrets, so restrict permissions tightly.
β Can I Use This Setup with OIDC Instead of Secrets?
Absolutely. GitHub Actions now supports OIDC (OpenID Connect), which lets you assume roles in AWS using temporary credentials β much safer for enterprise use.
β What if My Deployment Fails?
Check the Actions log. Common issues include:
- Incorrect AWS credentials or permissions
- Malformed
ecs-task-def.json
- Incorrect image tag
- ECS cluster or service name mismatch
β What Type of ECS Launch Mode Is This?
The above example uses Fargate, but it also works with EC2-backed ECS β just modify requiresCompatibilities
and add executionRoleArn
/taskRoleArn
if needed.
β Can I Roll Back Automatically?
Yes, but thatβs an advanced topic. Youβd need to integrate CloudWatch alarms and ECS deployment strategies or use a blue/green deployment tool like AWS CodeDeploy.
Bonus Brainstorm Questions (and Answers)
β Can I deploy multiple containers in one task?
Yes β define multiple container definitions in your ecs-task-def.json
.
β Can I deploy different branches to different environments?
Yes β use GitHub Environments with branch-based triggers (e.g., main
for production, dev
for staging).
β How do I test workflows before pushing?
Use the CLI tool act
to simulate GitHub Actions locally.
β Can I trigger rollback from within GitHub Actions?
Yes β combine a health check post-deploy and, on failure, re-deploy the last stable task definition.
β How do I manage different versions of the image?
Use semantic versioning in your tags, and pass the tag via workflow inputs or GitHub releases.
Final Thoughts
With this setup, you now have a complete CI/CD pipeline with GitHub Actions that not only builds and tests your app but also securely pushes Docker images to Amazon ECR and deploys them to Amazon ECS β fully automated.
This modern, cloud-native workflow is ideal for startups and enterprises alike, enabling fast, secure, and scalable deployments.