Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Flask

This example assumes you have already created your own Territory. If you have not, please refer to this guide.

In this tutorial we will be deploying our example application to CitadelHosts. We will upload the images that define our application to our Smart Image Registry. Then we will define our custom application in CitadelHosts. Finally, we will deploy that application to our own Territory instance.

Our Example Application

This Flask example application was intended to highlight Flask and it's ability to help user's design and create microservices in a minimal and efficient manner. We built a SaaS Metrics Dashboard. The application delivers some high level metrics that would be pertinent to a SaaS startup, such as Monthly Recurring Revenue (MRR) and Churn Rate.

The application is available on GitHub at: https://github.com/LiamJFitzpatrick/citadel-flask-example.

Uploading Custom Images To Your Smart Registry

The example application contains a Dockerfile for the Flask backend and and a Dockerfile.worker for the Python worker. These files define everything that our application needs to run. For our example, we have walkthroughs for deploying using GitHub Actions to build and upload your images or you can follow along the guide to build and deploy your images from your local machine using Docker.

Using GitHub Actions

An example deploy workflow is provided below. This will build the necessary images and upload them to your CitadelHosts account. You can clone the example repository and then push the code to your own GitHub repository. Whenever changes are pushed to your GitHub repository they will be automatically sent to your CitadelHosts registry. This is great to be able to enable automatic deployments.

.github/workflows/deploy.yml

name: Build and Push Container Images

on:
  push:
    branches:
      - develop
      - main
      - master
    tags:
      - 'v*'

env:
  REGISTRY: registry.citadelhosts.com
  FLASK_IMAGE_NAME: ${{ secrets.FLASK_IMAGE_NAME }}
  WORKER_IMAGE_NAME: ${{ secrets.WORKER_IMAGE_NAME }}

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to private registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ secrets.REGISTRY_USERNAME }}
          password: ${{ secrets.REGISTRY_PASSWORD }}

      - name: Extract metadata for Flask app
        id: flask-meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.FLASK_IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha

      - name: Extract metadata for Worker
        id: worker-meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.WORKER_IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha

      - name: Build and push Flask app image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ${{ steps.flask-meta.outputs.tags }}
          labels: ${{ steps.flask-meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Build and push Worker image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: ./Dockerfile.worker
          push: true
          tags: ${{ steps.worker-meta.outputs.tags }}
          labels: ${{ steps.worker-meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

This deploy workflow requires the following secrets in your repository:

  • FLASK_IMAGE_NAME: This is the name that the Flask backend will have in your CitadelHosts registry.
  • WORKER_IMAGE_NAME: This is the name that the worker will have in your CitadelHosts registry.
  • REGISTRY_USERNAME: This is your CitadelHosts username.
  • REGISTRY_PASSWORD: This is your CitadelHosts password.
Using Docker CLI

Getting and Building The Application

After you have cloned the repository, navigate into the newly created folder.

git clone https://github.com/LiamJFitzpatrick/citadel-flask-example.git
cd citadel-flask-example

Build the Flask backend image and the worker image.

docker build -t registry.citadelhosts.com/flask-example-backend:latest -f Dockerfile ./
docker build -t registry.citadelhosts.com/flask-example-worker:latest -f Dockerfile.worker ./

Authenticate your Docker CLI with the CitadelHosts.com Smart Image Registry. You will login using the same credentials you use to login to CitadelHosts.com.

docker login registry.citadelhosts.com

Push your newly built images to your registry.

docker push registry.citadelhosts.com/flask-example-backend:latest
docker push registry.citadelhosts.com/flask-example-worker:latest

Congrats! You have successfully uploaded the example application to your CitadelHosts account!

Defining Custom Applications

To define a custom application navigate to the Apps page and scroll down to the Create Application section (or click this link: https://citadelhosts.com/dashboard/apps#create-application).

This form allows you to define custom application configurations.

Step 1: Application Definition

The first step is to define the application. The table below shows suggested input values for our example.

LabelValueDescription
NameFlask ExampleThis is the name of your application and will appear in your App Library
DescriptionAn example cloud-native Flask application.A description for your custom application.

Step 2: Container Definition

The second step is to define the containers that will make up our application. Our example application consists of 5 containers, so you can hit Add Container for 5 containers. The suggested inputs are summarized in the tables below.

Container 1 Definition: Flask Backend

LabelValue
Name:backend
Start Order:4
Image:flask-example-backend:latest

Container 2 Definition: Python worker

LabelValue
Name:worker
Start Order:5
Image:flask-example-worker:latest

Container 3 Definition: Valkey

LabelValue
Name:valkey
Start Order:2
Image:Enter URL
docker.io/valkey/valkey:7-alpine

Container 4 Definition: RustFS

LabelValue
Name:rustfs
Start Order:1
Image:Enter URL
docker.io/rustfs/rustfs:latest

Container 5 Definition: RabbitMQ

LabelValue
Name:rabbitmq
Start Order:3
Image:Enter URL
docker.io/library/rabbitmq:3-management

Step 3: Container Configuration

The final step in defining your custom application is going to be to configure ports, volumes, and environment variables for each of the containers that make up your application. The necessary configuration for our example application is summarized in the sections below.

backend Configuration

Ports
Container Port:5000

Environment Variables:

KeyValue
VALKEY_HOSTlocalhost
VALKEY_PORT6379
S3_ENDPOINTlocalhost:9000
S3_ACCESS_KEYminioadmin
S3_SECRET_KEYminioadmin
S3_BUCKET_NAMEsaas-metrics-uploads
S3_USE_SSLfalse
RABBITMQ_HOSTlocalhost
RABBITMQ_PORT5672
RABBITMQ_USERguest
RABBITMQ_PASSguest
RABBITMQ_QUEUEmetrics-processing
SECRET_KEYdevsecretkey

worker Configuration

Environment Variables:

KeyValue
VALKEY_HOSTlocalhost
VALKEY_PORT6379
S3_ENDPOINTlocalhost:9000
S3_ACCESS_KEYminioadmin
S3_SECRET_KEYminioadmin
S3_BUCKET_NAMEsaas-metrics-uploads
S3_USE_SSLfalse
RABBITMQ_HOSTlocalhost
RABBITMQ_PORT5672
RABBITMQ_USERguest
RABBITMQ_PASSguest
RABBITMQ_QUEUEmetrics-processing

valkey Configuration

Volume Mounts:

NameContainer path
valkeydata/data

rustfs Configuration

Volume Mounts:

NameContainer path
rustfsdata/data

Environment Variables:

KeyValue
RUSTFS_SECRET_KEYminioadmin
RUSTFS_ACCESS_KEYminioadmin

rabbitmq Configuration

Volume Mounts:

NameContainer path
rabbitmqdata/var/lib/rabbitmq

Environment Variables:

KeyValue
RABBITMQ_DEFAULT_USERguest
RABBITMQ_DEFAULT_PASSguest

Finishing Up

Now that you have defined your application in the form, you just need to hit Create. You have succesfully defined your own custom Flask application on CitadelHosts! This application is available just to your account and can be deployed to any Territory of your choosing.

Deploying Custom Applications

Deploying custom applications is just as easy as deploying pre-configured applications. All one has to do is select the Territory you would like to deploy the application on and hit Deploy! Start the app up and navigate to your access link to view your own custom application. Great work!