End-to-end CI/CD pipeline with quality gates, artifact management, real deployment and rollback — built to reflect real industry practices.
This project demonstrates a production-grade CI/CD pipeline for a Python-based microservice using GitHub Actions, Docker, Docker Compose, SonarQubeCloud, and GitHub Container Registry (GHCR).
The goal was to eliminate manual builds and deployments by implementing:
- Automated testing and linting
- Code quality & coverage gates
- Containerized builds
- Versioned artifact publishing
- Real continuous deployment to a running environment
- Manual rollback by redeploying the latest production image
| Category | Tools |
|---|---|
| Language | Python 3.11 |
| Framework | Flask |
| CI/CD | GitHub Actions |
| Code Quality | Flake8, Pytest, Pytest-Cov |
| Security & Quality Gate | SonarQubeCloud |
| Containerization | Docker |
| Deployment | Docker Compose (VM-based) |
| Artifact Registry | GitHub Container Registry (GHCR) |
| Deployment Runner | Self-hosted GitHub Actions Runner (Windows) |
/→ Health endpoint (returns status + environment)/hello→ Sample API endpoint- Environment-aware configuration using
APP_ENV
- Dev: Local build using Docker Compose
- Prod: Pre-built image pulled from GHCR
- Uses
python:3.11-slim - Layer-optimized build
- Production-ready image
Development (docker-compose.dev.yml)
- Builds image locally
- Used for local testing
Production (docker-compose.prod.yml)
- Pulls image from GHCR
- Injects
APP_ENV=prod - Uses restart policies
Developer Push / PR
↓
GitHub Actions (CI)
↓
Lint → Test → Coverage → SonarQube Quality Gate
↓
Docker Image Build
↓
Tag (SHA / SemVer / latest)
↓
Push to GHCR
↓
Self-hosted Runner (CD)
↓
Docker Compose Deployment
The CI pipeline runs automatically on:
- Pull Requests
- Merges to
main
- Checkout source code
- Install dependencies
- Lint with Flake8
- Run unit tests
- Enforce 80% coverage threshold
- Generate coverage report (XML)
- Run SonarQubeCloud
- Enforce Sonar Quality Gate
- Build Docker image
- Tag image with:
- Git SHA
- Semantic version
latest
- Push image to GHCR
Quality gates ensure that bad code never reaches production.
Each successful pipeline run publishes three Docker image tags:
:latest:<semantic-version>(example:0.1.0):<git-sha>
This enables:
- Traceability
- Reproducible deployments
- Safe rollbacks
- Uses a self-hosted GitHub Actions runner
- Runs on merge to
main - Deploys via Docker Compose
- Authenticate to GHCR
- Pull latest production image
- Stop existing containers
- Start updated containers
- Verify running containers
Containers remain running after the workflow finishes
A dedicated rollback workflow allows manually redeploying the production service using Docker Compose.
- Manual trigger via GitHub UI (
workflow_dispatch) - Re-deploys the service using Docker Compose
- Does not require rebuilding artifacts
- Static code analysis
- Code smells & maintainability checks
- Coverage enforcement
- Quality Gate blocking deployments
This ensures:
- Clean, maintainable code
- Early detection of issues
- Uses GitHub-provided
GITHUB_TOKEN(no hardcoded secrets) - Scoped permissions (
contents,packages) - No credentials committed to the repository
- Self-hosted runner used only for deployment
Note: Self-hosted runners in public repos require trust. This setup reflects a controlled environment similar to internal company repos.
Docker Compose -f docker-compose.dev.yml up --build
Docker Compose -f docker-compose.prod.yml up -d
After running the production containers, you can verify the service endpoints:
- Health check: http://localhost:5000/
- Sample endpoint: http://localhost:5000/hello
Alternatively, you can run the automated tests:
pytest tests/