The Challenge
When DataFlow Solutions asked me to migrate their entire infrastructure — 80 VMware virtual machines — to AWS, the requirement was clear: zero downtime. No maintenance windows. No service interruptions. Just a seamless transition that users wouldn't even notice.
Here's exactly how we did it over 6 months.
Phase 1: Assessment (Weeks 1–2)
Before touching a single server, we ran a complete inventory:
# Export VMware VM inventory
govc ls -json /datacenter/vm | jq '.elements[].Object.Config | {name: .Name, cpu: .Hardware.NumCPU, mem: .Hardware.MemoryMB, os: .GuestFullName}'
We categorized every VM into three buckets:
- Lift-and-shift — stateless apps that move as-is
- Replatform — apps that benefit from managed services (RDS, ElastiCache)
- Refactor — legacy apps that need rearchitecting
Phase 2: Terraform Infrastructure
We defined all AWS infrastructure as code:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = "dataflow-prod"
cidr = "10.0.0.0/16"
azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = false # HA setup
}
resource "aws_instance" "app_server" {
ami = data.aws_ami.rhel9.id
instance_type = "t3.large"
subnet_id = module.vpc.private_subnets[0]
tags = { Name = "app-server-01", Environment = "production" }
}
Phase 3: The Blue/Green Strategy
This was the key to zero downtime. We ran both environments in parallel:
- Stand up full AWS environment (green)
- Set up real-time data replication from on-prem to AWS
- Test green environment thoroughly
- Switch DNS with low TTL (60 seconds)
- Monitor for 48 hours
- Decommission on-prem (blue)
Phase 4: Data Replication
# Continuous MySQL replication to RDS
mysqldump --single-transaction --master-data=2 production |
ssh aws-bastion "mysql -h rds.endpoint.amazonaws.com production"
# Set up replication
mysql -h rds.endpoint -e "
CHANGE MASTER TO
MASTER_HOST='on-prem-mysql.internal',
MASTER_USER='replication',
MASTER_PASSWORD='${REPL_PASS}',
MASTER_LOG_FILE='mysql-bin.000042',
MASTER_LOG_POS=4;
START SLAVE;"
Results
After 6 months of careful execution:
- ✅ Zero downtime — not a single user-facing outage
- ✅ 40% cost reduction — from $18k/month to $10.8k/month
- ✅ 60% better performance — faster instances, better I/O
- ✅ Full IaC — entire infrastructure in Terraform
Lessons Learned
The biggest lesson: test your rollback plan as carefully as your migration plan. We had a fully tested rollback procedure for every phase. We never needed it, but knowing it worked gave us the confidence to proceed.