Skip to content

Managed Backends

When you set managed: true on a backend spec, the operator provisions the database or cache cluster for you. This guide covers what is created, the topology options, and how readiness works.

Managed PostgreSQL (Percona PG Operator)

The operator provisions a PerconaPGCluster via the Percona PG Operator (pgv2.percona.com).

Standalone topology (development / single-instance)

spec:
  postgres:
    managed: true
    topology: standalone

The operator creates a minimal PerconaPGCluster named {instance-name}-pg. Suitable for non-production or development deployments.

HA topology (production)

spec:
  postgres:
    managed: true
    topology: ha
    pgbouncer: true
    nodes: 3          # optional, defaults to 3 for HA
  • topology: ha provisions a PerconaPGCluster with multiple replicas.
  • pgbouncer: true enables a PgBouncer connection pooler sidecar, strongly recommended for production GitLab loads.
  • nodes sets the number of PostgreSQL replicas (defaults to the profile value, or 3 for HA).

The production profile sets ha topology and pgbouncer: true by default:

# examples/profile-production.yaml
apiVersion: k8s.bnerd.com/v1alpha1
kind: GitlabProfile
metadata:
  name: production
spec:
  defaults:
    postgres:
      topology: ha
      nodes: 3
    redis:
      topology: ha
    elasticsearch:
      nodes: 3
    backupSchedule: "30 2 * * *"

What the operator creates

Resource Name Notes
PerconaPGCluster {instance}-pg No owner reference — survives instance deletion
PgUser (inside Percona) gitlab Percona creates the user and emits a Secret
Credentials Secret {instance}-pg-pguser-gitlab Created by Percona; consumed by the operator

Readiness

The operator polls the PerconaPGCluster status and checks for a ready primary. While waiting, the instance stays in phase: Provisioning with condition Ready=False / PostgresProvisioning. Once ready, the operator extracts the primary hostname and proceeds to compose Helm values.

# Check PG cluster status
kubectl get perconapgcluster {instance}-pg -n {namespace}
kubectl describe perconapgcluster {instance}-pg -n {namespace}

Managed Redis (OT-Container-Kit redis-operator)

The operator provisions Redis CRs via the OT-Container-Kit redis-operator (redis.redis.opstreelabs.in).

Standalone topology

spec:
  redis:
    managed: true
    topology: standalone

Creates a single-node Redis CR named {instance}-redis.

HA topology (Redis Sentinel)

spec:
  redis:
    managed: true
    topology: ha

Creates a RedisReplication and a RedisSentinel CR for high-availability quorum. The Sentinel endpoint is passed to the GitLab chart. The operator checks that both the main StatefulSet ({instance}-redis) and the sentinel StatefulSet ({instance}-redis-sentinel) have at least one ready replica.

What the operator creates

Resource Name Topology
Redis {instance}-redis standalone
RedisReplication {instance}-redis ha
RedisSentinel {instance}-redis ha (alongside RedisReplication)

All Redis CRs carry no owner reference to the GitlabInstance and are retained on deletion.

Readiness

OT-Container-Kit v0.25.0 ships an empty RedisStatus struct; status.readyReplicas on the Redis CR is pruned by the API server. The operator falls back to inspecting the underlying StatefulSet ({instance}-redis, plus {instance}-redis-sentinel for HA) to determine readiness. This is fully transparent — no configuration is needed.

# Check Redis StatefulSets
kubectl get statefulsets -n {namespace}
kubectl describe statefulset {instance}-redis -n {namespace}

Managed Elasticsearch (ECK — EE only)

Elasticsearch is provisioned only for Enterprise Edition deployments with a valid license.

spec:
  edition: ee
  licenseSecret: my-gitlab-ee-license

  elasticsearch:
    managed: true
    nodes: 3

EE + licenseSecret both required

Setting elasticsearch.managed: true on a CE instance or on an EE instance without spec.licenseSecret has no effect — the Elasticsearch block is silently omitted from the composed Helm values.

What the operator creates

Resource Name Notes
ECK Elasticsearch {instance}-es No owner reference — retained on deletion
ECK credentials Secret {instance}-es-elastic-user Created by ECK; key elastic

The operator passes global.appConfig.elasticsearch.enabled: true, url: https://{instance}-es-es-http.{namespace}.svc.cluster.local:9200, and username: elastic to the GitLab chart.

Advanced Search index bootstrap is a manual step

The operator wires the Elasticsearch connection to the chart. The index creation (gitlab:elastic:* tasks) and enabling Advanced Search in GitLab Admin → Settings → Advanced Search must be completed manually after the first deploy, using the ECK-generated credentials Secret ({instance}-es-elastic-user, key elastic).

Readiness

The operator polls the ECK Elasticsearch status. While the cluster is initialising, the instance stays in phase: Provisioning with condition ElasticsearchProvisioning. ECK typically takes 3–5 minutes to provision a 3-node cluster.

kubectl get elasticsearch {instance}-es -n {namespace}
kubectl describe elasticsearch {instance}-es -n {namespace}

The full EE example

The following example from examples/gitlabinstance-ee-full.yaml shows all three managed backends in a production topology:

apiVersion: k8s.bnerd.com/v1alpha1
kind: GitlabInstance
metadata:
  name: my-gitlab-ee
  namespace: my-gitlab-ee
spec:
  version: "17"
  edition: ee

  licenseSecret: my-gitlab-ee-license

  profile: production

  domains:
    gitlab:   git.example.com
    registry: registry.example.com
    kas:      kas.example.com
    pages:    pages.example.com

  postgres:
    managed: true
    topology: ha
    pgbouncer: true

  redis:
    managed: true
    topology: ha

  elasticsearch:
    managed: true
    nodes: 3

  objectStorage:
    credentialsSecret: my-gitlab-ee-s3-credentials

  smtp:
    credentialsSecret: my-gitlab-ee-smtp-credentials

  backups:
    schedule: "30 2 * * *"
    objectStorage:
      credentialsSecret: my-gitlab-ee-s3-credentials

  placement:
    nodeSelector:
      dedicated: my-gitlab-ee
    tolerations:
    - key: dedicated
      operator: Equal
      value: my-gitlab-ee
      effect: NoSchedule