Operators: the robot DBA/admin
An operator is a controller that knows how to run a specific piece of software. You don’t write a Deployment, a Service, a StatefulSet, and a backup cron by hand — you declare one high-level Custom Resource (CR) describing what you want, and the operator reconciles all the low-level objects to match. It’s a robot DBA/admin that watches its CR forever and keeps reality in sync.
Declare intent, get a managed system
Section titled “Declare intent, get a managed system”flowchart LR CR[/Custom Resource<br/>e.g. Cluster, Keycloak/] -->|watches| Op[Operator] Op -->|creates + manages| Pods[Pods / StatefulSet] Op --> Svc[Services] Op --> Sec[(Secrets)] Op -.->|drift? recreate| Pods
You commit the CR to Git; Argo CD applies it (see GitOps); the operator does the rest. One operator, many instances — the same CNPG operator runs every Postgres on the cluster, no matter which app owns it.
The operators here
Section titled “The operators here”| Operator | CR you write | API group/version | Namespace |
|---|---|---|---|
| CloudNativePG | Cluster | postgresql.cnpg.io/v1 | cnpg-system |
| Keycloak | Keycloak | k8s.keycloak.org/v2beta1 | keycloak |
| Infisical Secrets Operator | InfisicalStaticSecret (+ InfisicalConnection, InfisicalAuth) | secrets.infisical.com/v1beta1 | <app> (per app it serves) |
A CNPG Cluster is tiny — instances, storage, and a backup target — yet it yields a running Postgres with WAL
archiving:
apiVersion: postgresql.cnpg.io/v1kind: Clustermetadata: name: <app>-pg namespace: <app>spec: instances: 1 bootstrap: initdb: database: <app> owner: <app>A Keycloak CR points the auth server at its database and hostname; the operator creates the StatefulSet and a
keycloak-service for it (one instance per env namespace):
apiVersion: k8s.keycloak.org/v2beta1kind: Keycloakmetadata: name: keycloak namespace: keycloak-<env>spec: instances: 1 db: vendor: postgres host: keycloak-pg-rw database: keycloakAn InfisicalStaticSecret names a project/environment in Infisical
and a target Secret to own; a sibling InfisicalAuth CR holds the Machine Identity credential it authenticates with.
Unlike CNPG/Keycloak, this operator runs once but is configured per app — each app that wants GUI-managed secrets
gets its own trio of CRs in each env namespace:
apiVersion: secrets.infisical.com/v1beta1kind: InfisicalStaticSecretmetadata: name: <app>-synced-secrets namespace: <app>-<env>spec: infisicalAuthRef: { name: <app>-auth, namespace: <app>-<env> } sources: - projectId: "<project-id>" environmentSlug: staging secretPath: "/" targets: - kind: Secret creationPolicy: Owner name: <app>-api-kc namespace: <app>-<env>All three operators are installed declaratively via app-of-apps (apps/cnpg-operator, apps/keycloak-operator,
apps/infisical-secrets-operator).
The auto-generated connection secret
Section titled “The auto-generated connection secret”When CNPG creates a Cluster named <app>-pg, it also generates the **
<app>-pg-app** Secret automatically. That Secret holds the app user’s credentials and
a ready-to-use uri key — which the API consumes as DB_URL:
env: - name: DB_URL valueFrom: secretKeyRef: name: <app>-pg-app # <cluster>-app, created by CNPG key: uriSo the database password is never written anywhere by you — the operator mints it, and other workloads reference it by
name. The Keycloak DB works the same way via
keycloak-pg-app. See Secrets for the full picture.