Skip to main content

Cloud Provider Deployment

Deploy Dvara on AWS, Google Cloud, or Azure with provider-specific configurations and best practices.

This guide assumes you have completed the Kubernetes / Helm setup and are familiar with the Helm chart configuration.


AWS (EKS)

Prerequisites

  • eksctl or an existing EKS cluster (Kubernetes 1.28+)
  • AWS CLI configured with appropriate permissions
  • Helm 3.x installed

Create an EKS Cluster

eksctl create cluster \
--name dvara \
--region us-east-1 \
--nodegroup-name standard \
--node-type m6i.large \
--nodes 3 \
--nodes-min 2 \
--nodes-max 5 \
--managed

Install the AWS Load Balancer Controller

Required for ALB-based Ingress:

# Install the controller (see AWS docs for full IAM setup)
helm repo add eks https://aws.github.io/eks-charts
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=dvara \
--set serviceAccount.create=true

Store Secrets in AWS Secrets Manager

# Create the secret
aws secretsmanager create-secret \
--name dvara/provider-credentials \
--secret-string '{
"openai-api-key": "sk-...",
"anthropic-api-key": "sk-ant-...",
"enterprise-license-key": "eyJhbGci..."
}'

Use the External Secrets Operator to sync into Kubernetes:

# external-secret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: dvara-provider-keys
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: dvara-external
data:
- secretKey: openai-api-key
remoteRef:
key: dvara/provider-credentials
property: openai-api-key
- secretKey: anthropic-api-key
remoteRef:
key: dvara/provider-credentials
property: anthropic-api-key
- secretKey: enterprise-license-key
remoteRef:
key: dvara/provider-credentials
property: enterprise-license-key
kubectl apply -f external-secret.yaml

Deploy with ALB Ingress + IRSA

# aws-values.yaml
gatewayServer:
replicaCount: 3
javaOpts: "-Xms512m -Xmx768m"

serviceAccount:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/dvara-gateway

autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70

pdb:
enabled: true
minAvailable: 2

serviceMonitor:
enabled: true
additionalLabels:
release: kube-prometheus-stack

topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/component: gateway-server

gatewayUi:
enabled: true

secrets:
create: false
existingSecret: dvara-external

ingress:
enabled: true
className: alb
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-1:123456789012:certificate/abc-123
alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06
alb.ingress.kubernetes.io/healthcheck-path: /actuator/health/readiness
gatewayServer:
hosts:
- host: gateway.mycompany.com
paths:
- path: /
pathType: Prefix
gatewayUi:
hosts:
- host: admin.mycompany.com
paths:
- path: /
pathType: Prefix
helm install dvara charts/dvara/ -f aws-values.yaml

AWS Bedrock with IRSA (No API Keys)

Use IAM Roles for Service Accounts to access Bedrock without static credentials:

