Copy Common Deployment Recipes
Note: These recipes assume you are running from a checkout of the repository. For the full server env list and endpoint shapes, see Configuration and Environment Reference and REST API Reference.
Start a Simple Docker Compose Instance
Run the repository's shipped Compose stack with a persistent SQLite database and the combined UI/API on port 8000.
cat > .env <<'EOF'
JENKINS_URL=https://ci.example.com
JENKINS_USER=svc-jji
JENKINS_PASSWORD=jenkins-api-token-123
AI_PROVIDER=claude
AI_MODEL=claude-opus-4-1
ANTHROPIC_API_KEY=anthropic-demo-key-123
JJI_ENCRYPTION_KEY=change-this-before-prod-32chars
PUBLIC_BASE_URL=http://localhost:8000
SECURE_COOKIES=false
LOG_LEVEL=INFO
EOF
mkdir -p data
docker compose up -d --build
docker compose ps
curl -fsS http://localhost:8000/health
This uses the repository's docker-compose.yaml as-is: it builds Dockerfile, mounts ./data to /data, and keeps the container healthy with a /health probe. It is the fastest way to get a persistent JJI instance running from the repo checkout. After it is up, see Analyze Your First Jenkins Job for the first-run flow.
- For public HTTPS, change
PUBLIC_BASE_URLto your externalhttps://...URL and setSECURE_COOKIES=true. - If Jenkins uses a self-signed certificate, add
JENKINS_SSL_VERIFY=falseto.env. - If you change
PORT, update the Compose port mapping and healthcheck to match.
Run Container Dev Mode with Hot Reload
Start backend reload and frontend HMR inside the container without switching away from Docker.
cat > .env <<'EOF'
JENKINS_URL=https://ci.example.com
JENKINS_USER=svc-jji
JENKINS_PASSWORD=jenkins-api-token-123
AI_PROVIDER=claude
AI_MODEL=claude-opus-4-1
ANTHROPIC_API_KEY=anthropic-demo-key-123
JJI_ENCRYPTION_KEY=dev-only-encryption-key
SECURE_COOKIES=false
LOG_LEVEL=DEBUG
EOF
cat > docker-compose.override.yaml <<'EOF'
services:
jenkins-job-insight:
environment:
- DEV_MODE=true
ports:
- "5173:5173"
volumes:
- ./src:/app/src
- ./frontend:/app/frontend
EOF
mkdir -p data
docker compose up --build
With DEV_MODE=true, entrypoint.sh starts Vite on 5173 and appends uvicorn --reload --reload-dir /app/src for backend code changes. Open http://localhost:5173 for the UI; Vite proxies API traffic to the backend on http://localhost:8000.
Warning: Keep
SECURE_COOKIES=falseonly for local HTTP development.
- The first startup may run
npm installinside the container iffrontend/node_modulesis missing.
Put JJI Behind a Reverse Proxy
Terminate traffic at a proxy and keep the JJI app itself off the public port.
cat > .env.proxy <<'EOF'
JENKINS_URL=https://ci.example.com
JENKINS_USER=svc-jji
JENKINS_PASSWORD=jenkins-api-token-123
AI_PROVIDER=claude
AI_MODEL=claude-opus-4-1
ANTHROPIC_API_KEY=anthropic-demo-key-123
JJI_ENCRYPTION_KEY=change-this-before-prod-32chars
PUBLIC_BASE_URL=http://localhost:8080
SECURE_COOKIES=false
EOF
cat > nginx.conf <<'EOF'
events {}
http {
server {
listen 80;
server_name _;
location / {
proxy_pass http://jji:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
EOF
cat > compose.proxy.yaml <<'EOF'
services:
jji:
build: .
env_file:
- .env.proxy
volumes:
- ./data:/data
nginx:
image: nginx:alpine
depends_on:
- jji
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
EOF
mkdir -p data
docker compose -f compose.proxy.yaml up -d --build
This makes the proxy the only entry point and keeps JJI itself on the internal Compose network. PUBLIC_BASE_URL matters because JJI does not derive external links from request headers, so set it to the exact URL users will open.
- For public HTTPS, terminate TLS at the proxy, change
PUBLIC_BASE_URLtohttps://..., and setSECURE_COOKIES=true. - If your auth layer injects
X-Forwarded-User, addTRUST_PROXY_HEADERS=trueto JJI andproxy_set_header X-Forwarded-User $http_x_forwarded_user;to the proxy. - JJI ignores
X-Forwarded-User: admin;adminstays reserved for real admin auth.
Smoke-Test the Health Endpoints
Check that the service is up and inspect the detailed dependency view before you route traffic to it.
set -euo pipefail
BASE_URL=http://localhost:8000
echo "Lightweight health:"
curl -fsS "$BASE_URL/health"
echo
echo
echo "Detailed health:"
curl -fsS "$BASE_URL/api/health"
echo
/health is the lightweight endpoint used by the container healthcheck. /api/health adds database, Jenkins, AI provider, and Report Portal checks, and returns 503 only when JJI is actually unhealthy.
/health,/api/health, and/metricsare excluded from JJI's rolling error counters, so normal probes do not skewjji_error_rate.
Scrape Built-In Prometheus Metrics
Collect JJI's rolling-window metrics without adding an exporter sidecar.
cat > prometheus.yml <<'EOF'
global:
scrape_interval: 30s
scrape_configs:
- job_name: jenkins-job-insight
metrics_path: /metrics
static_configs:
- targets:
- jenkins-job-insight:8000
EOF
cat > compose.metrics.yaml <<'EOF'
services:
prometheus:
image: prom/prometheus
command:
- --config.file=/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
EOF
docker compose -f docker-compose.yaml -f compose.metrics.yaml up -d --build
This starts Prometheus alongside the repository's Compose service and scrapes JJI directly on the Compose network. JJI publishes rolling-window gauges for jji_requests_total, jji_errors_total, jji_error_rate, jji_errors_by_class, plus jji_health_up and jji_active_analyses.
- Open
http://localhost:9090/targetsto confirm the scrape isUP. - If Prometheus runs elsewhere, replace
jenkins-job-insight:8000with your service DNS name or external host:port. jji_health_upis1for bothhealthyanddegraded, and0only when/api/healthisunhealthy.
Send Lightweight Slack and Email Alerts
Let a single JJI instance notify you when 5xx responses spike, without waiting on external monitoring.
cat > .env <<'EOF'
JENKINS_URL=https://ci.example.com
JENKINS_USER=svc-jji
JENKINS_PASSWORD=jenkins-api-token-123
AI_PROVIDER=claude
AI_MODEL=claude-opus-4-1
ANTHROPIC_API_KEY=anthropic-demo-key-123
JJI_ENCRYPTION_KEY=change-this-before-prod-32chars
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/EXAMPLE/WEBHOOK/URL
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=jji-alerts@example.com
SMTP_PASSWORD=smtp-app-password-123
SMTP_FROM=jji-alerts@example.com
ALERT_EMAIL_TO=sre@example.com
EOF
mkdir -p data
docker compose up -d --build
JJI dispatches best-effort Slack and email alerts when its 5-minute rolling 5xx error rate goes above 50% and at least 10 requests have been seen. Duplicate alert events are throttled for 5 minutes, so this works well as a lightweight single-instance safety net.
- Slack webhook URLs should use
https://. - If you set
SMTP_HOSTwithoutALERT_EMAIL_TO, JJI starts but warns that email alerts will not be sent.
Apply the OpenShift PrometheusRule
Use the repository's current OpenShift alert thresholds for warning, critical, and health-down conditions.
oc apply -f - <<'EOF'
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: jenkins-job-insight-alerts
labels:
app: jenkins-job-insight
spec:
groups:
- name: jenkins-job-insight.rules
rules:
- alert: JJIHighErrorRate
expr: jji_error_rate > 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "JJI high error rate"
description: >
JJI error rate is {{ $value | humanizePercentage }} over the
rolling window (threshold 10%).
- alert: JJIVeryHighErrorRate
expr: jji_error_rate > 0.5
for: 2m
labels:
severity: critical
annotations:
summary: "JJI critical error rate"
description: >
JJI error rate is {{ $value | humanizePercentage }} over the
rolling window (threshold 50%).
- alert: JJIHealthUnhealthy
expr: jji_health_up == 0
for: 5m
labels:
severity: critical
annotations:
summary: "JJI health check failing"
description: "JJI /api/health is returning 503 (unhealthy) for over 5 minutes."
EOF
This matches the rule shipped in docs/openshift-prometheus-rule.yaml. Use it after OpenShift monitoring is scraping JJI's /metrics endpoint so you get two error-rate thresholds and one hard health-down alert.
- Add any labels your Alertmanager routing expects before applying the rule.
- The container image is already prepared for OpenShift-style arbitrary UID runtimes; the main deployment requirement is a writable
/datavolume.