Cloud Migration Strategies Cheat Sheet
Covers the six R's of cloud migration, migration phases, and key considerations for moving workloads from on-premises to the cloud.
The 6 R's of Migration
AWS's standard framework for categorizing migration approaches.
- Rehost (Lift and Shift)- Move workloads as-is to cloud infrastructure with minimal changes
- Replatform (Lift, Tinker, and Shift)- Make small optimizations during migration, e.g. moving to a managed database
- Repurchase (Drop and Shop)- Replace with a SaaS product, e.g. moving from self-hosted CRM to Salesforce
- Refactor / Re-architect- Redesign the application to be cloud-native, e.g. breaking a monolith into microservices
- Retire- Decommission applications no longer needed
- Retain- Keep certain workloads on-premises, e.g. due to compliance or dependencies
Migration Phases
Typical stages of a structured migration project.
- Assess- Inventory applications, dependencies, and business drivers for migration
- Mobilize- Build the landing zone, migration tooling, and skills readiness
- Migrate & Modernize- Execute wave-based migrations, validating each application post-move
- Operate & Optimize- Continuously right-size, monitor cost, and improve post-migration
Example: AWS Application Discovery Agent Install
Gathering on-prem server data to plan a migration wave.
# Install AWS Application Discovery Agent on an on-prem serversudo ./aws-discovery-agent.sh install \ --region us-east-1 \ --key-id AKIA... \ --secret-key ...# Verify agent registrationsudo /opt/aws/discovery/bin/aws-discovery-daemon status
AWS DMS: Full Load + CDC for Near-Zero-Downtime Cutover
Migrating a live database with change data capture so the cutover window is minutes, not a multi-hour maintenance freeze.
# Create a replication instanceaws dms create-replication-instance \ --replication-instance-identifier migration-repl \ --replication-instance-class dms.r5.large \ --allocated-storage 100# Create a task that does a full load, then streams ongoing changes (CDC)aws dms create-replication-task \ --replication-task-identifier onprem-to-rds \ --source-endpoint-arn arn:aws:dms:us-east-1:123456789012:endpoint:src-oracle \ --target-endpoint-arn arn:aws:dms:us-east-1:123456789012:endpoint:tgt-rds-pg \ --replication-instance-arn arn:aws:dms:us-east-1:123456789012:rep:migration-repl \ --migration-type full-load-and-cdc \ --table-mappings file://table-mappings.json# Monitor replication lag before cutoveraws dms describe-replication-tasks \ --filters Name=replication-task-id,Values=onprem-to-rds \ --query 'ReplicationTasks[0].ReplicationTaskStats'
Strangler Fig Pattern: Incremental Refactor via Routing Rules
Route traffic feature-by-feature to a new service while the legacy monolith still serves everything else, avoiding a risky big-bang rewrite.
# nginx acting as the strangler facade in front of legacy + new serviceslocation /api/v1/inventory/ { # Newly migrated microservice proxy_pass http://inventory-service.internal:8080/;}location /api/v1/ { # Everything not yet migrated falls through to the legacy monolith proxy_pass http://legacy-monolith.internal:80/;}# Canary a single migrated route to 10% of traffic before full cutoversplit_clients "${remote_addr}${request_uri}" $inventory_backend { 10% inventory-service.internal:8080; * legacy-monolith.internal:80;}
AWS Application Migration Service (MGN) Rehost Flow
Automated block-level replication for lift-and-shift rehosting of servers with minimal cutover downtime.
# Install the MGN replication agent on the source server (Linux)wget -O ./aws-replication-installer-init.py \ https://aws-application-migration-service-us-east-1.s3.us-east-1.amazonaws.com/latest/linux/aws-replication-installer-init.pysudo python3 aws-replication-installer-init.py \ --region us-east-1 --no-prompt --aws-access-key-id AKIA... --aws-secret-access-key ...# Check replication status for all source serversaws mgn describe-source-servers --region us-east-1 \ --query 'items[].{Server:sourceServerID,State:dataReplicationInfo.dataReplicationState}'# Launch a test instance from the replicated data without affecting productionaws mgn start-test --source-server-ids s-1234567890abcdef0# Once validated, cut over for realaws mgn start-cutover --source-server-ids s-1234567890abcdef0
Wave Planning Beyond the 6 R's
Practical factors that decide sequencing once you've picked a migration approach per application.
- Dependency Mapping- Use discovery tooling to graph which apps talk to which; migrate tightly coupled apps in the same wave
- Data Gravity- Move the database before (or with) the applications that query it heavily to avoid high cross-region latency
- Low-Risk-First Sequencing- Start waves with low-complexity, low-criticality apps to build team confidence and refine the runbook
- Network Path Validation- Confirm VPN/Direct Connect bandwidth and latency support hybrid operation during the migration window
- Rollback Criteria- Define objective go/no-go metrics (error rate, latency) per wave before cutover, not a subjective judgment call
- Freeze Windows- Coordinate change freezes on the source system so drift doesn't invalidate the migrated snapshot
Terraform: Standing Up the Target Landing Zone Ahead of Cutover
Provisioning target-cloud infrastructure as code so it's repeatable and reviewed before any workload moves.
module "landing_zone" { source = "./modules/landing-zone" vpc_cidr = "10.20.0.0/16" environment = "migration-target" enable_direct_connect = true dx_gateway_id = "dxgw-0123456789abcdef0" subnets = { app = ["10.20.1.0/24", "10.20.2.0/24"] data = ["10.20.11.0/24", "10.20.12.0/24"] }}resource "aws_dx_gateway_association" "onprem_link" { dx_gateway_id = "dxgw-0123456789abcdef0" associated_gateway_id = module.landing_zone.vpn_gateway_id allowed_prefixes = ["10.20.0.0/16"]}
Migrate in waves grouped by application dependency, not by team ownership — splitting a tightly coupled app across waves causes cross-environment latency and broken integrations mid-migration.