LogoLogo
  • Welcome to Release
  • Getting started
    • Quickstart
    • Create an account
    • Prepare to use Release
    • Create an application
      • Create custom application
      • Create from template
      • Servers vs runnables
    • Create an environment
  • Guides and examples
    • Domains and DNS
      • Manage domains
      • DNS and nameservers
        • Configure GoDaddy
        • Configure Cloudflare
        • Configure Namecheap
        • Other DNS hosts
      • Routing traffic
    • Example applications
      • Full stack voting app
      • Flask and RDS counter app
      • Static site with Gatsby
      • Golang with Postgres and Nginx
      • WordPress with MySQL
      • Spring and PostgreSQL
      • Terraform and Flask
      • OpenTelemetry demo
      • Load balancer with hostname
      • Static JavaScript service
      • SSH bastion access to services
      • ngrok and OAuth for private tunnels
      • Using OAuth Proxy
      • Hybrid Docker and static site
      • App Imports: Connecting two applications
      • Example library
    • Running instances
      • Cron jobs
      • Jobs
      • Using Helm charts
      • Using terminal
      • Viewing logs
      • Troubleshooting
        • ImagePullBackoff error
        • CrashLoopBackoff error
        • Exit codes
        • OOM: out of memory
    • Advanced guides
      • Containers guide
      • Application guide
      • Kubernetes guide
      • Create a cluster
      • Upgrade a cluster
      • Managing node groups
      • Patch node groups
      • Hostnames and rules
      • Serve traffic on multiple ports
      • Configure access to your K8s cluster
      • Designing for multiple environments
      • Microservices architecture
      • Monitoring your clusters
      • Performance tuning
      • Visibility and monitoring
      • Working with data
        • Container-based data
        • Seeding and migration
        • Cloud-provided data
        • Golden images
        • Third party
      • Pausing Instant Datasets
        • Application pausing schedules
        • Pause/resume environments
      • Infrastructure as code
        • Terraform
  • Reference documentation
    • Account settings
      • Account info
      • Managing users
      • Build settings
        • Build arguments
        • Build SSH keys
      • Add integrations
      • View clusters and cloud integrations
      • Add datasets
      • Environment handles
    • Workflows in Release
      • Stages of workflows
      • Serial deployments
      • Parallel deployments
      • Rolling deployments
      • Rainbow deployments
    • Networking
      • Network architecture (AWS)
      • Network architecture (GCP)
      • Ingresses
      • IP addresses
      • Cloud-provided services
      • Third-party services
    • Release environment versioning
    • Application settings
      • Application Template
        • Schema definition
      • Default environment variables
      • GitHub
      • Pull requests
      • GitOps
      • Just-in-time file mounts
      • Primary App Link
      • Create application FAQ
      • App-level build arguments
      • Parameters
      • Workspaces
    • End-to-end testing
    • Environment settings
      • Environment configuration
      • Environment variables
        • Environment variable mappings
        • Secrets vaults
        • Using Secrets with GitOps
        • Kubernetes Secrets as environment variables
        • Managing legacy Release Secrets
    • Environment expiration
    • Environment presets
    • Instant datasets on AWS
    • Instant datasets on GCP
    • Instant dataset tasks
      • Tonic Cloud
      • Tonic On-Premise
    • Cloud resources
    • Static service deployment
    • Helm
      • Getting started
      • Version-controlled Helm charts
      • Open-source charts
      • Building Docker images
      • Ingress and networking
      • Configuration
    • GitOps
    • The .release.yaml file
    • Docker Compose conversion support
    • Reference examples
      • Adding and removing services
      • Managing service resources
      • Adding database containers to the Application Template
      • Stock Off-The-Shelf Examples
    • Release API
      • Account Authentication
      • Environments API
        • Create
        • Get
        • Setup
        • Patch
      • User Authentication
      • Environment Presets API
        • Get Environment Preset List
        • Get Environment Preset
        • Put Environment Preset
  • Background concepts
    • How Release works
  • Frequently asked questions
    • Release FAQ
    • AWS FAQ
    • Docker FAQ
    • JavaScript FAQ
  • Integrations
    • Integrations overview
      • Artifactory integration
      • Cloud integrations (AWS)
        • AWS guides
        • Grant access to AWS resources
        • AWS how to increase EIP quota
        • Control your EKS fleet with systems manager
        • Managing STS access
        • AWS Permissions Boundaries
        • Private ECR Repositories
        • Using an Existing AWS VPC
        • Using an Existing EKS Cluster
      • Docker Hub integration
      • LaunchDarkly integration
      • Private registries
      • Slack integration
      • Cloud integrations (GCP)
        • GCP Permissions Boundary
      • Datadog Agent
      • Doppler Secrets Manager
      • AWS Secrets Management
    • Source control integrations
      • GitHub
        • Pull request comments
        • Pull request labels
        • GitHub deployments
        • GitHub statuses
        • Remove GitHub integration
      • Bitbucket
      • GitLab
    • Monitoring and logging add-ons
      • Datadog
      • New Relic
      • ELK (Elasticsearch, Logstash, and Kibana)
  • Release Delivery
    • Create new customer integration
    • Delivery guide
    • Release to customer account access controls
    • Delivery FAQs
  • Release Instant Datasets
    • Introduction
    • Quickstart
    • Security
      • AWS Instant Dataset security
    • FAQ
    • API
  • CLI
    • Getting started
    • Installation
    • Configuration
    • CLI usage example
    • Remote development environments
    • Command reference
      • release accounts
        • release accounts list
        • release accounts select
      • release ai
        • release ai chat
        • release ai config-delete
        • release ai config-init
        • release ai config-select
        • release ai config-upsert
      • release apps
        • release apps list
        • release apps select
      • release auth
        • release auth login
        • release auth logout
      • release builds
        • release builds create
      • release clusters
        • release clusters exec
        • release clusters kubeconfig
        • release clusters shell
      • release datasets
        • release datasets list
        • release datasets refresh
      • release deploys
        • release deploys create
        • release deploys list
      • release development
        • release development logs
        • release development start
      • release environments
        • release environments config-get
        • release environments config-set
        • release environments create
        • release environments delete
        • release environments get
        • release environments list
        • release environments vars-get
      • release gitops
        • release gitops init
        • release gitops validate
      • release instances
        • release instances exec
        • release instances logs
        • release instances terminal
  • Release.ai
    • Release.ai Introduction
    • Getting Started
    • Release.ai Templates
    • Template Configuration Basics
    • Using GPU Resources
    • Custom Workflows
    • Fine Tuning LlamaX
    • Serving Inference
