Uvicorn and Gunicorn for high-performance web apps in Python 3.11 and Python 3.12 with auto-tuning.
290
This Repository is modified from https://github.com/tiangolo/uvicorn-gunicorn-docker
Docker image with Uvicorn managed by Gunicorn for high-performance web applications in Python with performance auto-tuning.
Uvicorn: https://www.uvicorn.org/
Gunicorn: https://gunicorn.org/
you could have a Dockerfile like this:
# Dockerfile
FROM ai975/gunicorn:python3.12-slim
COPY ./app /ai975_server
RUN pip install --no-cache-dir --upgrade -r /ai975_server/requirements.txt
Then you can build your image from the directory that has your Dockerfile, e.g:
docker build -t repo/image:tag .
Run a container based on your image:
docker run -d --name ai975-server -p 9080:80 repo/image:tag
Here's a small example of one of the ways you could install your dependencies making sure you have a pinned version for each package.
Let's say you have a project managed with Poetry, so, you have your package dependencies in a file pyproject.toml. And possibly a file poetry.lock.
Then you could have a Dockerfile using Docker multi-stage building with:
FROM python:3.12 as requirements-stage
WORKDIR /tmp
RUN pip install poetry
COPY ./pyproject.toml ./poetry.lock* /tmp/
RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
FROM ai975/gunicorn:python3.12-slim
COPY --from=requirements-stage /tmp/requirements.txt /ai975_server/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /ai975_server/requirements.txt
COPY ./app /ai975_server
These are the environment variables that you can set in the container to configure it and their default values:
APP_MODULEThe string with the Python module and the variable name passed to Gunicorn.
By default:
main if there's a file /ai975_server/main.py orcustom_app.custom_main if there's a file /ai975_server/custom_app/custom_main.pyYou can set it like:
docker run -d -p 80:80 -e APP_MODULE="custom_app.custom_main:app" repo/image:tag
For example, if your main Python file has something like:
from fastapi import FastAPI
api = FastAPI()
@api.get("/")
def read_root():
return {"Hello": "World"}
In this case api would be the variable with the FastAPI application. You could set it like:
You can set it like:
docker run -d -p 80:80 -e APP_MODULE="custom_app.custom_main:api" repo/image:tag
GUNICORN_CONFThe path to a Gunicorn Python configuration file.
By default:
/app/gunicorn_conf.py if it exists/app/app/gunicorn_conf.py if it exists/gunicorn_conf.py (the included default)MAX_WORKERSSet the maximum number of workers to use.
You can use it to let the image compute the number of workers automatically but making sure it's limited to a maximum.
This can be useful, for example, if each worker uses a database connection and your database has a maximum limit of open connections.
BINDThe actual host and port passed to Gunicorn.
So, if you didn't change anything, it will be set by default to:
0.0.0.0:80LOG_LEVELThe log level for Gunicorn.
One of:
debuginfowarningerrorcriticalBy default, set to info.
ACCESS_LOG_FILEThe access log file to write to.
By default "-", which means stdout (print in the Docker logs).
ERROR_LOGThe error log file to write to.
By default "-", which means stderr (print in the Docker logs).
GUNICORN_CMD_ARGSAny additional command line settings for Gunicorn can be passed in the GUNICORN_CMD_ARGS environment variable.
docker run -d -p 80:8080 -e GUNICORN_CMD_ARGS="--keyfile=/secrets/key.pem --certfile=/secrets/cert.pem" -e PORT=443 myimage
PRE_START_PATHThe path where to find the pre-start script.
By default, set to /app/prestart.sh.
The image includes a default Gunicorn Python config file at /gunicorn_conf.py.
It uses the environment variables declared above to set all the configurations.
You can override it by including a file in:
/app/gunicorn_conf.py/app/app/gunicorn_conf.py/gunicorn_conf.py/app/prestart.shIf you need to run anything before starting the app, you can add a file prestart.sh to the directory /app. The image will automatically detect and run it before starting everything.
For example, if you want to add Alembic SQL migrations (with SQLALchemy), you could create a ./app/prestart.sh file in your code directory (that will be copied by your Dockerfile) with:
#! /usr/bin/env bash
# Let the DB start
sleep 10;
# Run migrations
alembic upgrade head
and it would wait 10 seconds to give the database some time to start and then run that alembic command.
If you need to run a Python script before starting the app, you could make the /app/prestart.sh file run your Python script, with something like:
#! /usr/bin/env bash
# Run custom Python script before starting
python /app/my_custom_prestart_script.py
You can customize the location of the prestart script with the environment variable PRE_START_PATH described above.
version: '3.8'
services:
ai975-server:
container_name: ai975-server
image: ai975/gunicorn:python3.12-slim
restart: unless-stopped
ports:
- "8880:80"
environment:
TZ: ${TZ:-"Asia/Shanghai"}
MAX_WORKERS: 4
WORKERS: 2
PYTHONPATH: "/local_app:/app"
BIND: "0.0.0.0:80"
LOG_LEVEL: "info"
ACCESS_LOG_FILE: "/app/access.log"
ERROR_LOG_FILE: "/app/error.log"
LOG_FORMAT: '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
APP_MODULE: "main:app"
# GUNICORN_CONF: "/gunicorn_conf.py"
# PRE_START_PATH: "/prestart.sh"
volumes:
# 容器默认工程放置目录
- /data/work/ai975_projects/ai975_server:/ai975_server
Content type
Image
Digest
sha256:9c63bb04d…
Size
149.7 MB
Last updated
almost 3 years ago
docker pull ai975/gunicorn:py3.12-slim-2023-11-24