monedula-gitops docs menu
Configure the Kubernetes operator
Install and configure the monedula-gitops operator with Helm: admission webhooks, reconciliation, credentials from Secrets and multi-tenancy.
On this page
The chart’s defaults work for a first run. These are the values to review before production; the chart’s values.yaml lists every value with its default.
Apply your values
Put the values you change in a file, values.yaml on this page. This one turns on the admission webhooks:
webhook:
enabled: true
Install or upgrade the release with the file, and run the same command after every change:
helm upgrade --install monedula-gitops oci://ghcr.io/monedula-dev/charts/monedula-gitops \
--namespace monedula-system --create-namespace \
-f values.yaml
The chart renders the custom resource definitions from its templates (crds.enabled, default true), so an upgrade keeps them current, and crds.keep (default true) leaves them and your custom resources in place on helm uninstall.
Admission webhooks
The webhooks are off by default. These are the chart’s defaults for them:
webhook:
enabled: false # opt-in; cert-free by default (matches --enable-webhooks default)
failurePolicy: Fail
certManager:
enabled: true # cert-manager issues + injects the serving cert (prerequisite)
certSecretName: "" # defaults to <fullname>-webhook-serving-cert
caBundle: "" # BYO mode (certManager.enabled=false): base64 CA bundle
With webhook.enabled: true, the operator validates KafkaTopic, KafkaQuota, KafkaAccessPolicy, KafkaRoleBinding and KafkaUser resources when they are created or updated. It rejects duplicate identities, changes to identity fields, invalid shapes, tenancy violations of topics and conflicting Allow and Deny ACL rules before Kubernetes stores the resource. It never blocks a deletion. Without the webhooks, the custom resource definitions still keep identity fields immutable, and the operator still detects duplicates and tenancy violations, but only after the resource is created.
failurePolicy: Failmeans that Kubernetes rejects creates and updates of these kinds while no operator pod can answer. The operator pod reports ready only once its webhook server runs, so a rollout does not reject requests.- With
certManager.enabled: true, cert-manager must run in the cluster: the chart has it issue the serving certificate and inject its CA into the webhook configuration. - To bring your own certificate, set
certManager.enabled: false, create a TLS Secret with the serving certificate and key, and setcaBundleto the base64-encoded CA bundle; the chart refuses to render without it. For the release on this page, the Secret is namedmonedula-gitops-webhook-serving-certunless you setcertSecretName, and the certificate must be valid formonedula-gitops-webhook.monedula-system.svc.
Reconciliation
resyncInterval(empty, so the operator default5mapplies; minimum30s): how often every resource is re-checked without a change in Git. It bounds how long an out-of-band broker change goes undetected and uncorrected, and how long a resource that lost a duplicate-identity contest waits after the winner is deleted. Each reconcile reads live state from Kafka, so at hundreds of resources this is the main load lever.maxConcurrentReconciles(empty, so1): how many reconciles of one kind run in parallel. Values above 1 needleaderElection.enabled: true; otherwise the chart refuses to render and the operator refuses to start, with exit code 2. Writers on the same cluster’s ACLs, and on the same cluster’s role bindings, still run one at a time, so a higher value helps installs with several Kafka clusters or many quotas and users, and not hundreds of topics on one cluster.leaderElection.enabled(defaulttrue): only one replica is active at a time. WithreplicaCountabove its default of 1, the extra replicas wait as standbys.
A KafkaCluster that is created after the resources that reference it, or whose spec changes, re-reconciles those resources at once, without waiting for the resync.
Resolve every KafkaCluster from one namespace
By default the operator looks up the KafkaCluster that a resource references in the resource’s own namespace:
clusterNamespace: "" # --cluster-namespace; empty = resolve KafkaCluster in the resource's own namespace
For several teams on shared clusters, set clusterNamespace to a namespace that only the cluster owners can write to, and keep every KafkaCluster there with the Secrets it references, which the operator reads from the cluster’s own namespace. Every clusterRef then resolves to these central objects, and a KafkaCluster that a team creates in its own namespace is never used. A tenancy policy on each KafkaCluster limits which namespaces may use it, as Enforce tenancy with admission webhooks shows.
Represent each Kafka cluster by exactly one KafkaCluster object. Several KafkaCluster objects for the same brokers each get their own view of the cluster’s ACLs and role bindings, and with pruning on they delete each other’s grants.
Read credentials from Kubernetes Secrets
Every credential in an operator KafkaCluster is a valueFrom.secretKeyRef (Connect to a secured Kafka cluster shows one). Label each credential Secret with gitops.monedula.dev/credential-source: "true":
apiVersion: v1
kind: Secret
metadata:
name: kafka-creds
labels:
gitops.monedula.dev/credential-source: "true"
type: Opaque
stringData:
username: svc-monedula
password: change-me
When a labeled Secret changes, the operator reconciles the KafkaCluster that references it, and the topics, policies, quotas and role bindings on that cluster, at once. Without the label, a rotated credential takes effect at the next resync, and the KafkaCluster reports the condition CredentialSourceUnwatched with the status True. The same label makes a KafkaUser pick up a changed password Secret at once. The values above are placeholders; create the real Secret from your secrets manager.
For workload identity, such as IRSA on EKS, GKE Workload Identity or Azure Workload Identity, add its annotations to the operator’s service account with serviceAccount.annotations. The chart creates the service account (serviceAccount.create: true), named after the chart’s full name, monedula-gitops for the release on this page, unless you set serviceAccount.name.
Expose metrics
The operator serves Prometheus metrics through a Service (metrics.service.enabled: true, metrics.service.port: 8080):
| Metric | Labels | Meaning |
|---|---|---|
monedula_reconcile_total |
controller, result (success or error) |
Reconcile runs. |
monedula_reconcile_errors_total |
controller |
Reconcile runs that returned an error. |
monedula_reconcile_duration_seconds |
controller |
Reconcile duration, as a histogram. |
monedula_kafka_cluster_reachable |
namespace, name |
1 while the KafkaCluster is reachable, else 0. |
monedula_kafka_topic_drift_detected, monedula_access_policy_drift_detected, monedula_kafka_quota_drift_detected, monedula_kafka_rolebinding_drift_detected, monedula_kafka_user_drift_detected |
namespace, name |
1 while the resource has drift, else 0. A KafkaUser drifts on its username, mechanism or iteration count, never its password. |
monedula_managed_topics, monedula_managed_quotas, monedula_managed_rolebindings, monedula_managed_users |
none | The number of resources of that kind the operator manages. |
monedula_reconcile_terminal_total |
kind, reason |
Outcomes that wait for a person or a spec change, such as TenancyDenied, DuplicateIdentity or MDSNotConfigured. It has no per-resource labels, so it suits alerting. |
metrics.serviceMonitor.enabled: truecreates a Prometheus OperatorServiceMonitor.metrics.serviceMonitor.intervalsets the scrape interval, andrelabelingsandmetricRelabelingsare passed through to it.metrics.secure: trueserves the metrics over HTTPS and requires a bearer token that is authorized for the non-resource URL/metrics. Setmetrics.serviceMonitor.bearerTokenSecretandmetrics.serviceMonitor.tlsConfigto match. Left empty,metrics.serviceMonitor.schemebecomeshttpswhenmetrics.secureis on.
The operator pod
The pod runs as non-root with a read-only root file system, the RuntimeDefault seccomp profile and all capabilities dropped. It requests 50m CPU and 64Mi memory, with limits of 500m and 256Mi, and logs at warn (logLevel: error, warn, info or debug). Placement, image and pass-through values (extraArgs, extraEnv, extraVolumes, extraVolumeMounts) are listed in values.yaml; each extraVolumeMounts entry needs a matching extraVolumes entry, or the chart refuses to render. image.tag defaults to the chart’s app version.
The liveness probe calls /healthz and the readiness probe /readyz on port 8081, where the operator serves both (--health-probe-bind-address, default :8081). The chart fixes that port and has no value for it, so leave --health-probe-bind-address out of extraArgs, or the probes fail.
Check it worked
After an install or upgrade, Helm prints the chart’s notes, which say whether the admission webhook is enabled. Wait for the rollout:
kubectl -n monedula-system rollout status deploy/monedula-gitops
If the rollout does not finish, read the operator logs:
kubectl -n monedula-system logs deploy/monedula-gitops
With cert-manager, a pod that stays in ContainerCreating usually waits for its serving certificate: check that cert-manager is healthy.
Related
- The operator command reference lists the flags that these values set.