Powered by GitBook
On this page
  • Set up an RDS instance
  • Identify the security group of your node group in AWS
  • Create the RDS database
  • Build the application
  • Write the app.py file
  • Write the templates/index.html file
  • Write the Dockerfile
  • Write the requirements.txt file
  • Write the docker-compose.yaml file
  • Deploy the application to Release
  • Create the application

Was this helpful?

  1. Guides and examples
  2. Example applications

Flask and RDS counter app

PreviousFull stack voting appNextStatic site with Gatsby

Last updated 1 year ago

Was this helpful?

Let's walk through an end-to-end example of building a basic counting app using:

  • Flask

  • PostgreSQL

  • RDS (AWS Relational Database Service)

We'll deploy the Flask application into our Release cluster and configure a security group to allow the nodes in the cluster to communicate with the RDS database. You can use a similar method to configure access to other cloud services, such as Redshift, Elasticache, or Redis.

Our final setup will look like this:

Note how the database and node group exist in the same VPC and use a common security group to communicate.

Set up an RDS instance

We'll create a small, free-tier RDS instance for this demonstration, but for a production application, you'll want to tweak the settings regarding the number of instances, multi-region deployments, backups, and so on. If you already have an RDS database, you'll just need to configure it to:

  • Share a VPC with your Release node group.

  • Share a security group with your Release node group.

Identify the security group of your node group in AWS

When you set up a new cluster and node group in Release, an EC2 launch template was automatically created for you with a default security group. We'll need to find this security group that your worker nodes already use so we can assign it to the database.

Log in to your Release account, and take note of your cluster context and node group name, as both of these are used in the name of the security group. You can see how to find each in the image below.

Also note which region your cluster is running in.

