Deployment Options
Condrox AI ships with three deployment paths. Pick the one that matches your scale and operational maturity.
| Option | Recommended For | Notes |
|---|---|---|
| Docker container | Single-node deployments | Recommended for single-node. Uses docker-compose with Prometheus and Grafana included. |
| Kubernetes cluster | Production scale | Recommended for production scale. 9 manifests in k8s/ cover autoscaling, TLS, network policies, and disruption budgets. |
| Direct Python execution | Development only | Run python -m condrox directly. Not suitable for production traffic. |
For anything beyond local development, use Docker or Kubernetes. Direct Python execution lacks process management, health checks, and restart semantics.
Docker Deployment
The Docker setup uses a multi-stage Dockerfile. The build stage installs all dependencies and compiles any native extensions. The runtime stage is based on python:3.11-slim, which keeps the final image small and reduces attack surface.
Container Characteristics
| Property | Value |
|---|---|
| Base image (runtime) | python:3.11-slim |
| Build stage | Full dependency installation and compilation |
| Runtime user | novaspire (UID 1000, non-root) |
| WSGI server | Gunicorn with uvicorn workers |
| Health check | GET /health endpoint |
The container runs as a non-root user named novaspire with UID 1000. This means the process cannot modify system files or bind to privileged ports. If you need port 80 or 443, handle that at the load balancer or ingress layer.
Environment Variables
| Variable | Purpose | Required |
|---|---|---|
API_KEY | Authentication key for API access | Yes |
KNOWLEDGE_DATA_PATH | Path to the knowledge base files | Yes |
GRAFANA_ADMIN_PASSWORD | Admin password for Grafana instance | Yes (with compose) |
CONDROX_SKIP_KNOWLEDGE_LOAD | Skip loading knowledge base on boot (faster startup for testing) | No |
docker-compose.yml
The included docker-compose.yml defines three services:
- Condrox API: The application container running Gunicorn with uvicorn workers.
- Prometheus: Scrapes metrics from the API at the
/metricsendpoint. - Grafana: Visualization layer with pre-configured dashboards connected to Prometheus as a data source.
Example Commands
# Build the container image
docker build -t condrox-ai:3.4.0 .
# Start all services (API, Prometheus, Grafana)
docker-compose up -d
# View logs
docker-compose logs -f condrox-api
# Stop all services
docker-compose down
The first build takes roughly 90 seconds depending on network speed and whether dependency caches are warm. Subsequent builds use Docker layer caching and complete in under 10 seconds if requirements have not changed.
Kubernetes Deployment
The k8s/ directory contains 9 manifests that cover a production-grade deployment. Apply them with kubectl apply -f k8s/ or integrate them into your GitOps workflow.
Manifest Inventory
| Manifest | Kind | Purpose |
|---|---|---|
namespace.yaml | Namespace | Isolated condrox namespace |
configmap.yaml | ConfigMap | Non-sensitive configuration values |
secret.yaml | Secret | API keys and passwords (base64-encoded) |
deployment.yaml | Deployment | 3 replicas (configurable) |
service.yaml | Service | ClusterIP, port 8000 |
ingress.yaml | Ingress | TLS termination at the edge |
hpa.yaml | HorizontalPodAutoscaler | Autoscaling based on CPU |
networkpolicy.yaml | NetworkPolicy | Ingress and egress restrictions |
pdb.yaml | PodDisruptionBudget | Min available 1 during disruptions |
Autoscaling
The HorizontalPodAutoscaler scales the deployment based on CPU utilization:
| Parameter | Value |
|---|---|
| Min replicas | 2 |
| Max replicas | 10 |
| CPU target | 70% |
When average CPU across pods exceeds 70%, the HPA adds replicas up to the max of 10. When CPU drops, it removes replicas down to the min of 2. Scale-up is fast (under 30 seconds once the new pod passes health checks). Scale-down is slower by default to avoid flapping.
Resource Requests and Limits
| Resource | Request | Limit |
|---|---|---|
| Memory | 256Mi | 512Mi |
| CPU | 250m | 500m |
Requests guarantee resources for scheduling. Limits cap usage to prevent a single pod from starving its neighbors. Adjust these based on your actual load patterns after reviewing Prometheus metrics.
Networking
The Service exposes the API on port 8000 via ClusterIP. Internal services within the cluster reach the API through this Service. External traffic enters through the Ingress, which terminates TLS before forwarding plaintext to the Service.
The NetworkPolicy restricts traffic in both directions:
- Ingress: Only traffic to port 8000 is allowed, and only from the Ingress controller namespace.
- Egress: Allowed only to knowledge storage and the database. All other outbound traffic is denied.
The PodDisruptionBudget ensures at least 1 pod stays available during voluntary disruptions like node drains or cluster upgrades. This prevents a rolling update from taking all replicas down at once.
CI/CD Pipeline
The GitHub Actions workflow automates testing, security scanning, building, and deployment. It triggers on every push to main and on all pull requests.
Jobs
| Job | Tool | What It Does |
|---|---|---|
| Test | pytest | Runs the full test suite (938 tests). Fails the pipeline on any test failure. |
| Security | Bandit, Trivy | Bandit runs SAST scanning on Python source. Trivy scans the built container image for known vulnerabilities. |
| Build | Docker | Builds the container image and pushes it to the registry with a version tag and latest. |
| Deploy | kubectl | Applies manifests to staging automatically. Production deployment requires manual approval before proceeding. |
All jobs must pass for deployment to proceed. A failing test, a Bandit finding above the configured severity, or a Trivy vulnerability match will block the build. The deploy job runs kubectl apply -f k8s/ against the staging cluster first, then waits for a human to click approve before applying to production.
# Trigger the pipeline
git push origin main
# Or open a pull request to run tests and security scans
# without deploying
Monitoring
The API exposes a /metrics endpoint in Prometheus format. Prometheus scrapes it at a configurable interval (default 15 seconds) and Grafana queries Prometheus to populate dashboards.
Metrics
9 metrics are exported:
| Metric | Type | What It Measures |
|---|---|---|
| Request count | Counter | Total requests processed |
| Latency histogram | Histogram | Request latency distribution in milliseconds |
| Error rate | Gauge | Current error percentage over a rolling window |
| Active connections | Gauge | Current in-flight requests |
| Memory usage | Gauge | Process RSS in bytes |
| CPU usage | Gauge | Process CPU percentage |
| Knowledge items | Gauge | Number of items loaded in the knowledge base |
| Cache hit rate | Gauge | Embedding cache hit percentage |
| Pipeline stage timing | Histogram | Per-stage latency for all 18 pipeline stages |
Grafana Dashboards
Grafana ships with pre-configured dashboards covering three areas:
- API health: Request rate, error rate, latency percentiles, active connections.
- Performance: Pipeline stage timing breakdown, cache hit rate, knowledge retrieval latency.
- System metrics: Memory usage, CPU usage, pod count, restart count.
The docker-compose.yml includes both Prometheus and Grafana, so a single docker-compose up gives you the full monitoring stack with no extra configuration.
Alerting
Grafana alerting rules are configured for three conditions:
- High error rate: Fires when error rate exceeds 5% over a 5-minute window.
- High latency: Fires when p99 latency exceeds 10 ms over a 5-minute window.
- Low cache hit rate: Fires when embedding cache hit rate drops below 80% over a 10-minute window.
Wire these alerts to your notification channel of choice (Slack, PagerDuty, email) through Grafana's contact points. The alert thresholds are starting points. Tune them based on your baseline traffic patterns.
Configuration
Condrox AI reads its configuration from system_config.yaml, which serves as the central configuration file. Every critical setting can be overridden by an environment variable, which takes precedence over the YAML value. This lets you run the same image in development, staging, and production with different configs.
Key Settings
| Setting | Default | Notes |
|---|---|---|
| Knowledge data path | E:\Data\condrox\knowledge | Configurable. Mount this as a volume in Docker or a PersistentVolume in Kubernetes. |
| Persistence path | SQLite database location | Store on persistent storage. Losing this file means losing session memory and conversation history. |
| Single instance lock | Enabled | Prevents multiple instances from writing to the same SQLite database. Disable only if you have external coordination. |
The knowledge data path defaults to E:\Data\condrox\knowledge because that is where the development environment stores it. In Docker, override this with KNOWLEDGE_DATA_PATH and mount a volume at that path. In Kubernetes, use a PersistentVolumeClaim.
Performance Characteristics
These numbers come from the benchmark suite running on actual hardware. They describe what you can expect from a single instance under normal load.
| Metric | Value | Notes |
|---|---|---|
| API latency (p50) | 0.748 ms average | Sub-millisecond for most requests |
| Throughput | 1,785 req/s | Single instance, no horizontal scaling |
| Memory per request | 0.010 MB peak | Per-request allocation, not sustained |
| Boot time | ~3 seconds | With knowledge loading enabled |
| Test suite | 938 tests in ~210 seconds | Full suite including Evidence Engine integration tests |
Boot time drops to under 1 second when CONDROX_SKIP_KNOWLEDGE_LOAD is set, but the API will return empty results for knowledge queries until the base is loaded manually. Use this only for testing.
Production Checklist
Run through this list before pointing real traffic at your deployment. Each item addresses a common failure mode.
Before You Go Live
- Set
API_KEYenvironment variable to a strong random value. Use at least 32 characters of mixed case, digits, and symbols. - Configure
CORS_ALLOWED_ORIGINSto your frontend domain. Do not leave it set to wildcard in production. - Set up TLS termination at the load balancer or ingress. Redirect all HTTP traffic to HTTPS.
- Configure persistent storage for the SQLite database. Use a PersistentVolumeClaim in Kubernetes or a named volume in Docker.
- Mount the knowledge data volume. Confirm the path matches
KNOWLEDGE_DATA_PATH. - Set up Grafana alerting. Wire the three default alerts to your on-call notification channel.
- Configure log aggregation. Ship container logs to your central logging system (ELK, Loki, CloudWatch, etc.).
- Set resource limits appropriate to your cluster. The defaults (256Mi/250m requests, 512Mi/500m limits) are starting points, not gospel.
- Enable the PodDisruptionBudget. Confirm
minAvailable: 1is set before draining nodes. - Test failover with pod deletion. Delete a pod manually and verify the deployment recovers without user-visible errors.
If you cannot check every box, figure out which ones are blocked and why. Going live with gaps in TLS, authentication, or persistence will cause problems that are harder to fix under load.