A Docker Compose multi-container application
-
Multi-Container Application
https://roadmap.sh/projects/multi-container-service -
Blue-Green Deployment
https://roadmap.sh/projects/blue-green-deployment
This project uses GitHub Actions to test → deploy → optionally destroy the infrastructure (manually via workflow_dispatch
)
It provisions a Python-based multi-container application using Docker and Docker Compose, consisting of a simple to-do list with a FastAPI backend and an HTML/CSS frontend
Infrastructure is provisioned using Terraform on AWS and deployed through CI/CD pipelines.
| Service | Description | URL |
| ------------ | -----------------------------------| ------------------------------------------------- |
| Frontend | Static HTML+CSS via NGINX | `http://<ec2-ip>:8080` |
| Backend API | FastAPI proxied through NGINX | `http://<ec2-ip>/` |
| API Direct | FastAPI exposed on Blue/Green | `http://<ec2-ip>:3001` (blue) or `:3002` (green) |
| Health Check | FastAPI /health endpoint | `http://<ec2-ip>:3001/health` or `:3002/health` |
| Metrics | FastAPI Prometheus endpoint | `http://<ec2-ip>:3001/metrics` or `:3002/metrics` |
| -------------| -----------------------------------| --------------------------------------------------|
| Prometheus | Monitoring system and data scraper | `http://<ec2-ip>:9090` |
| Grafana | Dashboard UI (login: admin/admin) | `http://<ec2-ip>:3003` |
| Node Exporter| System metrics exporter | `http://<ec2-ip>:9100/metrics` |
- Workflow Trigger — Manually triggered by the user or optionally on repository changes
- Runs the following jobs on Terraform and application code:
Terraform Jobs:
- Checkout Code
Clones the repository to the runner
- Setup Terraform
Installs Terraform CLI for command usage
- Terraform Init
Initializes configuration, backends, and providers
- Terraform Format Check
Enforces standard Terraform file formatting using terraform fmt -check
- Terraform Validate
Verifies Terraform syntax and logical correctness
Python Unit Tests:
- Checkout Code
Fetches the complete repo
- Set up Python
Installs Python 3.10
- Install Dependencies
Installs required packages via pip
- Force Correct httpx Version
Ensures FastAPI test compatibility
- Run Unit Tests
Executes pytest on backend test file (cd app/backend; pytest unit_tests.py)
Docker Compose Integration:
- Checkout Code
Loads the repository into the runner environment
- Install Docker & Compose
Ensures container tooling is available
- Run Docker Compose
Starts the full application stack
- Test API Endpoint
Confirms backend availability using curl on /todos
- Test Frontend
Verifies HTML response from nginx on port 8080
- Clean up
Shuts down containers using docker-compose down
- Workflow Trigger — Runs automatically after
test.yml
succeeds (workflow_run
), or manually viaworkflow_dispatch
Job Initialization:
- Sets Terraform variable: TF_VAR_key_name
- Uses AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY from repository secrets
- Checkout Code — Clones the repo into the runner
- Setup Terraform — Uses terraform_wrapper: false to enable direct output access
- Create Backend Infrastructure — S3 bucket and DynamoDB table for state management
- Terraform Init — Initializes the backend and modules
- Terraform Apply — Provisions infrastructure
- Save SSH Key — Extracts and secures generated EC2 SSH key (docker-key.pem)
- Wait for EC2 Instance — Ensures instance is ready before SSH
- Extract EC2 Public IP — Captures IP address from Terraform output for later use
IP=$(terraform -chdir=terraform output -raw public_ip | tr -d '
' | xargs)
echo "PUBLIC_IP=${IP}" >> $GITHUB_ENV
-
Deploy Application with Blue-Green Strategy:
- Detects currently active API container (blue or green)
- Spins up the inactive version (
docker-compose.blue.yml
orgreen.yml
) - Waits for the container to respond on
/health
- Updates NGINX configuration to switch traffic
- Removes the previously active version
-
Start Monitoring Stack — Prometheus, Grafana, and Node Exporter are launched with the app
-
Clean Up — Removes private SSH key from runner after deployment
- Destroys all provisioned resources, cleaning up Terraform-managed infrastructure using the remote backend
-
Prometheus scrapes system and application metrics:
- System metrics via Node Exporter
- App metrics via FastAPI
/metrics
usingprometheus_fastapi_instrumentator
-
Grafana dashboards configured to visualize:
- Request rates
- Latency distributions
- Error counts
- CPU, memory, and disk usage from Node Exporter
- Trigger deployment with:
test.yml # if all checks pass, triggers deploy.yml automatically
-
/health
is used for internal deployment checks to ensure the active container is healthy before traffic is switched -
To destroy the infrastructure manually:
Run destroy.yml
- Clone the repository
- Set GitHub Secrets for AWS access (
AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
) - Trigger
test.yml
manually via GitHub Actions UI or push changes - Once tests pass,
deploy.yml
runs automatically to:- Create AWS infrastructure
- SSH into the EC2 instance
- Deploy the blue or green container
- Set up Prometheus and Grafana monitoring
- Route traffic with NGINX
- Access your app via public EC2 IP and monitor performance using Grafana