Building the docker image uses Docker for Windows on
Windows 10 Home edition where only WSL 2 is available.
With Windows 10 Pro you can choose to use a
Hyper-V backend or WSL 2.
The documentation shows
- running
podmanandpodman-desktoponLinuxbut it is also possible onWindows. - running
dockeranddocker-desktoponWindowsbut it is also possible onLinux.
# Create podman volumes
sjfke@morpheus$ podman volume create postgres-flask-play
sjfke@morpheus$ podman volume create mongodb-flask-play
sjfke@morpheus$ podman volume create mongoconfigdb-flask-play
Uses the same compose.yaml written for the docker approach.
# Using compose.yaml file
sjfke@morpheus$ podman compose -f ./compose.yaml up -d mongo # start MongoDB container
sjfke@morpheus$ podman exec -it flask-play-mongo-1 mongosh mongodb://root:example@localhost:27017 # mongosh
# Add contents as described in 'tests\momgodb-test-data.txt'
# Using compose.yaml file
sjfke@morpheus$ podman play kube --start ./pods/flask-play-mongo.yaml
sjfke@morpheus$ podman exec -it flask-play-mongo-1-pod mongosh mongodb://root:example@localhost:27017 # mongosh
# Add contents as described in 'tests\momgodb-test-data.txt'
# Define variables
sjfke@morpheus$ export CONTAINER_NAME="crazy-frog"
sjfke@morpheus$ export IMAGE_NAME= "localhost/flask-play"
# Build image
sjfke@morpheus$ podman build --tag $image --no-cache --squash -f ./Dockerfile
sjfke@morpheus$ podman image ls $image
# Run, test, delete container
sjfke@morpheus$ podman run --name $name -p 8080:8080 -d $image
sjfke@morpheus$ podman logs ${CONTAINER_NAME}
sjfke@morpheus$ podman exec -it ${CONTAINER_NAME} sh
sjfke@morpheus$ podman kube generate ${CONTAINER_NAME} -f ./pods/flask-play-web-1.yaml # generate pod manifest
sjfke@morpheus$ /usr/bin/firefox http://localhost:8485
sjfke@morpheus$ podman rm --force $name
# Image Maintenance
sjfke@morpheus$ podman image prune# Preparation
sjfke@morpheus$ sudo dnf install jq # ensure 'jq' is installed
sjfke@morpheus$ podman network create flask-play_net
sjfke@morpheus$ podman inspect flask-play_net | jq '.[].subnets.[].subnet'
"10.89.0.0/24"
# Create DataBase secrets (TODO)
# sjfke@morpheus$ podman secret create --env=true my_secret MYSECRET
# Using Play Kube Pod files
sjfke@morpheus$ podman play kube --start ./pods/flask-play-mongo.yaml --net flask-play_net
sjfke@morpheus$ podman exec -it flask-play-mongo-1-pod mongosh mongodb://root:example@localhost:27017 # mongosh
# Add contents as described in 'tests\momgodb-test-data.txt'
# Run, test, delete container using podman play kube
# NOTE: 'flask-play-flask' needs to be started before 'flask-play-nginx'
sjfke@morpheus$ podman play kube --start ./pods/flask-play-dbgate.yaml --net flask-play_net
sjfke@morpheus$ podman play kube --start ./pods/flask-play-mongo.yaml --net flask-play_net
sjfke@morpheus$ podman play kube --start ./pods/flask-play-postgres.yaml --net flask-play_net
sjfke@morpheus$ podman play kube --start ./pods/flask-play-flask.yaml --net flask-play_net
sjfke@morpheus$ podman play kube --start ./pods/flask-play-nginx.yaml --net flask-play_net
# Build
sjfke@morpheus$ podman play kube --build ./pods/flask-play-flask.yaml
sjfke@morpheus$ podman play kube --build ./pods/flask-play-nginx.yaml
# Reload, Restart
sjfke@morpheus$ podman play kube --reload ./pods/flask-play-flask.yaml
sjfke@morpheus$ podman play kube --reload ./pods/flask-play-nginx.yaml
# Start all pods
sjfke@morpheus$ for pod in 'postgres' 'mongo' 'dbgate' 'flask' 'nginx'; do
podman pod ps | grep -q flask-play-${pod} || podman play kube --start ./pods/flask-play-${pod}.yaml --net flask-play_net
done
# Stop and delete all pods
sjfke@morpheus$ for pod in 'postgres' 'mongo' 'dbgate' 'flask' 'nginx'; do
podman pod ps | grep -q flask-play-${pod} && podman play kube --down ./pods/flask-play-${pod}.yaml
done
sjfke@morpheus$ /usr/bin/firefox http://localhost:8485
sjfke@morpheus$ podman play kube --down ./pods/flask-play-web.yaml
# Development, test (wash repeat cycle)
sjfke@morpheus$ export IMAGE="docker.io/library/flask-play-flask"
sjfke@morpheus$ export CONTAINER=$( basename $IMAGE)
sjfke@morpheus$ podman build --tag ${IMAGE} --no-cache --squash -f ./flask/Dockerfile
sjfke@morpheus$ podman play kube --replace ./pods/${CONTAINER}.yaml --net flask-play_net
sjfke@morpheus$ /usr/bin/firefox http://localhost:8485# Create docker volumes
PS C:\Users\sjfke> docker volume create postgres-flask-play
PS C:\Users\sjfke> docker volume create mongodb-flask-play
PS C:\Users\sjfke> docker volume create mongoconfigdb-flask-play
# Once compose.yaml is created, see references (ii, iii)
PS C:\Users\sjfke> docker compose -f .\compose.yaml up -d mongo # start MongoDB container
PS C:\Users\sjfke> docker exec -it flask-play-mongo-1 mongosh mongodb://root:example@localhost:27017 # mongosh
# Add contents as described in 'tests\momgodb-test-data.txt'
# Start the whole application
PS C:\Users\sjfke> docker compose -f .\compose.yaml up -d # builds flask-play-web image
PS C:\Users\sjfke> start http://localhost:8485
PS C:\Users\sjfke> start http://localhost:8486 # admin/admin
PS C:\Users\sjfke> docker compose -f .\compose.yaml down
# Development, test (wash repeat cycle)
PS C:\Users\sjfke> docker compose -f .\compose.yaml down web
PS C:\Users\sjfke> docker compose build web
PS C:\Users\sjfke> docker compose -f .\compose.yaml up -d web
PS C:\Users\sjfke> start http://localhost:8485- Docker: Overview of Docker Compose
- Docker: Compose specification
- Docker: Compose specification - ports
# Define variables
PS C:\Users\sjfke> $name = "crazy-frog"
PS C:\Users\sjfke> $image = "localhost/flask-play"
# Build image
PS C:\Users\sjfke> docker build --squash -t $image -f .\Dockerfile $PWD
PS C:\Users\sjfke> docker image ls $image
# Run, test, delete container
PS C:\Users\sjfke> docker run --name $name -p 8080:8080 -d $image
PS C:\Users\sjfke> docker exec -it $name sh
PS C:\Users\sjfke> docker logs $name
PS C:\Users\sjfke> start http://localhost:8485
PS C:\Users\sjfke> docker rm --force $namePS C:\Users\sjfke> docker image prune # clean up dangling images
PS C:\Users\sjfke> docker system prune
PS C:\Users\sjfke> docker rmi $(docker images -f 'dangling=true' -q) # UNIX, images with no tags
PS C:\Users\sjfke> $d = docker images -f 'dangling=true' -q; docker rmi $d # Powershell, images with no tagsCreate the auth database
$ podman exec -it flask-play-posgres-1 /bin/bash
root@79685c6f4e96:/# createdb auth
root@79685c6f4e96:/# exitNeed to grant podman flask-play_net network access to create the tables and use the auth database.
$ podman network inspect flask-play_net | grep subnet -A 5 | head -n 8
"subnets": [
{
"subnet": "10.89.0.0/24",
"gateway": "10.89.0.1"
}
],
"ipv6_enabled": false,
"internal": false,Update postgresql 'pg_hba.conf' file
$ podman cp flask-play-postgres-1:/var/lib/postgresql/data/pg_hba.conf .
$ gedit pg_hba.conf
$ cat /tmp/pg_hba.conf
# ...
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# Podman flask-play_net IPv4 local connections:
host all all 10.89.0.4/24 trust
# IPv6 local connections:
host all all ::1/128 trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all trust
host replication all 127.0.0.1/32 trust
host replication all ::1/128 trust
$ podman cp pg_hba.conf flask-play-postgres-1:/var/lib/postgresql/data/pg_hba.conf
$ podman restart flask-play-postgres-1To create the tables, for the auth database.
$ podman exec -it flask-play-web-1 /bin/ash
/usr/src/app # python create-postgresql-tables.py
/usr/src/app # exit- PyPi: Flask is a lightweight WSGI web application framework
- PythonBasics: Flask HTTP methods, handle GET & POST requests
- PalletsProjects: Flask Quickstart
- TutorialsPoint: Flask Tutorial
- PalletsProjects: API covers all the interfaces of Flask
- PalletsProjects: Handling Application Errors
- DelftStack: Flask Request Form
- StackOverflow: How to get json data from another website in Flask?
- StackOverflow: How to pass data to html page using flask?
- PalletsProjects: Jinja 3.0.x Template Designer Documentation
- PyFormat: Using % and .format() for great good!
- DigitalOcean: How To Process Incoming Request Data in Flask
- LearnWithJason: How to Convert HTML Form Field Values to a JSON Object
- PalletsProjects: Testing Flask Applications
- ReadTheDocs: Basic Usage of Pipenv
- PythonBasics: How to Set Up Flask with MongoDB
- PalletsProjects: MongoDB with MongoEngine
- DevTo: How to spin MongoDB server with Docker and Docker Compose
- MongoDB: MongoDB Basics
- DockerHub: MongoDB document databases provide high availability and easy scalability
- MongoDB: Docker and MongoDB
- dockerhub: dbgate/dbgate
- Securing Mongo Express web administrative interfaces
- How To Add Authentication to Your App with Flask-Login
- Pip - Caching
- Docker Official build of Nginx
- NGINX Reverse Proxy -> WSGI -> Python/Flask Backend
- How To Serve Flask Applications with Gunicorn and Nginx on Ubuntu 20.04
- How To Configure Nginx as a Reverse Proxy on Ubuntu 22.04
- GetBootstrap: Migrating to v5
- GetBootstrap: Bootstrap 5.2 Introduction
- GetBootstrap: Bootstrap 5.2 Reboot
- GetBootstrap: Bootstrap 5.2 Grid system
- CSSTricks: A Complete Guide to Flexbox
- GetBootstrap: Bootstrap 5.2 Forms
- GetBootstrap: Bootstrap 5.2 Forms - Layout
- GetBootstrap: Bootstrap 5.2 Form controls
- GetBootstrap: Bootstrap 5.2 Forms Checks and radios
- GetBootstrap: Bootstrap 5.2 Buttons
- GetBootstrap: Bootstrap 5.2 Button Group
- GetBootstrap: Bootstrap 5.2 Input group
- GetBootstrap: Bootstrap 5.2 Gutters
- GetBootstrap: Bootstrap 5.2 Spacing
- GetBootstrap: Bootstrap 5.2 Flex
- W3Schools: Bootstrap 5 Text/Typography
- GetBootstrap: Bootstrap 5.2
- W3Schools: Bootstrap 5 Tutorial
- W3Schools: Bootstrap 5 Containers
- W3Schools: Bootstrap 5 Grids
- Icons8: Free icons that match each other
- Pixabay: Stunning free images & royalty free stock
This repository provides a simple Python web application implemented using the Flask web framework and executed using
gunicorn. It is intended to be used to demonstrate building and test of Python Flask web applications
using Docker
Building the docker image uses Docker for Windows on
Windows 10 Home edition where only WSL 2 is available. With Windows 10 Pro you can choose to use a
Hyper-V backend or WSL 2.
Application's Key files:
- config.py: GUNICORN settings;
- wsgi.py: define the pages (routes) that are visible;
- static: several bootstrap themes from Bootstrap 4 themes
- templates/base.html: boiler-plate for all html pages;
- templates/index.html: Standard Lorem Ipsum;
- templates/legal.html: Legal-style Lorem Ipsum;
- templates/pirate.html: Pirate-style Lorem Ipsum;
- templates/zombie.html: Zombie-style Lorem Ipsum
None of the bootstrap themes are enabled be default, edit templates/base.html to activate them.
This sample Python application deploys a WSGI application using the gunicorn WSGI server. The requirements which
need to be satisfied for this to work are:
- The WSGI application code file needs to be named
wsgi.py. - The WSGI application entry point within the code file needs to be named
application. - The
gunicornpackage must be listed in therequirements.txtfile forpip. - The requirements.txt file is generated using
pipenv run pip freeze > requirements.txt.
The example is derived from Getting Started with Flask but has been modified to use BootStrap 4, work with Green Unicorn - WSGI sever, the content of the web-site changed to provide a sandbox for testing Flask
Other useful references:
- The best Docker base image for your Python application (February 2021)
- Python: Official Docker Images
- Windows Subsystem for Linux Documentation
- Docker on Hyper-V vs WSL 2
- Install Docker Desktop on Windows
A simple Docker file which using, python:3-alpine container, first it pip installs the required applications
specified in the requirements.txt file, copies the application files to the container, and finally, sets up the
environment and starts gunicorn.
FROM python:3-alpine
# TODO: Put the maintainer name in the image metadata
MAINTAINER Sjfke (Geoff Collis) <gcollis@ymail.com>
# TODO: Rename the builder environment variable to inform users about application you provide them
ENV BUILDER_VERSION 1.0
# TODO: Set labels used in OpenShift to describe the builder image
LABEL io.k8s.name="Flask" \
io.k8s.description="Sandbox for Flask Application for Docker" \
io.k8s.display-name="Flask Sandbox" \
io.k8s.version="0.1.0" \
io.openshift.expose-services="8080:http" \
io.openshift.tags="Sandbox,0.1.0,Flask"
ENV PORT=8080
WORKDIR /usr/src/app
# Project uses 'pipenv' (Pipfile, Pipfile.lock), Docker needs requirements.txt
# $ pipenv run pip freeze > requirements.txt # generates requirements.txt
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
# TODO (optional): Copy the builder files into /opt/app-root
# COPY ./<builder_folder>/ /opt/app-root/
COPY config.py ./
COPY static/* ./static/
COPY templates/* ./templates/
COPY wsgi.py ./
# TODO: Copy the S2I scripts to /usr/libexec/s2i, since openshift/base-centos7 image
# sets io.openshift.s2i.scripts-url label that way, or update that label
# COPY ./s2i/bin/ /usr/libexec/s2i
# TODO: Drop the root user and make the content of /opt/app-root owned by user 1001
# RUN chown -R 1001:1001 /opt/app-root
# This default user is created in the openshift/base-centos7 image
USER 1001
# TODO: Set the default port for applications built using this image
EXPOSE ${PORT}
# TODO: Set the default CMD for the image
CMD gunicorn -b 0.0.0.0:${PORT} wsgiPS1> docker exec -it flask-play-mongo-1 mongosh --username root