Skip to main content

Command Palette

Search for a command to run...

πŸš€ Building a CI/CD Pipeline with GitHub Actions, Docker, and AWS EC2

Published
β€’3 min read
πŸš€ 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

ToolPurpose
FlaskPython web app
DockerContainerization
Docker HubContainer Registry
GitHub ActionsCI/CD Pipeline
AWS EC2Hosting 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 and 5000 in the security group

  • Added 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