Orbit reconciler

Status: Implemented Issue: https://gitlab.com/gitlab-org/cloud-native/gitlab-operator/-/work_items/2251 Parent: none

Goal

An administrator deploys Orbit, the GitLab Knowledge Graph, beside a GitLab instance by writing one Orbit resource. The Operator keeps the Orbit chart in line with it. The resource names the GitLabCore and the Siphon that Orbit builds on, and points at the graph ClickHouse and the Secrets. It creates none of them. For the design, see ADR 36.

Requirements

  • The reconciler runs only in a build with the bridge tag and with ENABLE_BRIDGE=true. Without either, the manager starts with no Orbit watch.
  • The definition requires the GitLab reference, the Siphon reference, the chart version, the credentials of both ClickHouse connections (the datalake and the graph), the graph host and database, and a Secret reference for the JWT key. It rejects a resource name longer than 44 characters.
  • Nothing renders until the referenced GitLabCore reports Available and its GitLab version, and the referenced Siphon reports Available and its stream name. A missing, unavailable, or incomplete resource is a wait with a reason of its own. Each wait resolves without a change to the Orbit.
  • A GitLab version older than the oldest one Orbit supports is a failure. The condition names both versions.
  • A Siphon that names another gitlabRef than the Orbit is reported with a condition that names both instances, and nothing renders. So is a Siphon that sets NATS credentials, which Orbit cannot use.
  • An Orbit selects its chart version in spec.version, shaped like the one of a Siphon, with the Static type only. spec.chart carries the values only. The version comes from version or from versionRef, as Version reference describes, and a change to the referenced ConfigMap renders the chart again.
  • An unresolvable versionRef fails the pass with Initialized=False and reason VersionUnresolved, and leaves what is applied running.
  • The chart renders from the charts in the Operator image. A version the image does not include fails with a condition that lists the versions it does include.
  • The GitLab URL is derived from the referenced instance. The NATS connection, the datalake host and database, and the stream name are derived from the referenced Siphon. A change to the Siphon reaches the Orbit within 30 seconds.
  • The webserver, the dispatcher, and the indexer are always on. Product analytics is off unless spec.chart.values turns it on. spec.chart.values overrides every other value the Operator derives.
  • With spec.tls, the webserver serves gRPC over TLS with that Secret. spec.tls is optional.
  • spec.chart.values is refused before anything is applied, with a condition that names the value, when it turns on clickhouseSetup, dashboards, healthCheck, or indexer.keda. So is a render with no indexer pool, or with two objects of one kind and name.
  • A Siphon that is being deleted is a wait, whatever it reports.
  • Each pass applies every rendered object except RBAC. An object deleted or edited by hand is restored within 30 seconds of the previous pass.
  • A PodMonitor or PrometheusRule is rendered only on a cluster that serves its API.
  • Cleanup follows Object cleanup.
  • Available is True once the webserver, the dispatcher, and every indexer pool have rolled out. A pass that waits or fails before it checks them reports Available as Unknown.
  • The status records the GitLab version of the referenced instance and the chart version applied. When the webserver serves TLS, it also records the tls:// gRPC endpoint that GitLab connects to.
  • Deleting an Orbit removes what the chart rendered. The graph database and the NATS streams are left in place.
  • The Orbit reconciler reads no Secret, and the chart renders none. Each credential reaches the pods as a mounted Secret key.

Out of scope

  • Turning indexing on per group. GitLab is configured to use Orbit through spec.orbitRef of the GitLabCore, which GitLabCore configuration covers.
  • Generating the JWT key, the ClickHouse users, or the graph database.
  • Bridge API and UI support, which Orbit add-on covers.
  • Autoscaling with KEDA, the health-check component, and Grafana dashboards.
  • The gkg chart (3.x and older) and migrating from it.
  • A Siphon not managed by the Operator, and a Siphon in another namespace.
  • A validating webhook on spec.chart.values.

FAQ

  • Why are clickhouseSetup, dashboards, healthCheck, and indexer.keda refused? Each one breaks a rule the other v2alpha1 resources follow:

    • clickhouseSetup creates ClickHouse users with the admin password, which provisions a prerequisite.
    • dashboards runs a hook that creates ConfigMaps no release tracks, plus RBAC of its own.
    • healthCheck needs a Role in every namespace it targets, which the Operator does not apply.
    • indexer.keda requires healthCheck.

    A silently degraded workload is worse than a refusal.

  • Why is the dispatcher always on? The dispatcher creates the graph tables, and the indexer waits for it. The chart turns it off by default, which leaves a deployment that never indexes.

  • Does Available mean the graph is indexed? No. It means the workloads have rolled out. The first index finishes long after that. The health-check component, the only one that could report on the dependencies, answers ready unconditionally.

  • How does GitLab find Orbit? Through status.grpcEndpoint and the JWT Secret, which a GitLabCore reads when its spec.orbitRef names the Orbit. The GitLabCore never waits for the Orbit, so its readiness stays independent of Orbit.

  • Which GitLab chart does Orbit need? 10.4 or later. The Orbit refuses a GitLab older than 19.2.2, which Orbit itself needs, and a GitLabCore configures the connection only on chart 10.4 or later. See GitLabCore configuration.

  • Why does an Orbit reference a Siphon? Orbit reads the datalake that the Siphon fills and the NATS stream it publishes to, so it is of no use without one. The reference keeps the shared facts in one place and lets the Orbit wait for the Siphon.

  • Why does it still reference the GitLabCore? Every v2alpha1 resource names its instance the same way, and the GitLab URL, version, and JWT key belong to the instance. The mismatch check keeps the two references consistent.

  • Can an Orbit use a Siphon installed outside the Operator? Not yet. The reference is required. An optional reference with explicit fields as a fallback can be added later without breaking the API.

  • Is TLS on the gRPC port required? No. GitLab accepts only a tls:// endpoint, but TLS can also be terminated in front of Orbit. Without spec.tls, the Operator cannot observe that address, so it reports no endpoint.

  • Is product analytics on? No. The chart turns Snowplow on, and the GitLab Self-Managed docs say to leave it off. spec.chart.values can turn it back on.

  • Is there a structured field for replicas? Not yet. The chart defaults to three webserver replicas and two indexer pools, and spec.chart.values tunes both.

  • Why only the Static version type? The chart is bundled in the Operator image and never pulled, so no repository is followed. This matches Siphon.