Skip to content

This is the multi-page printable view of this section. .

Return to the regular view of this page.

Configuration

Describe your environment with config

Pigsty treats Infra & Database as Code. You can describe everything with declarative config Inventory. Which is usually an Ansible Inventory in YAML format: pigsty.yml. But CMDB can also be used as dynamic inventory.

The configure procedure will generate a config according to your environment and input. But it’s OPTIONAL: you can always edit the pigsty.yml file directly as tutorial shows. And there are plenty of templates for your reference.

Inventory
    The main config file of Pigsty, Describe your entire deployment
Configure
    Generate config file according to your input & environment
Tutorial
    Planning your deployment according to business requirements
Template
    Available configuration templates and examples
Security
    Security considerations and best practices for prod deployment
CMDB
    Use PostgreSQL as CMDB instead of local YAML config file

PGSQL
    PostgreSQL Cluster with HA, PITR, IaC, ACL, Monitoring, Pooling
INFRA
    Nginx, Repo, DNS, NTP, Prometheus and Grafana stack for Observability
NODE
    Enroll nodes into the desired state and monitor it, and VIP, HAProxy
ETCD
    Reliable distributed consensus storage (DCS), empowering PGSQL HA
MINIO
    S3 compatible object storage, optional backup storage
REDIS
    High-performance in-memory cache, optional data structure server

1 - Inventory

The main config file for Pigsty

Each pigsty deployment has a corresponding config inventory. It could be stored in a local config file in YAML format, or dynamically generated from CMDB or any ansible compatible format. Pigsty uses one monolith YAML config file by default, which is pigsty.yml, located in the pigsty home directory.

The configure script will generate the pigsty.yml file scaffold with good defaults according to your env and input, but it’s OPTIONAL: you can always edit the pigsty.yml file directly as the tutorial shows.


Structure

The inventory consists of two parts: global vars & multiple groups. You can define new clusters in all.children. And describe infra with global vars: all.vars. Which may look like this:

all:                  # Top-level object: all
  vars: {...}         # Global Parameters
  children:           # Group Definitions
    infra:            # Group Definition: 'infra'
      hosts: {...}        # Group Membership: 'infra'
      vars:  {...}        # Group Parameters: 'infra'
    etcd:    {...}    # Group Definition: 'etcd'
    pg-meta: {...}    # Group Definition: 'pg-meta'
    pg-test: {...}    # Group Definition: 'pg-test'
    redis-test: {...} # Group Definition: 'redis-test'
    # ...

There are plenty of examples under conf/, which can also be used as templates during configure.


Cluster

Each ansible group may represent a cluster, which could be a Node cluster, PostgreSQL cluster, Redis cluster, Etcd cluster, or Minio cluster, etc…

Cluster definition consists of two parts: hosts & vars. You can define cluster members in <cls>.hosts and describe cluster with parameters in <cls>.vars. Here’s an example of a 3-node HA PG cluster:

all:
  children:    # All Groups
    pg-test:   # Group Name
      hosts:   # Group Host (Cluster Membership)
        10.10.10.11: { pg_seq: 1, pg_role: primary } # Host1
        10.10.10.12: { pg_seq: 2, pg_role: replica } # Host2
        10.10.10.13: { pg_seq: 3, pg_role: offline } # Host3
      vars:    # Group Vars (Cluster Parameters)
        pg_cluster: pg-test

The vars in cluster level will override the global vars, and vars in host level will override the cluster vars and global vars.


Parameter

Parameters are key-value pairs that define all entities in the deployment. The key is a string name, and the value can be one of five types: boolean, string, number, array, or object.

And parameters can be set at different levels with the following precedence:

Level Location Description Precedence
CLI Args Command Line via -e cli param arg Highest (5)
Host Vars <group>.hosts.<host> Parameters specific to a single host High (4)
Group Vars <group>.vars Parameters shared by hosts in a group/cluster Medium (3)
Global Vars all.vars Parameters shared by all hosts Low (2)
Defaults <roles>/default/main.yml Role implementation default values Lowest (1)

