
Note: CoCreated with Gpt 4o
This release wasn’t about shipping features — it was about making sure we can ship features faster and with more confidence going forward.
After running everything on a VPS with Docker Compose for years, I’ve migrated the backend of my project (SkillChamber + LingoStand) to Azure Cloud, using Azure Container Apps and Azure Flexible Server for MySQL.
Here’s a breakdown of the stack, what I learned, what broke, and what I set up for future scaling.
🧭 Architecture Overview
The backend is split into two services:
- Python (Flask) for AI/NLP handling
- Spring Boot for persistence, profile logic, routing, and frontend APIs
Both services now run in separate containers on Azure Container Apps, managed via Azure Container Registry (ACR).
App structure:
- spring-backend: 2 vCPU, 4 GB RAM
- python-backend: 1.25 vCPU, 2.5 GB RAM
- ingress: enabled for both
No custom domain yet — just raw endpoints behind ACA ingress.
🛠️ CI/CD with GitHub Actions
I’ve created per-service GitHub Actions workflows, each responsible for:
- Building a Docker image
- Pushing it to Azure Container Registry
- Deploying the updated image to Azure Container Apps using
az containerapp update
Secrets like ACR credentials and image tags are managed through GitHub Secrets. I did not use ARM templates or Bicep files — the setup was handled via Azure CLI and the portal.
Here’s a simplified example of one of the deploy steps:
- name: Deploy to Azure Container App
run: |
az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} \
-p ${{ secrets.AZURE_CLIENT_SECRET }} \
--tenant ${{ secrets.AZURE_TENANT_ID }}
az containerapp update \
--name python-backend \
--resource-group my-resource-group \
--image myregistry.azurecr.io/python-backend:latest
🐬 MySQL Migration (Painful Lessons)
The move to Azure MySQL Flexible Server came with a fair share of headaches. The biggest blocker?
UTF-8 character set incompatibility between my local MySQL and the default Azure Flexible config.
I’ve documented the fix in the README — it boils down to setting:
character_set_server = utf8mb4
collation_server = utf8mb4_unicode_ci
Once migrated, I set up automatic daily backups (default policy in Flexible Server).
📈 Observability Setup
I was pleasantly surprised by how frictionless observability was on Azure compared to other clouds I’ve used (AWS, GCP).
- Logs: Azure Monitor
- Metrics & autoscaling: via Container Apps resource metrics
- Custom Dashboard: I created one that tracks replica count, CPU usage, and HTTP error rates
This gives me quick visibility into how the services are behaving under load — and it’s all native to the Azure portal.
🔐 Secrets and Environment
All sensitive credentials (MySQL, API keys, ACR access) are injected through GitHub Secrets during CI.
I no longer use Docker Compose locally — all environments now rely on cloud-native deployments.
🚧 What’s Next
This was a foundational release. Nothing flashy, but here’s what it enables:
- 🛠️ Faster, safer deployments
- 🌍 Scaling without fear
- 🧪 More room to experiment with new agents and simulations
The next sprint will be back to features — now with a clean, observable, and scalable platform behind them.