DEV Community

Cover image for Migrating a Legacy Monolith to Serverless on AWS(Strangler Fig Pattern)
nash9
nash9

Posted on

Migrating a Legacy Monolith to Serverless on AWS(Strangler Fig Pattern)

πŸš€ Overview

This project demonstrates how to migrate a legacy monolithic application to a serverless architecture using the Strangler Fig Pattern on AWS, leveraging:

  • Terraform for Infrastructure as Code
  • Python for application logic

The goal is to show how new features can be carved out from a monolith and replaced with serverless componentsβ€”without breaking the existing system.

πŸ— Architecture

The solution consists of major components:

Legacy Monolith
Python Flask app running on an EC2 instance.

New Serverless Components
AWS Lambda functions,DynamoDB tables,API Gateway (The Strangler Facade)
Routes traffic to the appropriate backend (legacy or new).

πŸ”Ž Route Behavior
`/users β†’ Legacy Route
Proxies traffic to EC2 running the Flask app.

/products β†’ Migrated Route
Handled by Lambda + DynamoDB.

/products/restock β†’ Enhanced Route
POST request that simulates a failure 60% of the time to demonstrate resiliency handling.`

πŸ–Ό Architecture Diagram

πŸ“¦ Prerequisites

Before deploying, ensure you have:

  • AWS Account (Free Tier eligible)
  • AWS CLI installed & configured (aws configure)
  • Terraform v1.0+
  • Postman or curl for testing

πŸ“ Project Structure

strangler-fig-aws-migration-demo/
β”‚
β”œβ”€β”€ README.md
β”œβ”€β”€ infra-terraform/
β”‚ β”œβ”€β”€ provider.tf
β”‚ β”œβ”€β”€ variables.tf
β”‚ β”œβ”€β”€ ec2.tf
β”‚ β”œβ”€β”€ dynamodb.tf
β”‚ β”œβ”€β”€ lambda.tf
β”‚ β”œβ”€β”€ apigateway.tf
β”‚ β”œβ”€β”€ outputs.tf
β”‚ β”œβ”€β”€ lambda_function/
β”‚ β”‚ └── lambda_function.py
β”‚ └── legacy_app/
β”‚ └── legacy_server.py

πŸš€ Deployment Instructions

1️⃣ Initialize Terraform

Inside infra-terraform:

terraform init

2️⃣ Deploy Infrastructure
terraform apply

Type yes when prompted.

⏳ Deployment takes ~2 minutes, plus an additional 3 minutes for the EC2 instance to install dependencies and start the legacy server.

3️⃣ Retrieve the API URL

Terraform will output something like:

api_url = "https://<random-id>.execute-api.us-east-1.amazonaws.com"

Copy this value for testing.

πŸ”¬ Testing Scenarios

Scenario 1: Legacy Route (/users)
Traffic routed to EC2 Flask app.

Scenario 2: Migrated Route (/products)
Traffic routed to Lambda + DynamoDB.

Scenario 3: Chaos Route (/products/restock)
A POST endpoint simulating 60% failure rate.

Request:

curl -X POST <api_url>/products/restock


Expected Behavior:

Chance Response
40% 200 OK β†’ {"status": "Restock Successful"}
60% 500 Internal Server Error β†’ Simulated external failure

πŸ›  Troubleshooting Guide

❌ 1. 502 Bad Gateway

Cause: API Gateway couldn't reach EC2 instance.
Fix:
Wait 2–3 minutes after deployment
Ensure EC2 is running
Re-run terraform apply

❌ 2. 400 Bad Request

Cause: Payload version mismatch.
Fix:
Ensure this is inside your Lambda integration block:
payload_format_version = "2.0"

❌ 3. 500 Internal Server Error

Cause: Expected behavior for chaos testing.
Fix:
Run the command multiple times or remove the failure logic in lambda_function.py.

❌ 4. 405 Method Not Allowed

Cause: Using GET on a POST-only route.
Fix:
Use the correct method:
curl -X POST <api_url>/products/restock

🧹 Cleanup (To Avoid Charges)

When finished, destroy all resources:

terraform destroy
Double-check the AWS Console to ensure everything is deleted.

Follow me for more.Thanks !!!

Top comments (0)