Here are some examples about parameter precedence:

  • Override the PostgreSQL major version with Playbook CLI Args -e pg_version=16
  • Override pg instance role with Instance Level Parameter pg_role on Host Vars
  • Override pg cluster name with Cluster Level Parameter pg_cluster on Group Vars.
  • Specify global NTP servers with Global Parameter node_ntp_servers on Global Vars
  • If no pg_version is set, pigsty will use the default value from role implementation (18 by default)

Every parameter has a proper default value except for mandatory IDENTITY PARAMETERS; they are used as identifiers and must be set explicitly. Such as pg_cluster, pg_role, and pg_seq in above snippet.

Available parameters vary according to the modules:


Reference

Pigsty has 290+ parameters, check module parameters for details.

Module Section Description Count
INFRA META Pigsty Metadata 4
INFRA CA Self-Signed CA 3
INFRA INFRA_ID Infra Portals & Identity 2
INFRA REPO Local Software Repo 9
INFRA INFRA_PACKAGE Infra Packages 2
INFRA NGINX Nginx Web Server 7
INFRA DNS DNSMASQ Nameserver 3
INFRA PROMETHEUS Prometheus Stack 18
INFRA GRAFANA Grafana Stack 6
INFRA LOKI Loki Logging Service 4
NODE NODE_ID Node Identity Parameters 5
NODE NODE_DNS Node domain names & resolver 6
NODE NODE_PACKAGE Node Repo & Packages 5
NODE NODE_TUNE Node Tuning & Kernel features 10
NODE NODE_ADMIN Admin User & Credentials 7
NODE NODE_TIME Node Timezone, NTP, Crontabs 5
NODE NODE_VIP Node Keepalived L2 VIP 8
NODE HAPROXY HAProxy the load balancer 10
NODE NODE_EXPORTER Node Monitoring Agent 3
NODE PROMTAIL Promtail logging Agent 4
DOCKER DOCKER Docker Daemon 4
ETCD ETCD ETCD DCS Cluster 10
MINIO MINIO MINIO S3 Object Storage 15
REDIS REDIS Redis the key-value NoSQL cache 20
PGSQL PG_ID PG Identity Parameters 11
PGSQL PG_BUSINESS PG Business Object Definition 12
PGSQL PG_INSTALL Install PG Packages & Extensions 10
PGSQL PG_BOOTSTRAP Init HA PG Cluster with Patroni 35
PGSQL PG_PROVISION Create in-database objects 9
PGSQL PG_BACKUP Set Backup Repo with pgBackRest 5
PGSQL PG_ACCESS Exposing service, bind vip, dns 16
PGSQL PG_MONITOR Collect metrics & logs for Postgres 18
PGSQL PG_EXPORTER Remove a Postgres cluster 4

2 - Configure

how to configure pigsty inventory file?

The configure script will generate the pigsty.yml config file inventory with good defaults according to your environment and input. It’s OPTIONAL, you can edit the pigsty.yml directly as the tutorial shows.


Usage

The configure script is an interactive wizard unless -n|--non-interactive is specified.

