Preliminary version. The functionality may change, but the basic features will be preserved. Compatibility with future versions is ensured, but may require additional migration actions.

Postgres

Namespaced resource that allows creating the final configuration and serves as the source of truth for the state of a specific deployed postgres service.

Postgres Class Name

The name of the class to which a specific resource will be linked. Deploying the service is impossible without a created Postgres Class.

spec:
  postgresClassName: default

Instance

Section that describes the resources of the service being created. Must pass validation according to the sizingPolicy of the corresponding class

spec:
  instance:
    memory:
      size: 1Gi
    cpu:
      cores: 1
      coreFraction: 50
    persistentVolumeClaim:
      size: 1Gi
      storageClassName: default

Configuration

Section describing the configuration of the postgres service. Must pass validation according to the overridableConfiguration and validations of the corresponding class

spec:
  configuration:
    maxConnections: 300
    sharedBuffers: 128Mi

Type

Service replication type, can be Cluster or Standalone

spec:
  type: Cluster

Cluster

Section describing the topology and replication method of the postgres cluster. Must pass validation according to the allowedTopology of the corresponding class

spec:
  cluster:
    topology: Zonal
    replication: ConsistencyAndAvailability

Postgres Image

Section allowing you to specify a specific postgres version

spec:
  postgresImage:
    type: standard
    version: "17.4"

Supported PostgreSQL Versions

PostgreSQL versions 16 and above are supported.

Our images for running PostgreSQL containers are based on distroless architecture.

Key concepts of each image:

  • Russian locale ru_RU.UTF-8 has been added
  • postgres processes are run under a user with UID 64535

Additionally, images are divided by types (postgresVersion.imageType).

Image Types

There are several types of images:

  • minimal - image without additional PG extensions, only built-in ones.
  • standard - image with additional PG extensions: pgaudit, pgvector and pg-failover-slots.

Users

Section that allows managing postgresql users. The list of structures declaratively reflects the state of service users and with the help of the Postgres Operator controller, will be synchronized in the Reconcile loop. Warning: Removing a list element or changing a name will mean deleting the user in the postgresql service.

spec:
  users:
    - name: test-rw
      hashedPassword: >-
        SCRAM-SHA-256$4096:8LTjDsWOlQ7fnvr0DqRQx0TXMTh6LIyQJow2UnNlsJE=$ZjQi5diDTvn0g7is1ez9qPSGm6SoGezF0FVCZXssDKw=:IEzN8Dz5KcGd1r47thky5XFRhXlIMeoNLNfZtIlGv/8=
      role: rw
#      password: 123
#      storeCredsToSecret: test-rw-creds

User Passwords

For security purposes, by default we use hashed passwords for database access. You can specify a password by yourself in the hashedPassword field in MD5/SCRAM-SHA-256 format, which is natively supported by postgresql. Or specify a plain-text password in the password field and we will automatically mutate it to hashed format. In case you specified plain-text password, you can specify the name of a secret, which will be created to store the password in plain text there, and updated with connection strings for existing logical databases.

Password change occurs by changing one of the fields hashedPassword or password followed by its mutation.

Warning: It is possible to specify a password either in hashed form hashedPassword, or as a plain string password. Warning: Delivery of credentials, when the storeCredsToSecret field is not specified, is the user’s responsibility.

Example user secret fields:

Kind: Secret
name: test-rw-creds
data:
  password: '123'
  test-dsn: 'pgsql:host=d8ms-pg-test-rw;port=5432;dbname=test;user=test-ro;password=123'
  username: test-rw

Roles

To manage user roles, we offer a set of pre-created roles:

  • rw - role that allows reading, writing, changing table schema within a logical database. Owns all logical databases
  • ro - role that only allows reading from logical database tables.
  • monitoring - allows collecting metrics from system tables, corresponds to the built-in pg_monitor role

Pre-created roles work globally for all logical databases within one deployed service.

Databases

Section that allows managing postgresql logical databases. The list of structures declaratively reflects the state of service logical databases and with the help of the Postgres Operator controller, will be synchronized in the Reconcile loop. Warning: Removing a list element or changing a name will mean deleting the database and ALL DATA of this database in the postgres service.

spec:
  databases:
  - name: "test"

Status

The status of the Managed Postgres service is reflected in the Postgres resource. The Conditions structure clearly shows the current status of the service

Significant types:

  • LastValidConfigurationApplied - Aggregating type that shows whether the last valid configuration was successfully applied at least once.
  • ConfigurationValid - shows whether the configuration passed all validations of the associated Postgres Class.
  • ScaledToLastValidConfiguration - shows whether the number of running replicas matches the specified configuration.
  • Available - shows whether the master replica of the service is running and accepting connections.
  • UsersSynced - shows whether all users have been synchronized and brought to the described state.
  • DatabasesSynced - shows whether all logical databases have been synchronized and brought to the described state.
