Manifest Mapping

Field-by-field mapping from the Zalando CR (acid.zalan.do/v1 postgresql) to CloudNativePG resources (postgresql.cnpg.io/v1).

An automated conversion script, zalando-to-cnpg, ships with the product delivery (operator source repository, hack/zalando-to-cnpg/): it emits a Cluster plus Pooler/Database resources and prints an explicit WARN for every field it cannot map — treat each warning as a checklist item.

Legend: direct = copy; transform = rename/convert; mechanism = different resource or approach; none = no equivalent (the tool warns).

Core

ZalandoCloudNativePGKindNotes
metadata.namemetadata.namedirectNo teamId- prefix rule in CNPG; renaming changes service DNS names.
spec.teamIdnoneConvention only; preserved as a label via inheritedMetadata.
spec.numberOfInstancesspec.instancesdirectZalando 0 (hibernation) → annotation cnpg.io/hibernation: "on", not instances: 0.
spec.dockerImagespec.imageNametransformNever copy — Spilo images are unusable with CNPG. Derive from postgresql.version → PostgreSQL operand image for that major.
spec.postgresql.versionimage majortransformCNPG infers the version from the image.
spec.envspec.envtransformDrop Spilo/WAL-G variables (WAL_S3_BUCKET, USE_WALG_*, AWS_*, …) — backup config moves to the barman-cloud ObjectStore.

Storage and resources

ZalandoCloudNativePGKindNotes
spec.volume.sizespec.storage.sizedirectIn-place growth supported; no shrink (either side).
spec.volume.storageClassspec.storage.storageClassdirect
spec.volume.selectorspec.storage.pvcTemplate.selectortransform
spec.volume.subPath / iops / throughputnoneFixed PGDATA layout; IOPS/throughput were AWS EBS API calls — express via the StorageClass.
spec.additionalVolumesnone (partial)Secrets/ConfigMaps → spec.projectedVolumeTemplate; data volumes → spec.tablespaces / spec.walStorage.
spec.resourcesspec.resourcesdirectIf absent in the Zalando CR, operator-config defaults applied — set explicit values in CNPG.

Users and databases

ZalandoCloudNativePGKindNotes
spec.usersspec.managed.roles[]transformFlags map 1:1 (superuser, createdb, createrole, replication, bypassrls; nologinlogin: false). ⚠ Zalando users are LOGIN by default; CNPG managed roles default login: false — the tool always emits login explicitly.
credential secretsmanaged.roles[].passwordSecretmechanismCNPG expects kubernetes.io/basic-auth secrets. Copy passwords from the Zalando <user>.<cluster>.credentials... secrets to keep application credentials working.
spec.usersWithSecretRotation (+ in-place variant)noneNo automated password rotation.
spec.databasesbootstrap.initdb.{database,owner} + Database CRstransformFirst entry bootstraps the cluster; each additional one becomes a Database resource.
spec.preparedDatabasesDatabase CR (schemas, extensions) + rolestransformThe Zalando auto role hierarchy (<db>_owner/_reader/_writer + default privileges) is not auto-created — synthesize roles and GRANTs (e.g. postInitApplicationSQL).

PostgreSQL configuration

ZalandoCloudNativePGKindNotes
spec.postgresql.parametersspec.postgresql.parameterstransformCopy, minus operator-controlled parameters (the tool strips and warns): archive_*, restore_command, port, hot_standby, recovery targets, ssl*, synchronous_standby_names, shared_preload_libraries (→ dedicated field), listen/log/file-path settings. Tuning parameters (max_connections, shared_buffers, …) all pass through.
spec.patroni.pg_hbaspec.postgresql.pg_hbatransformCNPG prepends fixed rules and appends host all all all scram-sha-256; Zalando's list replaced the whole file. Spilo-specific lines (pam, standby) are stripped.
spec.patroni.initdbspec.bootstrap.initdbtransformencoding/locale/data-checksums map; only relevant for fresh bootstrap.
spec.patroni.synchronous_modespec.postgresql.synchronoustransform{method: any, number: <synchronous_node_count or 1>}; non-strict → dataDurability: preferred, synchronous_mode_strict: truerequired.
spec.patroni.slotsspec.replicationSlotsmechanismHA slots are automatic; permanent logical slots for CDC → Publication/Subscription resources or SQL.
spec.patroni.ttl / loop_wait / retry_timeout / maximum_lag_on_failover / failsafe_modenonePatroni/DCS tuning has no counterpart (related: spec.failoverDelay, spec.probes).

Pooling, services, networking

ZalandoCloudNativePGKindNotes
spec.enableConnectionPoolerseparate Pooler resourcemechanism⚠ Zalando default pool mode is transaction; the CNPG default is session — set pgbouncer.poolMode: transaction explicitly. Zalando default 2 instances vs CNPG 1. Applications repoint to the Pooler service.
spec.enableReplicaConnectionPoolersecond Pooler with type: romechanism
spec.connectionPooler.*Pooler.spec.*transformnumberOfInstancesinstances; modepgbouncer.poolMode; maxDBConnectionspgbouncer.parameters; resources/image → pod template.
spec.enableMasterLoadBalancer / enableReplicaLoadBalancerspec.managed.services.additional[]mechanismAdd {selectorType: rw or ro, serviceTemplate: {spec: {type: LoadBalancer}}} — default services are never mutated; service DNS names change.
spec.allowedSourceRanges…serviceTemplate.spec.loadBalancerSourceRangestransform
spec.serviceAnnotations (+ per-role variants)service templates / inheritedMetadata.annotationstransform
spec.podAnnotationsspec.inheritedMetadata.annotationstransformApplies to all generated objects.