~/pigsty/configure
./configure
    [-c|--conf <confname>   # [meta|dual|trio|full|app/supa|...]
    [-i|--ip <ip>]          # primary IP address (skip with -s)
    [-v|--version <pgver>   # [18|17|16|15|14|13]
    [-r|--region <region>   # [default|china|europe]
    [-o|--output <file>]    # output config file (default: pigsty.yml)
    [-s|--skip]             # skip IP address probing
    [-x|--proxy]            # write proxy env from environment
    [-n|--non-interactive]  # non-interactively mode
    [-p|--port <port>]      # specify SSH port (only used if set)
Option Description
-c|--conf Generate config from config templates according to this parameter
-i|--ip Replace IP address placeholder 10.10.10.10 with given IP
-v|--version Specify PostgreSQL major version number (13|14|15|16|17|18)
-r|--region Set upstream repo mirror according to region (default|china|europe)
-o|--output Write the generated inventory to this file (pigsty.yml by default)
-x|--proxy Write current proxy env to the config proxy_env
-s|--skip Skip interactive wizard and using default/arg values
-n|--non-interactive Non-interactively mode
-p|--port Specify SSH port (only used if set)

Example

./configure                # if there's only one IP address, otherwise it will ask you for it
./configure -i 10.11.12.13 # just tell the primary IP address explicitly
./configure -c rich -v 16  # use the conf/rich.yml as template, with PG 16 and all extensions
./configure -c app/supa    # use the app/supa template, run self-hosting supabase
./configure -c mssql       # use the babelfish template, run MSSQL compatible PG kernel fork
./configure -c full -s     # use the 4-node sandbox config template, without IP replace & probe
./configure -r china       # use use china mirror instead of default repo

configure output example:

./configure
[vagrant@node-1 pigsty]$ ./configure
configure pigsty v3.7.0 begin
[ OK ] region = china
[ OK ] kernel  = Linux
[ OK ] machine = x86_64
[ OK ] package = rpm,dnf
[ OK ] vendor  = rocky (Rocky Linux)
[ OK ] version = 9 (9.5)
[ OK ] sudo = vagrant ok
[ OK ] ssh = [email protected] ok
[WARN] Multiple IP address candidates found:
    (1) 192.168.121.193	    inet 192.168.121.193/24 brd 192.168.121.255 scope global dynamic noprefixroute eth0
    (2) 10.10.10.11	    inet 10.10.10.11/24 brd 10.10.10.255 scope global noprefixroute eth1
[ IN ] INPUT primary_ip address (of current meta node, e.g 10.10.10.10):
=> 10.10.10.11
[ OK ] primary_ip = 10.10.10.11 (from input)
[ OK ] admin = [email protected] ok
[ OK ] mode = meta (el9)
[ OK ] locale  = C.UTF-8
[ OK ] configure pigsty done
proceed with ./install.yml

Behavior

Config Template

If -c|--conf <template> is specified, it will generate the config file from the specified template. Such as meta, app/supa, etc… If no config template is given, it will use the default 1-node config template meta.

IP Address

If -i|--ip <ipaddr> is specified, it will replace the placeholder 10.10.10.10 in the config template with the given IP address. Otherwise, if the current node has only one IP address, it will be used. If there are multiple IP addresses, it will ask you to input the primary IP address of current node manually.

PostgreSQL Version

If -v|--version is specified, it will use the specified PostgreSQL major version number, range from 13 to 18. If no version is specified, it leaves the pg_version intact, which usually fallbacks to 18 by default.

Region

If -r|--region is specified, it will use the specified region directly. The china mirror will be used where Google services are not accessible.

Proxy Environment

If -x|--proxy is specified, it will write the current proxy environment variables to the config proxy_env. Will be reused during installation. Including: HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, NO_PROXY.

Skip Mode

If -s|--skip is specified, it will skip IP address replacement and ssh sudo privilege check

Non-Interactive Mode

If -n|--non-interactive is specified, this script will not ask you for anything, but you have to specify a primary IP address with -i|--ip <ipaddr> explicitly.

SSH Port

If -p|--port is specified, it will use the specified SSH port instead of the default 22. It is used when your local SSH port is not 22.

Low-End Hardware Optimization

If current node CPU cores ≤ 4, it will use the tiny mode for pg_conf and node_tune to optimize for low-end hardware.

Locale Setting

Pigsty will use C.UTF-8 as the default locale, If:

  • PostgreSQL major version ≥ 17, with built-in local provider (default)
  • OR, Your system supports C.utf8 / C.utf-8 locale (locale -a)

Otherwise, local C will be used by default.

3 - Tutorial

Forge a complex config from scratch

Instead of using configure to generate config, you can write a pigsty config file from scratch manually.

Here is a tutorial to help you to build a complex config file inventory from scratch.


Minimal

This is a minimal working config example, you have to tell pigsty the IP of admin node and infra node.

~/pigsty/pigsty.yml
all:
  children: {infra: {hosts: {10.10.10.10: { infra_seq: 1 }}}}
  vars: { admin_ip: 10.10.10.10 }

This will install INFRA and NODE module on 10.10.10.10 (change to your IP address).

~/pigsty
./install.yml

You’ll have a complete observability stack with node monitoring. But database service is not running yet.


PGSQL & ETCD

To provide PostgreSQL service, you have to define additional groups and install PGSQL & ETCD modules.

~/pigsty/pigsty.yml
all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }, vars: { pg_cluster: pg-meta } }
  vars:
    admin_ip: 10.10.10.10

We add two new groups here: etcd and pg-meta, which defines an 1-node ETCD cluster and a 1-node PGSQL cluster. Recreate everything with ./install.yml, or using these cmd to do incremental steps:

~/pigsty
./etcd.yml  -l etcd      # install etcd module on group etcd
./pgsql.yml -l pg-meta   # install pgsql module on group pg-meta

The PGSQL module depends on ETCD for HA consensus, so make sure to install ETCD module first.


Database & Users

Now we want to customize our postgres database cluster, with users, database, and backups:

~/pigsty/pigsty.yml
all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta ,pgbouncer: true ,roles: [dbrole_admin] ,comment: admin user}
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [vector]}
        node_crontab:
          - '00 01 * * * postgres /pg/bin/pg-backup full'
  vars:
    admin_ip: 10.10.10.10

