KubemootConfig Guide

Overview

KubemootConfig is a cluster-scoped singleton CRD that centralizes default images and configuration for all Kubemoot components. It eliminates hardcoded image versions in the operator source code and enables GitOps-friendly version management.

Every Kubemoot controller reads from KubemootConfig via the ConfigCache - a thread-safe in-memory cache that the KubemootConfigReconciler populates on startup and updates on every change.

Why a singleton

Image references and operator defaults live in one cluster-scoped resource instead of the operator source, operator environment variables, or every custom resource. An image bump is a patch to one resource: no recompile, no operator restart, no Helm upgrade, and no chance of two namespaces running different runtime images. The scope is cluster-wide on purpose; a per-namespace config would bring the drift back. New cluster-wide defaults (scheduler strategy, retention windows) become new fields on the same resource rather than new CRDs. If default is missing, controllers fail their first reconcile until it exists, which is why the operator chart installs it.

Architecture

KubemootConfig CR ("default")
    │
    ▼
KubemootConfigReconciler
    │
    ▼
ConfigCache (thread-safe, in-memory)
    │
    ├── RAGSourceReconciler     → indexer, queryService, doclingServe images
    ├── AgentReconciler         → agentRuntime image
    ├── MCPServerReconciler     → mcpBridge image
    └── MCPGatewayReconciler    → mcpGateway image

The singleton must be named default. The operator creates it via the Helm chart on initial install.

Spec Reference

Images

FieldTypeDefaultDescription
images.indexerstringghcr.io/kubemoot/indexer:latestRAGSource indexer job image
images.queryServicestringghcr.io/kubemoot/query-service:latestRAGSource query service image
images.agentRuntimestringghcr.io/kubemoot/agent-runtime:latestAgent deployment image
images.mcpGatewaystringghcr.io/kubemoot/mcp-gateway:latestMCPGateway deployment image
images.mcpBridgestringghcr.io/kubemoot/mcp-bridge:latestMCP bridge sidecar image
images.doclingServestringquay.io/docling-project/docling-serve-cpu:latestDocling document converter image

Defaults

FieldTypeDefaultDescription
defaults.imagePullSecrets[]LocalObjectReferenceDefault pull secrets for all Kubemoot workloads
defaults.vectorStoreTypeenumpgvectorDefault vector store: pgvector, qdrant, milvus, chroma
defaults.vectorStoreEndpointstringDefault vector store endpoint for tool indexing. When empty, MCPServer tool indexing is disabled
defaults.embeddingModelstringnomic-embedDefault EmbeddingModel CR name for RAGSources
defaults.otelCollectorEndpointstringDefault OpenTelemetry collector for all agents

Status

FieldTypeDescription
readyboolConfiguration applied successfully
lastUpdatedTimeLast configuration update timestamp
messagestringAdditional status information

Example

Reference KubemootConfig

The Helm chart creates this on install:

apiVersion: kubemoot.ai/v1alpha1
kind: KubemootConfig
metadata:
  name: default
spec:
  images:
    indexer: "ghcr.io/kubemoot/indexer:0.3.1"
    queryService: "ghcr.io/kubemoot/query-service:0.2.0"
    agentRuntime: "ghcr.io/kubemoot/agent-runtime:0.8.5"
    mcpGateway: "ghcr.io/kubemoot/mcp-gateway:0.5.2"
    mcpBridge: "ghcr.io/kubemoot/mcp-bridge:0.4.0"
    doclingServe: "quay.io/docling-project/docling-serve-cpu:latest"
  defaults:
    vectorStoreType: pgvector
    embeddingModel: nomic-embed

defaults.imagePullSecrets is optional and empty by default: public images are published to ghcr.io/kubemoot and need no pull secret. Set it only if a private mirror requires one, for example:

  defaults:
    imagePullSecrets:
      - name: my-registry-pull-secret

Secret replication

The operator copies Secrets into crew namespaces: image pull secrets, vector-store credentials, and Secrets named in a crew’s kubemoot.ai/replicate-secrets annotation. It copies only from its own namespace plus the namespaces listed in the operator chart’s secretReplication.allowedSourceNamespaces value; a request to copy from any other namespace is refused.

secretReplication:
  allowedSourceNamespaces:
    - shared-credentials

Caching

The operator keeps a thread-safe, in-memory cache of the default KubemootConfig’s images and defaults, shared across every controller. The cache is populated on startup and updated whenever the default KubemootConfig changes; controllers read from it on every reconciliation, so no controller needs its own watch on KubemootConfig.

Image Version Management

CI/CD Flow

  1. CI builds a component (e.g., mcp-bridge) and pushes a versioned image tag
  2. The Flux HelmRelease in your GitOps repository overrides chart defaults with specific versions
  3. Helm renders KubemootConfig with the pinned versions
  4. All controllers pick up the new image via ConfigCache on next reconcile

Manual Override

After building a new image version outside of the normal CI flow, manually patch KubemootConfig:

kubectl patch kubemootconfig default --type=merge -p \
  '{"spec":{"images":{"mcpBridge":"ghcr.io/kubemoot/mcp-bridge:0.4.1"}}}'

Why Not :latest?

Using :latest tags with IfNotPresent pull policy causes stale images - Kubernetes caches the image and never pulls a newer version even when the tag is updated. Always use versioned tags. The Flux HelmRelease values file is the correct place to pin versions.

Troubleshooting

Controller using wrong image

Check the KubemootConfig:

kubectl get kubemootconfig default -o yaml

If the values are wrong, check the Flux HelmRelease values:

kubectl get helmrelease -n flux-system kubemoot-operator -o jsonpath='{.spec.values}' | jq .

imagePullSecrets not applied

KubemootConfig’s defaults.imagePullSecrets must use the secret name that exists in the target namespace. It is empty by default, since public images pull from ghcr.io/kubemoot without a secret. Set it to a secret you create in each namespace only if you point global.imageRegistry at a private mirror.

ConfigCache stale

The cache updates on KubemootConfig reconciliation. If a controller seems to use old values, check that the KubemootConfigReconciler is running:

kubectl logs deploy/kubemoot-operator | grep KubemootConfig