conditions:
    - lastTransitionTime: '2025-09-22T23:20:36Z'
      observedGeneration: 2
      status: 'True'
      type: Available
    - lastTransitionTime: '2025-09-22T14:38:04Z'
      observedGeneration: 2
      status: 'True'
      type: ConfigurationValid
    - lastTransitionTime: '2025-09-22T14:38:06Z'
      observedGeneration: 2
      status: 'True'
      type: DatabasesSynced
    - lastTransitionTime: '2025-09-22T14:38:47Z'
      observedGeneration: 2
      status: 'True'
      type: LastValidConfigurationApplied
    - lastTransitionTime: '2025-09-22T23:20:36Z'
      observedGeneration: 2
      status: 'True'
      type: ScaledToLastValidConfiguration
    - lastTransitionTime: '2025-09-22T14:38:05Z'
      observedGeneration: 2
      status: 'True'
      type: UsersSynced

Status False indicates a problem at one stage or another or incomplete state synchronization. For such a state, reason and message with description will be specified.

---
    - lastTransitionTime: '2025-09-23T14:53:33Z'
      message: Syncing
      observedGeneration: 1
      reason: Syncing
      status: 'False'
      type: LastValidConfigurationApplied
    - lastTransitionTime: '2025-09-23T14:54:58Z'
      message: Not all the instances are running still waiting for 1 to become ready
      observedGeneration: 1
      reason: ScalingInProgress
      status: 'False'
      type: ScaledToLastValidConfiguration
---

Usage Examples

Basic Usage

  1. Create a namespace named postgres.
  2. Create a Postgres resource
kubectl apply -f managed-services_v1alpha1_postgres.yaml -n postgres
apiVersion: managed-services.deckhouse.io/v1alpha1
kind: Postgres
metadata:
  labels:
    app.kubernetes.io/name: managed-psql-operator
  name: test
spec:
  users:
    - name: test-rw
      password: '123'
      role: rw
  databases:
    - name: "testdb"
  postgresClassName: default
  instance:
    memory:
      size: 4Gi
    cpu:
      cores: 2
      coreFraction: 50
    persistentVolumeClaim:
      size: 10Gi
  type: Cluster
  cluster:
    topology: TransZonal
    replication: ConsistencyAndAvailability
  1. Wait until the cluster is created and all conditions are True:
  kubectl get postgres test -n postgres -o wide -w
  1. To connect, use the psql client and the d8ms-test-rw service
  psql -U test-rw -d testdb -h d8ms-test-rw.postgres.svc -p 5432

Deployment in Standalone Mode

  1. Create a namespace named postgres.
  2. Create a Postgres resource
kubectl apply -f managed-services_v1alpha1_postgres.yaml -n postgres
apiVersion: managed-services.deckhouse.io/v1alpha1
kind: Postgres
metadata:
  labels:
    app.kubernetes.io/name: managed-psql-operator
  name: standalone
spec:
  users:
    - name: test-rw
      password: '123'
      role: rw
  databases:
    - name: "testdb"
  postgresClassName: default
  instance:
    memory:
      size: 4Gi
    cpu:
      cores: 2
      coreFraction: 50
    persistentVolumeClaim:
      size: 10Gi
  type: Standalone
  1. Wait until the cluster is created and all conditions are True:
  kubectl get postgres test -n postgres -o wide -w
  1. To connect, use the psql client and the d8ms-pg-standalone-rw service
  psql -U test-rw -d testdb -h d8ms-pg-standalone-rw.postgres.svc -p 5432

Availability for Use by Another Service in k8s

  1. Create a namespace named postgres.
  2. Create a Postgres resource
kubectl apply -f managed-services_v1alpha1_postgres.yaml -n postgres
apiVersion: managed-services.deckhouse.io/v1alpha1
kind: Postgres
metadata:
  labels:
    app.kubernetes.io/name: managed-psql-operator
  name: availability
spec:
  users:
    - name: test-rw
      password: '123'
      storeCredsToSecret: 'test-rw-creds'
      role: rw
  databases:
    - name: "testdb"
  postgresClassName: default
  instance:
    memory:
      size: 4Gi
    cpu:
      cores: 2
      coreFraction: 50
    persistentVolumeClaim:
      size: 10Gi
  type: Cluster
  cluster:
    topology: TransZonal
    replication: ConsistencyAndAvailability
  1. Wait until the cluster is created:
  kubectl get postgres availability -n postgres -o wide -w
  1. To get the DSN for connecting to the database, use the following command. Or set it as an environment variable in the service pod.
kubectl get secret test-rw-creds -n postgres-ek -o jsonpath='{.data.test-dsn}' | base64 --decode