Skip to content

Upgrade PostgreSQL in HA Deployments#

This section is intended for MSR administrators who manage the PostgreSQL cluster of an MSR deployment with High Availability (HA). It applies to the PostgreSQL cluster deployed with the Zalando Postgres Operator as described in Install highly available PostgreSQL. The procedure explains how to upgrade the Postgres Operator, the Spilo image, and the PostgreSQL major version.

Upgrading PostgreSQL is an on-demand task that you can perform independently of MSR upgrades. Typical reasons to upgrade include:

  • Compatibility with the MSR and Kubernetes versions that you run or plan to run.
  • Features that are available only in a newer PostgreSQL version.

Note

In single-host deployments, MSR manages its internal PostgreSQL database and upgrades it together with MSR.

Before You Upgrade#

  1. Verify that the Compatibility Matrix lists the target combination of MSR, Kubernetes, and Postgres Operator.

    If the matrix does not list your Kubernetes version for your MSR version, upgrade MSR first.

  2. Back up the MSR database:

    kubectl -n <namespace> exec <cluster-name>-0 -- \
        pg_dumpall -U postgres > msr-postgres-backup.sql
    
  3. Verify that the PostgreSQL cluster is healthy. All members must be running, and one member must be the Leader:

    kubectl -n <namespace> exec <cluster-name>-0 -- patronictl list
    
  4. Plan a maintenance window. MSR loses its database connection during parts of the upgrade.

Expected Service Interruption#

Upgrade What happens Impact on MSR
Postgres Operator, 2.x to 2.x The operator pod restarts. If the pod specification changes, the operator rolls the PostgreSQL pods. None, or a brief disconnect if the PostgreSQL pods roll.
Postgres Operator, 1.x to 2.x The Patroni leader state moves from Endpoints to ConfigMaps, and the PostgreSQL pods restart. MSR loses its database connection while the primary pod restarts.
Spilo image The operator rolls the PostgreSQL pods one by one. With replicas, the primary switches over to an updated replica, usually in less than 5 seconds. A brief disconnect with replicas. With a single instance, MSR is unavailable while the pod restarts.
PostgreSQL major version, 17 to 18 The operator runs pg_upgrade on the primary and re-creates the replicas. MSR loses its database connection during the upgrade, and users must log in again.

Upgrade the Postgres Operator and the Spilo Image#

  1. Verify the Zalando Postgres Operator image:

    kubectl -n <operator-namespace> get operatorconfiguration.acid.zalan.do \
        -o=jsonpath='{.items[0].configuration.docker_image}'
    
  2. Identify the installed Postgres Operator version:

    helm list -A --filter postgres-operator
    
  3. Perform the upgrade for the installed Postgres Operator version. The helm upgrade command upgrades the Postgres Operator and sets the Spilo image in the configGeneral.docker_image parameter. The operator then replaces the PostgreSQL pods one by one to run the new image:

    Warning

    The helm upgrade commands below do not use --reuse-values. Therefore, each command resets the operator values that it does not set to the chart defaults, including any custom values that you set during installation.

    For example, the upgrade from 1.x to 2.x scales the cluster back by resetting min_instances and max_instances to the chart default -1.

    helm upgrade postgres-operator postgres-operator \
        -n <operator-namespace> \
        --repo https://opensource.zalando.com/postgres-operator/charts/postgres-operator \
        --version 2.0.2 \
        --set configGeneral.docker_image=registry.mirantis.com/msr/spilo:18-4.1-p2-20260907083821
    

    Warning

    Postgres Operator 2.x changes the default of kubernetes_use_configmaps to true, so Patroni keeps the leader state in ConfigMaps instead of Endpoints, which Kubernetes deprecates starting from version 1.33. To avoid a split-brain while a leader Endpoint and a leader ConfigMap exist at the same time, scale the cluster to a single instance before you switch to ConfigMaps. The primary pod restarts during the switch, and MSR is unavailable until it is back.

    For details, see Zalando Postgres Operator documentation: Migrate from v1 to v2.

    1. Upgrade the operator, keep Endpoints, and scale the cluster to one instance:

      helm upgrade postgres-operator postgres-operator \
          -n <operator-namespace> \
          --repo https://opensource.zalando.com/postgres-operator/charts/postgres-operator \
          --version 2.0.2 \
          --set configGeneral.docker_image=registry.mirantis.com/msr/spilo:17-4.0-p3-20260907083821 \
          --set configGeneral.kubernetes_use_configmaps=false \
          --set configGeneral.min_instances=1 \
          --set configGeneral.max_instances=1
      
    2. Wait until the cluster has a single healthy Leader:

      kubectl -n <namespace> exec <cluster-name>-0 -- patronictl list
      
    3. Switch to ConfigMaps:

      helm upgrade postgres-operator postgres-operator \
          -n <operator-namespace> \
          --repo https://opensource.zalando.com/postgres-operator/charts/postgres-operator \
          --version 2.0.2 \
          --set configGeneral.docker_image=registry.mirantis.com/msr/spilo:17-4.0-p3-20260907083821 \
          --set configGeneral.kubernetes_use_configmaps=true \
          --set configGeneral.min_instances=1 \
          --set configGeneral.max_instances=1
      
    4. Verify that the Patroni ConfigMaps exist:

      kubectl -n <namespace> get configmap \
          <cluster-name>-leader <cluster-name>-config <cluster-name>-failover
      
    5. Scale the cluster back to numberOfInstances:

      helm upgrade postgres-operator postgres-operator \
          -n <operator-namespace> \
          --repo https://opensource.zalando.com/postgres-operator/charts/postgres-operator \
          --version 2.0.2 \
          --set configGeneral.docker_image=registry.mirantis.com/msr/spilo:17-4.0-p3-20260907083821
      
    6. Upgrade PostgreSQL to version 18 as described in Upgrade PostgreSQL from Version 17 to 18.

  4. Verify the upgrade as described in Perform the Post-Upgrade Checks.

