Skip to content

Deployment Guide

This guide covers deploying Gunicorn Prometheus Exporter in production environments.

Note: For basic setup, see the Setup Guide.

Docker Deployment

Basic Docker Setup

Dockerfile:

FROM python:3.11-slim

WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install -r requirements.txt
RUN pip install gunicorn gunicorn-prometheus-exporter

# Copy application
COPY . .

# Create metrics directory
RUN mkdir -p /tmp/prometheus_multiproc

# Expose ports
EXPOSE 8000 9091

# Set environment variables
ENV PROMETHEUS_METRICS_PORT=9091
ENV PROMETHEUS_BIND_ADDRESS=0.0.0.0
ENV PROMETHEUS_MULTIPROC_DIR=/tmp/prometheus_multiproc
ENV GUNICORN_WORKERS=4

# Start with gunicorn
CMD ["gunicorn", "-c", "gunicorn.conf.py", "app:app"]

docker-compose.yml:

version: "3.8"

services:
  app:
    build: .
    ports:
      - "8000:8000" # Application port
      - "9091:9091" # Metrics port
    environment:
      - PROMETHEUS_METRICS_PORT=9091
      - PROMETHEUS_BIND_ADDRESS=0.0.0.0
      - PROMETHEUS_MULTIPROC_DIR=/tmp/prometheus_multiproc
      - GUNICORN_WORKERS=4
    volumes:
      - prometheus_data:/tmp/prometheus_multiproc

  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090" # Prometheus UI
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_storage:/prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"

volumes:
  prometheus_data:
  prometheus_storage:

prometheus.yml:

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: "gunicorn-app"
    static_configs:
      - targets: ["app:9091"] # Docker service name
    metrics_path: /metrics
    scrape_interval: 5s

Kubernetes Deployment

Basic Kubernetes Setup

deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gunicorn-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: gunicorn-app
  template:
    metadata:
      labels:
        app: gunicorn-app
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9091"
        prometheus.io/path: "/metrics"
    spec:
      containers:
        - name: app
          image: princekrroshan01/gunicorn-app:0.2.0
          ports:
            - containerPort: 8000
              name: http
            - containerPort: 9091
              name: metrics
          env:
            - name: PROMETHEUS_METRICS_PORT
              value: "9091"
            - name: PROMETHEUS_BIND_ADDRESS
              value: "0.0.0.0"
            - name: PROMETHEUS_MULTIPROC_DIR
              value: "/tmp/prometheus_multiproc"
            - name: GUNICORN_WORKERS
              value: "4"
          resources:
            requests:
              memory: "256Mi"
              cpu: "250m"
            limits:
              memory: "512Mi"
              cpu: "500m"

service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: gunicorn-app-service
spec:
  selector:
    app: gunicorn-app
  ports:
    - name: http
      port: 8000
      targetPort: 8000
    - name: metrics
      port: 9091
      targetPort: 9091
  type: ClusterIP

Sidecar Deployment

Deploy the exporter as a sidecar container within the same Kubernetes pod for isolated monitoring.

Docker Hub Images

Pre-built Docker images are available on Docker Hub:

# Sidecar exporter image
docker pull princekrroshan01/gunicorn-prometheus-exporter:0.2.0

# Sample Flask application (for testing)
docker pull princekrroshan01/gunicorn-app:0.2.0

# Or build locally if the release is not yet available:
# docker build -t princekrroshan01/gunicorn-prometheus-exporter:0.2.0 .
# docker build -f docker/Dockerfile.app -t princekrroshan01/gunicorn-app:0.2.0 .

Images are automatically built and published for: - linux/amd64 (x86_64) - linux/arm64 (ARM64)

Quick Start with Docker Compose

Production recommendation: Keep Redis storage enabled (REDIS_ENABLED=true) so that metrics aggregate across all workers/pods. Only disable Redis for single-worker demos.

# Clone the repository
git clone https://github.com/Agent-Hellboy/gunicorn-prometheus-exporter.git
cd gunicorn-prometheus-exporter

# Start all services (app, sidecar, Redis, Prometheus, Grafana)
docker-compose up --build

# Access services:
# - Application: http://localhost:8000
# - Metrics: http://localhost:9091/metrics
# - Prometheus: http://localhost:9090
# - Grafana: http://localhost:3000
#   Username: admin
#   Password: admin (set GF_SECURITY_ADMIN_PASSWORD to override in production)