Now log in to your AWS account and navigate to the EC2 dashboard for the same region as your Release cluster. You should see at least one (and probably more) EC2 instances that are worker nodes for your cluster. You can identify them as they have the same cluster context and node group name that we noted in the Release control panel in their name, followed by the suffix -Node.

Select one of these worker nodes and navigate to Actions -> Security -> Change Security Groups, as shown below.

Don't make any changes here, but note the name of the security group and then press Cancel.

Finally, back on the main EC2 page, note the VPC ID of the worker node too. You can find it as shown in the image below.

Create the RDS database

Now navigate to the RDS dashboard and choose to create a new database.

The most important settings to change are:

  • The VPC - Make sure you create the database in the same VPC as your Release clusters.

  • The security group - Add the same security group as the one you noted earlier.

For this demo, we left most of the default settings for a free-tier Postgres database, as detailed below.

Leave the default database creation method as Standard create and choose PostgreSQL as the database type.

Choose Free tier, name your database something meaningful, and choose a strong password (note this somewhere safe).

Set the VPC and security group to match the settings from your Release EC2 worker node, which we noted in the previous section.

Scroll to the bottom and click Create database.

The database will take a few minutes to initialize. Once it's ready, navigate to it from the RDS dashboard and note the endpoint, as shown below.

You now have an RDS database that your Release cluster can communicate with. To complete the example, we'll build a basic Flask application that uses this database and deploy it into our cluster.

Build the application

For the demo, we'll build a very basic "counter" application that counts the number of times the Count button has been pressed. It'll look like this when it's up and running:

Our full project will have the following directory structure. We'll use a Docker Compose file even though we're only running a single container to make it easier to extend the app. We've called our app count, and placed all the application code in an app.py file and the frontend code in templates/index.html.

Create a directory for the overall project, a subdirectory called count for the Python application, and a subdirectory in the count directory called templates for the frontend. In the count directory, create blank files for app.py, Dockerfile, and requirements.txt. In the templates directory, create a blank file called index.html. In the outer project directory, create a blank file called docker-compose.yml.

Write the app.py file

Our app.py file uses Flask-SQLAlchemy as an ORM. First we get credentials from our environment (we'll set these up later), and then we define a basic counts object, which has an automatic primary key and a single field that always stores 1.

We then initialize the database and define a hello() method. When a user visits the page, we'll count the number of records in the database. If the user presses the Count button, we'll create a new count object, which will have the effect of incrementing the total.

Finally, we run the application on port 80 with debug turned on.

Add the following code to the count/app.py file:

from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
import traceback
import os

user = os.environ.get("POSTGRES_USER")
pw = os.environ.get("POSTGRES_PASSWORD")
host = os.environ.get("POSTGRES_HOST")
db = os.environ.get("POSTGRES_DATABASE_NAME")
DB_URL = f"postgresql+psycopg2://{user}:{pw}@{host}/{db}"
print(DB_URL)

app = Flask(__name__)

app.config["SQLALCHEMY_DATABASE_URI"] = DB_URL
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

db = SQLAlchemy(app)


class counts(db.Model):
    id = db.Column("count_id", db.Integer, primary_key=True)
    value = db.Column(db.Integer)


try:
    db.create_all()
except Exception as e:
    print(e)
    print("couldn't initialize db")
    traceback.print_exc()


@app.route("/", methods=["POST", "GET"])
def hello():
    if request.method == "POST":
        c = request.form["countbutton"]
        count = counts(value=1)
        db.session.add(count)
        db.session.commit()

    total_counts = counts.query.count()
    return render_template("index.html", total=total_counts)


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=80, debug=True, threaded=True)

Note that we've taken some liberties here in terms of best practices to keep the code simple. Specifically, for production settings, you should:

  • Turn debug mode off in the last line.

  • Run db.create_all() in a separate once-off script rather than in the web application code.

  • Properly handle the exception rather than only logging the error if the database connection fails.

Write the templates/index.html file

Our frontend contains a basic form with a single button and a templated variable {{count}} to display the total. Add the following code to templates/index.html:

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
        <h3>Count</h3>
        <p>Total counts: {{total}}</p>
        <form id="countform" name='form' method="POST" action="/">
          <input id="countbutton" type="submit" name="countbutton" value="Count"></input>
        </form>
  </body>