# Create the IAM policy
cat > bedrock-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": "arn:aws:bedrock:*:*:model/*"
}]
}
EOF

aws iam create-policy \
--policy-name DvaraBedrockAccess \
--policy-document file://bedrock-policy.json

# Associate with the service account
eksctl create iamserviceaccount \
--name dvara-server \
--namespace default \
--cluster dvara \
--attach-policy-arn arn:aws:iam::123456789012:policy/DvaraBedrockAccess \
--approve
# bedrock-values.yaml
gatewayServer:
serviceAccount:
create: false
name: dvara-server

secrets:
bedrockEnabled: "true"
helm install dvara charts/dvara/ -f bedrock-values.yaml

Database and Cache for Enterprise Persistence

Enterprise deployments can use PostgreSQL and Redis for durable storage instead of in-memory defaults.

RDS PostgreSQL:

aws rds create-db-instance \
--db-instance-identifier dvara-db \
--db-instance-class db.r6g.large \
--engine postgres --engine-version 14 \
--master-username dvara --master-user-password "${DB_PASSWORD}" \
--allocated-storage 100 --storage-encrypted \
--vpc-security-group-ids sg-... --db-subnet-group-name dvara-subnet

ElastiCache Redis:

aws elasticache create-replication-group \
--replication-group-id dvara-redis \
--replication-group-description "Dvara rate-limit and cache" \
--engine redis --engine-version 7.0 \
--cache-node-type cache.r6g.large \
--num-cache-clusters 2 --automatic-failover-enabled \
--transit-encryption-enabled --auth-token "${REDIS_PASSWORD}"

Helm values for database and cache:

gatewayServer:
env:
- name: SPRING_DATASOURCE_URL
value: "jdbc:postgresql://dvara-db.xxx.us-east-1.rds.amazonaws.com:5432/dvara"
- name: SPRING_DATASOURCE_USERNAME
value: "dvara"
- name: SPRING_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
name: dvara-db-credentials
key: password
- name: SPRING_DATA_REDIS_HOST
value: "dvara-redis.xxx.use1.cache.amazonaws.com"
- name: SPRING_DATA_REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: dvara-redis-credentials
key: password
- name: SPRING_DATA_REDIS_SSL_ENABLED
value: "true"

Multi-Region on AWS

Primary region (us-east-1):

# primary-values.yaml
gatewayServer:
replicaCount: 3
gatewayMode: full
region:
id: us-east-1
name: US East
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10

gatewayUi:
enabled: true

secrets:
providerKeys:
openai: sk-...
gatewayInternalSecret: "shared-internal-secret-change-me"
enterpriseLicenseKey: "eyJhbGci..."

Secondary region (eu-west-1) — syncs config from the primary:

# secondary-eu-values.yaml
gatewayServer:
replicaCount: 2
gatewayMode: full
region:
id: eu-west-1
name: EU West
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
env:
- name: GATEWAY_CONFIG_SYNC_ENABLED
value: "true"
- name: GATEWAY_CONFIG_SYNC_CONTROL_PLANE_URL
value: "http://dvara-server.us-east-1.internal:8080"
- name: GATEWAY_CONFIG_SYNC_INTERNAL_SECRET
value: "shared-internal-secret-change-me"

gatewayUi:
enabled: false

secrets:
providerKeys:
openai: sk-...
enterpriseLicenseKey: "eyJhbGci..."
# Deploy primary in us-east-1
kubectl config use-context us-east-1
helm install dvara charts/dvara/ -f primary-values.yaml

# Deploy secondary in eu-west-1
kubectl config use-context eu-west-1
helm install dvara-eu charts/dvara/ -f secondary-eu-values.yaml

Google Cloud (GKE)

Prerequisites

  • gcloud CLI configured
  • An existing GKE cluster or permissions to create one
  • Helm 3.x installed

Create a GKE Cluster

gcloud container clusters create dvara \
--region us-central1 \
--num-nodes 3 \
--machine-type e2-standard-4 \
--enable-autoscaling --min-nodes 2 --max-nodes 6 \
--workload-pool=my-project.svc.id.goog

gcloud container clusters get-credentials dvara --region us-central1

Store Secrets in Google Secret Manager

# Create secrets
echo -n "sk-..." | gcloud secrets create dvara-openai-key --data-file=-
echo -n "sk-ant-..." | gcloud secrets create dvara-anthropic-key --data-file=-
echo -n "eyJhbGci..." | gcloud secrets create dvara-license-key --data-file=-

Sync with External Secrets Operator:

# gcp-external-secret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: dvara-provider-keys
spec:
refreshInterval: 1h
secretStoreRef:
name: gcp-secret-manager
kind: ClusterSecretStore
target:
name: dvara-external
data:
- secretKey: openai-api-key
remoteRef:
key: dvara-openai-key
- secretKey: anthropic-api-key
remoteRef:
key: dvara-anthropic-key
- secretKey: enterprise-license-key
remoteRef:
key: dvara-license-key

Deploy with GCE Ingress + Gemini

# gcp-values.yaml
gatewayServer:
replicaCount: 3
javaOpts: "-Xms512m -Xmx768m"

serviceAccount:
annotations:
iam.gke.io/gcp-service-account: dvara@my-project.iam.gserviceaccount.com

autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10

pdb:
enabled: true
minAvailable: 2

serviceMonitor:
enabled: true

topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/component: gateway-server

gatewayUi:
enabled: true

secrets:
create: false
existingSecret: dvara-external

ingress:
enabled: true
className: gce
annotations:
kubernetes.io/ingress.global-static-ip-name: dvara-ip
networking.gke.io/managed-certificates: dvara-cert
gatewayServer:
hosts:
- host: gateway.mycompany.com
paths:
- path: /
pathType: Prefix
gatewayUi:
hosts:
- host: admin.mycompany.com
paths:
- path: /
pathType: Prefix

For Google Managed Certificates:

# managed-cert.yaml
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
name: dvara-cert
spec:
domains:
- gateway.mycompany.com
- admin.mycompany.com
kubectl apply -f managed-cert.yaml
helm install dvara charts/dvara/ -f gcp-values.yaml

Database and Cache for Enterprise Persistence

Cloud SQL PostgreSQL:

gcloud sql instances create dvara-db \
--database-version=POSTGRES_14 --tier=db-custom-2-8192 \
--region=us-central1 --storage-size=100GB --storage-auto-increase \
--require-ssl --availability-type=REGIONAL

gcloud sql databases create dvara --instance=dvara-db
gcloud sql users create dvara --instance=dvara-db --password="${DB_PASSWORD}"

Memorystore Redis:

gcloud redis instances create dvara-redis \
--size=5 --region=us-central1 --redis-version=redis_7_0 \
--tier=STANDARD_HA --transit-encryption-mode=SERVER_AUTHENTICATION

Helm values: use the same SPRING_DATASOURCE_* and SPRING_DATA_REDIS_* environment variables shown in the AWS section, substituting Cloud SQL and Memorystore endpoints.

Gemini Provider Setup

# With Gemini API key
secrets:
providerKeys:
gemini: AIzaSy...

# Or via Workload Identity (for Vertex AI)
gatewayServer:
serviceAccount:
annotations:
iam.gke.io/gcp-service-account: dvara@my-project.iam.gserviceaccount.com

Grant the service account access to Vertex AI:

gcloud projects add-iam-policy-binding my-project \
--member="serviceAccount:dvara@my-project.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"

Azure (AKS)

Prerequisites

  • Azure CLI configured
  • An existing AKS cluster or permissions to create one
  • Helm 3.x installed

Create an AKS Cluster

az group create --name dvara-rg --location eastus

az aks create \
--resource-group dvara-rg \
--name dvara \
--node-count 3 \
--node-vm-size Standard_D4s_v3 \
--enable-cluster-autoscaler \
--min-count 2 \
--max-count 6 \
--enable-managed-identity \
--enable-workload-identity \
--enable-oidc-issuer

az aks get-credentials --resource-group dvara-rg --name dvara

Store Secrets in Azure Key Vault

# Create key vault
az keyvault create --name dvara-vault --resource-group dvara-rg --location eastus

# Store secrets
az keyvault secret set --vault-name dvara-vault --name openai-api-key --value "sk-..."
az keyvault secret set --vault-name dvara-vault --name anthropic-api-key --value "sk-ant-..."
az keyvault secret set --vault-name dvara-vault --name enterprise-license-key --value "eyJhbGci..."

Use the Azure Key Vault Provider for Secrets Store CSI Driver:

# secret-provider-class.yaml
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: dvara-keyvault
spec:
provider: azure
parameters:
usePodIdentity: "false"
useVMManagedIdentity: "true"
userAssignedIdentityID: "<managed-identity-client-id>"
keyvaultName: dvara-vault
tenantId: "<azure-tenant-id>"
objects: |
array:
- |
objectName: openai-api-key
objectType: secret
- |
objectName: anthropic-api-key
objectType: secret
- |
objectName: enterprise-license-key
objectType: secret
secretObjects:
- secretName: dvara-external
type: Opaque
data:
- objectName: openai-api-key
key: openai-api-key
- objectName: anthropic-api-key
key: anthropic-api-key
- objectName: enterprise-license-key
key: enterprise-license-key
kubectl apply -f secret-provider-class.yaml

Deploy with NGINX Ingress Controller

# Install NGINX Ingress Controller
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz
# azure-values.yaml
gatewayServer:
replicaCount: 3
javaOpts: "-Xms512m -Xmx768m"

autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10

pdb:
enabled: true
minAvailable: 2

serviceMonitor:
enabled: true

topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/component: gateway-server

gatewayUi:
enabled: true

secrets:
create: false
existingSecret: dvara-external

ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
gatewayServer:
hosts:
- host: gateway.mycompany.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: gateway-tls
hosts:
- gateway.mycompany.com
gatewayUi:
hosts:
- host: admin.mycompany.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: admin-tls
hosts:
- admin.mycompany.com
helm install dvara charts/dvara/ -f azure-values.yaml

Database and Cache for Enterprise Persistence

Azure Database for PostgreSQL:

az postgres flexible-server create \
--resource-group dvara-rg --name dvara-db \
--version 14 --sku-name Standard_D2s_v3 --storage-size 128 \
--admin-user dvara --admin-password "${DB_PASSWORD}" \
--tier GeneralPurpose --high-availability ZoneRedundant

Azure Cache for Redis:

az redis create \
--resource-group dvara-rg --name dvara-redis \
--sku Premium --vm-size P1 --minimum-tls-version 1.2 \
--enable-non-ssl-port false

Helm values: use the same SPRING_DATASOURCE_* and SPRING_DATA_REDIS_* environment variables shown in the AWS section, substituting Azure Database for PostgreSQL and Azure Cache for Redis endpoints.

Azure OpenAI Service

To use Azure OpenAI instead of the public OpenAI API, override the base URL:

# azure-openai-values.yaml
gatewayServer:
env:
- name: OPENAI_BASE_URL
value: "https://my-resource.openai.azure.com/openai/deployments/gpt-4o"

secrets:
providerKeys:
openai: "<azure-openai-api-key>"

Monitoring Stack

All cloud providers can use the same monitoring setup. Install the kube-prometheus-stack for Prometheus + Grafana:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring --create-namespace \
--set grafana.adminPassword=admin

Enable ServiceMonitor in Dvara:

gatewayServer:
serviceMonitor:
enabled: true
interval: 15s
additionalLabels:
release: monitoring

mcpProxyServer:
serviceMonitor:
enabled: true
interval: 15s
additionalLabels:
release: monitoring

Import the included Grafana dashboard from grafana/dashboards/ for pre-built panels covering request rates, latencies, token usage, provider health, cost metrics, and agent session stats.

Key Prometheus Metrics to Alert On

# Example alerting rules
groups:
- name: dvara
rules:
- alert: HighErrorRate
expr: rate(gateway_requests_total{status=~"5.."}[5m]) / rate(gateway_requests_total[5m]) > 0.05
for: 5m
labels:
severity: critical
- alert: HighLatency
expr: histogram_quantile(0.95, rate(gateway_latency_seconds_bucket[5m])) > 5
for: 5m
labels:
severity: warning
- alert: BudgetCapBreached
expr: increase(gateway_budget_blocked_total[1h]) > 0
labels:
severity: warning

Enterprise Features on Cloud

Vault Integration

Dvara supports HashiCorp Vault, AWS Secrets Manager, and Azure Key Vault as credential backends for LLM provider keys. This is separate from Kubernetes secret management — it provides runtime credential resolution for the gateway itself.

HashiCorp Vault (any cloud):

gatewayServer:
env:
- name: GATEWAY_VAULT_BACKEND
value: hashicorp
- name: VAULT_ADDR
value: "https://vault.internal:8200"
- name: VAULT_AUTH_METHOD
value: approle
- name: VAULT_ROLE_ID
valueFrom:
secretKeyRef:
name: vault-credentials
key: role-id
- name: VAULT_SECRET_ID
valueFrom:
secretKeyRef:
name: vault-credentials
key: secret-id

AWS Secrets Manager:

gatewayServer:
env:
- name: GATEWAY_VAULT_BACKEND
value: aws-secrets-manager
- name: AWS_VAULT_REGION
value: us-east-1
- name: AWS_SECRET_NAME
value: dvara/provider-credentials
serviceAccount:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/dvara-secrets

Azure Key Vault:

gatewayServer:
env:
- name: GATEWAY_VAULT_BACKEND
value: azure-key-vault
- name: AZURE_VAULT_URL
value: "https://dvara-vault.vault.azure.net"
- name: AZURE_CLIENT_ID
value: "<managed-identity-client-id>"

OIDC / SSO Setup

Enable OIDC-based authentication for the admin API:

gatewayServer:
env:
- name: GATEWAY_SECURITY_ENABLED
value: "true"
- name: GATEWAY_OIDC_ISSUER_URI
value: "https://login.microsoftonline.com/<tenant-id>/v2.0" # Azure AD
# value: "https://accounts.google.com" # Google
# value: "https://cognito-idp.us-east-1.amazonaws.com/<pool>" # AWS Cognito
- name: GATEWAY_OIDC_AUDIENCE
value: "dvara-gateway"
- name: GATEWAY_OIDC_ROLE_CLAIM
value: "roles" # or "realm_access.roles" for Keycloak

Database and Cache Requirements

PostgreSQL and Redis are optional -- standalone and OSS-only deployments use in-memory defaults with no external dependencies. Enterprise deployments that enable persistent audit trails, rate limiting, or semantic caching should provision both.

DependencyMinimum VersionPurpose
PostgreSQL14+Audit events, policies, cost records, token usage, tenants, API keys
Redis6+Rate limiting (Bucket4j), semantic cache, session tracking

Flyway migrations run automatically on first startup when a datasource is configured. No manual schema setup is required. Subsequent application upgrades apply incremental migrations without data loss.

Connection pool defaults: HikariCP with maximumPoolSize=10. For high-throughput deployments, increase via SPRING_DATASOURCE_HIKARI_MAXIMUM_POOL_SIZE.


Quick Reference: Cloud-Specific Values

SettingAWSGCPAzure
Ingress classalbgcenginx
TLS terminationACM certificate ARN annotationGKE ManagedCertificatecert-manager + Let's Encrypt
Service account identityIRSA (eks.amazonaws.com/role-arn)Workload Identity (iam.gke.io/gcp-service-account)Managed Identity
Secret managementSecrets Manager + External SecretsSecret Manager + External SecretsKey Vault + CSI Driver
Node type (recommended)m6i.large (2 vCPU, 8 GB)e2-standard-4 (4 vCPU, 16 GB)Standard_D4s_v3 (4 vCPU, 16 GB)
AutoscalerCluster Autoscaler or KarpenterGKE Autopilot or Cluster AutoscalerAKS Cluster Autoscaler
Managed PostgreSQLRDS for PostgreSQLCloud SQL for PostgreSQLAzure Database for PostgreSQL
Managed RedisElastiCache for RedisMemorystore for RedisAzure Cache for Redis

Production Checklist

Before going to production on any cloud provider:

  • Enable HPA with appropriate min/max replicas
  • Enable PDB with minAvailable >= 2
  • Configure topology spread constraints for cross-zone scheduling
  • Use external secret management (not Helm --set for API keys)
  • Enable Ingress with TLS termination
  • Enable ServiceMonitor for Prometheus scraping
  • Set JVM options: -Xms512m -Xmx768m (adjust for workload)
  • Configure terminationGracePeriodSeconds: 45 and preStopSleepSeconds: 5
  • Set maxSurge: 1 and maxUnavailable: 0 for zero-downtime deploys
  • Provision PostgreSQL 14+ and Redis 6+ for enterprise persistence (optional for standalone mode)
  • Enable enterprise license key for governance features
  • Set up alerting on error rate, latency, and budget metrics
  • Configure OIDC/SSO for admin API access (enterprise)
  • Enable audit HMAC signing with a production secret
  • Review and set budget caps for cost governance