Deployment Patterns

Geode offers flexible deployment patterns to match your infrastructure requirements, from single-node development environments to distributed production clusters with full observability stacks.

Overview

Geode supports multiple deployment architectures:

  • Single-Node Deployment - Simple setup for development, testing, or low-traffic production
  • Distributed Deployment - Multi-node clusters with sharding and federation for high availability
  • Cloud Deployment - Container orchestration with Kubernetes or Docker Swarm
  • GPU-Capable Deployment - CUDA/Vulkan-enabled container image for the experimental GPU compute subsystem
  • Infrastructure Stack - Complete observability with monitoring, logging, and backup systems

This guide covers production-ready deployment patterns with best practices for security, performance, and reliability.

Quick Start

Prerequisites

System Requirements:

  • Docker 20.10+ and Docker Compose 1.29+
  • 8GB RAM minimum (16GB recommended for production)
  • 50GB disk space for data and backups
  • NVIDIA GPU with drivers + nvidia-docker2 (GPU deployment only)

Network Requirements:

  • Port 3141 (standard) or 8443 (alternative) for Geode QUIC+TLS
  • Firewall rules configured for inter-node communication (distributed)
  • Valid TLS certificates (self-signed for development, CA-signed for production)

Basic Setup

# Clone repository and setup deployment
git clone https://github.com/codeprosorg/geode
cd geode/deployment

# Run setup script (generates certificates, passwords, .env)
./scripts/setup-deployment.sh

# Review and customize environment variables
vi .env

# Add local DNS entries (development only)
echo "127.0.0.1 geode.local grafana.geode.local prometheus.geode.local minio.geode.local vault.geode.local" | sudo tee -a /etc/hosts

Start Services

Standard Deployment:

# Start full stack (Geode + infrastructure)
docker-compose up -d

# Verify all services running
docker-compose ps

# Check Geode logs
docker-compose logs -f geode

GPU-Capable Deployment (experimental — see GPU-Capable Deployment for what is and is not accelerated today):

# Install NVIDIA Container Toolkit
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
  sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo apt-get update
sudo apt-get install -y nvidia-docker2
sudo systemctl restart docker

# Verify GPU availability
docker run --rm --gpus all nvidia/cuda:12.3.0-base-ubuntu22.04 nvidia-smi

# Start GPU stack
docker-compose -f docker-compose.yml -f docker-compose.gpu.yml up -d

Verify Installation

# Test Geode connectivity
docker-compose exec geode geode query "RETURN 1 AS health" --server 127.0.0.1:8443

# Access web interfaces
# Grafana: https://grafana.geode.local (admin / check .env)
# Prometheus: https://prometheus.geode.local
# MinIO Console: https://minio.geode.local
# Vault UI: https://vault.geode.local

Single-Node Deployment

Architecture

Single-node deployment runs Geode with a complete infrastructure stack on one machine:

┌──────────────────────────────────────────────────────┐
│                  Host Machine                        │
│                                                      │
│  ┌──────────────┐  ┌──────────────┐  ┌────────────┐ │
│  │   Geode      │  │    Vault     │  │   Redis    │ │
│  │ Graph DB     │  │  Secrets     │  │   Cache    │ │
│  │ (port 8443)  │  │ Management   │  │            │ │
│  └──────┬───────┘  └──────────────┘  └────────────┘ │
│         │                                            │
│  ┌──────▼──────────────────────────────────────────┐ │
│  │              Nginx Reverse Proxy                │ │
│  │         (TLS termination, routing)              │ │
│  └──────┬──────────────────────────────────────────┘ │
│         │                                            │
│  ┌──────▼───────┐  ┌──────────────┐  ┌────────────┐ │
│  │ Prometheus   │  │   Grafana    │  │   MinIO    │ │
│  │  Metrics     │  │ Dashboards   │  │  Backups   │ │
│  └──────────────┘  └──────────────┘  └────────────┘ │
│                                                      │
│  ┌──────────────┐  ┌──────────────┐                 │
│  │    Loki      │  │   Promtail   │                 │
│  │ Log Storage  │  │ Log Collect  │                 │
│  └──────────────┘  └──────────────┘                 │
└──────────────────────────────────────────────────────┘

Configuration

Environment Variables (.env file):

# Geode Configuration
GEODE_LOG_LEVEL=info                # Log level: debug, info, warn, error
GEODE_DATA_DIR=/data                # Data directory path
GEODE_LISTEN_ADDR=0.0.0.0:8443      # Listen address
GEODE_MAX_CONNECTIONS=1000          # Maximum concurrent connections
GEODE_QUERY_TIMEOUT=30s             # Query execution timeout

# Security
VAULT_ADDR=http://vault:8200
VAULT_TOKEN=<generated-secure-token>
REDIS_PASSWORD=<generated-secure-password>

# Storage & Backup
S3_ENDPOINT=http://minio:9000
S3_ACCESS_KEY=geode-minio-admin
S3_SECRET_KEY=<generated-secure-password>
S3_BUCKET=geode-backups
S3_REGION=us-east-1