See docker/README.md for detailed Docker Compose documentation.

Kubernetes Sidecar Deployment

For a complete Kubernetes deployment with Redis, Prometheus, and Grafana:

Quick Deploy:

# Create required secrets
kubectl create secret generic grafana-secret \
  --from-literal=admin-password="$(openssl rand -base64 32)"

# Deploy everything
kubectl apply -f k8s/

# Access services via port-forwarding
kubectl port-forward service/gunicorn-app-service 8000:8000
kubectl port-forward service/gunicorn-metrics-service 9091:9091
kubectl port-forward service/prometheus-service 9090:9090
kubectl port-forward service/grafana-service 3000:3000

Minimal Sidecar Example:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gunicorn-app-with-sidecar
spec:
  replicas: 3
  selector:
    matchLabels:
      app: gunicorn-app
  template:
    metadata:
      labels:
        app: gunicorn-app
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9091"
        prometheus.io/path: "/metrics"
    spec:
      containers:
        # Main application container
        - name: app
          image: princekrroshan01/gunicorn-app:0.2.0
          securityContext:
            allowPrivilegeEscalation: false
            runAsNonRoot: true
            runAsUser: 1000
            capabilities:
              drop:
                - ALL
          ports:
            - containerPort: 8000
              name: http
          env:
            - name: PROMETHEUS_MULTIPROC_DIR
              value: "/tmp/prometheus_multiproc"
            - name: GUNICORN_WORKERS
              value: "2"
          volumeMounts:
            - name: prometheus-data
              mountPath: /tmp/prometheus_multiproc
          resources:
            requests:
              memory: "256Mi"
              cpu: "250m"
            limits:
              memory: "512Mi"
              cpu: "500m"

        # Prometheus exporter sidecar
        - name: prometheus-exporter
          image: princekrroshan01/gunicorn-prometheus-exporter:0.2.0
          securityContext:
            allowPrivilegeEscalation: false
            runAsNonRoot: true
            runAsUser: 1000
            readOnlyRootFilesystem: true
            capabilities:
              drop:
                - ALL
          ports:
            - containerPort: 9091
              name: metrics
          env:
            - name: PROMETHEUS_METRICS_PORT
              value: "9091"
            - name: PROMETHEUS_BIND_ADDRESS
              value: "0.0.0.0"
            - name: PROMETHEUS_MULTIPROC_DIR
              value: "/tmp/prometheus_multiproc"
            - name: REDIS_ENABLED
              value: "false"
          volumeMounts:
            - name: prometheus-data
              mountPath: /tmp/prometheus_multiproc
              readOnly: true
          resources:
            requests:
              memory: "64Mi"
              cpu: "50m"
            limits:
              memory: "128Mi"
              cpu: "100m"
      volumes:
        - name: prometheus-data
          emptyDir:
            medium: Memory
            sizeLimit: 1Gi

For production-ready Kubernetes deployments with Redis, security contexts, secrets management, and monitoring stack, see the Kubernetes Deployment Guide.

Benefits of Sidecar Deployment:

  • Isolation: Metrics collection is separate from application logic
  • Pre-built Images: Ready-to-use Docker images on Docker Hub
  • Multi-arch Support: Works on AMD64 and ARM64 architectures
  • Production-Ready: Includes security contexts and resource limits
  • Resource Management: Independent resource limits for monitoring
  • Scaling: Can scale monitoring independently
  • Security: Reduced attack surface for main application
  • Maintenance: Update monitoring without touching application

Production Considerations

Security

# Enable SSL/TLS for metrics endpoint
export PROMETHEUS_SSL_CERTFILE="/etc/ssl/certs/metrics.crt"
export PROMETHEUS_SSL_KEYFILE="/etc/ssl/private/metrics.key"
export PROMETHEUS_SSL_CLIENT_AUTH_REQUIRED="true"

Performance

resources:
  requests:
    memory: "512Mi"
    cpu: "500m"
  limits:
    memory: "1Gi"
    cpu: "1000m"

Monitoring Queries

# Request rate
rate(gunicorn_worker_requests_total[5m])

# Memory usage
gunicorn_worker_memory_bytes

# CPU usage
gunicorn_worker_cpu_percent

# Error rate
rate(gunicorn_worker_failed_requests_total[5m])