We define some additional details at the pg-meta cluster level:

  • pg_users: define a new user dbuser_meta with password DBUser.Meta
  • pg_databases: define a new database meta with pigsty CMDB schema and vector extension
  • node_crontab: define crontab that takes a full backup at 1 am every day

Instead of recreating everything with ./install.yml, we make changes incrementally:

~/pigsty
bin/pgsql-user pg-meta dbuser_meta      # create user dbuser_meta on pg-meta
bin/pgsql-db   pg-meta meta             # create database meta on pg-meta
./node.yml -l pg-meta -t node_crontab   # add backup task to crontab on pg-meta

PG VER & Extensions

You can install different major versions of PostgreSQL, and 437+ corresponding extensions.

Let’s install PostgreSQL 16 (instead of default 18) with timescaledb, postgis, and pgvector extensions.

~/pigsty/pigsty.yml
all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - name: dbuser_meta
            password: DBUser.Meta
            pgbouncer: true
            roles: [dbrole_admin]
            comment: pigsty admin user
        pg_databases:
          - name: meta
            baseline: cmdb.sql
            comment: pigsty meta database
            schemas: [pigsty]
            extensions: [ vector, postgis, timescaledb ]           # <--- CREATE EXTENSIONS
        pg_libs: 'timescaledb, pg_stat_statements, auto_explain'   # <--- LOAD EXTENSIONS
        node_crontab:
          - '00 01 * * * postgres /pg/bin/pg-backup full'
  vars:
    admin_ip: 10.10.10.10
    region: default # use local mirror for faster download speed   # <--- default|china|europe
    repo_extra_packages: [ timescaledb, postgis, pgvector, pgsql ] # <--- DOWNLOAD EXTENSIONS
    pg_extensions:       [ timescaledb, postgis, pgvector ]        # <--- INSTALL EXTENSIONS
    pg_version: 16   # PG 17 is the default latest major version   # <--- USE PG 16 VERSION
  • repo_extra_packages: download timescaledb and postgis extensions.
  • pg_libs: preload timescaledb, pg_stat_statements, auto_explain extensions.

Let’s redownload missing packages (PG 16 kernel & extensions), remove the old cluster, and recreate it:

make repo                   # redownload packages
./pgsql-rm.yml -l pg-meta   # remove the old pg-meta cluster (because it is PG18)
./pgsql.yml    -l pg-meta   # recreate the pg-meta cluster with PG16 & extensions

More NODE

We can add 3 more nodes to this deployment.

bin/node-add pg-test

Or add them one by one:

bin/node-add 10.10.10.11
bin/node-add 10.10.10.12
bin/node-add 10.10.10.13

PGSQL HA

