A production-grade DevOps portfolio project demonstrating end-to-end CI/CD pipelines, containerization, Infrastructure as Code, and Kubernetes orchestration across AWS EKS and Azure AKS.
This project showcases a complete DevOps workflow for a Python FastAPI microservice, deployed to both AWS and Azure using modern cloud-native tooling. It demonstrates:
- Application development with FastAPI, unit tests, and health probes
- Containerization with multi-stage Docker builds and security best practices
- CI/CD automation with GitHub Actions (lint → test → build → scan → deploy)
- Infrastructure as Code with Terraform for both AWS and Azure
- Kubernetes orchestration with Deployments, Services, Ingress, HPA, and Helm charts
- Security with Trivy image scanning, non-root containers, and IAM/RBAC
See architecture.md for detailed Mermaid diagrams of:
- CI/CD pipeline flow
- AWS VPC + EKS deployment topology
- Azure VNet + AKS deployment topology
- Kubernetes resource interaction flow
High-level flow:
Developer → GitHub → GitHub Actions → GHCR Image → EKS / AKS
↓
Terraform provisions VPC/VNet, EKS/AKS, IAM/RBAC
| Layer | Technology |
|---|---|
| Language | Python 3.11 |
| Framework | FastAPI + Uvicorn |
| Container | Docker (multi-stage, multi-arch) |
| Registry | GitHub Container Registry (GHCR) |
| CI/CD | GitHub Actions |
| Security Scan | Trivy (Aqua Security) |
| IaC — AWS | Terraform 1.8 (VPC, EC2, S3, IAM, EKS) |
| IaC — Azure | Terraform 1.8 (VNet, AKS, ACR, Key Vault) |
| Orchestration | Kubernetes 1.30 |
| Package Manager | Helm 3.x |
| Cloud — AWS | EKS, EC2, S3, IAM, VPC |
| Cloud — Azure | AKS, ACR, Key Vault, Log Analytics |
cloud-devops-multi-cloud-deployment/
├── app/
│ ├── __init__.py
│ └── main.py # FastAPI application
├── tests/
│ ├── __init__.py
│ └── test_main.py # Unit tests (pytest)
├── .github/
│ └── workflows/
│ ├── ci-cd.yml # Main CI/CD pipeline
│ └── pr-validation.yml # Pull request checks
├── terraform/
│ ├── aws/
│ │ ├── main.tf # VPC, EC2, S3, IAM, EKS
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ └── terraform.tfvars.example
│ └── azure/
│ ├── main.tf # VNet, AKS, ACR, Key Vault
│ ├── variables.tf
│ └── outputs.tf
├── kubernetes/
│ ├── namespace.yaml
│ ├── configmap.yaml
│ ├── secret.yaml # Placeholder — use External Secrets in prod
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ └── hpa.yaml
├── helm/
│ └── fastapi-app/
│ ├── Chart.yaml
│ ├── values.yaml
│ └── templates/
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── service.yaml
│ └── hpa.yaml
├── scripts/
│ └── prometheus.yml # Prometheus config for local observability
├── Dockerfile # Multi-stage build
├── docker-compose.yml # Local dev + optional observability stack
├── requirements.txt
├── .gitignore
├── architecture.md # Mermaid architecture diagrams
└── README.md
- Python 3.11+
- Docker Desktop
- kubectl
- Terraform 1.8+
- Helm 3.x
- AWS CLI / Azure CLI (for cloud deployments)
# Clone the repository
git clone https://github.com/your-github-username/cloud-devops-multi-cloud-deployment.git
cd cloud-devops-multi-cloud-deployment
# Create virtual environment
python -m venv venv
source venv/bin/activate # macOS/Linux
# venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
# Start the FastAPI application
uvicorn app.main:app --reload --port 8000
# API is now available at:
# http://localhost:8000
# http://localhost:8000/docs (Swagger UI)
# http://localhost:8000/health (Health check)# Run all tests with coverage
pytest tests/ -v --cov=app --cov-report=term-missing
# Expected output: 20 tests passing# Build the image
docker build -t fastapi-cloud-devops:local .
# Run the container
docker run -d \
--name fastapi-app \
-p 8000:8000 \
-e ENVIRONMENT=development \
fastapi-cloud-devops:local
# Verify health
curl http://localhost:8000/health
# Stop and remove
docker stop fastapi-app && docker rm fastapi-app# Start the API only
docker-compose up -d api
# Start with Prometheus + Grafana observability stack
docker-compose --profile observability up -d
# View logs
docker-compose logs -f api
# Tear down
docker-compose down -v- AWS CLI configured (
aws configure) - IAM user with permissions for VPC, EC2, S3, IAM, EKS
cd terraform/aws
# Copy and fill in your values
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with your AWS settings
# Initialize Terraform (downloads providers and modules)
terraform init
# Preview the plan
terraform plan -out=tfplan
# Apply infrastructure
terraform apply tfplan
# View outputs (VPC ID, EC2 IP, S3 bucket, EKS endpoint)
terraform output| Resource | Description |
|---|---|
| VPC | 10.0.0.0/16 with DNS enabled |
| Public Subnets | 2x public subnets across 2 AZs |
| Private Subnets | 2x private subnets for workloads |
| NAT Gateway | Outbound internet for private subnets |
| Security Groups | Web (80/443) and App (8000) tiers |
| EC2 Instance | t3.micro in private subnet, auto-pulls Docker image |
| S3 Bucket | Encrypted, versioned artifact storage |
| IAM Role | EC2 instance profile with S3 + SSM access |
| EKS Cluster | Kubernetes 1.30 with managed node group |
terraform destroy- Azure CLI configured (
az login) - Service principal with Contributor access
cd terraform/azure
# Set your subscription
az account set --subscription "YOUR_SUBSCRIPTION_ID"
# Initialize Terraform
terraform init
# Preview
terraform plan -var="environment=prod"
# Apply
terraform apply -var="environment=prod"
# Get AKS credentials
az aks get-credentials \
--resource-group $(terraform output -raw resource_group_name) \
--name $(terraform output -raw aks_cluster_name)| Resource | Description |
|---|---|
| Resource Group | All resources grouped by environment |
| Virtual Network | 10.1.0.0/16 with AKS and app subnets |
| NSG | Inbound rules for :80, :443, :8000 |
| Azure Container Registry | Standard SKU for container images |
| AKS Cluster | Kubernetes 1.30, auto-scaling node pool |
| Key Vault | Secrets and certificates storage |
| Storage Account | Blob storage for artifacts |
| Log Analytics | AKS monitoring and diagnostics |
# Ensure your kubeconfig is pointing to the right cluster
kubectl config current-context
# Apply all manifests in order
kubectl apply -f kubernetes/namespace.yaml
kubectl apply -f kubernetes/configmap.yaml
kubectl apply -f kubernetes/secret.yaml
kubectl apply -f kubernetes/deployment.yaml
kubectl apply -f kubernetes/service.yaml
kubectl apply -f kubernetes/ingress.yaml
kubectl apply -f kubernetes/hpa.yaml
# Watch pods come up
kubectl get pods -n cloud-devops -w
# Check deployment rollout
kubectl rollout status deployment/fastapi-cloud-devops -n cloud-devops# Install the chart
helm install fastapi-app ./helm/fastapi-app \
--namespace cloud-devops \
--create-namespace \
--set image.repository=ghcr.io/your-github-username/cloud-devops-multi-cloud-deployment/fastapi-cloud-devops \
--set image.tag=latest
# Upgrade an existing release
helm upgrade fastapi-app ./helm/fastapi-app \
--namespace cloud-devops \
--set image.tag=sha-abc1234
# Check release status
helm status fastapi-app -n cloud-devops
# Uninstall
helm uninstall fastapi-app -n cloud-devops# Get all resources in the namespace
kubectl get all -n cloud-devops
# Check HPA scaling status
kubectl get hpa -n cloud-devops
# View application logs
kubectl logs -l app=fastapi-cloud-devops -n cloud-devops --follow
# Port-forward for local access
kubectl port-forward svc/fastapi-cloud-devops-svc 8080:80 -n cloud-devops
curl http://localhost:8080/healthThe GitHub Actions pipeline in .github/workflows/ci-cd.yml has 4 jobs:
Triggered on every push and pull request.
- Checks out the code
- Sets up Python 3.11 with pip cache
- Installs dependencies
- Runs
flake8linting - Runs
pytestwith coverage report - Uploads coverage artifact
Runs after tests pass. Only pushes image on non-PR events.
- Sets up Docker Buildx for multi-platform builds
- Logs in to GitHub Container Registry
- Extracts metadata (tags from branch/SHA/semver)
- Builds multi-arch image (
linux/amd64+linux/arm64) - Uses GitHub Actions cache to speed up builds
- Runs Trivy vulnerability scan (CRITICAL + HIGH)
- Uploads SARIF results to GitHub Security tab
Runs on main branch pushes only.
- Configures AWS credentials from GitHub Secrets
- Updates kubeconfig for the EKS cluster
- Replaces image tag placeholder in manifests
- Applies all Kubernetes manifests
- Waits for rollout to complete (5-minute timeout)
Runs on main branch with deploy_target=azure or both.
- Logs in to Azure with Service Principal credentials
- Sets AKS context
- Applies manifests and waits for rollout
| Secret | Description |
|---|---|
AWS_ACCESS_KEY_ID |
AWS IAM access key |
AWS_SECRET_ACCESS_KEY |
AWS IAM secret key |
AWS_REGION |
AWS region (e.g. us-east-1) |
EKS_CLUSTER_NAME |
Name of your EKS cluster |
AZURE_CREDENTIALS |
Azure service principal JSON |
AZURE_RESOURCE_GROUP |
Azure resource group name |
AKS_CLUSTER_NAME |
Name of your AKS cluster |
Add screenshots of your running deployment here.
| Description | Screenshot |
|---|---|
| FastAPI Swagger UI | screenshots/swagger-ui.png |
| GitHub Actions pipeline | screenshots/github-actions.png |
| Trivy scan results | screenshots/trivy-scan.png |
| Kubernetes pods running | screenshots/kubectl-pods.png |
| HPA scaling in action | screenshots/hpa-scaling.png |
| Terraform apply output | screenshots/terraform-apply.png |
Use these bullet points when describing this project in interviews:
- Architected and deployed a FastAPI microservice to both AWS EKS and Azure AKS using a unified CI/CD pipeline with GitHub Actions, achieving zero-downtime rolling deployments
- Automated multi-cloud infrastructure provisioning with Terraform, creating VPCs, subnets, security groups, IAM roles, EKS clusters (AWS) and VNets, AKS clusters, ACR, and Key Vault (Azure)
- Built a multi-stage Docker image with non-root user, read-only filesystem, and multi-arch support (linux/amd64 + arm64), reducing image size by ~60% versus a single-stage build
- Integrated Trivy vulnerability scanning into the CI pipeline with automatic SARIF upload to GitHub Security tab, ensuring no CRITICAL/HIGH CVEs reach production
- Configured Kubernetes HPA to auto-scale pods between 2 and 10 replicas based on CPU (70%) and memory (80%) utilization thresholds
- Packaged the application as a Helm chart for parameterized, repeatable deployments across dev/staging/production environments
- Implemented Kubernetes security best practices: non-root containers, read-only root filesystem, capability drops, and resource limits on all pods
- Wrote 20 unit tests with pytest achieving 95%+ code coverage, integrated into the CI pipeline with automatic coverage reporting
- Fork the repository
- Create a feature branch (
git checkout -b feature/your-feature) - Commit your changes (
git commit -m 'Add your feature') - Push to the branch (
git push origin feature/your-feature) - Open a Pull Request — the PR validation workflow will run automatically
This project is licensed under the MIT License. See LICENSE for details.
Built by Parnika Goud Bingi — DevOps & Cloud Engineer