Skip to main content

Command Palette

Search for a command to run...

Docker Containerized Flask App with AWS, Terraform, and PostgreSQL

Published
5 min readView as Markdown
A

AWS Cloud & DevOps Engineer | Cloud Computing | Linux | Terraform & CloudFormation | AWS (EC2, S3, Lambda, API Gateway, DynamoDB, IAM) | Docker | Jenkins | CI/CD Pipelines | MySQL | Java | Jira | Postman | Git/GitHub

✅ STAR Methodology for Project Explanation:


S – Situation:

In April 2025, I was working on a cloud and DevOps-focused hands-on project where the goal was to build a fully containerized Flask-based web application, ensure persistent data storage, and automate infrastructure provisioning on AWS. The objective was to practice and implement modern DevOps and cloud deployment techniques, reduce manual errors, and achieve consistent deployment in any environment.


T – Task:

My task was to:

  • Develop a Python Flask web app and Dockerize it.

  • Integrate PostgreSQL in a containerized setup.

  • Ensure data persistence using Docker Volumes.

  • Use Docker Compose to orchestrate multi-container deployment.

  • Provision AWS EC2 instances using Terraform (Infrastructure as Code).

  • Deploy and run the containers on AWS EC2, maintaining environment consistency and scalability.


A – Action (Step-by-Step):

  1. Flask Application Development:

    • Created a simple Flask app with APIs for form submission and data storage.

    • Used Flask-SQLAlchemy for connecting Flask with PostgreSQL.

  2. Dockerization:

    • Created a Dockerfile to containerize the Flask app.

    • Exposed the Flask app on port 5000.

    DockerfileCopyEditFROM python:3.9
    WORKDIR /app
    COPY requirements.txt .
    RUN pip install -r requirements.txt
    COPY . .
    CMD ["python", "app.py"]
  1. PostgreSQL Container + Docker Volumes:

    • Added a PostgreSQL container in docker-compose.yml.

    • Used Docker Volumes to persist database data even after container restarts.

    yamlCopyEditservices:
      db:
        image: postgres
        environment:
          POSTGRES_USER: user
          POSTGRES_PASSWORD: pass
          POSTGRES_DB: flaskdb
        volumes:
          - postgres_data:/var/lib/postgresql/data
    volumes:
      postgres_data:
  1. Docker Compose:

    • Defined multi-container setup for both Flask app and PostgreSQL.

    • Ensured inter-service communication using container names.

  2. Infrastructure Automation with Terraform:

    • Wrote main.tf to provision an EC2 instance with user-defined AMI, security group, and key pair.

    • Ensured instance provisioning in ap-south-1 with necessary security_groups to allow ports 22 (SSH), 5000 (Flask), 5432 (PostgreSQL if needed).

    hCopyEditresource "aws_instance" "flask_server" {
      ami           = "ami-0abcdef1234567890"
      instance_type = "t2.micro"
      key_name      = "cicd-keypair"
      ...
    }
  1. Deploying on AWS:

    • Connected to the EC2 instance using SSH.

    • Installed Docker and Docker Compose on the EC2 instance.

    • Cloned the project and ran docker-compose up --build.

    • Flask app and PostgreSQL were running with persistent data, even across reboots.


R – Result:

  • Reduced deployment time by 60% due to containerization.

  • Achieved 100% environment consistency with Docker.

  • 90% reduction in DB downtime using Docker Volumes.

  • Cut manual provisioning effort by 80% via Terraform.

  • The project was robust, scalable, and could be replicated in any environment.


🎯 10 Follow-up Interview Questions (with Suggested Answers):


1. Q: Why did you choose Docker for this project?
A: Docker allowed me to encapsulate dependencies and code into portable containers. It ensures consistent behavior across environments—development, testing, and production—solving the "it works on my machine" problem.


2. Q: Why PostgreSQL? Why not MySQL or SQLite?
A: PostgreSQL offers powerful features like advanced indexing, JSON support, and ACID compliance. It’s also well-supported in production environments and integrates seamlessly with Flask via SQLAlchemy.


3. Q: How did Docker Volumes help you in this project?
A: Docker Volumes stored PostgreSQL data outside the container lifecycle. Even if the database container stopped or was recreated, the data persisted. This was crucial for maintaining user-submitted data.


4. Q: What is the role of Docker Compose here?
A: Docker Compose orchestrated multi-container applications using a single YAML file. It simplified the setup by allowing one command (docker-compose up) to launch Flask and PostgreSQL containers simultaneously.


5. Q: Why did you choose EC2 over ECS or Lambda for deployment?
A: Since the focus was on learning core deployment and provisioning using Terraform, EC2 offered better control for manual Docker and Compose setup. It was a conscious decision to understand and control every layer.


6. Q: What were your Terraform modules composed of?
A: The Terraform setup included AWS provider config, EC2 instance block, security groups for SSH and HTTP access, key pair for access, and output variables to capture instance details.


7. Q: How did you ensure Flask and DB communicated in Docker?
A: Docker Compose automatically creates a shared network. I used the service name (db) as the hostname in Flask’s DB connection string (postgresql://user:pass@db:5432/flaskdb).


8. Q: What if you need to scale this setup?
A: I would move to ECS or EKS for orchestration, use RDS for managed DB, and configure ALB for traffic distribution. I would also implement CI/CD via Jenkins or GitHub Actions.


9. Q: How is this project useful in real-world scenarios?
A: It replicates a common web application architecture: containerized microservices, persistent storage, cloud provisioning with IaC, and simplified deployment—all aligning with modern DevOps practices.


10. Q: How did you test the app after deployment?
A: After deploying to EC2, I accessed the Flask app via the public IP and tested endpoints using Postman. For database checks, I used Flask’s routes and sometimes connected directly via psql inside the container.


❗ 5 Challenges You Faced:


  1. Container Networking Issues:
    Initially, Flask couldn’t connect to PostgreSQL due to misconfigured hostnames. I learned to use service names defined in docker-compose.yml.

  2. Terraform Permissions:
    Faced IAM permission errors while provisioning EC2. Solved by assigning the right policies to my AWS user (like AmazonEC2FullAccess).

  3. Docker-Compose version mismatch on EC2:
    Docker Compose wasn’t installed by default. I had to manually install the right version compatible with Docker Engine.

  4. Flask DB URI Misconfiguration:
    Incorrect DB URI string led to SQLAlchemy errors. I debugged using logs and corrected the environment variables in Compose.

  5. Persistent Volume Cleanup:
    While testing, volume names overlapped and retained stale data. Solved by naming volumes explicitly and running docker volume prune carefully when needed.

More from this blog

The 5 Unbreakable Laws of DevOps

15 posts