Now we want to add a new database cluster pg-test, with 3-node HA setup:

~/pigsty/pigsty.yml
all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }, vars: { pg_cluster: pg-meta } }
    pg-test:
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }
        10.10.10.12: { pg_seq: 2, pg_role: replica  }
        10.10.10.13: { pg_seq: 3, pg_role: replica  }
      vars: { pg_cluster: pg-test }
  vars:
    admin_ip: 10.10.10.10

Pigsty’s working assumption is there’s only ONE postgres instance on each node. There’s no support to run multiple postgres instances on a single node.


Redis Up

Pigsty has optional Redis support, which is used as a cache in front of PostgreSQL.

bin/redis-add redis-ms
bin/redis-add redis-meta
bin/redis-add redis-test

Redis HA setup requires cluster mode, or sentinel infra, check Redis Config for details.


MinIO Up

Pigsty has optional MinIO support, which is used as a backup storage for PostgreSQL.

./minio.yml -l minio

Serious production MinIO deployment usually requires at least 4 nodes with 4 disks each (4N/16D)


Docker Up

Install docker on the infra group:

./docker.yml -l infra

Run PgAdmin

Check the App: Pgadmin for details on how to run pgAdmin with Pigsty. Short version:

./docker.yml -l infra
./app.yml    -l infra -e app=pgadmin

Self-Hosting Supabase

Check the App: Supabase for details on how to run Supabase with Pigsty. Short version:

./configure -c app/supa
./install.yml
./docker.yml
./app.yml

4 - Template

Configuration templates for Pigsty

This directory conf contains pigsty config templates, which will be used during configure procedure.

Config templates can be designated using ./configure -c <conf>, where the conf is a relative path to conf directory (with or without .yml suffix). e.g. the ~/pigsty/conf/rich.yml can be specified as rich

./configure                     # use the meta.yml config template by default
./configure -c meta             # use the meta.yml 1-node template explicitly
./configure -c rich             # use the 1-node template with all extensions & minio
./configure -c slim             # use the minimal 1-node template
./configure -c supabase         # use the Supabase 1-node template
./configure -c app/dify         # use the dify app template

If no -c|--conf is given, the single-node meta config template will be automatically selected by default.


Basic Templates

Here are one-node templates, which provide different features and configurations.

Template Node Description
meta.yml 1 Default 1-node config, pgsql, infra, node, etcd, minimal ext
rich.yml 1 meta + minio + all extensions
slim.yml 1 meta - infra - node monitor, minimal install
fat.yml 1 PG 13-18 packages, and install all extensions for current ver

Exotic Kernel

Using exotic Postgres kernel forks:

Template Node Description
mssql.yml 1 WiltonDB & Babelfish with MSSQL wire-compatibility
polar.yml 1 PolarDB for PostgreSQL with Aurora RAC Flavor
ivory.yml 1 IvorySQL cluster with Oracle compatibility
mysql.yml 1 Halo cluster with MySQL wire-compatibility
mongo.yml 1 FerretDB & DocumentDB with Mongo wire-compatibility
oriole.yml 1 OrioleDB cluster with OLTP enhancement

Multi Node

Template Node Description
dual.yml 2 Semi-HA deployment
trio.yml 3 Standard HA deployment
full.yml 4 Sandbox deployment
safe.yml 4 Security enhancement with delayed replica
simu.yml 36 Production simulation

Applications

Template Description
app/supa.yml Launch 1-node supabase
app/odoo.yml Launch the odoo ERP system
app/dify.yml Launch the dify AI workflow system
app/electric.yml Launch the electric sync engine app

Demo Templates

Template Description
demo/el.yml Config file with all default parameters for EL 8/9/10 systems
demo/debian.yml Config file with all default parameters for debian/ubuntu systems
demo/remote.yml Example config for monitoring a remote pgsql cluster or RDS PG
demo/redis.yml Example config for redis clusters
demo/minio.yml Example config for a 3-node minio clusters
demo/demo.yml Config file for the pigsty public demo
citus.yml Citus cluster example: 1 coordinator and 3 data nodes (4-node)

