<?xml version="1.0" encoding="UTF-8" ?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" version="2.0"><channel><title>James Chanco Jr. | CrunchyData Blog</title>
<atom:link href="https://www.crunchydata.com/blog/author/james-chanco-jr/rss.xml" rel="self" type="application/rss+xml" />
<link>https://www.crunchydata.com/blog/author/james-chanco-jr</link>
<image><url>https://www.crunchydata.com/build/_assets/default.png-W4XGD4DB.webp</url>
<title>James Chanco Jr. | CrunchyData Blog</title>
<link>https://www.crunchydata.com/blog/author/james-chanco-jr</link>
<width>256</width>
<height>256</height></image>
<description>PostgreSQL experts from Crunchy Data share advice, performance tips, and guides on successfully running PostgreSQL and Kubernetes solutions</description>
<language>en-us</language>
<pubDate>Tue, 20 Oct 2020 05:00:00 EDT</pubDate>
<dc:date>2020-10-20T09:00:00.000Z</dc:date>
<dc:language>en-us</dc:language>
<sy:updatePeriod>hourly</sy:updatePeriod>
<sy:updateFrequency>1</sy:updateFrequency>
<item><title><![CDATA[ Online Upgrades in Postgres ]]></title>
<link>https://www.crunchydata.com/blog/online-upgrade-in-postgres</link>
<description><![CDATA[ In our previous blog post, we talked about upgrading a PostgreSQL cluster to a new major version with pg_upgrade. But in some instances zero downtime may be essential. ]]></description>
<content:encoded><![CDATA[ <p>In our previous blog post, we talked about <a href=/blog/how-to-perform-a-major-version-upgrade-using-pg_upgrade-in-postgresql>upgrading a PostgreSQL cluster</a> to a new major version with <a href=https://www.postgresql.org/docs/13/pgupgrade.html>pg_upgrade</a>. This can be fast and with little downtime even for large databases, but in some instances zero downtime may be essential for doing a major upgrade. This method is called an "online upgrade" and can be achieved through <a href=https://www.postgresql.org/docs/current/logical-replication.html>logical replication</a>. While logical replication can help to achieve a zero-downtime, online upgrade, there are still some things to consider. For some hands-on experience, you can check out this learning module on <a href=https://learn.crunchydata.com/pg-administration/courses/postgresql-features/logical-replication/>logical replication</a>.<p><a href="https://www.postgresql.org/docs/10/logical-replication.html#:~:text=Logical%20replication%20is%20a%20method,byte%2Dby%2Dbyte%20replication.">Logical replication</a> can be useful if you have a few test databases that you don’t want to replicate to the upgrade destination. This is possible with logical replication, where pg_upgrade is all or nothing.<p>If your database is large, it can take a bit of time to traverse the network. Additionally, this upgrade method is only capable of "per DB" or “per table” replication unlike pg_upgrade. We’ll be going over the former in the steps ahead.<p>There are quite a few preliminary steps needed to set up logical replication for an upgrade. For example, you'll need to change the wal_level in the postgresql.conf to "logical", which will require a restart of the cluster. It's also worth noting that versions of PostgreSQL that are 9.4 or older need a third party extension to install logical replication.<p>Throughout this blog we're going to perform an online upgrade on the "lrtest" database. I'll be doing this on the same system using port 5411 for my PostgreSQL 11.9 version, and 5412 for my PostgreSQL 12.4 version. With those considerations in mind, let's get started.<h2 id=prerequisites-and-configuration-changes><a href=#prerequisites-and-configuration-changes>Prerequisites and Configuration Changes</a></h2><p>Create <dfn>Primary Keys</dfn> (<abbr>PKs</abbr>) if you don't already have PKs in use for each table that you plan to replicate. This query shows you which tables DON’T have primary keys. This should show 0 tables before you start the upgrade.<pre><code class=language-pgsql>psql -U postgres -d lrtest -p 5411

psql (11.9)
Type "help" for help.

SELECT
  n.nspname as schema,
  c.relname as table
FROM
  pg_class c
JOIN
  pg_namespace n
ON n.oid = c.relnamespace
WHERE
  c.relkind = 'r'
AND NOT EXISTS (
  SELECT 1
  FROM pg_constraint con
  WHERE con.conrelid = c.oid
  AND con.contype = 'p'
)
AND n.nspname &#60> ALL (
  ARRAY [
	'pg_catalog',
	'sys',
	'dbo',
	'information_schema'
  ]
);
 schema | table
--------+-------
(0 rows)
</code></pre><p>If you don't get a value of 0 rows here, stop and solve for that by creating PKs on your tables. Another important thing to note is that if you’ve tuned your postgresql.conf for memory, max connections, etc., those parameters are not replicated in the logical replication process. As always, it’s incredibly important to test your application on the newest PostgreSQL version and ensure the destination postgresql.conf is tuned appropriately.<p>We need to allow for replication connections. Let’s edit the pg_hba.conf on both nodes (substitute 0.0.0.0/0 to match the appropriate IP/CIDR). Since we’re changing the pg_hba.conf on both nodes, we’ll need to restart both nodes later on. Add the following lines, but keep in mind that the pg_hba.conf is read from top to bottom. In my use case, I’m using “trust”. This means you'll need to place these lines appropriately per the <a href=https://www.postgresql.org/docs/11/auth-pg-hba-conf.html>documentation</a>:<pre><code class=language-txt>local  lrtest  logicalrep  trust
host   lrtest  logicalrep  127.0.0.1/32  md5
</code></pre><p>Since logical replication requires a replication role/user, we’ll create one now. Here, we’ll technically create a “role” with login permissions which is effectively a user. We'll do this on the source cluster.<pre><code class=language-pgsql>psql -U postgres -d lrtest -p 5411

psql (11.9)
Type "help" for help.

CREATE ROLE logicalrep LOGIN REPLICATION ENCRYPTED PASSWORD 'yourpassword';
CREATE ROLE
lrtest=#
</code></pre><p>Do note that depending on your log settings, the password listed here will show in the PostgreSQL logs. I'll also set <code>wal_level</code> to <code>logical</code> before I connect to the <code>lrtest</code> user while I’m still connected.<pre><code class=language-pgsql>ALTER SYSTEM SET wal_level TO logical;
ALTER
</code></pre><h2 id=service-restart><a href=#service-restart>Service Restart</a></h2><p>We’ve updated all of the parameters that will require either a reload or a restart at this point. Let’s restart the database (source) so the config changes are captured. If systemd is in use you can run <code>sudo systemctl restart postgresql-nn</code>, where <code>nn</code> is the version number. In this case I restarted via <code>pg_ctl -D /path/to/data/dir restart -mf</code> since I'm not using systemd.<h2 id=globalschema-dumps><a href=#globalschema-dumps>Global/Schema Dumps</a></h2><p>Next, we want to ensure that all of the necessary global objects like; users, their passwords, tablespaces, etc. are carried over to the destination. In order to do so we <a href=/blog/performing-a-major-postgresql-upgrade-with-pg_dumpall>pg_dumpall</a> to a .sql file. We’ll use this file to restore these objects after the pg_dumpall is completed.<pre><code class=language-pgsql>pg_dumpall -p 5411 -U postgres -g -f /tmp/globals.sql
</code></pre><p>Since in this instance both clusters are on the same node, I don’t have to move the file. If you’re doing this across the WAN, you’ll need to move the globals.sql file to the destination accordingly. Once the file is on the destination node, we can run the following command to add the global objects.<pre><code class=language-pgsql>psql -U postgres -d postgres -p 5412 -f /tmp/globals.sql
SET
SET
SET
CREATE ROLE
ALTER ROLE
psql:/tmp/globals.sql:16: ERROR:  role "postgres" already exists
ALTER ROLE
</code></pre><p>You’ll notice an “ERROR” regarding the Postgres user already existing. You can ignore this. After the dump you can see that the global logicalrep user and password are now present on the destination.<pre><code class=language-pgsql>psql -p 5412 -U postgres -d lrtest

psql (12.4)
Type "help" for help.

table pg_shadow;
  usename   | usesysid | usecreatedb | usesuper | userepl | usebypassrls |           	passwd             	   | valuntil | useconfig
------------+----------+-------------+----------+---------+--------------+-------------------------------------+----------+-----------
 logicalrep |	16399  | f        	 | f    	| t   	  | f        	 | md59bccb4e5d8d0bb18b691d519254b3a68 |      	  |
 postgres   |   	10 | t       	 | t    	| t   	  | t        	 |                                 	   |      	  |
(2 rows)
</code></pre><p>For the source database you want to replicate, run a schema only dump in addition to the above global dump. This will allow us to restore the schema information on the destination.<pre><code class=language-pgsql>pg_dump -Fc -s -d lrtest -p 5411 -U postgres -f /tmp/lrtest_schema.dmp
</code></pre><p>We need to do this step because schema information is <em>not</em> replicated over in logical replication. Keep this in mind should you change schema information on your source with logical replication in place. Next, copy the schema dump to the destination location and restore.<pre><code class=language-pgsql>pg_restore -C -d template1 -p 5412 -U postgres /tmp/lrtest_schema.dmp
</code></pre><h2 id=publicationsubscription-creation><a href=#publicationsubscription-creation>Publication/Subscription creation</a></h2><p>Now that the global objects and schemas are all in place on the destination, we can create the publication by running the following on the source (11.9) cluster. As mentioned above, I’m only upgrading one table, but it’s the only table in the database. If you only wanted to replicate a single table, but had multiple tables in the database, you would pass FOR TABLE, per the documentation.<pre><code class=language-pgsql>psql -p 5411 -U postgres -d lrtest

psql (11.9)
Type "help" for help.

create publication lrtest_pg12_upgrade for all tables;
</code></pre><p>I’m doing the upgrade on the same system, if you’re upgrading across the WAN, you’ll need to amend <code>host=, password=</code> in the single quotes with the rest of the connection string.<pre><code class=language-pgsql>psql -p 5412 -U postgres -d lrtest

psql (12.4)
Type "help" for help.

create subscription lrtest_pg12_upgrade connection 'port=5411 dbname=lrtest user=logicalrep' publication lrtest_pg12_upgrade;

NOTICE:  created replication slot "lrtest_pg12_upgrade" on publisher
CREATE SUBSCRIPTION


\q
</code></pre><h2 id=verification><a href=#verification>Verification</a></h2><p>At this point everything looks good in the logs, but we should verify.<p><strong>To verify the data is present on the destination</strong>:<pre><code class=language-pgsql>psql -p 5412 -U postgres -d lrtest

psql (12.4)
Type "help" for help.

select count(*) from chanco;
 count
-------
   100
(1 row)

\q
</code></pre><p><strong>Verify that number with the number on the source</strong>:<pre><code class=language-pgsql>psql -p 5411 -U postgres -d lrtest

psql (11.9)
Type "help" for help.

select count(*) from chanco;
 count
-------
   100
(1 row)

 \q
</code></pre><p>After verifying the row count matches the source, let’s add a row to check and ensure it carries over from the source to the destination.<p><strong>Create row</strong>:<pre><code class=language-pgsql>psql -p 5411 -U postgres -d lrtest

psql (11.9)
Type "help" for help.

insert into chanco values(default,'crunchydata','8437376045','crunchy data software', 'info@crunchydata.com');
INSERT 0 1

select * from chanco where name = 'crunchydata';
 id  |	name 	   |   phone	|    	company    	    |    	email
-----+-------------+------------+-----------------------+----------------------
 101 | crunchydata | 8437376045 | crunchy data software | info@crunchydata.com
(1 row)

\q
</code></pre><p><strong>Check for row on destination</strong>:<pre><code class=language-pgsql>psql -p 5412 -U postgres -d lrtest

psql (12.4)
Type "help" for help.

select * from chanco where name = 'crunchydata';
 id  |	name 	   |   phone	|    	company    	    |    	email
-----+-------------+------------+-----------------------+----------------------
 101 | crunchydata | 8437376045 | crunchy data software | info@crunchydata.com
(1 row)

select count(*) from chanco;
 count
-------
   101
(1 row)

\q
</code></pre><h2 id=clean-up><a href=#clean-up>Clean up</a></h2><p>The original 100 rows from 11.9, have successfully replicated over to the 12.4 cluster. We’ve even gone a step further by ensuring that post upgrade replication works if a new row is added. At this point with logical replication running, you can leave it in place until you are ready to do the cut-over. If all of your data has been replicated, and you've already done the cut-over, you can drop the subscription.<pre><code class=language-pgsql>psql -p 5412 -U postgres -d lrtest

psql (12.4)
Type "help" for help.

DROP SUBSCRIPTION lrtest_pg12_upgrade;
NOTICE:  dropped replication slot "lrtest_pg12_upgrade" on publisher
DROP SUBSCRIPTION
#
</code></pre><p>Now that the online upgrade procedure has successfully completed, we can remove the old cluster if you no longer need it around.<p>I hope this information has proven useful. Be sure to check the <a href=/blog>Crunchy Data blog</a> often as content is constantly being added, and feel free to stop by and follow us on twitter (<a href=https://twitter.com/crunchydata>@crunchydata</a>) or sign up for our newsletter for additional up to date information on PostgreSQL! ]]></content:encoded>
<category><![CDATA[ Production Postgres ]]></category>
<author><![CDATA[ James.Chanco.Jr.@crunchydata.com (James Chanco Jr.) ]]></author>
<dc:creator><![CDATA[ James Chanco Jr. ]]></dc:creator>
<guid isPermalink="false">https://blog.crunchydata.com/blog/online-upgrade-in-postgres</guid>
<pubDate>Tue, 20 Oct 2020 05:00:00 EDT</pubDate>
<dc:date>2020-10-20T09:00:00.000Z</dc:date>
<atom:updated>2020-10-20T09:00:00.000Z</atom:updated></item>
<item><title><![CDATA[ Getting Started with PostgreSQL Operator 4.3 in OpenShift ]]></title>
<link>https://www.crunchydata.com/blog/getting-started-with-postgresql-operator-4.3-in-openshift</link>
<description><![CDATA[ I’ll guide you through the steps for installing and using the PostgreSQL Operator using the pgo-deployer. The pgo-deployer is included in the PostgreSQL Operator, and is presented in a container. In this guide, I’ll be using OpenShift 4.4.3 but any version on 3.11 or greater will work. ]]></description>
<content:encoded><![CDATA[ <p>The first step of working with any software is getting it installed. Based on your environment, this could be as easy as a one-click installer, or require a manual that's hundreds of pages long with thousands of config bits to tune. Deploying complex applications on Kubernetes and OpenShift can often fall somewhere in the middle. For example, deploying an <a href=https://operatorhub.io/operator/postgresql>Operator on OpenShift</a> can be viewed as an intimidating thing, but it doesn't have to be. Here we're going to walk through the quickest and easiest possible way to get started!<p>Below I’ll guide you through the steps for installing and using the <a href=https://access.crunchydata.com/documentation/postgres-operator/latest>PostgreSQL Operator</a> using the pgo-deployer. The pgo-deployer is included in the PostgreSQL Operator, and is presented in a container. In this guide, I’ll be using OpenShift 4.4.3 but any version on 3.11 or greater will work.<h2 id=confirming-your-environment><a href=#confirming-your-environment>Confirming your environment</a></h2><p>Before you get started, you will need to confirm your environment is set up to deploy the PostgreSQL Operator.<p>You will need an OpenShift environment where:<ul><li>You are running OpenShift v 3.11+<li>You have enough privileges to install an application, i.e. you can add a ClusterRole. If you’re a Cluster Admin, you’re all set<li>There are PersistentVolumes available<li>You can access your OpenShift cluster using oc</ul><h2 id=install-the-postgresql-operator><a href=#install-the-postgresql-operator>Install the PostgreSQL Operator</a></h2><p>To get started we’ll first need to download the PostgreSQL Operator Installer manifest to our OpenShift environment. In this example we’ll do so with the following command:<pre><code class=language-shell>curl https://github.com/CrunchyData/postgres-operator/blob/REL_4_3/installers/kubectl/postgres-operator.yml
</code></pre><p>Note the "REL_4_3" - this is pulling the installer from the PostgreSQL Operator 4.3.x branch. Also note that if you are installing on OpenShift 3.11, you will have to download the installer manifest from as such:<pre><code class=language-shell>curl https://github.com/CrunchyData/postgres-operator/blob/REL_4_3/installers/kubectl/postgres-operator-ocp311.yml > postgres-operator.yml
</code></pre><p>It’s important to review the configuration parameters in detail. In this example, we’ll be using many of the default settings, but there are a number of variables that should be changed. A good example of this would be PGO_ADMIN_PASSWORD. This password is used with the pgo client to manage your PostgreSQL clusters. Changing this from the default of “password” is generally recommended. Additionally, you’ll want to specify your particular storage class. We’ll be using GCE for our instance.<pre><code class=language-yaml>- name: BACKREST_STORAGE
  value: “gce"
- name: BACKUP_STORAGE
  value: 'gce'
- name: PRIMARY_STORAGE
  value: 'gce'
- name: REPLICA_STORAGE
  value: 'gce'
</code></pre><p>All of these changes (password, storage class, etc) should be applied by editing the postgres-operator.yml file that we downloaded in the above steps.<p>Now that we’ve edited our manifest file we can begin installing the PostgreSQL Operator. First, we’ll need to create the pgo namespace. We can do this with the following command:<pre><code class=language-shell>oc create namespace pgo
</code></pre><p>To launch the pgo-deployer container we’ll need to apply the postgres-operator.yml manifest. We can do this with the following command:<pre><code class=language-shell>oc apply -f postgres-operator.yml
</code></pre><p>Next we’ll download the pgo client setup script to help set up the OpenShift environment for using the PostgreSQL Operator.<pre><code class=language-shell>curl https://github.com/CrunchyData/postgres-operator/blob/REL_4_3/installers/olm/install.sh
chmod +x install.sh
</code></pre><p>Once the PostgreSQL Operator has installed successfully, you can then run the install.sh script. This will do a number of different things for you, like creating a subscription to install the operator, and creating a client pod where commands can be executed. This can take a few minutes to complete depending on your OpenShift cluster.<p>While the PostgreSQL Operator is being installed, for ease of using the pgo command line interface, you will need to set up some environmental variables.<p>You can do so with the following command within your RHEL or CentOS system.<pre><code class=language-shell>export PATH="${HOME?}/.pgo/pgo/pgouser"
export PGOUSER="${HOME?}/.pgo/pgo/pgouser"
export PGO_CA_CERT="${HOME?}/.pgo/pgo/client.crt"
export PGO_CLIENT_CERT="${HOME?}/.pgo/pgo/client.crt"
export PGO_CLIENT_KEY="${HOME?}/.pgo/pgo/client.key"
</code></pre><p>If you wish to permanently add these variables to your environment, you can run the following:<pre><code class=language-shell>export PATH="${HOME?}/.pgo/pgo/pgouser"
export PGOUSER="${HOME?}/.pgo/pgo/pgouser"
export PGO_CA_CERT="${HOME?}/.pgo/pgo/client.crt"
export PGO_CLIENT_CERT="${HOME?}/.pgo/pgo/client.crt"
export PGO_CLIENT_KEY="${HOME?}/.pgo/pgo/client.key"
</code></pre><pre><code class=language-shell>source ~/.bashrc
</code></pre><p>NOTE: For macOS users, you must use ~/.bash_profile instead of ~/.bashrc<h2 id=verify-the-installation><a href=#verify-the-installation>Verify the Installation</a></h2><p>Below are a few steps to check if the PostgreSQL Operator is up and running.<p>By default, the PostgreSQL Operator installs into a namespace called pgo. First, see that the the OpenShift Deployment of the Operator exists and is healthy:<pre><code class=language-shell>oc -n pgo get deployments
</code></pre><p>If successful, you should see output similar to this:<pre><code class=language-txt>NAME READY UP-TO-DATE AVAILABLE AGE
postgres-operator 1/1 1 1 16h
</code></pre><p>Next, see if the Pods that run the PostgreSQL Operator are up and running:<pre><code class=language-shell>oc -n pgo get pods
</code></pre><p>If successful, you should see output similar to this:<pre><code class=language-txt>NAME READY STATUS RESTARTS AGE
postgres-operator-56d6ccb97-tmz7m 4/4 Running 0 2m
</code></pre><h2 id=connect-to-the-postgresql-operator><a href=#connect-to-the-postgresql-operator>Connect to the PostgreSQL Operator</a></h2><p>Finally, let’s see if we can connect to the PostgreSQL Operator from the pgo command-line client. In order to communicate with the PostgreSQL Operator API server, you will first need to set up a port forwarding to your local environment.<p>In a new console window, run the following command to set up a port forward:<pre><code class=language-shell>oc -n pgo port-forward svc/postgres-operator 8443:8443
</code></pre><p>Back to your original console window, you can verify that you can connect to the PostgreSQL Operator using the following command:<pre><code class=language-shell>pgo version
</code></pre><p>If successful, you should see output similar to this:<pre><code class=language-txt>pgo client version 4.3.2
pgo-apiserver version 4.3.2
</code></pre><h2 id=have-some-fun---create-a-postgres-cluster><a href=#have-some-fun---create-a-postgres-cluster>Have Some Fun - Create a Postgres Cluster</a></h2><p>The quickstart installation method creates two namespaces that you can deploy your PostgreSQL clusters into called pgouser1 and pgouser2. Let’s create a new Postgres cluster in pgouser1:<pre><code class=language-shell>pgo create cluster -n pgouser1 hippo
</code></pre><p>If successful, you should see output similar to this:<pre><code class=language-txt>created Pgcluster hippo
workflow id 1cd0d225-7cd4-4044-b269-aa7bedae219b
</code></pre><p>This will create a Postgres cluster named hippo. It may take a few moments for the cluster to be provisioned. You can see the status of this cluster using the pgo test command:<pre><code class=language-shell>pgo test -n pgouser1 hippo
</code></pre><p>When everything is up and running, you should set output similar to this:<pre><code class=language-txt>cluster : hippo
Services
        primary (10.97.140.113:5432): UP
Instances
        primary (hippo-594f794476-glt9n): UP
</code></pre><p>Once everything is up and running, we can check to make sure our pgBackRest stanza and backup completed successfully. If successful, we should see “Completed” under the “Status” column.<pre><code class=language-txt>NAME                                     	READY   STATUS  	RESTARTS   AGE
backrest-backup-hippo-pwpwq                 0/1 	Completed   0      	11m
hippo-594f794476-glt9n                   	1/1 	Running 	0      	12m
hippo-backrest-shared-repo-b5d7f8f68-6rl8k  1/1 	Running 	0      	13m
hippo-stanza-create-5v7j4                	0/1 	Completed   0      	12m
</code></pre><p>Awesome! We now have a Postgres primary as well as a successful backup. We can log into the pgBackRest repo and check to make sure by issuing the following command:<pre><code class=language-shell>oc exec -it hippo-backrest-shared-repo-b5d7f8f68-6rl8k -n pgouser1 bash
</code></pre><p>From here, you’ll be able to run your <code>pgbackrest info</code> command to check on the status of the backup.<pre><code class=language-shell>bash-4.2$ pgbackrest info
stanza: db
	status: ok
	cipher: none

	db (current)
    	wal archive min/max (12-1): 000000010000000000000001/000000010000000000000004

    	full backup: 20200511-171705F
        	timestamp start/stop: 2020-05-11 17:17:05 / 2020-05-11 17:17:16
        	wal start/stop: 000000010000000000000002 / 000000010000000000000002
        	database size: 31.0MB, backup size: 31.0MB
        	repository size: 3.7MB, repository backup size: 3.7MB
</code></pre><p>The pgo test command provides the basic information you need to connect to your PostgreSQL cluster from within your OpenShift environment. For more detailed information, you can use the following command:<pre><code class=language-shell>pgo show cluster -n pgouser1 hippo

cluster : hippo (crunchy-postgres-ha:centos7-12.2-4.3.0)
    pod : hippo-594f794476-glt9n (Running) on opensh-c49lw-w-b-k4fb9.c.container-suite.internal (1/1) (primary)
    pvc : hippo
    resources : Memory: 128Mi
    storage : Primary=300M Replica=300M
    deployment : hippo
    deployment : hippo-backrest-shared-repo
    service : hippo - ClusterIP (172.30.62.61)
    labels : crunchy-pgha-scope=hippo crunchy_collect=false deployment-name=hippo pgo-backrest=true pgo-version=4.3.0 pgouser=admin workflowid=e3793de6-3d6c-4278-b37b-8b49f79b076a autofail=true crunchy-pgbadger=false name=hippo pg-cluster=hippo pg-pod-anti-affinity=
</code></pre><h2 id=pgo-cli-commands><a href=#pgo-cli-commands>PGO CLI Commands</a></h2><h3 id=scale-up><a href=#scale-up><code>scale</code> (up)</a></h3><p>We’ve now verified that we have a single Postgres cluster with 1 primary! You’ve likely read through some of the documentation at this point and noticed the <a href=https://github.com/CrunchyData/postgres-operator>Crunchy PostgreSQL Operator</a> also offers High Availability. Let’s scale up our existing cluster and make it so.<p>To create 2 replicas in addition to our existing primary, let’s run the following command on our specify our “hippo” cluster, shall we?<pre><code class=language-shell>pgo scale hippo --replica-count=2 -n pgouser1
</code></pre><p>Here, you’ll be asked if you’re sure you want to proceed. Type “yes” and you’ll get output showing that two Pgreplica’s have been created:<pre><code class=language-txt>created Pgreplica hippo-rkol
created Pgreplica hippo-egzo
</code></pre><p>Very good! At this point we can re-run our pgo show cluster command. We should see additional pods and pvcs for our newly created replicas.<pre><code class=language-txt>cluster : hippo (crunchy-postgres-ha:centos7-12.2-4.3.0)
    pod : hippo-594f794476-glt9n (Running) on opensh-c49lw-w-b-k4fb9.c.container-suite.internal (1/1) (primary)
    pvc : hippo
    pod : hippo-egzo-7d567dc84d-sfqfr (Running) on opensh-c49lw-w-b-k4fb9.c.container-suite.internal (1/1) (replica)
    pvc : hippo-egzo
    pod : hippo-rkol-b69947d99-mr58r (Running) on opensh-c49lw-w-c-hws4x.c.container-suite.internal (1/1) (replica)
    pvc : hippo-rkol
</code></pre><p>The pgo test command now shows the additional PostgreSQL clusters as well.<pre><code class=language-txt>cluster : hippo
    Services
   	 primary (172.30.62.61:5432): UP
   	 replica (172.30.213.187:5432): UP
    Instances
   	 primary (hippo-594f794476-glt9n): UP
   	 replica (hippo-egzo-7d567dc84d-sfqfr): UP
   	 replica (hippo-rkol-b69947d99-mr58r): UP
</code></pre><p>You now have a High Availability cluster with 2 replicas! With automated failover now available, and Pod Affinity to help configure how aggressive automatic self healing of failed primaries should be.<h3 id=scaledown><a href=#scaledown><code>scaledown</code></a></h3><p>With the pgo command you can add and remove replicas as needed. Need to remove a replica because it’s just not needed? No problem! With the Scaledown command we can specify a particular replica to remove. Let’s do it, but first we need to choose a replica. We can do so by querying available replicas with the following command:<pre><code class=language-shell>pgo scaledown hippo -n pgouser1 --query

Cluster: hippo
REPLICA        		 STATUS   	 NODE 		 REPLICATION LAG
hippo-egzo     		 running  	 opensh-c49lw-w-b-k4fb9.c.container-suite.internal           	0 MB
hippo-rkol     		 running  	 opensh-c49lw-w-c-hws4x.c.container-suite.internal           	0 MB
</code></pre><p>For this example we’ll use hippo-egzo as our replica to remove.<pre><code class=language-shell>pgo scaledown hippo -n pgouser1 --target=hippo-egzo
</code></pre><p>For this example we’ll use hippo-egzo as our replica to remove.<pre><code class=language-shell>pgo scaledown hippo -n pgouser1 --target=hippo-egzo
</code></pre><p>Again, you’ll be prompted to confirm your decision. We’re ready to go here, so we’ll type “yes” and proceed.<pre><code class=language-txt>WARNING: Are you sure? (yes/no): yes
deleted replica hippo-egzo
</code></pre><p>If we run our pgo test command again, we’ll now get output without the replica we chose to delete.<pre><code class=language-txt>cluster : hippo
    Services
   	 primary (172.30.62.61:5432): UP
   	 replica (172.30.213.187:5432): UP
    Instances
   	 primary (hippo-594f794476-glt9n): UP
   	 replica (hippo-rkol-b69947d99-mr58r): UP
</code></pre><h3 id=failover-manual><a href=#failover-manual>Failover (manual)</a></h3><p>Thanks to distributed consensus, the PostgreSQL Operator is designed to tolerate automated failover with ease. This is great, but there may be a need to test failovers manually from time to time. With the pgo client, this can be done easily. Let’s prove that here. Just like with the replica scaledown command, let’s query available failover targets and choose one. We’ll take a note of the provided replica here since it will soon switch places with the existing primary.<pre><code class=language-shell>pgo failover -n pgouser1 hippo --query

Cluster: hippo
REPLICA        		 STATUS   	 NODE 		 REPLICATION LAG
hippo-rkol     		 running  	 opensh-c49lw-w-c-hws4x.c.container-suite.internal
0 MB
</code></pre><p>Since we recently scaled down the number of replicas we have, we only see one remaining replica. We’ll choose this replica as our failover target.<pre><code class=language-shell>pgo failover hippo -n pgouser1 --target=hippo-rkol
</code></pre><p>We’ll be asked if we’re sure we want to do this. Again, we’ll type “yes” and a failover Pgtask will be created for us.<p>Running the pgo test command we can now see our old replica, hippo-rkol, is now a primary. Easy!<pre><code class=language-txt>cluster : hippo
    Services
   	 primary (172.30.62.61:5432): UP
   	 replica (172.30.213.187:5432): UP
    Instances
   	 replica (hippo-594f794476-glt9n): UP
   	 primary (hippo-rkol-b69947d99-mr58r): UP
</code></pre><h3 id=labels><a href=#labels>Labels</a></h3><p>Do you have a need to label your PostgreSQL clusters? The Crunchy PostgreSQL Operator allows you to do so easily in the event you need to differentiate between production, UAT, SIT, or DEV environments for example. Let’s create a label for a DEV environment. This will be applied to our “hippo” cluster.<pre><code class=language-shell>pgo label hippo --label=env=development
</code></pre><p>Now if we run our pgo show cluster command, we’ll notice that in the labels section there is an “env=development”. This can be quite useful if you need to group PostgreSQL clusters together based on what they’re used for.<pre><code class=language-txt>labels : workflowid=e3793de6-3d6c-4278-b37b-8b49f79b076a autofail=true crunchy-pgbadger=false crunchy-pgha-scope=hippo name=hippo pg-cluster=hippo pg-pod-anti-affinity= pgo-backrest=true crunchy_collect=false deployment-name=hippo-rkol env=development pgo-version=4.3.0 pgouser=admin
</code></pre><h3 id=creating-backups><a href=#creating-backups>Creating Backups</a></h3><p>When we first deployed the Operator, we took a look at how a stanza is created, and a backup is taken. What if we need to create a backup, manually, after deployment? No problem! The pgo command makes this easy by utilizing pgBackRest. Let’s run a backup.<pre><code class=language-shell>pgo backup -n pgouser1 hippo
</code></pre><p>This will create a Pgtask for pgBackRest. Last time, we connected to the pgBackRest manually and ran the pgbackrest info command to look at our list of available backups. This time, let’s use the pgo command since it’s a quick and easy way to get the same list. In this output, we’ll see the full backup that was taken a day before, when the cluster was deployed, as well as the manually run Incremental.<pre><code class=language-txt>cluster: hippo
storage type: local

stanza: db
	status: ok
	cipher: none

	db (current)
    	wal archive min/max (12-1)

    	full backup: 20200511-171705F
        	timestamp start/stop: 2020-05-11 17:17:05 +0000 UTC / 2020-05-11 17:17:16 +0000 UTC
        	wal start/stop: 000000010000000000000002 / 000000010000000000000002
        	database size: 31.0MiB, backup size: 31.0MiB
        	repository size: 3.7MiB, repository backup size: 3.7MiB
        	backup reference list:

    	incr backup: 20200511-171705F_20200512-132803I
        	timestamp start/stop: 2020-05-12 13:28:03 +0000 UTC / 2020-05-12 13:28:06 +0000 UTC
        	wal start/stop: 000000020000000000000009 / 000000020000000000000009
        	database size: 31.0MiB, backup size: 229.8KiB
        	repository size: 3.7MiB, repository backup size: 27.1KiB
        	backup reference list: 20200511-171705F
</code></pre><h4 id=backup-types><a href=#backup-types>Backup types</a></h4><p>Taking a full backup instead of an incremental is easy. All we have to do here is pass the “--backup-opts” flag and specify “--type=full”. For example:<pre><code class=language-shell>pgo backup -n pgouser1 hippo --backup-opts=”--type=full”
</code></pre><h4 id=backup-schedule-creation><a href=#backup-schedule-creation>Backup schedule creation</a></h4><p>You can just as easily schedule certain types of backups to run on a cron schedule with the create schedule command listed below.<pre><code class=language-shell>pgo create schedule -n pgouser1 hippo --schedule="*/1 * * * *" --schedule-type=pgbackrest --pgbackrest-backup-type=diff
</code></pre><h4 id=backup-schedule-deletion><a href=#backup-schedule-deletion>Backup schedule deletion</a></h4><p>This creates a schedule to run a differential backup every minute. That’s a bit aggressive for some environments and datasets. Let’s delete this schedule to ensure we don’t fill up our pgBackRest repo, shall we?<pre><code class=language-shell>pgo delete schedule -n pgouser1 --schedule -name=hippo-pgbackrest-diff
</code></pre><h3 id=restore-from-backup><a href=#restore-from-backup>Restore from backup</a></h3><p>Having backups is great, and definitely necessary, however, backups without regular restore testing is like not having a backup at all! It’s extremely important to test your backups by restoring them in regular testing. Let’s restore a backup to make sure it restores appropriately.<pre><code class=language-shell>pgo restore -n pgouser1 hippo
</code></pre><p>It’s important to note that the primary will be stopped and recreated. The following prompt ensures you’re aware of this by requesting a “yes” or “no” input.<p>Warning: If currently running, the primary database in this cluster will be stopped and recreated as part of this workflow!<pre><code class=language-shell>WARNING: Are you sure? (yes/no): yes
</code></pre><p>After selecting “yes” we can then check the status of the job by running the following command:<pre><code class=language-shell>oc get job -n pgouser1

NAME                	COMPLETIONS   DURATION   AGE
backrest-backup-hippo   1/1       	18s    	62s
hippo-stanza-create 	1/1       	12s    	133m
restore-hippo-mxrm  	1/1       	35s    	118s
</code></pre><p>Our restore was successful! There are a number of different flags that can be passed in the restore command in order to get your desired result for the restore. More information can be found in the PGO Restore section of our documentation.<h3 id=delete><a href=#delete>Delete</a></h3><p>So we’ve deployed and tested numerous pgo command line examples. The Crunchy PostgreSQL Operator is extremely robust, and has loads of features to experiment with! At this point we’ve walked through the beginning steps, and have a good idea of how to get started. Let’s delete the cluster. In the event you’d like to keep the data, you can always pass the “--keep-data” flag so that the PVC is kept. In this example, we’ll simply delete the data.<pre><code class=language-shell>pgo delete cluster hippo -n pgouser1
</code></pre><p>As usual, we’ll be prompted to confirm our decision.<pre><code class=language-shell>WARNING - This will delete ALL OF YOUR DATA, including backups. Proceed? (yes/no): yes
deleted pgcluster hippo
</code></pre><p>Voila! The cluster is now in the process of being deleted. It may take a few minutes, but you’ll be able to run the following oc commands to ensure the cluster has been deleted successfully.<pre><code class=language-shell>oc get pod -n pgouser1
oc get pvc -n pgouser1
</code></pre><p>If you run the commands before the cluster is actually deleted, you’ll see “terminating” in the status field instead of the following:<pre><code class=language-txt>No resources found in pgouser1 namespace.
</code></pre><hr><p>There is much, much more to do within the Crunchy PostgreSQL Operator. This fundamental guide is only the beginning. If the above functionality was as interesting to you as we hope it was, please visit the official documentation to see what else the Operator has to offer! ]]></content:encoded>
<category><![CDATA[ Kubernetes ]]></category>
<author><![CDATA[ James.Chanco.Jr.@crunchydata.com (James Chanco Jr.) ]]></author>
<dc:creator><![CDATA[ James Chanco Jr. ]]></dc:creator>
<guid isPermalink="false">https://blog.crunchydata.com/blog/getting-started-with-postgresql-operator-4.3-in-openshift</guid>
<pubDate>Tue, 07 Jul 2020 05:00:00 EDT</pubDate>
<dc:date>2020-07-07T09:00:00.000Z</dc:date>
<atom:updated>2020-07-07T09:00:00.000Z</atom:updated></item>
<item><title><![CDATA[ How to Perform a Major Version Upgrade Using pg_upgrade in PostgreSQL ]]></title>
<link>https://www.crunchydata.com/blog/how-to-perform-a-major-version-upgrade-using-pg_upgrade-in-postgresql</link>
<description><![CDATA[ Tested methods for upgrading PostgreSQL software from one major release to another with the least amount of headache. ]]></description>
<content:encoded><![CDATA[ <p>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 help get you upgraded with the least amount of headache possible! For this use case, we’ll be using pg_upgrade. Let’s get started!<p>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.<p>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.<p>After the appropriate release notes have been read thoroughly, it’s time to get upgrading!<p>Before we get underway with the actual pg_upgrade command and implementation, we should take a backup using our favorite backup tool. As a pgBackRest advocate, I would suggest using pgBackRest. Some details on <a href=https://pgbackrest.org/>getting pgBackRest setup can be found here</a>.<p>Now that a backup has been taken, we'll install the PostgreSQL 12 binaries.<pre><code class=language-shell>yum -y install postgresql12-server postgresql12-contrib
</code></pre><p>Let us initialize the new cluster as the postgres user.<pre><code class=language-shell>/usr/pgsql-12/bin/initdb -D /var/lib/pgsql/12/data
</code></pre><p>Stop all connections from the application (or elsewhere) to the database. To do so, become the postgres user and run the following command; Note: if you’ve changed the location of the data directory or binaries for PostgreSQL, you’ll need to substitute the paths below for your custom paths.<pre><code class=language-shell>/usr/pgsql-11/bin/pg_ctl -D /var/lib/pgsql/11/data/ -mf stop
</code></pre><p>Once the new cluster is initialized, and the old cluster is halted we’ll now run the pg_upgrade command with the -c (check) flag.<pre><code class=language-shell>time /usr/pgsql-12/bin/pg_upgrade --old-bindir /usr/pgsql-11/bin --new-bindir /usr/pgsql-12/bin --old-datadir /var/lib/pgsql/11/data --new-datadir /var/lib/pgsql/12/data --link --check
</code></pre><p>Some information regarding the flags used above:<p><code>-b (--old-bindir=bindir)</code> is the old cluster executable directory<p><code>-B (--new-bindir=bindir)</code> is the new cluster executable directory<p><code>-d (--old-datadir=configdir)</code> is the old cluster data directory<p><code>-D (--new-datadir=configdir)</code> is the new cluster data directory<p><code>-k (--link)links</code> 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 <code>-k</code>. Please be sure that you have enough disk space for 2 whole copies of the cluster if you do NOT use the <code>-k</code> flag.<p><code>-c (--check)</code> 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.<p>Additional information regarding pg_upgrade can be found in the documentation.<p>We’ve trained for this. Let us remove the <code>-c (--check)</code> flag and run the upgrade!<pre><code class=language-shell>time /usr/pgsql-12/bin/pg_upgrade --old-bindir /usr/pgsql-11/bin --new-bindir /usr/pgsql-12/bin --old-datadir /var/lib/pgsql/11/data --new-datadir /var/lib/pgsql/12/data --link
</code></pre><p>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.<p>Lastly, if you wish to remove the old cluster’s data files, you can run <code>./delete_old_cluster.sh</code> as the postgres user. ]]></content:encoded>
<category><![CDATA[ Production Postgres ]]></category>
<author><![CDATA[ James.Chanco.Jr.@crunchydata.com (James Chanco Jr.) ]]></author>
<dc:creator><![CDATA[ James Chanco Jr. ]]></dc:creator>
<guid isPermalink="false">https://blog.crunchydata.com/blog/how-to-perform-a-major-version-upgrade-using-pg_upgrade-in-postgresql</guid>
<pubDate>Mon, 09 Dec 2019 04:00:00 EST</pubDate>
<dc:date>2019-12-09T09:00:00.000Z</dc:date>
<atom:updated>2019-12-09T09:00:00.000Z</atom:updated></item></channel></rss>