CareerLabs made a strategic decision to migrate its cloud infrastructure from Amazon Web Services (AWS) to Microsoft Azure - driven by enterprise integration requirements, governance standardization, and long-term cloud strategy alignment.
As the technical lead, I evaluated Azure Kubernetes Service (AKS) as the migration target, designed the full cut-over plan, and executed the migration end-to-end across workloads, databases, container registries, networking, and CI/CD.
Non-negotiable requirement: the least business downtime possible.
Scope
This was a full infrastructure migration, not a lift-and-shift of one or two services:
- EC2-based Lower Env and EKS Deployed applications → Azure Kubernetes Service (AKS)
- AWS RDS (PostgreSQL) databases → Azure Database for PostgreSQL
- AWS ECR container registry → Azure Container Registry
- Jenkins CI/CD → Azure DevOps with Azure Pipelines
- AWS networking (VPC, security groups, load balancers) → Azure VNets, NSGs, CDN Front Door, Nginx Ingress
- AWS CloudWatch monitoring → Azure Monitor + Application Insights
Every component had to be assessed, an Azure equivalent identified, migrated, and validated - without touching live production traffic.
Technical Approach
1. Assessment & Migration Planning
Started with a full inventory of all AWS resources. For each:
- Identified the appropriate Azure equivalent
- Assessed migration complexity and downtime risk
- Mapped service dependencies to determine safe migration order
- Projected cost in the new environment
This produced a phased roadmap - lower-risk, higher-isolation services first, databases and high-traffic services last.
2. Docker Compose → AKS with HPA and Node Autoscaling
Applications were running on Docker Compose on EC2 for Dev Environment - manageable at small scale but not horizontally scalable. Migration to AKS was the opportunity to fix this.
Applications were running on EKS for Production Environment - Migration to AKS was the opportunity to fix this.
I refactored Docker Compose workloads into Kubernetes manifests with:
- Horizontal Pod Autoscaler (HPA) for traffic-responsive scaling
- Node Autoscaling for cost-efficient cluster sizing
- Namespace-based isolation per environment and service tier
- Azure Container Registry replacing AWS ECR for image storage
3. Database Migration (AWS RDS for PostgreSQL → Azure Database for PostgreSQL)
Migrated relational databases from AWS RDS for PostgreSQL to Azure Database for PostgreSQL using Azure Database Migration Service (DMS).
Initially, the migration service failed due to configuration issues that I couldn't immediately identify. To keep the broader infrastructure migration moving, I temporarily migrated the databases using PostgreSQL dumps while continuing to troubleshoot the managed migration service.
After investigating the documentation and debugging the configuration, I resolved the issues and validated the migration service against a test database instance in Azure. Once the test migration succeeded, I proceeded with the production migration:
- Removed the temporary production database previously restored in Azure.
- Migrated the production database from AWS RDS to Azure Database for PostgreSQL using Azure Database Migration Service.
- After migrating the infrastructure and switching the application to the Azure database endpoint, verified that no further writes were occurring on the AWS source database.
- Performed a final synchronization to ensure the Azure database was up to date with the AWS source before completing the migration.
This approach allowed me to validate the managed migration workflow before using it for production and avoid relying on the initial manual dump-and-restore workaround as the final migration method.
4. Delivery Layer - Nginx Ingress + Azure CDN Front Door
Configured Nginx Ingress Controller inside AKS for internal cluster routing and TLS termination. Set up Azure CDN Front Door as the global entry point - handling:
- Global load balancing and traffic routing
- DDoS protection
- SSL/TLS at the edge
- Caching for static assets via Azure Storage
This delivery layer replaced the combination of AWS ALB, CloudFront, and S3 that was in place on the AWS side.
5. Environment Sync & DNS Cutover
Every image deployed to AWS was also deployed to Azure, so both environments ran the same versions throughout the migration. Azure was never behind AWS, which turned the cutover into a traffic switch rather than a release.
DNS stayed on Cloudflare for the whole migration. The cutover followed a fixed sequence:
- Lower the TTL: Reduced the TTL on the production records before the flip, so resolvers would pick up the change within a short window and stop serving the old endpoints.
- Flip: Pointed the records at the Azure endpoints behind Azure CDN Front Door.
- Keep AWS live: Left the AWS environment running on its original endpoints for a couple of days after the flip. Clients still holding cached records kept reaching the old servers, so no requests were dropped, and the records could be pointed back if a problem appeared.
- Decommission: Shut down the AWS servers only after confirming they were receiving no traffic from external networks.
6. CI/CD Migration - Jenkins → Azure DevOps
Re-engineered Jenkins pipelines into Azure Pipelines integrated with Azure DevOps. The new pipeline architecture was deliberately cleaner than what it replaced - this migration was used as an opportunity to pay down CI/CD technical debt and establish repeatable, automated deployments post-migration.
7. Monitoring & Observability
Deployed Azure Monitor, Application Insights, and Log Analytics to establish a standardized observability framework. Set up real-time alerting to replace the Google Chat/Telegram alerting that was running on AWS.
Technology Stack
| Category | Source (AWS) | Target (Azure) |
|---|---|---|
| Compute | EC2 (Docker Compose), EKS | AKS with HPA + Node Autoscaling |
| Databases | AWS RDS (PostgreSQL) | Azure Database for PostgreSQL |
| Container Registry | AWS ECR | Azure Container Registry |
| CI/CD | Jenkins | Azure DevOps + Azure Pipelines |
| Ingress | AWS ALB | Nginx Ingress Controller |
| CDN / Edge | CloudFront | Azure CDN Front Door |
| Storage | S3 | Azure Storage |
| Monitoring | CloudWatch | Azure Monitor + Application Insights |
| IaC | Manual | Terraform |
Quantified Impact
| Metric | Result |
|---|---|
| Business downtime | Minimal |
| Cloud cost reduction | 20% via right-sizing and reserved capacity planning |
| Deployment model | Docker Compose on EC2, EKS → Kubernetes with HPA and autoscaling |
| CI/CD | Manual Jenkins → automated Azure Pipelines |
| Cutover | Cloudflare DNS flip with pre-lowered TTL; AWS kept live until external traffic stopped |
| Database migration | Azure Database Migration Service, configuration fixed and validated on a dummy instance before the production migration |
Full enterprise migration. Least downtime possible. EC2 + Docker Compose, EKS → AKS with autoscaling. 20% cost reduction.
Cloud migrations fail when they're treated as pure infrastructure exercises. This one succeeded because it was treated as an engineering project with clear dependency sequencing, validated rollback plans at every step, and a DNS cutover that left the old environment live until traffic had drained.
The 20% cost reduction was the headline outcome. The more durable outcome was a modernized, governable infrastructure - migrating from Docker Compose to AKS with autoscaling was not just a cloud-provider switch but a genuine architectural improvement that the engineering team could build on confidently.