A full-stack skill tracking web application — built to demonstrate end-to-end DevOps practices including containerization, CI/CD automation, cloud deployment, and infrastructure management.
This project was built from scratch to gain hands-on experience with real-world DevOps workflows. Every component was deliberately chosen to mirror industry practices.
- Designed a multi-service Docker Compose setup with 3 containers: MySQL database, Go backend API, and Nginx reverse proxy
- Wrote a multi-stage Dockerfile for the Go backend — separating the build stage from the runtime stage to produce a lightweight production image
- Configured health checks so dependent services wait for the database to be ready before starting
- Managed persistent volumes for database storage across container restarts
All 3 containers running live on Azure VM:
- Built a 4-stage automated pipeline from scratch: Code Quality → Build → Test → Deploy
- Every
git pushtomainautomatically triggers the full pipeline — no manual deployment needed - Implemented health check verification after deployment to confirm the app is live
- Pipeline completed in under 4 minutes end-to-end
Pipeline runs — all stages passing:
Stage breakdown — Code Quality, Build, Test, Deploy:
- Provisioned and configured an Azure Ubuntu VM as the deployment target
- Set up a self-hosted Azure DevOps agent on the VM using a custom bash installer script
- The agent registers as a systemd service — starts automatically on VM reboot
Agent installation on Azure VM:
Agent showing Online in Azure DevOps:
- Managed the entire project using Azure Boards with a proper Scrum workflow
- Organized work into Epics → Features → Tasks to simulate a real team environment
- All 4 Epics completed: Project Infrastructure, Backend Development, Frontend Development, CI/CD Pipeline
Kanban board — all Epics marked Done:
- Configured Nginx to serve the static frontend and simultaneously proxy API requests to the Go backend — all on port 80
- Eliminates CORS issues and mimics how production applications route traffic
- Designed the MySQL schema with an initialization script that runs automatically on first container start
- Connected the Go backend to MySQL using environment variables — no hardcoded credentials
- All sensitive values (passwords, tokens) stored as Azure DevOps Variable Group secrets — never committed to the repository
- The pipeline injects secrets at runtime into the
.envfile
┌─────────────────────────────────────────────┐
│ User Browser │
└──────────────────────┬──────────────────────┘
│ HTTP :80
┌────────────▼────────────┐
│ Nginx │
│ Static Files + Proxy │
└──┬─────────────────────┘
│ /api/* → :8080
┌──────────▼──────────┐ ┌─────────────────┐
│ Go Backend │───▶│ MySQL 8.0 │
│ REST API │ │ Database │
└─────────────────────┘ └─────────────────┘
Hosted on: Azure VM (Ubuntu)
Deployed via: Azure DevOps Pipeline
Agent: Self-hosted on same VM
Git Push to main
│
▼
① Code Quality
└── Validate docker-compose.yml syntax
│
▼
② Build
└── Build all Docker images
│
▼
③ Test
└── Start DB container
└── Wait for DB health check
└── Run integration tests
└── Cleanup test environment
│
▼
④ Deploy
└── docker compose up -d --build
└── Health check on /health endpoint
└── Prune old Docker images
| Layer | Technology | Purpose |
|---|---|---|
| Frontend | HTML, CSS, JavaScript | Skill tracking dashboard UI |
| Backend | Go (Golang) | REST API server |
| Database | MySQL 8.0 | Persistent data storage |
| Reverse Proxy | Nginx | Traffic routing + static file serving |
| Containerization | Docker + Docker Compose | Service orchestration |
| CI/CD | Azure DevOps Pipelines | Automated build, test, deploy |
| Cloud | Azure VM (Ubuntu) | Production server |
| Agent | Azure DevOps Self-hosted | Pipeline execution on VM |
| Project Mgmt | Azure Boards (Scrum) | Agile workflow tracking |
| Version Control | Git + Azure Repos | Source code management |
skillpulse/
├── backend/
│ ├── main.go # Go REST API (health, skills, sessions)
│ └── Dockerfile # Multi-stage build → lightweight image
├── frontend/
│ ├── index.html # Dashboard UI
│ ├── css/style.css # Dark/light theme, responsive design
│ └── js/app.js # Fetch API, dynamic rendering
├── nginx/
│ └── nginx.conf # Reverse proxy + static file config
├── mysql/
│ └── init.sql # Auto-executed schema on first run
├── docker-compose.yml # 3-service orchestration with health checks
├── azure-pipelines.yml # 4-stage CI/CD pipeline definition
├── install-agent.sh # Self-hosted agent installer script
├── docs/
│ └── screenshots/ # Project screenshots
└── .env.example # Environment variable template
# Clone
git clone https://github.com/haideralimazari/SkillPulse-Azure-DevOps-CICD.git
cd skillpulse
# Configure
cp .env.example .env
# Edit .env with your values
# Run
docker compose up -d --build
# Open
# http://localhost → Dashboard
# http://localhost/health → Health Check
# http://localhost/api/skills → API| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Service health check |
GET |
/api/skills |
Fetch all skills |
POST |
/api/skills |
Create a new skill |
DELETE |
/api/skills/:id |
Remove a skill |
POST |
/api/skills/:id/log |
Log a learning session |
GET |
/api/dashboard |
Aggregated stats |
Full project board, pipeline runs, and repo history:







