In the last post we’ve created a very simple three node PostgreSQL cluster using CloudNativePG and this was really easy to do. While this is great to get started quickly, you usually want to have more control on how PostgreSQL is initialized and configured. In this post we’ll look at bootstrapping the cluster and what options you have for controlling it, when you want to start with an empty cluster.
What we got in the last post was mostly a default configuration. Lets start from scratch by deleting the existing cluster:
1 2 3 4 5 6 7 8 9 10 | minicube@micro-minicube:~> kubectl get cluster -A NAMESPACE NAME AGE INSTANCES READY STATUS PRIMARY default cluster-example 26h 3 3 Cluster in healthy state cluster-example-1 minicube@micro-minicube:~> kubectl delete cluster cluster-example cluster.postgresql.cnpg.io "cluster-example" deleted minicube@micro-minicube:~> kubectl get cluster -A No resources found minicube@micro-minicube:~> kubectl get pods No resources found in default namespace. minicube@micro-minicube:~> |
Instead of using the minimal configuration from the last post, we’ll now use this one to describe our cluster:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | minicube@micro-minicube:~> cat pg.yaml apiVersion: postgresql.cnpg.io /v1 kind: Cluster metadata: name: my-pg-cluster spec: instances: 3 bootstrap: initdb: database: db1 owner: db1 dataChecksums: true walSegmentSize: 32 storage: size: 1Gi |
This is what changed (all under the “initdb” section):
- The name of the cluster
- We want a new database “db1” to be created and this database should be owned by a new user called “db1”
- We want data checksum to be enabled
- Finally we want to change the WAL segment size from the default of 16MB to 32MB
Once we apply this, we of course get the same picture as before for the pods and the services:
1 2 3 4 5 6 7 | minicube@micro-minicube:~> kubectl apply -f pg.yaml cluster.postgresql.cnpg.io /my-pg-cluster created minicube@micro-minicube:~> kubectl get pods NAME READY STATUS RESTARTS AGE my-pg-cluster-1 1 /1 Running 0 119s my-pg-cluster-2 1 /1 Running 0 97s my-pg-cluster-3 1 /1 Running 0 78s |
Lets take one of these pods, start a shell and check what was created:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | minicube@micro-minicube:~> kubectl exec my-pg-cluster-2 -i -t -- /bin/bash Defaulted container "postgres" out of: postgres, bootstrap-controller (init) postgres@my-pg-cluster-2:/$ psql psql (16.2 (Debian 16.2-1.pgdg110+2)) Type "help" for help. postgres= # \l List of databases Name | Owner | Encoding | Locale Provider | Collate | Ctype | ICU Locale | ICU Rules | Access privileges -----------+----------+----------+-----------------+---------+-------+------------+-----------+----------------------- db1 | db1 | UTF8 | libc | C | C | | | postgres | postgres | UTF8 | libc | C | C | | | template0 | postgres | UTF8 | libc | C | C | | | =c /postgres + | | | | | | | | postgres=CTc /postgres template1 | postgres | UTF8 | libc | C | C | | | =c /postgres + | | | | | | | | postgres=CTc /postgres (4 rows) postgres= # |
We got the database and the database is owned by the new user. What we also can see is, the we got “C” for the “Collate” and “Ctype”. This is probably not what you want, so you also need to change this in the initdb section of the cluster definition:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | minicube@micro-minicube:~> cat pg.yaml apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: my-pg-cluster spec: instances: 3 bootstrap: initdb: database: db1 owner: db1 dataChecksums: true walSegmentSize: 32 localeCollate: 'en_US.utf8' localeCType: 'en_US.utf8' storage: size: 1Gi |
Destroy, re-create and check again:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | minicube@micro-minicube:~> kubectl delete -f pg.yaml cluster.postgresql.cnpg.io "my-pg-cluster" deleted minicube@micro-minicube:~> kubectl apply -f pg.yaml cluster.postgresql.cnpg.io /my-pg-cluster created minicube@micro-minicube:~> kubectl get pods NAME READY STATUS RESTARTS AGE my-pg-cluster-1 1 /1 Running 0 55m my-pg-cluster-2 1 /1 Running 0 54m my-pg-cluster-3 1 /1 Running 0 54m minicube@micro-minicube:~> kubectl exec my-pg-cluster-1 -i -t -- /bin/bash Defaulted container "postgres" out of: postgres, bootstrap-controller (init) postgres@my-pg-cluster-1:/$ psql psql (16.2 (Debian 16.2-1.pgdg110+2)) Type "help" for help. postgres= # \l List of databases Name | Owner | Encoding | Locale Provider | Collate | Ctype | ICU Locale | ICU Rules | Access privileges -----------+----------+----------+-----------------+------------+------------+------------+-----------+----------------------- db1 | db1 | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | postgres | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | template0 | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | =c /postgres + | | | | | | | | postgres=CTc /postgres template1 | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | =c /postgres + | | | | | | | | postgres=CTc /postgres (4 rows) postgres= # |
Now we are fine and the size of the WAL segments is as well as we wanted to have it:
1 2 3 4 5 | postgres=# show wal_segment_size; wal_segment_size ------------------ 32MB (1 row) |
Data checksum are enabled:
1 2 | postgres=# \! pg_controldata | grep checksum Data page checksum version: 1 |
We could have changed the encoding, but as the default anyway is “UTF8”, there is no reason to touch this usually.
Another option you have, is to execute SQL commands or whole scripts (via ConfigMaps). A simple example is this one:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | minicube@micro-minicube:~> cat pg.yaml apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: my-pg-cluster spec: instances: 3 bootstrap: initdb: database: db1 owner: db1 dataChecksums: true walSegmentSize: 32 localeCollate: 'en_US.utf8' localeCType: 'en_US.utf8' postInitSQL: - create user db2 - create database db2 with owner = db2 storage: size: 1Gi minicube@micro-minicube:~> kubectl delete -f pg.yaml cluster.postgresql.cnpg.io "my-pg-cluster" deleted minicube@micro-minicube:~> kubectl apply -f pg.yaml cluster.postgresql.cnpg.io/my-pg-cluster created minicube@micro-minicube:~> kubectl exec my-pg-cluster-1 -i -t -- /bin/bash Defaulted container "postgres" out of: postgres, bootstrap-controller (init) postgres@my-pg-cluster-1:/$ psql psql (16.2 (Debian 16.2-1.pgdg110+2)) Type "help" for help. postgres=# \l List of databases Name | Owner | Encoding | Locale Provider | Collate | Ctype | ICU Locale | ICU Rules | Access privileges -----------+----------+----------+-----------------+------------+------------+------------+-----------+----------------------- db1 | db1 | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | db2 | db2 | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | postgres | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | template0 | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | =c/postgres + | | | | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | =c/postgres + | | | | | | | | postgres=CTc/postgres (5 rows) postgres=# |
All this is documented, of course. In the next post we’ll look at how we can configure PostgreSQL, because bootstrapping is one task, but configuring PostgreSQL for your needs is another task you definitely should look at.