Upgrade PostgreSQL from Version 17 to 18#

Note

If the manifest defines maintenanceWindows, the operator runs the upgrade only within those windows. For details, see Zalando Postgres Operator documentation: In-place major version upgrade.

  1. You cannot revert the upgrade after pg_upgrade runs. Therefore, back up the MSR database:

    kubectl -n <namespace> exec <cluster-name>-0 -- \
        pg_dumpall -U postgres > msr-postgres-backup.sql
    
  2. Switch the operator to the Spilo 18 image. The PostgreSQL pods restart one by one and continue to run PostgreSQL 17:

    helm upgrade postgres-operator postgres-operator \
        -n <operator-namespace> \
        --repo https://opensource.zalando.com/postgres-operator/charts/postgres-operator \
        --version 2.0.2 \
        --set configGeneral.docker_image=registry.mirantis.com/msr/spilo:18-4.1-p2-20260907083821
    
  3. Wait until all PostgreSQL pods are Running and Ready:

    kubectl -n <namespace> get pods \
        -l application=spilo,cluster-name=<cluster-name>
    
  4. In msr-postgres-manifest.yaml, change the PostgreSQL version from "17" to "18":

    spec:
      postgresql:
        version: "18"
    
  5. Apply the manifest. The operator runs an in-place major version upgrade (pg_upgrade) on the primary and then re-creates the replicas:

    kubectl -n <namespace> apply -f msr-postgres-manifest.yaml
    
  6. Verify the upgrade as described in Perform the Post-Upgrade Checks.

Perform the Post-Upgrade Checks#

  1. Verify that all PostgreSQL pods are Running and Ready:

    kubectl -n <namespace> get pods \
        -l application=spilo,cluster-name=<cluster-name>
    
  2. Verify that the Patroni cluster has one Leader and that all replicas are streaming:

    kubectl -n <namespace> exec <cluster-name>-0 -- patronictl list
    
  3. Verify that the operator uses the expected pod image:

    kubectl -n <operator-namespace> get operatorconfiguration.acid.zalan.do \
        -o=jsonpath='{.items[0].configuration.docker_image}'
    
  4. After an upgrade from Postgres Operator 1.x to 2.x, verify that the Patroni ConfigMaps exist:

    kubectl -n <namespace> get configmap \
        <cluster-name>-leader <cluster-name>-config <cluster-name>-failover
    
  5. After a PostgreSQL major version upgrade, verify that the postgresql resource has the last-major-upgrade-success annotation and that the server reports the new version. A last-major-upgrade-failure annotation means that the upgrade failed:

    kubectl -n <namespace> get postgresql <cluster-name> \
        -o jsonpath='{.metadata.annotations}'
    kubectl -n <namespace> exec <cluster-name>-0 -- \
        psql -U postgres -tc 'SHOW server_version;'
    
  6. Verify that MSR reports all components, including the database, as healthy:

    curl -u admin:<password> https://<msr-host>/api/v2.0/health
    
  7. Log in to MSR, push an image, and pull it back.

Now, you have successfully upgraded PostgreSQL, and MSR is ready to use with the upgraded database.