Upgrade a Plone RelStorage PostgreSQL Database in Docker Swarm#
For over 7 years we are running Plone now on PostgreSQL, primary in a Docker Swarm environment.
Here a short How-To update major versions.
Attention: Always BACKUP FIRST!
Strategy#
I name my current running database container in the Docker Stack here db, the new container with the new version is named db-update.
In our stack I have two databases one with the currently running old version and one with the new version of PostgreSQL.
Additional, I have a storage called maintenance mounted to both containers.
Process is:
- Edit the deployment YAML file and - create a new storage i.e. - /data/project/pg16
- create the new service database with the new version as i.e. - db-updatewith the storage above (do not use the current db storage!)
 
- deploy the new configuration 
- Stop all Plone containers 
- In the current database container export the database to the maintenance storage 
- In the new database container import the previous export 
- Edit the deployment.yaml, - remove the current - dbservice and plus the old storage (also the data on disk)
- rename the service - db-updateto- db
 
- deploy the new configuration 
- DONE 
In Practice#
First on the server create the new data folder
mkdir -p /data/project/pg16
Then edit the deployment.yaml (or whatever the Swarm deployment is named at your place).
Add volumes:
  # existing
  pgdb16:
    driver_opts:
      type: none
      device: /data/project/pgdb16
      o: bind
  # new
  pgdb16:
    driver_opts:
      type: none
      device: /data/project/pgdb16
      o: bind
  maintenance:
    driver_opts:
      type: none
      device: /data/project/maintenance
      o: bind
and a new service for the new database (here a version 16), i.e. like so:
  # existing
  db:
    image: 'postgres:12'
    command: postgres -c max_locks_per_transaction=1024 -c shared_buffers=512MB -c work_mem=8MB -c max_wal_size=512MB
    environment:
      POSTGRES_USER: plone
      POSTGRES_PASSWORD: plone
      POSTGRES_DB: plone
    networks:
      - backend
    volumes:
      - "pgdb12:/var/lib/postgresql/data"
      - "maintenance:/maintenance"
      - type: tmpfs
        target: /dev/shm
        tmpfs:
          size: 256000000
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2GB
      mode: global
      endpoint_mode: dnsrr
  # new
  db-update:
    image: 'postgres:16'
    command: postgres -c max_locks_per_transaction=1024 -c shared_buffers=512MB -c work_mem=8MB -c max_wal_size=512MB
    environment:
      POSTGRES_USER: plone
      POSTGRES_PASSWORD: plone
      POSTGRES_DB: plone
    networks:
      - backend
    volumes:
      - "pgdb16:/var/lib/postgresql/data"
      - "maintenance:/maintenance"
      - type: tmpfs
        target: /dev/shm
        tmpfs:
          size: 256000000
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2GB
      mode: global
      endpoint_mode: dnsrr
Apply the new configuration, like
docker stack deploy -c deployment.yaml
Now stop the Plone containers docker stop PLONE_CONTAINER_ID (multiple times).
After stopping all Plone containers export the database
docker exec -it CURRENT_DB_CONTAINER_ID pg_dump -u plone -d plone /maintenance/upgrade_export.sql`
And import it in the new version of the database:
docker exec -it UPDATE_DB_CONTAINER_ID cat /maintenance/upgrade_export.sql | psql -u plone -d plone
Then edit the deployment.yaml again,
- remove the whole service - dband
- rename the service - db-updateto- db.
- remove the storage - pgdb12.
Apply the new configuration, check if all is up and running!
If so, remove rm -rf /data/project/pgdb12 to get rid of the duplicate data.
Remove the dump too. Do a docker system prune too.
All done.