mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-12 23:54:01 +09:00
Seven guides in docs/ were written next to the code and left in the source tree, where no operator looks. The website carries them now, so a second copy here only lets the two drift again: the Backup Classes page had already fallen behind its original. docs/release.md, docs/deprecating-applications.md and the two SeaweedFS runbooks in docs/operations stay. A migration, a bats suite, a workflow or AGENTS.md reads each of them by path, which is the test for keeping a document in this repository. Assisted-by: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
480 lines
26 KiB
YAML
480 lines
26 KiB
YAML
{{- $tlsEnabled := (include "postgres.tls.enabled" .) | eq "true" -}}
|
|
{{- $tlsRequired := (include "postgres.tls.required" .) | eq "true" -}}
|
|
{{- $autoscaling := (include "postgres.autoscaling.active" .) | eq "true" -}}
|
|
---
|
|
apiVersion: postgresql.cnpg.io/v1
|
|
kind: Cluster
|
|
metadata:
|
|
name: {{ .Release.Name }}
|
|
{{- with .Values.bootstrap.newServerName }}
|
|
{{- /* Rendered whether or not the barman plugin is: the CNPG restore driver
|
|
reads it to tell the Cluster its own restore produced from one rendered
|
|
for an earlier restore. */}}
|
|
annotations:
|
|
postgres.cozystack.io/restored-server-name: {{ . | quote }}
|
|
{{- end }}
|
|
spec:
|
|
{{- if $autoscaling }}
|
|
{{- /* Under active autoscaling KEDA owns the runtime count via the /scale
|
|
subresource. The chart SEEDS spec.instances at a constant = max(replicas,
|
|
effectiveMin) (postgres.autoscaling.activeSeed) rather than omitting it, for
|
|
three reasons: (1) with synchronous quorum an omitted field defaults to 1 and
|
|
CNPG's webhook rejects "maxSyncReplicas must be lower than the number of
|
|
instances"; (2) omitting it on an EXISTING cluster's enable/upgrade makes
|
|
three-way merge delete the field, CNPG re-defaults to 1, and every replica +
|
|
its PVC is decommissioned before KEDA re-clones (hours with no read replicas);
|
|
(3) seeding effectiveMin ALONE differs from the else-branch (instances:
|
|
replicas), so a dryRun/transition flip would rebase a staged live count down to
|
|
the bare floor. Seeding max(replicas, effectiveMin) equals the else-branch value
|
|
whenever replicas is staged at/above the floor, so those flips render the same
|
|
value and the live count does not dip; it still never undercuts the quorum floor.
|
|
Because the seed is constant, each reconcile renders the value it rendered last
|
|
time, so the client-side patch is empty and never reverts KEDA's higher live
|
|
value. This holds ONLY under client-side apply, where helm-controller patches
|
|
this CRD from the previous-vs-new rendered manifest and does not consult live
|
|
state (it leaves Helm's threeWayMergeForUnstructured at the default): the
|
|
platform's helm-controller (v1.5.0) defaults to SERVER-SIDE
|
|
apply, which force-owns every rendered field and would revert spec.instances from
|
|
KEDA's live /scale value on every reconcile. (Editing replicas / minReplicas /
|
|
quorum.maxSyncReplicas moves the constant, so that one reconcile DOES patch
|
|
spec.instances to the new seed — a documented floor-change caveat, see values.yaml.)
|
|
The postgres ApplicationDefinition
|
|
therefore forces client-side apply via the annotation
|
|
release.cozystack.io/helm-server-side-apply: "false"
|
|
(packages/system/postgres-rd/cozyrds/postgres.yaml), threaded onto the tenant
|
|
HelmRelease's Install/Upgrade.ServerSideApply in
|
|
pkg/registry/apps/application/rest.go (convertApplicationToHelmRelease) and
|
|
guarded by TestConvertApplicationToHelmRelease_ServerSideApplyOverride.
|
|
(Go-template comment, stripped at render.) */}}
|
|
instances: {{ include "postgres.autoscaling.activeSeed" . }}
|
|
{{- else }}
|
|
{{- /* Static-count path (autoscaling off / dryRun / transition), which renders
|
|
instances: <replicas>. CNPG's webhook rejects the Cluster if maxSyncReplicas
|
|
>= instances; guard the DISABLE case in particular, where an autoscaled +
|
|
sync-quorum cluster runs with instances seeded from effectiveMin while
|
|
replicas may sit at its default, so a naive disable would render an invalid
|
|
count and wedge the HelmRelease. Fail closed with an actionable message.
|
|
(Stripped at render.) */}}
|
|
{{- if le (int .Values.replicas) (int .Values.quorum.maxSyncReplicas) }}
|
|
{{- fail (printf "postgres: replicas (%d) must be greater than quorum.maxSyncReplicas (%d) - CNPG rejects a Cluster whose maxSyncReplicas is not lower than its instance count. Raise replicas above maxSyncReplicas. (If you are disabling autoscaling on a synchronous-quorum cluster, first set replicas to at least the live instance count: kubectl scale cluster.postgresql.cnpg.io/%s --replicas=<live count>, with the HelmRelease suspended.)" (int .Values.replicas) (int .Values.quorum.maxSyncReplicas) .Release.Name) }}
|
|
{{- end }}
|
|
instances: {{ .Values.replicas }}
|
|
{{- end }}
|
|
{{- if and $tlsEnabled .Values.external }}
|
|
# Operator-managed TLS. CNPG auto-generates its own self-signed CA and signs
|
|
# server + client + replication certs from it. The operator's default SAN list
|
|
# already covers the three built-in services (rw/r/ro) in four DNS forms each
|
|
# (bare, .ns, .ns.svc, .ns.svc.<cluster-domain>); only the external hostnames
|
|
# need to be appended via serverAltDNSNames.
|
|
#
|
|
# serverAltDNSNames is mutually exclusive with serverTLSSecret per the CNPG
|
|
# admission webhook, which is why the chart no longer renders a cert-manager
|
|
# chain — the operator owns the chain end-to-end.
|
|
#
|
|
# Trust anchor for clients: the key-free "<release>.tenant-ca" Secret the CA
|
|
# extraction controller publishes, as declared by the sentinel in
|
|
# templates/tenant-projection.yaml. Tenants read that Secret through the
|
|
# core.cozystack.io tenantsecrets API. It is neither <release>-credentials,
|
|
# which is chart-rendered and holds user passwords only, nor CNPG's
|
|
# <release>-ca, which holds the CA private key next to ca.crt.
|
|
#
|
|
# The second name is the per-engine one, meant for SNI routing through a
|
|
# TLS-passthrough listener on the tenant Gateway (*.postgres.<apex>). Both
|
|
# are issued so that a later move between the two hostname schemes reissues
|
|
# no certificate and changes no client's trust anchor; clients still change
|
|
# the host they dial.
|
|
{{- $apex := include "cozy-lib.ns-host-required" . }}
|
|
certificates:
|
|
serverAltDNSNames:
|
|
- {{ printf "%s.%s" .Release.Name $apex }}
|
|
- {{ printf "%s.postgres.%s" .Release.Name $apex }}
|
|
{{- end }}
|
|
{{/*
|
|
s3Credentials points at the operator-supplied Secret when
|
|
backup.s3CredentialsSecret.name is set; otherwise it falls back to the
|
|
chart-managed <release>-s3-creds Secret materialised from s3AccessKey/
|
|
s3SecretKey. The override path keeps credentials out of the Postgres
|
|
CR .spec — the CNPG backup driver uses it on restore.
|
|
*/}}
|
|
{{- $credCfg := default (dict) .Values.backup.s3CredentialsSecret }}
|
|
{{- $credSecretName := $credCfg.name | default (printf "%s-s3-creds" .Release.Name) }}
|
|
{{/*
|
|
Platform-managed default flow (useSystemBucket=true):
|
|
- The chart does NOT render spec.plugins or the barman-cloud
|
|
ObjectStore. The backup-controller's CNPG driver SSA-applies a
|
|
barmancloud.cnpg.io ObjectStore (carrying destinationPath/
|
|
endpointURL/credentials) and SSA-patches the live Cluster's
|
|
spec.plugins to reference it at first BackupJob time, using field
|
|
manager "cozystack-cnpg-backup-driver" with ForceOwnership (see
|
|
internal/backupcontroller/cnpgstrategy_controller.go
|
|
applyClusterPluginBackup). The postgres HelmRelease is applied
|
|
CLIENT-SIDE (release.cozystack.io/helm-server-side-apply: "false",
|
|
for the autoscaler seed invariant), and Helm's client-side patch
|
|
only diffs fields the chart RENDERS (previous-vs-new manifest);
|
|
since the chart never renders spec.plugins under useSystemBucket, a
|
|
subsequent Flux re-render leaves the driver's SSA+ForceOwnership
|
|
patch intact — no tug-of-war on the live Cluster (the two apply on
|
|
disjoint field sets).
|
|
Coordinates come from a single backupStorage values block in
|
|
the backupstrategy-controller chart. This eliminates the
|
|
endpoint-duplication failure mode (an operator switching the
|
|
platform endpoint would otherwise have to update both the
|
|
backupstrategy-controller and this chart).
|
|
- Consequence: WAL archiving via the plugin is not active until the
|
|
first BackupJob has run. WAL accumulates on the local PVC in the
|
|
meantime — fine for small / fresh clusters, but admins of large
|
|
Postgres releases switching mid-flight should run an ad-hoc
|
|
BackupJob immediately after enabling the flag.
|
|
- The chart-emitted <release>-s3-creds Secret is also skipped, so a
|
|
default install no longer leaks placeholder credentials into the
|
|
tenant namespace.
|
|
*/}}
|
|
{{- $destinationPath := .Values.backup.destinationPath }}
|
|
{{- $endpointURL := .Values.backup.endpointURL }}
|
|
{{/*
|
|
accessKeyIDKey/secretAccessKeyKey only apply when an external Secret was
|
|
supplied via backup.s3CredentialsSecret.name. The chart-managed
|
|
<release>-s3-creds Secret materialised by backup-secret.yaml hard-codes
|
|
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY, so applying overrides in
|
|
that mode would point CNPG at non-existent keys and break credential
|
|
reads. Default both names unconditionally and let the override take
|
|
effect only in external-Secret mode.
|
|
*/}}
|
|
{{- $credAccessKey := "AWS_ACCESS_KEY_ID" }}
|
|
{{- $credSecretKey := "AWS_SECRET_ACCESS_KEY" }}
|
|
{{- if $credCfg.name }}
|
|
{{- $credAccessKey = $credCfg.accessKeyIDKey | default "AWS_ACCESS_KEY_ID" }}
|
|
{{- $credSecretKey = $credCfg.secretAccessKeyKey | default "AWS_SECRET_ACCESS_KEY" }}
|
|
{{- end }}
|
|
{{/*
|
|
endpointCA references a Secret carrying the CA bundle the barman-cloud
|
|
plugin should trust. Required when the S3 endpoint serves a self-signed
|
|
certificate (the cozystack default seaweedfs-s3 ingress qualifies). The
|
|
same reference flows into both the backup ObjectStore's
|
|
spec.configuration.endpointCA and the recovery ObjectStore's
|
|
spec.configuration.endpointCA (referenced from externalClusters[].plugin)
|
|
so backup *and* recovery can verify TLS - missing it on the recovery
|
|
side made bootstrap.recovery panic in CNPG's instance-manager.
|
|
*/}}
|
|
{{- $caCfg := default (dict) .Values.backup.endpointCA }}
|
|
{{- $caKey := $caCfg.key | default "ca.crt" }}
|
|
{{/*
|
|
The barman-cloud plugin is chart-wired only when the legacy path has
|
|
real coordinates:
|
|
- backup.enabled=true AND
|
|
- useSystemBucket=false (platform flow lets the CNPG driver SSA-
|
|
patch spec.plugins + the ObjectStore instead) AND
|
|
- destinationPath is non-empty AND either an inline access/secret
|
|
pair is supplied OR an external Secret reference (s3Credentials-
|
|
Secret.name) is set.
|
|
Anything short of that means the user has enabled backup but not yet
|
|
supplied S3 coordinates — wiring the plugin against a half-empty
|
|
ObjectStore would just feed CNPG a broken archive_command. Tenants
|
|
opting into `useSystemBucket: true` keep spec.plugins unset until the
|
|
backup-controller's CNPG driver SSA-patches it on the first BackupJob.
|
|
|
|
The S3/barman settings live in the barmancloud.cnpg.io/ObjectStore CR
|
|
rendered at the bottom of this file (named after the release); the
|
|
Cluster only references it by name. Native spec.backup.barmanObjectStore
|
|
is deprecated in CNPG 1.27 and removed in 1.29. The bare (system-flavor)
|
|
image tags this chart pins still ship the barman-cloud-* binaries the
|
|
native path needs (unlike the `standard` variant keycloak-db pins), but
|
|
the system flavor is deprecated upstream, so this chart moves to the
|
|
plugin as well.
|
|
*/}}
|
|
{{- $hasInlineCreds := and (ne (default "" .Values.backup.s3AccessKey) "") (ne (default "" .Values.backup.s3SecretKey) "") }}
|
|
{{- $hasLegacyCreds := or $hasInlineCreds (ne (default "" $credCfg.name) "") }}
|
|
{{- $renderBarman := and .Values.backup.enabled (not .Values.backup.useSystemBucket) (ne $destinationPath "") $hasLegacyCreds }}
|
|
{{- if $renderBarman }}
|
|
plugins:
|
|
- name: barman-cloud.cloudnative-pg.io
|
|
isWALArchiver: true
|
|
parameters:
|
|
barmanObjectName: {{ .Release.Name }}
|
|
# Pin the WAL-archive S3 prefix explicitly (the plugin would default it
|
|
# to the Cluster name anyway); the driver preserves it on a live cluster.
|
|
# On restore bootstrap.newServerName overrides it with a fresh prefix, so
|
|
# the re-bootstrapped cluster does not archive onto the recovery source.
|
|
serverName: {{ .Values.bootstrap.newServerName | default .Release.Name }}
|
|
{{- end }}
|
|
|
|
{{/*
|
|
bootstrap.enabled + backup.useSystemBucket is unsupported in this
|
|
chart: bootstrap.recovery requires an explicit externalClusters entry
|
|
with destinationPath / endpointURL / s3Credentials, but useSystemBucket
|
|
deliberately leaves the platform coordinates out of values.yaml (they
|
|
live in the backupstrategy-controller chart). Rendering the bootstrap
|
|
block here with empty coordinates would produce a broken cnpg.io
|
|
Cluster CR and a confusing CNPG bootstrap failure.
|
|
|
|
The supported way to restore against the platform bucket is a
|
|
backups.cozystack.io/RestoreJob targeting a fresh Postgres app — the
|
|
backup-controller's CNPG driver SSA-patches the Cluster's
|
|
spec.bootstrap before CNPG sees it. See the BackupClass and Restore
|
|
flow in https://cozystack.io/docs/v1/operations/services/backup-classes/.
|
|
|
|
Fail fast at chart-render time so tenants see the misconfiguration
|
|
immediately rather than during a Postgres bootstrap pod crash loop.
|
|
*/}}
|
|
{{- if and .Values.bootstrap.enabled .Values.backup.useSystemBucket }}
|
|
{{- fail "postgres: bootstrap.enabled=true is incompatible with backup.useSystemBucket=true. Use a backups.cozystack.io/RestoreJob against the cozy-default BackupClass to restore from the system bucket; see https://cozystack.io/docs/v1/operations/services/backup-classes/." }}
|
|
{{- end }}
|
|
{{/*
|
|
The externalClusters bootstrap block below references $credSecretName
|
|
(default <release>-s3-creds) for recovery. That Secret is only
|
|
materialised by backup-secret.yaml when inline creds are present, so a
|
|
legacy-flow bootstrap with no usable credentials would render a cnpg.io
|
|
Cluster whose recovery s3Credentials points at a Secret that never
|
|
exists — CNPG then crash-loops with an opaque "secret not found".
|
|
Fail closed at render time (mirroring the useSystemBucket guard above)
|
|
so the misconfiguration is obvious immediately. useSystemBucket-mode
|
|
restore is the RestoreJob flow, already rejected by the guard above.
|
|
*/}}
|
|
{{- if and .Values.bootstrap.enabled (not .Values.backup.useSystemBucket) (not $credCfg.name) (not $hasInlineCreds) }}
|
|
{{- fail "postgres: bootstrap.enabled=true requires S3 credentials: set backup.s3AccessKey+backup.s3SecretKey, backup.s3CredentialsSecret.name, or backup.useSystemBucket=true (with a backups.cozystack.io/RestoreJob)." }}
|
|
{{- end }}
|
|
{{- if .Values.bootstrap.enabled }}
|
|
bootstrap:
|
|
recovery:
|
|
source: {{ .Values.bootstrap.oldName }}
|
|
{{- if or .Values.bootstrap.recoveryTime .Values.bootstrap.backupID }}
|
|
recoveryTarget:
|
|
{{- with .Values.bootstrap.backupID }}
|
|
backupID: {{ . | quote }}
|
|
{{- end }}
|
|
{{- with .Values.bootstrap.recoveryTime }}
|
|
targetTime: {{ . }}
|
|
{{- end }}
|
|
{{- end }}
|
|
externalClusters:
|
|
- name: {{ .Values.bootstrap.oldName }}
|
|
plugin:
|
|
name: barman-cloud.cloudnative-pg.io
|
|
parameters:
|
|
# References the recovery ObjectStore rendered at the bottom of this
|
|
# file, which carries the source cluster's S3 coordinates. serverName
|
|
# (the source's S3 path prefix) rides on the plugin parameter, not the
|
|
# ObjectStore (the plugin forbids serverName there). It must always be
|
|
# set: the native path defaulted an absent serverName to the external
|
|
# cluster's NAME (= oldName), but the plugin defaults it to the NEW
|
|
# cluster's name — which would read the wrong S3 prefix on restore.
|
|
barmanObjectName: {{ .Release.Name }}-recovery
|
|
serverName: {{ .Values.bootstrap.serverName | default .Values.bootstrap.oldName }}
|
|
{{- end }}
|
|
|
|
resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 4 }}
|
|
|
|
{{- include "postgres.flavorGuard" $ }}
|
|
imageName: {{ include "postgres.imageName" $ }}
|
|
enableSuperuserAccess: true
|
|
{{- if .Values._cluster.scheduling }}
|
|
{{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }}
|
|
{{- if $rawConstraints }}
|
|
{{- $rawConstraints | fromYaml | toYaml | nindent 2 }}
|
|
labelSelector:
|
|
matchLabels:
|
|
cnpg.io/cluster: {{ .Release.Name }}
|
|
{{- end }}
|
|
{{- end }}
|
|
postgresql:
|
|
{{- if $tlsRequired }}
|
|
{{- /*
|
|
CloudNativePG offers TLS (ssl=on) but its built-in last rule, host all all
|
|
all, also accepts plaintext, so a client choosing sslmode=disable gets an
|
|
unencrypted session. User rules go after the operator's fixed rules
|
|
(local peer, streaming_replica cert) and before that default rule, and the
|
|
first match wins, so these two lines make remote sessions TLS-only.
|
|
https://cloudnative-pg.io/documentation/current/postgresql_conf/#the-pg_hba-section
|
|
*/}}
|
|
{{- /*
|
|
Same password method as CloudNativePG's own default rule: md5 before
|
|
PostgreSQL 14 (where password_encryption defaults to md5, and md5 also
|
|
accepts SCRAM verifiers), scram-sha-256 from 14 on.
|
|
pkg/management/postgres/configuration.go in cloudnative-pg.
|
|
*/}}
|
|
{{- $pgMajor := trimPrefix "v" .Values.version | atoi }}
|
|
{{- $authMethod := ternary "md5" "scram-sha-256" (lt $pgMajor 14) }}
|
|
{{- /*
|
|
With ssl turned off, hostssl never matches and the reject rule would refuse
|
|
every remote session; stop with an actionable error instead.
|
|
*/}}
|
|
{{- $sslParam := "" }}
|
|
{{- if and .Values.postgresql .Values.postgresql.parameters }}
|
|
{{- $sslParam = toString (dig "ssl" "" .Values.postgresql.parameters) | lower }}
|
|
{{- end }}
|
|
{{- if has $sslParam (list "off" "false" "0" "no") }}
|
|
{{- fail "postgresql.parameters.ssl is off while tls.required is in effect (external: true or tls.required: true): enable ssl or set tls.required: false" }}
|
|
{{- end }}
|
|
pg_hba:
|
|
- hostssl all all all {{ $authMethod }}
|
|
- host all all all reject
|
|
{{- end }}
|
|
{{- /*
|
|
Preloading is exposed as a closed allowlist rather than through the blocked
|
|
shared_preload_libraries parameter. The parameter is free text and accepts a
|
|
path, so it can point at a writable location; a bare name from this list can
|
|
only resolve inside $libdir, which lives on the read-only image filesystem.
|
|
The names below all ship with the CloudNativePG PostgreSQL image. The enum in
|
|
values.schema.json is the primary guard; this check backs it up for renders
|
|
that bypass schema validation. helm-unittest cannot reach it, since the schema
|
|
rejects first, so hack/check-postgres-preload-allowlist.bats pins it instead.
|
|
*/ -}}
|
|
{{- with .Values.postgresql.sharedPreloadLibraries }}
|
|
{{- $allowedPreload := list "pg_stat_statements" "auto_explain" "pgaudit" "pg_prewarm" }}
|
|
shared_preload_libraries:
|
|
{{- range . }}
|
|
{{- if not (has . $allowedPreload) }}
|
|
{{- fail (printf "SECURITY: shared preload library %q is not allowed. Allowed: %s. Loading a library from an arbitrary path enables code execution inside the instance." . (join ", " $allowedPreload)) }}
|
|
{{- end }}
|
|
- {{ quote . }}
|
|
{{- end }}
|
|
{{- end }}
|
|
parameters:
|
|
{{- $defaults := dict "max_wal_senders" "30" }}
|
|
{{- /*
|
|
PostgreSQL sizes shared_buffers at 128MB whatever the container gets.
|
|
The pool is shared memory, which the kernel cannot reclaim without
|
|
swap, so every page that fills stays charged against the memory limit.
|
|
A full pool is the whole limit on t1.nano and half of it on t1.micro,
|
|
the default preset. A small or idle database never fills it, but a
|
|
dump, index scans over a large table or a replica catching up after a
|
|
failover can, and then the OOM killer takes the instance. Below 512Mi
|
|
the default is therefore a quarter of the memory limit with a 16MB
|
|
floor, capped at the memory request: CloudNativePG rejects a Cluster
|
|
whose shared_buffers exceeds that request. From 512Mi up a quarter
|
|
is at least 128MB, so nothing is
|
|
rendered and PostgreSQL keeps its own default as before. An explicit
|
|
shared_buffers in postgresql.parameters still wins. The limit is read
|
|
through the same cozy-lib helper that fills spec.resources, so presets
|
|
and resources overrides resolve exactly as they do there.
|
|
*/}}
|
|
{{- $resources := include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | fromYaml }}
|
|
{{- with $resources.limits.memory }}
|
|
{{- /* 4194304 is 4Mi, so bytes divided by it is a quarter of the limit in MiB. PostgreSQL reads MB as MiB. */}}
|
|
{{- $quarterMi := div (include "cozy-lib.resources.toFloat" . | float64 | int64) 4194304 }}
|
|
{{- if lt $quarterMi 128 }}
|
|
{{- $requestMi := div (include "cozy-lib.resources.toFloat" $resources.requests.memory | float64 | int64) 1048576 }}
|
|
{{- $_ := set $defaults "shared_buffers" (printf "%dMB" (min $requestMi (max 16 $quarterMi))) }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- $params := merge (dict) .Values.postgresql.parameters $defaults }}
|
|
{{- /* Security: Block parameters that enable arbitrary code execution (shell commands or .so loading) */ -}}
|
|
{{- $dangerousParams := list "archive_command" "restore_command" "ssl_passphrase_command" "archive_cleanup_command" "recovery_end_command" "dynamic_library_path" "local_preload_libraries" "session_preload_libraries" "shared_preload_libraries" }}
|
|
{{- range $key, $value := $params }}
|
|
{{- $normalizedKey := lower $key }}
|
|
{{- if has $normalizedKey $dangerousParams }}
|
|
{{- fail (printf "SECURITY: Parameter '%s' is blocked. This parameter can enable arbitrary code execution and must not be set by tenants." $key) }}
|
|
{{- end }}
|
|
{{ $key }}: {{ $value | toString | quote }}
|
|
{{- end }}
|
|
|
|
minSyncReplicas: {{ .Values.quorum.minSyncReplicas }}
|
|
maxSyncReplicas: {{ .Values.quorum.maxSyncReplicas }}
|
|
|
|
monitoring:
|
|
enablePodMonitor: true
|
|
|
|
storage:
|
|
size: {{ required ".Values.size is required" .Values.size }}
|
|
{{- with .Values.storageClass }}
|
|
storageClass: {{ . }}
|
|
{{- end }}
|
|
|
|
inheritedMetadata:
|
|
labels:
|
|
policy.cozystack.io/allow-to-apiserver: "true"
|
|
app.kubernetes.io/name: postgres.apps.cozystack.io
|
|
app.kubernetes.io/instance: {{ $.Release.Name }}
|
|
---
|
|
apiVersion: cozystack.io/v1alpha1
|
|
kind: WorkloadMonitor
|
|
metadata:
|
|
name: {{ $.Release.Name }}
|
|
labels:
|
|
workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }}
|
|
spec:
|
|
{{- /* Under active autoscaling the desired-replica count is set to the quorum FLOOR
|
|
(effectiveMin), NOT the seeded spec.instances (activeSeed = max(replicas,
|
|
effectiveMin)) and not KEDA's live autoscaled target: the seed is only the
|
|
starting count, KEDA owns the runtime count via /scale and legitimately idles the
|
|
cluster DOWN to effectiveMin under low load. NOTE the health decision does not
|
|
actually read this field today — WorkloadMonitorReconciler gates Status.Operational
|
|
solely on availableReplicas < minReplicas (below), so with minReplicas: 1 an idle
|
|
autoscaled cluster never false-alarms regardless of what replicas says. replicas is
|
|
the declared desired target (see the field doc: "desired number of replicas");
|
|
pinning it to effectiveMin keeps that target honest — the floor KEDA never goes
|
|
below, so should a future reconciler compare desired vs observed it still holds
|
|
actual >= desired, rather than false-flagging every idle-to-floor as the live
|
|
count (or the >floor seed) would. */}}
|
|
replicas: {{ if $autoscaling }}{{ include "postgres.autoscaling.effectiveMin" . }}{{ else }}{{ .Values.replicas }}{{ end }}
|
|
minReplicas: 1
|
|
kind: postgres
|
|
type: postgres
|
|
selector:
|
|
app.kubernetes.io/name: postgres.apps.cozystack.io
|
|
app.kubernetes.io/instance: {{ $.Release.Name }}
|
|
version: {{ $.Chart.Version }}
|
|
{{- if $renderBarman }}
|
|
---
|
|
# Backup ObjectStore for the barman-cloud plugin. Carries the S3/barman
|
|
# settings the deprecated spec.backup.barmanObjectStore used to hold; the
|
|
# Cluster references it by name via spec.plugins above. serverName is
|
|
# intentionally omitted (the plugin forbids it here and defaults it to the
|
|
# cluster name, preserving the s3://.../<cluster>/ layout).
|
|
apiVersion: barmancloud.cnpg.io/v1
|
|
kind: ObjectStore
|
|
metadata:
|
|
name: {{ .Release.Name }}
|
|
spec:
|
|
{{- if .Values.backup.retentionPolicy }}
|
|
retentionPolicy: {{ .Values.backup.retentionPolicy | quote }}
|
|
{{- end }}
|
|
# Size the barman-cloud sidecar explicitly instead of inheriting the tenant
|
|
# LimitRange default of 128Mi, and pin its S3 request checksum (rationale in
|
|
# cozy-lib.barman.sidecarConfiguration).
|
|
{{- include "cozy-lib.barman.sidecarConfiguration" . | nindent 2 }}
|
|
configuration:
|
|
destinationPath: {{ $destinationPath }}
|
|
endpointURL: {{ $endpointURL }}
|
|
{{- if $caCfg.name }}
|
|
endpointCA:
|
|
name: {{ $caCfg.name }}
|
|
key: {{ $caKey }}
|
|
{{- end }}
|
|
s3Credentials:
|
|
accessKeyId:
|
|
name: {{ $credSecretName }}
|
|
key: {{ $credAccessKey }}
|
|
secretAccessKey:
|
|
name: {{ $credSecretName }}
|
|
key: {{ $credSecretKey }}
|
|
{{- end }}
|
|
{{- if .Values.bootstrap.enabled }}
|
|
---
|
|
# Recovery ObjectStore for bootstrap. Points at the source cluster's S3
|
|
# coordinates; referenced from externalClusters[].plugin above. serverName
|
|
# rides on that plugin parameter, not here.
|
|
apiVersion: barmancloud.cnpg.io/v1
|
|
kind: ObjectStore
|
|
metadata:
|
|
name: {{ .Release.Name }}-recovery
|
|
spec:
|
|
# Same sidecar configuration as the backup ObjectStore above.
|
|
{{- include "cozy-lib.barman.sidecarConfiguration" . | nindent 2 }}
|
|
configuration:
|
|
destinationPath: {{ $destinationPath }}
|
|
endpointURL: {{ $endpointURL }}
|
|
{{- if $caCfg.name }}
|
|
endpointCA:
|
|
name: {{ $caCfg.name }}
|
|
key: {{ $caKey }}
|
|
{{- end }}
|
|
s3Credentials:
|
|
accessKeyId:
|
|
name: {{ $credSecretName }}
|
|
key: {{ $credAccessKey }}
|
|
secretAccessKey:
|
|
name: {{ $credSecretName }}
|
|
key: {{ $credSecretKey }}
|
|
{{- end }}
|