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
@@ -0,0 +1,23 @@
# 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/
@@ -0,0 +1,19 @@
apiVersion: v2
name: bifrost
description: A Helm chart for deploying Bifrost - AI Gateway with unified interface for multiple providers
type: application
version: 2.1.26
appVersion: "1.5.12"
keywords:
- ai
- gateway
- llm
- openai
- anthropic
home: https://www.getmaxim.ai/bifrost
sources:
- https://github.com/maximhq/bifrost
maintainers:
- name: Bifrost Team
email: support@getbifrost.ai
icon: https://www.getbifrost.ai/favicon.png
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,392 @@
#!/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,228 @@
#!/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,93 @@
#!/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,82 @@
Bifrost has been installed!
{{- $isLegacy := true }}
{{- range $k, $v := .Values.ingress }}
{{- if and (kindIs "map" $v) (hasKey $v "enabled") }}{{- $isLegacy = false }}{{- end }}
{{- end }}
{{- if and .Values.ingress $isLegacy .Values.ingress.enabled }}
1. Access Bifrost at:
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .host }}
{{- end }}
{{- else if and .Values.ingress (not $isLegacy) }}
1. Access Bifrost at:
{{- range (keys .Values.ingress | sortAlpha) }}
{{- $ing := index $.Values.ingress . }}
{{- if and (kindIs "map" $ing) $ing.enabled }}
{{- range $ing.hosts }}
http{{ if $ing.tls }}s{{ end }}://{{ .host }}
{{- end }}
{{- end }}
{{- 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 }}
{{- if and .Values.postgresql.enabled (eq .Values.postgresql.auth.password "bifrost_password") }}
WARNING: PostgreSQL is using the default password "bifrost_password". Set postgresql.auth.password to a strong password before going to production.
{{- end }}
{{- if and .Values.vectorStore.enabled (eq .Values.vectorStore.type "redis") .Values.vectorStore.redis.enabled .Values.vectorStore.redis.auth.enabled (eq .Values.vectorStore.redis.auth.password "redis_password") }}
WARNING: Redis is using the default password "redis_password". Set vectorStore.redis.auth.password to a strong password before going to production.
{{- 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,312 @@
{{- /* 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 }}
{{- with .Values.strategy }}
strategy:
{{- toYaml . | nindent 4 }}
{{- 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
{{- if .Values.bifrost.cluster.grpc }}
- name: grpc
containerPort: {{ .Values.bifrost.cluster.grpc.port }}
protocol: TCP
{{- end }}
{{- 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 }}
- 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" }}
{{- else if and .Values.postgresql.enabled (not .Values.postgresql.external.enabled) .Values.postgresql.auth.existingSecret }}
- name: BIFROST_POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.postgresql.auth.existingSecret }}
key: {{ .Values.postgresql.auth.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 }}
{{- /* Object storage credentials from existing secret */ -}}
{{- if and .Values.storage.logsStore.enabled .Values.storage.logsStore.objectStorage .Values.storage.logsStore.objectStorage.enabled .Values.storage.logsStore.objectStorage.existingSecret }}
{{- if eq .Values.storage.logsStore.objectStorage.type "s3" }}
- name: BIFROST_OBJECT_STORAGE_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: {{ .Values.storage.logsStore.objectStorage.existingSecret }}
key: {{ .Values.storage.logsStore.objectStorage.accessKeyIdKey | default "access-key-id" }}
optional: true
- name: BIFROST_OBJECT_STORAGE_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.storage.logsStore.objectStorage.existingSecret }}
key: {{ .Values.storage.logsStore.objectStorage.secretAccessKeyKey | default "secret-access-key" }}
optional: true
- name: BIFROST_OBJECT_STORAGE_SESSION_TOKEN
valueFrom:
secretKeyRef:
name: {{ .Values.storage.logsStore.objectStorage.existingSecret }}
key: {{ .Values.storage.logsStore.objectStorage.sessionTokenKey | default "session-token" }}
optional: true
- name: BIFROST_OBJECT_STORAGE_ROLE_ARN
valueFrom:
secretKeyRef:
name: {{ .Values.storage.logsStore.objectStorage.existingSecret }}
key: {{ .Values.storage.logsStore.objectStorage.roleArnKey | default "role-arn" }}
optional: true
{{- end }}
{{- if eq .Values.storage.logsStore.objectStorage.type "gcs" }}
- name: BIFROST_OBJECT_STORAGE_CREDENTIALS_JSON
valueFrom:
secretKeyRef:
name: {{ .Values.storage.logsStore.objectStorage.existingSecret }}
key: {{ .Values.storage.logsStore.objectStorage.credentialsJsonKey | default "credentials-json" }}
{{- end }}
{{- 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 }}
{{- /* MCP client connection strings from existing secrets (one per client with secretRef.name set) */ -}}
{{- if .Values.bifrost.mcp.enabled }}
{{- range $idx, $client := .Values.bifrost.mcp.clientConfigs }}
{{- if and $client.secretRef $client.secretRef.name }}
- name: BIFROST_MCP_{{ regexReplaceAll "[^A-Z0-9]+" (upper $client.name) "_" }}_CONNECTION_STRING
valueFrom:
secretKeyRef:
name: {{ $client.secretRef.name }}
key: {{ $client.secretRef.connectionStringKey | default "connection-string" }}
{{- end }}
{{- end }}
{{- 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 := (.Values.bifrost.providerSecrets | keys | sortAlpha) }}
{{- $secret := index $.Values.bifrost.providerSecrets $provider }}
{{- 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.extraEnv }}
{{- range $name := keys . | sortAlpha }}
- name: {{ $name }}
value: {{ index $.Values.extraEnv $name | quote }}
{{- end }}
{{- 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,141 @@
{{- 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 | default .Release.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 }}
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
namespace: {{ $namespace }}
name: {{ $namespace }}-intra-{{ $count }}
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: {{ $namespace }}-intra
namespace: {{ $namespace }}
{{- end }}
{{- end }}
{{- end }}
---
{{ $count = add1 $count }}
{{- /* Child Intra HTTPProxy - routes with services */}}
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
namespace: {{ $namespace }}
name: {{ $namespace }}-intra
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 }}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
@@ -0,0 +1,142 @@
{{- 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 | default .Release.Namespace -}}
{{- $ingressClassName := .Values.ingress.ingressClassName -}}
{{ $count := 0 | int }}
{{- range .Values.ingress.hosts }}
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
namespace: {{ $namespace }}
name: {{ $namespace }}-{{ $count }}
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 -}}
{{- $releaseNs := $.Values.namespace | default $.Release.Namespace -}}
{{- $targetNs := ternary .namespace (ternary (split "/" $svc)._0 $releaseNs $hasSlash) (hasKey . "namespace") -}}
{{- $useAlias := ne $targetNs $releaseNs -}}
{{- $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: {{ $namespace }}
namespace: {{ $namespace }}
{{- end }}
{{- end }}
{{- end }}
---
{{ $count = add1 $count }}
{{- /* Child HTTPProxy - routes with services */}}
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
namespace: {{ $namespace }}
name: {{ $namespace }}
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 }}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
@@ -0,0 +1,100 @@
{{- if .Values.ingress }}
{{- $isLegacy := true }}
{{- range $k, $v := .Values.ingress }}
{{- if and (kindIs "map" $v) (hasKey $v "enabled") }}{{- $isLegacy = false }}{{- end }}
{{- end }}
{{- if $isLegacy }}
{{- /* Single ingress (legacy format) — no non-legacy keys present */}}
{{- 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 }}
{{- else }}
{{- /* Named ingresses map (new format) */}}
{{- range (keys .Values.ingress | sortAlpha) }}
{{- $name := . }}
{{- $ing := index $.Values.ingress $name }}
{{- if and (kindIs "map" $ing) $ing.enabled }}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "bifrost.fullname" $ }}-{{ $name }}
namespace: {{ $.Release.Namespace }}
labels:
{{- include "bifrost.labels" $ | nindent 4 }}
{{- with $ing.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if $ing.className }}
ingressClassName: {{ $ing.className }}
{{- end }}
{{- if $ing.tls }}
tls:
{{- range $ing.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range $ing.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 }}
{{- 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,104 @@
{{- 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:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.postgresql.primary.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- else }}
securityContext:
fsGroup: 999
{{- end }}
containers:
- name: postgresql
image: "{{ .Values.postgresql.image.repository }}:{{ .Values.postgresql.image.tag }}"
imagePullPolicy: {{ .Values.postgresql.image.pullPolicy }}
{{- with .Values.postgresql.primary.containerSecurityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: postgresql
containerPort: 5432
protocol: TCP
env:
- name: POSTGRES_USER
value: {{ .Values.postgresql.auth.username | quote }}
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.postgresql.auth.existingSecret | default (printf "%s-postgresql" (include "bifrost.fullname" .)) }}
key: {{ if .Values.postgresql.auth.existingSecret }}{{ .Values.postgresql.auth.passwordKey | default "password" }}{{ else }}password{{ end }}
- 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 }}
{{- with .Values.postgresql.primary.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.postgresql.primary.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.postgresql.primary.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- 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,64 @@
{{- 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,23 @@
{{- 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,24 @@
{{- 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,38 @@
{{- /*
Create pod-discovery RBAC only when all of these are true:
1) rbac.podDiscovery.enabled
2) cluster mode is enabled
3) cluster discovery is enabled
4) discovery type is kubernetes
*/ -}}
{{- if and .Values.rbac.podDiscovery.enabled .Values.bifrost.cluster.enabled .Values.bifrost.cluster.discovery.enabled (eq .Values.bifrost.cluster.discovery.type "kubernetes") -}}
{{- $podDiscoveryRoleName := printf "%s-pod-discovery" (include "bifrost.fullname" . | trunc 49 | trimSuffix "-") -}}
{{- $discoveryNamespace := .Values.bifrost.cluster.discovery.k8sNamespace | default .Release.Namespace -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ $podDiscoveryRoleName }}
namespace: {{ $discoveryNamespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ $podDiscoveryRoleName }}
namespace: {{ $discoveryNamespace }}
labels:
{{- include "bifrost.labels" . | nindent 4 }}
subjects:
- kind: ServiceAccount
name: {{ include "bifrost.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ $podDiscoveryRoleName }}
{{- end -}}
@@ -0,0 +1,88 @@
{{- 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
- name: REDISCLI_AUTH
valueFrom:
secretKeyRef:
name: {{ include "bifrost.fullname" . }}-redis
key: password
{{- end }}
{{- if .Values.vectorStore.redis.auth.enabled }}
command:
{{- if contains "redis-stack" .Values.vectorStore.redis.image.repository }}
- redis-stack-server
{{- else }}
- redis-server
{{- end }}
- --requirepass
- $(REDIS_PASSWORD)
{{- end }}
livenessProbe:
exec:
command:
- sh
- -c
- redis-cli ping
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command:
- sh
- -c
- redis-cli ping
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) (not .Values.postgresql.auth.existingSecret) }}
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,36 @@
{{- 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
{{- if .Values.bifrost.cluster.grpc }}
- port: {{ .Values.bifrost.cluster.grpc.port }}
targetPort: grpc
protocol: TCP
name: grpc
{{- end }}
{{- end }}
selector:
{{- include "bifrost.serverSelectorLabels" . | nindent 4 }}
{{- end }}
@@ -0,0 +1,36 @@
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
{{- if .Values.bifrost.cluster.grpc }}
- port: {{ .Values.bifrost.cluster.grpc.port }}
targetPort: grpc
protocol: TCP
name: grpc
{{- end }}
{{- 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,321 @@
{{- /* 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
{{- if .Values.bifrost.cluster.grpc }}
- name: grpc
containerPort: {{ .Values.bifrost.cluster.grpc.port }}
protocol: TCP
{{- end }}
{{- 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 }}
- 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" }}
{{- else if and .Values.postgresql.enabled (not .Values.postgresql.external.enabled) .Values.postgresql.auth.existingSecret }}
- name: BIFROST_POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.postgresql.auth.existingSecret }}
key: {{ .Values.postgresql.auth.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 }}
{{- /* Object storage credentials from existing secret */ -}}
{{- if and .Values.storage.logsStore.enabled .Values.storage.logsStore.objectStorage .Values.storage.logsStore.objectStorage.enabled .Values.storage.logsStore.objectStorage.existingSecret }}
{{- if eq .Values.storage.logsStore.objectStorage.type "s3" }}
- name: BIFROST_OBJECT_STORAGE_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: {{ .Values.storage.logsStore.objectStorage.existingSecret }}
key: {{ .Values.storage.logsStore.objectStorage.accessKeyIdKey | default "access-key-id" }}
optional: true
- name: BIFROST_OBJECT_STORAGE_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.storage.logsStore.objectStorage.existingSecret }}
key: {{ .Values.storage.logsStore.objectStorage.secretAccessKeyKey | default "secret-access-key" }}
optional: true
- name: BIFROST_OBJECT_STORAGE_SESSION_TOKEN
valueFrom:
secretKeyRef:
name: {{ .Values.storage.logsStore.objectStorage.existingSecret }}
key: {{ .Values.storage.logsStore.objectStorage.sessionTokenKey | default "session-token" }}
optional: true
- name: BIFROST_OBJECT_STORAGE_ROLE_ARN
valueFrom:
secretKeyRef:
name: {{ .Values.storage.logsStore.objectStorage.existingSecret }}
key: {{ .Values.storage.logsStore.objectStorage.roleArnKey | default "role-arn" }}
optional: true
{{- end }}
{{- if eq .Values.storage.logsStore.objectStorage.type "gcs" }}
- name: BIFROST_OBJECT_STORAGE_CREDENTIALS_JSON
valueFrom:
secretKeyRef:
name: {{ .Values.storage.logsStore.objectStorage.existingSecret }}
key: {{ .Values.storage.logsStore.objectStorage.credentialsJsonKey | default "credentials-json" }}
{{- end }}
{{- 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 }}
{{- /* MCP client connection strings from existing secrets (one per client with secretRef.name set) */ -}}
{{- if .Values.bifrost.mcp.enabled }}
{{- range $idx, $client := .Values.bifrost.mcp.clientConfigs }}
{{- if and $client.secretRef $client.secretRef.name }}
- name: BIFROST_MCP_{{ regexReplaceAll "[^A-Z0-9]+" (upper $client.name) "_" }}_CONNECTION_STRING
valueFrom:
secretKeyRef:
name: {{ $client.secretRef.name }}
key: {{ $client.secretRef.connectionStringKey | default "connection-string" }}
{{- end }}
{{- end }}
{{- 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 := (.Values.bifrost.providerSecrets | keys | sortAlpha) }}
{{- $secret := index $.Values.bifrost.providerSecrets $provider }}
{{- 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.extraEnv }}
{{- range $name := keys . | sortAlpha }}
- name: {{ $name }}
value: {{ index $.Values.extraEnv $name | quote }}
{{- end }}
{{- 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:
{{- /*
Keep volumeClaimTemplates labels immutable-safe.
Do not include bifrost.labels here because chart/app version labels
change between releases and StatefulSet volumeClaimTemplates are immutable.
*/}}
{{- include "bifrost.selectorLabels" . | nindent 10 }}
app.kubernetes.io/component: server
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,70 @@
{{- 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 := (.Values.vectorStore.weaviate.env | keys | sortAlpha) }}
{{- $value := index $.Values.vectorStore.weaviate.env $key }}
- 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) .Values.vectorStore.weaviate.persistence.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,35 @@
# 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,45 @@
# 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,74 @@
# 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,71 @@
# 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,144 @@
# 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,620 @@
# Configuration: Full Provider and Virtual Key Reference
# Usage: helm install bifrost ./bifrost -f values-examples/providers-and-virtual-keys.yaml
#
# This example demonstrates configuration for every Bifrost-supported provider
# (23 total) plus 7 virtual-key patterns covering different access-control needs:
# - Simple API-key providers (openai, anthropic, cohere, groq, gemini, ...)
# - Deployment-map providers (huggingface, replicate)
# - URL-based / self-hosted providers (ollama, sgl, vllm)
# - Cloud-native providers with nested config (azure, vertex, bedrock)
#
# Secrets are referenced via env.VAR_NAME (see ENVIRONMENT VARIABLES block
# below). Provide them via extraEnv (map), env, envFrom, or a Kubernetes Secret
# mounted on the pod — see values-examples/secrets-from-k8s.yaml for patterns.
#
# Field names follow transports/config.schema.json (the Bifrost runtime config
# contract). VK provider_configs use the helm-native keys:[{name:...}] form,
# which the helm chart template passes through to config.json.
# ==========================================================================
# ENVIRONMENT VARIABLES REFERENCED
# ==========================================================================
# This file uses env.VAR_NAME for all secret values. Supply them via extraEnv
# (map), env, envFrom, or an external secret store. Full list:
#
# Provider API keys:
# OPENAI_API_KEY_1, OPENAI_API_KEY_2, OPENAI_API_KEY_3
# ANTHROPIC_API_KEY_1, ANTHROPIC_API_KEY_2
# GROQ_API_KEY_1, GROQ_API_KEY_2
# COHERE_API_KEY, MISTRAL_API_KEY, GEMINI_API_KEY, OPENROUTER_API_KEY
# PARASAIL_API_KEY, PERPLEXITY_API_KEY, CEREBRAS_API_KEY
# ELEVENLABS_API_KEY, XAI_API_KEY, NEBIUS_API_KEY, FIREWORKS_API_KEY
# RUNWAY_API_KEY, HUGGINGFACE_API_KEY, REPLICATE_API_KEY
#
# Azure:
# AZURE_API_KEY, AZURE_ENDPOINT
#
# Vertex (Google Cloud):
# VERTEX_PROJECT_ID, VERTEX_AUTH_CREDENTIALS (service-account key JSON)
#
# Bedrock (AWS) — choose static creds OR STS AssumeRole:
# AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
# AWS_ROLE_ARN, AWS_EXTERNAL_ID
#
# Self-hosted endpoints:
# OLLAMA_URL, SGL_URL, VLLM_URL
# 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
maxRequestBodySizeMb: 100
# ==========================================================================
# PROVIDERS
# ==========================================================================
# Every key entry supports the base fields:
# name (required), value, weight (optional; defaults to 1), models, use_for_batch_api, aliases
# Providers with nested configs add *_key_config blocks
# (azure_key_config, vertex_key_config, bedrock_key_config, vllm_key_config,
# ollama_key_config, sgl_key_config, replicate_key_config).
providers:
# ------------------------------------------------------------------------
# Simple API-key providers (base_key shape)
# ------------------------------------------------------------------------
# OpenAI — 3 keys with weighted load balancing.
# openai-batch is flagged use_for_batch_api so it can serve the Batch API.
openai:
keys:
- name: "openai-primary"
value: "env.OPENAI_API_KEY_1"
weight: 2 # 50% of traffic (2 of 4 total weight)
models: ["*"]
- name: "openai-secondary"
value: "env.OPENAI_API_KEY_2"
weight: 1 # 25%
models: ["*"]
- name: "openai-batch"
value: "env.OPENAI_API_KEY_3"
weight: 1 # 25%
models: ["*"]
use_for_batch_api: true # Allow Batch API with this key
# Anthropic — 2 keys, equal weight
anthropic:
keys:
- name: "anthropic-primary"
value: "env.ANTHROPIC_API_KEY_1"
weight: 1
models: ["*"]
- name: "anthropic-secondary"
value: "env.ANTHROPIC_API_KEY_2"
weight: 1
models: ["*"]
# Groq — 2 keys
groq:
keys:
- name: "groq-primary"
value: "env.GROQ_API_KEY_1"
weight: 1
models: ["*"]
- name: "groq-secondary"
value: "env.GROQ_API_KEY_2"
weight: 1
models: ["*"]
cohere:
keys:
- name: "cohere-main"
value: "env.COHERE_API_KEY"
weight: 1
models: ["*"]
mistral:
keys:
- name: "mistral-main"
value: "env.MISTRAL_API_KEY"
weight: 1
models: ["*"]
gemini:
keys:
- name: "gemini-main"
value: "env.GEMINI_API_KEY"
weight: 1
models: ["*"]
openrouter:
keys:
- name: "openrouter-main"
value: "env.OPENROUTER_API_KEY"
weight: 1
models: ["*"]
parasail:
keys:
- name: "parasail-main"
value: "env.PARASAIL_API_KEY"
weight: 1
models: ["*"]
perplexity:
keys:
- name: "perplexity-main"
value: "env.PERPLEXITY_API_KEY"
weight: 1
models: ["*"]
cerebras:
keys:
- name: "cerebras-main"
value: "env.CEREBRAS_API_KEY"
weight: 1
models: ["*"]
elevenlabs:
keys:
- name: "elevenlabs-main"
value: "env.ELEVENLABS_API_KEY"
weight: 1
models: ["*"]
xai:
keys:
- name: "xai-main"
value: "env.XAI_API_KEY"
weight: 1
models: ["*"]
nebius:
keys:
- name: "nebius-main"
value: "env.NEBIUS_API_KEY"
weight: 1
models: ["*"]
fireworks:
keys:
- name: "fireworks-main"
value: "env.FIREWORKS_API_KEY"
weight: 1
models: ["*"]
runway:
keys:
- name: "runway-main"
value: "env.RUNWAY_API_KEY"
weight: 1
models: ["*"]
# ------------------------------------------------------------------------
# Deployment-map providers (use `aliases` to map logical -> provider IDs)
# ------------------------------------------------------------------------
huggingface:
keys:
- name: "huggingface-main"
value: "env.HUGGINGFACE_API_KEY"
weight: 1
models: ["llama-3", "mixtral"]
aliases:
# Logical model name -> HF repo path used when invoking
llama-3: "meta-llama/Meta-Llama-3-8B-Instruct"
mixtral: "mistralai/Mixtral-8x7B-Instruct-v0.1"
replicate:
keys:
- name: "replicate-main"
value: "env.REPLICATE_API_KEY"
weight: 1
models: ["llama-3"]
aliases:
llama-3: "meta/meta-llama-3-70b-instruct"
replicate_key_config:
use_deployments_endpoint: false # false = /models endpoint (default)
# ------------------------------------------------------------------------
# URL-based / self-hosted providers
# ------------------------------------------------------------------------
# These providers talk to an HTTP endpoint you operate yourself. They do
# not typically require API keys (value stays empty).
ollama:
keys:
- name: "ollama-main"
value: ""
weight: 1
models: ["*"]
ollama_key_config:
url: "env.OLLAMA_URL" # e.g. http://ollama.svc.cluster.local:11434
sgl:
keys:
- name: "sgl-main"
value: ""
weight: 1
models: ["*"]
sgl_key_config:
url: "env.SGL_URL" # e.g. http://sgl-router.svc.cluster.local:30000
vllm:
# vLLM instances are model-specific: one key per served model.
keys:
- name: "vllm-llama3-70b"
value: ""
weight: 1
models: ["llama-3-70b"]
vllm_key_config:
url: "env.VLLM_URL" # e.g. http://vllm.svc.cluster.local:8000
model_name: "meta-llama/Meta-Llama-3-70B-Instruct"
# ------------------------------------------------------------------------
# Cloud-native providers (nested provider-specific config)
# ------------------------------------------------------------------------
# Azure OpenAI — two auth modes:
# 1. azure-apikey: explicit API key (via env var).
# 2. azure-managed-identity: inherits credentials via DefaultAzureCredential
# when `value` is empty. Covers managed identity
# on Azure VMs / AKS workload identity / env vars
# (AZURE_CLIENT_ID etc.) / Azure CLI (dev).
# (Service-principal client_id/client_secret/tenant_id fields exist in the
# runtime code but aren't exposed in the current schema — use env-based
# DefaultAzureCredential instead.)
azure:
keys:
- name: "azure-apikey"
value: "env.AZURE_API_KEY"
weight: 1
models: ["gpt-4o", "gpt-4o-mini", "text-embedding-3-small"]
azure_key_config:
endpoint: "env.AZURE_ENDPOINT" # e.g. https://my-resource.openai.azure.com
api_version: "2024-10-21"
deployments:
# Logical model name -> Azure deployment name
gpt-4o: "gpt-4o-prod"
gpt-4o-mini: "gpt-4o-mini-prod"
text-embedding-3-small: "embeddings-prod"
- name: "azure-managed-identity"
# Pure identity inheritance: empty `value` triggers DefaultAzureCredential.
# Works out-of-the-box on AKS with workload identity, Azure VMs with
# system/user-assigned managed identity, or local dev via `az login`.
value: ""
weight: 1
models: ["gpt-4o"]
azure_key_config:
endpoint: "env.AZURE_ENDPOINT"
api_version: "2024-10-21"
deployments:
gpt-4o: "gpt-4o-prod"
# Google Vertex AI — two auth modes:
# 1. vertex-sa-key: explicit service-account key JSON via env var.
# 2. vertex-workload-id: inherits credentials from the environment
# (GKE Workload Identity, GCE metadata server,
# or GOOGLE_APPLICATION_CREDENTIALS path). Omit
# `auth_credentials` and the Google SDK calls
# google.FindDefaultCredentials automatically.
vertex:
keys:
- name: "vertex-sa-key"
value: ""
weight: 1
models: ["*"]
vertex_key_config:
project_id: "env.VERTEX_PROJECT_ID"
region: "us-central1"
auth_credentials: "env.VERTEX_AUTH_CREDENTIALS"
# project_number: "env.VERTEX_PROJECT_NUMBER" # optional
- name: "vertex-workload-id"
# Pure ADC inheritance: works on GKE with Workload Identity, GCE
# VMs, Cloud Run, or local dev via `gcloud auth application-default login`.
value: ""
weight: 1
models: ["*"]
vertex_key_config:
project_id: "env.VERTEX_PROJECT_ID"
region: "us-central1"
# auth_credentials intentionally omitted -> ADC lookup
# AWS Bedrock — three auth modes:
# 1. bedrock-static: explicit AWS access/secret keys + S3 batch bucket
# 2. bedrock-irsa: inherits pod/EKS credentials (IRSA, EC2 instance
# profile, env vars, ~/.aws/credentials) — set only
# `region`; the AWS SDK default credential chain
# resolves the rest.
# 3. bedrock-assumerole: STS AssumeRole chained on top of the default
# chain — inherits *source* creds from the pod,
# then assumes a cross-account role.
bedrock:
keys:
- name: "bedrock-static"
value: ""
weight: 1
models: ["*"]
bedrock_key_config:
region: "us-east-1"
access_key: "env.AWS_ACCESS_KEY_ID"
secret_key: "env.AWS_SECRET_ACCESS_KEY"
deployments:
# Logical model -> Bedrock inference profile
anthropic.claude-3-5-sonnet: "us.anthropic.claude-3-5-sonnet-20240620-v1:0"
batch_s3_config:
buckets:
- bucket_name: "my-bedrock-batch-bucket"
prefix: "batch/"
is_default: true
- name: "bedrock-irsa"
# Pure credential inheritance: works out-of-the-box on EKS with IRSA,
# on EC2 with an instance profile, or with AWS_* env vars present.
value: ""
weight: 1
models: ["*"]
bedrock_key_config:
region: "us-east-1"
# access_key / secret_key intentionally omitted -> SDK default chain
- name: "bedrock-assumerole"
value: ""
weight: 1
models: ["*"]
bedrock_key_config:
region: "us-west-2"
# No static creds -> source identity comes from pod's default chain.
role_arn: "env.AWS_ROLE_ARN"
external_id: "env.AWS_EXTERNAL_ID"
session_name: "bifrost-session"
# ==========================================================================
# GOVERNANCE — budgets, rate limits, and virtual keys
# ==========================================================================
governance:
# --------------------------------------------------------------------
# Budgets — spending caps per period
# --------------------------------------------------------------------
budgets:
- id: "budget-dev"
max_limit: 50 # $50
reset_duration: "1M" # monthly
- id: "budget-production"
max_limit: 500 # $500
reset_duration: "1M"
- id: "budget-testing"
max_limit: 10 # $10
reset_duration: "1d" # daily
- id: "budget-team-platform"
max_limit: 2000 # $2000 — larger team/platform budget
reset_duration: "1M"
# --------------------------------------------------------------------
# Rate limits — token + request caps 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"
- id: "rate-limit-burst"
token_max_limit: 50000
token_reset_duration: "1m" # Short-window burst cap
request_max_limit: 500
request_reset_duration: "1m"
# --------------------------------------------------------------------
# Virtual keys — access tokens scoped to providers/models/keys
# --------------------------------------------------------------------
# provider_configs[].keys scopes the VK to specific provider keys by name.
# Omit provider_configs to grant access to every provider.
# Omit keys inside a provider_config to allow all keys for that provider.
virtualKeys:
# 1. Dev key — access to every provider, no restrictions.
- id: "vk-all-providers-dev"
name: "Dev: all providers"
is_active: true
budget_id: "budget-dev"
rate_limit_id: "rate-limit-standard"
# No provider_configs -> all providers accessible
# 2. OpenAI only — restricted to 2 keys and 2 models.
- id: "vk-openai-scoped"
name: "OpenAI only (scoped)"
is_active: true
budget_id: "budget-production"
rate_limit_id: "rate-limit-high"
provider_configs:
- provider: "openai"
weight: 1
allowed_models: ["gpt-4o", "gpt-4o-mini"]
keys:
- name: "openai-primary"
- name: "openai-secondary"
# 3. Multi-provider — weighted routing across OpenAI/Anthropic/Groq.
# OpenAI gets 50% (weight 2), the others 25% each (weight 1).
- id: "vk-multi-provider"
name: "Multi-provider weighted"
is_active: true
budget_id: "budget-production"
rate_limit_id: "rate-limit-high"
provider_configs:
- provider: "openai"
weight: 2
allowed_models: ["*"]
# Omitting keys -> all openai keys allowed
- provider: "anthropic"
weight: 1
allowed_models: ["*"]
keys:
- name: "anthropic-primary"
- provider: "groq"
weight: 1
allowed_models: ["*"]
# 4. Cloud providers — Azure + Vertex + Bedrock only.
# Shows that VK scoping is identical regardless of nested key_config.
- id: "vk-cloud-providers"
name: "Cloud providers (Azure/Vertex/Bedrock)"
is_active: true
budget_id: "budget-team-platform"
rate_limit_id: "rate-limit-high"
provider_configs:
- provider: "azure"
weight: 1
keys:
- name: "azure-apikey"
- name: "azure-managed-identity"
- provider: "vertex"
weight: 1
keys:
- name: "vertex-sa-key"
- name: "vertex-workload-id"
- provider: "bedrock"
weight: 1
keys:
- name: "bedrock-static"
- name: "bedrock-irsa"
- name: "bedrock-assumerole"
# 5. Self-hosted — Ollama + vLLM + SGL only.
# Low budget because self-hosted inference is ~free.
- id: "vk-self-hosted"
name: "Self-hosted (Ollama/vLLM/SGL)"
is_active: true
budget_id: "budget-dev"
rate_limit_id: "rate-limit-high"
provider_configs:
- provider: "ollama"
weight: 1
- provider: "vllm"
weight: 1
- provider: "sgl"
weight: 1
# 6. Testing — tight budget, tight rate limit, single model, single key.
- id: "vk-testing-limited"
name: "Testing (gpt-4o-mini only)"
is_active: true
budget_id: "budget-testing"
rate_limit_id: "rate-limit-testing"
provider_configs:
- provider: "openai"
weight: 1
allowed_models: ["gpt-4o-mini"]
keys:
- name: "openai-secondary"
# 7. Batch API — restricted to keys flagged use_for_batch_api: true.
# Pairs with the openai-batch key above. Burst rate-limit for batch flushes.
- id: "vk-batch-api"
name: "Batch API workloads"
is_active: true
budget_id: "budget-production"
rate_limit_id: "rate-limit-burst"
provider_configs:
- provider: "openai"
weight: 1
allowed_models: ["*"]
keys:
- name: "openai-batch"
# 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,109 @@
# 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:
- name: "openai-primary"
value: "env.OPENAI_API_KEY"
weight: 1
models: ["*"]
anthropic:
keys:
- name: "anthropic-primary"
value: "env.ANTHROPIC_API_KEY"
weight: 1
models: ["*"]
# 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,27 @@
# 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,33 @@
# 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,75 @@
# 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,59 @@
# 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
File diff suppressed because it is too large Load Diff