Classroom "rules":
Tell us about yourself:
Option 1: Online development with Codespaces:
Option 2: Local development with VS Code
Option 3: Local development
The Docker engine runs multiple Docker containers, where each container is an isolated environment.
Each container can be a very different environment, with binaries and libraries dependent on the application.
A container image is a software package that includes
everything needed to run an application.
A container is a running instance of a container image.
Multiple containers can be run from the same image.
A registry is a place to store and share images.
Commonly used image registries:
A container image often starts off with a base image, and then adds layers on top of it.
For example:
Docker can cache each layer, which improves performance.
from flask import Flask, render_template, request
app = Flask(__name__, template_folder='templates', static_folder='static')
@app.route('/')
def index():
return render_template('index.html')
@app.route('/hello')
def hello():
return render_template('hello.html', name=request.args.get('name'))
👀 Demo: flaskcontainer-jd5m-containerapp.graymoss-ba9f7d1d.centralus.azurecontainerapps.io
👩🏼💻 Code: github.com/pamelafox/simple-flask-server-container
Using the built-in Flask server:
python3 -m flask run --port 50505 --debug
⚠️ The dev server is not recommended for production use.
Gunicorn is a production-level server that can run multiple worker processes.
Add gunicorn
to requirements.txt
:
Flask==2.2.3
gunicorn==20.1.0
Use gunicorn
to run Flask app with multiple workers:
python3 -m gunicorn app:app --workers 4 --bind 0.0.0.0:50505
Gunicorn can be configured with a gunicorn.conf.py
file:
import multiprocessing
max_requests = 1000
max_requests_jitter = 50
log_file = "-"
bind = "0.0.0.0:50505"
workers = (multiprocessing.cpu_count() * 2) + 1
threads = workers
timeout = 120
The run command can be simplified to:
python3 -m gunicorn app:app
A Dockerfile includes:
The base or parent image* | FROM python:3.11
|
Additional software | RUN pip3 install Flask gunicorn
|
Application code | WORKDIR /code COPY . .
|
Services to expose (storage/network) | EXPOSE 50505
|
Command to run upon launching container | ENTRYPOINT ["gunicorn", "-c", "gunicorn.conf.py", "app:app"]
|
*Find existing images in registries, like DockerHub.
A complete file:
FROM python:3.11
WORKDIR /code
COPY requirements.txt .
RUN pip3 install -r requirements.txt
COPY . .
EXPOSE 50505
ENTRYPOINT ["gunicorn", "-c", "gunicorn.conf.py", "app:app"]
📖 Learn more: Docker images layer and cache
Prevent unnecessary files from being copied to the image:
.git*
.venv/
**/*.pyc
__pycache__/
Using the docker build
command:
docker build --tag flaskapp .
Using the VS Code Docker extension
:
Using the docker run
command:
docker run --publish 50505:50505 flaskapp
Using Docker Desktop:
You can also use the VS Code Docker extension to run containers.
Starting from this repo:
github.com/pamelafox/simple-flask-server-container
🙋🏼♀️🙋🏾♀️🙋🏽♀️ Let us know if you need any help! 🙋🏻♀️🙋🏽♂️🙋🏿♀️
...
@app.route('/surveys', methods=['GET'])
def surveys_list_page():
surveys = Survey.query.all()
return render_template('surveys_list.html', surveys=surveys)
@app.route('/surveys/', methods=['GET'])
def survey_page(survey_id):
survey = Survey.query.where(Survey.id == survey_id).first()
answers = Survey.query.where(Answer.survey==survey_id)
return render_template('survey_details.html', survey=survey, answers=answers, already_voted='survey_id' in request.cookies)
...
👀 Demo: flasurveycon-b2ikkm-ca.ashysea-c408c9d0.eastus.azurecontainerapps.io/surveys
Data can be written to a container's file system, but:
If you need to persist data, you should store it outside the container.
A volume is a directory on the host machine that is mapped to a directory in the container.
When developing with databases locally, use a volume to store the data for the database.
Create a volume:
docker volume create postgres-data
Create a network for the containers to communicate over:
docker network create postgres-net
Run a PostgreSQL container with the volume and network:
docker run --rm -d -v postgres-data:/var/lib/postgresql/data \
--network postgres-net --name db \
-e POSTGRES_USER=app_user -e POSTGRES_PASSWORD=app_password \
postgres
Set environment variables for the database connection:
DBHOST=db
DBNAME=postgres
DBUSER=app_user
DBPASS=app_password
Build the container:
docker build --tag flasksurveyscontainerapp .
Run the app container over the same network:
docker run --rm -d --network postgres-net \
--name flask-db-app -p 50505:50505 \
flasksurveyscontainerapp
Docker compose is a tool for defining and running multi-container Docker apps,
and docker-compose.yaml
is a YAML file that defines the services that make up your app.
services:
db:
image: postgres
restart: always
environment:
POSTGRES_PASSWORD: ${DBPASS:?database password not set}
POSTGRES_USER: ${DBUSER:?database user not set}
POSTGRES_DB: ${DBNAME:?database name not set}
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DBUSER} -d ${DBNAME}"]
interval: 5s
timeout: 5s
retries: 5
app:
build:
context: .
ports:
- 50505:50505
depends_on:
db:
condition: service_healthy
volumes:
postgres-data:
Run the app and database containers:
docker-compose up
Starting from this repo:
github.com/pamelafox/flask-surveys-container-app
🙋🏼♀️🙋🏾♀️🙋🏽♀️ Let us know if you need any help! 🙋🏻♀️🙋🏽♂️🙋🏿♀️
Cloud | Azure | |||
---|---|---|---|---|
Environment | Containers | PaaS | ||
Azure Kubernetes Service | Container Management | Azure App Service | Serverless | |
Azure Container Apps | Azure Functions |
For hosting containers, Kubernetes Service, Container Apps, and App Service are all good options.
For temporary storage, you can write to file system or have an ephemeral volume in a container app.
For permanent storage, you can mount Azure Files but performance is too limited to be useful for a database.
Best approach for Azure:
Use a managed database service outside the container.
These are just some of the options:
Option | Description |
---|---|
Azure CosmosDB | Distributed database with multiple APIs, including MongoDB and Cassandra. |
Azure Cosmos DB for PostgreSQL | Distributed database using PostgreSQL and the Citus extension. Can scale vertically and horizontally. |
Azure Database for PostgreSQL – Flexible Server | Fully managed service with vertical scaling. |
A Container Apps Environment manages a Container App which pulls its image from an Azure Container Registry.
The Container App connects with the PostgreSQL server over the internal Azure network.
Using the Azure Dev CLI:
Starting from this repo (or your fork):
github.com/pamelafox/flask-surveys-container-app
azd down
to un-deploy the app.
🙋🏼♀️🙋🏾♀️🙋🏽♀️ Let us know if you need any help! 🙋🏻♀️🙋🏽♂️🙋🏿♀️