Scheduling and pod attributes

ZalandoCloudNativePGKindNotes
spec.nodeAffinityspec.affinity.nodeAffinitydirectCNPG adds anti-affinity controls (podAntiAffinityType, topologyKey).
spec.tolerationsspec.affinity.tolerationsdirectNote the nesting under affinity.
spec.podPriorityClassNamespec.priorityClassNamedirect
spec.schedulerNamespec.schedulerNamedirect
spec.spiloRunAsUser / spiloRunAsGroup / spiloFSGroupspec.postgresUID / postgresGIDtransformCNPG default uid/gid 26 (Spilo used 101); normally drop.
spec.sidecars / spec.initContainersnoneDeliberately unsupported. Metrics sidecar → built-in exporter; init logic → bootstrap.initdb.postInit*SQL.
spec.maintenanceWindowsnoneClosest: spec.primaryUpdateStrategy: supervised.

Backup, clone, standby, TLS, CDC

ZalandoCloudNativePGKindNotes
spec.enableLogicalBackup + schedulenoneCNPG backups are physical via ScheduledBackup (⚠ 6-field cron — prepend a seconds field). Keep logical dumps as your own CronJob if needed.
spec.clone (no timestamp)spec.bootstrap.pg_basebackup + externalClustersmechanismClone from a live cluster — works against a running Zalando cluster (a supported migration path).
spec.clone (timestamp / s3 fields)bootstrap.recovery + externalClusters[].barmanObjectStoremechanismOnly from a barman-format archive — Spilo WAL-E/WAL-G archives are unreadable by CNPG.
spec.standby (S3 WAL path)noneSame archive incompatibility.
spec.standby (host/port)spec.replica + externalClustersmechanismStreaming standby of an external primary; promote by flipping replica.enabled.
spec.tlsspec.certificatestransformOne-secret model splits into server/client(+replication) certificates; SANs must cover <cluster>-rw.<ns>.svc. Simplest: omit and let CNPG self-manage.
spec.streams (CDC)noneRe-architect on Publication/Subscription resources or external Debezium (wal_level=logical is the CNPG default).

Fork-specific Zalando fields (previous ACP PostgreSQL releases)

Zalando (ACP fork)CloudNativePGNotes
spec.backup (WAL-G schedule/retention/storage)barman-cloud ObjectStore + spec.plugins + ScheduledBackup + retentionPolicyFirst CNPG backup is a fresh full backup.
spec.exporter / enableExporterspec.monitoring (built-in exporter)See the Grafana dashboards guide (How To section).
spec.enablePgpool2PgBouncer Pooler only; query load-balancing ≈ -ro service + app routing.
spec.clusterReplicationspec.replica + externalClusters (+ promotion/demotion tokens)CNPG replica-cluster (distributed topology) model.
spec.usersCustomizedPasswdmanaged.roles[].passwordSecretMove passwords out of the CR into basic-auth secrets.
spec.ipFamilyPreferservice templates ipFamilies/ipFamilyPolicySingle-stack IPv6 requires the url.Build fix in the operator (see Configuration).

Worked example

Zalando source:

apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
  name: acid-orders
spec:
  teamId: acid
  numberOfInstances: 3
  postgresql:
    version: "16"
    parameters:
      shared_buffers: 512MB
      max_connections: "300"
  volume:
    size: 20Gi
    storageClass: sc-topolvm
  users:
    orders_svc: [createdb]
    analyst: []
  databases:
    orders: orders_svc
  patroni:
    pg_hba: [host all all 10.0.0.0/8 md5]
    synchronous_mode: true
    synchronous_node_count: 1
  resources:
    requests: {cpu: "1", memory: 2Gi}
    limits: {cpu: "2", memory: 4Gi}
  enableConnectionPooler: true

Converted (what the tool emits — a Cluster plus a Pooler):

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: acid-orders
spec:
  instances: 3
  imageName: <postgresql-16-operand-image>   # per your platform registry
  inheritedMetadata:
    labels:
      acid.zalan.do/team: acid
  bootstrap:
    initdb:
      database: orders
      owner: orders_svc
  managed:
    roles:
      - {name: analyst, ensure: present, login: true}
      - {name: orders_svc, ensure: present, login: true, createdb: true}
  postgresql:
    parameters:
      shared_buffers: 512MB
      max_connections: "300"
    pg_hba: [host all all 10.0.0.0/8 md5]
    synchronous:
      method: any
      number: 1
      dataDurability: preferred   # synchronous_mode without 'strict'
  storage: {size: 20Gi, storageClass: sc-topolvm}
  resources:
    requests: {cpu: "1", memory: 2Gi}
    limits: {cpu: "2", memory: 4Gi}
---
apiVersion: postgresql.cnpg.io/v1
kind: Pooler
metadata:
  name: acid-orders-pooler-rw
spec:
  cluster: {name: acid-orders}
  type: rw
  instances: 2                   # Zalando default
  pgbouncer:
    poolMode: transaction        # Zalando default (CNPG default is session!)

This exact conversion was verified end-to-end during release qualification: the converted manifests deployed to a healthy 3-instance cluster, with the bootstrap database/owner, role flags, synchronous replication (ANY 1 (...)), parameters, and pg_hba verified by SQL, and writes executed through the Pooler in transaction mode.

What changes for the application:

ZalandoCloudNativePG
write endpointacid-orders.<ns>.svcacid-orders-rw.<ns>.svc (or the Pooler service)
read endpointacid-orders-repl.<ns>.svcacid-orders-ro.<ns>.svc
credentialsorders_svc.acid-orders.credentials... secretacid-orders-app (bootstrap owner) / your basic-auth secrets