docs: Add quickstart guide and Docker deployment

This commit is contained in:
Benoit Chesneau 2026-01-22 22:20:43 +01:00
parent 0a697cde7f
commit 819d2a2490
4 changed files with 596 additions and 104 deletions

View File

@ -0,0 +1,339 @@
# Docker Deployment
Running Gunicorn in Docker containers is the most common deployment pattern
for modern Python applications. This guide covers best practices for
containerizing Gunicorn applications.
## Basic Dockerfile
```dockerfile
FROM python:3.12-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# Run gunicorn
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]
```
Build and run:
```bash
docker build -t myapp .
docker run -p 8000:8000 myapp
```
## Production Configuration
### Environment Variables
Use environment variables for configuration:
```dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Configuration via environment
ENV GUNICORN_WORKERS=4
ENV GUNICORN_BIND=0.0.0.0:8000
CMD gunicorn app:app \
--workers ${GUNICORN_WORKERS} \
--bind ${GUNICORN_BIND}
```
Or use `GUNICORN_CMD_ARGS`:
```dockerfile
ENV GUNICORN_CMD_ARGS="--workers=4 --bind=0.0.0.0:8000"
CMD ["gunicorn", "app:app"]
```
### Worker Count
In containers, determine workers based on available CPU:
```python
# gunicorn.conf.py
import multiprocessing
workers = multiprocessing.cpu_count() * 2 + 1
bind = "0.0.0.0:8000"
```
Or let Kubernetes/Docker limit CPU and calculate accordingly:
```bash
# At runtime
gunicorn app:app --workers $(( 2 * $(nproc) + 1 ))
```
### Non-Root User
Run as a non-root user for security:
```dockerfile
FROM python:3.12-slim
# Create non-root user
RUN useradd --create-home appuser
WORKDIR /home/appuser/app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY --chown=appuser:appuser . .
USER appuser
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]
```
### Health Checks
Add a health check endpoint and Docker health check:
```dockerfile
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
```
## Multi-Stage Build
Reduce image size with multi-stage builds:
```dockerfile
# Build stage
FROM python:3.12 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt
# Runtime stage
FROM python:3.12-slim
WORKDIR /app
# Copy wheels and install
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels
COPY . .
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000", "--workers", "4"]
```
## Docker Compose
Example `docker-compose.yml`:
```yaml
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgres://db:5432/myapp
depends_on:
- db
deploy:
resources:
limits:
cpus: '2'
memory: 512M
db:
image: postgres:15
environment:
- POSTGRES_DB=myapp
- POSTGRES_PASSWORD=secret
volumes:
- postgres_data:/var/lib/postgresql/data
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- web
volumes:
postgres_data:
```
## Kubernetes Deployment
Example Kubernetes deployment:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8000
env:
- name: GUNICORN_WORKERS
value: "4"
resources:
limits:
cpu: "1"
memory: "512Mi"
requests:
cpu: "500m"
memory: "256Mi"
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 8000
```
## Graceful Shutdown
Gunicorn handles `SIGTERM` gracefully by default. Configure the timeout:
```dockerfile
CMD ["gunicorn", "app:app", \
"--bind", "0.0.0.0:8000", \
"--graceful-timeout", "30", \
"--timeout", "120"]
```
Match Docker's stop timeout:
```yaml
# docker-compose.yml
services:
web:
stop_grace_period: 30s
```
## Logging
Log to stdout/stderr for Docker log collection:
```python
# gunicorn.conf.py
accesslog = "-"
errorlog = "-"
loglevel = "info"
```
Use JSON logging for log aggregation:
```python
# gunicorn.conf.py
import json
import datetime
class JsonFormatter:
def format(self, record):
return json.dumps({
"timestamp": datetime.datetime.utcnow().isoformat(),
"level": record.levelname,
"message": record.getMessage(),
})
logconfig_dict = {
"version": 1,
"formatters": {
"json": {"()": JsonFormatter}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "json",
"stream": "ext://sys.stdout"
}
},
"root": {
"handlers": ["console"],
"level": "INFO"
}
}
```
## Troubleshooting
### Worker Timeout
If workers are killed with `[CRITICAL] WORKER TIMEOUT`, increase the timeout:
```bash
gunicorn app:app --timeout 120
```
Or investigate slow requests in your application.
### Out of Memory
If containers are OOM-killed:
1. Reduce worker count
2. Use `--max-requests` to restart workers periodically
3. Increase container memory limits
```bash
gunicorn app:app --workers 2 --max-requests 1000 --max-requests-jitter 100
```
### Connection Reset
If you see connection resets, ensure:
1. Load balancer health checks match your `/health` endpoint
2. Graceful timeout is sufficient for in-flight requests
3. Keepalive settings match between Gunicorn and upstream proxy
## See Also
- [Deploy](../deploy.md) - General deployment patterns
- [Settings](../reference/settings.md) - All configuration options

View File

@ -3,140 +3,174 @@
!!! note
Gunicorn requires **Python 3.12 or newer**.
## Quick Install
=== "pip"
```bash
pip install gunicorn
```
=== "pipx"
```bash
pipx install gunicorn
```
=== "Docker"
```bash
docker run -p 8000:8000 -v $(pwd):/app -w /app \
python:3.12-slim sh -c "pip install gunicorn && gunicorn app:app"
```
See the [Docker guide](guides/docker.md) for production configurations.
=== "System Packages"
**Debian/Ubuntu:**
```bash
sudo apt-get update
sudo apt-get install gunicorn
```
**Fedora:**
```bash
sudo dnf install python3-gunicorn
```
**Arch Linux:**
```bash
sudo pacman -S gunicorn
```
!!! warning
System packages may lag behind the latest release. For production,
prefer pip installation in a virtual environment.
## Virtual Environment (Recommended)
Always install Gunicorn inside a virtual environment to isolate dependencies:
```bash
# Create virtual environment
python -m venv venv
# Activate it
source venv/bin/activate # Linux/macOS
# or: venv\Scripts\activate # Windows
# Install gunicorn
pip install gunicorn
```
## From source
## From Source
Install Gunicorn from GitHub if you want the latest development version:
Install the latest development version from GitHub:
```bash
pip install git+https://github.com/benoitc/gunicorn.git
```
Stay current by upgrading in place:
Upgrade to the latest commit:
```bash
pip install -U git+https://github.com/benoitc/gunicorn.git
```
## Async workers
## Extra Packages
Install Eventlet or Gevent if your application benefits from cooperative I/O.
Both rely on `greenlet`, so make sure the Python headers are available (for
example, install the `python-dev` package on Ubuntu).
```bash
pip install greenlet # Required for both
pip install eventlet # For eventlet workers
pip install gunicorn[eventlet] # Or, using extra
pip install gevent # For gevent workers
pip install gunicorn[gevent] # Or, using extra
```
!!! note
Gevent also needs `libevent` 1.4.x or 2.0.4+. Install it from your package
manager or build it manually if the packaged version is too old.
## Extra packages
Some Gunicorn options require additional dependencies. Install them via
extras to pull everything in with one command.
Most extras enable alternative worker types—see the
[design docs](design.md) for when each worker makes sense.
- `gunicorn[eventlet]` — Eventlet-based greenlet workers
- `gunicorn[gevent]` — Gevent-based greenlet workers
- `gunicorn[gthread]` — Threaded workers
- `gunicorn[tornado]` — Tornado-based workers (not recommended)
If you run more than one Gunicorn instance, the
[`proc_name`](reference/settings.md#proc_name) setting helps distinguish them in tools such
as `ps` and `top`.
- `gunicorn[setproctitle]` — Enables setting the process name
You can combine multiple extras, for example:
Gunicorn provides optional extras for additional worker types and features.
Install them with pip's bracket syntax:
```bash
pip install gunicorn[gevent,setproctitle]
```
## Debian GNU/Linux
### Worker Types
On Debian systems prefer the distribution packages unless you need per-project
virtual environments:
| Extra | Description |
|-------|-------------|
| `gunicorn[eventlet]` | Eventlet-based greenlet workers |
| `gunicorn[gevent]` | Gevent-based greenlet workers |
| `gunicorn[gthread]` | Threaded workers |
| `gunicorn[tornado]` | Tornado-based workers (not recommended) |
- Zero-effort installation: automatically starts multiple instances based on
configs in `/etc/gunicorn.d`.
- Sensible log locations (`/var/log/gunicorn`) with `logrotate` support.
- Improved security: run each instance with a dedicated UNIX user/group.
- Safe upgrades: minimal downtime, reversible changes, and easy package purge.
See the [design docs](design.md) for guidance on choosing worker types.
### stable ("buster")
### Utilities
The Debian [stable](https://www.debian.org/releases/stable/) release ships
Gunicorn 19.9.0 (December 2020):
| Extra | Description |
|-------|-------------|
| `gunicorn[setproctitle]` | Set process name in `ps`/`top` output |
!!! tip
If running multiple Gunicorn instances, use `setproctitle` with the
[`proc_name`](reference/settings.md#proc_name) setting to distinguish them.
## Async Workers
For applications using async I/O patterns, install the appropriate greenlet
library:
=== "Gevent"
```bash
pip install gunicorn[gevent]
```
Run with:
```bash
gunicorn app:app --worker-class gevent
```
=== "Eventlet"
```bash
pip install gunicorn[eventlet]
```
Run with:
```bash
gunicorn app:app --worker-class eventlet
```
=== "ASGI (asyncio)"
No extra installation required:
```bash
gunicorn app:app --worker-class asgi
```
For better performance, install uvloop:
```bash
pip install uvloop
gunicorn app:app --worker-class asgi --asgi-loop uvloop
```
!!! note
Greenlet-based workers require the Python development headers. On Ubuntu:
`sudo apt-get install python3-dev`
## Verify Installation
Check the installed version:
```bash
sudo apt-get install gunicorn3
gunicorn --version
```
Install Gunicorn 20.0.4 from [Debian Backports](https://backports.debian.org/)
by adding this line to `/etc/apt/sources.list`:
```text
deb http://ftp.debian.org/debian buster-backports main
```
Refresh package metadata and install:
Test with a simple application:
```bash
sudo apt-get update
sudo apt-get -t buster-backports install gunicorn
echo 'def app(e, s): s("200 OK", []); return [b"OK"]' > test_app.py
gunicorn test_app:app
# Visit http://127.0.0.1:8000
```
### oldstable ("stretch")
## Next Steps
Stretch provides Gunicorn 19.6.0 (December 2020). Install the Python 3 version:
```bash
sudo apt-get install gunicorn3
```
To upgrade to 19.7.1 from backports, add:
```text
deb http://ftp.debian.org/debian stretch-backports main
```
Then update and install:
```bash
sudo apt-get update
sudo apt-get -t stretch-backports install gunicorn3
```
### testing ("bullseye") and unstable ("sid")
Both distributions include Gunicorn 20.0.4. Install it in the usual way:
```bash
sudo apt-get install gunicorn
```
## Ubuntu
Ubuntu 20.04 LTS (Focal Fossa) and newer include Gunicorn 20.0.4. Keep it
current through the package manager:
```bash
sudo apt-get update
sudo apt-get install gunicorn
```
- [Quickstart](quickstart.md) - Get running in 5 minutes
- [Run](run.md) - CLI usage and framework integration
- [Configure](configure.md) - Configuration options

115
docs/content/quickstart.md Normal file
View File

@ -0,0 +1,115 @@
# Quickstart
Get a Python web application running with Gunicorn in 5 minutes.
## Install
```bash
pip install gunicorn
```
## Create an Application
Create `app.py`:
=== "Flask"
```python
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
```
=== "FastAPI"
```python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def hello():
return {"message": "Hello, World!"}
```
=== "Django"
Django projects already have a WSGI application at `myproject/wsgi.py`.
No additional code is needed.
=== "Plain WSGI"
```python
def app(environ, start_response):
data = b"Hello, World!"
start_response("200 OK", [
("Content-Type", "text/plain"),
("Content-Length", str(len(data)))
])
return [data]
```
## Run
```bash
gunicorn app:app
```
For Django:
```bash
gunicorn myproject.wsgi
```
For FastAPI (ASGI):
```bash
gunicorn app:app --worker-class asgi
```
## Add Workers
Use multiple workers to handle concurrent requests:
```bash
gunicorn app:app --workers 4
```
A good starting point is `2 * CPU_CORES + 1` workers.
## Bind to a Port
By default Gunicorn binds to `127.0.0.1:8000`. Change it with:
```bash
gunicorn app:app --bind 0.0.0.0:8080
```
## Configuration File
Create `gunicorn.conf.py` for reusable settings:
```python
bind = "0.0.0.0:8000"
workers = 4
accesslog = "-"
```
Then run:
```bash
gunicorn app:app
```
Gunicorn automatically loads `gunicorn.conf.py` from the current directory.
## Next Steps
- [Run](run.md) - Full CLI reference and framework integration
- [Configure](configure.md) - Configuration file options
- [Deploy](deploy.md) - Production deployment with nginx and process managers
- [Settings](reference/settings.md) - Complete settings reference

View File

@ -7,19 +7,23 @@ use_directory_urls: true
nav:
- Home: index.md
- Guides:
- Getting Started:
- Quickstart: quickstart.md
- Install: install.md
- Run: run.md
- Configure: configure.md
- Guides:
- Deploy: deploy.md
- Docker: guides/docker.md
- ASGI Worker: asgi.md
- uWSGI Protocol: uwsgi.md
- Signals: signals.md
- Instrumentation: instrumentation.md
- Custom: custom.md
- Community: community.md
- FAQ: faq.md
- Design: design.md
- Community:
- Overview: community.md
- FAQ: faq.md
- Reference:
- Settings: reference/settings.md
- News: