Skip to content

Architecture ​

Palena sits between you and the upstream operators (CloudNativePG, LiteLLM Operator, Langfuse Operator), composing them into a single opinionated stack. You write intent; Palena produces the CRs those operators consume, and deploys the rest directly.

Composition graph ​

Reference graph ​

The CRDs reference each other in a strict order:

  • PalenaModel → PalenaGateway (many-to-many via gatewayRefs)
  • PalenaUI → PalenaGateway (one) + PalenaMCPServer (zero or more)
  • PalenaObservability → PalenaGateway (one)
  • PalenaMCPServer → standalone (no gatewayRef in v1alpha1)

Deletion order ​

Finalizers ensure child CRs are cleaned up before their parent:

PalenaUI      ─┐
PalenaModel   ─┤
PalenaObservability ─┼──► PalenaGateway (blocked until children gone)
               ─┘

PalenaMCPServer  ──► independent; owned resources GC'd via ownerRef

When you delete a PalenaGateway, its finalizer blocks removal until all referencing PalenaModel, PalenaUI, and PalenaObservability CRs have been removed. This prevents orphan LiteLLM models pointing at a deleted instance.

Ownership model ​

Every Kubernetes resource created by the operator gets an ownerReference pointing at the Palena CR that caused it. This means:

  • kubectl delete palenagateway production cascades to the CNPG Cluster, Redis StatefulSet, LiteLLMInstance, and NetworkPolicies.
  • kubectl delete palenaui chat cascades to LibreChat Deployment, MongoDB StatefulSet, MeiliSearch, and the auto-generated librechat.yaml ConfigMap.

The only resources Palena explicitly does not own are user-managed secrets referenced by SecretKeyRef. Those survive CR deletion — Palena treats them as input, not state.

Labels ​

Every managed resource is labeled consistently:

yaml
labels:
  app.kubernetes.io/name: <component>          # litellm, librechat, redis, ...
  app.kubernetes.io/instance: <cr-name>         # production, chat, ...
  app.kubernetes.io/component: <role>           # gateway, ui, database, mcp
  app.kubernetes.io/part-of: palena
  app.kubernetes.io/managed-by: palena-operator
  operator.palena.ai/gateway: <gateway-name>    # only when applicable

The operator.palena.ai/gateway label makes it trivial to list everything tied to one gateway:

bash
kubectl get all -l operator.palena.ai/gateway=production

Naming convention ​

All resources created by the operator follow:

<cr-name>-palena-<component>

For a PalenaGateway named production:

  • CNPG Cluster: production-palena-pg
  • Redis StatefulSet: production-palena-redis
  • LiteLLMInstance: production-palena-litellm

For a PalenaUI named chat:

  • LibreChat Deployment: chat-palena-librechat
  • MongoDB StatefulSet: chat-palena-mongodb
  • MeiliSearch Deployment: chat-palena-meilisearch

This convention makes it easy to spot Palena-managed objects and understand which CR produced them.

Released under the Apache 2.0 License. "Palena" is a trademark of bitkaio LLC.