Skip to content

Concepts ​

This section is aimed at contributors, operators running Palena in production, and anyone debugging a tricky reconciliation. It explains how the operator is built — not just what the CRDs look like.

Four layers ​

Palena is structured as four cooperating layers:

Each layer has one job:

1. CRD types (api/v1alpha1/) ​

Go structs with kubebuilder markers. These are the source of truth for the CRD schema — make manifests regenerates YAML into config/crd/bases/ and the OLM bundle. Every field, default, and enum constraint lives here.

Read: CRD design

2. Controllers (internal/controller/) ​

One *_controller.go per CRD. Each implements the controller-runtime Reconciler interface and owns the reconcile loop for its type: finalizer handling, prerequisite checks, dispatching to the wiring + resource layers, and status updates.

Read: Controllers

3. Wiring builders (internal/wiring/) ​

Pure functions that translate a Palena CR into an unstructured upstream CR. Used for resources Palena doesn't own the Go types for — CloudNativePG Cluster, LiteLLM LiteLLMInstance / LiteLLMModel, Langfuse LangfuseInstance. No I/O; no state.

Read: Wiring upstream CRs

4. Resource builders (internal/resources/) ​

Pure functions that build native Kubernetes resources Palena deploys directly — Redis StatefulSet, LibreChat Deployment, MongoDB, MeiliSearch, and the websearch MCP sidecars. Again: no I/O, just builders.

Read: Managed resources

Why wiring and resources are separate ​

The split is deliberate:

  • Wiring targets CRDs owned by other operators. We import them as unstructured.Unstructured to avoid pulling in the upstream operator's Go module (which would explode our dependency graph and create version pinning hell).
  • Resources targets native k8s.io/api types. We import them directly because they're stable.

This also means: if a new upstream operator comes along, the only things that need to change are a few wiring builders + a prerequisite check. Controllers stay identical.

Common patterns ​

  • Every controller uses the same finalizer pattern, the same condition naming scheme, and the same standard labels — see internal/resources/common.go.
  • Status updates happen once at the end of every reconciliation, never mid-loop.
  • Owner references are set on every created resource so kubectl delete cascades correctly.
  • Config hashes are computed over every generated ConfigMap and attached to the consuming Deployment's pod template annotations — changing the CR triggers a rolling restart automatically.

What's next ​

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