Build Templates

Template Description
build/oss.yml Building config for EL 8, 9, Debian 12, and Ubuntu 22.04/24.04 OSS
build/pro.yml Building config for EL 7-10, Ubuntu, Debian pro version

5 - Security

Security considerations and best-practices

Pigsty already provides a secure-by-default database authentication and access control model.

It is strong enough for most common scenarios, as long as you follow the security best-practices below.


Confidentiality

Files

Secure your pigsty config file
  • pigsty.yml hold very sensitive information like passwords
  • Limit access to admin/infra nodes to admin/DBA users only
  • Limit access to repo, if you are managing pigsty config with GitOps
Secure your CA private key
  • Generated at ~/pigsty/files/pki/ca/ca.key by default
  • Secure & backup it in a safe place, DON’T THROW IT AWAY!
  • Also consider secure other private keys for various certs

Passwords

DO NOT USE THE DEFAULT PASSWORDs

Always change these default passwords in serious deployment

Change MinIO credentials and pgbackrest references

If you are using MinIO as backup storage, also change these credentials:

Enforce strong pg password with the passwordcheck extension
  • add $lib/passwordcheck to pg_libs to enforce password policy.
  • stronger version: passwordcheck_cracklib
Encrypt remote backup with an encryption algorithm
  • check pgbackrest_repo definition repo_cipher_type
  • cipher_type: aes-256-cbc by default
Use advanced password encryption method for PostgreSQL
  • use pg_pwd_enc default scram-sha-256 instead of legacy md5
  • default behavior is scram-sha-256, md5 is deprecated
Add an expiration date to business user passwords

You can set an expiry date for each user for compliance purposes.

