๐ Building a CI/CD Pipeline with GitHub Actions, Docker, and AWS EC2


๐ Introduction
In this blog, Iโll walk you through how I built a complete CI/CD pipeline to deploy a Flask application using GitHub Actions, Docker, and AWS EC2.
This hands-on project gave me a deeper understanding of DevOps practices like automated builds, containerization, and remote deployment โ all using free-tier AWS resources.
๐งฐ Tech Stack Used
Tool | Purpose |
Flask | Python web app |
Docker | Containerization |
Docker Hub | Container Registry |
GitHub Actions | CI/CD Pipeline |
AWS EC2 | Hosting the App |
๐๏ธ Step 1: Create a Simple Flask App
I started with a minimal Flask
app.
app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "Hello from Flask CI/CD on AWS!"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
requirements.txt
flask
Test locally:
python3 app.py
Visit: http://localhost:5000
๐ณ Step 2: Dockerize the App
Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
Build and run locally:
docker build -t flask-cicd .
docker run -p 5000:5000 flask-cicd
๐ค Step 3: Push Code to GitHub
I initialized a Git repo and pushed the code:
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/mahesh-diwan/flask-cicd.git
git push -u origin master
๐ View Repo on GitHub
โ๏ธ Step 4: Push Docker Image to Docker Hub
docker tag flask-cicd maheshdiwan/flask-cicd:latest
docker push maheshdiwan/flask-cicd:latest
๐ Docker Hub Image
๐ Step 5: GitHub Actions CI/CD Workflow
This GitHub Actions workflow automates:
Docker build on every push
Docker push to Docker Hub
SSH into EC2 and run the container
.github/workflows/deploy.yml
name: Build and Deploy
on:
push:
branches: [master]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/flask-cicd:latest .
docker push ${{ secrets.DOCKER_USERNAME }}/flask-cicd:latest
- name: Deploy to EC2 via SSH
uses: appleboy/ssh-action@v0.1.7
with:
host: ${{ secrets.EC2_HOST }}
username: ubuntu
key: ${{ secrets.EC2_SSH_KEY }}
script: |
docker pull ${{ secrets.DOCKER_USERNAME }}/flask-cicd:latest
docker stop flask-cicd || true
docker rm flask-cicd || true
docker run -d --name flask-cicd -p 5000:5000 ${{ secrets.DOCKER_USERNAME }}/flask-cicd:latest
โ Secrets are configured in the GitHub repo:
DOCKER_USERNAME
DOCKER_PASSWORD
EC2_HOST
EC2_SSH_KEY
๐ฅ๏ธ Step 6: Set Up EC2 on AWS
I launched a t2.micro Ubuntu EC2 instance, then:
- Installed Docker:
sudo apt update
sudo apt install docker.io -y
Opened ports
22
and5000
in the security groupAdded my private SSH key to GitHub Secrets
Pushed to GitHub to trigger deployment
๐ Final Architecture
GitHub โ GitHub Actions โ Docker Hub
โ SSH
AWS EC2 โ Docker โ Flask App (port 5000)
๐ง Key Takeaways
CI/CD automation reduces manual deployment work
Docker + GitHub Actions is an efficient pipeline combo
AWS EC2 gives full control over deployments
Real-world projects teach more than theory ever could!
๐ Final Notes
To save AWS credits, my EC2 instance is currently turned off.
You can still clone the project and run locally:
docker build -t flask-cicd .
docker run -p 5000:5000 flask-cicd
๐ Links
Subscribe to my newsletter
Read articles from Mahesh Diwan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
