Environment variables¶
Usage¶
To set environment variables when starting a Docker container:
docker run -d -p 80:80 \
-e APP_MODULE="package.custom.module:api" \
-e WORKERS_PER_CORE="2" \
myimage
To set environment variables within a Dockerfile:
FROM ghcr.io/br3ndonland/inboard:fastapi
ENV APP_MODULE="package.custom.module:api" WORKERS_PER_CORE="2"
General¶
APP_MODULE
- Python module with app instance.
- Default: The appropriate app module from inboard.
-
Custom: For a module at
/app/package/custom/module.py
and app instance objectapi
,APP_MODULE="package.custom.module:api"
Example of a custom FastAPI app module
# /app/package/custom/module.py from fastapi import FastAPI api = FastAPI() @api.get("/") def read_root(): return {"message": "Hello World!"}
Note
The base Docker image sets the environment variable
PYTHONPATH=/app
, so the module name will be relative to/app
unless you supply a customPYTHONPATH
.
PRE_START_PATH
- Path to a pre-start script.
- inboard optionally runs a pre-start script before starting the server. The path to a pre-start script can be specified with the environment variable
PRE_START_PATH
. If the environment variable is set to a nonzero value, inboard will run the script at the provided path, using thesubprocess
standard library package. - If the pre-start script exits with an error, inboard will not start the server.
- inboard optionally runs a pre-start script before starting the server. The path to a pre-start script can be specified with the environment variable
- Default:
"/app/inboard/prestart.py"
(provided with inboard) -
Custom:
PRE_START_PATH="/app/package/custom_script.sh"
PRE_START_PATH=
(set to an empty value) to disable
Tip
Add a file
prestart.py
orprestart.sh
to the application directory, and copy the directory into the Docker image as described (for a project with the Python application inrepo/package
,COPY package /app/package
). The container will automatically detect and run the prestart script before starting the web server.
- Python's search path for module files.
- Default:
PYTHONPATH="/app"
- Custom:
PYTHONPATH="/app/custom"
Gunicorn¶
Configuration file¶
GUNICORN_CONF
- Path to a Gunicorn configuration file. Gunicorn accepts either file paths or module paths.
- Default:
"python:inboard.gunicorn_conf"
(provided with inboard)
- Custom:
GUNICORN_CONF="/app/package/custom_gunicorn_conf.py"
(file path)GUNICORN_CONF="python:package.custom_gunicorn_conf"
(module paths accepted with thepython:
prefix)
Process management¶
Info
As described in the Uvicorn docs, "Uvicorn includes a Gunicorn worker class allowing you to run ASGI applications, with all of Uvicorn's performance benefits, while also giving you Gunicorn's fully-featured process management."
PROCESS_MANAGER
- Manager for Uvicorn worker processes.
- Default:
"gunicorn"
(run Uvicorn with Gunicorn as the process manager) - Custom:
"uvicorn"
(run Uvicorn alone for local development)
- Uvicorn worker class for Gunicorn to use.
- Default:
uvicorn.workers.UvicornWorker
- Custom: For the alternate Uvicorn worker,
WORKER_CLASS="uvicorn.workers.UvicornH11Worker"
(the H11 worker is provided for PyPy and hasn't been tested)
Worker process calculation¶
Info
The number of Gunicorn worker processes to run is determined based on the MAX_WORKERS
, WEB_CONCURRENCY
, and WORKERS_PER_CORE
environment variables, with a default of 1 worker per CPU core and a default minimum of 2. This is the "performance auto-tuning" feature described in tiangolo/uvicorn-gunicorn-docker.
MAX_WORKERS
- Maximum number of workers, independent of number of CPU cores.
- Default: not set (unlimited)
- Custom:
MAX_WORKERS="24"
WEB_CONCURRENCY
- Total number of workers, independent of number of CPU cores.
- Default: not set
- Custom:
WEB_CONCURRENCY="4"
WORKERS_PER_CORE
- Number of Gunicorn workers per CPU core. Overridden if
WEB_CONCURRENCY
is set. - Default: 1
-
Custom:
WORKERS_PER_CORE="2"
: Run 2 worker processes per core (8 worker processes on a server with 4 cores).WORKERS_PER_CORE="0.5"
(floating point values permitted): Run 1 worker process for every 2 cores (2 worker processes on a server with 4 cores).
Note
- The default number of workers is the number of CPU cores multiplied by the value of the environment variable
WORKERS_PER_CORE
(which defaults to 1). On a machine with only 1 CPU core, the default minimum number of workers is 2 to avoid poor performance and blocking, as explained in the release notes for tiangolo/uvicorn-gunicorn-docker 0.3.0. - If both
MAX_WORKERS
andWEB_CONCURRENCY
are set, the least of the two will be used as the total number of workers. - If either
MAX_WORKERS
orWEB_CONCURRENCY
are set to 1, the total number of workers will be 1, overriding the default minimum of 2.
Worker timeouts¶
- Number of seconds to wait for workers to finish serving requests before restart.
- Default:
"120"
- Custom:
GRACEFUL_TIMEOUT="20"
- Workers silent for more than this many seconds are killed and restarted.
- Default:
"120"
- Custom:
TIMEOUT="20"
- Number of seconds to wait for workers to finish serving requests on a Keep-Alive connection.
- Default:
"5"
- Custom:
KEEP_ALIVE="20"
Host networking¶
HOST
- Host IP address (inside of the container) where Gunicorn will listen for requests.
- Default:
"0.0.0.0"
- Custom: n/a
PORT
- Port the container should listen on.
- Default:
"80"
- Custom:
PORT="8080"
- The actual host and port passed to Gunicorn.
- Default:
HOST:PORT
("0.0.0.0:80"
) - Custom:
BIND="0.0.0.0:8080"
(if customBIND
is set, overridesHOST
andPORT
)
Runtime configuration¶
GUNICORN_CMD_ARGS
- Additional command-line arguments for Gunicorn. Gunicorn looks for the
GUNICORN_CMD_ARGS
environment variable automatically, and gives these settings precedence over other environment variables and Gunicorn config files. -
Custom: To use a custom TLS certificate, copy or mount the certificate and private key into the Docker image, and set
--keyfile
and--certfile
to the location of the files.CERTS="--keyfile=/secrets/key.pem --certfile=/secrets/cert.pem" docker run -d -p 443:443 \ -e GUNICORN_CMD_ARGS="$CERTS" \ -e PORT=443 myimage
Uvicorn¶
Info
These settings are mostly used for local development.
WITH_RELOAD
- Configure the Uvicorn auto-reload setting.
- Default:
"false"
(don't auto-reload when files change) -
Custom:
"true"
(watch files and auto-reload when files change).
RELOAD_DIRS
(new in inboard 0.7)
- Directories and files to watch for changes, formatted as comma-separated string.
- Default: watch all directories under project root.
-
Custom:
"inboard"
(one directory)"inboard, tests"
(two directories)"inboard, tests, Dockerfile"
(two directories and a file) (watching non-Python files requireswatchfiles
, installed with theinboard[uvicorn-standard]
extra)
Note
On the command-line, this Uvicorn setting is configured by passing
--reload-dir
, and can be passed multiple times, with one directory each.However, when running Uvicorn programmatically,
uvicorn.run
accepts a list of strings (uvicorn.run(reload_dirs=["dir1", "dir2"])
), so inboard will parse the environment variable, send the list to Uvicorn, and Uvicorn will watch each directory or file specified.
RELOAD_DELAY
(new in inboard 0.11)
- Floating point value specifying the time, in seconds, to wait before reloading files.
- Default: not set (the value is set by
uvicorn.config.Config
) -
Custom:
"0.5"
Note
uvicorn.run
equivalent:reload_delay
- Uvicorn CLI equivalent:
--reload-delay
RELOAD_EXCLUDES
(new in inboard 0.11)
- Glob pattern indicating files to exclude when watching for changes, formatted as comma-separated string.
- Default: not set (the value is set by
uvicorn.config.Config
) -
Custom:
"*[Dd]ockerfile"
(watching non-Python files requireswatchfiles
, installed with theinboard[uvicorn-standard]
extra)Note
- Parsed into a list of strings in the same manner as for
RELOAD_DIRS
. uvicorn.run
equivalent:reload_excludes
- Uvicorn CLI equivalent:
--reload-exclude
- Parsed into a list of strings in the same manner as for
RELOAD_INCLUDES
(new in inboard 0.11)
- Glob pattern indicating files to include when watching for changes, formatted as comma-separated string.
- Default: not set (the value is set by
uvicorn.config.Config
) -
Custom:
"*.py, *.md"
(watching non-Python files requireswatchfiles
, installed with theinboard[uvicorn-standard]
extra)Note
- Parsed into a list of strings in the same manner as for
RELOAD_DIRS
. uvicorn.run
equivalent:reload_includes
- Uvicorn CLI equivalent:
--reload-include
- Parsed into a list of strings in the same manner as for
UVICORN_CONFIG_OPTIONS
(advanced usage, new in inboard 0.11)
- JSON-formatted string containing arguments to pass directly to Uvicorn.
- Default: not set
- Custom:
UVICORN_CONFIG_OPTIONS='{"reload": true, "reload_delay": null}'
The idea here is to allow a catch-all Uvicorn config variable in the spirit of GUNICORN_CMD_ARGS
, so that advanced users can specify the full range of Uvicorn options even if inboard has not directly implemented them. The inboard.start
module will run the UVICORN_CONFIG_OPTIONS
environment variable value through json.loads()
, and then pass the resultant dictionary through to Uvicorn. If the same option is set with an individual environment variable (such as WITH_RELOAD
) and with a JSON value in UVICORN_CONFIG_OPTIONS
, the JSON value will take precedence.
json.loads()
converts data types from JSON to Python, and returns a Python dictionary. See the guide to understanding JSON schema for many helpful examples of how JSON data types correspond to Python data types. If the Uvicorn options are already available as a Python dictionary, dump them to a JSON-formatted string with json.dumps()
, and set that as an environment variable.
Example of how to format UVICORN_CONFIG_OPTIONS
as valid JSON
>>> import json
>>> import os
>>> uvicorn_config_dict = dict(host="0.0.0.0", port=80, log_config=None, log_level="info", reload=False)
>>> json.dumps(uvicorn_config_dict)
'{"host": "0.0.0.0", "port": 80, "log_config": null, "log_level": "info", "reload": false}'
>>> os.environ["UVICORN_CONFIG_OPTIONS"] = json.dumps(uvicorn_config_dict)
>>> json.loads(os.environ["UVICORN_CONFIG_OPTIONS"]) == uvicorn_config_dict
True
Warning
The UVICORN_CONFIG_OPTIONS
environment variable is suggested for advanced usage because it requires some knowledge of uvicorn.config.Config
. Other than the JSON -> Python dictionary conversion, no additional type conversions or validations are performed on UVICORN_CONFIG_OPTIONS
. All options should be able to be passed directly to uvicorn.config.Config
.
In the example below, reload
will be passed through with the correct type (because it was formatted with the correct JSON type initially), but access_log
will have an incorrect type (because it was formatted as a string instead of as a Boolean).
>>> import json
>>> import os
>>> os.environ["UVICORN_CONFIG_OPTIONS_INCORRECT"] = '{"access_log": "false", "reload": true}'
>>> json.loads(os.environ["UVICORN_CONFIG_OPTIONS_INCORRECT"])
{'access_log': "false", 'reload': True}
Logging¶
LOGGING_CONF
- Python module containing a logging configuration dictionary object named
LOGGING_CONFIG
. Can be either a module path (inboard.logging_conf
) or a file path (/app/inboard/logging_conf.py
). TheLOGGING_CONFIG
dictionary will be loaded and passed tologging.config.dictConfig()
. - Default:
"inboard.logging_conf"
(the default module provided with inboard) - Custom: For a logging config module at
/app/package/custom_logging.py
,LOGGING_CONF="package.custom_logging"
orLOGGING_CONF="/app/package/custom_logging.py"
.
LOG_COLORS
- Whether or not to color log messages. Currently only supported for
LOG_FORMAT="uvicorn"
. - Default:
- Auto-detected based on
sys.stdout.isatty()
.
- Auto-detected based on
- Custom:
LOG_COLORS="true"
LOG_COLORS="false"
LOG_FILTERS
- Comma-separated string identifying log records to filter out. The string will be split on commas and converted to a set. Each log message will then be checked for each filter in the set. If any matches are present in the log message, the logger will not log that message.
- Default:
None
(don't filter out any log records, just log every record) - Custom:
LOG_FILTERS="/health, /heartbeat"
(filter out log messages that contain either the string"/health"
or the string"/heartbeat"
, to avoid logging health checks) - See also:
- AWS Builders' Library: Implementing health checks
- AWS Elastic Load Balancing docs: Target groups - Health checks for your target groups
- benoitc/gunicorn#1781
- Python 3 docs: How-To - Logging Cookbook - Using Filters to impart contextual information
- Python 3 docs: What's new in Python 3.2 - logging
- Django 4.0 docs: Topics - Logging
LOG_FORMAT
- Python logging format.
- Default:
"simple"
: Simply the log level and message.
-
Custom:
"verbose"
: The most informative format, with the first 80 characters providing metadata, and the remainder supplying the log message."gunicorn"
: Gunicorn's default format."uvicorn"
: Uvicorn's default format, similar tosimple
, with support forLOG_COLORS
. Note that Uvicorn'saccess
formatter is not supported here, because it frequently throws errors related to ASGI scope.
Example log message in different formats
# simple INFO Started server process [19012] # verbose 2020-08-19 21:07:31 -0400 19012 uvicorn.error main INFO Started server process [19012] # gunicorn [2020-08-19 21:07:31 -0400] [19012] [INFO] Started server process [19012] # uvicorn (can also be colored) INFO: Started server process [19012]
LOG_LEVEL
- Log level for Gunicorn or Uvicorn.
- Default:
"info"
- Custom (organized from greatest to least amount of logging):
LOG_LEVEL="debug"
LOG_LEVEL="info"
LOG_LEVEL="warning"
LOG_LEVEL="error"
LOG_LEVEL="critical"
ACCESS_LOG
- Access log file to which to write.
- Default:
"-"
(stdout
, print in Docker logs) - Custom:
ACCESS_LOG="./path/to/accesslogfile.txt"
ACCESS_LOG=
(set to an empty value) to disable
ERROR_LOG
- Error log file to which to write.
- Default:
"-"
(stdout
, print in Docker logs) - Custom:
ERROR_LOG="./path/to/errorlogfile.txt"
ERROR_LOG=
(set to an empty value) to disable
See the logging reference for further info.
Authentication¶
BASIC_AUTH_USERNAME
- Username for HTTP Basic auth.
- Default: not set
- Custom:
BASIC_AUTH_USERNAME=test_user
BASIC_AUTH_PASSWORD
- Password for HTTP Basic auth.
- Default: not set
- Custom:
BASIC_AUTH_PASSWORD=r4ndom_bUt_memorable
See the authentication reference for further info.