- { name: dbuser_meta , password: Pleas3-ChangeThisPwd ,expire_in: 7300 ,pgbouncer: true ,roles: [ dbrole_admin ]    ,comment: pigsty admin user }
- { name: dbuser_view , password: Make.3ure-Compl1ance  ,expire_in: 7300 ,pgbouncer: true ,roles: [ dbrole_readonly ] ,comment: read-only viewer for meta database }
- { name: postgres     ,superuser: true  ,expire_in: 7300                        ,comment: system superuser }
- { name: replicator ,replication: true  ,expire_in: 7300 ,roles: [pg_monitor, dbrole_readonly]   ,comment: system replicator }
- { name: dbuser_dba   ,superuser: true  ,expire_in: 7300 ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
- { name: dbuser_monitor ,roles: [pg_monitor] ,expire_in: 7300 ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

Don’t forget to refresh these expiry dates periodically with pgsql-user.yml playbook

Don't print password to logs
SET log_statement TO 'none';
ALTER USER "{{ user.name }}" PASSWORD '{{ user.password }}';
SET log_statement TO DEFAULT;

IP Addresses

Bind specific IP addresses for postgres/pgbouncer/patroni
  • The default pg_listen address is 0.0.0.0, which is all IPv4 addresses.
  • Consider using pg_listen: '${ip},${vip},${lo}' to bind to specific addresses for better security.
Do not expose any port to the Internet; except 80/443, the infra portal
  • Grafana/Prometheus are bind to all IP address by default for convenience.
  • You can modify their bind configuration to listen on localhost/intranet IP and expose by Nginx.
  • Redis server are bind to all IP address by default for convenience. You can change redis_bind_address to listen on intranet IP.
  • You can also implement it with the security group or firewall rules.
Limit postgres client access with HBA
  • There’s a security enhance config template: safe.yml
Limit patroni admin access from the infra/admin node

Network Traffic

Access Nginx with SSL and domain names
Secure Patroni REST API with SSL
  • patroni_ssl_enabled is disabled by default
  • Since it affects health checks and API invocation.
  • Note this is a global option, and you have to decide before deployment.
Secure Pgbouncer Client Traffic with SSL
  • pgbouncer_sslmode is disable by default
  • Since it has a significant performance impact.

Integrity

Consistency

Use consistency-first mode for PostgreSQL
  • Use crit.yml templates for pg_conf will trade some availability for the best consistency.
Use node crit tuned template for better consistency
  • set node_tune to crit to reduce dirty page ratio.

  • Enable data checksum to detect silent data corruption.

  • pg_checksum is enabled by default in v3.7.0

  • This can be enabled later, which requires a full cluster scan/stop.

Audit

Enable connection logging for audit
  • Enable log_connections and log_disconnections after the pg cluster bootstrap.
  • Audit incoming sessions; this is enabled in crit.yml by default.

Fat Finger

DO NOT RE-RUN install.yml PLAYBOOK

Running install.yml again will nuke (overwrite) the entire deployment!

RE-RUN pgsql.yml WITH CAUTION

It will OVERWRITE existing PostgreSQL by default before v3.5.

Use pg_safeguard to avoid fat fingers


Availability

Redundancy

Use enough nodes for serious production deployment
  • You need at least three nodes (tolerate one node failure) to achieve production-grade high availability.
  • If you only have two nodes, you can tolerate the failure of the specific standby node.
  • If you have one node, use an external S3/MinIO for cold backup & wal archive storage.
Use multiple infra nodes in serious production deployment
  • Use multiple infra nodes in serious production deployment (e.g., 1~3)
  • Usually, 2 ~ 3 is enough for a large production deployment.
Use enough etcd members and use odd numbers
  • Use enough etcd members and use odd numbers (1,3,5,7).
  • Check ETCD Configuration for details.

Fault Tolerance

Trade off between availability and consistency for PostgreSQL
  • pg_rpo : trade-off between Availability and Consistency
  • pg_rto : trade-off between failure chance and impact

Access

Use VIP, DNS, HAProxy instead of fixed IP
  • Do not access the database directly via a fixed IP address; use VIP, DNS, HAProxy, or their combination.
  • Haproxy will handle the traffic control for the clients in case of failover/switchover.

6 - CMDB

Use PostgreSQL as config inventory

Pigsty allows you to use a database (CMDB) as a dynamic configuration source instead of a static configuration file. You can use the built-in PostgreSQL as config inventory for config management.

With Postgres CMDB, configuration is organized in structured relational tables, which can be easily queried and manipulated using SQL. This allows for easier integration with other systems and tools.


How does it work?

Ansible allows you to use a dynamic inventory script to generate the inventory config on-the-fly.

The idea is to replace static pigsty.yml in ansible.cfg with a dynamic shell script inventory.sh

~/pigsty/ansible.cfg
---
inventory = pigsty.yml
+++
inventory = inventory.sh

The content of inventory.sh is very simple, it will query the PostgreSQL CMDB and retrieve config.

~/pigsty/inventory.sh
psql ${METADB_URL} -AXtwc 'SELECT text FROM pigsty.inventory;'
Util Scripts for CMDB

CMDB Schema

The CMDB baseline schema is shipped with pigsty: files/cmdb.sql And most of the default config templates will use it as example baseline. Which means it can be used by default.

all:
  children:
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_databases:
          - name: meta
            baseline: cmdb.sql  # <--- use this as database schema baseline

Load Config Data

CMDB is empty by default, load config file into the CMDB with the bin/inventory_load script.

Run bin/inventory_load without arguments will load the default pigsty.yml into the default CMDB.

usage: inventory_load [-h] [-p PATH] [-d CMDB_URL]

load config arguments

optional arguments:
  -h, --help            show this help message and exit
  -p PATH, --path PATH  config path, ${PIGSTY_HOME}/pigsty.yml by default
  -d DATA, --data DATA  postgres cmdb pgurl, ${METADB_URL} by default

Use -p to specify the config file path, and -d to specify the CMDB URL.

bin/inventory_load
bin/inventory_load -p conf/demo.yml
bin/inventory_load -p conf/ha/full.yml -d postgresql://dbuser_meta:[email protected]:5432/meta

Switch Inventory

You can switch to dynamic CMDB inventory with:

bin/inventory_cmdb

Which essentially changes the inventory parameter in the ansible.cfg to use the inventory.sh script.