added repo

This commit is contained in:
Your Name
2026-08-26 03:39:42 +05:30
parent 45c25a95af
commit b8575bb8b9
6889 changed files with 1217125 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
+20
View File
@@ -0,0 +1,20 @@
apiVersion: v2
appVersion: 1.4.11
description: A Helm chart for deploying Bifrost - AI Gateway with unified interface
for multiple providers
home: https://www.getmaxim.ai/bifrost
icon: https://www.getbifrost.ai/favicon.png
keywords:
- ai
- gateway
- llm
- openai
- anthropic
maintainers:
- email: support@getbifrost.ai
name: Bifrost Team
name: bifrost
sources:
- https://github.com/maximhq/bifrost
type: application
version: 2.0.14
+656
View File
@@ -0,0 +1,656 @@
# Bifrost Helm Charts
[![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/bifrost)](https://artifacthub.io/packages/helm/bifrost/bifrost)
Official Helm charts for deploying [Bifrost](https://github.com/maximhq/bifrost) - a high-performance AI gateway with unified interface for multiple providers.
**Latest Version:** 2.0.14
## Changelog
### v2.0.14
- Added `placement` and `order` fields to custom plugin schema and template rendering
- Added plugin property completeness check to `validate-helm-schema.sh`
- Added custom plugin placement/order rendering tests to `validate-helm-templates.sh`
- Added `PluginConfig` struct validation to `validate-go-config-fields.sh`
### v2.0.13
- Added missing client config properties: `asyncJobResultTTL`, `requiredHeaders`, `loggingHeaders`, `allowedHeaders`, `mcpAgentDepth`, `mcpToolExecutionTimeout`, `mcpCodeModeBindingLevel`, `mcpToolSyncInterval`, `hideDeletedVirtualKeysInFilters`
- Added MCP new fields: top-level `toolSyncInterval`, per-client `clientId`, `isCodeModeClient`, `toolSyncInterval`, `isPingAvailable`, `toolPricing`, and `codeModeBindingLevel` in tool manager config
- Added governance `modelConfigs` and `providers` top-level properties
- Added cluster `region` property
- Added guardrail provider `timeout` field (was missing from schema and template rendering)
- Fixed `isPingAvailable` rendering bug in `_helpers.tpl` (was using wrong key name)
- Added `is_ping_available` and `tool_pricing` to `config.schema.json` MCP client config
- Added new CI script `validate-go-config-fields.sh` for Go struct-to-schema drift detection
- Expanded all 3 existing CI validation scripts with Gap 1-8 property coverage
### v2.0.12
- Fixed health probe paths to use `/health` instead of `/metrics`
### v2.0.11
- Bumped appVersion to 1.4.11
### v2.0.10
- Added missing plugin config properties from Go implementations:
- governance: `required_headers`, `is_enterprise`
- logging: `disable_content_logging`, `logging_headers`
- otel: `headers`, `tls_ca_cert`, `insecure`
- telemetry: `custom_labels`
### v2.0.9
- Bumped appVersion to 1.4.8
### v2.0.8
- Added comprehensive config field coverage for all `config.schema.json` fields
- Added Pinecone vector store support (external only) with secret injection
- Added governance routing rules template support
- Added OTEL metrics fields (metrics_enabled, metrics_endpoint, metrics_push_interval)
- Added advanced Redis connection pool fields (pool_size, timeouts, idle conns, etc.)
- Added Weaviate timeout and className fields
- Expanded values.yaml with commented examples for all provider types (Azure, Vertex, Bedrock), network config, concurrency, proxy config, and governance entities
- Added helm config field validation CI test (246 assertions covering all config.schema.json fields)
### v2.0.7
- Previous release
### v2.0.6
- Fixes MCP client config template to convert camelCase Helm values to snake_case config format
### v2.0.5
- Fixes config field validation parity
### v2.0.2
- Added Qdrant vector store support with deployment, service, and PVC templates
- Added headless service template for StatefulSet DNS resolution
- Fixed gitignore pattern that was excluding template files from version control
### v2.0.1
- Added missing StatefulSet template for SQLite with persistence mode
- Added headless service for StatefulSet DNS resolution
- v2.0.0 documented StatefulSet support but the template was not included - this release fixes that
### v2.0.0 (Breaking Change)
#### StatefulSet for SQLite with Persistence
This release fixes the multi-attach volume error when running multiple replicas with SQLite storage mode.
#### What Changed
- When using `storage.mode: sqlite` with `storage.persistence.enabled: true`, Bifrost now deploys as a **StatefulSet** instead of a Deployment
- Each pod gets its own dedicated PersistentVolumeClaim (e.g., `data-bifrost-0`, `data-bifrost-1`, `data-bifrost-2`)
- A headless service is created for StatefulSet DNS resolution
- HorizontalPodAutoscaler now correctly references StatefulSet or Deployment based on storage configuration
#### Who Is Affected
- Users running SQLite mode with persistence enabled and multiple replicas
- Users upgrading existing SQLite deployments need to migrate (see below)
#### Who Is NOT Affected
- Users running PostgreSQL mode (`storage.mode: postgres`) - no changes, still uses Deployment
- Users running SQLite without persistence (`storage.persistence.enabled: false`)
- Users running SQLite with an existing PVC claim (`storage.persistence.existingClaim`)
#### Migration Guide for Existing SQLite Deployments
Since Kubernetes doesn't allow in-place conversion from Deployment to StatefulSet, you need to:
1. Back up your data (if needed)
2. Uninstall the existing release: `helm uninstall bifrost`
3. Delete the old PVC: `kubectl delete pvc bifrost-data`
4. Install with the new chart version: `helm install bifrost bifrost/bifrost --set image.tag=<latest-image>`
**Note:** For production high-availability setups, we recommend using PostgreSQL mode which scales horizontally without these concerns.
### v1.7.0
- Previous stable release with Deployment-based architecture for all storage modes
## Quick Start
```bash
# Add the Bifrost Helm repository
helm repo add bifrost https://maximhq.github.io/bifrost/helm-charts
# Update your local Helm chart repository cache
helm repo update
# Install Bifrost with default configuration (SQLite storage)
helm install bifrost bifrost/bifrost --set image.tag=v1.4.3
```
## Prerequisites
- Kubernetes 1.23+
- Helm 3.2.0+
- PV provisioner support in the underlying infrastructure (for persistent storage)
## Installation
### From Helm Repository (Recommended)
```bash
# Add repository
helm repo add bifrost https://maximhq.github.io/bifrost/helm-charts
helm repo update
# Install with default values
helm install bifrost bifrost/bifrost --set image.tag=v1.4.3
# Or install with custom values
helm install bifrost bifrost/bifrost -f my-values.yaml
```
### From Source
```bash
# Clone the repository
git clone https://github.com/maximhq/bifrost.git
cd bifrost/helm-charts
# Install from local chart
helm install bifrost ./bifrost --set image.tag=v1.5.2
```
### Interactive Installation
Use the included installation script for guided setup:
```bash
cd bifrost/helm-charts/bifrost
./scripts/install.sh
```
## Configuration
### Image Configuration
| Parameter | Description | Default |
|-----------|-------------|---------|
| `image.repository` | Container image repository | `docker.io/maximhq/bifrost` |
| `image.tag` | Container image tag (required) | `""` |
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
> **Important:** You must specify the `image.tag`. See available tags at [Docker Hub](https://hub.docker.com/r/maximhq/bifrost/tags).
### Enterprise Private Registry
For enterprise customers with private container registries, simply override the `image.repository` with your full registry URL:
```yaml
# Google Artifact Registry
image:
repository: us-west1-docker.pkg.dev/bifrost-enterprise/your-org/bifrost
tag: v1.5.0
# AWS ECR
image:
repository: 123456789.dkr.ecr.us-east-1.amazonaws.com/bifrost
tag: v1.5.0
# Azure Container Registry
image:
repository: yourregistry.azurecr.io/bifrost
tag: v1.5.0
# Self-hosted registry
image:
repository: registry.yourcompany.com/ai/bifrost
tag: v1.5.0
```
If your private registry requires authentication, configure `imagePullSecrets`:
```yaml
image:
repository: us-west1-docker.pkg.dev/bifrost-enterprise/your-org/bifrost
tag: v1.5.0
imagePullSecrets:
- name: my-registry-secret
```
Create the secret beforehand:
```bash
kubectl create secret docker-registry my-registry-secret \
--docker-server=us-west1-docker.pkg.dev \
--docker-username=_json_key \
--docker-password="$(cat key.json)" \
--docker-email=your-email@example.com
```
### Storage Configuration
Bifrost supports two storage backends (SQLite and PostgreSQL) that can be configured independently for config and logs stores.
| Parameter | Description | Default |
|-----------|-------------|---------|
| `storage.mode` | Default storage backend (fallback when per-store type not set) | `sqlite` |
| `storage.persistence.enabled` | Enable persistent storage for SQLite | `true` |
| `storage.persistence.size` | Storage size | `10Gi` |
| `storage.configStore.enabled` | Enable configuration store | `true` |
| `storage.configStore.type` | Config store backend: `sqlite`, `postgres`, or `""` | `""` (uses `storage.mode`) |
| `storage.logsStore.enabled` | Enable logs store | `true` |
| `storage.logsStore.type` | Logs store backend: `sqlite`, `postgres`, or `""` | `""` (uses `storage.mode`) |
#### Mixed Backend Example
You can use different backends for config and logs stores:
```yaml
storage:
mode: sqlite # Default fallback
configStore:
enabled: true
type: sqlite # Config in SQLite (fast, local)
logsStore:
enabled: true
type: postgres # Logs in PostgreSQL (scalable, queryable)
postgresql:
enabled: true
# ... PostgreSQL configuration for logs store
```
### PostgreSQL Configuration
| Parameter | Description | Default |
|-----------|-------------|---------|
| `postgresql.enabled` | Deploy PostgreSQL | `false` |
| `postgresql.auth.username` | Database username | `bifrost` |
| `postgresql.auth.password` | Database password | `bifrost_password` |
| `postgresql.auth.database` | Database name | `bifrost` |
| `postgresql.external.enabled` | Use external PostgreSQL | `false` |
| `postgresql.external.host` | External PostgreSQL host | `""` |
### Vector Store Configuration (Semantic Caching)
Bifrost supports multiple vector stores for semantic caching:
| Parameter | Description | Default |
|-----------|-------------|---------|
| `vectorStore.enabled` | Enable vector store | `false` |
| `vectorStore.type` | Vector store type: `none`, `weaviate`, `redis`, `qdrant` | `none` |
#### Weaviate
```yaml
vectorStore:
enabled: true
type: weaviate
weaviate:
enabled: true # Deploy Weaviate
# Or use external:
# external:
# enabled: true
# host: "weaviate.example.com"
```
#### Redis
```yaml
vectorStore:
enabled: true
type: redis
redis:
enabled: true # Deploy Redis
# Or use external:
# external:
# enabled: true
# host: "redis.example.com"
```
#### Qdrant
```yaml
vectorStore:
enabled: true
type: qdrant
qdrant:
enabled: true # Deploy Qdrant
# Or use external:
# external:
# enabled: true
# host: "qdrant.example.com"
```
### Bifrost Application Configuration
| Parameter | Description | Default |
|-----------|-------------|---------|
| `bifrost.port` | Application port | `8080` |
| `bifrost.host` | Bind address | `0.0.0.0` |
| `bifrost.logLevel` | Log level | `info` |
| `bifrost.logStyle` | Log format: `json` or `text` | `json` |
| `bifrost.encryptionKey` | Encryption key for sensitive data | `""` |
### Provider Configuration
Configure AI provider API keys:
```yaml
bifrost:
providers:
openai:
keys:
- value: "sk-..."
weight: 1
anthropic:
keys:
- value: "sk-ant-..."
weight: 1
```
### Plugins Configuration
| Plugin | Parameter | Description |
|--------|-----------|-------------|
| Telemetry | `bifrost.plugins.telemetry.enabled` | Enable metrics collection |
| Logging | `bifrost.plugins.logging.enabled` | Enable request logging |
| Governance | `bifrost.plugins.governance.enabled` | Enable budget management |
| Semantic Cache | `bifrost.plugins.semanticCache.enabled` | Enable semantic caching |
| OTEL | `bifrost.plugins.otel.enabled` | Enable OpenTelemetry integration |
| Maxim | `bifrost.plugins.maxim.enabled` | Enable Maxim observability |
| Datadog | `bifrost.plugins.datadog.enabled` | Enable Datadog APM integration |
| Custom | `bifrost.plugins.custom` | Array of custom/dynamic plugins |
#### Custom Plugins
You can add custom/dynamic plugins using the `bifrost.plugins.custom` array:
```yaml
bifrost:
plugins:
custom:
- name: "my-custom-plugin"
enabled: true
path: "/plugins/my-plugin.so"
version: 1
placement: "pre_builtin" # or "post_builtin" (default)
order: 0 # execution order within placement group
config:
key: value
```
### Client Configuration
| Parameter | Description | Default |
|-----------|-------------|---------|
| `bifrost.client.disableDbPingsInHealth` | Disable DB pings in health check | `false` |
| `bifrost.client.headerFilterConfig.allowlist` | Headers allowed to forward to LLM providers | `[]` |
| `bifrost.client.headerFilterConfig.denylist` | Headers blocked from forwarding | `[]` |
### MCP Configuration
| Parameter | Description | Default |
|-----------|-------------|---------|
| `bifrost.mcp.enabled` | Enable MCP (Model Context Protocol) | `false` |
| `bifrost.mcp.clientConfigs` | Array of MCP client configurations | `[]` |
| `bifrost.mcp.toolManagerConfig.toolExecutionTimeout` | Tool execution timeout in seconds | `30` |
| `bifrost.mcp.toolManagerConfig.maxAgentDepth` | Maximum agent depth | `10` |
### Ingress Configuration
```yaml
ingress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
hosts:
- host: bifrost.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: bifrost-tls
hosts:
- bifrost.example.com
```
### Auto-scaling Configuration
```yaml
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 80
targetMemoryUtilizationPercentage: 80
```
## Example Configurations
The chart includes pre-configured examples in `values-examples/`:
| Configuration | Description |
|---------------|-------------|
| `sqlite-only.yaml` | Simple setup with SQLite (local development) |
| `postgres-only.yaml` | PostgreSQL for config and logs |
| `mixed-backend.yaml` | SQLite for config + PostgreSQL for logs (mixed backend) |
| `postgres-weaviate.yaml` | PostgreSQL + Weaviate for semantic caching |
| `postgres-redis.yaml` | PostgreSQL + Redis for semantic caching |
| `postgres-qdrant.yaml` | PostgreSQL + Qdrant for semantic caching |
| `sqlite-weaviate.yaml` | SQLite + Weaviate |
| `sqlite-redis.yaml` | SQLite + Redis |
| `sqlite-qdrant.yaml` | SQLite + Qdrant |
| `external-postgres.yaml` | Using external PostgreSQL |
| `production-ha.yaml` | Production high-availability setup |
### Using Example Configurations
```bash
# From Helm repository
helm install bifrost bifrost/bifrost \
-f https://raw.githubusercontent.com/maximhq/bifrost/main/helm-charts/bifrost/values-examples/postgres-only.yaml \
--set image.tag=v1.5.2
# From local source
helm install bifrost ./bifrost -f ./bifrost/values-examples/postgres-only.yaml
```
## Production Deployment
For production deployments, we recommend:
1. **Use PostgreSQL** for reliable data persistence
2. **Enable semantic caching** with Weaviate, Redis, or Qdrant
3. **Configure auto-scaling** for handling variable load
4. **Set up Ingress** with TLS termination
5. **Use external secrets** for sensitive data
### Example Production Setup
```yaml
# production-values.yaml
replicaCount: 3
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
storage:
mode: postgres
postgresql:
enabled: true
auth:
password: "SECURE_PASSWORD_HERE"
primary:
persistence:
size: 50Gi
vectorStore:
enabled: true
type: weaviate
weaviate:
enabled: true
persistence:
size: 50Gi
ingress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
hosts:
- host: bifrost.yourdomain.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: bifrost-tls
hosts:
- bifrost.yourdomain.com
bifrost:
client:
initialPoolSize: 1000
allowedOrigins:
- "https://yourdomain.com"
plugins:
semanticCache:
enabled: true
telemetry:
enabled: true
logging:
enabled: true
```
## Upgrading
```bash
# Update repository
helm repo update
# Upgrade release
helm upgrade bifrost bifrost/bifrost --set image.tag=v1.5.2
# Or with custom values
helm upgrade bifrost bifrost/bifrost -f my-values.yaml
```
## Uninstalling
```bash
# Uninstall release
helm uninstall bifrost
# If you want to delete persistent volumes
kubectl delete pvc -l app.kubernetes.io/name=bifrost
```
## Accessing Bifrost
After installation, access Bifrost using one of these methods:
### Port Forwarding (Development)
```bash
kubectl port-forward svc/bifrost 8080:8080
# Then visit http://localhost:8080
```
### LoadBalancer
```yaml
service:
type: LoadBalancer
```
### Ingress
Configure the `ingress` section as shown above.
## Monitoring
Bifrost exposes Prometheus metrics at `/metrics`:
```bash
# Get metrics
curl http://localhost:8080/metrics
```
For OpenTelemetry integration:
```yaml
bifrost:
plugins:
otel:
enabled: true
config:
service_name: "bifrost"
collector_url: "http://otel-collector:4317"
trace_type: "otel"
protocol: "grpc"
```
## Troubleshooting
### Check Pod Status
```bash
kubectl get pods -l app.kubernetes.io/name=bifrost
kubectl describe pod <pod-name>
```
### View Logs
```bash
kubectl logs -l app.kubernetes.io/name=bifrost -f
```
### Check Configuration
```bash
# View generated configmap
kubectl get configmap bifrost -o yaml
# View generated secrets
kubectl get secret bifrost -o yaml
```
### Common Issues
**Pod stuck in Pending state:**
- Check if PersistentVolume is available: `kubectl get pv`
- Check storage class: `kubectl get storageclass`
**Pod CrashLoopBackOff:**
- Check logs: `kubectl logs <pod-name>`
- Verify environment variables and secrets
**Cannot connect to PostgreSQL:**
- Ensure PostgreSQL pod is running
- Check connection string in configmap/secrets
- Verify network policies allow connectivity
## Resources
- [Bifrost Documentation](https://docs.getbifrost.ai)
- [GitHub Repository](https://github.com/maximhq/bifrost)
- [Docker Hub](https://hub.docker.com/r/maximhq/bifrost)
- [Discord Community](https://discord.gg/exN5KAydbU)
## License
This project is licensed under the Apache 2.0 License - see the [LICENSE](../LICENSE) file for details.
Built with ❤️ by [Maxim](https://github.com/maximhq)
@@ -0,0 +1,393 @@
#!/bin/bash
# Bifrost Values File Generator
# This interactive script helps you generate a custom values.yaml file
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
print_info() { echo -e "${BLUE} ${NC}$1"; }
print_success() { echo -e "${GREEN}${NC}$1"; }
print_warning() { echo -e "${YELLOW}${NC}$1"; }
print_error() { echo -e "${RED}${NC}$1"; }
print_banner() {
echo ""
echo -e "${BLUE}╔═══════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ ║${NC}"
echo -e "${BLUE}║ Bifrost Values Generator ║${NC}"
echo -e "${BLUE}║ ║${NC}"
echo -e "${BLUE}╚═══════════════════════════════════════════╝${NC}"
echo ""
}
print_banner
OUTPUT_FILE="my-values.yaml"
# Storage configuration - per-store backend selection
echo "1. Select backend for Config Store:"
echo " 1) SQLite (simple, single node)"
echo " 2) PostgreSQL (production, scalable)"
read -p "Choice [1-2]: " config_store_choice
case $config_store_choice in
1) CONFIG_STORE_TYPE="sqlite" ;;
2) CONFIG_STORE_TYPE="postgres" ;;
*) print_error "Invalid choice"; exit 1 ;;
esac
echo ""
echo "2. Select backend for Logs Store:"
echo " 1) SQLite (simple, single node)"
echo " 2) PostgreSQL (production, scalable)"
read -p "Choice [1-2]: " logs_store_choice
case $logs_store_choice in
1) LOGS_STORE_TYPE="sqlite" ;;
2) LOGS_STORE_TYPE="postgres" ;;
*) print_error "Invalid choice"; exit 1 ;;
esac
# Determine if PostgreSQL is needed (for either store)
if [[ "$CONFIG_STORE_TYPE" == "postgres" ]] || [[ "$LOGS_STORE_TYPE" == "postgres" ]]; then
NEEDS_POSTGRES="true"
else
NEEDS_POSTGRES="false"
fi
# Determine if SQLite persistence is needed (for either store)
if [[ "$CONFIG_STORE_TYPE" == "sqlite" ]] || [[ "$LOGS_STORE_TYPE" == "sqlite" ]]; then
NEEDS_SQLITE_PERSISTENCE="true"
else
NEEDS_SQLITE_PERSISTENCE="false"
fi
# Vector store
echo ""
echo "3. Do you need vector store for semantic caching?"
read -p "Enable vector store? (y/n): " vector_choice
if [[ "$vector_choice" =~ ^[Yy]$ ]]; then
echo " 1) Weaviate"
echo " 2) Redis"
echo " 3) Qdrant"
read -p "Choice [1-3]: " vector_type_choice
case $vector_type_choice in
1) VECTOR_TYPE="weaviate" ;;
2) VECTOR_TYPE="redis" ;;
3) VECTOR_TYPE="qdrant" ;;
*) print_error "Invalid choice"; exit 1 ;;
esac
VECTOR_ENABLED="true"
else
VECTOR_ENABLED="false"
VECTOR_TYPE="none"
fi
# Deployment type
echo ""
echo "4. Deployment type:"
echo " 1) Development (1 replica, minimal resources)"
echo " 2) Production (3+ replicas, auto-scaling)"
read -p "Choice [1-2]: " deploy_choice
case $deploy_choice in
1)
REPLICAS="1"
AUTOSCALING="false"
CPU_REQUEST="250m"
MEM_REQUEST="256Mi"
CPU_LIMIT="1000m"
MEM_LIMIT="1Gi"
;;
2)
REPLICAS="3"
AUTOSCALING="true"
CPU_REQUEST="1000m"
MEM_REQUEST="1Gi"
CPU_LIMIT="4000m"
MEM_LIMIT="4Gi"
;;
*) print_error "Invalid choice"; exit 1 ;;
esac
# Ingress
echo ""
read -p "5. Do you want to enable Ingress? (y/n): " ingress_choice
if [[ "$ingress_choice" =~ ^[Yy]$ ]]; then
INGRESS_ENABLED="true"
read -p " Enter your domain (e.g., bifrost.yourdomain.com): " DOMAIN
else
INGRESS_ENABLED="false"
DOMAIN="bifrost.local"
fi
# Encryption key
echo ""
read -p "6. Enter encryption key (leave empty to skip): " ENCRYPTION_KEY
# Check if output file already exists
if [[ -f "$OUTPUT_FILE" ]]; then
echo ""
print_warning "File '$OUTPUT_FILE' already exists."
read -p "Do you want to overwrite it? (y/n): " overwrite_choice
if [[ ! "$overwrite_choice" =~ ^[Yy]$ ]]; then
print_info "Generation aborted. No files were modified."
exit 0
fi
fi
# Generate the file
print_info "Generating values file..."
cat > "$OUTPUT_FILE" <<EOF
# Generated Bifrost values file
# Generated on: $(date)
# Deployment configuration
replicaCount: ${REPLICAS}
autoscaling:
enabled: ${AUTOSCALING}
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70
resources:
limits:
cpu: ${CPU_LIMIT}
memory: ${MEM_LIMIT}
requests:
cpu: ${CPU_REQUEST}
memory: ${MEM_REQUEST}
# Storage configuration (per-store backend selection)
storage:
mode: sqlite # Default fallback
EOF
if [[ "$NEEDS_SQLITE_PERSISTENCE" == "true" ]]; then
cat >> "$OUTPUT_FILE" <<EOF
persistence:
enabled: true
size: 10Gi
EOF
fi
cat >> "$OUTPUT_FILE" <<EOF
configStore:
enabled: true
type: ${CONFIG_STORE_TYPE}
logsStore:
enabled: true
type: ${LOGS_STORE_TYPE}
EOF
# PostgreSQL configuration
if [[ "$NEEDS_POSTGRES" == "true" ]]; then
cat >> "$OUTPUT_FILE" <<EOF
# PostgreSQL configuration (used by: $(
stores=""
[[ "$CONFIG_STORE_TYPE" == "postgres" ]] && stores="config store"
[[ "$LOGS_STORE_TYPE" == "postgres" ]] && { [[ -n "$stores" ]] && stores="$stores, logs store" || stores="logs store"; }
echo "$stores"
))
postgresql:
enabled: true
auth:
username: bifrost
password: "CHANGE_ME_SECURE_PASSWORD"
database: bifrost
primary:
persistence:
enabled: true
size: 20Gi
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
EOF
else
cat >> "$OUTPUT_FILE" <<EOF
# PostgreSQL disabled (using SQLite for all stores)
postgresql:
enabled: false
EOF
fi
# Vector store configuration
cat >> "$OUTPUT_FILE" <<EOF
# Vector store configuration
vectorStore:
enabled: ${VECTOR_ENABLED}
type: ${VECTOR_TYPE}
EOF
if [[ "$VECTOR_TYPE" == "weaviate" ]] && [[ "$VECTOR_ENABLED" == "true" ]]; then
cat >> "$OUTPUT_FILE" <<EOF
weaviate:
enabled: true
replicas: 1
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
EOF
elif [[ "$VECTOR_TYPE" == "redis" ]] && [[ "$VECTOR_ENABLED" == "true" ]]; then
cat >> "$OUTPUT_FILE" <<EOF
redis:
enabled: true
auth:
enabled: true
password: "CHANGE_ME_REDIS_PASSWORD"
master:
persistence:
enabled: true
size: 8Gi
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
EOF
elif [[ "$VECTOR_TYPE" == "qdrant" ]] && [[ "$VECTOR_ENABLED" == "true" ]]; then
cat >> "$OUTPUT_FILE" <<EOF
qdrant:
enabled: true
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
EOF
fi
# Ingress
cat >> "$OUTPUT_FILE" <<EOF
# Ingress configuration
ingress:
enabled: ${INGRESS_ENABLED}
EOF
if [[ "$INGRESS_ENABLED" == "true" ]]; then
cat >> "$OUTPUT_FILE" <<EOF
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
hosts:
- host: ${DOMAIN}
paths:
- path: /
pathType: Prefix
tls:
- secretName: bifrost-tls
hosts:
- ${DOMAIN}
EOF
fi
# Bifrost configuration
cat >> "$OUTPUT_FILE" <<EOF
# Bifrost application configuration
bifrost:
EOF
if [[ -n "$ENCRYPTION_KEY" ]]; then
cat >> "$OUTPUT_FILE" <<EOF
encryptionKey: "${ENCRYPTION_KEY}"
EOF
fi
cat >> "$OUTPUT_FILE" <<EOF
client:
enableLogging: true
allowedOrigins:
- "*"
maxRequestBodySizeMb: 100
# Add your provider keys here
providers: {}
# Example:
# openai:
# keys:
# - value: "sk-..."
# weight: 1
# anthropic:
# keys:
# - value: "sk-ant-..."
# weight: 1
plugins:
telemetry:
enabled: true
config: {}
logging:
enabled: true
config: {}
EOF
if [[ "$VECTOR_ENABLED" == "true" ]]; then
cat >> "$OUTPUT_FILE" <<EOF
semanticCache:
enabled: true
config:
provider: "openai"
keys:
- "sk-..." # Add your OpenAI key for embeddings
embeddingModel: "text-embedding-3-small"
dimension: 1536
threshold: 0.8
ttl: "5m"
EOF
fi
print_success "Values file generated: $OUTPUT_FILE"
echo ""
print_info "Storage configuration:"
print_info " - Config Store: ${CONFIG_STORE_TYPE}"
print_info " - Logs Store: ${LOGS_STORE_TYPE}"
echo ""
print_warning "Please review and edit the generated file:"
print_warning " - Add your provider API keys"
if [[ "$NEEDS_POSTGRES" == "true" ]]; then
print_warning " - Change PostgreSQL password"
fi
if [[ "$VECTOR_TYPE" == "redis" ]] && [[ "$VECTOR_ENABLED" == "true" ]]; then
print_warning " - Change Redis password"
fi
if [[ -z "$ENCRYPTION_KEY" ]]; then
print_warning " - Add encryption key for production"
fi
echo ""
print_info "Install with: helm install bifrost ./bifrost -f $OUTPUT_FILE"
@@ -0,0 +1,229 @@
#!/bin/bash
# Bifrost Helm Chart Installation Script
# This script helps you install Bifrost with different configurations
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Print colored output
print_info() {
echo -e "${BLUE} ${NC}$1"
}
print_success() {
echo -e "${GREEN}${NC}$1"
}
print_warning() {
echo -e "${YELLOW}${NC}$1"
}
print_error() {
echo -e "${RED}${NC}$1"
}
# Print banner
print_banner() {
echo ""
echo -e "${BLUE}╔═══════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ ║${NC}"
echo -e "${BLUE}║ Bifrost Helm Chart Installer ║${NC}"
echo -e "${BLUE}║ ║${NC}"
echo -e "${BLUE}╚═══════════════════════════════════════════╝${NC}"
echo ""
}
# Check prerequisites
check_prerequisites() {
print_info "Checking prerequisites..."
if ! command -v helm &> /dev/null; then
print_error "Helm is not installed. Please install Helm 3.2.0 or later."
exit 1
fi
if ! command -v kubectl &> /dev/null; then
print_error "kubectl is not installed. Please install kubectl."
exit 1
fi
# Check kubectl connection
if ! kubectl cluster-info &> /dev/null; then
print_error "Cannot connect to Kubernetes cluster. Please check your kubeconfig."
exit 1
fi
print_success "All prerequisites met"
}
# Show menu
show_menu() {
echo ""
echo "Select a deployment configuration:"
echo ""
echo " 1) SQLite only (simple, local development)"
echo " 2) PostgreSQL only (production-ready database)"
echo " 3) PostgreSQL + Weaviate (semantic caching with Weaviate)"
echo " 4) PostgreSQL + Redis (semantic caching with Redis)"
echo " 5) SQLite + Weaviate (local dev with semantic caching)"
echo " 6) SQLite + Redis (local dev with Redis caching)"
echo " 7) External PostgreSQL (use your own database)"
echo " 8) Production HA (high-availability setup)"
echo " 9) Custom (use your own values file)"
echo ""
echo " 0) Exit"
echo ""
}
# Get user input
get_input() {
read -p "Enter your choice [0-9]: " choice
case $choice in
1) CONFIG="sqlite-only" ;;
2) CONFIG="postgres-only" ;;
3) CONFIG="postgres-weaviate" ;;
4) CONFIG="postgres-redis" ;;
5) CONFIG="sqlite-weaviate" ;;
6) CONFIG="sqlite-redis" ;;
7) CONFIG="external-postgres" ;;
8) CONFIG="production-ha" ;;
9) CONFIG="custom" ;;
0) exit 0 ;;
*)
print_error "Invalid choice. Please try again."
return 1
;;
esac
return 0
}
# Get release name
get_release_name() {
read -p "Enter release name (default: bifrost): " RELEASE_NAME
RELEASE_NAME=${RELEASE_NAME:-bifrost}
}
# Get namespace
get_namespace() {
read -p "Enter namespace (default: default): " NAMESPACE
NAMESPACE=${NAMESPACE:-default}
# Check if namespace exists
if ! kubectl get namespace "$NAMESPACE" &> /dev/null; then
read -p "Namespace '$NAMESPACE' does not exist. Create it? (y/n): " CREATE_NS
if [[ "$CREATE_NS" =~ ^[Yy]$ ]]; then
kubectl create namespace "$NAMESPACE"
print_success "Namespace '$NAMESPACE' created"
else
print_error "Installation aborted"
exit 1
fi
fi
}
# Get custom values file
get_custom_values() {
read -p "Enter path to custom values file: " CUSTOM_VALUES
if [[ ! -f "$CUSTOM_VALUES" ]]; then
print_error "File not found: $CUSTOM_VALUES"
exit 1
fi
}
# Install chart
install_chart() {
local values_file=""
if [[ "$CONFIG" == "custom" ]]; then
# Validate that CUSTOM_VALUES is non-empty
if [[ -z "$CUSTOM_VALUES" ]]; then
print_error "Custom values file path is empty"
exit 1
fi
values_file="$CUSTOM_VALUES"
# Validate that the custom values file exists and is a regular file
if [[ ! -f "$values_file" ]]; then
print_error "Custom values file does not exist or is not a regular file: $values_file"
exit 1
fi
else
values_file="${CHART_DIR}/values-examples/${CONFIG}.yaml"
# Validate that the predefined values file exists
if [[ ! -f "$values_file" ]]; then
print_error "Values file does not exist: $values_file"
exit 1
fi
fi
print_info "Installing Bifrost..."
print_info "Release: $RELEASE_NAME"
print_info "Namespace: $NAMESPACE"
print_info "Configuration: $CONFIG"
echo ""
# Ask for confirmation
read -p "Proceed with installation? (y/n): " CONFIRM
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
print_warning "Installation cancelled"
exit 0
fi
# Run helm install with explicit chart directory
if helm install "$RELEASE_NAME" "$CHART_DIR" \
--namespace "$NAMESPACE" \
-f "$values_file" \
--create-namespace; then
print_success "Bifrost installed successfully!"
echo ""
print_info "To check the status:"
echo " helm status $RELEASE_NAME -n $NAMESPACE"
echo ""
print_info "To get the application URL:"
echo " kubectl --namespace $NAMESPACE port-forward svc/$RELEASE_NAME 8080:8080"
echo " Then visit: http://localhost:8080"
echo ""
print_info "To view logs:"
echo " kubectl logs -l app.kubernetes.io/name=bifrost -n $NAMESPACE -f"
echo ""
else
print_error "Installation failed"
exit 1
fi
}
# Main function
main() {
print_banner
check_prerequisites
while true; do
show_menu
if get_input; then
break
fi
done
get_release_name
get_namespace
if [[ "$CONFIG" == "custom" ]]; then
get_custom_values
fi
# Set explicit chart directory (parent of scripts directory)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CHART_DIR="$SCRIPT_DIR/.."
install_chart
}
# Run main function
main
@@ -0,0 +1,94 @@
#!/bin/bash
# Bifrost Helm Chart Validation Script
# This script validates the Helm chart before installation
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
print_info() {
echo -e "${BLUE} ${NC}$1"
}
print_success() {
echo -e "${GREEN}${NC}$1"
}
print_error() {
echo -e "${RED}${NC}$1"
}
print_banner() {
echo ""
echo -e "${BLUE}╔═══════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ ║${NC}"
echo -e "${BLUE}║ Bifrost Chart Validator ║${NC}"
echo -e "${BLUE}║ ║${NC}"
echo -e "${BLUE}╚═══════════════════════════════════════════╝${NC}"
echo ""
}
# Set explicit chart directory (parent of scripts directory)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CHART_DIR="$SCRIPT_DIR/.."
print_banner
# Check if Helm is installed
print_info "Checking Helm installation..."
if ! command -v helm &> /dev/null; then
print_error "Helm is not installed"
exit 1
fi
print_success "Helm is installed"
# Lint the chart
print_info "Linting Helm chart..."
if helm lint "$CHART_DIR"; then
print_success "Chart linting passed"
else
print_error "Chart linting failed"
exit 1
fi
# Template the chart with default values
print_info "Templating chart with default values..."
if helm template test-release "$CHART_DIR" > /dev/null; then
print_success "Default values template successful"
else
print_error "Default values template failed"
exit 1
fi
# Test all example configurations
print_info "Testing example configurations..."
for config in "$CHART_DIR"/values-examples/*.yaml; do
config_name=$(basename "$config")
print_info " Testing $config_name..."
if helm template test-release "$CHART_DIR" -f "$config" > /dev/null; then
print_success " $config_name: OK"
else
print_error " $config_name: FAILED"
exit 1
fi
done
# Dry run install
print_info "Performing dry-run installation..."
if helm install test-release "$CHART_DIR" --dry-run --debug > /dev/null 2>&1; then
print_success "Dry-run installation successful"
else
print_error "Dry-run installation failed"
exit 1
fi
echo ""
print_success "All validation checks passed!"
echo ""
print_info "Chart is ready for installation"
@@ -0,0 +1,59 @@
Bifrost has been installed!
{{- if .Values.ingress.enabled }}
1. Access Bifrost at:
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .host }}
{{- end }}
{{- else if eq .Values.service.type "LoadBalancer" }}
1. Get the LoadBalancer IP:
kubectl get svc {{ include "bifrost.fullname" . }} -n {{ .Release.Namespace }}
2. Access Bifrost at:
http://<EXTERNAL-IP>:{{ .Values.service.port }}
{{- else if eq .Values.service.type "NodePort" }}
1. Get the NodePort:
export NODE_PORT=$(kubectl get svc {{ include "bifrost.fullname" . }} -n {{ .Release.Namespace }} -o jsonpath='{.spec.ports[0].nodePort}')
export NODE_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="ExternalIP")].address}' || kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
2. Access Bifrost at:
http://$NODE_IP:$NODE_PORT
{{- else }}
1. Port-forward to access Bifrost:
kubectl port-forward svc/{{ include "bifrost.fullname" . }} 8080:{{ .Values.service.port }} -n {{ .Release.Namespace }}
2. Access Bifrost at:
http://localhost:8080
{{- end }}
Configuration:
- Storage Mode: {{ .Values.storage.mode }}
{{- if eq .Values.storage.mode "postgres" }}
{{- if .Values.postgresql.enabled }}
- PostgreSQL: Deployed
{{- else }}
- PostgreSQL: External ({{ .Values.postgresql.external.host }})
{{- end }}
{{- else }}
- SQLite: Using persistent volume ({{ .Values.storage.persistence.size }})
{{- end }}
{{- if and .Values.vectorStore.enabled (ne .Values.vectorStore.type "none") }}
- Vector Store: {{ .Values.vectorStore.type }}
{{- end }}
{{- if .Values.autoscaling.enabled }}
- Autoscaling: Enabled ({{ .Values.autoscaling.minReplicas }}-{{ .Values.autoscaling.maxReplicas }} replicas)
{{- else }}
- Replicas: {{ .Values.replicaCount }}
{{- end }}
Metrics: http://{{ include "bifrost.fullname" . }}:{{ .Values.service.port }}/metrics
For documentation, visit: https://www.getbifrost.ai/docs
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,10 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "bifrost.fullname" . }}-config
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
data:
config.json: |
{{- include "bifrost.config" . | nindent 4 }}
@@ -0,0 +1,242 @@
{{- /* Use Deployment when: postgres mode, OR sqlite without persistence, OR sqlite with existingClaim */}}
{{- /* StatefulSet is used for: sqlite mode with persistence enabled and no existingClaim */}}
{{- $useStatefulSet := and (eq .Values.storage.mode "sqlite") .Values.storage.persistence.enabled (not .Values.storage.persistence.existingClaim) }}
{{- if not $useStatefulSet }}
{{- if not .Values.image.tag }}
{{- fail "ERROR: image.tag is required. Please specify the Bifrost image version (e.g., --set image.tag=v1.3.36). See available tags at https://hub.docker.com/r/maximhq/bifrost/tags" }}
{{- end }}
{{- include "bifrost.validate" . }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "bifrost.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
{{- with .Values.deploymentLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "bifrost.serverSelectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "bifrost.labels" . | nindent 8 }}
app.kubernetes.io/component: server
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "bifrost.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
{{- if .Values.terminationGracePeriodSeconds }}
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
{{- end }}
{{- with .Values.initContainers }}
initContainers:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- with .Values.lifecycle }}
lifecycle:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.bifrost.port }}
protocol: TCP
{{- if .Values.bifrost.cluster.enabled }}
- name: gossip
containerPort: {{ .Values.bifrost.cluster.gossip.port }}
protocol: TCP
- name: gossip-udp
containerPort: {{ .Values.bifrost.cluster.gossip.port }}
protocol: UDP
{{- end }}
env:
- name: APP_DIR
value: {{ .Values.bifrost.appDir | quote }}
- name: APP_PORT
value: {{ .Values.bifrost.port | quote }}
- name: APP_HOST
value: {{ .Values.bifrost.host | quote }}
- name: LOG_LEVEL
value: {{ .Values.bifrost.logLevel | quote }}
- name: LOG_STYLE
value: {{ .Values.bifrost.logStyle | quote }}
{{- if .Values.bifrost.encryptionKeySecret }}
- name: BIFROST_ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.encryptionKeySecret.name }}
key: {{ .Values.bifrost.encryptionKeySecret.key }}
{{- end }}
{{- if and .Values.bifrost.plugins.semanticCache.enabled .Values.bifrost.plugins.semanticCache.secretRef .Values.bifrost.plugins.semanticCache.secretRef.name }}
- name: SEMANTIC_CACHE_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.plugins.semanticCache.secretRef.name }}
key: {{ .Values.bifrost.plugins.semanticCache.secretRef.key | default "api-key" }}
{{- end }}
{{- /* PostgreSQL password from existing secret */ -}}
{{- if and .Values.postgresql.external.enabled .Values.postgresql.external.existingSecret }}
- name: BIFROST_POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.postgresql.external.existingSecret }}
key: {{ .Values.postgresql.external.passwordKey | default "password" }}
{{- end }}
{{- /* Redis password from existing secret */ -}}
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "redis") .Values.vectorStore.redis.external.enabled .Values.vectorStore.redis.external.existingSecret }}
- name: BIFROST_REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.vectorStore.redis.external.existingSecret }}
key: {{ .Values.vectorStore.redis.external.passwordKey | default "password" }}
{{- end }}
{{- /* Weaviate API key from existing secret */ -}}
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "weaviate") .Values.vectorStore.weaviate.external.enabled .Values.vectorStore.weaviate.external.existingSecret }}
- name: BIFROST_WEAVIATE_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.vectorStore.weaviate.external.existingSecret }}
key: {{ .Values.vectorStore.weaviate.external.apiKeyKey | default "api-key" }}
{{- end }}
{{- /* Qdrant API key from existing secret */ -}}
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "qdrant") .Values.vectorStore.qdrant.external.enabled .Values.vectorStore.qdrant.external.existingSecret }}
- name: BIFROST_QDRANT_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.vectorStore.qdrant.external.existingSecret }}
key: {{ .Values.vectorStore.qdrant.external.apiKeyKey | default "api-key" }}
{{- end }}
{{- /* Pinecone API key from existing secret */ -}}
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "pinecone") .Values.vectorStore.pinecone.external.enabled .Values.vectorStore.pinecone.external.existingSecret }}
- name: BIFROST_PINECONE_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.vectorStore.pinecone.external.existingSecret }}
key: {{ .Values.vectorStore.pinecone.external.apiKeyKey | default "api-key" }}
{{- end }}
{{- /* Maxim API key from existing secret */ -}}
{{- if and .Values.bifrost.plugins.maxim.enabled .Values.bifrost.plugins.maxim.secretRef .Values.bifrost.plugins.maxim.secretRef.name }}
- name: BIFROST_MAXIM_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.plugins.maxim.secretRef.name }}
key: {{ .Values.bifrost.plugins.maxim.secretRef.key | default "api-key" }}
{{- end }}
{{- /* Governance auth credentials from existing secret */ -}}
{{- if and .Values.bifrost.governance .Values.bifrost.governance.authConfig .Values.bifrost.governance.authConfig.existingSecret }}
- name: BIFROST_ADMIN_USERNAME
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.governance.authConfig.existingSecret }}
key: {{ .Values.bifrost.governance.authConfig.usernameKey | default "username" }}
- name: BIFROST_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.governance.authConfig.existingSecret }}
key: {{ .Values.bifrost.governance.authConfig.passwordKey | default "password" }}
{{- end }}
{{- /* Top-level auth credentials from existing secret (reuses same env vars as governance) */ -}}
{{- if and .Values.bifrost.authConfig .Values.bifrost.authConfig.existingSecret (not (and .Values.bifrost.governance .Values.bifrost.governance.authConfig .Values.bifrost.governance.authConfig.existingSecret)) }}
- name: BIFROST_ADMIN_USERNAME
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.authConfig.existingSecret }}
key: {{ .Values.bifrost.authConfig.usernameKey | default "username" }}
- name: BIFROST_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.authConfig.existingSecret }}
key: {{ .Values.bifrost.authConfig.passwordKey | default "password" }}
{{- end }}
{{- /* Provider secrets */ -}}
{{- range $provider, $secret := .Values.bifrost.providerSecrets }}
{{- if and $secret.existingSecret $secret.envVar }}
- name: {{ $secret.envVar }}
valueFrom:
secretKeyRef:
name: {{ $secret.existingSecret }}
key: {{ $secret.key | default "api-key" }}
{{- end }}
{{- end }}
{{- with .Values.env }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.envFrom }}
envFrom:
{{- toYaml . | nindent 12 }}
{{- end }}
livenessProbe:
{{- toYaml .Values.livenessProbe | nindent 12 }}
readinessProbe:
{{- toYaml .Values.readinessProbe | nindent 12 }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
{{- if eq .Values.storage.mode "sqlite" }}
- name: data
mountPath: {{ .Values.bifrost.appDir }}
{{- end }}
- name: config
mountPath: {{ .Values.bifrost.appDir }}/config.json
subPath: config.json
readOnly: true
{{- with .Values.volumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
volumes:
- name: config
configMap:
name: {{ include "bifrost.fullname" . }}-config
{{- if eq .Values.storage.mode "sqlite" }}
- name: data
{{- if .Values.storage.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.storage.persistence.existingClaim | default (printf "%s-data" (include "bifrost.fullname" .)) }}
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
{{- with .Values.volumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
@@ -0,0 +1,27 @@
{{- if .Values.externalSecret.enabled }}
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: {{ .Values.externalSecret.secretName | default (printf "%s-vault" (include "bifrost.fullname" .)) }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
annotations:
argocd.argoproj.io/sync-wave: "-5"
spec:
dataFrom:
- extract:
conversionStrategy: Default
key: {{ .Values.externalSecret.path }}
{{- if .Values.externalSecret.version }}
version: {{ .Values.externalSecret.version | quote }}
{{- end }}
refreshInterval: {{ .Values.externalSecret.refreshInterval | default "0" | quote }}
secretStoreRef:
kind: ClusterSecretStore
name: {{ .Values.externalSecret.secretStoreRef | default "vault-backend" }}
target:
name: {{ .Values.externalSecret.secretName | default (printf "%s-vault" (include "bifrost.fullname" .)) }}
creationPolicy: Owner
deletionPolicy: Retain
{{- end }}
@@ -0,0 +1,38 @@
{{- if .Values.autoscaling.enabled }}
{{- $useStatefulSet := and (eq .Values.storage.mode "sqlite") .Values.storage.persistence.enabled (not .Values.storage.persistence.existingClaim) }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "bifrost.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: {{ if $useStatefulSet }}StatefulSet{{ else }}Deployment{{ end }}
name: {{ include "bifrost.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- with .Values.autoscaling.behavior }}
behavior:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
@@ -0,0 +1,149 @@
{{- if .Values.httpProxy.enabled -}}
{{- if .Values.createContourGateway -}}
{{- if or (eq "contour-internal" .Values.ingress.ingressClassName) (eq "contour-internal-0" .Values.ingress.ingressClassName) (eq "contour-internal-1" .Values.ingress.ingressClassName) }}
{{- $servicePortNumber := .Values.ingress.servicePortNumber | default 80 -}}
{{- $namespace := .Values.namespace -}}
{{- /* resolve intra ingress class */ -}}
{{- $intraIngressClass := "" -}}
{{- if eq .Values.ingress.ingressClassName "contour-internal" -}}
{{- $intraIngressClass = "contour-internal-intra" -}}
{{- else if eq .Values.ingress.ingressClassName "contour-internal-0" -}}
{{- $intraIngressClass = "contour-internal-intra-0" -}}
{{- else if eq .Values.ingress.ingressClassName "contour-internal-1" -}}
{{- $intraIngressClass = "contour-internal-intra-1" -}}
{{- end -}}
{{ $count := 0 | int }}
{{- range .Values.ingress.hosts }}
{{- $hasName := hasKey . "name" -}}
{{- $proxyName := ternary .intraName (printf "%s-intra-%d" $namespace $count) (hasKey . "intraName") -}}
{{- $childProxyName := printf "%s-intra" $namespace -}}
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
namespace: {{ $namespace }}
name: {{ $proxyName }}
labels:
{{- include "bifrost.labels" $ | nindent 4 }}
annotations:
projectcontour.io/ingress.class: {{ $intraIngressClass }}
spec:
ingressClassName: {{ $intraIngressClass }}
virtualhost:
fqdn: "{{ .host }}"
routes:
{{- range .paths }}
{{- if hasKey . "backends" }}
- conditions:
{{- if or (eq (lower .pathType) "prefix") (eq (lower .pathType) "implementationspecific") }}
- prefix: {{ .path }}
{{- end }}
{{- if eq (lower .pathType) "exact" }}
- exact: {{ .path }}
{{- end }}
{{- if eq (lower .pathType) "regex" }}
- regex: {{ .path }}
{{- end }}
{{- if hasKey . "header" }}
- header:
name: {{ (split "___" .header)._0 }}
{{ (split "___" .header)._1 }}: {{ (split "___" .header)._2 }}
{{ end }}
services:
{{ range .backends }}
{{- $svc := .service -}}
{{- $hasSlash := contains "/" $svc -}}
{{- $svcName := ternary (split "/" $svc)._1 $svc $hasSlash -}}
{{- $targetNs := ternary .namespace (ternary (split "/" $svc)._0 $namespace $hasSlash) (hasKey . "namespace") -}}
{{- $useAlias := ne $targetNs $namespace -}}
{{- $aliasName := printf "%s-xns-%s" $svcName $targetNs | trunc 63 | trimSuffix "-" -}}
- name: {{ ternary $aliasName $svcName $useAlias }}
port: {{ $servicePortNumber }}
{{- if .weight }}
weight: {{ .weight }}
{{- end }}
{{- if $.Values.ingress.slowStart.enabled }}
slowStartPolicy:
window: {{ $.Values.ingress.slowStart.window }}
aggression: {{ $.Values.ingress.slowStart.aggression | float64 | squote }}
minWeightPercent: {{ $.Values.ingress.slowStart.minPercent }}
{{- end }}
{{ end }}
{{- end }}
{{- end }}
includes:
{{- range .paths }}
{{- if not (hasKey . "backends") }}
- conditions:
{{- if or (eq (lower .pathType) "prefix") (eq (lower .pathType) "implementationspecific") }}
- prefix: {{ .path }}
{{- end }}
{{- if eq (lower .pathType) "exact" }}
- exact: {{ .path }}
{{- end }}
{{- if eq (lower .pathType) "regex" }}
- regex: {{ .path }}
{{- end }}
{{- if eq (lower .pathType) "header" }}
- header:
name: {{ (split "___" .path)._0 }}
{{ (split "___" .path)._1 }}: {{ (split "___" .path)._2 }}
{{- end }}
{{- if eq (lower .pathType) "prefixheader" }}
- prefix: {{ (split "___" .path)._0 }}
- header:
name: {{ (split "___" .path)._1 }}
{{ (split "___" .path)._2 }}: {{ (split "___" .path)._3 }}
{{- end }}
{{- if .targetService }}
name: {{ .targetService | replace "/" "-" }}-intra
namespace: {{ (split "/" .targetService)._0 }}
{{- else }}
name: {{ $childProxyName }}
namespace: {{ $namespace }}
{{- end }}
{{- end }}
{{- end }}
---
{{- if not $hasName }}
{{ $count = add1 $count }}
{{- /* Child Intra HTTPProxy - routes with services */}}
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
namespace: {{ $namespace }}
name: {{ $childProxyName }}
labels:
{{- include "bifrost.labels" $ | nindent 4 }}
annotations:
projectcontour.io/ingress.class: {{ $intraIngressClass }}
spec:
ingressClassName: {{ $intraIngressClass }}
routes:
- services:
- name: {{ $namespace }}
port: {{ $servicePortNumber | default "80" }}
{{- if $.Values.ingress.slowStart.enabled }}
slowStartPolicy:
window: {{ $.Values.ingress.slowStart.window }}
aggression: {{ $.Values.ingress.slowStart.aggression | float64 | squote }}
minWeightPercent: {{ $.Values.ingress.slowStart.minPercent }}
{{- end }}
{{- if $.Values.ingress.enableWebsocket }}
enableWebsockets: true
{{- end }}
{{- if $.Values.contourResponseTimeout }}
timeoutPolicy:
response: {{ $.Values.contourResponseTimeout }}
{{- end }}
---
{{- else }}
{{ $count = add1 $count }}
{{- end }}
{{ end }}
{{- end -}}
{{- end -}}
{{- end -}}
@@ -0,0 +1,149 @@
{{- if .Values.httpProxy.enabled -}}
{{- if .Values.createContourGateway -}}
{{- if or ( eq "contour-internal" .Values.ingress.ingressClassName ) ( eq "contour-external" .Values.ingress.ingressClassName ) ( eq "contour-internal-0" .Values.ingress.ingressClassName ) ( eq "contour-internal-1" .Values.ingress.ingressClassName ) ( eq "contour-external-0" .Values.ingress.ingressClassName ) ( eq "contour-external-1" .Values.ingress.ingressClassName ) }}
{{- $servicePortNumber := .Values.ingress.servicePortNumber | default 80 -}}
{{- $servicePort := .Values.ingress.servicePort -}}
{{- $pathType := .Values.ingress.pathType -}}
{{- $namespace := .Values.namespace -}}
{{- $ingressClassName := .Values.ingress.ingressClassName -}}
{{ $count := 0 | int }}
{{- range .Values.ingress.hosts }}
{{- $hasName := hasKey . "name" -}}
{{- $proxyName := ternary .name (printf "%s-%d" $namespace $count) (hasKey . "name") -}}
{{- $childProxyName := $namespace -}}
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
namespace: {{ $namespace }}
name: {{ $proxyName }}
labels:
{{- include "bifrost.labels" $ | nindent 4 }}
annotations:
projectcontour.io/ingress.class: {{ $.Values.ingress.ingressClassName }}
spec:
ingressClassName: {{ $ingressClassName }}
virtualhost:
fqdn: "{{ .host }}"
{{- /* 1) Weighted paths render here as routes with services */}}
routes:
{{- range .paths }}
{{- if hasKey . "backends" }}
- conditions:
{{- if or ( eq ( lower .pathType ) "prefix" ) ( eq ( lower .pathType ) "implementationspecific") }}
- prefix: {{ .path }}
{{- end }}
{{- if ( eq ( lower .pathType ) "exact" ) }}
- exact: {{ .path }}
{{- end }}
{{- if ( eq ( lower .pathType ) "regex" ) }}
- regex: {{ .path }}
{{- end }}
{{- if ( eq ( lower .pathType ) "header" ) }}
- header:
name: {{ (split "___" .path)._0 }}
{{ (split "___" .path)._1 }}: {{ (split "___" .path)._2 }}
{{- end }}
{{- if ( eq ( lower .pathType ) "prefixheader" ) }}
- prefix: {{ (split "___" .path)._0 }}
- header:
name: {{ (split "___" .path)._1 }}
{{ (split "___" .path)._2 }}: {{ (split "___" .path)._3 }}
{{- end }}
services:
{{ range .backends }}
{{- $svc := .service -}}
{{- $hasSlash := contains "/" $svc -}}
{{- $svcName := ternary (split "/" $svc)._1 $svc $hasSlash -}}
{{- $targetNs := ternary .namespace (ternary (split "/" $svc)._0 $.Values.namespace $hasSlash) (hasKey . "namespace") -}}
{{- $useAlias := ne $targetNs $.Values.namespace -}}
{{- $aliasName := printf "%s-xns-%s" $svcName $targetNs | trunc 63 | trimSuffix "-" -}}
- name: {{ ternary $aliasName $svcName $useAlias }}
port: {{ $servicePortNumber }}
{{- if .weight }}
weight: {{ .weight }}
{{- end }}
{{- if $.Values.ingress.slowStart.enabled }}
slowStartPolicy:
window: {{ $.Values.ingress.slowStart.window }}
aggression: {{ $.Values.ingress.slowStart.aggression | float64 | squote }}
minWeightPercent: {{ $.Values.ingress.slowStart.minPercent }}
{{- end }}
{{ end }}
{{- end }}
{{- end }}
{{- /* 2) Non-weighted paths keep using includes to your upstreams */}}
includes:
{{- range .paths }}
{{- if not (hasKey . "backends") }}
- conditions:
{{- if or ( eq ( lower .pathType ) "prefix" ) ( eq ( lower .pathType ) "implementationspecific") }}
- prefix: {{ .path }}
{{- end }}
{{- if ( eq ( lower .pathType ) "exact" ) }}
- exact: {{ .path }}
{{- end }}
{{- if ( eq ( lower .pathType ) "regex" ) }}
- regex: {{ .path }}
{{- end }}
{{- if ( eq ( lower .pathType ) "header" ) }}
- header:
name: {{ (split "___" .path)._0 }}
{{ (split "___" .path)._1 }}: {{ (split "___" .path)._2 }}
{{- end }}
{{- if ( eq ( lower .pathType ) "prefixheader" ) }}
- prefix: {{ (split "___" .path)._0 }}
- header:
name: {{ (split "___" .path)._1 }}
{{ (split "___" .path)._2 }}: {{ (split "___" .path)._3 }}
{{- end }}
{{- if .targetService }}
name: {{ .targetService | replace "/" "-" }}
namespace: {{ (split "/" .targetService)._0 }}
{{- else }}
name: {{ $childProxyName }}
namespace: {{ $namespace }}
{{- end }}
{{- end }}
{{- end }}
---
{{- if not $hasName }}
{{ $count = add1 $count }}
{{- /* Child HTTPProxy - routes with services */}}
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
namespace: {{ $namespace }}
name: {{ $childProxyName }}
labels:
{{- include "bifrost.labels" $ | nindent 4 }}
annotations:
projectcontour.io/ingress.class: {{ $ingressClassName }}
spec:
ingressClassName: {{ $ingressClassName }}
routes:
- services:
- name: {{ $namespace }}
port: {{ $servicePortNumber | default "80" }}
{{- if $.Values.ingress.slowStart.enabled }}
slowStartPolicy:
window: {{ $.Values.ingress.slowStart.window }}
aggression: {{ $.Values.ingress.slowStart.aggression | float64 | squote }}
minWeightPercent: {{ $.Values.ingress.slowStart.minPercent }}
{{- end }}
{{- if $.Values.ingress.enableWebsocket }}
enableWebsockets: true
{{- end }}
{{- if $.Values.contourResponseTimeout }}
timeoutPolicy:
response: {{ $.Values.contourResponseTimeout }}
{{- end }}
---
{{- else }}
{{ $count = add1 $count }}
{{- end }}
{{ end }}
{{- end -}}
{{- end -}}
{{- end -}}
@@ -0,0 +1,42 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "bifrost.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "bifrost.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
@@ -0,0 +1,18 @@
{{- if .Values.podDisruptionBudget.enabled }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "bifrost.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
spec:
{{- if .Values.podDisruptionBudget.minAvailable }}
minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
{{- else }}
maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable | default "10%" }}
{{- end }}
selector:
matchLabels:
{{- include "bifrost.serverSelectorLabels" . | nindent 6 }}
{{- end }}
@@ -0,0 +1,79 @@
{{- if and (eq .Values.storage.mode "postgres") .Values.postgresql.enabled (not .Values.postgresql.external.enabled) }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "bifrost.fullname" . }}-postgresql
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: database
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
{{- include "bifrost.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: database
template:
metadata:
labels:
{{- include "bifrost.labels" . | nindent 8 }}
app.kubernetes.io/component: database
spec:
securityContext:
fsGroup: 999
containers:
- name: postgresql
image: "{{ .Values.postgresql.image.repository }}:{{ .Values.postgresql.image.tag }}"
imagePullPolicy: {{ .Values.postgresql.image.pullPolicy }}
ports:
- name: postgresql
containerPort: 5432
protocol: TCP
env:
- name: POSTGRES_USER
value: {{ .Values.postgresql.auth.username | quote }}
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "bifrost.fullname" . }}-postgresql
key: password
- name: POSTGRES_DB
value: {{ .Values.postgresql.auth.database | quote }}
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
livenessProbe:
exec:
command:
- /bin/sh
- -c
- pg_isready -U "{{ .Values.postgresql.auth.username }}"
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
readinessProbe:
exec:
command:
- /bin/sh
- -c
- pg_isready -U "{{ .Values.postgresql.auth.username }}"
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
resources:
{{- toYaml .Values.postgresql.primary.resources | nindent 12 }}
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumes:
- name: data
{{- if .Values.postgresql.primary.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ include "bifrost.fullname" . }}-postgresql
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
@@ -0,0 +1,23 @@
{{- if and (eq .Values.storage.mode "postgres") .Values.postgresql.enabled (not .Values.postgresql.external.enabled) .Values.postgresql.primary.persistence.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "bifrost.fullname" . }}-postgresql
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: database
spec:
accessModes:
- ReadWriteOnce
{{- if .Values.postgresql.primary.persistence.storageClass }}
{{- if (eq "-" .Values.postgresql.primary.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: {{ .Values.postgresql.primary.persistence.storageClass }}
{{- end }}
{{- end }}
resources:
requests:
storage: {{ .Values.postgresql.primary.persistence.size }}
{{- end }}
@@ -0,0 +1,20 @@
{{- if and (eq .Values.storage.mode "postgres") .Values.postgresql.enabled (not .Values.postgresql.external.enabled) }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "bifrost.fullname" . }}-postgresql
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: database
spec:
type: ClusterIP
ports:
- port: 5432
targetPort: postgresql
protocol: TCP
name: postgresql
selector:
{{- include "bifrost.selectorLabels" . | nindent 4 }}
app.kubernetes.io/component: database
{{- end }}
@@ -0,0 +1,65 @@
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "qdrant") .Values.vectorStore.qdrant.enabled (not .Values.vectorStore.qdrant.external.enabled) }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "bifrost.fullname" . }}-qdrant
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: vectorstore
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
{{- include "bifrost.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: vectorstore-qdrant
template:
metadata:
labels:
{{- include "bifrost.labels" . | nindent 8 }}
app.kubernetes.io/component: vectorstore-qdrant
spec:
containers:
- name: qdrant
image: "{{ .Values.vectorStore.qdrant.image.repository }}:{{ .Values.vectorStore.qdrant.image.tag }}"
imagePullPolicy: {{ .Values.vectorStore.qdrant.image.pullPolicy }}
ports:
- name: http
containerPort: 6333
protocol: TCP
- name: grpc
containerPort: 6334
protocol: TCP
livenessProbe:
httpGet:
path: /readyz
port: http
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /readyz
port: http
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
resources:
{{- toYaml .Values.vectorStore.qdrant.resources | nindent 12 }}
volumeMounts:
- name: data
mountPath: /qdrant/storage
volumes:
- name: data
{{- if .Values.vectorStore.qdrant.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ include "bifrost.fullname" . }}-qdrant
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
@@ -0,0 +1,24 @@
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "qdrant") .Values.vectorStore.qdrant.enabled (not .Values.vectorStore.qdrant.external.enabled) .Values.vectorStore.qdrant.persistence.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "bifrost.fullname" . }}-qdrant
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: vectorstore-qdrant
spec:
accessModes:
- ReadWriteOnce
{{- if .Values.vectorStore.qdrant.persistence.storageClass }}
{{- if (eq "-" .Values.vectorStore.qdrant.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: {{ .Values.vectorStore.qdrant.persistence.storageClass }}
{{- end }}
{{- end }}
resources:
requests:
storage: {{ .Values.vectorStore.qdrant.persistence.size }}
{{- end }}
@@ -0,0 +1,25 @@
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "qdrant") .Values.vectorStore.qdrant.enabled (not .Values.vectorStore.qdrant.external.enabled) }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "bifrost.fullname" . }}-qdrant
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: vectorstore-qdrant
spec:
type: ClusterIP
ports:
- port: 6333
targetPort: http
protocol: TCP
name: http
- port: 6334
targetPort: grpc
protocol: TCP
name: grpc
selector:
{{- include "bifrost.selectorLabels" . | nindent 4 }}
app.kubernetes.io/component: vectorstore-qdrant
{{- end }}
@@ -0,0 +1,89 @@
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "redis") .Values.vectorStore.redis.enabled (not .Values.vectorStore.redis.external.enabled) }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "bifrost.fullname" . }}-redis-master
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: redis
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
{{- include "bifrost.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: redis
template:
metadata:
labels:
{{- include "bifrost.labels" . | nindent 8 }}
app.kubernetes.io/component: redis
spec:
containers:
- name: redis
image: "{{ .Values.vectorStore.redis.image.repository }}:{{ .Values.vectorStore.redis.image.tag }}"
imagePullPolicy: {{ .Values.vectorStore.redis.image.pullPolicy }}
ports:
- name: redis
containerPort: 6379
protocol: TCP
env:
{{- if .Values.vectorStore.redis.auth.enabled }}
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "bifrost.fullname" . }}-redis
key: password
{{- end }}
{{- if .Values.vectorStore.redis.auth.enabled }}
command:
- redis-server
- --requirepass
- $(REDIS_PASSWORD)
{{- end }}
livenessProbe:
exec:
command:
- sh
- -c
- |
{{- if .Values.vectorStore.redis.auth.enabled }}
redis-cli -a "$REDIS_PASSWORD" ping
{{- else }}
redis-cli ping
{{- end }}
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command:
- sh
- -c
- |
{{- if .Values.vectorStore.redis.auth.enabled }}
redis-cli -a "$REDIS_PASSWORD" ping
{{- else }}
redis-cli ping
{{- end }}
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
resources:
{{- toYaml .Values.vectorStore.redis.master.resources | nindent 12 }}
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
{{- if .Values.vectorStore.redis.master.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ include "bifrost.fullname" . }}-redis
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
@@ -0,0 +1,23 @@
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "redis") .Values.vectorStore.redis.enabled (not .Values.vectorStore.redis.external.enabled) .Values.vectorStore.redis.master.persistence.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "bifrost.fullname" . }}-redis
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: redis
spec:
accessModes:
- ReadWriteOnce
{{- if .Values.vectorStore.redis.master.persistence.storageClass }}
{{- if (eq "-" .Values.vectorStore.redis.master.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: {{ .Values.vectorStore.redis.master.persistence.storageClass }}
{{- end }}
{{- end }}
resources:
requests:
storage: {{ .Values.vectorStore.redis.master.persistence.size }}
{{- end }}
@@ -0,0 +1,20 @@
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "redis") .Values.vectorStore.redis.enabled (not .Values.vectorStore.redis.external.enabled) }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "bifrost.fullname" . }}-redis-master
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: redis
spec:
type: ClusterIP
ports:
- port: 6379
targetPort: redis
protocol: TCP
name: redis
selector:
{{- include "bifrost.selectorLabels" . | nindent 4 }}
app.kubernetes.io/component: redis
{{- end }}
@@ -0,0 +1,42 @@
{{- if .Values.keda.enabled }}
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: {{ include "bifrost.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
annotations:
argocd.argoproj.io/sync-wave: "5"
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "bifrost.fullname" . }}
pollingInterval: {{ .Values.keda.pollingInterval | default 30 }}
minReplicaCount: {{ .Values.keda.minReplicaCount | default 2 }}
maxReplicaCount: {{ .Values.keda.maxReplicaCount | default 200 }}
advanced:
horizontalPodAutoscalerConfig:
behavior:
scaleDown:
stabilizationWindowSeconds: {{ .Values.keda.scaledown.stabilizationWindowSeconds }}
policies:
{{- range .Values.keda.scaledown.policies }}
- type: {{ .type }}
value: {{ .value }}
periodSeconds: {{ .periodseconds }}
{{- end }}
selectPolicy: {{ .Values.keda.scaledown.selectpolicy }}
scaleUp:
stabilizationWindowSeconds: {{ .Values.keda.scaleup.stabilizationWindowSeconds }}
policies:
{{- range .Values.keda.scaleup.policies }}
- type: {{ .type }}
value: {{ .value }}
periodSeconds: {{ .periodseconds }}
{{- end }}
selectPolicy: {{ .Values.keda.scaleup.selectpolicy }}
triggers:
{{- toYaml .Values.keda.triggers | nindent 2 }}
{{- end }}
@@ -0,0 +1,27 @@
{{- if and (eq .Values.storage.mode "postgres") .Values.postgresql.enabled (not .Values.postgresql.external.enabled) }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "bifrost.fullname" . }}-postgresql
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: database
type: Opaque
data:
password: {{ .Values.postgresql.auth.password | b64enc | quote }}
{{- end }}
---
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "redis") .Values.vectorStore.redis.enabled (not .Values.vectorStore.redis.external.enabled) .Values.vectorStore.redis.auth.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "bifrost.fullname" . }}-redis
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: redis
type: Opaque
data:
password: {{ .Values.vectorStore.redis.auth.password | b64enc | quote }}
{{- end }}
@@ -0,0 +1,30 @@
{{- if and (eq .Values.storage.mode "sqlite") .Values.storage.persistence.enabled (not .Values.storage.persistence.existingClaim) }}
# Headless service for StatefulSet pod DNS resolution
apiVersion: v1
kind: Service
metadata:
name: {{ include "bifrost.fullname" . }}-headless
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
spec:
type: ClusterIP
clusterIP: None
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
{{- if .Values.bifrost.cluster.enabled }}
- port: {{ .Values.bifrost.cluster.gossip.port }}
targetPort: gossip
protocol: TCP
name: gossip
- port: {{ .Values.bifrost.cluster.gossip.port }}
targetPort: gossip-udp
protocol: UDP
name: gossip-udp
{{- end }}
selector:
{{- include "bifrost.serverSelectorLabels" . | nindent 4 }}
{{- end }}
@@ -0,0 +1,30 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "bifrost.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
{{- if .Values.bifrost.cluster.enabled }}
- port: {{ .Values.bifrost.cluster.gossip.port }}
targetPort: gossip
protocol: TCP
name: gossip
- port: {{ .Values.bifrost.cluster.gossip.port }}
targetPort: gossip-udp
protocol: UDP
name: gossip-udp
{{- end }}
selector:
{{- include "bifrost.serverSelectorLabels" . | nindent 4 }}
@@ -0,0 +1,14 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "bifrost.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
{{- end }}
@@ -0,0 +1,250 @@
{{- /* StatefulSet is used for: sqlite mode with persistence enabled and no existingClaim */}}
{{- $useStatefulSet := and (eq .Values.storage.mode "sqlite") .Values.storage.persistence.enabled (not .Values.storage.persistence.existingClaim) }}
{{- if $useStatefulSet }}
{{- if not .Values.image.tag }}
{{- fail "ERROR: image.tag is required. Please specify the Bifrost image version (e.g., --set image.tag=v1.3.36). See available tags at https://hub.docker.com/r/maximhq/bifrost/tags" }}
{{- end }}
{{- include "bifrost.validate" . }}
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ include "bifrost.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
{{- with .Values.deploymentLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
serviceName: {{ include "bifrost.fullname" . }}-headless
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "bifrost.serverSelectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "bifrost.labels" . | nindent 8 }}
app.kubernetes.io/component: server
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "bifrost.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
{{- if .Values.terminationGracePeriodSeconds }}
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
{{- end }}
{{- with .Values.initContainers }}
initContainers:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- with .Values.lifecycle }}
lifecycle:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.bifrost.port }}
protocol: TCP
{{- if .Values.bifrost.cluster.enabled }}
- name: gossip
containerPort: {{ .Values.bifrost.cluster.gossip.port }}
protocol: TCP
- name: gossip-udp
containerPort: {{ .Values.bifrost.cluster.gossip.port }}
protocol: UDP
{{- end }}
env:
- name: APP_DIR
value: {{ .Values.bifrost.appDir | quote }}
- name: APP_PORT
value: {{ .Values.bifrost.port | quote }}
- name: APP_HOST
value: {{ .Values.bifrost.host | quote }}
- name: LOG_LEVEL
value: {{ .Values.bifrost.logLevel | quote }}
- name: LOG_STYLE
value: {{ .Values.bifrost.logStyle | quote }}
{{- if .Values.bifrost.encryptionKeySecret }}
- name: BIFROST_ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.encryptionKeySecret.name }}
key: {{ .Values.bifrost.encryptionKeySecret.key }}
{{- end }}
{{- if and .Values.bifrost.plugins.semanticCache.enabled .Values.bifrost.plugins.semanticCache.secretRef .Values.bifrost.plugins.semanticCache.secretRef.name }}
- name: SEMANTIC_CACHE_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.plugins.semanticCache.secretRef.name }}
key: {{ .Values.bifrost.plugins.semanticCache.secretRef.key | default "api-key" }}
{{- end }}
{{- /* PostgreSQL password from existing secret */ -}}
{{- if and .Values.postgresql.external.enabled .Values.postgresql.external.existingSecret }}
- name: BIFROST_POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.postgresql.external.existingSecret }}
key: {{ .Values.postgresql.external.passwordKey | default "password" }}
{{- end }}
{{- /* Redis password from existing secret */ -}}
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "redis") .Values.vectorStore.redis.external.enabled .Values.vectorStore.redis.external.existingSecret }}
- name: BIFROST_REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.vectorStore.redis.external.existingSecret }}
key: {{ .Values.vectorStore.redis.external.passwordKey | default "password" }}
{{- end }}
{{- /* Weaviate API key from existing secret */ -}}
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "weaviate") .Values.vectorStore.weaviate.external.enabled .Values.vectorStore.weaviate.external.existingSecret }}
- name: BIFROST_WEAVIATE_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.vectorStore.weaviate.external.existingSecret }}
key: {{ .Values.vectorStore.weaviate.external.apiKeyKey | default "api-key" }}
{{- end }}
{{- /* Qdrant API key from existing secret */ -}}
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "qdrant") .Values.vectorStore.qdrant.external.enabled .Values.vectorStore.qdrant.external.existingSecret }}
- name: BIFROST_QDRANT_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.vectorStore.qdrant.external.existingSecret }}
key: {{ .Values.vectorStore.qdrant.external.apiKeyKey | default "api-key" }}
{{- end }}
{{- /* Pinecone API key from existing secret */ -}}
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "pinecone") .Values.vectorStore.pinecone.external.enabled .Values.vectorStore.pinecone.external.existingSecret }}
- name: BIFROST_PINECONE_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.vectorStore.pinecone.external.existingSecret }}
key: {{ .Values.vectorStore.pinecone.external.apiKeyKey | default "api-key" }}
{{- end }}
{{- /* Maxim API key from existing secret */ -}}
{{- if and .Values.bifrost.plugins.maxim.enabled .Values.bifrost.plugins.maxim.secretRef .Values.bifrost.plugins.maxim.secretRef.name }}
- name: BIFROST_MAXIM_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.plugins.maxim.secretRef.name }}
key: {{ .Values.bifrost.plugins.maxim.secretRef.key | default "api-key" }}
{{- end }}
{{- /* Governance auth credentials from existing secret */ -}}
{{- if and .Values.bifrost.governance .Values.bifrost.governance.authConfig .Values.bifrost.governance.authConfig.existingSecret }}
- name: BIFROST_ADMIN_USERNAME
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.governance.authConfig.existingSecret }}
key: {{ .Values.bifrost.governance.authConfig.usernameKey | default "username" }}
- name: BIFROST_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.governance.authConfig.existingSecret }}
key: {{ .Values.bifrost.governance.authConfig.passwordKey | default "password" }}
{{- end }}
{{- /* Top-level auth credentials from existing secret (reuses same env vars as governance) */ -}}
{{- if and .Values.bifrost.authConfig .Values.bifrost.authConfig.existingSecret (not (and .Values.bifrost.governance .Values.bifrost.governance.authConfig .Values.bifrost.governance.authConfig.existingSecret)) }}
- name: BIFROST_ADMIN_USERNAME
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.authConfig.existingSecret }}
key: {{ .Values.bifrost.authConfig.usernameKey | default "username" }}
- name: BIFROST_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.bifrost.authConfig.existingSecret }}
key: {{ .Values.bifrost.authConfig.passwordKey | default "password" }}
{{- end }}
{{- /* Provider secrets */ -}}
{{- range $provider, $secret := .Values.bifrost.providerSecrets }}
{{- if and $secret.existingSecret $secret.envVar }}
- name: {{ $secret.envVar }}
valueFrom:
secretKeyRef:
name: {{ $secret.existingSecret }}
key: {{ $secret.key | default "api-key" }}
{{- end }}
{{- end }}
{{- with .Values.env }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.envFrom }}
envFrom:
{{- toYaml . | nindent 12 }}
{{- end }}
livenessProbe:
{{- toYaml .Values.livenessProbe | nindent 12 }}
readinessProbe:
{{- toYaml .Values.readinessProbe | nindent 12 }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: data
mountPath: {{ .Values.bifrost.appDir }}
- name: config
mountPath: {{ .Values.bifrost.appDir }}/config.json
subPath: config.json
readOnly: true
{{- with .Values.volumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
volumes:
- name: config
configMap:
name: {{ include "bifrost.fullname" . }}-config
{{- with .Values.volumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumeClaimTemplates:
- metadata:
name: data
labels:
{{- include "bifrost.labels" . | nindent 10 }}
spec:
accessModes:
- {{ .Values.storage.persistence.accessMode }}
{{- if .Values.storage.persistence.storageClass }}
{{- if (eq "-" .Values.storage.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: {{ .Values.storage.persistence.storageClass }}
{{- end }}
{{- end }}
resources:
requests:
storage: {{ .Values.storage.persistence.size }}
{{- end }}
@@ -0,0 +1,69 @@
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "weaviate") .Values.vectorStore.weaviate.enabled (not .Values.vectorStore.weaviate.external.enabled) }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "bifrost.fullname" . }}-weaviate
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: vectorstore
spec:
replicas: {{ .Values.vectorStore.weaviate.replicas }}
strategy:
type: Recreate
selector:
matchLabels:
{{- include "bifrost.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: vectorstore
template:
metadata:
labels:
{{- include "bifrost.labels" . | nindent 8 }}
app.kubernetes.io/component: vectorstore
spec:
containers:
- name: weaviate
image: "{{ .Values.vectorStore.weaviate.image.repository }}:{{ .Values.vectorStore.weaviate.image.tag }}"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
protocol: TCP
- name: grpc
containerPort: 50051
protocol: TCP
env:
{{- range $key, $value := .Values.vectorStore.weaviate.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
livenessProbe:
httpGet:
path: /v1/.well-known/live
port: http
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /v1/.well-known/ready
port: http
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
resources:
{{- toYaml .Values.vectorStore.weaviate.resources | nindent 12 }}
volumeMounts:
- name: data
mountPath: /var/lib/weaviate
volumes:
- name: data
{{- if .Values.vectorStore.weaviate.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ include "bifrost.fullname" . }}-weaviate
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
@@ -0,0 +1,23 @@
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "weaviate") .Values.vectorStore.weaviate.enabled (not .Values.vectorStore.weaviate.external.enabled) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "bifrost.fullname" . }}-weaviate
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: vectorstore
spec:
accessModes:
- ReadWriteOnce
{{- if .Values.vectorStore.weaviate.persistence.storageClass }}
{{- if (eq "-" .Values.vectorStore.weaviate.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: {{ .Values.vectorStore.weaviate.persistence.storageClass }}
{{- end }}
{{- end }}
resources:
requests:
storage: {{ .Values.vectorStore.weaviate.persistence.size }}
{{- end }}
@@ -0,0 +1,24 @@
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "weaviate") .Values.vectorStore.weaviate.enabled (not .Values.vectorStore.weaviate.external.enabled) }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "bifrost.fullname" . }}-weaviate
namespace: {{ .Release.Namespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
app.kubernetes.io/component: vectorstore
spec:
type: ClusterIP
ports:
- port: 8080
targetPort: http
protocol: TCP
name: http
- port: 50051
targetPort: grpc
protocol: TCP
name: grpc
selector:
{{- include "bifrost.selectorLabels" . | nindent 4 }}
app.kubernetes.io/component: vectorstore
{{- end }}
@@ -0,0 +1,36 @@
# Configuration: External PostgreSQL (not deployed by Helm)
# Usage: helm install bifrost ./bifrost -f values-examples/external-postgres.yaml
# Storage configuration
storage:
mode: postgres
configStore:
enabled: true
logsStore:
enabled: true
# Use external PostgreSQL
postgresql:
enabled: false
external:
enabled: true
host: "your-postgres-host.example.com"
port: 5432
user: bifrost
password: "your-secure-password"
database: bifrost
sslMode: require
# No vector store
vectorStore:
enabled: false
type: none
# Bifrost configuration
bifrost:
encryptionKey: "your-encryption-key-here"
client:
enableLogging: true
providers: {}
# Add your provider keys here
@@ -0,0 +1,51 @@
# Configuration: SQLite for config store + PostgreSQL for logs store
# This demonstrates independent backend selection for each store
# Usage: helm install bifrost ./bifrost -f values-examples/mixed-backend.yaml
# Storage configuration with mixed backends
storage:
mode: sqlite # Default fallback (not used when per-store type is set)
persistence:
enabled: true
size: 5Gi
configStore:
enabled: true
type: sqlite # Config store uses SQLite (fast, local, simple)
logsStore:
enabled: true
type: postgres # Logs store uses PostgreSQL (scalable, queryable)
# Deploy PostgreSQL for logs store
postgresql:
enabled: true
auth:
username: bifrost
password: bifrost_password
database: bifrost
primary:
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 250m
memory: 256Mi
# No vector store
vectorStore:
enabled: false
type: none
# Bifrost configuration
bifrost:
client:
enableLogging: true
providers: {}
# Add your provider keys here
# openai:
# keys:
# - value: "sk-..."
# weight: 1
@@ -0,0 +1,46 @@
# Configuration: PostgreSQL for config and logs store
# Usage: helm install bifrost ./bifrost -f values-examples/postgres-only.yaml
# Storage configuration
storage:
mode: postgres
configStore:
enabled: true
logsStore:
enabled: true
# Deploy PostgreSQL
postgresql:
enabled: true
auth:
username: bifrost
password: bifrost_password
database: bifrost
primary:
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 250m
memory: 256Mi
# No vector store
vectorStore:
enabled: false
type: none
# Bifrost configuration
bifrost:
client:
enableLogging: true
providers: {}
# Add your provider keys here
# openai:
# keys:
# - value: "sk-..."
# weight: 1
@@ -0,0 +1,82 @@
# Configuration: PostgreSQL for config/logs + Qdrant for vector store
# Usage: helm install bifrost ./bifrost -f values-examples/postgres-qdrant.yaml
#
# SECURITY NOTE: This example contains placeholder values that MUST be replaced
# before deployment. Specifically:
# - PostgreSQL password must be set to a strong, randomly generated value
# - Provider API keys must be replaced with real keys
# See inline comments for specific requirements.
# Storage configuration
storage:
mode: postgres
configStore:
enabled: true
logsStore:
enabled: true
# PostgreSQL configuration
postgresql:
enabled: true
auth:
username: bifrost
# REQUIRED: Replace with a strong, randomly generated password
# Example: Use `openssl rand -base64 32` to generate a secure password
# Or set via Helm: --set postgresql.auth.password="$(openssl rand -base64 32)"
password: "REPLACE_ME_WITH_STRONG_PASSWORD"
database: bifrost
primary:
persistence:
enabled: true
size: 20Gi
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
# Deploy Qdrant for vector store
vectorStore:
enabled: true
type: qdrant
qdrant:
enabled: true
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
# Bifrost configuration
bifrost:
client:
enableLogging: true
providers: {}
# Add your provider keys here
# Enable semantic cache plugin to use Qdrant vector store
plugins:
semanticCache:
enabled: true
# OPTION 1 (Recommended): Reference to external Kubernetes Secret for OpenAI API key
# Create the secret with: kubectl create secret generic bifrost-semantic-cache --from-literal=openai-key=sk-YOUR_OPENAI_KEY
secretRef:
name: "bifrost-semantic-cache"
key: "openai-key"
# OPTION 2 (Not recommended): Or uncomment to provide keys directly (not secure)
# Remove secretRef above and uncomment the keys below:
config:
provider: "openai"
# keys:
# - "REPLACE_WITH_OPENAI_API_KEY" # Not recommended: use secretRef instead
embedding_model: "text-embedding-3-small"
dimension: 1536
threshold: 0.8
ttl: "5m"
@@ -0,0 +1,75 @@
# Configuration: PostgreSQL for config/logs + Redis for vector store
# Usage: helm install bifrost ./bifrost -f values-examples/postgres-redis.yaml
# Storage configuration
storage:
mode: postgres
configStore:
enabled: true
logsStore:
enabled: true
# Deploy PostgreSQL
postgresql:
enabled: true
auth:
username: bifrost
password: bifrost_password
database: bifrost
primary:
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 250m
memory: 256Mi
# Deploy Redis for vector store
vectorStore:
enabled: true
type: redis
redis:
enabled: true
auth:
enabled: true
password: "redis_password"
master:
persistence:
enabled: true
size: 8Gi
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
# Bifrost configuration
bifrost:
client:
enableLogging: true
providers: {}
# Add your provider keys here
# Enable semantic cache plugin to use Redis vector store
plugins:
semanticCache:
enabled: true
# Reference to external Kubernetes Secret for OpenAI API key
# Create the secret with: kubectl create secret generic bifrost-semantic-cache --from-literal=openai-key=sk-YOUR_OPENAI_KEY
secretRef:
name: "bifrost-semantic-cache"
key: "openai-key"
config:
provider: "openai"
# keys are injected from the secret via environment variable
embedding_model: "text-embedding-3-small"
dimension: 1536
threshold: 0.8
ttl: "5m"
@@ -0,0 +1,72 @@
# Configuration: PostgreSQL for config/logs + Weaviate for vector store
# Usage: helm install bifrost ./bifrost -f values-examples/postgres-weaviate.yaml
# Storage configuration
storage:
mode: postgres
configStore:
enabled: true
logsStore:
enabled: true
# Deploy PostgreSQL
postgresql:
enabled: true
auth:
username: bifrost
password: bifrost_password
database: bifrost
primary:
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 250m
memory: 256Mi
# Deploy Weaviate for vector store
vectorStore:
enabled: true
type: weaviate
weaviate:
enabled: true
replicas: 1
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
# Bifrost configuration
bifrost:
client:
enableLogging: true
providers: {}
# Add your provider keys here
# Enable semantic cache plugin to use vector store
plugins:
semanticCache:
enabled: true
# Reference to external Kubernetes Secret for OpenAI API key
# Create the secret with: kubectl create secret generic bifrost-semantic-cache --from-literal=openai-key=sk-YOUR_OPENAI_KEY
secretRef:
name: "bifrost-semantic-cache"
key: "openai-key"
config:
provider: "openai"
# keys are injected from the secret via environment variable
embedding_model: "text-embedding-3-small"
dimension: 1536
threshold: 0.8
ttl: "5m"
@@ -0,0 +1,145 @@
# Configuration: Production High-Availability Setup
# PostgreSQL + Weaviate + Auto-scaling + Ingress
# Usage: helm install bifrost ./bifrost -f values-examples/production-ha.yaml
# Multiple replicas for HA
replicaCount: 3
# Auto-scaling configuration
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# Ingress configuration
ingress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
hosts:
- host: bifrost.yourdomain.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: bifrost-tls
hosts:
- bifrost.yourdomain.com
# Resource limits for production
resources:
limits:
cpu: 4000m
memory: 4Gi
requests:
cpu: 1000m
memory: 1Gi
# Storage configuration
storage:
mode: postgres
configStore:
enabled: true
logsStore:
enabled: true
# PostgreSQL with higher resources
postgresql:
enabled: true
auth:
username: bifrost
password: "CHANGE_ME_SECURE_PASSWORD"
database: bifrost
primary:
persistence:
enabled: true
size: 50Gi
resources:
limits:
cpu: 2000m
memory: 4Gi
requests:
cpu: 1000m
memory: 2Gi
# Weaviate for semantic caching
vectorStore:
enabled: true
type: weaviate
weaviate:
enabled: true
replicas: 2
persistence:
enabled: true
size: 50Gi
resources:
limits:
cpu: 2000m
memory: 4Gi
requests:
cpu: 1000m
memory: 2Gi
# Bifrost production configuration
bifrost:
# Reference to external Kubernetes Secret for encryption key
# Create the secret with: kubectl create secret generic bifrost-encryption --from-literal=key=YOUR_ENCRYPTION_KEY
encryptionKeySecret:
name: "bifrost-encryption"
key: "key"
client:
initialPoolSize: 1000
allowedOrigins:
- "https://yourdomain.com"
- "https://app.yourdomain.com"
enableLogging: true
maxRequestBodySizeMb: 100
providers: {}
# Add your production provider keys here
plugins:
telemetry:
enabled: true
config: {}
logging:
enabled: true
config: {}
semanticCache:
enabled: true
# Reference to external Kubernetes Secret for OpenAI API key
# Create the secret with: kubectl create secret generic bifrost-semantic-cache --from-literal=openai-key=sk-YOUR_OPENAI_KEY
secretRef:
name: "bifrost-semantic-cache"
key: "openai-key"
config:
provider: "openai"
# keys are injected from the secret via environment variable
embedding_model: "text-embedding-3-small"
dimension: 1536
threshold: 0.85
ttl: "1h"
conversation_history_threshold: 5
# Pod affinity for better distribution
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- bifrost
topologyKey: kubernetes.io/hostname
@@ -0,0 +1,250 @@
# Configuration: Multiple Providers with API Keys and Virtual Keys
# Usage: helm install bifrost ./bifrost -f values-examples/providers-and-virtual-keys.yaml
#
# This example demonstrates:
# - Multiple providers (OpenAI, Anthropic, Groq) with 2-3 API keys each
# - Virtual keys with provider restrictions
# - Budgets and rate limits for governance
#
# Note: API keys in this example are dummy values for demonstration purposes.
# Replace with real keys in production.
# Image configuration
image:
repository: docker.io/maximhq/bifrost
pullPolicy: IfNotPresent
tag: "v1.3.55"
replicaCount: 1
# Service
service:
type: ClusterIP
port: 8080
# Storage configuration - using SQLite for simplicity
storage:
mode: sqlite
persistence:
enabled: true
size: 5Gi
configStore:
enabled: true
logsStore:
enabled: true
# No PostgreSQL needed for this example
postgresql:
enabled: false
# No vector store for this example
vectorStore:
enabled: false
type: none
# Bifrost configuration
bifrost:
appDir: /app/data
port: 8080
host: 0.0.0.0
logLevel: info
logStyle: json
client:
dropExcessRequests: false
initialPoolSize: 100
allowedOrigins:
- "*"
enableLogging: true
enforceGovernanceHeader: false
allowDirectKeys: false
maxRequestBodySizeMb: 100
# ==========================================================================
# PROVIDERS CONFIGURATION
# ==========================================================================
# Configure multiple providers with 2-3 API keys each.
# Keys have weights for load balancing - higher weight = more traffic.
# Replace dummy values with real API keys in production.
providers:
# OpenAI - 3 API keys with different weights
openai:
keys:
- name: "openai-primary"
value: "sk-dummy-openai-key-1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
weight: 2 # Gets 50% of traffic (2 out of 4 total weight)
models:
- name: "openai-secondary"
value: "sk-dummy-openai-key-2-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
weight: 1 # Gets 25% of traffic
models:
- name: "openai-backup"
value: "sk-dummy-openai-key-3-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
weight: 1 # Gets 25% of traffic
models:
# Anthropic - 2 API keys
anthropic:
keys:
- name: "anthropic-primary"
value: "sk-ant-dummy-key-1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
weight: 1
models:
- name: "anthropic-secondary"
value: "sk-ant-dummy-key-2-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
weight: 1
models:
# Groq - 2 API keys
groq:
keys:
- name: "groq-primary"
value: "gsk_dummy_groq_key_1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
weight: 1
models:
- name: "groq-secondary"
value: "gsk_dummy_groq_key_2_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
weight: 1
models:
# ==========================================================================
# GOVERNANCE CONFIGURATION
# ==========================================================================
# Configure budgets, rate limits, and virtual keys for access control
governance:
# Budget configurations - limit spending per period
budgets:
- id: "budget-dev"
max_limit: 50 # $50 limit
reset_duration: "1M" # Resets monthly
- id: "budget-production"
max_limit: 500 # $500 limit
reset_duration: "1M"
- id: "budget-testing"
max_limit: 10 # $10 limit
reset_duration: "1d" # Resets daily
# Rate limit configurations - limit requests/tokens per period
rateLimits:
- id: "rate-limit-standard"
token_max_limit: 100000
token_reset_duration: "1h"
request_max_limit: 1000
request_reset_duration: "1h"
- id: "rate-limit-high"
token_max_limit: 500000
token_reset_duration: "1h"
request_max_limit: 5000
request_reset_duration: "1h"
- id: "rate-limit-testing"
token_max_limit: 10000
token_reset_duration: "1h"
request_max_limit: 100
request_reset_duration: "1h"
# Virtual Keys - access tokens for different use cases
virtualKeys:
# Development virtual key - access to ALL providers (no restrictions)
- id: "vk-development"
name: "Development Key"
value: "vk-dev-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
is_active: true
budget_id: "budget-dev"
rate_limit_id: "rate-limit-standard"
# No provider_configs means all providers are accessible
# OpenAI-only virtual key - restricted to OpenAI provider with specific keys
- id: "vk-openai-only"
name: "OpenAI Only Key"
value: "vk-openai-yyyyyyyyyyyyyyyyyyyyyyyyyyyy"
is_active: true
budget_id: "budget-production"
rate_limit_id: "rate-limit-high"
provider_configs:
- provider: "openai"
weight: 1
# Restrict to primary and secondary keys only (exclude backup)
keys:
- name: "openai-primary"
- name: "openai-secondary"
# Anthropic + Groq virtual key - access to both providers with key restrictions
- id: "vk-anthropic-groq"
name: "Anthropic and Groq Key"
value: "vk-anthgroq-zzzzzzzzzzzzzzzzzzzzzzzzzz"
is_active: true
budget_id: "budget-production"
rate_limit_id: "rate-limit-high"
provider_configs:
- provider: "anthropic"
weight: 1
# Only use primary anthropic key
keys:
- name: "anthropic-primary"
- provider: "groq"
weight: 1
# Use both groq keys
keys:
- name: "groq-primary"
- name: "groq-secondary"
# Testing virtual key - limited budget and rate for testing
- id: "vk-testing"
name: "Testing Key"
value: "vk-test-tttttttttttttttttttttttttttt"
is_active: true
budget_id: "budget-testing"
rate_limit_id: "rate-limit-testing"
provider_configs:
- provider: "openai"
weight: 1
allowed_models:
- "gpt-4o-mini" # Only allow the cheaper model for testing
# Use only the backup key for testing purposes
keys:
- name: "openai-backup"
# Plugins configuration
plugins:
telemetry:
enabled: false
logging:
enabled: true
config: {}
governance:
enabled: true
config:
is_vk_mandatory: false # Set to true to require virtual key on all requests
# Resource limits
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 250m
memory: 256Mi
# Probes
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
autoscaling:
enabled: false
@@ -0,0 +1,106 @@
# Configuration: Using Kubernetes Secrets for All Sensitive Values
# Usage: helm install bifrost ./bifrost -f values-examples/secrets-from-k8s.yaml
#
# This example demonstrates how to use existing Kubernetes secrets for all
# sensitive values instead of putting them directly in the values file.
#
# Prerequisites:
# 1. Create the required Kubernetes secrets before installing the chart:
#
# # PostgreSQL password secret
# kubectl create secret generic postgres-credentials \
# --from-literal=password='your-postgres-password'
#
# # Encryption key secret
# kubectl create secret generic bifrost-encryption \
# --from-literal=key='your-encryption-key'
#
# # Provider API keys secret
# kubectl create secret generic provider-api-keys \
# --from-literal=openai-api-key='sk-...' \
# --from-literal=anthropic-api-key='sk-ant-...'
#
# # Qdrant API key secret (if using Qdrant)
# kubectl create secret generic qdrant-credentials \
# --from-literal=api-key='your-qdrant-api-key'
# Storage configuration
storage:
mode: postgres
configStore:
enabled: true
logsStore:
enabled: true
# External PostgreSQL with credentials from Kubernetes secret
postgresql:
enabled: false
external:
enabled: true
host: "your-postgres-host.example.com"
port: 5432
user: bifrost
database: bifrost
sslMode: require
# Reference existing Kubernetes secret for password
existingSecret: "postgres-credentials"
passwordKey: "password"
# Vector store with API key from Kubernetes secret
vectorStore:
enabled: true
type: qdrant
qdrant:
enabled: false
external:
enabled: true
host: "your-qdrant-host.example.com"
port: 6334
useTls: true
# Reference existing Kubernetes secret for API key
existingSecret: "qdrant-credentials"
apiKeyKey: "api-key"
# Bifrost configuration
bifrost:
# Encryption key from Kubernetes secret
encryptionKeySecret:
name: "bifrost-encryption"
key: "key"
client:
enableLogging: true
# Provider configurations using env.VAR_NAME syntax
# The actual values come from providerSecrets below
providers:
openai:
keys:
- value: "env.OPENAI_API_KEY"
weight: 1
anthropic:
keys:
- value: "env.ANTHROPIC_API_KEY"
weight: 1
# Provider secrets - inject API keys from Kubernetes secrets as env vars
providerSecrets:
openai:
existingSecret: "provider-api-keys"
key: "openai-api-key"
envVar: "OPENAI_API_KEY"
anthropic:
existingSecret: "provider-api-keys"
key: "anthropic-api-key"
envVar: "ANTHROPIC_API_KEY"
plugins:
# Maxim plugin with API key from secret
maxim:
enabled: false # Set to true if using Maxim
config:
log_repo_id: "your-log-repo-id"
secretRef:
name: "maxim-credentials"
key: "api-key"
@@ -0,0 +1,28 @@
# Example Kubernetes Secret for Semantic Cache API Key
# This secret is referenced by production-ha.yaml
#
# IMPORTANT: Do not commit this file with real API keys to version control!
#
# Usage:
# 1. Replace 'YOUR_OPENAI_API_KEY' with your actual OpenAI API key
# 2. Apply the secret: kubectl apply -f semantic-cache-secret-example.yaml -n <namespace>
# 3. Deploy Bifrost with: helm install bifrost . -f values-examples/production-ha.yaml -n <namespace>
#
# Alternative: Create the secret using kubectl command:
# kubectl create secret generic bifrost-semantic-cache \
# --from-literal=openai-key=sk-YOUR_OPENAI_API_KEY \
# -n <namespace>
apiVersion: v1
kind: Secret
metadata:
name: bifrost-semantic-cache
namespace: default # Change this to your target namespace
labels:
app.kubernetes.io/name: bifrost
app.kubernetes.io/component: semantic-cache
type: Opaque
stringData:
# Replace with your actual OpenAI API key
openai-key: "sk-YOUR_OPENAI_API_KEY"
@@ -0,0 +1,34 @@
# Configuration: SQLite for config and logs store
# Usage: helm install bifrost ./bifrost -f values-examples/sqlite-only.yaml
# Storage configuration
storage:
mode: sqlite
persistence:
enabled: true
size: 10Gi
configStore:
enabled: true
logsStore:
enabled: true
# No PostgreSQL
postgresql:
enabled: false
# No vector store
vectorStore:
enabled: false
type: none
# Bifrost configuration
bifrost:
client:
enableLogging: true
providers: {}
# Add your provider keys here
# openai:
# keys:
# - value: "sk-..."
# weight: 1
@@ -0,0 +1,58 @@
# Configuration: SQLite for config/logs + Qdrant for vector store
# Usage: helm install bifrost ./bifrost -f values-examples/sqlite-qdrant.yaml
# Storage configuration
storage:
mode: sqlite
persistence:
enabled: true
size: 10Gi
configStore:
enabled: true
logsStore:
enabled: true
# No PostgreSQL
postgresql:
enabled: false
# Deploy Qdrant for vector store
vectorStore:
enabled: true
type: qdrant
qdrant:
enabled: true
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
# Bifrost configuration
bifrost:
client:
enableLogging: true
providers: {}
# Add your provider keys here
# Enable semantic cache plugin to use vector store
plugins:
semanticCache:
enabled: true
# Reference to external Kubernetes Secret for OpenAI API key
# Create the secret with: kubectl create secret generic bifrost-semantic-cache --from-literal=openai-key=sk-YOUR_OPENAI_KEY
secretRef:
name: "bifrost-semantic-cache"
key: "openai-key"
config:
provider: "openai"
# keys are injected from the secret via environment variable
embedding_model: "text-embedding-3-small"
dimension: 1536
threshold: 0.8
ttl: "5m"
@@ -0,0 +1,76 @@
# Configuration: SQLite for config/logs + Redis for vector store
# Usage: helm install bifrost ./bifrost -f values-examples/sqlite-redis.yaml
#
# SECURITY NOTE: This example contains placeholder values that MUST be replaced
# before deployment. Specifically:
# - Redis password must be set to a strong, randomly generated value
# - Provider API keys must be replaced with real keys
# See inline comments for specific requirements.
# Storage configuration
storage:
mode: sqlite
persistence:
enabled: true
size: 10Gi
configStore:
enabled: true
logsStore:
enabled: true
# No PostgreSQL
postgresql:
enabled: false
# Deploy Redis for vector store
vectorStore:
enabled: true
type: redis
redis:
enabled: true
auth:
enabled: true
# REQUIRED: Replace with a strong, randomly generated password
# Example: Use `openssl rand -base64 32` to generate a secure password
# Or set via Helm: --set vectorStore.redis.auth.password="$(openssl rand -base64 32)"
# Or use a Kubernetes secret: --set vectorStore.redis.auth.existingSecret=redis-secret
password: "REPLACE_ME_WITH_STRONG_PASSWORD"
master:
persistence:
enabled: true
size: 8Gi
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
# Bifrost configuration
bifrost:
client:
enableLogging: true
providers: {}
# Add your provider keys here
# Enable semantic cache plugin to use Redis vector store
plugins:
semanticCache:
enabled: true
# OPTION 1 (Recommended): Reference to external Kubernetes Secret for OpenAI API key
# Create the secret with: kubectl create secret generic bifrost-semantic-cache --from-literal=openai-key=sk-YOUR_OPENAI_KEY
secretRef:
name: "bifrost-semantic-cache"
key: "openai-key"
# OPTION 2 (Not recommended): Or uncomment to provide keys directly (not secure)
# Remove secretRef above and uncomment the keys below:
config:
provider: "openai"
# keys:
# - "REPLACE_WITH_OPENAI_API_KEY" # Not recommended: use secretRef instead
embedding_model: "text-embedding-3-small"
dimension: 1536
threshold: 0.8
ttl: "5m"
@@ -0,0 +1,60 @@
# Configuration: SQLite for config/logs + Weaviate for vector store
# Usage: helm install bifrost ./bifrost -f values-examples/sqlite-weaviate.yaml
# Storage configuration
storage:
mode: sqlite
persistence:
enabled: true
size: 10Gi
configStore:
enabled: true
logsStore:
enabled: true
# No PostgreSQL
postgresql:
enabled: false
# Deploy Weaviate for vector store
vectorStore:
enabled: true
type: weaviate
weaviate:
enabled: true
replicas: 1
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
# Bifrost configuration
bifrost:
client:
enableLogging: true
providers: {}
# Add your provider keys here
# Enable semantic cache plugin to use vector store
plugins:
semanticCache:
enabled: true
# Reference to external Kubernetes Secret for OpenAI API key
# Create the secret with: kubectl create secret generic bifrost-semantic-cache --from-literal=openai-key=sk-YOUR_OPENAI_KEY
secretRef:
name: "bifrost-semantic-cache"
key: "openai-key"
config:
provider: "openai"
# keys are injected from the secret via environment variable
embedding_model: "text-embedding-3-small"
dimension: 1536
threshold: 0.8
ttl: "5m"
File diff suppressed because it is too large Load Diff
+911
View File
@@ -0,0 +1,911 @@
# Default values for Bifrost
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# Bifrost application configuration
replicaCount: 1
image:
# Container image repository
# Default: Docker Hub public image
# For enterprise customers with private registry, use full URL:
# repository: us-west1-docker.pkg.dev/bifrost-enterprise/your-org/bifrost
# repository: your-registry.example.com/your-org/bifrost
# repository: 123456789.dkr.ecr.us-east-1.amazonaws.com/bifrost
repository: docker.io/maximhq/bifrost
pullPolicy: IfNotPresent
# REQUIRED: Specify the image tag (e.g., v1.5.0, latest)
# Docker images are tagged with v prefix (e.g., v1.5.0)
# See available tags at: https://hub.docker.com/r/maximhq/bifrost/tags
tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
# Automatically mount a ServiceAccount's API credentials?
automount: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
# Annotations to add to the deployment metadata
# Useful for tools like Keel (keel.sh) for automatic image updates
# Example:
# deploymentAnnotations:
# keel.sh/policy: force
# keel.sh/trigger: poll
deploymentAnnotations: {}
# Labels to add to the deployment metadata (in addition to default labels)
deploymentLabels: {}
podAnnotations: {}
podLabels: {}
podSecurityContext:
fsGroup: 1000
runAsUser: 1000
runAsNonRoot: true
securityContext:
capabilities:
drop:
- ALL
readOnlyRootFilesystem: false
runAsNonRoot: true
runAsUser: 1000
service:
type: ClusterIP
port: 8080
annotations: {}
ingress:
enabled: false
className: ""
annotations: {}
hosts:
- host: bifrost.local
paths:
- path: /
pathType: Prefix
tls: []
resources:
limits:
cpu: 2000m
memory: 2Gi
requests:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 80
targetMemoryUtilizationPercentage: 80
# HPA scaling behavior configuration
# Controls how quickly the HPA scales up/down to prevent connection disruption
behavior:
scaleDown:
# Stabilization window prevents rapid scale-down oscillation.
# The HPA will wait this long after the last scale event before scaling down again.
# Important for long-lived streaming connections (e.g. SSE for LLM inference).
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 120
scaleUp:
stabilizationWindowSeconds: 30
# Additional volumes on the output Deployment definition.
volumes: []
# Additional volumeMounts on the output Deployment definition.
volumeMounts: []
nodeSelector: {}
tolerations: []
affinity: {}
# Graceful shutdown configuration for long-lived connections (SSE streaming)
# When a pod is terminated (e.g. during HPA scale-down), active streaming connections
# are severed abruptly. This causes clients to lose their SSE stream mid-response.
# The preStop hook and termination grace period give in-flight requests time to complete.
terminationGracePeriodSeconds: 60
lifecycle:
preStop:
exec:
# Sleep allows the pod to be removed from the Service endpoints and load balancer
# before the process starts shutting down, preventing new connections from arriving
# while existing ones drain.
command: ["sh", "-c", "sleep 15"]
# Bifrost specific configuration
# You can find entire schema at https://getbifrost.ai/schema
bifrost:
# Application settings
appDir: /app/data
port: 8080
host: 0.0.0.0
logLevel: info
logStyle: json
# Encryption key for sensitive data
# Can be set as a secret or environment variable
encryptionKey: ""
# Authentication configuration (top-level)
# This controls authentication for Bifrost API and dashboard
authConfig:
adminUsername: ""
adminPassword: ""
isEnabled: false
disableAuthOnInference: false
# Use existing Kubernetes secret for admin credentials
existingSecret: ""
usernameKey: "username"
passwordKey: "password"
# Client configuration
client:
dropExcessRequests: false
initialPoolSize: 300
allowedOrigins:
- "*"
enableLogging: true
disableContentLogging: false
disableDbPingsInHealth: false
logRetentionDays: 365
enforceGovernanceHeader: false
allowDirectKeys: false
maxRequestBodySizeMb: 100
prometheusLabels: []
# Header filtering configuration for x-bf-eh-* headers forwarded to LLM providers
headerFilterConfig:
allowlist: []
denylist: []
# asyncJobResultTTL: 3600 # Default TTL for async job results in seconds
# requiredHeaders: [] # Headers that must be present on every request
# loggingHeaders: [] # Headers to capture in log metadata
# allowedHeaders: [] # Additional allowed headers for CORS and WebSocket
# mcpAgentDepth: 10 # Maximum depth for MCP agent mode tool execution
# mcpToolExecutionTimeout: 30 # Timeout for individual MCP tool execution in seconds
# mcpCodeModeBindingLevel: "" # Code mode binding level (server or tool)
# mcpToolSyncInterval: 0 # Global tool sync interval in minutes (0 = disabled)
# hideDeletedVirtualKeysInFilters: false # Omit deleted virtual keys from logs/MCP filter data
# Framework configuration
framework:
pricing:
# Custom pricing URL for model cost data
pricingUrl: ""
# Sync interval in seconds (default: 86400 = 24 hours, minimum: 3600)
pricingSyncInterval: 86400
# Provider configurations (add your provider keys here)
# You can specify API keys directly or use env.VAR_NAME syntax to reference environment variables
# When using existingSecret in providerSecrets, the keys will be injected as env vars and
# you should use env.VAR_NAME syntax in the value field
# Note: The entire providers block is passed through to the config as-is.
# See https://getbifrost.ai/schema for the full provider schema.
providers: {}
# openai:
# keys:
# - name: "primary-key" # Key name (required, must be unique)
# value: "sk-..." # Direct value
# weight: 1
# models: ["gpt-4o", "gpt-4o-mini"] # Restrict key to specific models
# use_for_batch_api: false # Whether this key can be used for batch API
# - name: "secondary-key"
# value: "env.OPENAI_KEY" # Reference to environment variable
# weight: 1
# # Network configuration (optional, per-provider)
# network_config:
# base_url: "" # Custom base URL (required for Ollama)
# extra_headers: {} # Additional headers to send with requests
# default_request_timeout_in_seconds: 300 # Request timeout
# max_retries: 3 # Maximum number of retries
# retry_backoff_initial_ms: 500 # Initial retry backoff in ms
# retry_backoff_max_ms: 5000 # Max retry backoff in ms
# # Concurrency configuration (optional)
# concurrency_and_buffer_size:
# concurrency: 100 # Number of concurrent requests
# buffer_size: 200 # Buffer size for requests
# # Proxy configuration (optional)
# proxy_config:
# type: "none" # Options: none, http, socks5, environment
# url: ""
# username: ""
# password: ""
# ca_cert_pem: "" # PEM-encoded CA cert for SSL-intercepting proxies
# send_back_raw_response: false # Include raw response in BifrostResponse
# store_raw_request_response: false # Capture raw payloads for plugins only; not returned to client
#
# anthropic:
# keys:
# - name: "anthropic-key"
# value: "sk-ant-..."
# weight: 1
#
# # Azure OpenAI example (requires azure_key_config)
# azure:
# keys:
# - name: "azure-key"
# value: "..."
# weight: 1
# azure_key_config:
# endpoint: "https://your-resource.openai.azure.com"
# api_version: "2024-02-15-preview"
# deployments:
# gpt-4o: "my-gpt4o-deployment"
#
# # Google Vertex AI example (requires vertex_key_config)
# vertex:
# keys:
# - name: "vertex-key"
# value: ""
# weight: 1
# vertex_key_config:
# project_id: "my-gcp-project"
# region: "us-central1"
# auth_credentials: "env.GOOGLE_CREDENTIALS"
#
# # AWS Bedrock example (requires bedrock_key_config)
# bedrock:
# keys:
# - name: "bedrock-key"
# value: ""
# weight: 1
# bedrock_key_config:
# region: "us-east-1"
# access_key: "env.AWS_ACCESS_KEY_ID"
# secret_key: "env.AWS_SECRET_ACCESS_KEY"
# Provider secrets - use existing Kubernetes secrets for provider API keys
# These will be injected as environment variables that can be referenced in providers config
providerSecrets: {}
# openai:
# existingSecret: "my-openai-secret"
# key: "api-key"
# envVar: "OPENAI_API_KEY" # Environment variable name to inject
# anthropic:
# existingSecret: "my-anthropic-secret"
# key: "api-key"
# envVar: "ANTHROPIC_API_KEY"
# MCP (Model Context Protocol) configuration
mcp:
enabled: false
clientConfigs: []
# - name: "example-mcp"
# connectionType: "stdio"
# stdioConfig:
# command: "/path/to/mcp/server"
# args: []
# envs: []
# toolSyncInterval: "10m" # Global tool sync interval (Go duration)
# Tool manager configuration
toolManagerConfig:
toolExecutionTimeout: 30
maxAgentDepth: 10
# codeModeBindingLevel: "" # Code mode binding level (server or tool)
# Plugins configuration
plugins:
telemetry:
enabled: false
config:
custom_labels: []
# push_gateway:
# enabled: false
# push_gateway_url: ""
# job_name: "bifrost"
# instance_id: ""
# push_interval: 15
# basic_auth:
# username: ""
# password: ""
logging:
enabled: false
config:
disable_content_logging: false
logging_headers: []
governance:
enabled: false
config:
is_vk_mandatory: false
required_headers: []
is_enterprise: false
maxim:
enabled: false
config:
api_key: ""
log_repo_id: ""
# Use existing Kubernetes secret for API key (takes precedence over config.api_key)
secretRef:
name: ""
key: "api-key"
semanticCache:
enabled: false
config:
# Semantic caching mode (dimension > 1): requires provider, keys, and embedding_model
# Direct caching mode (dimension: 1): hash-based exact matching, no embedding provider needed
provider: "openai"
keys: []
embedding_model: "text-embedding-3-small"
dimension: 1536
threshold: 0.8
ttl: "5m"
conversation_history_threshold: 3
cache_by_model: true
cache_by_provider: true
exclude_system_prompt: false
cleanup_on_shutdown: false
vector_store_namespace: ""
otel:
enabled: false
config:
service_name: "bifrost"
collector_url: ""
trace_type: "otel"
protocol: "grpc"
# Push-based metrics export via OTLP (recommended for multi-node clusters)
metrics_enabled: false
metrics_endpoint: "" # e.g., http://otel-collector:4318/v1/metrics (HTTP) or otel-collector:4317 (gRPC)
metrics_push_interval: 15 # Push interval in seconds (1-300)
# Custom headers for the collector (supports env.VAR_NAME prefix for env var substitution)
headers: {}
# TLS configuration
tls_ca_cert: "" # Path to TLS CA certificate file
insecure: false # Skip TLS verification (ignored if tls_ca_cert is set)
datadog:
enabled: false
config:
service_name: "bifrost"
agent_addr: "localhost:8126"
env: ""
version: ""
custom_tags: {}
enable_traces: true
# Custom/dynamic plugins
custom: []
# - name: "my-custom-plugin"
# enabled: true
# path: "/plugins/my-plugin.so"
# version: 1
# config:
# key: value
# Governance configuration for budgets, rate limits, customers, teams, virtual keys, and routing rules
governance:
budgets: []
# - id: "budget-1"
# max_limit: 100
# reset_duration: "1M" # Supports: 30s, 5m, 1h, 1d, 1w, 1M, 1Y
rateLimits: []
# - id: "rate-limit-1"
# token_max_limit: 100000
# token_reset_duration: "1d"
# request_max_limit: 1000
# request_reset_duration: "1h"
customers: []
# - id: "customer-1"
# name: "Customer Name"
# budget_id: "budget-1"
# rate_limit_id: "rate-limit-1"
teams: []
# - id: "team-1"
# name: "Team Name"
# customer_id: "customer-1"
# budget_id: "budget-1"
# rate_limit_id: "rate-limit-1"
# profile: {} # Team profile data
# config: {} # Team configuration data
# claims: {} # Team claims data
virtualKeys: []
# - id: "vk-1"
# name: "Virtual Key 1"
# description: "Virtual key description"
# value: "vk-..."
# is_active: true
# team_id: "team-1" # Mutually exclusive with customer_id
# customer_id: "" # Mutually exclusive with team_id
# budget_id: "budget-1"
# rate_limit_id: "rate-limit-1"
# # Provider-specific configurations (empty means all providers allowed)
# provider_configs:
# - provider: "openai"
# weight: 1.0
# allowed_models: ["gpt-4o"]
# budget_id: ""
# rate_limit_id: ""
# keys:
# - key_id: "uuid-of-key"
# name: "my-key"
# value: "sk-..."
# # MCP configurations for this virtual key
# mcp_configs:
# - mcp_client_id: 1
# tools_to_execute: ["tool1", "tool2"]
modelConfigs: []
# - id: "model-config-1"
# model_name: "gpt-4o"
# provider: "openai"
# budget_id: "budget-1"
# rate_limit_id: "rate-limit-1"
providers: []
# - name: "openai"
# budget_id: "budget-1"
# rate_limit_id: "rate-limit-1"
# send_back_raw_request: false
# send_back_raw_response: false
routingRules: []
# - id: "route-1"
# name: "Route to Azure"
# description: "Route GPT requests to Azure"
# enabled: true
# cel_expression: "request.model.startsWith('gpt-')"
# provider: "azure"
# model: "" # Empty means use original model
# fallbacks: ["openai"]
# scope: "global" # Options: global, team, customer, virtual_key
# scope_id: "" # Required for non-global scopes
# priority: 0 # Lower = evaluated first
authConfig:
adminUsername: ""
adminPassword: ""
isEnabled: false
disableAuthOnInference: false
# Use existing Kubernetes secret for admin credentials
existingSecret: ""
usernameKey: "username"
passwordKey: "password"
# Cluster mode configuration for distributed deployments
cluster:
enabled: false
# region: "" # Region identifier for cluster
peers: []
# - "bifrost-0.bifrost-headless:7946"
# - "bifrost-1.bifrost-headless:7946"
gossip:
port: 7946
config:
timeoutSeconds: 10
successThreshold: 3
failureThreshold: 3
discovery:
enabled: false
# Discovery type: kubernetes, dns, udp, consul, etcd, mdns
type: ""
allowedAddressSpace: []
# Kubernetes discovery
k8sNamespace: ""
k8sLabelSelector: ""
# DNS discovery
dnsNames: []
# UDP broadcast discovery
udpBroadcastPort: 0
# Consul discovery
consulAddress: ""
# Etcd discovery
etcdEndpoints: []
# mDNS discovery
mdnsService: ""
# SAML/SCIM configuration for enterprise SSO
saml:
enabled: false
# Provider: okta, entra
provider: ""
config: {}
# Okta configuration:
# issuerUrl: "https://your-domain.okta.com/oauth2/default"
# clientId: ""
# clientSecret: ""
# audience: ""
# userIdField: "sub"
# teamIdsField: "groups"
# rolesField: "roles"
#
# Entra (Azure AD) configuration:
# tenantId: ""
# clientId: ""
# clientSecret: ""
# cloud: "commercial" # or "gcc-high" or "dod"
# audience: ""
# appIdUri: ""
# userIdField: "oid"
# teamIdsField: "groups"
# rolesField: "roles"
# Load balancer configuration for intelligent request routing
loadBalancer:
enabled: false
trackerConfig: {}
bootstrap: {}
# Guardrails configuration for content moderation and policy enforcement
guardrails:
rules: []
# - id: 1
# name: "Block PII"
# description: "Block requests containing PII"
# enabled: true
# cel_expression: "!contains(request.body, 'SSN')"
# apply_to: "input"
# sampling_rate: 100
# timeout: 1000
providers: []
# - id: 1
# provider_name: "bedrock"
# policy_name: "content-filter"
# enabled: true
# config: {}
# Audit logs configuration for CADF-compliant activity logging
auditLogs:
disabled: false
hmacKey: ""
# Storage configuration
storage:
# Default storage mode: sqlite or postgres
# Used as fallback when per-store type is not specified
mode: sqlite # Options: sqlite, postgres
# Persistent volume for SQLite databases (when using sqlite for any store)
persistence:
enabled: true
# storageClass: "-" # Use default storage class
accessMode: ReadWriteOnce
size: 10Gi
# existingClaim: "" # Use an existing PVC
# Configuration store settings
configStore:
enabled: true
# Backend type for config store. Empty string uses storage.mode as default
type: "" # Options: sqlite, postgres, or "" (uses storage.mode)
# PostgreSQL connection pool tuning (only applies when type is postgres)
# maxIdleConns: 5
# maxOpenConns: 50
# Logs store settings
logsStore:
enabled: true
# Backend type for logs store. Empty string uses storage.mode as default
type: "" # Options: sqlite, postgres, or "" (uses storage.mode)
# PostgreSQL connection pool tuning (only applies when type is postgres)
# maxIdleConns: 5
# maxOpenConns: 50
# PostgreSQL configuration (when any store uses postgres)
postgresql:
# Deploy PostgreSQL as part of this chart
enabled: false
# Use external PostgreSQL instance
external:
enabled: false
host: ""
port: 5432
user: bifrost
password: ""
database: bifrost
sslMode: disable
# Use existing Kubernetes secret for password (takes precedence over password field)
existingSecret: ""
passwordKey: "password"
# PostgreSQL image configuration
image:
repository: postgres
tag: "16-alpine"
pullPolicy: IfNotPresent
# PostgreSQL subchart configuration (when postgresql.enabled is true)
auth:
username: bifrost
password: bifrost_password
database: bifrost
primary:
persistence:
enabled: true
size: 8Gi
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 250m
memory: 256Mi
metrics:
enabled: false
# Vector store configuration
vectorStore:
# Enable vector store for semantic caching
enabled: false
type: none # Options: none, weaviate, redis, qdrant
# Weaviate configuration
weaviate:
# Deploy Weaviate as part of this chart
enabled: false
# Use external Weaviate instance
external:
enabled: false
scheme: http
host: ""
apiKey: ""
grpcHost: ""
grpcSecured: false
# timeout: "5s" # Timeout for operations (e.g., "5s", "30s")
# className: "" # Class name for vector store
# Use existing Kubernetes secret for API key (takes precedence over apiKey field)
existingSecret: ""
apiKeyKey: "api-key"
# Weaviate subchart configuration (when weaviate.enabled is true)
replicas: 1
image:
repository: semitechnologies/weaviate
tag: "1.24.1"
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
env:
QUERY_DEFAULTS_LIMIT: "25"
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: "true"
PERSISTENCE_DATA_PATH: "/var/lib/weaviate"
DEFAULT_VECTORIZER_MODULE: "none"
ENABLE_MODULES: ""
CLUSTER_HOSTNAME: "node1"
# Redis configuration
redis:
# Deploy Redis as part of this chart
enabled: false
# Use external Redis instance
external:
enabled: false
host: ""
port: 6379
username: ""
password: ""
database: 0
# Connection pool tuning (optional)
# poolSize: 10 # Maximum number of socket connections
# maxActiveConns: 0 # Maximum number of active connections
# minIdleConns: 0 # Minimum number of idle connections
# maxIdleConns: 0 # Maximum number of idle connections
# connMaxLifetime: "" # Connection max lifetime (e.g., "30m")
# connMaxIdleTime: "" # Connection max idle time (e.g., "5m")
# dialTimeout: "" # Socket connection timeout (e.g., "5s")
# readTimeout: "" # Socket read timeout (e.g., "3s")
# writeTimeout: "" # Socket write timeout (e.g., "3s")
# contextTimeout: "" # Redis operation timeout (e.g., "10s")
# Use existing Kubernetes secret for password (takes precedence over password field)
existingSecret: ""
passwordKey: "password"
# Redis image configuration
image:
repository: redis
tag: "7-alpine"
pullPolicy: IfNotPresent
# Redis subchart configuration (when redis.enabled is true)
auth:
enabled: true
password: "redis_password"
master:
persistence:
enabled: true
size: 8Gi
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
metrics:
enabled: false
# Qdrant configuration
qdrant:
# Deploy Qdrant as part of this chart
enabled: false
# Use external Qdrant instance
external:
enabled: false
host: ""
port: 6334
apiKey: ""
useTls: false
# Use existing Kubernetes secret for API key (takes precedence over apiKey field)
existingSecret: ""
apiKeyKey: "api-key"
# Qdrant image configuration
image:
repository: qdrant/qdrant
tag: "v1.16.0"
pullPolicy: IfNotPresent
# Qdrant subchart configuration (when qdrant.enabled is true)
persistence:
enabled: true
size: 10Gi
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
# Pinecone configuration (external only, no self-hosted option)
pinecone:
external:
enabled: false
apiKey: ""
indexHost: "" # Index host URL from Pinecone console (e.g., your-index.svc.environment.pinecone.io)
# Use existing Kubernetes secret for API key (takes precedence over apiKey field)
existingSecret: ""
apiKeyKey: "api-key"
# Environment variables
env: []
# - name: CUSTOM_ENV_VAR
# value: "value"
# Environment variables from secrets/configmaps
envFrom: []
# - secretRef:
# name: my-secret
# - configMapRef:
# name: my-configmap
# Init containers to run before the main application container.
# Provide a list of init containers using standard Kubernetes container spec.
initContainers: []
# --- Meesho Infrastructure Extensions ---
# PodDisruptionBudget
# Ensures high availability during voluntary disruptions (node drains, upgrades)
podDisruptionBudget:
enabled: false
# maxUnavailable and minAvailable are mutually exclusive
maxUnavailable: "10%"
# minAvailable: ""
# ExternalSecret (external-secrets.io)
# Pulls secrets from Vault and creates a K8s Secret
# Use with postgresql.external.existingSecret to inject DB password securely
externalSecret:
enabled: false
# Name of the K8s Secret to create
secretName: ""
# Vault path to extract secrets from
path: ""
# Optional: pin to a specific Vault secret version
version: ""
# Refresh interval ("0" = fetch once, "15s" = poll)
refreshInterval: "0"
# ClusterSecretStore name
secretStoreRef: "vault-backend"
# Contour HTTPProxy
# Replaces standard K8s Ingress with Contour's HTTPProxy for advanced routing
httpProxy:
enabled: false
# Slow start policy applied to all backends
slowStart:
enabled: false
window: "120s"
aggression: 1
minPercent: 10
# List of HTTPProxy resources to create
entries: []
# - fqdn: "llm-gateway.prd.meesho.int"
# ingressClassName: "contour-internal-1"
# routes:
# - conditions:
# - prefix: "/"
# services:
# - port: 8080
# timeoutPolicy:
# response: "infinity"
# KEDA ScaledObject
# Replaces standard HPA with KEDA for event-driven autoscaling
# IMPORTANT: Set autoscaling.enabled=false when using KEDA (mutually exclusive)
keda:
enabled: false
pollingInterval: 30
minReplicaCount: 2
maxReplicaCount: 200
scaledown:
stabilizationWindowSeconds: 1800
selectpolicy: Min
policies:
- type: Pods
value: 2
periodseconds: 15
scaleup:
stabilizationWindowSeconds: 120
selectpolicy: Max
policies:
- type: Pods
value: 2
periodseconds: 15
- type: Percent
value: 10
periodseconds: 15
triggers:
- type: cpu
metricType: Utilization
metadata:
value: "40"