# Monitoring
GF_SECURITY_ADMIN_USER=admin
GF_SECURITY_ADMIN_PASSWORD=<generated-secure-password>
GF_SERVER_DOMAIN=grafana.geode.local
GF_SERVER_ROOT_URL=https://grafana.geode.local

# Resource Limits
GEODE_MEMORY_LIMIT=8G
GEODE_CPU_LIMIT=4.0

Docker Compose Configuration

Basic docker-compose.yml excerpt:

version: '3.9'

services:
  geode:
    image: geode:latest
    container_name: geode
    restart: unless-stopped
    ports:
      - "8443:8443"
    environment:
      - GEODE_LOG_LEVEL=${GEODE_LOG_LEVEL}
      - GEODE_DATA_DIR=${GEODE_DATA_DIR}
      - VAULT_ADDR=${VAULT_ADDR}
      - VAULT_TOKEN=${VAULT_TOKEN}
      - S3_ENDPOINT=${S3_ENDPOINT}
      - S3_ACCESS_KEY=${S3_ACCESS_KEY}
      - S3_SECRET_KEY=${S3_SECRET_KEY}
    volumes:
      - geode-data:/data
      - ./certs:/certs:ro
    networks:
      - geode-network
    deploy:
      resources:
        limits:
          cpus: '${GEODE_CPU_LIMIT}'
          memory: ${GEODE_MEMORY_LIMIT}
        reservations:
          cpus: '2.0'
          memory: 4G
    healthcheck:
      test: ["CMD", "geode", "query", "RETURN 1", "--server", "127.0.0.1:8443"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  vault:
    image: hashicorp/vault:latest
    container_name: geode-vault
    restart: unless-stopped
    environment:
      - VAULT_DEV_ROOT_TOKEN_ID=${VAULT_TOKEN}
    cap_add:
      - IPC_LOCK
    volumes:
      - vault-data:/vault/data
      - vault-logs:/vault/logs
    networks:
      - geode-network

  redis:
    image: redis:7-alpine
    container_name: geode-redis
    restart: unless-stopped
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis-data:/data
    networks:
      - geode-network

volumes:
  geode-data:
  vault-data:
  vault-logs:
  redis-data:

networks:
  geode-network:
    driver: bridge

Vault Initialization

First-time setup (production):

# Initialize Vault (save unseal keys and root token securely!)
docker-compose exec vault vault operator init

# Unseal Vault (required after every restart)
docker-compose exec vault vault operator unseal <unseal-key-1>
docker-compose exec vault vault operator unseal <unseal-key-2>
docker-compose exec vault vault operator unseal <unseal-key-3>

# Login with root token
docker-compose exec vault vault login

# Enable KV secrets engine
docker-compose exec vault vault secrets enable -path=geode kv-v2

# Store encryption keys
docker-compose exec vault vault kv put geode/encryption \
  master_key="$(openssl rand -base64 32)" \
  data_key="$(openssl rand -base64 32)"

# Create policy for Geode
cat <<EOF | docker-compose exec -T vault vault policy write geode-policy -
path "geode/*" {
  capabilities = ["read", "list"]
}
EOF

# Create token for Geode (update .env with this token)
docker-compose exec vault vault token create -policy=geode-policy

Development setup (auto-unseal):

For development, Vault runs in dev mode with auto-unseal. Update .env:

VAULT_DEV_MODE=true
VAULT_TOKEN=dev-only-token

Resource Management

Setting Resource Limits:

# docker-compose.yml
services:
  geode:
    deploy:
      resources:
        limits:
          cpus: '4.0'      # Maximum 4 CPU cores
          memory: 8G       # Maximum 8GB RAM
        reservations:
          cpus: '2.0'      # Reserve 2 CPU cores
          memory: 4G       # Reserve 4GB RAM

Monitoring Resource Usage:

# Real-time container stats
docker stats

# Geode-specific stats
docker stats geode

# Check disk usage
docker system df
docker volume ls
du -sh /var/lib/docker/volumes/geode_geode-data

Backup and Recovery

Automated Backups to MinIO/S3:

# Configure backup schedule (cron)
docker-compose exec geode geode backup --dest s3://geode-backups/scheduled-$(date +%Y%m%d-%H%M%S)

# List backups
docker-compose exec minio mc ls local/geode-backups

# Restore from backup
docker-compose stop geode
docker-compose exec geode geode restore --source s3://geode-backups/backup-20260124-120000
docker-compose start geode

Volume Backups (full data directory):

# Backup volume to tar.gz
docker run --rm \
  -v geode_geode-data:/data:ro \
  -v $(pwd)/backups:/backup \
  alpine tar czf /backup/geode-data-$(date +%Y%m%d).tar.gz -C /data .

# Restore volume from tar.gz
docker-compose stop geode
docker run --rm \
  -v geode_geode-data:/data \
  -v $(pwd)/backups:/backup \
  alpine sh -c "rm -rf /data/* && tar xzf /backup/geode-data-20260124.tar.gz -C /data"
docker-compose start geode

Use Cases

Development & Testing:

  • Local development with hot reloading
  • Integration testing with realistic infrastructure
  • Feature validation before production

Small Production Deployments:

  • Startups and small teams (< 10,000 queries/day)
  • Internal tools and dashboards
  • Proof of concept and prototypes

Edge Computing:

  • On-premises installations with limited resources
  • IoT gateway aggregation
  • Offline-capable applications

Distributed Deployment

Architecture

Distributed deployment provides high availability, horizontal scaling, and data sharding:

┌─────────────────────────────────────────────────────────┐
│                    Load Balancer                        │
│              (Nginx / HAProxy / Cloud LB)               │
└────────────┬─────────────┬──────────────┬───────────────┘
             │             │              │
    ┌────────▼────┐  ┌─────▼──────┐  ┌───▼──────────┐
    │  Geode      │  │  Geode     │  │   Geode      │
    │  Node 1     │  │  Node 2    │  │   Node 3     │
    │ (Shard A)   │  │ (Shard B)  │  │  (Shard C)   │
    └────────┬────┘  └─────┬──────┘  └───┬──────────┘
             │             │              │
             └─────────────┴──────────────┘
                 ┌────────▼─────────┐
                 │  Raft Consensus  │
                 │  Cluster State   │
                 └──────────────────┘
             ┌────────────┴──────────────┐
             │                           │
    ┌────────▼────────┐      ┌──────────▼────────┐
    │  Shared Storage │      │  Shared Vault     │
    │  (MinIO / S3)   │      │  (Multi-node)     │
    └─────────────────┘      └───────────────────┘

Multi-Node Configuration

Node 1 (docker-compose.node1.yml):

version: '3.9'

services:
  geode-node1:
    image: geode:latest
    container_name: geode-node1
    hostname: geode-node1
    environment:
      - GEODE_NODE_ID=1
      - GEODE_CLUSTER_MODE=true
      - GEODE_RAFT_PEERS=geode-node1:9000,geode-node2:9000,geode-node3:9000
      - GEODE_SHARD_ID=A
      - GEODE_LISTEN_ADDR=0.0.0.0:8443
      - GEODE_RAFT_ADDR=0.0.0.0:9000
    ports:
      - "8443:8443"
      - "9000:9000"
    volumes:
      - geode-node1-data:/data
    networks:
      - geode-cluster

volumes:
  geode-node1-data:

networks:
  geode-cluster:
    driver: overlay
    attachable: true

Node 2 & 3 - Similar configuration with different node IDs and shard assignments.

Sharding Strategy

Consistent Hashing:

# Configure sharding in Geode
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.
  --strategy consistent-hash \
  --replicas 3 \
  --rebalance-threshold 0.1

# Assign shards to nodes
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.

Range-Based Sharding:

-- Create sharded graph
CREATE GRAPH social_network
  PARTITION BY RANGE (user_id)
  (
    SHARD shard_a VALUES LESS THAN (1000000),
    SHARD shard_b VALUES LESS THAN (2000000),
    SHARD shard_c VALUES LESS THAN (MAXVALUE)
  );

Federation

Cross-Cluster Queries:

-- Configure federation
USE GRAPH social_network;
CREATE FEDERATION global_social
  WITH CLUSTERS (
    'us-west' AT 'geode-us-west.example.com:8443',
    'eu-central' AT 'geode-eu.example.com:8443',
    'ap-southeast' AT 'geode-ap.example.com:8443'
  );

-- Query across federated clusters
USE FEDERATION global_social;
MATCH (user:Person)-[:FRIENDS_WITH]->(friend:Person)
WHERE user.region = 'us-west' AND friend.region = 'eu-central'
RETURN user.name, friend.name;

Consensus and Coordination

Raft Configuration:

# Initialize Raft cluster
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.
  --node-id 1 \
  --peers geode-node1:9000,geode-node2:9000,geode-node3:9000

# Check cluster status
geode query "SHOW CLUSTER STATUS"

# Example output:
# Node ID: 1
# Role: Leader
# Term: 5
# Commit Index: 1234
# Peers: [geode-node2:Follower, geode-node3:Follower]

Load Balancing

Nginx Configuration (nginx-lb.conf):

upstream geode_cluster {
    least_conn;
    server geode-node1:8443 max_fails=3 fail_timeout=30s;
    server geode-node2:8443 max_fails=3 fail_timeout=30s;
    server geode-node3:8443 max_fails=3 fail_timeout=30s;
}

server {
    listen 443 ssl http2;
    server_name geode.example.com;

    ssl_certificate /etc/nginx/certs/server.crt;
    ssl_certificate_key /etc/nginx/certs/server.key;
    ssl_protocols TLSv1.3;

    location / {
        proxy_pass https://geode_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # QUIC support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    # Health check endpoint
    location /health {
        proxy_pass https://geode_cluster;
        access_log off;
    }
}

Failover and High Availability

Automatic Failover:

# Configure automatic failover
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.
  --min-replicas 2 \
  --auto-promote true \
  --failover-timeout 30s

# Manual failover (if needed)
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.

Health Checks:

# docker-compose.yml healthcheck
healthcheck:
  test: ["CMD", "geode", "query", "RETURN 1", "--server", "127.0.0.1:8443"]
  interval: 10s
  timeout: 5s
  retries: 3
  start_period: 30s

Scaling Operations

Horizontal Scaling (add nodes):

# Scale up cluster
docker-compose up -d --scale geode=5

# Rebalance shards
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.

# Verify distribution
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.

Vertical Scaling (increase resources):

# Update resource limits
services:
  geode:
    deploy:
      resources:
        limits:
          cpus: '8.0'
          memory: 16G
        reservations:
          cpus: '4.0'
          memory: 8G

Cloud Deployment

Kubernetes Deployment

Namespace and ConfigMap:

# geode-namespace.yml
apiVersion: v1
kind: Namespace
metadata:
  name: geode

---
# geode-config.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: geode-config
  namespace: geode
data:
  GEODE_LOG_LEVEL: "info"
  GEODE_DATA_DIR: "/data"
  GEODE_CLUSTER_MODE: "true"

StatefulSet for Geode:

# geode-statefulset.yml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: geode
  namespace: geode
spec:
  serviceName: geode
  replicas: 3
  selector:
    matchLabels:
      app: geode
  template:
    metadata:
      labels:
        app: geode
    spec:
      containers:
      - name: geode
        image: geode:latest
        ports:
        - containerPort: 8443
          name: quic
        - containerPort: 9000
          name: raft
        env:
        - name: GEODE_NODE_ID
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: GEODE_CLUSTER_MODE
          value: "true"
        - name: GEODE_RAFT_PEERS
          value: "geode-0.geode:9000,geode-1.geode:9000,geode-2.geode:9000"
        envFrom:
        - configMapRef:
            name: geode-config
        - secretRef:
            name: geode-secrets
        volumeMounts:
        - name: data
          mountPath: /data
        - name: certs
          mountPath: /certs
          readOnly: true
        resources:
          requests:
            memory: "4Gi"
            cpu: "2000m"
          limits:
            memory: "8Gi"
            cpu: "4000m"
        livenessProbe:
          exec:
            command:
            - geode
            - query
            - "RETURN 1"
            - --server
            - 127.0.0.1:8443
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          exec:
            command:
            - geode
            - query
            - "RETURN 1"
            - --server
            - 127.0.0.1:8443
          initialDelaySeconds: 10
          periodSeconds: 5
      volumes:
      - name: certs
        secret:
          secretName: geode-tls-certs
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: fast-ssd
      resources:
        requests:
          storage: 100Gi

Service and Ingress:

# geode-service.yml
apiVersion: v1
kind: Service
metadata:
  name: geode
  namespace: geode
spec:
  clusterIP: None
  selector:
    app: geode
  ports:
  - port: 8443
    name: quic
  - port: 9000
    name: raft

---
apiVersion: v1
kind: Service
metadata:
  name: geode-lb
  namespace: geode
spec:
  type: LoadBalancer
  selector:
    app: geode
  ports:
  - port: 8443
    targetPort: 8443
    name: quic

---
# geode-ingress.yml (if using HTTP/3 ingress)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: geode-ingress
  namespace: geode
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
spec:
  ingressClassName: nginx
  rules:
  - host: geode.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: geode-lb
            port:
              number: 8443
  tls:
  - hosts:
    - geode.example.com
    secretName: geode-tls-certs

Secrets Management:

# Create TLS secret
kubectl create secret tls geode-tls-certs \
  --cert=server.crt \
  --key=server.key \
  --namespace=geode

# Create application secrets
kubectl create secret generic geode-secrets \
  --from-literal=VAULT_TOKEN=<vault-token> \
  --from-literal=S3_ACCESS_KEY=<s3-key> \
  --from-literal=S3_SECRET_KEY=<s3-secret> \
  --namespace=geode

Deploy to Kubernetes:

# Apply configurations
kubectl apply -f geode-namespace.yml
kubectl apply -f geode-config.yml
kubectl apply -f geode-statefulset.yml
kubectl apply -f geode-service.yml
kubectl apply -f geode-ingress.yml

# Verify deployment
kubectl get pods -n geode
kubectl get svc -n geode
kubectl logs -f geode-0 -n geode

# Scale cluster
kubectl scale statefulset geode --replicas=5 -n geode

Cloud Provider Specifics

AWS Deployment:

# Use EBS for storage
storageClassName: gp3-encrypted

# Use Application Load Balancer
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "tcp"

# Use S3 for backups
S3_ENDPOINT: https://s3.us-west-2.amazonaws.com
S3_BUCKET: geode-backups-production

Google Cloud Platform:

# Use Persistent Disk
storageClassName: pd-ssd

# Use Cloud Load Balancer
cloud.google.com/load-balancer-type: "Internal"

# Use Cloud Storage for backups
S3_ENDPOINT: https://storage.googleapis.com
S3_BUCKET: geode-backups-gcp

Azure Deployment:

# Use Premium SSD
storageClassName: managed-premium

# Use Azure Load Balancer
service.beta.kubernetes.io/azure-load-balancer-internal: "true"

# Use Blob Storage for backups
S3_ENDPOINT: https://geodebackups.blob.core.windows.net
S3_BUCKET: geode-backups

Digital Ocean:

# Use DO Block Storage
storageClassName: do-block-storage

# Use DO Load Balancer
service.beta.kubernetes.io/do-loadbalancer-protocol: "tcp"

# Use DO Spaces for backups
S3_ENDPOINT: https://nyc3.digitaloceanspaces.com
S3_BUCKET: geode-backups
S3_REGION: nyc3

GPU-Capable Deployment

What Is and Is Not GPU-Accelerated

Geode ships an experimental GPU compute subsystem: Vulkan compute shaders (pagerank, shortest_path, setops, vector_add) plus a dynamically loaded CUDA driver used for device enumeration. Today it is exercised by the engine’s own benchmarks and a planner cost heuristic; it is not wired into query execution.

Concretely, at the current release:

  • There is no GPU-accelerated vector index. HNSW index build and search, and every vector function (similarity, distance, vector_l2, vector_cosine, vector_dot, vector_knn), run on the CPU.
  • There is no gpu_acceleration session setting, no gpu_enabled index option, and no gpu_enabled procedure parameter. Queries using them will be rejected.
  • GPU use is not configured by environment variables. Device availability is probed at runtime by dlopen-ing the CUDA driver on Linux; when no device is present every code path falls back to the CPU implementation.

The GPU image is therefore useful for evaluating the compute kernels and for pre-provisioning GPU nodes, not for speeding up production queries. Treat the section below as an experimental deployment, and benchmark against the standard image before committing to GPU hardware.

GPU Configuration

The engine repository ships Dockerfile.gpu (CUDA + Vulkan build) and docker-compose.gpu.yml, which layers a geode-gpu service and an NVIDIA DCGM exporter on top of the base stack:

# docker-compose.gpu.yml (excerpt from the engine repository)
services:
  geode-gpu:
    build:
      context: .
      dockerfile: Dockerfile.gpu
    image: geode:gpu
    container_name: geode-db-gpu
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=compute,utility
      - CUDA_VISIBLE_DEVICES=0
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

  nvidia-exporter:
    image: nvidia/dcgm-exporter:3.3.0-3.2.0-ubuntu22.04
    container_name: geode-nvidia-exporter
    ports:
      - "127.0.0.1:9400:9400"
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

NVIDIA_VISIBLE_DEVICES / CUDA_VISIBLE_DEVICES are consumed by the NVIDIA container runtime and the CUDA driver, not by Geode itself.

Kubernetes GPU Deployment:

# geode-gpu-statefulset.yml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: geode-gpu
  namespace: geode
spec:
  replicas: 2
  template:
    spec:
      containers:
      - name: geode
        image: geode:gpu
        resources:
          limits:
            nvidia.com/gpu: 1  # Request 1 GPU per pod
      nodeSelector:
        accelerator: nvidia-tesla-v100  # Target GPU nodes

Query Tuning on GPU Nodes

Because queries execute on the CPU, tune vector workloads exactly as you would on a standard node — create the index for the metric you query with, and let the index serve the ranking:

-- Create the vector index for the metric you will query with
CREATE INDEX user_embeddings ON Person(embedding) USING vector
  WITH (metric = 'euclidean');

-- Nearest neighbours by Euclidean distance (lower = closer)
MATCH (user:Person)
WHERE distance(user.embedding, $query_embedding, 'euclidean') < 0.5
RETURN user.name, user.embedding
ORDER BY distance(user.embedding, $query_embedding, 'euclidean') ASC
LIMIT 100;
-- PageRank runs on the CPU; the procedure takes no tuning parameters today
CALL algo.pagerank.stream() YIELD nodeId, score
RETURN nodeId, score
ORDER BY score DESC
LIMIT 10;

GPU Monitoring

Prometheus Metrics (from DCGM exporter):

# GPU utilization
DCGM_FI_DEV_GPU_UTIL

# GPU memory usage
DCGM_FI_DEV_FB_USED / DCGM_FI_DEV_FB_FREE

# GPU temperature
DCGM_FI_DEV_GPU_TEMP

# GPU power draw
DCGM_FI_DEV_POWER_USAGE

Grafana Dashboard:

  • GPU utilization over time
  • Device memory usage (reported by DCGM, not attributed per query)
  • Temperature and throttling events
  • Power consumption trends

Infrastructure Stack

Monitoring with Prometheus & Grafana

Prometheus Configuration (prometheus.yml):

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'geode'
    static_configs:
      - targets: ['geode:9090']
    metrics_path: '/metrics'

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']

  - job_name: 'dcgm-exporter'
    static_configs:
      - targets: ['dcgm-exporter:9400']

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']

rule_files:
  - '/etc/prometheus/alerts/*.yml'

Alert Rules (alerts/geode.yml):

groups:
  - name: geode_alerts
    interval: 30s
    rules:
      - alert: GeodeHighMemoryUsage
        expr: geode_memory_usage_percent > 90
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Geode high memory usage on {{ $labels.instance }}"
          description: "Memory usage is {{ $value }}%"

      - alert: GeodeDown
        expr: up{job="geode"} == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Geode is down on {{ $labels.instance }}"
          description: "Geode database is not responding"

      - alert: HighQueryLatency
        expr: geode_query_duration_seconds{quantile="0.99"} > 5
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "High query latency detected"
          description: "P99 query latency is {{ $value }}s"

      - alert: TooManyConnections
        expr: geode_active_connections > 900
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Too many active connections"
          description: "Active connections: {{ $value }}"

Grafana Dashboards:

Pre-configured dashboards available in config/grafana/dashboards/:

  1. Geode Overview

    • Query throughput (queries/second)
    • Query latency (P50, P95, P99)
    • Active connections
    • Memory and CPU usage
    • Cache hit rate
  2. Storage Metrics

    • Disk I/O (read/write ops)
    • WAL write throughput
    • Index size and growth
    • Page cache efficiency
  3. GPU Metrics (GPU deployment only)

    • GPU utilization per card
    • Memory allocation
    • Temperature and power
    • Kernel execution time
  4. System Health

    • Node availability
    • Raft consensus state
    • Replication lag
    • Backup status

Logging with Loki & Promtail

Promtail Configuration (promtail-config.yml):

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
  - job_name: geode
    static_configs:
      - targets:
          - localhost
        labels:
          job: geode
          __path__: /var/log/geode/*.log
    pipeline_stages:
      - json:
          expressions:
            level: level
            timestamp: timestamp
            message: message
            query: query
      - labels:
          level:
      - timestamp:
          source: timestamp
          format: RFC3339

Loki Configuration (loki-config.yml):

auth_enabled: false

server:
  http_listen_port: 3100

ingester:
  lifecycler:
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
  chunk_idle_period: 15m
  chunk_retain_period: 30s

schema_config:
  configs:
    - from: 2024-01-01
      store: boltdb-shipper
      object_store: filesystem
      schema: v11
      index:
        prefix: index_
        period: 24h

storage_config:
  boltdb_shipper:
    active_index_directory: /loki/index
    cache_location: /loki/cache
    shared_store: filesystem
  filesystem:
    directory: /loki/chunks

limits_config:
  enforce_metric_name: false
  reject_old_samples: true
  reject_old_samples_max_age: 168h

chunk_store_config:
  max_look_back_period: 0s

table_manager:
  retention_deletes_enabled: true
  retention_period: 720h  # 30 days

Backup with MinIO

MinIO Configuration:

# Access MinIO container
docker-compose exec minio sh

# Configure mc (MinIO client)
mc alias set local http://localhost:9000 $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD

# Create buckets
mc mb local/geode-backups
mc mb local/geode-wal-archive

# Set retention policy (30 days)
mc retention set --default GOVERNANCE 30d local/geode-backups

# Enable versioning
mc version enable local/geode-backups

Lifecycle Policy (automatic cleanup):

{
  "Rules": [
    {
      "Expiration": {
        "Days": 30
      },
      "ID": "DeleteOldBackups",
      "Filter": {
        "Prefix": "daily/"
      },
      "Status": "Enabled"
    },
    {
      "Expiration": {
        "Days": 90
      },
      "ID": "DeleteOldWeeklyBackups",
      "Filter": {
        "Prefix": "weekly/"
      },
      "Status": "Enabled"
    },
    {
      "Transition": {
        "Days": 7,
        "StorageClass": "GLACIER"
      },
      "ID": "ArchiveToGlacier",
      "Filter": {
        "Prefix": "daily/"
      },
      "Status": "Enabled"
    }
  ]
}

Apply lifecycle policy:

cat lifecycle.json | docker-compose exec -T minio sh -c "mc ilm import local/geode-backups"

Nginx Reverse Proxy

Nginx Configuration (nginx.conf):

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 4096;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    # SSL Configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # Compression
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml text/javascript
               application/json application/javascript application/xml+rss;

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=geode_limit:10m rate=100r/s;
    limit_conn_zone $binary_remote_addr zone=geode_conn:10m;

    # Include virtual hosts
    include /etc/nginx/conf.d/*.conf;
}

stream {
    # QUIC passthrough for Geode
    upstream geode_quic {
        server geode:8443;
    }

    server {
        listen 8443 udp;
        proxy_pass geode_quic;
        proxy_timeout 30s;
    }
}

Virtual Host Configuration (conf.d/geode.conf):

# Geode
server {
    listen 443 ssl http2;
    server_name geode.local;

    ssl_certificate /etc/nginx/certs/server.crt;
    ssl_certificate_key /etc/nginx/certs/server.key;

    location / {
        proxy_pass https://geode:8443;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        limit_req zone=geode_limit burst=20 nodelay;
        limit_conn geode_conn 10;
    }
}

# Grafana
server {
    listen 443 ssl http2;
    server_name grafana.geode.local;

    ssl_certificate /etc/nginx/certs/server.crt;
    ssl_certificate_key /etc/nginx/certs/server.key;

    location / {
        proxy_pass http://grafana:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# Prometheus
server {
    listen 443 ssl http2;
    server_name prometheus.geode.local;

    ssl_certificate /etc/nginx/certs/server.crt;
    ssl_certificate_key /etc/nginx/certs/server.key;

    location / {
        proxy_pass http://prometheus:9090;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Security Best Practices

TLS Certificates

Production Certificates (Let’s Encrypt):

# Install certbot
apt-get install certbot

# Obtain certificate
certbot certonly --standalone \
  -d geode.example.com \
  --email [email protected] \
  --agree-tos

# Copy certificates
cp /etc/letsencrypt/live/geode.example.com/fullchain.pem certs/server.crt
cp /etc/letsencrypt/live/geode.example.com/privkey.pem certs/server.key

# Set permissions
chmod 600 certs/server.key
chmod 644 certs/server.crt

# Restart services
docker-compose restart geode nginx

Auto-renewal:

# Add cron job for renewal
cat <<EOF | sudo tee /etc/cron.d/certbot
0 3 * * * root certbot renew --quiet --post-hook "docker-compose -f /path/to/docker-compose.yml restart geode nginx"
EOF

Firewall Configuration

UFW (Ubuntu):

# Allow SSH
ufw allow 22/tcp

# Allow Geode QUIC
ufw allow 8443/udp
ufw allow 8443/tcp

# Allow HTTPS (Nginx)
ufw allow 443/tcp

# Allow Raft (internal cluster only)
ufw allow from 10.0.0.0/8 to any port 9000

# Enable firewall
ufw enable

iptables:

# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Allow Geode QUIC
iptables -A INPUT -p udp --dport 8443 -j ACCEPT
iptables -A INPUT -p tcp --dport 8443 -j ACCEPT

# Allow HTTPS
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Allow Raft (internal network only)
iptables -A INPUT -s 10.0.0.0/8 -p tcp --dport 9000 -j ACCEPT

# Drop everything else
iptables -A INPUT -j DROP

# Save rules
iptables-save > /etc/iptables/rules.v4

Network Segmentation

Docker Networks:

# docker-compose.yml
networks:
  geode-frontend:
    driver: bridge
  geode-backend:
    driver: bridge
    internal: true  # No external access

services:
  geode:
    networks:
      - geode-frontend
      - geode-backend

  vault:
    networks:
      - geode-backend  # Only internal access

  nginx:
    networks:
      - geode-frontend  # Only frontend access

Secrets Management

Best Practices:

  1. Never commit secrets to version control
  2. Use Vault for production secrets
  3. Rotate credentials regularly (90 days)
  4. Use strong random passwords (32+ characters)
  5. Enable MFA for admin access
  6. Audit secret access (Vault audit logs)

Automated Rotation:

# Rotate database encryption keys
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.
  --old-key-id vault:geode/encryption/master_key \
  --new-key-id vault:geode/encryption/master_key_v2

# Rotate service tokens
docker-compose exec vault vault token renew -increment=720h

Troubleshooting

Common Issues

Geode Won’t Start:

# Check logs
docker-compose logs geode

# Verify certificates
ls -l certs/
openssl x509 -in certs/server.crt -text -noout

# Test connectivity to dependencies
docker-compose exec geode ping vault
docker-compose exec geode nc -zv minio 9000
docker-compose exec geode nc -zv redis 6379

High Memory Usage:

# Check container stats
docker stats geode

# Verify memory limits
docker inspect geode | grep -A 10 Memory

# Adjust limits if needed
# Edit docker-compose.yml and restart
docker-compose up -d geode

Vault Sealed:

# Check Vault status
docker-compose exec vault vault status

# Unseal Vault
docker-compose exec vault vault operator unseal <unseal-key-1>
docker-compose exec vault vault operator unseal <unseal-key-2>
docker-compose exec vault vault operator unseal <unseal-key-3>

# Enable auto-unseal (AWS KMS, GCP KMS, Azure Key Vault)

MinIO Access Denied:

# Verify credentials in .env
cat .env | grep S3_

# Test MinIO access
docker-compose exec minio mc alias set test \
  http://localhost:9000 \
  $MINIO_ROOT_USER \
  $MINIO_ROOT_PASSWORD

# List buckets
docker-compose exec minio mc ls test/

GPU Not Detected:

# Verify NVIDIA runtime
docker run --rm --gpus all nvidia/cuda:12.3.0-base-ubuntu22.04 nvidia-smi

# Check Docker daemon configuration
cat /etc/docker/daemon.json

# Should contain:
# {
#   "runtimes": {
#     "nvidia": {
#       "path": "nvidia-container-runtime",
#       "runtimeArgs": []
#     }
#   },
#   "default-runtime": "nvidia"
# }

# Restart Docker
sudo systemctl restart docker

Cluster Split-Brain:

# Check Raft status on all nodes
geode query "SHOW CLUSTER STATUS"
geode query "SHOW CLUSTER STATUS"
geode query "SHOW CLUSTER STATUS"

# Force leader election
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.

# Reset Raft state (DANGEROUS - data loss possible)
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.

Performance Issues

Slow Queries:

# Enable query logging
docker-compose exec geode geode query "SHOW CLUSTER STATUS"

# Analyze slow queries
docker-compose logs geode | grep "slow_query"

# Use EXPLAIN to analyze query plan
geode query "EXPLAIN MATCH (n:Person) RETURN n" --server geode:8443

High Latency:

# Check network latency
docker-compose exec geode ping -c 10 geode-node2

# Verify QUIC performance
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.

# Monitor metrics
curl http://localhost:9090/api/v1/query?query=geode_query_duration_seconds

Disk I/O Bottleneck:

# Check disk performance
docker-compose exec geode iostat -x 1 10

# Enable I/O optimizations
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.
  --async-io true \
  --io-threads 8 \
  --read-ahead 128k

# Consider upgrading to faster storage (NVMe SSD)

Health Checks

System Health:

# Check all services
docker-compose ps

# Verify Geode health
curl -k https://geode.local/health

# Check cluster health
geode query "SHOW CLUSTER STATUS"

# Example output:
# Cluster: healthy
# Nodes: 3/3 online
# Shards: 3/3 balanced
# Replication: current

Database Integrity:

# Run integrity check
geode query "CALL geode.storage.integrity()"

# Vacuum database
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.

# Analyze statistics
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.

# Reindex (if needed)
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.

Maintenance

Regular Maintenance Tasks

Daily:

  • Monitor metrics and alerts
  • Review error logs
  • Check backup completion
  • Verify cluster health

Weekly:

  • Review slow query logs
  • Analyze storage growth
  • Update statistics
  • Rotate logs

Monthly:

  • Vacuum database
  • Update Docker images
  • Review and update secrets
  • Test disaster recovery

Quarterly:

  • Security audit
  • Performance benchmarks
  • Capacity planning review
  • Update TLS certificates (if needed)

Update Procedure

# Pull latest images
docker-compose pull

# Backup current state
geode backup --dest s3://geode-backups/pre-update-$(date +%Y%m%d)

# Stop services
docker-compose stop geode

# Recreate containers
docker-compose up -d geode

# Verify health
docker-compose logs -f geode
geode query "RETURN 1" --server geode:8443

# Clean up old images
docker image prune -a

Log Rotation

Configure logrotate:

# /etc/logrotate.d/geode
/var/lib/docker/volumes/geode_logs/_data/*.log {
    daily
    rotate 30
    compress
    delaycompress
    notifempty
    create 0640 root root
    sharedscripts
    postrotate
        docker-compose exec geode kill -USR1 1
    endscript
}

Cleanup

# Remove old backups (30+ days)
docker-compose exec minio mc find local/geode-backups --older-than 30d --exec "mc rm {}"

# Clean up old Docker volumes
docker volume prune

# Clean up old logs
find /var/log/geode -name "*.log" -mtime +30 -delete

# Clean WAL archives (after backup)
# There is no `geode admin` subcommand. Geode's CLI is: serve, shell, query,
# lsp, backup, restore, migrate, auth, login, logout, user, role, tenant,
# policy, grant, revoke, completion, mcp.

Production Checklist

Before going to production, verify:

  • Security

    • Production TLS certificates installed
    • All default passwords changed
    • Firewall rules configured
    • Vault initialized and unsealed
    • Secrets rotation policy in place
    • Audit logging enabled
    • Network encryption between services
  • High Availability

    • Minimum 3 nodes for distributed deployment
    • Raft consensus configured
    • Load balancer with health checks
    • Automatic failover tested
    • Replication lag monitoring
  • Backup & Recovery

    • Automated backups scheduled
    • Backup retention policy configured
    • Restore procedure tested
    • Disaster recovery plan documented
    • Off-site backup storage
  • Monitoring

    • Prometheus scraping Geode metrics
    • Grafana dashboards configured
    • Alerting rules defined
    • On-call rotation established
    • Runbook for common issues
  • Performance

    • Load testing completed
    • Resource limits configured
    • Query optimization reviewed
    • Index strategy validated
    • Scaling plan defined
  • Operations

    • Maintenance windows scheduled
    • Update procedure documented
    • Team trained on operations
    • Support escalation path defined
    • SLA/SLO targets documented

Next Steps

After successful deployment:

  1. Configure Monitoring - Set up dashboards and alerts in Grafana
  2. Test Backups - Verify backup and restore procedures
  3. Optimize Queries - Use EXPLAIN and PROFILE to tune performance
  4. Review Security - Conduct security audit and penetration testing
  5. Document Operations - Create runbooks for common operational tasks
  6. Train Team - Ensure operations team is familiar with Geode deployment

Related Documentation:


Last Updated: January 2026 Geode Version: 0.8.14+ Status: Production Ready