</html>

Write the Dockerfile

For our Dockerfile, we'll extend the Python3 Alpine Docker image, as this has most of the packages we need while still being very slim. Add the following code to the count/Dockerfile file:

# Using official Python runtime base image
FROM python:3-alpine

# Set the application directory
WORKDIR /app

# Install our requirements.txt
ADD requirements.txt /app/requirements.txt

RUN apk add build-base

RUN apk add --no-cache supervisor \
    && python -m pip install --upgrade pip \
    && pip install -r requirements.txt

# Copy our code from the current folder to /app inside the container
ADD . /app

# Make port 80 available for links and/or publish
EXPOSE 80

# Define our command to be run when launching the container
CMD ["gunicorn", "app:app", "-b", "0.0.0.0:80", "--log-file", "-", "--access-logfile", "-", "--workers", "4", "--keep-alive", "0"]

This brings in a few more dependencies that we need to correctly install the psycopg2binary database driver, copies in our application code, installs our Python requirements, and runs the application using Gunicorn.

Write the requirements.txt file

Our application needs Flask (our web framework), Gunicorn (to act as a gateway between Flask and our webserver), Flask-SQLAlchemy (as an ORM to easily create objects in our database), and psycopg2-binary (as a driver to talk to PostgreSQL).

Flask
gunicorn
flask-sqlalchemy
psycopg2-binary

Write the docker-compose.yaml file

Finally, we'll initialize everything using Docker Compose. This step is not essential in our case as we have only a single Docker file, but real-world applications will usually tie together a few different containers so it's useful to have it in place. Add the following code to the top-level docker-compose.yml file:

version: "1"

services:
  count:
    build: ./count
    command: 
    - python 
    - app.py
    ports:
      - "5000:80"

This creates a single service (count) and builds the Docker file in our count directory.

We now have a full-stack application running. If you have Docker and Postgres running locally, you can set the expected environment variables and run docker-compose up to test that everything is working, otherwise we can skip straight to deploying it on Release and debugging any issues there.

Deploy the application to Release

To deploy the application to Release, you need to:

  • Push the application up to GitHub or other provider that you've integrated with Release.

  • Create a new application in Release.

  • Configure the environment variables to connect to the database.

Create the application

You can find detailed steps for doing this in our create your application guide, but we'll cover the most important steps below.

In your Release dashboard, choose to create a new application.

Select the repository that holds your application code and proceed to the next step. You can leave all the defaults in the generated Application Template.

In the "Build & Runtime Configurations" section, choose to Edit "Default Environment Variables", and add in the connection settings for the database.

The bottom of the file (after the comments) should look as follows (substituting in your own database endpoint and password that you set in AWS, and username and database name if you changed those from their defaults).

defaults: []
services:
  count:
  - key: POSTGRES_DATABASE_NAME
    value: postgres
  - key: POSTGRES_USER
    value: postgres
  - key: POSTGRES_PASSWORD
    secret: true
  - key: POSTGRES_HOST
    secret: true

Note how we define these under the count service (named in our docker-compose.yml file) so that these are only available to our main application service. We've also set the secret flag on the password and host fields to true, so these will be encrypted by Release at rest.

Click Start Build & Deploy and wait for the environment to come up. Once it's ready, you can click the URL in the section "Hosted URLs" to navigate to your running application.

If everything worked as expected, you should see the basic counting application running and be able to add to the count by clicking on the button.

To follow along, you should have a Release account configured with AWS, with a domain name and cluster already running. Follow the if you don't have these in place yet.

If you see an error or a blank page, to look for any errors, or to double check that the environment variables are set correctly by running, for example, echo $POSTGRES_USER.

quickstart guide
use the log viewer
use the terminal
Counter app and RDS in AWS VPC
Find the cluster identifier and node group name
Navigate to security groups for EC2 instance
Note the security group name
Get the VPC ID of an EC2 instance
Create a new RDS database
Choose Postgres
Choose free tier and set name and password
Set VPC and security group
Confirm create
Note RDS endpoint
An application showing a count button and the total recorded counts
Directory structure as tree output
Create new app
Edit environment variables
View hosted URL
Final app