Odds are you've been tasked with upgrading software from one major release to another at some point. Trust me, I understand how cumbersome and difficult these upgrades can be! Luckily, Crunchy Data has some tested methods to get you upgraded with the least amount of headache possible! For this use case, we’ll be using pg_upgrade. Let’s get started!
This part is critical to a successful and healthy upgrade: read the release notes. Sometimes, even within minor upgrades, additional steps may be required and you won’t know if this is the case unless you read the release notes or risk running into an issue during the upgrade. Usually, you won’t have any extra steps to perform, but sometimes things like rebuilding indexes or changing paths may be needed. Again, be sure to read the release notes to avoid issues when implementing the upgrade.
In this instance, we’ll be using pg_upgrade to upgrade from Crunchy Certified PostgreSQL 11 to Crunchy Certified PostgreSQL 12 on CentOS 7. I choose pg_upgrade due to the upgrade speed. It’s literally done in minutes most of the time. If you’ve already tried to guess where the pg_upgrade binary is located and guessed /usr/pgsql-##/bin, then congratulations! You’re right! pg_upgrade can be found in the same default location that you’ll find initdb, pg_ctl, etc in.
After the appropriate release notes have been read thoroughly, it’s time to get upgrading!
Stop all connections from the application (or elsewhere) to the database.
Before we get underway with the actual pg_upgrade command and implementation, let us go ahead and take a backup using your favorite backup tool. As a pgBackRest advocate, I would suggest using pgBackRest. Some details on getting pgBackRest setup can be found here.
Now that a backup has been taken, let's stop the cluster by becoming the postgres user and running the following command; Note: if you’ve changed the location of the data directory or binaries for pg, you’ll need to substitute the paths below for your custom paths.
/usr/pgsql-11/bin/pg_ctl -D /var/lib/pgsql/11/data/ -mf stop
After stopping the cluster we can install the new binaries. In this example I’m going to leave the data directory as the default /var/lib/pgsql/##/data.
yum -y install postgresql12-server postgresql12-contrib
With the old cluster still halted, lets initialize the new cluster as the postgres user.
/usr/pgsql-12/bin/initdb -D /var/lib/pgsql/12/data
Once the new cluster is initialized we’ll now run the pg_upgrade command with the -c (check) flag.
time /usr/pgsql-12/bin/pg_upgrade -b /usr/pgsql-11/bin -B /usr/pgsql-12/bin -d /var/lib/postgresql/11/data -D /var/lib/postgresql/12/data -k -c
Some information regarding the flags used above:
-b is the old cluster executable directory
-B is the new cluster executable directory
-d is the old cluster data directory
-D is the new cluster data directory
-k links instead of copying files to the new cluster NOTE: remove this option if you need to keep a local copy of the old cluster's data files. This will increase the time it takes the upgrade to run as well as the size of the cluster on disk. You can NOT go back after using -k. Please be sure that you have enough disk space for 2 whole copies of the cluster if you do NOT use the -k flag.
-c does a "check" only, and doesn't change any data. It will run through numerous consistency checks. Always run your pg_upgrade command with this first.
Additional information regarding pg_upgrade can be found in the documentation.
We’ve trained for this. Let us remove the -c flag and run the upgrade!
time /usr/pgsql-12/bin/pg_upgrade -b /usr/pgsql-11/bin -B /usr/pgsql-12/bin -d /var/lib/postgresql/11/data -D /var/lib/postgresql/12/data -k
After the above is done you should get an output congratulating your success! At this point it will be worthwhile to run the ./analyze_new_cluster.sh script in order to generate stats so the system is usable. You can also wait and vacuum will eventually generate this for you. The former option is typically the best route.
Lastly, if you wish to remove the old cluster’s data files, you can run ./delete_old_cluster.sh as the postgres user.