Flask + DynamoDB on Elastic Beanstalk
Topics: Elastic Beanstalk, Flask, DynamoDB, REST API, IAM, PaaS
Overview
This lab builds on previous excercise by integrating a Flask application with DynamoDB for data persistence. You'll deploy a RESTful API that performs CRUD operations on a DynamoDB table, all managed through Elastic Beanstalk's PaaS environment. The activity demonstrates serverless database architecture with managed application hosting.
Key Concepts
| Concept | Description |
|---|---|
| Boto3 | AWS SDK for Python to interact with DynamoDB |
| RESTful API | HTTP-based interface for CRUD operations |
| IAM Instance Profile | Role attached to EC2 for secure AWS service access |
| Environment Variables | Configuration values passed to application at runtime |
| Runtime.txt | Specifies Python version for Elastic Beanstalk |
| JSON Responses | Structured data format for API responses |
Prerequisites
- Active AWS account with billing enabled
- IAM permissions for Elastic Beanstalk, EC2, and DynamoDB
- Basic knowledge of Flask, REST APIs, and NoSQL databases
- Completion of Lab 18 (DynamoDB basics) recommended
Architecture Overview
Click to expand Architecture Diagram
Click to expand Architecture Diagram
Phase 1: Local Environment Preparation
Before deploying to AWS, prepare your project folder with the required files.
Project Structure
Create a folder named flask-ddb-lab containing exactly these four files:
application.py- Flask application coderequirements.txt- Python dependenciesProcfile- Gunicorn configurationruntime.txt- Python version specification
File Contents
application.py
application.py Code
from flask import Flask, request, jsonify
import boto3
import os
app = Flask(__name__)
REGION = os.getenv("AWS_REGION", "ap-south-1")
TABLE_NAME = os.getenv("TABLE_NAME", "Students")
dynamodb = boto3.resource("dynamodb", region_name=REGION)
table = dynamodb.Table(TABLE_NAME)
@app.route("/")
def home():
return "Flask + DynamoDB on Elastic Beanstalk is working!"
@app.route("/health")
def health():
return jsonify(status="ok")
# CREATE
@app.route("/student", methods=["POST"])
def create_student():
try:
data = request.get_json()
table.put_item(Item={
"StudentID": data["StudentID"],
"Name": data["Name"],
"Dept": data.get("Dept", "")
})
return jsonify(message="Student created"), 201
except Exception as e:
return jsonify(error=str(e)), 500
# READ
@app.route("/student/<student_id>", methods=["GET"])
def get_student(student_id):
try:
resp = table.get_item(Key={"StudentID": student_id})
item = resp.get("Item")
if not item:
return jsonify(error="Student not found"), 404
return jsonify(item)
except Exception as e:
return jsonify(error=str(e)), 500
# UPDATE
@app.route("/student/<student_id>", methods=["PUT"])
def update_student(student_id):
data = request.get_json()
resp = table.update_item(
Key={"StudentID": student_id},
UpdateExpression="SET #n = :n, Dept = :d",
ExpressionAttributeNames={"#n": "Name"},
ExpressionAttributeValues={":n": data["Name"], ":d": data.get("Dept", "")},
ReturnValues="UPDATED_NEW"
)
return jsonify(message="Student updated", updated=resp["Attributes"])
# DELETE
@app.route("/student/<student_id>", methods=["DELETE"])
def delete_student(student_id):
table.delete_item(Key={"StudentID": student_id})
return jsonify(message="Student deleted")requirements.txt
Flask
boto3
gunicornProcfile
web: gunicorn --bind 0.0.0.0:8000 application:appruntime.txt
python-3.11Packaging the Application
- Select all 4 files in the
flask-ddb-labfolder - On Windows/Mac: Right-click → Send to → Compressed (zipped) folder
- On Ubuntu/Linux: Open terminal in the
flask-ddb-labfolder and run:
zip flask-ddb-lab.zip application.py requirements.txt Procfile runtime.txt- Name the file:
flask-ddb-lab.zip
IMPORTANT
When you open the zip file, all 4 files should be at the root level, NOT inside a subfolder. Elastic Beanstalk expects the application code at the root of the archive.
Phase 2: AWS Resource Configuration
Create DynamoDB Table
- Navigate to DynamoDB → Tables → Create table
- Configure the table:
- Table name:
Students - Partition key:
StudentID(Type: String)
- Table name:
- Click Create table
- Wait for the table status to become Active
Create IAM Role for EC2 Instances
The IAM role grants EC2 instances permission to access DynamoDB.
- Navigate to IAM → Roles → Create role
- Trusted entity type: AWS service
- Use case: EC2
- Click Next
- Attach permissions policy: Search for and select
AmazonDynamoDBFullAccess - Click Next
- Role name:
EB-EC2-DynamoDB-Role - Click Create role
TIP
Once this role is created, it will be available for all future Elastic Beanstalk environments. You only need to create it once per AWS account. For production, create a custom policy with minimal DynamoDB permissions instead of full access.
Phase 3: Elastic Beanstalk Deployment
Create Application Environment
- Navigate to Elastic Beanstalk → Create application
- Configure application:
- Application name:
flask-ddb-lab - Platform: Python
- Application code: Select Sample application (for initial setup)
- Presets: Single instance (free tier eligible)
- Application name:
Configure Service Access
- Service role: Leave as default (auto-created)
- EC2 instance profile: Select
EB-EC2-DynamoDB-Role - Click Next through remaining configuration screens
- Click Submit
Wait 5-10 minutes for the environment to launch. The environment health should show Ok (green) when ready.
Verify Sample Application
- In the environment dashboard, locate the Domain URL (e.g.,
flask-ddb-lab.us-east-1.elasticbeanstalk.com) - Open the URL in your browser
- You should see the default Python sample application
Deploy Your Application
- In the environment dashboard, click Upload and deploy
- Click Choose file and select
flask-ddb-lab.zip - Version label:
v1 - Click Deploy
Wait for the deployment to complete (health status returns to Ok).
Phase 4: Environment Variables Configuration
Environment variables tell your Flask app which DynamoDB table and region to use.
- In the environment dashboard, click Configuration (left sidebar)
- Locate the Updates category and click Edit
- In the Platform software section, scroll to Environment variables
- Add these properties:
| Name | Value |
|---|---|
TABLE_NAME | Students |
AWS_REGION | ap-south-1 |
- Click Apply
- Wait for the environment to finish updating (2-3 minutes)
WARNING
Without these environment variables, your application will fail to connect to DynamoDB. The Flask app reads these values using os.getenv() with defaults, but explicit configuration ensures correct region and table name.
Phase 5: Testing & Verification
Health Check
Open AWS CloudShell (or your local terminal) and test the health endpoint:
curl http://<your-eb-domain>/healthExpected output:
{"status":"ok"}CRUD Operations Testing
Replace <your-eb-domain> with your actual Elastic Beanstalk domain URL.
Create a Student (POST)
curl -X POST http://<your-eb-domain>/student \
-H "Content-Type: application/json" \
-d '{"StudentID":"101","Name":"Anita","Dept":"MCA"}'Expected response:
{"message":"Student created"}Read Student Data (GET)
curl http://<your-eb-domain>/student/101Expected response:
{"StudentID":"101","Name":"Anita","Dept":"MCA"}Update Student Data (PUT)
curl -X PUT http://<your-eb-domain>/student/101 \
-H "Content-Type: application/json" \
-d '{"Name":"Anita S","Dept":"MCA-III"}'Expected response:
{"message":"Student updated","updated":{"Name":"Anita S","Dept":"MCA-III"}}Delete Student (DELETE)
curl -X DELETE http://<your-eb-domain>/student/101Expected response:
{"message":"Student deleted"}Verify in DynamoDB Console
- Navigate to DynamoDB → Tables → Students
- Click Explore table items
- Confirm the data reflects your test operations
Validation
- Local Setup: Verify all files are created and Flask app runs locally.
- Packaging: Confirm ZIP contains files at root level.
- Deployment: Check EB environment health is "OK" and domain is accessible.
- API Testing: Test all CRUD endpoints with curl commands.
- Database: Verify data persistence in DynamoDB console.
- Environment Variables: Ensure TABLE_NAME and AWS_REGION are set.
Validation
- Elastic Beanstalk Environment: Health status shows "Ok" in EB console
- Application URL: Accessible and returns "Flask + DynamoDB on Elastic Beanstalk is working!" on root path
- DynamoDB Table: "Students" table exists with correct partition key
- API Endpoints: All CRUD operations (POST, GET, PUT, DELETE) work correctly
- IAM Role: EB-EC2-DynamoDB-Role attached to EC2 instance with proper permissions
- Environment Variables: TABLE_NAME and AWS_REGION properly configured
Common Issues & Solutions
Troubleshooting
Issue: Application returns 500 errors
Causes:
- Missing environment variables (
TABLE_NAME,AWS_REGION) - Incorrect IAM role attached to EC2 instance
- DynamoDB table doesn't exist or wrong name
Solution:
- Check environment variables in Configuration → Software
- Verify IAM role in Configuration → Security
- Confirm table name matches exactly (case-sensitive)
Issue: Environment health shows "Degraded"
Causes:
- Application code errors
- Missing dependencies in
requirements.txt - Incorrect file structure in zip
Solution:
- Check logs: Logs → Request logs → Last 100 lines
- Verify all 4 files are at zip root (not in subfolder)
- Ensure
application.pyhas the correct variable name (app)
Issue: 502 Bad Gateway error
Causes:
- Procfile missing port binding (should bind to 8000)
- Nginx proxy configuration mismatch
Solution:
- Ensure Procfile is:
web: gunicorn --bind 0.0.0.0:8000 application:app - Redeploy the application
- Check
/var/log/nginx/error.logfor upstream connection errors
Issue: Permission denied accessing DynamoDB
Cause: IAM role not attached or incorrect permissions
Solution:
- Go to Configuration → Security → Edit
- Verify IAM instance profile is set to
EB-EC2-DynamoDB-Role - Confirm role has
AmazonDynamoDBFullAccesspolicy attached
Cost Considerations
Cost Considerations
- Elastic Beanstalk: ~$0.01/hour for t3.micro EC2 (free tier eligible)
- DynamoDB: On-demand pricing (~$1.25/million writes, $0.25/million reads)
- Tip: Terminate EB environment and delete DynamoDB table immediately after lab. Monitor via AWS Cost Explorer.
Cleanup
Cleanup
To avoid ongoing charges:
Elastic Beanstalk:
- Go to your environment → Actions → Terminate environment
- Confirm by typing the environment name
DynamoDB:
- Go to DynamoDB → Tables → Students
- Click Delete → Confirm deletion
IAM Role (optional):
- Can be retained for future labs
- Or delete via IAM → Roles →
EB-EC2-DynamoDB-Role→ Delete
Result
Successfully deployed a Flask REST API integrated with DynamoDB on Elastic Beanstalk. Demonstrated serverless database operations, secure IAM access, and managed application deployment with full CRUD functionality.
Viva Questions
- What is the role of Boto3 in this Flask application?
- Why do we use IAM instance profiles instead of access keys?
- What are the benefits of deploying on Elastic Beanstalk?
- How does DynamoDB differ from traditional relational databases?
- What is the purpose of the Procfile in Elastic Beanstalk deployments?
Quick Start Guide
Quick Start Guide
- Create a Flask application with
application.py,requirements.txt,Procfile, andruntime.txt. - Package files into a ZIP with files at the root level.
- Create a DynamoDB table named
StudentswithStudentIDas the partition key. - Create an IAM role
EB-EC2-DynamoDB-Rolewith DynamoDB access. - Create an Elastic Beanstalk environment with the IAM role attached.
- Configure environment variables for
TABLE_NAMEandAWS_REGION. - Deploy the application ZIP to Elastic Beanstalk.
- Test CRUD operations using curl commands.
