AWS vs Azure: Field-Engineered Migration and Service Comparison
Cloud inertia is real—especially for organizations with entrenched workloads on AWS and pressure to standardize on Azure. Whether it’s compliance, negotiated discounts, or ecosystem alignment, a clean migration from AWS to Azure demands more than mapping features. This post focuses on pragmatic steps, critical deltas, and technical traps often encountered during cross-cloud migration, illustrated with an application lift-and-shift scenario.
Cloud Service Mapping
Translating functionality isn’t always one-to-one. Here’s a crosswalk of major services, as referenced in production migrations (2023-24):
Function | AWS | Azure |
---|---|---|
Compute | EC2 (various families, e.g. t3.large) | Virtual Machines (D-series, e.g. D2s_v4) |
Kubernetes | EKS (v1.27) / ECS | AKS (v1.27+), Container Instances |
Stateless Functions | Lambda (Node.js 18, Python 3.9, etc.) | Azure Functions (Premium Plan, v4.x) |
Object Storage | S3 (Intelligent-Tiering, etc.) | Blob Storage (Hot/Cool/Archive Tiers) |
Relational DB | RDS (Aurora, MySQL 8.0, Postgres 13) | Azure DB for MySQL/Postgres (Flexible) |
Identity | IAM (with SSO/OIDC plugins) | Azure AD (Entra ID, Conditional Access) |
Networking | VPC, Security Groups, Transit Gateway | VNet, NSG, ExpressRoute, Route Tables |
Note: Automatic tooling (e.g., Azure Migrate) rarely resolves deeper semantic mismatches—expect some hands-on code/config rework.
Pricing and Cost Controls
Pricing surprises derail many first migrations. Azure’s “Hybrid Benefit” leans in Microsoft’s favor if you hold active Software Assurance. AWS’s cost disciplines are clearer with reserved and spot instance strategies, though spot can behave unexpectedly (auto-term at load, without warnings).
- Scrutinize ingress/egress fees; Azure can penalize cross-region moves more harshly.
- Both platforms support budgets and analytics (“Cost Explorer” on AWS, “Cost Management + Billing” on Azure). The Azure calculator is more conservative with defaults—double-check for stealthy “premium” toggles.
Side Note
Uncommitted PaaS options (like Aurora Serverless vs. Azure Flexible Server) behave differently under sustained workloads. Test for cold start delays or CPU throttling.
Migration Process: Breaking Down a Real Web Stack
Suppose you’re running an image-heavy Node.js web app on AWS: EC2 (Ubuntu 22.04 LTS), S3-backed file storage, and RDS/MySQL 8.0. The goal—stand up the same stack on Azure with minimal disruption.
1. VM Migration (from EC2 to Azure VM)
- Sizing: Azure’s D2s_v4 instance roughly matches a t3.large; adjust as needed.
- Firewalling: Translate Security Group rules into Azure NSG rules. Some ephemeral port behaviors differ (especially around Azure Load Balancers).
- Image Prep: Don’t use default images blindly. On Azure, Ubuntu “Pro” images trigger extra billing; standard 22.04 LTS suffices.
Provision and SSH in:
az vm create --name web-vm --resource-group rg-migrate \
--image Ubuntu2204 --size D2s_v4 --admin-username azureuser \
--public-ip-sku Standard
ssh azureuser@<public-ip>
Known issue: Azure VMs may have older agent preloads—update cloud-init and WALinuxAgent after launch.
2. S3 to Azure Blob Storage
- Tooling: Use AWS CLI (
aws s3 sync
) thenazcopy
. Direct S3-to-Blob sync isn’t natively supported (as of azcopy 10.22.0)—requires local intermediary.
# Local sync from S3
aws s3 sync s3://bucket-name ./temp-content/
# Upload to Blob Storage
azcopy copy './temp-content/*' 'https://<account>.blob.core.windows.net/<container>' --recursive
- Authentication: Set up both AWS credentials (~/.aws/credentials) and Azure SAS token.
- Gotcha: Blob Storage public access is disabled by default since 2022—adjust access level if your app reads from public URLs.
3. Database (#MySQL Example)
- Assessment: Not all MySQL flags and extensions are equal. Check for geo-partitioning, case-sensitivity, or custom plugins.
- Migration Tool: For <2TB,
mysqldump
+mysql
import is simplest. For continuous sync, use Azure Database Migration Service. - Network: Azure Database for MySQL expects client IP whitelisting—your new VM, jumpbox subnet, or all if you risk it.
mysqldump -h <rds-endpoint> -u app_user -p app_db > dump.sql
mysql -h <azure-mysql-host> -u app_user -p app_db < dump.sql
Note: Expect minor downtime on final cutover—DDL lock lag or replication lag is common.
4. Updating Application Endpoints
Don't overlook code/config rewrites for endpoint URL changes:
- S3 → Blob Storage: replace
https://s3.amazonaws.com/
withhttps://<account>.blob.core.windows.net/
- RDS → Azure DB Hostname.
- Hardcoding credentials in code? Fixed in staging, but always audit before final DNS swap.
Error Sample:
Common after a rushed migration:
Error: The specified blob does not exist. RequestId:...
Usually a naming/path mismatch; Azure Blob’s flat namespace differs from S3’s pseudo-directory semantics.
5. Automation and Infrastructure as Code
Applied Terraform scripts for both clouds (v1.5+ as of mid-2024). Cross-cloud IaC yields reusability, but tweaks are inevitable (tags, lifecycle hooks, naming schemes).
provider "azurerm" { features {} }
resource "azurerm_linux_virtual_machine" "example" {
// ...
}
Tip: Avoid large monolithic state files; split resources by env or service.
Security & Permissions
IAM to Azure RBAC isn’t a direct mapping. Avoid 1:1 role translation; instead, refactor permissions to match least privilege models per platform. Azure’s “Contributor” role is broad—tighten with custom roles if you care about privilege boundaries.
Non-Obvious Migration Notes
- Blob Storage metadata limits (8KB per object as of 2024) can break apps that depended on richer S3 metadata.
- OS-level disk optimizations differ. AWS EC2 supports EBS-optimized I/O by default; in Azure, enable Accelerated Networking.
- Azure throttles API requests more aggressively. Batch data transfers, or expect 429 throttling errors.
Summary
Cloud migrations are rarely just table-stakes service swaps. Each platform expresses features, billing, and edge behaviors differently, so model, test, then execute—ideally with blue/green deployments and end-to-end validation before decommissioning AWS resources.
No migration playbook is perfect, but firsthand trial—migrating a single EC2+S3+RDS stack to Azure equivalents—can flush out non-obvious issues early. Use automation, expect some “broken windows,” and build post-migration monitoring as early as possible.
Further questions, or want a deeper dive into serverless, managed Kubernetes, or hybrid patterns? Ping for technical case studies or reference architectures in future posts.