This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Pigsty Docs v4.0

PostgreSQL In Great STYle”: Postgres, Infras, Graphics, Service, Toolbox, it’s all Yours.

—— Battery-Included, Local-First PostgreSQL Distribution as an Free & Open-Source RDS

GtiHub | Demo | Blog | Discuss | Discord | DeepWiki | Roadmap | 中文文档

Get Started with the latest release: curl -fsSL https://repo.pigsty.io/get | bash


About: Features | History | Event | Community | Privacy Policy | License | Sponsor | Subscription

Setup: Install | Offline Install | Preparation | Configuration | Playbook | Provision | Security | FAQ

Concept: Architecture | Cluster Model | Monitoring | IaC | HA | PITR | Service Access | Security

Reference: Supported Linux | Fire Hierarchy | Parameters | Playbooks | Ports | Comparison | Cost

Modules: PGSQL | INFRA | NODE | ETCD | MINIO | REDIS | FERRET | DOCKER | APP

1 - PIGSTY

2 - About

Learn about Pigsty itself in every aspect - features, history, license, privacy policy, community events, and news.

2.1 - Features

Pigsty’s value propositions and highlight features.

PostgreSQL In Great STYle”: Postgres, Infras, Graphics, Service, Toolbox, it’s all Yours.

—— Battery-included, local-first PostgreSQL distribution, open-source RDS alternative


Value Propositions


Overview

Pigsty is a better local open-source RDS for PostgreSQL alternative:

  • Battery-Included RDS: From kernel to RDS distribution, providing production-grade PG database services for versions 13-18 on EL/Debian/Ubuntu.
  • Rich Extensions: Providing unparalleled 440+ extensions with out-of-the-box distributed, time-series, geospatial, graph, vector, multi-modal database capabilities.
  • Flexible Modular Architecture: Flexible composition, free extension: Redis/Etcd/MinIO/Mongo; can be used independently to monitor existing RDS/hosts/databases.
  • Stunning Observability: Based on modern observability stack Prometheus/Grafana, providing stunning, unparalleled database observability capabilities.
  • Battle-Tested Reliability: Self-healing high-availability architecture: automatic failover on hardware failure, seamless traffic switching. With auto-configured PITR as safety net for accidental data deletion!
  • Easy to Use and Maintain: Declarative API, GitOps ready, foolproof operation, Database/Infra-as-Code and management SOPs encapsulating management complexity!
  • Solid Security Practices: Encryption and backup all included, with built-in basic ACL best practices. As long as hardware and keys are secure, you don’t need to worry about database security!
  • Broad Application Scenarios: Low-code data application development, or use preset Docker Compose templates to spin up massive software using PostgreSQL with one click!
  • Open-Source Free Software: Own better database services at less than 1/10 the cost of cloud databases! Truly “own” your data and achieve autonomy!

PostgreSQL integrates ecosystem tools and best practices:

  • Out-of-the-box PostgreSQL distribution, deeply integrating 440+ extension plugins for geospatial, time-series, distributed, graph, vector, search, and AI!
  • Runs on bare operating systems without container support, supporting mainstream operating systems: EL 8/9/10, Ubuntu 22.04/24.04, and Debian 12/13.
  • Based on patroni, haproxy, and etcd, creating a self-healing high-availability architecture: automatic failover on hardware failure, seamless traffic switching.
  • Based on pgBackRest and optional MinIO clusters providing out-of-the-box PITR point-in-time recovery, serving as a safety net for software defects and accidental data deletion.
  • Based on Ansible providing declarative APIs to abstract complexity, greatly simplifying daily operations management in a Database-as-Code manner.
  • Pigsty has broad applications, can be used as complete application runtime, develop demo data/visualization applications, and massive software using PG can be spun up with Docker templates.
  • Provides Vagrant-based local development and testing sandbox environment, and Terraform-based cloud auto-deployment solutions, keeping development, testing, and production environments consistent.
  • Deploy and monitor dedicated Redis (primary-replica, sentinel, cluster), MinIO, Etcd, Haproxy, MongoDB (FerretDB) clusters

Battery-Included RDS

Get production-grade PostgreSQL database services locally immediately!

PostgreSQL is a near-perfect database kernel, but it needs more tools and systems to become a good enough database service (RDS). Pigsty helps PostgreSQL make this leap. Pigsty solves various challenges you’ll encounter when using PostgreSQL: kernel extension installation, connection pooling, load balancing, service access, high availability / automatic failover, log collection, metrics monitoring, alerting, backup recovery, PITR, access control, parameter tuning, security encryption, certificate issuance, NTP, DNS, parameter tuning, configuration management, CMDB, management playbooks… You no longer need to worry about these details!

Pigsty supports PostgreSQL 13 ~ 18 mainline kernels and other compatible forks, running on EL / Debian / Ubuntu and compatible OS distributions, available on x86_64 and ARM64 chip architectures, without container support required. Besides database kernels and many out-of-the-box extension plugins, Pigsty also provides complete infrastructure and runtime required for database services, as well as local sandbox / production environment / cloud IaaS auto-deployment solutions.

Pigsty can bootstrap an entire environment from bare metal with one click, reaching the last mile of software delivery. Ordinary developers and operations engineers can quickly get started and manage databases part-time, building enterprise-grade RDS services without database experts!

pigsty-arch.jpg


Rich Extensions

Hyper-converged multi-modal, use PostgreSQL for everything, one PG to replace all databases!

PostgreSQL’s soul lies in its rich extension ecosystem, and Pigsty uniquely deeply integrates 440+ extensions from the PostgreSQL ecosystem, providing you with an out-of-the-box hyper-converged multi-modal database!

Extensions can create synergistic effects, producing 1+1 far greater than 2 results. You can use PostGIS for geospatial data, TimescaleDB for time-series/event stream data analysis, and Citus to upgrade it in-place to a distributed geospatial-temporal database; You can use PGVector to store and search AI embeddings, ParadeDB for ElasticSearch-level full-text search, and simultaneously use precise SQL, full-text search, and fuzzy vector for hybrid search. You can also achieve dedicated OLAP database/data lakehouse analytical performance through Hydra, duckdb_fdw, pg_analytics, pg_duckdb and other analytical extensions.

Using PostgreSQL as a single component to replace MySQL, Kafka, ElasticSearch, MongoDB, and big data analytics stacks has become a best practice — a single database choice can significantly reduce system complexity, greatly improve development efficiency and agility, achieving remarkable software/hardware and development/operations cost reduction and efficiency improvement.

pigsty-ecosystem.jpg


Flexible Modular Architecture

Flexible composition, free extension, multi-database support, monitor existing RDS/hosts/databases

Components in Pigsty are abstracted as independently deployable modules, which can be freely combined to address varying requirements. The INFRA module comes with a complete modern monitoring stack, while the NODE module tunes nodes to desired state and brings them under management. Installing the PGSQL module on multiple nodes automatically forms a high-availability database cluster based on primary-replica replication, while the ETCD module provides consensus and metadata storage for database high availability.

Beyond these four core modules, Pigsty also provides a series of optional feature modules: The MINIO module can provide local object storage capability and serve as a centralized database backup repository. The REDIS module can provide auxiliary services for databases in standalone primary-replica, sentinel, or native cluster modes. The DOCKER module can be used to spin up stateless application software.

Additionally, Pigsty provides PG-compatible / derivative kernel support. You can use Babelfish for MS SQL Server compatibility, IvorySQL for Oracle compatibility, OpenHaloDB for MySQL compatibility, and OrioleDB for ultimate OLTP performance.

Furthermore, you can use FerretDB for MongoDB compatibility, Supabase for Firebase compatibility, and PolarDB to meet domestic compliance requirements. More professional/pilot modules will be continuously introduced to Pigsty, such as GPSQL, KAFKA, DUCKDB, VICTORIA, TIGERBEETLE, KUBERNETES, CONSUL, JUPYTER, GREENPLUM, CLOUDBERRY, MYSQL, …

pigsty-sandbox.jpg


Stunning Observability

Using modern open-source observability stack, providing unparalleled monitoring best practices!

Pigsty provides best practices for monitoring based on the open-source Grafana / Prometheus modern observability stack: Grafana for visualization, VictoriaMetrics for metrics collection, VictoriaLogs for log collection and querying, Alertmanager for alert notifications. Blackbox Exporter for checking service availability. The entire system is also designed for one-click deployment as the out-of-the-box INFRA module.

Any component managed by Pigsty is automatically brought under monitoring, including host nodes, load balancer HAProxy, database Postgres, connection pool Pgbouncer, metadata store ETCD, KV cache Redis, object storage MinIO, …, and the entire monitoring infrastructure itself. Numerous Grafana monitoring dashboards and preset alert rules will qualitatively improve your system observability capabilities. Of course, this system can also be reused for your application monitoring infrastructure, or for monitoring existing database instances or RDS.

Whether for failure analysis or slow query optimization, capacity assessment or resource planning, Pigsty provides comprehensive data support, truly achieving data-driven operations. In Pigsty, over three thousand types of monitoring metrics are used to describe all aspects of the entire system, and are further processed, aggregated, analyzed, refined, and presented in intuitive visualization modes. From global overview dashboards to CRUD details of individual objects (tables, indexes, functions) in a database instance, everything is visible at a glance. You can drill down, roll up, or jump horizontally freely, browsing current system status and historical trends, and predicting future evolution.

pigsty-dashboard.jpg

Additionally, Pigsty’s monitoring system module can be used independently — to monitor existing host nodes and database instances, or cloud RDS services. With just one connection string and one command, you can get the ultimate PostgreSQL observability experience.

Visit the Screenshot Gallery and Online Demo for more details.


Battle-Tested Reliability

Out-of-the-box high availability and point-in-time recovery capabilities ensure your database is rock-solid!

For table/database drops caused by software defects or human error, Pigsty provides out-of-the-box PITR point-in-time recovery capability, enabled by default without additional configuration. As long as storage space allows, base backups and WAL archiving based on pgBackRest give you the ability to quickly return to any point in the past. You can use local directories/disks, or dedicated MinIO clusters or S3 object storage services to retain longer recovery windows, according to your budget.

More importantly, Pigsty makes high availability and self-healing the standard for PostgreSQL clusters. The high-availability self-healing architecture based on patroni, etcd, and haproxy lets you handle hardware failures with ease: RTO < 30s for primary failure automatic failover (configurable), with zero data loss RPO = 0 in consistency-first mode. As long as any instance in the cluster survives, the cluster can provide complete service, and clients only need to connect to any node in the cluster to get full service.

Pigsty includes built-in HAProxy load balancers for automatic traffic switching, providing DNS/VIP/LVS and other access methods for clients. Failover and active switchover are almost imperceptible to the business side except for brief interruptions, and applications don’t need to modify connection strings or restart. The minimal maintenance window requirements bring great flexibility and convenience: you can perform rolling maintenance and upgrades on the entire cluster without application coordination. The feature that hardware failures can wait until the next day to handle lets developers, operations, and DBAs sleep well. Many large organizations and core institutions have been using Pigsty in production for extended periods. The largest deployment has 25K CPU cores and 200+ PostgreSQL ultra-large instances; in this deployment case, dozens of hardware failures and various incidents occurred over six to seven years, DBAs changed several times, but still maintained availability higher than 99.999%.

pigsty-ha.png


Easy to Use and Maintain

Infra as Code, Database as Code, declarative APIs encapsulate database management complexity.

Pigsty provides services through declarative interfaces, elevating system controllability to a new level: users tell Pigsty “what kind of database cluster I want” through configuration inventories, without worrying about how to do it. In effect, this is similar to CRDs and Operators in K8S, but Pigsty can be used for databases and infrastructure on any node: whether containers, virtual machines, or physical machines.

Whether creating/destroying clusters, adding/removing replicas, or creating new databases/users/services/extensions/whitelist rules, you only need to modify the configuration inventory and run the idempotent playbooks provided by Pigsty, and Pigsty adjusts the system to your desired state. Users don’t need to worry about configuration details — Pigsty automatically tunes based on machine hardware configuration. You only need to care about basics like cluster name, how many instances on which machines, what configuration template to use: transaction/analytics/critical/tiny — developers can also self-serve. But if you’re willing to dive into the rabbit hole, Pigsty also provides rich and fine-grained control parameters to meet the demanding customization needs of the most meticulous DBAs.

Beyond that, Pigsty’s own installation and deployment is also one-click foolproof, with all dependencies pre-packaged, requiring no internet access during installation. The machine resources needed for installation can also be automatically obtained through Vagrant or Terraform templates, allowing you to spin up a complete Pigsty deployment from scratch on a local laptop or cloud VM in about ten minutes. The local sandbox environment can run on a 1-core 2GB micro VM, providing the same functional simulation as production environments, usable for development, testing, demos, and learning.

pigsty-iac.jpg


Solid Security Practices

Encryption and backup all included. As long as hardware and keys are secure, you don’t need to worry about database security.

Pigsty is designed for high-standard, demanding enterprise scenarios, adopting industry-leading security best practices to protect your data security (confidentiality/integrity/availability). The default configuration’s security is sufficient to meet compliance requirements for most scenarios.

Pigsty creates self-signed CAs (or uses your provided CA) to issue certificates and encrypt network communication. Sensitive management pages and API endpoints that need protection are password-protected. Database backups use AES encryption, database passwords use scram-sha-256 encryption, and plugins are provided to enforce password strength policies. Pigsty provides an out-of-the-box, easy-to-use, easily extensible ACL model, providing read/write/admin/ETL permission distinctions, with HBA rule sets following the principle of least privilege, ensuring system confidentiality through multiple layers of protection.

Pigsty enables database checksums by default to avoid silent data corruption, with replicas providing bad block fallback. Provides CRIT zero-data-loss configuration templates, using watchdog to ensure HA fencing as a fallback. You can audit database operations through the audit plugin, with all system and database logs collected for reference to meet compliance requirements.

Pigsty correctly configures SELinux and firewall settings, and follows the principle of least privilege in designing OS user groups and file permissions, ensuring system security baselines meet compliance requirements. Security is also uncompromised for auxiliary optional components like Etcd and MinIO — both use RBAC models and TLS encrypted communication, ensuring overall system security.

A properly configured system easily passes Level 3 security certification. As long as you follow security best practices, deploy on internal networks with properly configured security groups and firewalls, database security will no longer be your pain point.

pigsty-acl.jpg


Broad Application Scenarios

Use preset Docker templates to spin up massive software using PostgreSQL with one click!

In various data-intensive applications, the database is often the trickiest part. For example, the core difference between GitLab Enterprise and Community Edition is the underlying PostgreSQL database monitoring and high availability. If you already have a good enough local PG RDS, you can refuse to pay for software’s homemade database components.

Pigsty provides the Docker module and many out-of-the-box Compose templates. You can use Pigsty-managed high-availability PostgreSQL (as well as Redis and MinIO) as backend storage, spinning up these software in stateless mode with one click: GitLab, Gitea, Wiki.js, NocoDB, Odoo, Jira, Confluence, Harbor, Mastodon, Discourse, KeyCloak, etc. If your application needs a reliable PostgreSQL database, Pigsty is perhaps the simplest way to get one.

Pigsty also provides application development toolsets closely related to PostgreSQL: PGAdmin4, PGWeb, ByteBase, PostgREST, Kong, as well as EdgeDB, FerretDB, Supabase — these “upper-layer databases” using PostgreSQL as storage. More wonderfully, you can build interactive data applications quickly in a low-code manner based on the Grafana and Postgres built into Pigsty, and even use Pigsty’s built-in ECharts panels to create more expressive interactive visualization works.

Pigsty provides a powerful runtime for your AI applications. Your agents can leverage PostgreSQL and the powerful capabilities of the observability world in this environment to quickly build data-driven intelligent agents.

pigsty-app.jpg


Open-Source Free Software

Pigsty is free software open-sourced under AGPLv3, watered by the passion of PostgreSQL-loving community members

Pigsty is completely open-source and free software, allowing you to run enterprise-grade PostgreSQL database services at nearly pure hardware cost without database experts. For comparison, database vendors’ “enterprise database services” and public cloud vendors’ RDS charge premiums several to over ten times the underlying hardware resources as “service fees.”

Many users choose the cloud precisely because they can’t handle databases themselves; many users use RDS because there’s no other choice. We will break cloud vendors’ monopoly, providing users with a cloud-neutral, better open-source RDS alternative: Pigsty follows PostgreSQL upstream closely, with no vendor lock-in, no annoying “licensing fees,” no node count limits, and no data collection. All your core assets — data — can be “autonomously controlled,” in your own hands.

Pigsty itself aims to replace tedious manual database operations with database autopilot software, but even the best software can’t solve all problems. There will always be some rare, low-frequency edge cases requiring expert intervention. This is why we also provide professional subscription services to provide safety nets for enterprise users who need them. Subscription consulting fees of tens of thousands are less than one-thirtieth of a top DBA’s annual salary, completely eliminating your concerns and putting costs where they really matter. For community users, we also contribute with love, providing free support and daily Q&A.

pigsty-price.jpg

2.2 - Roadmap

Future feature planning, new feature release schedule, and todo list.

Release Strategy

Pigsty uses semantic versioning: <major>.<minor>.<patch>. Alpha/Beta/RC versions will have suffixes like -a1, -b1, -c1 appended to the version number.

Major version updates signify incompatible foundational changes and major new features; minor version updates typically indicate regular feature updates and small API changes; patch version updates mean bug fixes and package version updates.

Pigsty plans to release one major version update per year. Minor version updates usually follow PostgreSQL’s minor version update rhythm, catching up within a month at the latest after a new PostgreSQL version is released. Pigsty typically plans 4-6 minor versions per year. For complete release history, please refer to Release Notes.


Features Under Consideration

  • A sufficiently good command-line management tool
  • ARM architecture support for infrastructure components
  • Add more extensions for PostgreSQL
  • More preset scenario-based configuration templates
  • Fully migrate software repository and installation download sources to Cloudflare
  • Deploy and monitor highly available Kubernetes clusters using SealOS!
  • Use VictoriaMetrics to replace Prometheus for time-series data storage
  • Monitor and deploy MySQL databases
  • Monitor databases in Kubernetes
  • Provide richer Docker application templates
  • PGLite browser-side support

Here are our Active Issues and Roadmap.


Extensions and Packages

For the extension support roadmap, you can find it here: https://pgext.cloud/e/roadmap

Under Consideration

Not Considering for Now

2.3 - History

The origin and motivation of the Pigsty project, its development history, and future goals and vision.

Historical Origins

The Pigsty project began in 2018-2019, originating from Tantan. Tantan is an internet dating app — China’s Tinder, now acquired by Momo. Tantan was a Nordic-style startup with a Swedish engineering founding team.

Tantan had excellent technical taste, using PostgreSQL and Go as its core technology stack. The entire Tantan system architecture was modeled after Instagram, designed entirely around the PostgreSQL database. Up to several million daily active users, millions of TPS, and hundreds of TB of data, the data component used only PostgreSQL. Almost all business logic was implemented using PG stored procedures — even including 100ms recommendation algorithms!

This atypical development model of deeply using PostgreSQL features placed extremely high demands on the capabilities of engineers and DBAs. And Pigsty is the open-source project we forged in this real-world large-scale, high-standard database cluster scenario — embodying our experience and best practices as top PostgreSQL experts.


Development Process

In the beginning, Pigsty did not have the vision, goals, and scope it has today. It aimed to provide a PostgreSQL monitoring system for our own use. We surveyed all available solutions — open-source, commercial, cloud-based, datadog, pgwatch, etc. — and none could meet our observability needs. So we decided to build one ourselves based on Grafana and Prometheus. This became Pigsty’s predecessor and prototype. Pigsty as a monitoring system was quite impressive, helping us solve countless management problems.

Subsequently, developers wanted such a monitoring system on their local development machines, so we used Ansible to write provisioning playbooks, transforming this system from a one-time construction task into reusable, replicable software. The new functionality allowed users to use Vagrant and Terraform, using Infrastructure as Code to quickly spin up local DevBox development machines or production environment servers, automatically completing PostgreSQL and monitoring system deployment.

Next, we redesigned the production environment PostgreSQL architecture, introducing Patroni and pgBackRest to solve database high availability and point-in-time recovery issues. We developed a zero-downtime migration solution based on logical replication, rolling upgrading two hundred production database clusters to the latest major version through blue-green deployment. And we incorporated these capabilities into Pigsty.

Pigsty is software we made for ourselves. As client users ourselves, we know exactly what we need and won’t slack on our own requirements. The greatest benefit of “eating dog food” is that we are both developers and users — therefore we know exactly what we need and won’t slack on our own requirements.

We solved problem after problem, depositing the solutions into Pigsty. Pigsty’s positioning also gradually evolved from a monitoring system into an out-of-the-box PostgreSQL database distribution. Therefore, at this stage, we decided to open-source Pigsty and began a series of technical sharing and publicity, and external users from various industries began using Pigsty and providing feedback.


Full-Time Entrepreneurship

In 2022, the Pigsty project received seed funding from Miracle Plus, initiated by Dr. Qi Lu, allowing me to work on this full-time.

As an open-source project, Pigsty has developed quite well. In these two years of full-time entrepreneurship, Pigsty’s GitHub stars have multiplied from a few hundred to 3,700; it made the HN front page, and growth began snowballing; In the OSSRank open-source rankings, Pigsty ranks 22nd among PostgreSQL ecosystem projects, the highest among Chinese-led projects.

Previously, Pigsty could only run on CentOS 7, but now it basically covers all mainstream Linux distributions (EL, Debian, Ubuntu). Supported PG major versions cover 13-18, maintaining, collecting, and integrating 440 extension plugins in the PG ecosystem. Among these, I personally maintain over half of the extension plugins, providing out-of-the-box RPM/DEB packages. Including Pigsty itself, “based on open source, giving back to open source,” this is making some contribution to the PG ecosystem.

Pigsty’s positioning has also continuously evolved from a PostgreSQL database distribution to an open-source cloud database alternative. It truly benchmarks against cloud vendors’ entire cloud database brands.


Rebel Against Public Clouds

Public cloud vendors like AWS, Azure, GCP, and Aliyun have provided many conveniences for startups, but they are closed-source and force users to rent infrastructure at exorbitant fees.

We believe that excellent database services, like excellent database kernels, should be accessible to every user, rather than requiring expensive rental from cyber lords.

Cloud computing’s agility and elasticity are great, but it should be free, open-source, inclusive, and local-first — We believe the cloud computing universe needs a solution representing open-source values that returns infrastructure control to users without sacrificing the benefits of the cloud.

Therefore, we are also leading a movement and battle to exit the cloud, as rebels against public clouds, to reshape the industry’s values.


Our Vision

I hope that in the future world, everyone will have the de facto right to freely use excellent services, rather than being confined to a few cyber lord public cloud giants’ territories as cyber tenants or even cyber serfs.

This is exactly what Pigsty aims to do — a better, free and open-source RDS alternative. Allowing users to spin up database services better than cloud RDS anywhere (including cloud servers) with one click.

Pigsty is a complete complement to PostgreSQL, and a spicy mockery of cloud databases. Its original meaning is “pigsty,” but it’s also an acronym for Postgres In Great STYle, meaning “PostgreSQL in its full glory.”

Pigsty itself is completely free and open-source software. We purely rely on providing consulting and services to sustain operations. A well-built system may run for years without encountering problems needing a “safety net,” but database problems, once they occur, are never small issues. Often, expert experience can turn decay into magic with a word, and we provide such services to clients in need — we believe this is a more just, reasonable, and sustainable model.


About the Team

I am Feng Ruohang, the author of Pigsty. The vast majority of Pigsty’s code was developed by me alone, with individual features contributed by the community.

Individual heroism still exists in the software field. Only unique individuals can create unique works — I hope Pigsty can become such a work.

If you’re interested in me, here’s my personal homepage: https://vonng.com/

Modb Interview with Feng Ruohang” (Chinese)

Post-90s, Quit to Start Business, Says Will Crush Cloud Databases” (Chinese)




2.4 - News & Events

News and events related to Pigsty and PostgreSQL, including latest announcements!

Recent News

The name of this project always makes me grin: PIGSTY is actually an acronym, standing for Postgres In Great STYle! It’s a Postgres distribution that includes lots of components and tools out of the box in areas like availability, deployment, and observability. The latest release pushes everything up to Postgres 16.2 standards and introduces new ParadeDB and DuckDB FDW extensions.


Conferences & Talks

DateTypeEventTopic
2025-11-29Award&TalkThe 8th Conf of PG Ecosystem (Hangzhou)PostgreSQL Magneto Award, A World-Grade Postgres Meta Distribution
2025-05-16LightningPGConf.Dev 2025, MontrealExtension Delivery: Make your PGEXT accessible to users
2025-05-12KeynotePGEXT.DAY, PGCon.Dev 2025The Missing Package Manager and Extension Repo for PostgreSQL Ecosystem
2025-04-19WorkshopPostgreSQL Database Technology SummitUsing Pigsty to Deploy PG Ecosystem Partners: Dify, Odoo, Supabase
2025-04-11Live HostOSCHINA Data Intelligence TalkIs the Viral MCP Hype or Revolutionary?
2025-01-15Live StreamOpen Source Veterans & Newcomers Episode 4PostgreSQL Extensions Devouring DB World? PG Package Manager pig & Self-hosted RDS
2025-01-09AwardOSCHINA 2024 Outstanding Contribution ExpertOutstanding Contribution Expert Award
2025-01-06PanelChina PostgreSQL Database Ecosystem ConferencePostgreSQL Extensions are Devouring the Database World
2024-11-23PodcastTech Hotpot PodcastFrom the Linux Foundation: Why the Recent Focus on ‘Chokepoints’?
2024-08-21InterviewBlue Tech WaveInterview with Feng Ruohang: Simplifying PG Management
2024-08-15Tech SummitGOTC Global Open Source Technology SummitPostgreSQL AI/ML/RAG Extension Ecosystem and Best Practices
2024-07-12Keynote13th PG China Technical ConferenceThe Future of Database World: Extensions, Service, and Postgres
2024-05-31UnconferencePGCon.Dev 2024 Global PG Developer ConferenceBuilt-in Prometheus Metrics Exporter
2024-05-28SeminarPGCon.Dev 2024 Extension SummitExtension in Core & Binary Packing
2024-05-10Live DebateThree-way Talk: Cloud Mudslide Series Episode 3Is Public Cloud a Scam?
2024-04-17Live DebateThree-way Talk: Cloud Mudslide Series Episode 2Are Cloud Databases a Tax on Intelligence?
2024-04-16PanelCloudflare Immerse ShenzhenCyber Bodhisattva Panel Discussion
2024-04-12Tech Summit2024 Data Technology CarnivalPigsty: Solving PostgreSQL Operations Challenges
2024-03-31Live DebateThree-way Talk: Cloud Mudslide Series Episode 1Luo Selling Cloud While We’re Moving Off Cloud?
2024-01-24Live HostOSCHINA Open Source Talk Episode 9Will DBAs Be Eliminated by Cloud?
2023-12-20Live DebateOpen Source Talk Episode 7To Cloud or Not: Cost Cutting or Value Creation?
2023-11-24Tech SummitVector Databases in the LLM EraPanel: New Future of Vector Databases in the AI Age
2023-09-08InterviewMotianlun Feature InterviewFeng Ruohang: A Tech Enthusiast Who Makes Great Open Source Founders
2023-08-16Tech SummitDTCC 2023DBA Night: PostgreSQL vs MySQL Open Source License Issues
2023-08-09Live DebateOpen Source Talk Episode 1MySQL vs PostgreSQL: Which is World’s No.1?
2023-07-01Tech SummitSACC 2023Workshop 8: FinOps Practice: Cloud Cost Management & Optimization
2023-05-12MeetupPostgreSQL China Wenzhou MeetupPG With DB4AI: Vector Database PGVECTOR & AI4DB: Self-Driving Database Pigsty
2023-04-08Tech SummitDatabase Carnival 2023A Better Open Source RDS Alternative: Pigsty
2023-04-01Tech SummitPostgreSQL China Xi’an MeetupPG High Availability & Disaster Recovery Best Practices
2023-03-23Live StreamBytebase x PigstyBest Practices for Managing PostgreSQL: Bytebase x Pigsty
2023-03-04Tech SummitPostgreSQL China ConferenceChallenging RDS, Pigsty v2.0 Release
2023-02-01Tech SummitDTCC 2022Open Source RDS Alternative: Battery-Included, Self-Driving Database Distro Pigsty
2022-07-21Live DebateCloud Swallows Open SourceCan Open Source Strike Back Against Cloud?
2022-07-04InterviewCreator’s StoryPost-90s Developer Quits to Start Up, Aiming to Challenge Cloud Databases
2022-06-28Live StreamBass’s RoundtableDBA’s Gospel: SQL Audit Best Practices
2022-06-12Demo DayMiraclePlus S22 Demo DayUser-Friendly Cost-Effective Database Distribution Pigsty
2022-06-05Live StreamPG Chinese Community SharingPigsty v1.5 Quick Start, New Features & Production Cluster Setup

2.5 - Join the Community

Pigsty is a Build in Public project. We are very active on GitHub, and Chinese users are mainly active in WeChat groups.

GitHub

Our GitHub repository is: https://github.com/pgsty/pigsty. Please give us a ⭐️ star!

We welcome anyone to submit new Issues or create Pull Requests, propose feature suggestions, and contribute to Pigsty.

Star History Chart

Please note that for issues related to Pigsty documentation, please submit Issues in the github.com/pgsty/pigsty.cc repository.


WeChat Groups

Chinese users are mainly active in WeChat groups. Currently, there are seven active groups. Groups 1-4 are full; for other groups, you need to add the assistant’s WeChat to be invited.

To join the WeChat community, search for “Pigsty小助手” (WeChat ID: pigsty-cc), note or send “加群” (join group), and the assistant will invite you to the group.


International Community

Telegram: https://t.me/joinchat/gV9zfZraNPM3YjFh

Discord: https://discord.gg/j5pG8qfKxU

You can also contact me via email: [email protected]


Community Help

When you encounter problems using Pigsty, you can seek help from the community. The more information you provide, the more likely you are to get help from the community.

Please refer to the Community Help Guide and provide as much information as possible so that community members can help you solve the problem. Here is a reference template for asking for help:

What happened? (Required)

Pigsty version and OS version (Required)

$ grep version pigsty.yml

$ cat /etc/os-release

$ uname -a

Some cloud providers have customized standard OS distributions. You can tell us which cloud provider’s OS image you are using. If you have customized and modified the environment after installing the OS, or if there are specific security rules and firewall configurations in your LAN, please also inform us when asking questions.

Pigsty configuration file

Please don’t forget to redact any sensitive information: passwords, internal keys, sensitive configurations, etc.

cat ~/pigsty/pigsty.yml

What did you expect to happen?

Please describe what should happen under normal circumstances, and how the actual situation differs from expectations.

How to reproduce this issue?

Please tell us in as much detail as possible how to reproduce this issue.

Monitoring screenshots

If you are using the monitoring system provided by Pigsty, you can provide relevant screenshots.

Error logs

Please provide logs related to the error as much as possible. Please do not paste content like “Failed to start xxx service” that has no informational value.

You can query logs from Grafana / Loki, or get logs from the following locations:

  • Syslog: /var/log/messages (rhel) or /var/log/syslog (debian)
  • Postgres: /pg/log/postgres/*
  • Patroni: /pg/log/patroni/*
  • Pgbouncer: /pg/log/pgbouncer/*
  • Pgbackrest: /pg/log/pgbackrest/*
journalctl -u patroni
journalctl -u <service name>

Have you searched Issues/Website/FAQ?

In the FAQ, we provide answers to many common questions. Please check before asking.

You can also search for related issues from GitHub Issues and Discussions:

Is there any other information we need to know?

The more information and context you provide, the more likely we can help you solve the problem.

2.6 - Privacy Policy

What user data does Pigsty software and website collect, and how will we process your data and protect your privacy?

Pigsty Software

When you install Pigsty software, if you use offline package installation in a network-isolated environment, we will not receive any data about you.

If you choose online installation, when downloading related packages, our servers or cloud provider servers will automatically log the visiting machine’s IP address and/or hostname in the logs, along with the package names you downloaded.

We will not share this information with other organizations unless required by law. (Honestly, we’d have to be really bored to look at this stuff.)

Pigsty’s primary domain is: pigsty.io. For mainland China, please use the registered mirror site pigsty.cc.


Pigsty Website

When you visit our website, our servers will automatically log your IP address and/or hostname in Nginx logs.

We will only store information such as your email address, name, and location when you decide to send us such information by completing a survey or registering as a user on one of our websites.

We collect this information to help us improve website content, customize web page layouts, and contact people for technical and support purposes. We will not share your email address with other organizations unless required by law.

This website uses Google Analytics, a web analytics service provided by Google, Inc. (“Google”). Google Analytics uses “cookies,” which are text files placed on your computer to help the website analyze how users use the site.

The information generated by the cookie about your use of the website (including your IP address) will be transmitted to and stored by Google on servers in the United States. Google will use this information to evaluate your use of the website, compile reports on website activity for website operators, and provide other services related to website activity and internet usage. Google may also transfer this information to third parties if required by law or where such third parties process the information on Google’s behalf. Google will not associate your IP address with any other data held by Google. You may refuse the use of cookies by selecting the appropriate settings on your browser, however, please note that if you do this, you may not be able to use the full functionality of this website. By using this website, you consent to the processing of data about you by Google in the manner and for the purposes set out above.

If you have any questions or comments about this policy, or request deletion of personal data, you can contact us by sending an email to [email protected]




2.7 - License

Pigsty’s open-source licenses — Apache-2.0, AGPLv3, and CC BY 4.0

Official License: https://github.com/pgsty/pigsty/blob/main/LICENSE


License Summary

Pigsty uses Apache-2.0, AGPLv3 for two optional modules, and CC BY 4.0 for documentation.


Pigsty Core

The Pigsty core is licensed under Apache License 2.0.

Apache-2.0 is a permissive open-source license. You may freely use, modify, and distribute the software for commercial purposes without opening your own source code or adopting the same license.

What This License GrantsWhat This License Does NOT GrantLicense Conditions
Commercial use Trademark use Include license and copyright notice
Modification Liability & warranty State changes
Distribution
Patent grant
Private use

Pigsty Optional Modules

The INFRA and MINIO modules are licensed under GNU Affero General Public License v3.0 (AGPLv3).

AGPLv3 does not affect regular users: using the software is not “distribution,” so your business code using Pigsty need not be open-sourced.

AGPLv3 obligations apply only when you “distribute” these modules or modifications as part or all of a software/service offering.

What This License GrantsWhat This License Does NOT GrantLicense Conditions
Commercial use Trademark use Include license and prominent notice
Modification Liability & warranty Maintain open-source status
Distribution Disclose source code
Patent grant Network use is distribution
Private use Use same license

These modules are optional — avoid them completely to evade AGPLv3 requirements. If used, AGPLv3 compliance is straightforward since Grafana and MinIO already use AGPLv3.

Files and directories under AGPL-3.0:

Files and DirectoriesDescription
roles/infra/Infrastructure module (Grafana integration)
roles/minio/MinIO object storage module (optional backup repository)
files/grafana/Grafana dashboard definitions
infra.ymlINFRA module installation playbook
infra-rm.ymlINFRA module removal playbook
minio.ymlMinIO module installation playbook
minio-rm.ymlMinIO module removal playbook

Pigsty Documentation

Pigsty documentation sites (pigsty.cc, pigsty.io, pgsty.com) use Creative Commons Attribution 4.0 International (CC BY 4.0).

CC BY 4.0 permits free sharing and adaptation with appropriate credit, a license link, and indication of changes.

What This License GrantsWhat This License Does NOT GrantLicense Conditions
Commercial use Trademark use Attribution
Modification Liability & warranty Indicate changes
Distribution Patent grant Provide license link
Private use

SBOM Inventory

Open-source software used or related to the Pigsty project.

For PostgreSQL extension plugin licenses, refer to PostgreSQL Extension License List.

ModuleSoftware NameLicensePurpose & DescriptionNecessity
PGSQLPostgreSQLPostgreSQL LicensePostgreSQL kernelRequired
PGSQLpatroniMIT LicensePostgreSQL high availabilityRequired
ETCDetcdApache License 2.0HA consensus and distributed config storageRequired
INFRAAnsibleGPLv3Executes playbooks and management commandsRequired
INFRANginxBSD-2Exposes Web UI and serves local repoRecommended
PGSQLpgbackrestMIT LicensePITR backup/recovery managementRecommended
PGSQLpgbouncerISC LicensePostgreSQL connection poolingRecommended
PGSQLvip-managerBSD 2-Clause LicenseAutomatic L2 VIP binding to PG primaryRecommended
PGSQLpg_exporterApache License 2.0PostgreSQL and PgBouncer monitoringRecommended
NODEnode_exporterApache License 2.0Host node monitoring metricsRecommended
NODEhaproxyHAPROXY’s License (GPLv2)Load balancing and service exposureRecommended
INFRAGrafanaAGPLv3Database visualization platformRecommended
INFRAPrometheus StackApache License 2.0TSDB, metric collection, alertingRecommended
INFRALokiAGPLv3Centralized log collection, storage, queryRecommended
INFRADNSMASQGPLv2 / GPLv3DNS resolution and cluster name lookupRecommended
MINIOMinIOAGPLv3S3-compatible object storage serviceOptional
NODEkeepalivedMIT LicenseVIP binding on node clustersOptional
REDISRedisRedis License (BSD-3)Cache service, locked at 7.2.6Optional
REDISRedis ExporterMIT LicenseRedis monitoringOptional
MONGOFerretDBApache License 2.0MongoDB compatibility over PostgreSQLOptional
DOCKERdocker-ceApache License 2.0Container managementOptional
CLOUDSealOSApache License 2.0Fast K8S cluster deployment and packagingOptional
DUCKDBDuckDBMITHigh-performance analyticsOptional
ExternalVagrantBusiness Source License 1.1Local test environment VMsOptional
ExternalTerraformBusiness Source License 1.1One-click cloud resource provisioningOptional
ExternalVirtualboxGPLv2Virtual machine management softwareOptional

Necessity Levels:

  • Required: Essential core capabilities, no option to disable
  • Recommended: Enabled by default, can be disabled via configuration
  • Optional: Not enabled by default, can be enabled via configuration

Apache-2.0 License Text

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright (C) 2018-2026  Ruohang Feng, @Vonng ([email protected])

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

AGPLv3 License Text

                    GNU AFFERO GENERAL PUBLIC LICENSE
                       Version 3, 19 November 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.

  A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate.  Many developers of free software are heartened and
encouraged by the resulting cooperation.  However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.

  The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community.  It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server.  Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.

  An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals.  This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU Affero General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of that material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Remote Network Interaction; Use with the GNU General Public License.

  Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software.  This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time.  Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    Copyright (C) 2018-2026  Ruohang Feng, Author of Pigsty

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source.  For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code.  There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.

2.8 - Sponsor Us

Pigsty sponsors and investors list - thank you for your support of this project!

Pigsty is a free and open-source software, passionately developed by PostgreSQL community members, aiming to integrate the power of the PostgreSQL ecosystem and promote the widespread adoption of PostgreSQL. If our work has helped you, please consider sponsoring or supporting our project:

  • Sponsor us directly with financial support - express your sincere support in the most direct and powerful way!
  • Consider purchasing our Technical Support Services. We can provide professional PostgreSQL high-availability cluster deployment and maintenance services, making your budget worthwhile!
  • Share your Pigsty use cases and experiences through articles, talks, and videos.
  • Allow us to mention your organization in “Users of Pigsty.”
  • Recommend/refer our project and services to friends, colleagues, and clients in need.
  • Follow our WeChat Official Account and share relevant technical articles to groups and your social media.

Angel Investors

Pigsty is a project invested by Miracle Plus (formerly YC China) S22. We thank Miracle Plus and Dr. Qi Lu for their support of this project!


Sponsors

Special thanks to Vercel for sponsoring pigsty and hosting the Pigsty website.

Vercel OSS Program

2.9 - User Cases

Pigsty customer and application cases across various domains and industries

According to Google Analytics PV and download statistics, Pigsty currently has approximately 100,000 users, with half from mainland China and half from other regions globally. They span across multiple industries including internet, cloud computing, finance, autonomous driving, manufacturing, tech innovation, ISV, and defense. If you are using Pigsty and are willing to share your case and Logo with us, please contact us - we offer one free consultation session as a token of appreciation.

Internet

Tantan: 200+ physical machines for PostgreSQL and Redis services

Bilibili: Supporting PostgreSQL innovative business

Cloud Vendors

Bitdeer: Providing PG DBaaS

Oracle OCI: Using Pigsty to deliver PostgreSQL clusters

Finance

AirWallex: Monitoring 200+ GCP PostgreSQL databases

Media & Entertainment

Media Storm: Self-hosted PG RDS / Victoria Metrics

Autonomous Driving

Momenta: Autonomous driving, managing self-hosted PostgreSQL clusters

Manufacturing

Huafon Group: Using Pigsty to deliver PostgreSQL clusters as chemical industry time-series data warehouse

Tech Innovation

Beijing Lingwu Technology: Migrating PostgreSQL from cloud to self-hosted

Motphys: Self-hosted PostgreSQL supporting GitLab

Sailong Biotech: Self-hosted Supabase

Hangzhou Lingma Technology: Self-hosted PostgreSQL

ISV

Inner Mongolia Haode Tianmu Technology Co., Ltd.

Shanghai Yuanfang

DSG

2.10 - Subscription

Pigsty Professional/Enterprise subscription service - When you encounter difficulties related to PostgreSQL and Pigsty, our subscription service provides you with comprehensive support.

Pigsty aims to unite the power of the PostgreSQL ecosystem and help users make the most of the world’s most popular database, PostgreSQL, with self-driving database management software.

While Pigsty itself has already resolved many issues in PostgreSQL usage, achieving truly enterprise-grade service quality requires expert support and comprehensive coverage from the original provider. We deeply understand the importance of professional commercial support for enterprise customers. Therefore, Pigsty Enterprise Edition provides a series of value-added services on top of the open-source version, helping users better utilize PostgreSQL and Pigsty for customers to choose according to their needs.

If you have any of the following needs, please consider Pigsty subscription service:

  • Running databases in critical scenarios requiring strict SLA guarantees and comprehensive coverage.
  • Need comprehensive support for complex issues related to Pigsty and PostgreSQL.
  • Seeking guidance on PostgreSQL/Pigsty production environment best practices.
  • Want experts to help interpret monitoring dashboards, analyze and identify performance bottlenecks and fault root causes, and provide recommendations.
  • Need to plan database architectures that meet security/disaster recovery/compliance requirements based on existing resources and business needs.
  • Need to migrate from other databases to PostgreSQL, or migrate and transform legacy instances.
  • Building an observability system, data dashboards, and visualization applications based on the Prometheus/Grafana technology stack.
  • Migrating off cloud and seeking open-source alternatives to RDS for PostgreSQL - cloud-neutral, vendor lock-in-free solutions.
  • Want professional support for Redis/ETCD/MinIO, as well as extensions like TimescaleDB/Citus.
  • Want to avoid AGPL v3 license restrictions that mandate derivative works to use the same open-source license, for secondary development and OEM branding.
  • Want to sell Pigsty as SaaS/PaaS/DBaaS, or provide technical services/consulting/cloud services based on this distribution.

Subscription Plans

In addition to the Open Source Edition, Pigsty offers two different subscription service tiers: Professional Edition and Enterprise Edition, which you can choose based on your actual situation and needs.

Pigsty Open Source Edition (OSS)
Free and Open Source
No scale limit, no warranty

License: AGPLv3

PG Support: 18

Architecture Support: x86_64

OS Support: Latest minor versions of three families

  • EL 9.4
  • Debian 12.7
  • Ubuntu 22.04.5

Features: Core Modules

SLA: No SLA commitment

Community support Q&A:

Support: No person-day support option

Repository: Global Cloudflare hosted repository

Pigsty Professional Edition (PRO)
Starting Price: ¥150,000 / year
Default choice for regular users

License: Commercial License

PG Support: 17, 18

Architecture Support: x86_64, Arm64

OS Support: Five families major/minor versions

  • EL 8 / 9 compatible
  • Debian 12
  • Ubuntu 22 / 24

Features: All Modules (except 信创)

SLA: Response within business hours

Expert consulting services:

  • Software bug fixes
  • Complex issue analysis
  • Expert ticket support

Support: 1 person-day included per year

Delivery: Standard offline software package

Repository: China mainland mirror sites

Pigsty Enterprise Edition (ENTERPRISE)
Starting Price: ¥400,000 / year
Critical scenarios with strict SLA

License: Commercial License

PG Support: 12 - 18+

Architecture Support: x86_64, Arm64

OS Support: Customized on demand

  • EL, Debian, Ubuntu
  • Cloud Linux operating systems
  • Domestic OS and ARM

Features: All Modules

SLA: 7 x 24 (< 1h)

Enterprise-level expert consulting services:

  • Software bug fixes
  • Complex issue analysis
  • Expert Q&A support
  • Backup compliance advice
  • Upgrade path support
  • Performance bottleneck identification
  • Annual architecture review
  • Extension plugin integration
  • DBaaS & OEM use cases

Support: 2 person-days included per year

Repository: China mainland mirror sites

Delivery: Customized offline software package

信创: PolarDB-O support


Pigsty Open Source Edition (OSS)

Pigsty Open Source Edition uses the AGPLv3 license, provides complete core functionality, requires no fees, but does not guarantee any warranty service. If you find defects in Pigsty, we welcome you to submit an Issue on Github.

If you are a regular end user (i.e., users other than public cloud providers and database vendors), we actually enforce the more permissive Apache 2.0 license - even if you perform secondary development on Pigsty, we will not pursue this.

For the open source version, we provide pre-built standard offline software packages for PostgreSQL 18 on the latest minor versions of three specific operating system distributions: EL 9.4, Debian 12.7, Ubuntu 22.04.5 (as support for open source, we also provide Debian 12 Arm64 offline software packages).

Using the Pigsty open source version allows junior development/operations engineers to have 70%+ of the capabilities of professional DBAs. Even without database experts, they can easily set up a highly available, high-performance, easy-to-maintain, secure and reliable PostgreSQL database cluster.

CodeOS Distribution Versionx86_64Arm64PG17PG16PG15PG14PG13
EL9RHEL 9 / Rocky9 / Alma9el9.x86_64
U22Ubuntu 22.04 (jammy)u22.x86_64
D12Debian 12 (bookworm)d12.x86_64d12.aarch64

= Primary support, = Optional support


Pigsty Professional Edition (PRO)

Pigsty Professional Edition subscription provides complete functional modules and warranty for Pigsty itself. For defects in PostgreSQL itself and extension plugins, we will make our best efforts to provide feedback and fixes through the PostgreSQL global developer community.

Pigsty Professional Edition is built on the open source version, fully compatible with all features of the open source version, and provides additional functional modules and broader database/operating system version compatibility options: we will provide build options for all minor versions of five mainstream operating system distributions.

Pigsty Professional Edition includes support for the latest two PostgreSQL major versions (18, 17), providing all available extension plugins in both major versions, ensuring you can smoothly migrate to the latest PostgreSQL major version through rolling upgrades.

Pigsty Professional Edition subscription allows you to use China mainland mirror site software repositories, accessible without VPN/proxy; we will also customize offline software installation packages for your exact operating system major/minor version, ensuring normal installation and delivery in air-gapped environments, achieving autonomous and controllable deployment.

Pigsty Professional Edition subscription provides standard expert consulting services, including complex issue analysis, DBA Q&A support, backup compliance advice, etc. We commit to responding to your issues within business hours (5x8), and provide 1 person-day support per year, with optional person-day add-on options.

Pigsty Professional Edition uses a commercial license and provides written contractual exemption from AGPLv3 open source obligations. Even if you perform secondary development on Pigsty and violate the AGPLv3 license by not open-sourcing, we will not pursue this.

Pigsty Professional Edition starting price is ¥150,000 / year, equivalent to the annual fee for 9 vCPU AWS high-availability RDS PostgreSQL, or a junior operations engineer with a monthly salary of 10,000 yuan.

CodeOS Distribution Versionx86_64Arm64PG17PG16PG15PG14PG13
EL9RHEL 9 / Rocky9 / Alma9el9.x86_64el9.aarch64
EL8RHEL 8 / Rocky8 / Alma8 / Anolis8el8.x86_64el8.aarch64
U24Ubuntu 24.04 (noble)u24.x86_64u24.aarch64
U22Ubuntu 22.04 (jammy)u22.x86_64u22.aarch64
D12Debian 12 (bookworm)d12.x86_64d12.aarch64

Pigsty Enterprise Edition

Pigsty Enterprise Edition subscription includes all service content provided by the Pigsty Professional Edition subscription, plus the following value-added service items:

Pigsty Enterprise Edition subscription provides the broadest range of database/operating system version support, including extended support for EOL operating systems (EL7, U20, D11), domestic operating systems, cloud vendor operating systems, and EOL database major versions (from PG 13 onwards), as well as full support for Arm64 architecture chips.

Pigsty Enterprise Edition subscription provides 信创 (domestic innovation) and localization solutions, allowing you to use PolarDB v2.0 (this kernel license needs to be purchased separately) kernel to replace the native PostgreSQL kernel to meet domestic compliance requirements.

Pigsty Enterprise Edition subscription provides higher-standard enterprise-level consulting services, committing to 7x24 with (< 1h) response time SLA, and can provide more types of consulting support: version upgrades, performance bottleneck identification, annual architecture review, extension plugin integration, etc.

Pigsty Enterprise Edition subscription includes 2 person-days of support per year, with optional person-day add-on options, for resolving more complex and time-consuming issues.

Pigsty Enterprise Edition allows you to use Pigsty for DBaaS purposes, building cloud database services for external sales.

Pigsty Enterprise Edition starting price is ¥400,000 / year, equivalent to the annual fee for 24 vCPU AWS high-availability RDS, or an operations expert with a monthly salary of 30,000 yuan.

CodeOS Distribution Versionx86_64PG17PG16PG15PG14PG13PG12Arm64PG17PG16PG15PG14PG13PG12
EL9RHEL 9 / Rocky9 / Alma9el9.x86_64el9.arm64
EL8RHEL 8 / Rocky8 / Alma8 / Anolis8el8.x86_64el8.arm64
U24Ubuntu 24.04 (noble)u24.x86_64u24.arm64
U22Ubuntu 22.04 (jammy)u22.x86_64u22.arm64
D12Debian 12 (bookworm)d12.x86_64d12.arm64
D11Debian 11 (bullseye)d12.x86_64d11.arm64
U20Ubuntu 20.04 (focal)d12.x86_64u20.arm64
EL7RHEL7 / CentOS7 / UOS …d12.x86_64el7.arm64

Pigsty Subscription Notes

Feature Differences

Pigsty Professional/Enterprise Edition includes the following additional features compared to the open source version:

  • Command Line Management Tool: Unlock the full functionality of the Pigsty command line tool (pig)
  • System Customization Capability: Provide pre-built offline installation packages for exact mainstream Linux operating system distribution major/minor versions
  • Offline Installation Capability: Complete Pigsty installation in environments without Internet access (air-gapped environments)
  • Multi-version PG Kernel: Allow users to freely specify and install PostgreSQL major versions within the lifecycle (13 - 17)
  • Kernel Replacement Capability: Allow users to use other PostgreSQL-compatible kernels to replace the native PG kernel, and the ability to install these kernels offline
    • Babelfish: Provides Microsoft SQL Server wire protocol-level compatibility
    • IvorySQL: Based on PG, provides Oracle syntax/type/stored procedure compatibility
    • PolarDB PG: Provides support for open-source PolarDB for PostgreSQL kernel
    • PolarDB O: 信创 database, Oracle-compatible kernel that meets domestic compliance requirements (Enterprise Edition subscription only)
  • Extension Support Capability: Provides out-of-the-box installation for 440 available PG Extensions for PG 13-18 on mainstream operating systems.
  • Complete Functional Modules: Provides all functional modules:
    • Supabase: Reliably self-host production-grade open-source Firebase
    • MinIO: Enterprise PB-level object storage planning and self-hosting
    • DuckDB: Provides comprehensive DuckDB support, and PostgreSQL + DuckDB OLAP extension plugin support
    • Kafka: Provides high-availability Kafka cluster deployment and monitoring
    • Kubernetes, VictoriaMetrics & VictoriaLogs
  • Domestic Operating System Support: Provides domestic 信创 operating system support options (Enterprise Edition subscription only)
  • Domestic ARM Architecture Support: Provides domestic ARM64 architecture support options (Enterprise Edition subscription only)
  • China Mainland Mirror Repository: Smooth installation without VPN, providing domestic YUM/APT repository mirrors and DockerHub access proxy.
  • Chinese Interface Support: Monitoring system Chinese interface support (Beta)

Payment Model

Pigsty subscription uses an annual payment model. After signing the contract, the one-year validity period is calculated from the contract date. If payment is made before the subscription contract expires, it is considered automatic renewal. Consecutive subscriptions have discounts. The first renewal (second year) enjoys a 95% discount, the second and subsequent renewals enjoy a 90% discount on subscription fees, and one-time subscriptions for three years or more enjoy an overall 85% discount.

After the annual subscription contract terminates, you can choose not to renew the subscription service. Pigsty will no longer provide software updates, technical support, and consulting services, but you can continue to use the already installed version of Pigsty Professional Edition software. If you subscribed to Pigsty professional services and choose not to renew, when re-subscribing you do not need to make up for the subscription fees during the interruption period, but all discounts and benefits will be reset.

Pigsty’s pricing strategy ensures value for money - you can immediately get top DBA’s database architecture construction solutions and management best practices, with their consulting support and comprehensive coverage; while the cost is highly competitive compared to hiring database experts full-time or using cloud databases. Here are market references for enterprise-level database professional service pricing:

The fair price for decent database professional services is 10,000 ~ 20,000 yuan / year, with the billing unit being vCPU, i.e., one CPU thread (1 Intel core = 2 vCPU threads). Pigsty provides top-tier PostgreSQL expert services in China and adopts a per-node billing model. On commonly seen high-core-count server nodes, it brings users an unparalleled cost reduction and efficiency improvement experience.


Pigsty Expert Services

In addition to Pigsty subscription, Pigsty also provides on-demand Pigsty x PostgreSQL expert services - industry-leading database experts available for consultation.


Contact Information

Please send an email to [email protected]. Users in mainland China are welcome to add WeChat ID RuohangFeng.

2.11 - FAQ

Answers to frequently asked questions about the Pigsty project itself.

What is Pigsty, and what is it not?

Pigsty is a PostgreSQL database distribution, a local-first open-source RDS cloud database solution. Pigsty is not a Database Management System (DBMS), but rather a tool, distribution, solution, and best practice for managing DBMS.

Analogy: The database is the car, then the DBA is the driver, RDS is the taxi service, and Pigsty is the autonomous driving software.


What problem does Pigsty solve?

The ability to use databases well is extremely scarce: either hire database experts at high cost to self-build (hire drivers), or rent RDS from cloud vendors at sky-high prices (hail a taxi), but now you have a new option: Pigsty (autonomous driving). Pigsty helps users use databases well: allowing users to self-build higher-quality and more efficient local cloud database services at less than 1/10 the cost of RDS, without a DBA!


Who are Pigsty’s target users?

Pigsty has two typical target user groups. The foundation is medium to large companies building ultra-large-scale enterprise/production-grade PostgreSQL RDS / DBaaS services. Through extreme customizability, Pigsty can meet the most demanding database management needs and provide enterprise-level support and service guarantees.

At the same time, Pigsty also provides “out-of-the-box” PG RDS self-building solutions for individual developers, small and medium enterprises lacking DBA capabilities, and the open-source community.


Why can Pigsty help you use databases well?

Pigsty embodies the experience and best practices of top experts refined in the most complex and largest-scale client PostgreSQL scenarios, productized into replicable software: Solving extension installation, high availability, connection pooling, monitoring, backup and recovery, parameter optimization, IaC batch management, one-click installation, automated operations, and many other issues at once. Avoiding many pitfalls in advance and preventing repeated mistakes.


Why is Pigsty better than RDS?

Pigsty provides a feature set and infrastructure support far beyond RDS, including 440 extension plugins and 8+ kernel support. Pigsty provides a unique professional-grade monitoring system in the PG ecosystem, along with architectural best practices battle-tested in complex scenarios, simple and easy to use.

Moreover, forged in top-tier client scenarios like Tantan, Apple, and Alibaba, continuously nurtured with passion and love, its depth and maturity are incomparable to RDS’s one-size-fits-all approach.


Why is Pigsty cheaper than RDS?

Pigsty allows you to use 10 ¥/core·month pure hardware resources to run 400¥-1400¥/core·month RDS cloud databases, and save the DBA’s salary. Typically, the total cost of ownership (TCO) of a large-scale Pigsty deployment can be over 90% lower than RDS.

Pigsty can simultaneously reduce software licensing/services/labor costs. Self-building requires no additional staff, allowing you to spend costs where it matters most.


How does Pigsty help developers?

Pigsty integrates the most comprehensive extensions in the PG ecosystem (440), providing an All-in-PG solution: a single component replacing specialized components like Redis, Kafka, MySQL, ES, vector databases, OLAP / big data analytics.

Greatly improving R&D efficiency and agility while reducing complexity costs, and developers can achieve self-service management and autonomous DevOps with Pigsty’s support, without needing a DBA.


How does Pigsty help operations?

Pigsty’s self-healing high-availability architecture ensures hardware failures don’t need immediate handling, letting ops and DBAs sleep well; monitoring aids problem analysis and performance optimization; IaC enables automated management of ultra-large-scale clusters.

Operations can moonlight as DBAs with Pigsty’s support, while DBAs can skip the system building phase, saving significant work hours and focusing on high-value work, or relaxing, learning PG.


Who is the author of Pigsty?

Pigsty is primarily developed by Feng Ruohang alone, an open-source contributor, database expert, and evangelist who has focused on PostgreSQL for 10 years, formerly at Alibaba, Tantan, and Apple, a full-stack expert. Now the founder of a one-person company, providing professional consulting services.

He is also a tech KOL, the founder of the top WeChat database personal account “非法加冯” (Illegally Add Feng), with 60,000+ followers across all platforms.


What is Pigsty’s ecosystem position and influence?

Pigsty is the most influential Chinese open-source project in the global PostgreSQL ecosystem, with about 100,000 users, half from overseas. Pigsty is also one of the most active open-source projects in the PostgreSQL ecosystem, currently dominating in extension distribution and monitoring systems.

PGEXT.Cloud is a PostgreSQL extension repository maintained by Pigsty, with the world’s largest PostgreSQL extension distribution volume. It has become an upstream software supply chain for multiple international PostgreSQL vendors.

Pigsty is currently one of the major distributions in the PostgreSQL ecosystem and a challenger to cloud vendor RDS, now widely used in defense, government, healthcare, internet, finance, manufacturing, and other industries.


What scale of customers is Pigsty suitable for?

Pigsty originated from the need for ultra-large-scale PostgreSQL automated management but has been deeply optimized for ease of use. Individual developers and small-medium enterprises lacking professional DBA capabilities can also easily get started.

The largest deployment is 25K vCPU, 4.5 million QPS, 6+ years; the smallest deployment can run completely on a 1c1g VM for Demo / Devbox use.


What capabilities does Pigsty provide?

Pigsty focuses on integrating the PostgreSQL ecosystem and providing PostgreSQL best practices, but also supports a series of open-source software that works well with PostgreSQL. For example:

  • Etcd, Redis, MinIO, DuckDB, Prometheus
  • FerretDB, Babelfish, IvorySQL, PolarDB, OrioleDB
  • OpenHalo, Supabase, Greenplum, Dify, Odoo, …

What scenarios is Pigsty suitable for?

  • Running large-scale PostgreSQL clusters for business
  • Self-building RDS, object storage, cache, data warehouse, Supabase, …
  • Self-building enterprise applications like Odoo, Dify, Wiki, GitLab
  • Running monitoring infrastructure, monitoring existing databases and hosts
  • Using multiple PG extensions in combination
  • Dashboard development and interactive data application demos, data visualization, web building

Is Pigsty open source and free?

Pigsty is 100% open-source software + free software. Under the premise of complying with the open-source license, you can use it freely and for various commercial purposes.

We value software freedom. For non-DBaaS / OEM use cases, we enforce a more relaxed equivalent Apache 2.0 license. Please see the license for more details.


Does Pigsty provide commercial support?

Pigsty software itself is open-source and free, and provides commercial subscriptions for all budgets, providing quality assurance for Pigsty & PostgreSQL. Subscriptions provide broader OS/PG/chip architecture support ranges, as well as expert consulting and support. Pigsty commercial subscriptions deliver industry-leading management/technical experience/solutions, helping you save valuable time, shouldering risks for you, and providing a safety net for difficult problems.


Does Pigsty support domestic innovation (信创)?

Pigsty software itself is not a database and is not subject to domestic innovation catalog restrictions, and already has multiple military use cases. However, the Pigsty open-source edition does not provide any form of domestic innovation support. Commercial subscription provides domestic innovation solutions in cooperation with Alibaba Cloud, supporting the use of PolarDB-O with domestic innovation qualifications (requires separate purchase) as the RDS kernel, capable of running on domestic innovation OS/chip environments.


Can Pigsty run as a multi-tenant DBaaS?

If you use the Pigsty Infra module and distribute or operate it as part of a public cloud database service (DBaaS), you may use it for this purpose under the premise of complying with the AGPLv3 license — open-sourcing derivative works under the same license.

We reserve the right to hold public cloud/database vendors accountable for violating the AGPLv3 license. If you do not wish to open-source derivative works, we recommend purchasing the Pigsty Enterprise Edition subscription plan, which provides clear authorization for this use case and exemption from Pigsty’s AGPLv3 open-source obligations.


Can Pigsty’s Logo be rebranded as your own product?

When redistributing Pigsty, you must retain copyright notices, patent notices, trademark notices, and attribution notices from the original work, and attach prominent change descriptions in modified files while preserving the content of the LICENSE file. Under these premises, you can replace PIGSTY’s Logo and trademark, but you must not promote it as “your own original work.” We provide commercial licensing support for OEM and rebranding in the enterprise edition.


Pigsty’s Business Entity

Pigsty is a project invested by Miracle Plus S22. The original entity Panji Cloud Data (Beijing) Technology Co., Ltd. has been liquidated and divested of the Pigsty business.

Pigsty is currently independently operated and maintained by author Feng Ruohang. The business entities are:

  • Hainan Zhuxia Cloud Data Co., Ltd. / 91460000MAE6L87B94
  • Haikou Longhua Piji Data Center / 92460000MAG0XJ569B
  • Haikou Longhua Yuehang Technology Center / 92460000MACCYGBQ1N

PIGSTY® and PGSTY® are registered trademarks of Haikou Longhua Yuehang Technology Center.

2.12 - Release Note

Pigsty historical version release notes

The current stable version is v3.7.0, and the latest beta is v4.0.0-b3.

VersionRelease DateSummaryRelease Page
v4.0.02026-01-31Infra overhaul, security hardening, agent capabilities, fork & clonev4.0.0-c1
v3.7.02025-12-02PG18 default, 437 extensions, EL10 & Debian 13 support, PGEXT.CLOUDv3.7.0
v3.6.12025-08-15Routine PG minor updates, PGDG China mirror, EL10/D13 stubsv3.6.1
v3.6.02025-07-30pgactive, MinIO/ETCD improvements, simplified install, config cleanupv3.6.0
v3.5.02025-06-16PG18 beta, 421 extensions, monitoring upgrade, code refactorv3.5.0
v3.4.12025-04-05OpenHalo & OrioleDB, MySQL compatibility, pgAdmin improvementsv3.4.1
v3.4.02025-03-30Backup improvements, auto certs, AGE, IvorySQL all platformsv3.4.0
v3.3.02025-02-24404 extensions, extension directory, App playbook, Nginx customizationv3.3.0
v3.2.22025-01-23390 extensions, Omnigres, Mooncake, Citus 13 & PG17 supportv3.2.2
v3.2.12025-01-12350 extensions, Ivory4, Citus enhancements, Odoo templatev3.2.1
v3.2.02024-12-24Extension CLI, Grafana enhancements, ARM64 extension completionv3.2.0
v3.1.02024-11-24PG17 default, config simplification, Ubuntu24 & ARM supportv3.1.0
v3.0.42024-10-30PG17 extensions, OLAP suite, pg_duckdbv3.0.4
v3.0.32024-09-27PostgreSQL 17, Etcd improvements, IvorySQL 3.4, PostGIS 3.5v3.0.3
v3.0.22024-09-07Mini install mode, PolarDB 15 support, monitoring view updatesv3.0.2
v3.0.12024-08-31Routine bug fixes, Patroni 4 support, Oracle compatibility improvementsv3.0.1
v3.0.02024-08-25333 extensions, pluggable kernels, MSSQL/Oracle/PolarDB compatibilityv3.0.0
v2.7.02024-05-20Extension explosion, 20+ new powerful extensions, Docker appsv2.7.0
v2.6.02024-02-28PG16 as default, ParadeDB & DuckDB extensions introducedv2.6.0
v2.5.12023-12-01Routine minor update, PG16 key extension supportv2.5.1
v2.5.02023-09-24Ubuntu/Debian support: bullseye, bookworm, jammy, focalv2.5.0
v2.4.12023-09-24Supabase/PostgresML support with graphql, jwt, pg_net, vaultv2.4.1
v2.4.02023-09-14PG16, RDS monitoring, new extensions: FTS/graph/HTTP/embeddingv2.4.0
v2.3.12023-09-01PGVector with HNSW, PG16 RC1, doc refresh, Chinese docs, bug fixesv2.3.1
v2.3.02023-08-20Node VIP, FerretDB, NocoDB, MySQL stub, CVE fixesv2.3.0
v2.2.02023-08-04Dashboard & provisioning overhaul, UOS compatibilityv2.2.0
v2.1.02023-06-10PostgreSQL 12-16beta supportv2.1.0
v2.0.22023-03-31Added pgvector support, fixed MinIO CVEv2.0.2
v2.0.12023-03-21v2 bug fixes, security enhancements, Grafana upgradev2.0.1
v2.0.02023-02-28Major architecture upgrade, compatibility/security/maintainabilityv2.0.0
v1.5.12022-06-18Grafana security hotfixv1.5.1
v1.5.02022-05-31Docker application supportv1.5.0
v1.4.12022-04-20Bug fixes & full English documentation translationv1.4.1
v1.4.02022-03-31MatrixDB support, separated INFRA/NODES/PGSQL/REDIS modulesv1.4.0
v1.3.02021-11-30PGCAT overhaul & PGSQL enhancement & Redis beta supportv1.3.0
v1.2.02021-11-03Default PGSQL version upgraded to 14v1.2.0
v1.1.02021-10-12Homepage, JupyterLab, PGWEB, Pev2 & pgbadgerv1.1.0
v1.0.02021-07-26v1 GA, Monitoring System Overhaulv1.0.0
v0.9.02021-04-04Pigsty GUI, CLI, Logging Integrationv0.9.0
v0.8.02021-03-28Service Provisionv0.8.0
v0.7.02021-03-01Monitor only deploymentv0.7.0
v0.6.02021-02-19Architecture Enhancementv0.6.0
v0.5.02021-01-07Database Customize Templatev0.5.0
v0.4.02020-12-14PostgreSQL 13 Support, Official Documentationv0.4.0
v0.3.02020-10-22Provisioning Solution GAv0.3.0
v0.2.02020-07-10PGSQL Monitoring v6 GAv0.2.0
v0.1.02020-06-20Validation on Testing Environmentv0.1.0
v0.0.52020-08-19Offline Installation Modev0.0.5
v0.0.42020-07-27Refactor playbooks into Ansible rolesv0.0.4
v0.0.32020-06-22Interface enhancementv0.0.3
v0.0.22020-04-30First Commitv0.0.2
v0.0.12019-05-15POCv0.0.1

v4.0.0-c1

curl https://pigsty.cc/get | bash -s v4.0.0

Highlights

  • Observability Revolution: Prometheus → VictoriaMetrics (10x perf), Loki+Promtail → VictoriaLogs+Vector
  • Security Hardening: Auto-generated passwords, etcd RBAC, firewall/SELinux modes, permission tightening
  • Database Management: pg_databases state (create/absent/recreate), instant clone with strategy
  • PITR & Fork: /pg/bin/pg-fork for instant CoW cloning, enhanced pg-pitr with pre-backup
  • Multi-Cloud Terraform: AWS, Azure, GCP, Hetzner, DigitalOcean, Linode, Vultr, TencentCloud templates
  • AI Agent: Add support for claude code, opencode and uv
  • License: AGPL-3.0 → Apache-2.0

244 commits, 554 files changed, +94,508 / -41,374 lines

Infra Software Versions

PackageVersionPackageVersion
grafana12.3.1victoria-metrics1.132.0
victoria-logs1.43.1vector0.52.0
alertmanager0.30.0blackbox_exporter0.28.0
etcd3.6.7duckdb1.4.3
pg_exporter1.1.1pgbackrest_exporter0.22.0
minio20251203pig0.9.0
uv0.9.18 (new)opencode1.0.223 (new)

PostgreSQL Extensions

New: pg_textsearch 0.1.0, pg_clickhouse 0.1.0, pg_ai_query 0.1.1

Updated: IvorySQL 5.1, timescaledb 2.24.0, pg_search 0.20.4, pg_duckdb 1.1.1, pg_biscuit 2.0.1, pg_anon 2.5.1, pg_enigma 0.5.0, pg_session_jwt 0.4.0, pg_vectorize 0.26.0, vchord_bm25 0.3.0, wrappers 0.5.7

PG18 Deb Fixes: pg_vectorize, pg_tiktoken, pg_tzf, pglite_fusion, pgsmcrypto, pgx_ulid, plprql, pg_summarize, supautils

Breaking Changes

Observability Stack

BeforeAfter
PrometheusVictoriaMetrics
LokiVictoriaLogs
PromtailVector

Parameters

RemovedReplacement
node_disable_firewallnode_firewall_mode (off/none/zone)
node_disable_selinuxnode_selinux_mode (disabled/permissive/enforcing)
pg_pwd_encremoved
infra_pipinfra_uv

Defaults Changed

ParameterBefore → After
grafana_cleantrue → false
effective_io_concurrency1000 → 200
install.ymlrenamed to deploy.yml (symlink kept)

Observability

  • Using the new VictoriaMetrics to replace Prometheus — achieving several times the performance with a fraction of the resources.
  • Using the new log collection solution: VictoriaLogs + Vector, replacing Promtail + Loki.
  • Unified log format adjustments for all components, PG logs use UTC timestamp (log_timezone)
  • Adjusted PostgreSQL log rotation method, using weekly truncated log rotation mode
  • Recording temporary file allocations over 1MB in PG logs, enabling PG 17/18 log new parameters in specific templates
  • Added Nginx Access & Error / Syslog / PG CSV / Pgbackrest vector log parsing configurations
  • Datasource registration now runs on all Infra nodes, Victoria datasources automatically registered in Grafana
  • Added grafana_pgurl parameter allowing Grafana to use PG as backend metadata storage
  • Added grafana_view_pgpass parameter to specify password used by Grafana Meta datasource
  • pgbackrest_exporter default options now set a 120s internal cache interval (originally 600s)
  • grafana_clean parameter default now changed from true to false, i.e., not cleaned by default.
  • Added new metric collector pg_timeline, collecting more real-time timeline metrics pg_timeline_id
  • pg_exporter updated to 1.1.1, fixing numerous historical issues.

Interface Improvements

  • install.yml playbook now renamed to deploy.yml for better semantics.
  • pg_databases database provisioning improvements:
    • Added database removal capability: use state field to specify create, absent, recreate states.
    • Added clone capability: use strategy parameter in database definition to specify clone method
    • Support newer version locale config parameters: locale_provider, icu_locale, icu_rules, builtin_locale
    • Support is_template parameter to mark database as template database
    • Added more type checks, avoiding character parameter injection
    • Allow specifying state: absent in extension to remove extensions
  • pg_users user provisioning improvements: added admin parameter, similar to roles, but with ADMIN OPTION permission for re-granting.

Parameter Optimization

  • pg_io_method parameter, auto, sync, worker, io_uring four options available, default worker
  • idle_replication_slot_timeout, default 7d, crit template 3d
  • log_lock_failures, oltp, crit templates enabled
  • track_cost_delay_timing, olap, crit templates enabled
  • log_connections, oltp/olap enables authentication logs, crit enables all logs.
  • maintenance_io_concurrency set to 100 if using SSD
  • effective_io_concurrency reduced from 1000 to 200
  • file_copy_method parameter set to clone for PG18, providing instant database cloning capability
  • For PG17+, if pg_checksums switch is off, explicitly disable checksums during patroni cluster initialization
  • Fixed issue where duckdb.allow_community_extensions always took effect
  • Allow specifying HBA trusted “intranet segments” via node_firewall_intranet
  • pg_hba and pgbouncer_hba now support IPv6 localhost access

Architecture Improvements

  • On Infra nodes, set fixed /infra symlink pointing to Infra data directory /data/infra.
  • Infra data now defaults to /data/infra directory, making container usage more convenient.
  • Local software repo now placed at /data/nginx/pigsty, /www now a symlink to /data/nginx for compatibility.
  • DNS resolution records now placed under /infra/hosts directory, solving Ansible SELinux race condition issues
  • pg_remove/pg_pitr etcd metadata removal tasks now run on etcd cluster instead of depending on admin_ip management node
  • Simplify the 36-node simu template into the 20-node version.
  • Adapted to upstream changes, removed PGDG sysupdate repo, removed all llvmjit related packages on EL systems
  • Using full OS version numbers (major.minor) for EPEL 10 / PGDG 9/10 repos
  • Allow specifying meta parameter in repo definitions to override yum repo definition metadata
  • Added /pg/bin/pg-fork script for quickly creating CoW replica database instances
  • Adjusted /pg/bin/pg-pitr script, now usable for instance-level PITR recovery
  • Ensure vagrant libvirt templates default to 128GB disk, mounted at /data with xfs.
  • Ensure pgbouncer no longer modifies 0.0.0.0 listen address to *.
  • Multi-cloud Terraform templates: AWS, Azure, GCP, Hetzner, DigitalOcean, Linode, Vultr, TencentCloud

Security Improvements

  • configure now auto-generates random strong passwords, avoiding security risks from default passwords.
  • Removed node_disable_firewall, added node_firewall_mode supporting off, none, zone three modes.
  • Removed node_disable_selinux, added node_selinux_mode supporting disabled, permissive, enforcing three modes.
  • Added nginx basic auth support, allowing optional HTTP Basic Auth for Nginx Servers.
  • Fixed ownca certificate validity issues, ensuring Chrome can recognize self-signed certificates.
  • Changed MinIO module default password to avoid conflict with well-known default passwords
  • Enabled etcd RBAC, each cluster can now only manage its own PostgreSQL database cluster.
  • etcd root password now placed in /etc/etcd/etcd.pass file, readable only by administrators
  • Configured correct SELinux contexts for HAProxy, Nginx, DNSMasq, Redis and other components
  • Revoked executable script ownership permissions from all non-root users
  • Added admin_ip to Patroni API allowed access IP whitelist
  • Always create admin system user group, patronictl config restricted to admin group users only
  • Added node_admin_sudo parameter allowing specification/adjustment of database administrator sudo permission mode (all/nopass)
  • Fixed several ansible copy content field empty error issues.
  • Fixed some legacy issues in pg_pitr, ensuring no race conditions during patroni cluster recovery.

Bug Fixes

  • Fixed ownca certificate validity for Chrome compatibility
  • Fixed Vector 0.52 syslog_raw parsing issue
  • Fixed pg_pitr multiple replica clonefrom timing issues
  • Fixed Ansible SELinux race condition in dnsmasq
  • Fixed EL9 aarch64 patroni & llvmjit issues
  • Fixed Debian groupadd path issue
  • Fixed empty sudoers file generation
  • Fixed pgbouncer pid path (/run/postgresql)
  • Fixed duckdb.allow_community_extensions always active
  • Hidden pg_partman for EL8 due to upstream break

Checksums

4c38ca59e756f239448e7eb45d2236f0  pigsty-pkg-v4.0.0.d12.aarch64.tgz
020b0ded1af009d0e758de8a33393239  pigsty-pkg-v4.0.0.d12.x86_64.tgz
513c98a3ba911eebf10a1364fd70ce90  pigsty-pkg-v4.0.0.d13.aarch64.tgz
524ca6f1e8ef6ff821eff1f618f8683e  pigsty-pkg-v4.0.0.d13.x86_64.tgz
b5ad7a6b6dee0515e7a0dd33611b7aba  pigsty-pkg-v4.0.0.el10.aarch64.tgz
bb20de1730c9cce75f476f3dc444eab5  pigsty-pkg-v4.0.0.el10.x86_64.tgz
fe2f27406d218216beba9b92d7da3080  pigsty-pkg-v4.0.0.el8.aarch64.tgz
f2e12f9db85b280df5e4e6504bbf69af  pigsty-pkg-v4.0.0.el8.x86_64.tgz
73d79ef99e5030cb0daf5ec1bd8afe2f  pigsty-pkg-v4.0.0.el9.aarch64.tgz
27b59e5b4994dd0bb17d1b4f50eff96a  pigsty-pkg-v4.0.0.el9.x86_64.tgz
9838065e0c43c67a3ff2274c9b48f354  pigsty-pkg-v4.0.0.u22.aarch64.tgz
fec238e811b0f838770602ed1c93a5a1  pigsty-pkg-v4.0.0.u22.x86_64.tgz
0dc4140abd907c872c29db7b77aeb54a  pigsty-pkg-v4.0.0.u24.aarch64.tgz
3aa158fb40555f34e45422a4177850b7  pigsty-pkg-v4.0.0.u24.x86_64.tgz
8eeb5d05edf865543aafcc7fcb935825  pigsty-v4.0.0.tgz

v3.7.0

Highlights

  • PostgreSQL 18 Deep Support: Now the default major PG version, with full extension readiness!
  • Expanded OS Support: Added EL10 and Debian 13, bringing the total supported operating systems to 14.
  • Extension Growth: The PostgreSQL extension library now includes 437 entries.
  • Ansible 2.19 Compatibility: Full support for Ansible 2.19 following its breaking changes.
  • Kernel Updates: Latest versions for Supabase, PolarDB, IvorySQL, and Percona kernels.
  • Optimized Tuning: Refined logic for default PG parameters to maximize resource utilization.
  • PGEXT.CLOUD: Dedicated extension website open-sourced under Apache-2.0 license

Version Updates

  • PostgreSQL 18.1, 17.7, 16.11, 15.15, 14.20, 13.23
  • Patroni 4.1.0
  • Pgbouncer 1.25.0
  • pg_exporter 1.0.3
  • pgbackrest 2.57.0
  • Supabase 2025-11
  • PolarDB 15.15.5.0
  • FerretDB 2.7.0
  • DuckDB 1.4.2
  • Etcd 3.6.6
  • pig 0.7.4

For detailed version changes, please refer to:

API Changes

  • Implemented a refined optimization strategy for parallel execution parameters. See Tuning Guide.
  • The citus extension is no longer installed by default in rich and full templates (PG 18 support pending).
  • Added duckdb extension stubs to PostgreSQL parameter templates.
  • Capped min_wal_size, max_wal_size, and max_slot_wal_keep_size at 200 GB, 2000 GB, and 3000 GB, respectively.
  • Capped temp_file_limit at 200 GB (2 TB for OLAP workloads).
  • Increased the default connection count for the connection pool.
  • Added prometheus_port (default: 9058) to avoid conflicts with the EL10 RHEL Web Console port.
  • Changed alertmanager_port default to 9059 to avoid potential conflicts with Kafka SSL ports.
  • Added a pg_pre subtask to pg_pkg: removes conflicting LLVM packages (bpftool, python3-perf) on EL9+ prior to PG installation.
  • Added the llvm module to the default repository definition for Debian/Ubuntu.
  • Fixed package removal logic in infra-rm.yml.

Compatibility Fixes

  • Ubuntu/Debian CA Trust: Fixed incorrect warning return codes when trusting Certificate Authorities.
  • Ansible 2.19 Support: Resolved numerous compatibility issues introduced by Ansible 2.19 to ensure stability across versions:
    • Added explicit int type casting for sequence variables.
    • Migrated with_items syntax to loop.
    • Nested key exchange variables in lists to prevent character iteration on strings in newer versions.
    • Explicitly cast range usage to list.
    • Renamed reserved variables such as name and port.
    • Replaced play_hosts with ansible_play_hosts.
    • Added string casting for specific variables to prevent runtime errors.
  • EL10 Adaptation:
    • Fixed missing ansible-collection-community-crypto preventing key generation.
    • Fixed missing ansible logic packages.
    • Removed modulemd_tools, flamegraph, and timescaledb-tool.
    • Replaced java-17-openjdk with java-21-openjdk.
    • Resolved aarch64 YUM repository naming issues.
  • Debian 13 Adaptation:
    • Replaced dnsutils with bind9-dnsutils.
  • Ubuntu 24 Fixes:
    • Temporarily removed tcpdump due to upstream dependency crashes.

Checksums

e00d0c2ac45e9eff1cc77927f9cd09df  pigsty-v3.7.0.tgz
987529769d85a3a01776caefefa93ecb  pigsty-pkg-v3.7.0.d12.aarch64.tgz
2d8272493784ae35abeac84568950623  pigsty-pkg-v3.7.0.d12.x86_64.tgz
090cc2531dcc25db3302f35cb3076dfa  pigsty-pkg-v3.7.0.d13.x86_64.tgz
ddc54a9c4a585da323c60736b8560f55  pigsty-pkg-v3.7.0.el10.aarch64.tgz
d376e75c490e8f326ea0f0fbb4a8fd9b  pigsty-pkg-v3.7.0.el10.x86_64.tgz
8c2deeba1e1d09ef3d46d77a99494e71  pigsty-pkg-v3.7.0.el8.aarch64.tgz
9795e059bd884b9d1b2208011abe43cd  pigsty-pkg-v3.7.0.el8.x86_64.tgz
08b860155d6764ae817ed25f2fcf9e5b  pigsty-pkg-v3.7.0.el9.aarch64.tgz
1ac430768e488a449d350ce245975baa  pigsty-pkg-v3.7.0.el9.x86_64.tgz
e033aaf23690755848db255904ab3bcd  pigsty-pkg-v3.7.0.u22.aarch64.tgz
cc022ea89181d89d271a9aaabca04165  pigsty-pkg-v3.7.0.u22.x86_64.tgz
0e978598796db3ce96caebd76c76e960  pigsty-pkg-v3.7.0.u24.aarch64.tgz
48223898ace8812cc4ea79cf3178476a  pigsty-pkg-v3.7.0.u24.x86_64.tgz

v3.6.1

curl https://repo.pigsty.cc/get | bash -s v3.6.1

Highlights

  • PostgreSQL 17.6, 16.10, 15.14, 14.19, 13.22, and 18 Beta 3 Released!
  • PGDG APT/YUM mirror for Mainland China Users
  • New home website https://pgsty.com
  • Add el10, debian 13 stub, add el10 terraform images

Infra Package Updates

  • Grafana 12.1.0
  • pg_exporter 1.0.2
  • pig 0.6.1
  • vector 0.49.0
  • redis_exporter 1.75.0
  • mongo_exporter 0.47.0
  • victoriametrics 1.123.0
  • victorialogs: 1.28.0
  • grafana-victoriametrics-ds 0.18.3
  • grafana-victorialogs-ds 0.19.3
  • grafana-infinity-ds 3.4.1
  • etcd 3.6.4
  • ferretdb 2.5.0
  • tigerbeetle 0.16.54
  • genai-toolbox 0.12.0

Extension Package Updates

  • pg_search 0.17.3

API Changes

  • remove br_filter from default node_kernel_modules
  • do not use OS minor version dir for pgdg yum repos

Checksums

045977aff647acbfa77f0df32d863739  pigsty-pkg-v3.6.1.d12.aarch64.tgz
636b15c2d87830f2353680732e1af9d2  pigsty-pkg-v3.6.1.d12.x86_64.tgz
700a9f6d0db9c686d371bf1c05b54221  pigsty-pkg-v3.6.1.el8.aarch64.tgz
2aff03f911dd7be363ba38a392b71a16  pigsty-pkg-v3.6.1.el8.x86_64.tgz
ce07261b02b02b36a307dab83e460437  pigsty-pkg-v3.6.1.el9.aarch64.tgz
d598d62a47bbba2e811059a53fe3b2b5  pigsty-pkg-v3.6.1.el9.x86_64.tgz
13fd68752e59f5fd2a9217e5bcad0acd  pigsty-pkg-v3.6.1.u22.aarch64.tgz
c25ccfb98840c01eb7a6e18803de55bb  pigsty-pkg-v3.6.1.u22.x86_64.tgz
0d71e58feebe5299df75610607bf428c  pigsty-pkg-v3.6.1.u24.aarch64.tgz
4fbbab1f8465166f494110c5ec448937  pigsty-pkg-v3.6.1.u24.x86_64.tgz
083d8680fa48e9fec3c3fcf481d25d2f  pigsty-v3.6.1.tgz

v3.6.0

curl https://repo.pigsty.cc/get | bash -s v3.6.0

Highlights

  • Brand-new documentation site: https://doc.pgsty.com
  • Added pgsql-pitr playbook and backup/restore tutorial, improved PITR experience
  • Added kernel support: Percona PG TDE (PG17)
  • Optimized self-hosted Supabase experience, updated to the latest version, and fixed issues with the official template
  • Simplified installation steps, online install by default, bootstrap now part of install script

Improvements

  • Refactored ETCD module with dedicated remove playbook and bin utils
  • Refactored MinIO module with plain HTTP mode, better bucket provisioning options.
  • Reorganized and streamlined all configuration templates for easier use
  • Faster Docker Registry mirror for users in mainland China
  • Optimized tuned OS parameter templates for modern hardware and NVMe disks
  • Added extension pgactive for multi-master replication and sub-second failover
  • Adjusted default values for pg_fs_main / pg_fs_backup, simplified file directory structure design

Bug Fixes

  • Fixed pgbouncer configuration file error by @housei-zzy
  • Fixed OrioleDB issues on Debian platform
  • Fixed tuned shm configuration parameter issue
  • Offline packages now use the PGDG source directly, avoiding out-of-sync mirror sites
  • Fix ivorysql libxcrypt dependencies issues
  • Fix Replace the slow and broken epel mirror
  • Fix haproxy_enabled flag not working

Infra Package Updates

Added Victoria Metrics / Victoria Logs related packages

  • genai-toolbox 0.9.0 (new)
  • victoriametrics 1.120.0 -> 1.121.0 (refactor)
  • vmutils 1.121.0 (rename from victoria-metrics-utils)
  • grafana-victoriametrics-ds 0.15.1 -> 0.17.0
  • victorialogs 1.24.0 -> 1.25.1 (refactor)
  • vslogcli 1.24.0 -> 1.25.1
  • vlagent 1.25.1 (new)
  • grafana-victorialogs-ds 0.16.3 -> 0.18.1
  • prometheus 3.4.1 -> 3.5.0
  • grafana 12.0.0 -> 12.0.2
  • vector 0.47.0 -> 0.48.0
  • grafana-infinity-ds 3.2.1 -> 3.3.0
  • keepalived_exporter 1.7.0
  • blackbox_exporter 0.26.0 -> 0.27.0
  • redis_exporter 1.72.1 -> 1.77.0
  • rclone 1.69.3 -> 1.70.3

Database Package Updates

  • PostgreSQL 18 Beta2 update
  • pg_exporter 1.0.1, updated to latest dependencies and provides Docker image
  • pig 0.6.0, updated extension and repository list, with pig install subcommand
  • vip-manager 3.0.0 -> 4.0.0
  • ferretdb 2.2.0 -> 2.3.1
  • dblab 0.32.0 -> 0.33.0
  • duckdb 1.3.1 -> 1.3.2
  • etcd 3.6.1 -> 3.6.3
  • ferretdb 2.2.0 -> 2.4.0
  • juicefs 1.2.3 -> 1.3.0
  • tigerbeetle 0.16.41 -> 0.16.50
  • pev2 1.15.0 -> 1.16.0

Extension Package Updates

  • OrioleDB 1.5 beta12
  • OriolePG 17.11
  • plv8 3.2.3 -> 3.2.4
  • postgresql_anonymizer 2.1.1 -> 2.3.0
  • pgvectorscale 0.7.1 -> 0.8.0
  • wrappers 0.5.0 -> 0.5.3
  • supautils 2.9.1 -> 2.10.0
  • citus 13.0.3 -> 13.1.0
  • timescaledb 2.20.0 -> 2.21.1
  • vchord 0.3.0 -> 0.4.3
  • pgactive 2.1.5 (new)
  • documentdb 0.103.0 -> 0.105.0
  • pg_search 0.17.0

API Changes

  • pg_fs_backup: Renamed to pg_fs_backup, default value /data/backups.
  • pg_rm_bkup: Renamed to pg_rm_backup, default value true.
  • pg_fs_main: Default value adjusted to /data/postgres.
  • nginx_cert_validity: New parameter to control Nginx self-signed certificate validity, default 397d.
  • minio_buckets: Default value adjusted to create three buckets named pgsql, meta, data.
  • minio_users: Removed dba user, added s3user_meta and s3user_data users for meta and data buckets respectively.
  • minio_https: New parameter to allow MinIO to use HTTP mode.
  • minio_provision: New parameter to allow skipping MinIO provisioning stage (skip bucket and user creation)
  • minio_safeguard: New parameter, abort minio-rm.yml when enabled
  • minio_rm_data: New parameter, whether to remove minio data directory during minio-rm.yml
  • minio_rm_pkg: New parameter, whether to uninstall minio package during minio-rm.yml
  • etcd_learner: New parameter to control whether to init etcd instance as learner
  • etcd_rm_data: New parameter, whether to remove etcd data directory during etcd-rm.yml
  • etcd_rm_pkg: New parameter, whether to uninstall etcd package during etcd-rm.yml

Checksums

ab91bc05c54b88c455bf66533c1d8d43  pigsty-v3.6.0.tgz
cea861e2b4ec7ff5318e1b3c30b470cb  pigsty-pkg-v3.6.0.d12.aarch64.tgz
2f253af87e19550057c0e7fca876d37c  pigsty-pkg-v3.6.0.d12.x86_64.tgz
0158145b9bbf0e4a120b8bfa8b44f857  pigsty-pkg-v3.6.0.el8.aarch64.tgz
07330d687d04d26e7d569c8755426c5a  pigsty-pkg-v3.6.0.el8.x86_64.tgz
311df5a342b39e3288ebb8d14d81e0d1  pigsty-pkg-v3.6.0.el9.aarch64.tgz
92aad54cc1822b06d3e04a870ae14e29  pigsty-pkg-v3.6.0.el9.x86_64.tgz
c4fadf1645c8bbe3e83d5a01497fa9ca  pigsty-pkg-v3.6.0.u22.aarch64.tgz
5477ed6be96f156a43acd740df8a9b9b  pigsty-pkg-v3.6.0.u22.x86_64.tgz
196169afc1be02f93fcc599d42d005ca  pigsty-pkg-v3.6.0.u24.aarch64.tgz
dbe5c1e8a242a62fe6f6e1f6e6b6c281  pigsty-pkg-v3.6.0.u24.x86_64.tgz

v3.5.0

Highlights

  • New website: https://pgsty.com
  • PostgreSQL 18 (Beta) support: monitoring via pg_exporter 1.0.0, installer alias via pig 0.4.2, and a pg18 template
  • 421 bundled extensions, now including OrioleDB and OpenHalo kernels on all platforms
  • pig do CLI replaces legacy bin/ scripts
  • Hardening for self-hosted Supabase (replication lag, key distribution, etc.)
  • Code & architecture refactor — slimmer tasks, cleaner defaults for Postgres & PgBouncer
  • Monitoring stack refresh — Grafana 12, pg_exporter 1.0, new panels & plugins
  • Run vagrant on Apple Silicon
curl https://repo.pigsty.io/get | bash -s v3.5.0

Module Changes

  • Add PostgreSQL 18 support
  • PG18 metrics support with pg_exporter 1.0.0+
  • PG18 install support with pig 0.4.1+
  • New config template pg18.yml
  • Refactored pgsql module
  • Split monitoring into a new pg_monitor role; removed clean logic
  • Pruned duplicate tasks, dropped dir/utils block, renamed templates (no .j2)
  • All extensions install in extensions schema (Supabase best-practice)
  • Added SET search_path='' to every monitoring function
  • Tuned PgBouncer defaults (larger pool, cleanup query); new pgbouncer_ignore_param
  • New pg_key task to generate pgsodium master keys
  • Enabled sync_replication_slots by default on PG 17
  • Retagged subtasks for clearer structure
  • Refactored pg_remove module
  • New flags pg_rm_data, pg_rm_bkup, pg_rm_pkg control what gets wiped
  • Clearer role layout & tagging
  • Added new pg_monitor module
  • pgbouncer_exporter no longer shares configuration files with pg_exporter
  • Added monitoring metrics for TimescaleDB and Citus
  • Using pg_exporter 0.9.0 with updated replication slot metrics for PG16/17
  • Using more compact, newly designed collector configuration files
  • Supabase Enhancement (thanks @lawso017 for the contribution)
  • update supabase containers and schemas to the latest version
  • Support pgsodium server key loading
  • fix logflare lag issue with supa-kick crontab
  • add set search_path clause for monitor functions
  • Added new pig do command to CLI, allowing command-line tool to replace Shell scripts in bin/

Infra Package Updates

  • pig 0.4.2
  • duckdb 1.3.0
  • etcd 3.6.0
  • vector 0.47.0
  • minio 20250422221226
  • mcli 20250416181326
  • pev 1.5.0
  • rclone 1.69.3
  • mtail 3.0.8 (new)

Observability Package Updates

  • grafana 12.0.0
  • grafana-victorialogs-ds 0.16.3
  • grafana-victoriametrics-ds 0.15.1
  • grafana-infinity-ds 3.2.1
  • grafana_plugins 12.0.0
  • prometheus 3.4.0
  • pushgateway 1.11.1
  • nginx_exporter 1.4.2
  • pg_exporter 1.0.0
  • pgbackrest_exporter 0.20.0
  • redis_exporter 1.72.1
  • keepalived_exporter 1.6.2
  • victoriametrics 1.117.1
  • victoria_logs 1.22.2

Database Package Updates

  • PostgreSQL 17.5, 16.9, 15.13, 14.18, 13.21
  • PostgreSQL 18beta1 support
  • pgbouncer 1.24.1
  • pgbackrest 2.55
  • pgbadger 13.1

Extension Package Updates

  • spat 0.1.0a4 new extension
  • pgsentinel 1.1.0 new extension
  • pgdd 0.6.0 (pgrx 0.14.1) new extension add back
  • convert 0.0.4 (pgrx 0.14.1) new extension
  • pg_tokenizer.rs 0.1.0 (pgrx 0.13.1)
  • pg_render 0.1.2 (pgrx 0.12.8)
  • pgx_ulid 0.2.0 (pgrx 0.12.7)
  • pg_idkit 0.3.0 (pgrx 0.14.1)
  • pg_ivm 1.11.0
  • orioledb 1.4.0 beta11 rpm & add debian/ubuntu support
  • openhalo 14.10 add debian/ubuntu support
  • omnigres 20250507 (miss on d12/u22)
  • citus 12.0.3
  • timescaledb 2.20.0 (DROP PG14 support)
  • supautils 2.9.2
  • pg_envvar 1.0.1
  • pgcollection 1.0.0
  • aggs_for_vecs 1.4.0
  • pg_tracing 0.1.3
  • pgmq 1.5.1
  • tzf-pg 0.2.0 (pgrx 0.14.1)
  • pg_search 0.15.18 (pgrx 0.14.1)
  • anon 2.1.1 (pgrx 0.14.1)
  • pg_parquet 0.4.0 (0.14.1)
  • pg_cardano 1.0.5 (pgrx 0.12) -> 0.14.1
  • pglite_fusion 0.0.5 (pgrx 0.12.8) -> 14.1
  • vchord_bm25 0.2.1 (pgrx 0.13.1)
  • vchord 0.3.0 (pgrx 0.13.1)
  • pg_vectorize 0.22.1 (pgrx 0.13.1)
  • wrappers 0.4.6 (pgrx 0.12.9)
  • timescaledb-toolkit 1.21.0 (pgrx 0.12.9)
  • pgvectorscale 0.7.1 (pgrx 0.12.9)
  • pg_session_jwt 0.3.1 (pgrx 0.12.6) -> 0.12.9
  • pg_timetable 5.13.0
  • ferretdb 2.2.0
  • documentdb 0.103.0 (+aarch64 support)
  • pgml 2.10.0 (pgrx 0.12.9)
  • sqlite_fdw 2.5.0 (fix pg17 deb)
  • tzf 0.2.2 0.14.1 (rename src)
  • pg_vectorize 0.22.2 (pgrx 0.13.1)
  • wrappers 0.5.0 (pgrx 0.12.9)

Checksums

c7e5ce252ddf848e5f034173e0f29345  pigsty-v3.5.0.tgz
ba31f311a16d615c1ee1083dc5a53566  pigsty-pkg-v3.5.0.d12.aarch64.tgz
3aa5c56c8f0de53303c7100f2b3934f4  pigsty-pkg-v3.5.0.d12.x86_64.tgz
a098cb33822633357e6880eee51affd6  pigsty-pkg-v3.5.0.el8.x86_64.tgz
63723b0aeb4d6c02fff0da2c78e4de31  pigsty-pkg-v3.5.0.el9.aarch64.tgz
eb91c8921d7b8a135d8330c77468bfe7  pigsty-pkg-v3.5.0.el9.x86_64.tgz
87ff25e14dfb9001fe02f1dfbe70ae9e  pigsty-pkg-v3.5.0.u22.x86_64.tgz
18be503856f6b39a59efbd1d0a8556b6  pigsty-pkg-v3.5.0.u24.aarch64.tgz
2bbef6a18cfa99af9cd175ef0adf873c  pigsty-pkg-v3.5.0.u24.x86_64.tgz

v3.4.1

GitHub Release Page: v3.4.1

  • Added support for MySQL wire-compatible PostgreSQL kernel on EL systems: openHalo
  • Added support for OLTP-enhanced PostgreSQL kernel on EL systems: orioledb
  • Optimized pgAdmin 9.2 application template with automatic server list updates and pgpass password population
  • Increased PG default max connections to 250, 500, 1000
  • Removed the mysql_fdw extension with dependency errors from EL8

Infra Updates

  • pig 0.3.4
  • etcd 3.5.21
  • restic 0.18.0
  • ferretdb 2.1.0
  • tigerbeetle 0.16.34
  • pg_exporter 0.8.1
  • node_exporter 1.9.1
  • grafana 11.6.0
  • zfs_exporter 3.8.1
  • mongodb_exporter 0.44.0
  • victoriametrics 1.114.0
  • minio 20250403145628
  • mcli 20250403170756

Extension Update

  • Bump pg_search to 0.15.13
  • Bump citus to 13.0.3
  • Bump timescaledb to 2.19.1
  • Bump pgcollection RPM to 1.0.0
  • Bump pg_vectorize RPM to 0.22.1
  • Bump pglite_fusion RPM to 0.0.4
  • Bump aggs_for_vecs RPM to 1.4.0
  • Bump pg_tracing RPM to 0.1.3
  • Bump pgmq RPM to 1.5.1

Checksums

471c82e5f050510bd3cc04d61f098560  pigsty-v3.4.1.tgz
4ce17cc1b549cf8bd22686646b1c33d2  pigsty-pkg-v3.4.1.d12.aarch64.tgz
c80391c6f93c9f4cad8079698e910972  pigsty-pkg-v3.4.1.d12.x86_64.tgz
811bf89d1087512a4f8801242ca8bed5  pigsty-pkg-v3.4.1.el9.x86_64.tgz
9fe2e6482b14a3e60863eeae64a78945  pigsty-pkg-v3.4.1.u22.x86_64.tgz

v3.4.0

GitHub Release Page: v3.4.0

Introduction Blog: Pigsty v3.4 MySQL Compatibility and Overall Enhancements

New Features

  • Added new pgBackRest backup monitoring metrics and dashboards
  • Enhanced Nginx server configuration options, with support for automated Certbot issuance
  • Now prioritizing PostgreSQL’s built-in C/C.UTF-8 locale settings
  • IvorySQL 4.4 is now fully supported across all platforms (RPM/DEB on x86/ARM)
  • Added new software packages: Juicefs, Restic, TimescaleDB EventStreamer
  • The Apache AGE graph database extension now fully supports PostgreSQL 13–17 on EL
  • Improved the app.yml playbook: launch standard Docker app without extra config
  • Bump Supabase, Dify, and Odoo app templates, bump to their latest versions
  • Add electric app template, local-first PostgreSQL Sync Engine

Infra Packages

  • +restic 0.17.3
  • +juicefs 1.2.3
  • +timescaledb-event-streamer 0.12.0
  • Prometheus 3.2.1
  • AlertManager 0.28.1
  • blackbox_exporter 0.26.0
  • node_exporter 1.9.0
  • mysqld_exporter 0.17.2
  • kafka_exporter 1.9.0
  • redis_exporter 1.69.0
  • pgbackrest_exporter 0.19.0-2
  • DuckDB 1.2.1
  • etcd 3.5.20
  • FerretDB 2.0.0
  • tigerbeetle 0.16.31
  • vector 0.45.0
  • VictoriaMetrics 1.113.0
  • VictoriaLogs 1.17.0
  • rclone 1.69.1
  • pev2 1.14.0
  • grafana-victorialogs-ds 0.16.0
  • grafana-victoriametrics-ds 0.14.0
  • grafana-infinity-ds 3.0.0

PostgreSQL Related

  • Patroni 4.0.5
  • PolarDB 15.12.3.0-e1e6d85b
  • IvorySQL 4.4
  • pgbackrest 2.54.2
  • pev2 1.14
  • WiltonDB 13.17

PostgreSQL Extensions

  • pgspider_ext 1.3.0 (new extension)
  • apache age 13–17 el rpm (1.5.0)
  • timescaledb 2.18.2 → 2.19.0
  • citus 13.0.1 → 13.0.2
  • documentdb 1.101-0 → 1.102-0
  • pg_analytics 0.3.4 → 0.3.7
  • pg_search 0.15.2 → 0.15.8
  • pg_ivm 1.9 → 1.10
  • emaj 4.4.0 → 4.6.0
  • pgsql_tweaks 0.10.0 → 0.11.0
  • pgvectorscale 0.4.0 → 0.6.0 (pgrx 0.12.5)
  • pg_session_jwt 0.1.2 → 0.2.0 (pgrx 0.12.6)
  • wrappers 0.4.4 → 0.4.5 (pgrx 0.12.9)
  • pg_parquet 0.2.0 → 0.3.1 (pgrx 0.13.1)
  • vchord 0.2.1 → 0.2.2 (pgrx 0.13.1)
  • pg_tle 1.2.0 → 1.5.0
  • supautils 2.5.0 → 2.6.0
  • sslutils 1.3 → 1.4
  • pg_profile 4.7 → 4.8
  • pg_snakeoil 1.3 → 1.4
  • pg_jsonschema 0.3.2 → 0.3.3
  • pg_incremental 1.1.1 → 1.2.0
  • pg_stat_monitor 2.1.0 → 2.1.1
  • ddl_historization 0.7 → 0.0.7 (bug fix)
  • pg_sqlog 3.1.7 → 1.6 (bug fix)
  • pg_random removed development suffix (bug fix)
  • asn1oid 1.5 → 1.6
  • table_log 0.6.1 → 0.6.4

Interface Changes

  • Added new Docker parameters: docker_data and docker_storage_driver (#521 by @waitingsong)
  • Added new Infra parameter: alertmanager_port, which lets you specify the AlertManager port
  • Added new Infra parameter: certbot_sign, apply for cert during nginx init? (false by default)
  • Added new Infra parameter: certbot_email, specifying the email used when requesting certificates via Certbot
  • Added new Infra parameter: certbot_options, specifying additional parameters for Certbot
  • Updated IvorySQL to place its default binary under /usr/ivory-4 starting in IvorySQL 4.4
  • Changed the default for pg_lc_ctype and other locale-related parameters from en_US.UTF-8 to C
  • For PostgreSQL 17, if using UTF8 encoding with C or C.UTF-8 locales, PostgreSQL’s built-in localization rules now take priority
  • configure automatically detects whether C.utf8 is supported by both the PG version and the environment, and adjusts locale-related options accordingly
  • Set the default IvorySQL binary path to /usr/ivory-4
  • Updated the default value of pg_packages to pgsql-main patroni pgbouncer pgbackrest pg_exporter pgbadger vip-manager
  • Updated the default value of repo_packages to [node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-utility, extra-modules]
  • Removed LANG and LC_ALL environment variable settings from /etc/profile.d/node.sh
  • Now using bento/rockylinux-8 and bento/rockylinux-9 as the Vagrant box images for EL
  • Added a new alias, extra_modules, which includes additional optional modules
  • Updated PostgreSQL aliases: postgresql, pgsql-main, pgsql-core, pgsql-full
  • GitLab repositories are now included among available modules
  • The Docker module has been merged into the Infra module
  • The node.yml playbook now includes a node_pip task to configure a pip mirror on each node
  • The pgsql.yml playbook now includes a pgbackrest_exporter task for collecting backup metrics
  • The Makefile now allows the use of META/PKG environment variables
  • Added /pg/spool directory as temporary storage for pgBackRest
  • Disabled pgBackRest’s link-all option by default
  • Enabled block-level incremental backups for MinIO repositories by default

Bug Fixes

  • Fixed the exit status code in pg-backup (#532 by @waitingsong)
  • In pg-tune-hugepage, restricted PostgreSQL to use only large pages (#527 by @waitingsong)
  • Fixed logic errors in the pg-role task
  • Corrected type conversion for hugepage configuration parameters
  • Fixed default value issues for node_repo_modules in the slim template

Checksums

768bea3bfc5d492f4c033cb019a81d3a  pigsty-v3.4.0.tgz
7c3d47ef488a9c7961ca6579dc9543d6  pigsty-pkg-v3.4.0.d12.aarch64.tgz
b5d76aefb1e1caa7890b3a37f6a14ea5  pigsty-pkg-v3.4.0.d12.x86_64.tgz
42dacf2f544ca9a02148aeea91f3153a  pigsty-pkg-v3.4.0.el8.aarch64.tgz
d0a694f6cd6a7f2111b0971a60c49ad0  pigsty-pkg-v3.4.0.el8.x86_64.tgz
7caa82254c1b0750e89f78a54bf065f8  pigsty-pkg-v3.4.0.el9.aarch64.tgz
8f817e5fad708b20ee217eb2e12b99cb  pigsty-pkg-v3.4.0.el9.x86_64.tgz
8b2fcaa6ef6fd8d2726f6eafbb488aaf  pigsty-pkg-v3.4.0.u22.aarch64.tgz
83291db7871557566ab6524beb792636  pigsty-pkg-v3.4.0.u22.x86_64.tgz
c927238f0343cde82a4a9ab230ecd2ac  pigsty-pkg-v3.4.0.u24.aarch64.tgz
14cbcb90693ed5de8116648a1f2c3e34  pigsty-pkg-v3.4.0.u24.x86_64.tgz

v3.3.0

  • Total available extensions increased to 404!
  • PostgreSQL February Minor Updates: 17.4, 16.8, 15.12, 14.17, 13.20
  • New Feature: app.yml script for auto-installing apps like Odoo, Supabase, Dify.
  • New Feature: Further Nginx configuration customization in infra_portal.
  • New Feature: Added Certbot support for quick free HTTPS certificate requests.
  • New Feature: Pure-text extension list now supported in pg_default_extensions.
  • New Feature: Default repositories now include mongo, redis, groonga, haproxy, etc.
  • New Parameter: node_aliases to add command aliases for Nodes.
  • Fix: Resolved default EPEL repo address issue in Bootstrap script.
  • Improvement: Added Aliyun mirror for Debian Security repository.
  • Improvement: pgBackRest backup support for IvorySQL kernel.
  • Improvement: ARM64 and Debian/Ubuntu support for PolarDB.
  • pg_exporter 0.8.0 now supports new metrics in pgbouncer 1.24.
  • New Feature: Auto-completion for common commands like git, docker, systemctl #506 #507 by @waitingsong.
  • Improvement: Refined ignore_startup_parameters in pgbouncer config template #488 by @waitingsong.
  • New homepage design: Pigsty’s website now features a fresh new look.
  • Extension Directory: Detailed information and download links for RPM/DEB binary packages.
  • Extension Build: pig CLI now auto-sets PostgreSQL extension build environment.

New Extensions

12 new PostgreSQL extensions added, bringing the total to 404 available extensions.

Bump Extension

  • citus 13.0.0 -> 13.0.1
  • pg_duckdb 0.2.0 -> 0.3.1
  • pg_mooncake 0.1.0 -> 0.1.2
  • timescaledb 2.17.2 -> 2.18.2
  • supautils 2.5.0 -> 2.6.0
  • supabase_vault 0.3.1 (become C)
  • VectorChord 0.1.0 -> 0.2.1
  • pg_bulkload 3.1.22 (+pg17)
  • pg_store_plan 1.8 (+pg17)
  • pg_search 0.14 -> 0.15.2
  • pg_analytics 0.3.0 -> 0.3.4
  • pgroonga 3.2.5 -> 4.0.0
  • zhparser 2.2 -> 2.3
  • pg_vectorize 0.20.0 -> 0.21.1
  • pg_net 0.14.0
  • pg_curl 2.4.2
  • table_version 1.10.3 -> 1.11.0
  • pg_duration 1.0.2
  • pg_graphql 1.5.9 -> 1.5.11
  • vchord 0.1.1 -> 0.2.1 ((+13))
  • vchord_bm25 0.1.0 -> 0.1.1
  • pg_mooncake 0.1.1 -> 0.1.2
  • pgddl 0.29
  • pgsql_tweaks 0.11.0

Infra Updates

  • pig 0.1.3 -> 0.3.0
  • pushgateway 1.10.0 -> 1.11.0
  • alertmanager 0.27.0 -> 0.28.0
  • nginx_exporter 1.4.0 -> 1.4.1
  • pgbackrest_exporter 0.18.0 -> 0.19.0
  • redis_exporter 1.66.0 -> 1.67.0
  • mongodb_exporter 0.43.0 -> 0.43.1
  • VictoriaMetrics 1.107.0 -> 1.111.0
  • VictoriaLogs v1.3.2 -> 1.9.1
  • DuckDB 1.1.3 -> 1.2.0
  • Etcd 3.5.17 -> 3.5.18
  • pg_timetable 5.10.0 -> 5.11.0
  • FerretDB 1.24.0 -> 2.0.0-rc
  • tigerbeetle 0.16.13 -> 0.16.27
  • grafana 11.4.0 -> 11.5.2
  • vector 0.43.1 -> 0.44.0
  • minio 20241218131544 -> 20250218162555
  • mcli 20241121172154 -> 20250215103616
  • rclone 1.68.2 -> 1.69.0
  • vray 5.23 -> 5.28

v3.2.2

What’s Changed

  • Bump IvorySQL to 4.2 (PostgreSQL 17.2)
  • Add Arm64 and Debian support for PolarDB kernel
  • Add certbot and certbot-nginx to default infra_packages
  • Increase pgbouncer max_prepared_statements to 256
  • remove pgxxx-citus package alias
  • hide pgxxx-olap category in pg_extensions by default

v3.2.1

Highlights

  • 351 PostgreSQL Extensions, including the powerful postgresql-anonymizer 2.0
  • IvorySQL 4.0 support for EL 8/9
  • Now use the Pigsty compiled Citus, TimescaleDB and pgroonga on all distros
  • Add self-hosting Odoo template and support

Bump software versions

  • pig CLI 0.1.2 self-updating capability
  • prometheus 3.1.0

Add New Extension

  • add pg_anon 2.0.0
  • add omnisketch 1.0.2
  • add ddsketch 1.0.1
  • add pg_duration 1.0.1
  • add ddl_historization 0.0.7
  • add data_historization 1.1.0
  • add schedoc 0.0.1
  • add floatfile 1.3.1
  • add pg_upless 0.0.3
  • add pg_task 1.0.0
  • add pg_readme 0.7.0
  • add vasco 0.1.0
  • add pg_xxhash 0.0.1

Update Extension

  • lower_quantile 1.0.3
  • quantile 1.1.8
  • sequential_uuids 1.0.3
  • pgmq 1.5.0 (subdir)
  • floatvec 1.1.1
  • pg_parquet 0.2.0
  • wrappers 0.4.4
  • pg_later 0.3.0
  • topn fix for deb.arm64
  • add age 17 on debian
  • powa + pg17, 5.0.1
  • h3 + pg17
  • ogr_fdw + pg17
  • age + pg17 1.5 on debian
  • pgtap + pg17 1.3.3
  • repmgr
  • topn + pg17
  • pg_partman 5.2.4
  • credcheck 3.0
  • ogr_fdw 1.1.5
  • ddlx 0.29
  • postgis 3.5.1
  • tdigest 1.4.3
  • pg_repack 1.5.2

v3.2.0

Highlights

  • New CLI: Introducing the pig command-line tool for managing extension plugins.
  • ARM64 Support: 390 extensions are now available for ARM64 across five major distributions.
  • Supabase Update: Latest Supabase Release Week updates are now supported for self-hosting on all distributions.
  • Grafana v11.4: Upgraded Grafana to version 11.4, featuring a new Infinity datasource.

Package Changes

  • New Extensions
  • Added timescaledb, timescaledb-loader, timescaledb-toolkit, and timescaledb-tool to the PIGSTY repository.
  • Added a custom-compiled pg_timescaledb for EL.
  • Added pgroonga, custom-compiled for all EL variants.
  • Added vchord 0.1.0.
  • Added pg_bestmatch.rs 0.0.1.
  • Added pglite_fusion 0.0.3.
  • Added pgpdf 0.1.0.
  • Updated Extensions
  • pgvectorscale: 0.4.0 → 0.5.1
  • pg_parquet: 0.1.0 → 0.1.1
  • pg_polyline: 0.0.1
  • pg_cardano: 1.0.2 → 1.0.3
  • pg_vectorize: 0.20.0
  • pg_duckdb: 0.1.0 → 0.2.0
  • pg_search: 0.13.0 → 0.13.1
  • aggs_for_vecs: 1.3.1 → 1.3.2
  • Infrastructure
  • Added promscale 0.17.0
  • Added grafana-plugins 11.4
  • Added grafana-infinity-plugins
  • Added grafana-victoriametrics-ds
  • Added grafana-victorialogs-ds
  • vip-manager: 2.8.0 → 3.0.0
  • vector: 0.42.0 → 0.43.0
  • grafana: 11.3 → 11.4
  • prometheus: 3.0.0 → 3.0.1 (package name changed from prometheus2 to prometheus)
  • nginx_exporter: 1.3.0 → 1.4.0
  • mongodb_exporter: 0.41.2 → 0.43.0
  • VictoriaMetrics: 1.106.1 → 1.107.0
  • VictoriaLogs: 1.0.0 → 1.3.2
  • pg_timetable: 5.9.0 → 5.10.0
  • tigerbeetle: 0.16.13 → 0.16.17
  • pg_export: 0.7.0 → 0.7.1
  • New Docker App
  • Add mattermost the open-source Slack alternative self-hosting template
  • Bug Fixes
  • Added python3-cdiff for el8.aarch64 to fix missing Patroni dependency.
  • Added timescaledb-tools for el9.aarch64 to fix missing package in official repo.
  • Added pg_filedump for el9.aarch64 to fix missing package in official repo.
  • Removed Extensions
  • pg_mooncake: Removed due to conflicts with pg_duckdb.
  • pg_top: Removed because of repeated version issues and quality concerns.
  • hunspell_pt_pt: Removed because of conflict with official PG dictionary files.
  • pgml: Disabled by default (no longer downloaded or installed).

API Changes

  • repo_url_packages now defaults to an empty array; packages are installed via OS package managers.
  • grafana_plugin_cache is deprecated; Grafana plugins are now installed via OS package managers.
  • grafana_plugin_list is deprecated for the same reason.
  • The 36-node “production” template has been renamed to simu.
  • Auto-generated code under node_id/vars now includes aarch64 support.
  • infra_packages now includes the pig CLI tool.
  • The configure command now updates the version numbers of pgsql-xxx aliases in auto-generated config files.
  • Update terraform templates with Makefile shortcuts and better provision experience

Bug Fix

Checksums

c42da231067f25104b71a065b4a50e68  pigsty-pkg-v3.2.0.d12.aarch64.tgz
ebb818f98f058f932b57d093d310f5c2  pigsty-pkg-v3.2.0.d12.x86_64.tgz
d2b85676235c9b9f2f8a0ad96c5b15fd  pigsty-pkg-v3.2.0.el9.aarch64.tgz
649f79e1d94ec1845931c73f663ae545  pigsty-pkg-v3.2.0.el9.x86_64.tgz
24c0be1d8436f3c64627c12f82665a17  pigsty-pkg-v3.2.0.u22.aarch64.tgz
0b9be0e137661e440cd4f171226d321d  pigsty-pkg-v3.2.0.u22.x86_64.tgz
8fdc6a60820909b0a2464b0e2b90a3a6  pigsty-v3.2.0.tgz

v3.1.0

2024-11-24 : ARM64 & Ubuntu24, PG17 by Default, Better Supabase & MinIO

https://github.com/pgsty/pigsty/releases/tag/v3.1.0


v3.0.4

2024-10-28 : PostgreSQL 17 Extensions, Better self-hosting Supabase

https://github.com/pgsty/pigsty/releases/tag/v3.0.4


v3.0.3

2024-09-27 : PostgreSQL 17, Etcd Enhancement, IvorySQL 3.4, PostGIS 3.5

https://github.com/pgsty/pigsty/releases/tag/v3.0.3


v3.0.2

2024-09-07 : Mini Install, PolarDB 15, Bloat View Update

https://github.com/pgsty/pigsty/releases/tag/v3.0.2


v3.0.1

2024-08-31 : Oracle Compatibility, Patroni 4.0, Routine Bug Fix

https://github.com/pgsty/pigsty/releases/tag/v3.0.1


v3.0.0

2024-08-30 : Extension Exploding & Pluggable Kernels (MSSQL, Oracle)

https://github.com/pgsty/pigsty/releases/tag/v3.0.0


v2.7.0

2024-05-16 : Extension Overwhelming, new docker apps

https://github.com/pgsty/pigsty/releases/tag/v2.7.0


v2.6.0

2024-02-29 : PG 16 as default version, ParadeDB & DuckDB

https://github.com/pgsty/pigsty/releases/tag/v2.6.0


v2.5.1

2023-12-01 : Routine update, pg16 major extensions

https://github.com/pgsty/pigsty/releases/tag/v2.5.1


v2.5.0

2023-10-24 : Ubuntu/Debian Support: bullseye, bookworm, jammy, focal

https://github.com/pgsty/pigsty/releases/tag/v2.5.0


v2.4.1

2023-09-24 : Supabase/PostgresML support, graphql, jwt, pg_net, vault

https://github.com/pgsty/pigsty/releases/tag/v2.4.1


v2.4.0

2023-09-14 : PG16, RDS Monitor, New Extensions

https://github.com/pgsty/pigsty/releases/tag/v2.4.0


v2.3.1

2023-09-01 : PGVector with HNSW, PG16 RC1, Chinese Docs, Bug Fix

https://github.com/pgsty/pigsty/releases/tag/v2.3.1


v2.3.0

2023-08-20 : PGSQL/REDIS Update, NODE VIP, Mongo/FerretDB, MYSQL Stub

https://github.com/pgsty/pigsty/releases/tag/v2.3.0


v2.2.0

2023-08-04 : Dashboard & Provision overhaul, UOS compatibility

https://github.com/pgsty/pigsty/releases/tag/v2.2.0


v2.1.0

2023-06-10 : PostgreSQL 12 ~ 16beta support

https://github.com/pgsty/pigsty/releases/tag/v2.1.0


v2.0.2

2023-03-31 : Add pgvector support and fix MinIO CVE

https://github.com/pgsty/pigsty/releases/tag/v2.0.2


v2.0.1

2023-03-21 : v2 Bug Fix, security enhance and bump grafana version

https://github.com/pgsty/pigsty/releases/tag/v2.0.1


v2.0.0

2023-02-28 : Compatibility Security Maintainability Enhancement

https://github.com/pgsty/pigsty/releases/tag/v2.0.0


v1.5.1

2022-06-18 : Grafana Security Hotfix

https://github.com/pgsty/pigsty/releases/tag/v1.5.1


v1.5.0

2022-05-31 : Docker Applications

https://github.com/pgsty/pigsty/releases/tag/v1.5.0


v1.4.1

2022-04-20 : Bug fix & Full translation of English documents.

https://github.com/pgsty/pigsty/releases/tag/v1.4.1


v1.4.0

2022-03-31 : MatrixDB Support, Separated INFRA, NODES, PGSQL, REDIS

https://github.com/pgsty/pigsty/releases/tag/v1.4.0


v1.3.0

2021-11-30 : PGCAT Overhaul & PGSQL Enhancement & Redis Support Beta

https://github.com/pgsty/pigsty/releases/tag/v1.3.0


v1.2.0

2021-11-03 : Upgrade default Postgres to 14, monitoring existing pg

https://github.com/pgsty/pigsty/releases/tag/v1.2.0


v1.1.0

2021-10-12 : HomePage, JupyterLab, PGWEB, Pev2 & Pgbadger

https://github.com/pgsty/pigsty/releases/tag/v1.1.0


v1.0.0

2021-07-26 : v1 GA, Monitoring System Overhaul

https://github.com/pgsty/pigsty/releases/tag/v1.0.0


v0.9.0

2021-04-04 : Pigsty GUI, CLI, Logging Integration

https://github.com/pgsty/pigsty/releases/tag/v0.9.0


v0.8.0

2021-03-28 : Service Provision

https://github.com/pgsty/pigsty/releases/tag/v0.8.0


v0.7.0

2021-03-01 : Monitor only deployment

https://github.com/pgsty/pigsty/releases/tag/v0.7.0


v0.6.0

2021-02-19 : Architecture Enhancement

https://github.com/pgsty/pigsty/releases/tag/v0.6.0


v0.5.0

2021-01-07 : Database Customize Template

https://github.com/pgsty/pigsty/releases/tag/v0.5.0


v0.4.0

2020-12-14 : PostgreSQL 13 Support, Official Documentation

https://github.com/pgsty/pigsty/releases/tag/v0.4.0


v0.3.0

2020-10-22 : Provisioning Solution GA

https://github.com/pgsty/pigsty/releases/tag/v0.3.0


v0.2.0

2020-07-10 : PGSQL Monitoring v6 GA

https://github.com/pgsty/pigsty/commit/385e33a62a19817e8ba19997260e6b77d99fe2ba


v0.1.0

2020-06-20 : Validation on Testing Environment

https://github.com/pgsty/pigsty/commit/1cf2ea5ee91db071de00ec805032928ff582453b


v0.0.5

2020-08-19 : Offline Installation Mode

https://github.com/pgsty/pigsty/commit/0fe9e829b298fe5e56307de3f78c95071de28245


v0.0.4

2020-07-27 : Refactor playbooks into ansible roles

https://github.com/pgsty/pigsty/commit/90b44259818d2c71e37df5250fe8ed1078a883d0


v0.0.3

2020-06-22 : Interface enhancement

https://github.com/pgsty/pigsty/commit/4c5c68ccd57bc32a9e9c98aa3f264aa19f45c7ee


v0.0.2

2020-04-30 : First Commit

https://github.com/pgsty/pigsty/commit/dd646775624ddb33aef7884f4f030682bdc371f8


v0.0.1

2019-05-15 : POC

https://github.com/Vonng/pg/commit/fa2ade31f8e81093eeba9d966c20120054f0646b


2.13 - Comparison

This article compares Pigsty with similar products and projects, highlighting feature differences.

Comparison with RDS

Pigsty is a local-first RDS alternative released under AGPLv3, deployable on your own physical/virtual machines or cloud servers.

We’ve chosen Amazon AWS RDS for PostgreSQL (the global market leader) and Alibaba Cloud RDS for PostgreSQL (China’s market leader) as benchmarks for comparison.

Both Aliyun RDS and AWS RDS are closed-source cloud database services, available only through rental models on public clouds. The following comparison is based on the latest PostgreSQL 16 as of February 2024.


Feature Comparison

FeaturePigstyAliyun RDSAWS RDS
Major Version Support13 - 1813 - 1813 - 18
Read Replicas Supports unlimited read replicas Standby instances not exposed to users Standby instances not exposed to users
Read/Write Splitting Port-based traffic separation Separate paid component Separate paid component
Fast/Slow Separation Supports offline ETL instances Not available Not available
Cross-Region DR Supports standby clusters Multi-AZ deployment supported Multi-AZ deployment supported
Delayed Replicas Supports delayed instances Not available Not available
Load Balancing HAProxy / LVS Separate paid component Separate paid component
Connection Pool Pgbouncer Separate paid component: RDS Separate paid component: RDS Proxy
High Availability Patroni / etcd Requires HA edition Requires HA edition
Point-in-Time Recovery pgBackRest / MinIO Backup supported Backup supported
Metrics Monitoring Prometheus / Exporter Free basic / Paid advanced Free basic / Paid advanced
Log Collection Loki / Promtail Basic support Basic support
Visualization Grafana / Echarts Basic monitoring Basic monitoring
Alert Aggregation AlertManager Basic support Basic support

Key Extensions

Here are some important extensions compared based on PostgreSQL 16, as of 2024-02-28

ExtensionPigsty RDS / PGDG Official RepoAliyun RDSAWS RDS
Install Extensions Free to install Not allowed Not allowed
Geospatial PostGIS 3.4.2 PostGIS 3.3.4 / Ganos 6.1 PostGIS 3.4.1
Point Cloud PG PointCloud 1.2.5 Ganos PointCloud 6.1
Vector Embedding PGVector 0.6.1 / Svector 0.5.6 pase 0.0.1 PGVector 0.6
Machine Learning PostgresML 2.8.1
Time Series TimescaleDB 2.14.2
Horizontal Scaling Citus 12.1
Columnar Storage Hydra 1.1.1
Full Text Search pg_bm25 0.5.6
Graph Database Apache AGE 1.5.0
GraphQL PG GraphQL 1.5.0
OLAP pg_analytics 0.5.6
Message Queue pgq 3.5.0
DuckDB duckdb_fdw 1.1
Fuzzy Tokenization zhparser 1.1 / pg_bigm 1.2 zhparser 1.0 / pg_jieba pg_bigm 1.2
CDC Extraction wal2json 2.5.3 wal2json 2.5
Bloat Management pg_repack 1.5.0 pg_repack 1.4.8 pg_repack 1.5.0
AWS RDS PG Available Extensions

AWS RDS for PostgreSQL 16 available extensions (excluding PG built-in extensions)

namepg16pg15pg14pg13pg12pg11pg10
amcheck1.31.31.31.21.2yes1
auto_explainyesyesyesyesyesyesyes
autoinc1111nullnullnull
bloom1111111
bool_plperl1111nullnullnull
btree_gin1.31.31.31.31.31.31.2
btree_gist1.71.71.61.51.51.51.5
citext1.61.61.61.61.61.51.4
cube1.51.51.51.41.41.41.2
dblink1.21.21.21.21.21.21.2
dict_int1111111
dict_xsyn1111111
earthdistance1.11.11.11.11.11.11.1
fuzzystrmatch1.21.11.11.11.11.11.1
hstore1.81.81.81.71.61.51.4
hstore_plperl1111111
insert_username1111nullnullnull
intagg1.11.11.11.11.11.11.1
intarray1.51.51.51.31.21.21.2
isn1.21.21.21.21.21.21.1
jsonb_plperl11111nullnull
lo1.11.11.11.11.11.11.1
ltree1.21.21.21.21.11.11.1
moddatetime1111nullnullnull
old_snapshot111nullnullnullnull
pageinspect1.121.111.91.81.71.71.6
pg_buffercache1.41.31.31.31.31.31.3
pg_freespacemap1.21.21.21.21.21.21.2
pg_prewarm1.21.21.21.21.21.21.1
pg_stat_statements1.11.11.91.81.71.61.6
pg_trgm1.61.61.61.51.41.41.3
pg_visibility1.21.21.21.21.21.21.2
pg_walinspect1.11nullnullnullnullnull
pgcrypto1.31.31.31.31.31.31.3
pgrowlocks1.21.21.21.21.21.21.2
pgstattuple1.51.51.51.51.51.51.5
plperl1111111
plpgsql1111111
pltcl1111111
postgres_fdw1.11.11.11111
refint1111nullnullnull
seg1.41.41.41.31.31.31.1
sslinfo1.21.21.21.21.21.21.2
tablefunc1111111
tcn1111111
tsm_system_rows1111111.1
tsm_system_time1111111.1
unaccent1.11.11.11.11.11.11.1
uuid-ossp1.11.11.11.11.11.11.1
Aliyun RDS PG Available Extensions

Aliyun RDS for PostgreSQL 16 available extensions (excluding PG built-in extensions)

namepg16pg15pg14pg13pg12pg11pg10description
bloom1111111Provides a bloom filter-based index access method.
btree_gin1.31.31.31.31.31.31.2Provides GIN operator class examples that implement B-tree equivalent behavior for multiple data types and all enum types.
btree_gist1.71.71.61.51.51.51.5Provides GiST operator class examples that implement B-tree equivalent behavior for multiple data types and all enum types.
citext1.61.61.61.61.61.51.4Provides a case-insensitive string type.
cube1.51.51.51.41.41.41.2Provides a data type for representing multi-dimensional cubes.
dblink1.21.21.21.21.21.21.2Cross-database table operations.
dict_int1111111Additional full-text search dictionary template example.
earthdistance1.11.11.11.11.11.11.1Provides two different methods to calculate great circle distances on the Earth’s surface.
fuzzystrmatch1.21.11.11.11.11.11.1Determines similarities and distances between strings.
hstore1.81.81.81.71.61.51.4Stores key-value pairs in a single PostgreSQL value.
intagg1.11.11.11.11.11.11.1Provides an integer aggregator and an enumerator.
intarray1.51.51.51.31.21.21.2Provides some useful functions and operators for manipulating null-free integer arrays.
isn1.21.21.21.21.21.21.1Validates input according to a hard-coded prefix list, also used for concatenating numbers during output.
ltree1.21.21.21.21.11.11.1For representing labels of data stored in a hierarchical tree structure.
pg_buffercache1.41.31.31.31.31.31.3Provides a way to examine the shared buffer cache in real time.
pg_freespacemap1.21.21.21.21.21.21.2Examines the free space map (FSM).
pg_prewarm1.21.21.21.21.21.21.1Provides a convenient way to load data into the OS buffer or PostgreSQL buffer.
pg_stat_statements1.11.11.91.81.71.61.6Provides a means of tracking execution statistics of all SQL statements executed by a server.
pg_trgm1.61.61.61.51.41.41.3Provides functions and operators for alphanumeric text similarity, and index operator classes that support fast searching of similar strings.
pgcrypto1.31.31.31.31.31.31.3Provides cryptographic functions for PostgreSQL.
pgrowlocks1.21.21.21.21.21.21.2Provides a function to show row locking information for a specified table.
pgstattuple1.51.51.51.51.51.51.5Provides multiple functions to obtain tuple-level statistics.
plperl1111111Provides Perl procedural language.
plpgsql1111111Provides SQL procedural language.
pltcl1111111Provides Tcl procedural language.
postgres_fdw1.11.11.11111Cross-database table operations.
sslinfo1.21.21.21.21.21.21.2Provides information about the SSL certificate provided by the current client.
tablefunc1111111Contains multiple table-returning functions.
tsm_system_rows1111111Provides the table sampling method SYSTEM_ROWS.
tsm_system_time1111111Provides the table sampling method SYSTEM_TIME.
unaccent1.11.11.11.11.11.11.1A text search dictionary that can remove accents (diacritics) from lexemes.
uuid-ossp1.11.11.11.11.11.11.1Provides functions to generate universally unique identifiers (UUIDs) using several standard algorithms.
xml21.11.11.11.11.11.11.1Provides XPath queries and XSLT functionality.

Performance Comparison

MetricPigstyAliyun RDSAWS RDS
Peak PerformancePGTPC on NVME SSD Benchmark sysbench oltp_rwRDS PG Performance Whitepaper sysbench oltp scenario QPS 4000 ~ 8000 per core
Storage Spec: Max Capacity32TB / NVME SSD32 TB / ESSD PL364 TB / io2 EBS Block Express
Storage Spec: Max IOPS4K Random Read: Max 3M, Random Write 2000~350K4K Random Read: Max 1M16K Random IOPS: 256K
Storage Spec: Max Latency4K Random Read: 75µs, Random Write: 15µs4K Random Read: 200µs500µs / Inferred as 16K random IO
Storage Spec: Max ReliabilityUBER < 1e-18, equivalent to 18 nines MTBF: 2M hours 5DWPD, 3 years continuousReliability 9 nines, equivalent to UBER 1e-9 Storage and Data ReliabilityDurability: 99.999%, 5 nines (0.001% annual failure rate) io2 specification
Storage Spec: Max Cost¥31.5/TB·month (5-year warranty amortized / 3.2T / Enterprise-grade / MLC)¥3200/TB·month (original ¥6400, monthly ¥4000) 50% off with 3-year prepaid¥1900/TB·month using max spec 65536GB / 256K IOPS best discount

Observability

Pigsty provides nearly 3000 monitoring metrics and 50+ monitoring dashboards, covering database monitoring, host monitoring, connection pool monitoring, load balancer monitoring, and more, providing users with an unparalleled observability experience.

Pigsty provides 638 PostgreSQL-related monitoring metrics, while AWS RDS only has 99, and Aliyun RDS has only single-digit metrics:

Additionally, some projects provide PostgreSQL monitoring capabilities, but are relatively simple:


Maintainability

MetricPigstyAliyun RDSAWS RDS
System UsabilitySimpleSimpleSimple
Configuration ManagementConfig files / CMDB based on Ansible InventoryCan use TerraformCan use Terraform
Change MethodIdempotent Playbooks based on Ansible PlaybookConsole click operationsConsole click operations
Parameter TuningAuto-adapts to node specs, Four preset templates: OLTP, OLAP, TINY, CRIT
Infra as CodeNatively supportedCan use TerraformCan use Terraform
Customizable ParametersPigsty Parameters 283 parameters
Service & SupportCommercial subscription support availableAfter-sales ticket supportAfter-sales ticket support
Air-gapped DeploymentOffline installation supportedN/AN/A
Database MigrationPlaybooks for zero-downtime migration from existing v10+ PG instances to Pigsty managed instances via logical replicationCloud migration assistance Aliyun RDS Data Sync

Cost

Based on experience, RDS unit cost is 5-15 times that of self-hosted for software and hardware resources, with a rent-to-own ratio typically around one month. For details, see Cost Analysis.

FactorMetricPigstyAliyun RDSAWS RDS
CostSoftware License/Service FeeFree, hardware ~¥20-40/core·month¥200-400/core·month¥400-1300/core·month
Support Service FeeService ~¥100/core·monthIncluded in RDS cost

Other On-Premises Database Management Software

Some software and vendors providing PostgreSQL management capabilities:

  • Aiven: Closed-source commercial cloud-hosted solution
  • Percona: Commercial consulting, simple PG distribution
  • ClusterControl: Commercial database management software

Other Kubernetes Operators

Pigsty refuses to use Kubernetes for managing databases in production, so there are ecological differences with these solutions.

  • PGO
  • StackGres
  • CloudNativePG
  • TemboOperator
  • PostgresOperator
  • PerconaOperator
  • Kubegres
  • KubeDB
  • KubeBlocks

For more information, see:

2.13.1 - Cost Reference

This article provides cost data to help you evaluate self-hosted Pigsty, cloud RDS costs, and typical DBA salaries.

Overview

EC2Core·MonthRDSCore·Month
DHH Self-Hosted Core-Month Price (192C 384G)25.32Junior Open Source DB DBA Reference Salary¥15K/person·month
IDC Self-Hosted (Dedicated Physical: 64C384G)19.53Mid-Level Open Source DB DBA Reference Salary¥30K/person·month
IDC Self-Hosted (Container, 500% Oversold)7Senior Open Source DB DBA Reference Salary¥60K/person·month
UCloud Elastic VM (8C16G, Oversold)25ORACLE Database License10000
Aliyun ECS 2x Memory (Dedicated, No Oversold)107Aliyun RDS PG 2x Memory (Dedicated)260
Aliyun ECS 4x Memory (Dedicated, No Oversold)138Aliyun RDS PG 4x Memory (Dedicated)320
Aliyun ECS 8x Memory (Dedicated, No Oversold)180Aliyun RDS PG 8x Memory (Dedicated)410
AWS C5D.METAL 96C 200G (Monthly No Prepaid)100AWS RDS PostgreSQL db.T2 (2x)440
AWS C5D.METAL 96C 200G (3-Year Prepaid)80AWS RDS PostgreSQL db.M5 (4x)611
AWS C7A.METAL 192C 384G (3-Year Prepaid)104.8AWS RDS PostgreSQL db.R6G (8x)786

RDS Cost Reference

Payment ModelPriceAnnualized (¥10K)
IDC Self-Hosted (Single Physical Machine)¥75K / 5 years1.5
IDC Self-Hosted (2-3 Machines for HA)¥150K / 5 years3.0 ~ 4.5
Aliyun RDS On-Demand¥87.36/hour76.5
Aliyun RDS Monthly (Baseline)¥42K / month50
Aliyun RDS Annual (85% off)¥425,095 / year42.5
Aliyun RDS 3-Year Prepaid (50% off)¥750,168 / 3 years25
AWS On-Demand$25,817 / month217
AWS 1-Year No Prepaid$22,827 / month191.7
AWS 3-Year Full Prepaid$120K + $17.5K/month175
AWS China/Ningxia On-Demand¥197,489 / month237
AWS China/Ningxia 1-Year No Prepaid¥143,176 / month171
AWS China/Ningxia 3-Year Full Prepaid¥647K + ¥116K/month160.6

Here’s a comparison of self-hosted vs cloud database costs:

MethodAnnualized (¥10K)
IDC Hosted Server 64C / 384G / 3.2TB NVME SSD 660K IOPS (2-3 Machines)3.0 ~ 4.5
Aliyun RDS PG HA Edition pg.x4m.8xlarge.2c, 64C / 256GB / 3.2TB ESSD PL325 ~ 50
AWS RDS PG HA Edition db.m5.16xlarge, 64C / 256GB / 3.2TB io1 x 80k IOPS160 ~ 217

ECS Cost Reference

Pure Compute Price Comparison (Excluding NVMe SSD / ESSD PL3)

Using Aliyun as an example, the monthly pure compute price is 5-7x the self-hosted baseline, while 5-year prepaid is 2x self-hosted

Payment ModelUnit Price (¥/Core·Month)Relative to StandardSelf-Hosted Premium Multiple
On-Demand (1.5x)¥ 202160 %9.2 ~ 11.2
Monthly (Standard)¥ 126100 %5.7 ~ 7.0
1-Year Prepaid (65% off)¥ 83.766 %3.8 ~ 4.7
2-Year Prepaid (55% off)¥ 70.656 %3.2 ~ 3.9
3-Year Prepaid (44% off)¥ 55.144 %2.5 ~ 3.1
4-Year Prepaid (35% off)¥ 4535 %2.0 ~ 2.5
5-Year Prepaid (30% off)¥ 38.530 %1.8 ~ 2.1
DHH @ 2023¥ 22.0
Tantan IDC Self-Hosted¥ 18.0

Equivalent Price Comparison Including NVMe SSD / ESSD PL3

Including common NVMe SSD specs, the monthly pure compute price is 11-14x the self-hosted baseline, while 5-year prepaid is about 9x.

Payment ModelUnit Price (¥/Core·Month)+ 40GB ESSD PL3Self-Hosted Premium Multiple
On-Demand (1.5x)¥ 202¥ 36214.3 ~ 18.6
Monthly (Standard)¥ 126¥ 28611.3 ~ 14.7
1-Year Prepaid (65% off)¥ 83.7¥ 2449.6 ~ 12.5
2-Year Prepaid (55% off)¥ 70.6¥ 2309.1 ~ 11.8
3-Year Prepaid (44% off)¥ 55.1¥ 2158.5 ~ 11.0
4-Year Prepaid (35% off)¥ 45¥ 2058.1 ~ 10.5
5-Year Prepaid (30% off)¥ 38.5¥ 1997.9 ~ 10.2
DHH @ 2023¥ 25.3
Tantan IDC Self-Hosted¥ 19.5

DHH Case: 192 cores with 12.8TB Gen4 SSD (1c:66); Tantan Case: 64 cores with 3.2T Gen3 MLC SSD (1c:50).

Cloud prices calculated at 40GB ESSD PL3 per core (1 core:4x RAM:40x disk).


EBS Cost Reference

Evaluation FactorLocal PCI-E NVME SSDAliyun ESSD PL3AWS io2 Block Express
Capacity32TB32 TB64 TB
IOPS4K Random Read: 600K ~ 1.1M, 4K Random Write: 200K ~ 350K4K Random Read: Max 1M16K Random IOPS: 256K
Latency4K Random Read: 75µs, 4K Random Write: 15µs4K Random Read: 200µsRandom IO: ~500µs (contextually inferred as 16K)
ReliabilityUBER < 1e-18, equivalent to 18 nines, MTBF: 2M hours, 5DWPD for 3 yearsData Reliability 9 nines Storage and Data ReliabilityDurability: 99.999%, 5 nines (0.001% annual failure rate) io2 Specification
Cost¥16/TB·month (5-year amortized / 3.2T MLC), 5-year warranty, ¥3000 retail¥3200/TB·month (original ¥6400, monthly ¥4000), 50% off with 3-year full prepaid¥1900/TB·month using max spec 65536GB 256K IOPS best discount
SLA5-year warranty, replacement on failureAliyun RDS SLA Availability 99.99%: 15% monthly fee, 99%: 30% monthly fee, 95%: 100% monthly feeAmazon RDS SLA Availability 99.95%: 15% monthly fee, 99%: 25% monthly fee, 95%: 100% monthly fee

S3 Cost Reference

Date$/GB·Month¥/TB·5YearsHDD ¥/TBSSD ¥/TB
2006.030.150630002800
2010.110.140588001680
2012.120.0953990042015400
2014.040.030126003719051
2016.120.02396602453766
2023.120.0239660105280
Other ReferencesHigh-Perf StorageTop-Tier Discountedvs Purchased NVMe SSDPrice Ref
S3 Express0.16067200DHH 12T1400
EBS io20.125 + IOPS114000Shannon 3.2T900

Cloud Exit Collection

There was a time when “moving to the cloud” was almost politically correct in tech circles, and an entire generation of app developers had their vision obscured by the cloud. Let’s use real data analysis and firsthand experience to explain the value and pitfalls of the public cloud rental model — for your reference in this era of cost reduction and efficiency improvement — please see “Cloud Computing Mudslide: Collection

Cloud Infrastructure Basics


Cloud Business Model


Cloud Exit Odyssey


Cloud Failure Post-Mortems


RDS Failures


Cloud Vendor Profiles

3 - Concepts

Understand Pigsty’s core concepts, architecture design, and principles. Master high availability, backup recovery, security compliance, and other key capabilities.

Pigsty is a portable, extensible open-source PostgreSQL distribution for building production-grade database services in local environments with declarative configuration and automation. It has a vast ecosystem providing a complete set of tools, scripts, and best practices to bring PostgreSQL to enterprise-grade RDS service levels.

Pigsty’s name comes from PostgreSQL In Great STYle, also understood as Postgres, Infras, Graphics, Service, Toolbox, it’s all Yours—a self-hosted PostgreSQL solution with graphical monitoring that’s all yours. You can find the source code on GitHub, visit the official documentation for more information, or experience the Web UI in the online demo.

pigsty-banner


Why Pigsty? What Can It Do?

PostgreSQL is a sufficiently perfect database kernel, but it needs more tools and systems to become a truly excellent database service. In production environments, you need to manage every aspect of your database: high availability, backup recovery, monitoring alerts, access control, parameter tuning, extension installation, connection pooling, load balancing…

Wouldn’t it be easier if all this complex operational work could be automated? This is precisely why Pigsty was created.

Pigsty provides:

  • Out-of-the-Box PostgreSQL Distribution

    Pigsty deeply integrates 440+ extensions from the PostgreSQL ecosystem, providing out-of-the-box distributed, time-series, geographic, spatial, graph, vector, search, and other multi-modal database capabilities. From kernel to RDS distribution, providing production-grade database services for versions 13-18 on EL/Debian/Ubuntu.

  • Self-Healing High Availability Architecture

    A high availability architecture built on Patroni, Etcd, and HAProxy enables automatic failover for hardware failures with seamless traffic handoff. Primary failure recovery time RTO < 30s, data recovery point RPO ≈ 0. You can perform rolling maintenance and upgrades on the entire cluster without application coordination.

  • Complete Point-in-Time Recovery Capability

    Based on pgBackRest and optional MinIO cluster, providing out-of-the-box PITR point-in-time recovery capability. Giving you the ability to quickly return to any point in time, protecting against software defects and accidental data deletion.

  • Flexible Service Access and Traffic Management

    Through HAProxy, Pgbouncer, and VIP, providing flexible service access patterns for read-write separation, connection pooling, and automatic routing. Delivering stable, reliable, auto-routing, transaction-pooled high-performance database services.

  • Stunning Observability

    A modern observability stack based on Prometheus and Grafana provides unparalleled monitoring best practices. Over three thousand types of monitoring metrics describe every aspect of the system, from global dashboards to CRUD operations on individual objects.

  • Declarative Configuration Management

    Following the Infrastructure as Code philosophy, using declarative configuration to describe the entire environment. You just tell Pigsty “what kind of database cluster you want” without worrying about how to implement it—the system automatically adjusts to the desired state.

  • Modular Architecture Design

    A modular architecture design that can be freely combined to suit different scenarios. Beyond the core PostgreSQL module, it also provides optional modules for Redis, MinIO, Etcd, FerretDB, and support for various PG-compatible kernels.

  • Solid Security Best Practices

    Industry-leading security best practices: self-signed CA certificate encryption, AES encrypted backups, scram-sha-256 encrypted passwords, out-of-the-box ACL model, HBA rule sets following the principle of least privilege, ensuring data security.

  • Simple and Easy Deployment

    All dependencies are pre-packaged for one-click installation in environments without internet access. Local sandbox environments can run on micro VMs with 1 core and 2GB RAM, providing functionality identical to production environments. Provides Vagrant-based local sandboxes and Terraform-based cloud deployments.


What Pigsty Is Not

Pigsty is not a traditional, all-encompassing PaaS (Platform as a Service) system.

  • Pigsty doesn’t provide basic hardware resources. It runs on nodes you provide, whether bare metal, VMs, or cloud instances, but it doesn’t create or manage these resources itself (though it provides Terraform templates to simplify cloud resource preparation).

  • Pigsty is not a container orchestration system. It runs directly on the operating system, not requiring Kubernetes or Docker as infrastructure. Of course, it can coexist with these systems and provides a Docker module for running stateless applications.

  • Pigsty is not a general database management tool. It focuses on PostgreSQL and its ecosystem. While it also supports peripheral components like Redis, Etcd, and MinIO, the core is always built around PostgreSQL.

  • Pigsty won’t lock you in. It’s built on open-source components, doesn’t modify the PostgreSQL kernel, and introduces no proprietary protocols. You can continue using your well-managed PostgreSQL clusters anytime without Pigsty.

Pigsty doesn’t restrict how you should or shouldn’t build your database services. For example:

  • Pigsty provides good parameter defaults and configuration templates, but you can override any parameter.
  • Pigsty provides a declarative API, but you can still use underlying tools (Ansible, Patroni, pgBackRest, etc.) for manual management.
  • Pigsty can manage the complete lifecycle, or you can use only its monitoring system to observe existing database instances or RDS.

Pigsty provides a different level of abstraction than the hardware layer—it works at the database service layer, focusing on how to deliver PostgreSQL at its best, rather than reinventing the wheel.


Evolution of PostgreSQL Deployment

To understand Pigsty’s value, let’s review the evolution of PostgreSQL deployment approaches.

Manual Deployment Era

In traditional deployment, DBAs needed to manually install and configure PostgreSQL, manually set up replication, manually configure monitoring, and manually handle failures. The problems with this approach are obvious:

  • Low efficiency: Each instance requires repeating many manual operations, prone to errors.
  • Lack of standardization: Databases configured by different DBAs can vary greatly, making maintenance difficult.
  • Poor reliability: Failure handling depends on manual intervention, with long recovery times and susceptibility to human error.
  • Weak observability: Lack of unified monitoring, making problem discovery and diagnosis difficult.

Managed Database Era

To solve these problems, cloud providers offer managed database services (RDS). Cloud RDS does solve some operational issues, but also brings new challenges:

  • High cost: Managed services typically charge multiples to dozens of times hardware cost as “service fees.”
  • Vendor lock-in: Migration is difficult, tied to specific cloud platforms.
  • Limited functionality: Cannot use certain advanced features, extensions are restricted, parameter tuning is limited.
  • Data sovereignty: Data stored in the cloud, reducing autonomy and control.

Local RDS Era

Pigsty represents a third approach: building database services in local environments that match or exceed cloud RDS.

Pigsty combines the advantages of both approaches:

  • High automation: One-click deployment, automatic configuration, self-healing failures—as convenient as cloud RDS.
  • Complete autonomy: Runs on your own infrastructure, data completely in your own hands.
  • Extremely low cost: Run enterprise-grade database services at near-pure-hardware costs.
  • Complete functionality: Unlimited use of PostgreSQL’s full capabilities and ecosystem extensions.
  • Open architecture: Based on open-source components, no vendor lock-in, free to migrate anytime.

This approach is particularly suitable for:

  • Private and hybrid clouds: Enterprises needing to run databases in local environments.
  • Cost-sensitive users: Organizations looking to reduce database TCO.
  • High-security scenarios: Critical data requiring complete autonomy and control.
  • PostgreSQL power users: Scenarios requiring advanced features and rich extensions.
  • Development and testing: Quickly setting up databases locally that match production environments.

What’s Next

Now that you understand Pigsty’s basic concepts, you can:

3.1 - Architecture

Pigsty’s modular architecture—declarative composition, on-demand customization, flexible deployment.

Pigsty uses a modular architecture with a declarative interface. You can freely combine modules like building blocks as needed.


Modules

Pigsty uses a modular design with six main default modules: PGSQL, INFRA, NODE, ETCD, REDIS, and MINIO.

  • PGSQL: Self-healing HA Postgres clusters powered by Patroni, Pgbouncer, HAproxy, PgBackrest, and more.
  • INFRA: Local software repo, Nginx, Grafana, Victoria, AlertManager, Blackbox Exporter—the complete observability stack.
  • NODE: Tune nodes to desired state—hostname, timezone, NTP, ssh, sudo, haproxy, docker, vector, keepalived.
  • ETCD: Distributed key-value store as DCS for HA Postgres clusters: consensus leader election/config management/service discovery.
  • REDIS: Redis servers supporting standalone primary-replica, sentinel, and cluster modes with full monitoring.
  • MINIO: S3-compatible simple object storage that can serve as an optional backup destination for PG databases.

You can declaratively compose them freely. If you only want host monitoring, installing the INFRA module on infrastructure nodes and the NODE module on managed nodes is sufficient. The ETCD and PGSQL modules are used to build HA PG clusters—installing these modules on multiple nodes automatically forms a high-availability database cluster. You can reuse Pigsty infrastructure and develop your own modules; REDIS and MINIO can serve as examples. More modules will be added—preliminary support for Mongo and MySQL is already on the roadmap.

Note that all modules depend strongly on the NODE module: in Pigsty, nodes must first have the NODE module installed to be managed before deploying other modules. When nodes (by default) use the local software repo for installation, the NODE module has a weak dependency on the INFRA module. Therefore, the admin/infrastructure nodes with the INFRA module complete the bootstrap process in the deploy.yml playbook, resolving the circular dependency.

pigsty-sandbox


Standalone Installation

By default, Pigsty installs on a single node (physical/virtual machine). The deploy.yml playbook installs INFRA, ETCD, PGSQL, and optionally MINIO modules on the current node, giving you a fully-featured observability stack (Prometheus, Grafana, Loki, AlertManager, PushGateway, BlackboxExporter, etc.), plus a built-in PostgreSQL standalone instance as a CMDB, ready to use out of the box (cluster name pg-meta, database name meta).

This node now has a complete self-monitoring system, visualization tools, and a Postgres database with PITR auto-configured (HA unavailable since you only have one node). You can use this node as a devbox, for testing, running demos, and data visualization/analysis. Or, use this node as an admin node to deploy and manage more nodes!

pigsty-arch


Monitoring

The installed standalone meta node can serve as an admin node and monitoring center to bring more nodes and database servers under its supervision and control.

Pigsty’s monitoring system can be used independently. If you want to install the Prometheus/Grafana observability stack, Pigsty provides best practices! It offers rich dashboards for host nodes and PostgreSQL databases. Whether or not these nodes or PostgreSQL servers are managed by Pigsty, with simple configuration, you immediately have a production-grade monitoring and alerting system, bringing existing hosts and PostgreSQL under management.

pigsty-dashboard.jpg


HA PostgreSQL Clusters

Pigsty helps you own your own production-grade HA PostgreSQL RDS service anywhere.

To create such an HA PostgreSQL cluster/RDS service, you simply describe it with a short config and run the playbook to create it:

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 }
$ bin/pgsql-add pg-test  # Initialize cluster 'pg-test'

In less than 10 minutes, you’ll have a PostgreSQL database cluster with service access, monitoring, backup PITR, and HA fully configured.

pigsty-ha.png

Hardware failures are covered by the self-healing HA architecture provided by patroni, etcd, and haproxy—in case of primary failure, automatic failover executes within 30 seconds by default. Clients don’t need to modify config or restart applications: Haproxy uses patroni health checks for traffic distribution, and read-write requests are automatically routed to the new cluster primary, avoiding split-brain issues. This process is seamless—for example, in case of replica failure or planned switchover, clients experience only a momentary flash of the current query.

Software failures, human errors, and datacenter-level disasters are covered by pgbackrest and the optional MinIO cluster. This provides local/cloud PITR capabilities and, in case of datacenter failure, offers cross-region replication and disaster recovery.

3.1.1 - Nodes

A node is an abstraction of hardware/OS resources—physical machines, bare metal, VMs, or containers/pods.

A node is an abstraction of hardware resources and operating systems. It can be a physical machine, bare metal, virtual machine, or container/pod.

Any machine running a Linux OS (with systemd daemon) and standard CPU/memory/disk/network resources can be treated as a node.

Nodes can have modules installed. Pigsty has several node types, distinguished by which modules are deployed:

TypeDescription
Regular NodeA node managed by Pigsty
ADMIN NodeThe node that runs Ansible to issue management commands
INFRA NodeNodes with the INFRA module installed
ETCD NodeNodes with the ETCD module for DCS
MINIO NodeNodes with the MINIO module for object storage
PGSQL NodeNodes with the PGSQL module installed
Nodes with other modules…

In a singleton Pigsty deployment, multiple roles converge on one node: it serves as the regular node, admin node, infra node, ETCD node, and database node simultaneously.


Regular Node

Nodes managed by Pigsty can have modules installed. The node.yml playbook configures nodes to the desired state. A regular node may run the following services:

ComponentPortDescriptionStatus
node_exporter9100Host metrics exporterEnabled
haproxy9101HAProxy load balancer (admin port)Enabled
vector9598Log collection agentEnabled
docker9323Container runtime supportOptional
keepalivedn/aL2 VIP for node clusterOptional
keepalived_exporter9650Keepalived status monitorOptional

Here, node_exporter exposes host metrics, vector sends logs to the collection system, and haproxy provides load balancing. These three are enabled by default. Docker, keepalived, and keepalived_exporter are optional and can be enabled as needed.


ADMIN Node

A Pigsty deployment has exactly one admin node—the node that runs Ansible playbooks and issues control/deployment commands.

This node has ssh/sudo access to all other nodes. Admin node security is critical; ensure access is strictly controlled.

During single-node installation and configuration, the current node becomes the admin node. However, alternatives exist. For example, if your laptop can SSH to all managed nodes and has Ansible installed, it can serve as the admin node—though this isn’t recommended for production.

For instance, you might use your laptop to manage a Pigsty VM in the cloud. In this case, your laptop is the admin node.

In serious production environments, the admin node is typically 1-2 dedicated DBA machines. In resource-constrained setups, INFRA nodes often double as admin nodes since all INFRA nodes have Ansible installed by default.


INFRA Node

A Pigsty deployment may have 1 or more INFRA nodes; large production environments typically have 2-3.

The infra group in the inventory defines which nodes are INFRA nodes. These nodes run the INFRA module with these components:

ComponentPortDescription
nginx80/443Web UI, local software repository
grafana3000Visualization platform
victoriaMetrics8428Time-series database (metrics)
victoriaLogs9428Log collection server
victoriaTraces10428Trace collection server
vmalert8880Alerting and derived metrics
alertmanager9093Alert aggregation and routing
blackbox_exporter9115Blackbox probing (ping nodes/VIPs)
dnsmasq53Internal DNS resolution
chronyd123NTP time server
ansible-Playbook execution

Nginx serves as the module’s entry point, providing the web UI and local software repository. With multiple INFRA nodes, services on each are independent, but you can access all monitoring data sources from any INFRA node’s Grafana.

Note: The INFRA module is licensed under AGPLv3 due to Grafana. As an exception, if you only use Nginx/Victoria components without Grafana, you’re effectively under Apache-2.0.


ETCD Node

The ETCD module provides Distributed Consensus Service (DCS) for PostgreSQL high availability.

The etcd group in the inventory defines ETCD nodes. These nodes run etcd servers on two ports:

ComponentPortDescription
etcd2379ETCD key-value store (client port)
etcd2380ETCD cluster peer communication

MINIO Node

The MINIO module provides optional backup storage for PostgreSQL.

The minio group in the inventory defines MinIO nodes. These nodes run MinIO servers on:

ComponentPortDescription
minio9000MinIO S3 API endpoint
minio9001MinIO admin console

PGSQL Node

Nodes with the PGSQL module are called PGSQL nodes. Node and PostgreSQL instance have a 1:1 deployment—one PG instance per node.

PGSQL nodes can borrow identity from their PostgreSQL instance—controlled by node_id_from_pg, defaulting to true, meaning the node name is set to the PG instance name.

PGSQL nodes run these additional components beyond regular node services:

ComponentPortDescriptionStatus
postgres5432PostgreSQL database serverEnabled
pgbouncer6432PgBouncer connection poolEnabled
patroni8008Patroni HA managementEnabled
pg_exporter9630PostgreSQL metrics exporterEnabled
pgbouncer_exporter9631PgBouncer metrics exporterEnabled
pgbackrest_exporter9854pgBackRest metrics exporterEnabled
vip-managern/aBinds L2 VIP to cluster primaryOptional
{{ pg_cluster }}-primary5433HAProxy service: pooled read/writeEnabled
{{ pg_cluster }}-replica5434HAProxy service: pooled read-onlyEnabled
{{ pg_cluster }}-default5436HAProxy service: primary direct connectionEnabled
{{ pg_cluster }}-offline5438HAProxy service: offline readEnabled
{{ pg_cluster }}-<service>543xHAProxy service: custom PostgreSQL servicesCustom

The vip-manager is only enabled when users configure a PG VIP. Additional custom services can be defined in pg_services, exposed via haproxy using additional service ports.


Node Relationships

Regular nodes typically reference an INFRA node via the admin_ip parameter as their infrastructure provider. For example, with global admin_ip = 10.10.10.10, all nodes use infrastructure services at this IP.

Parameters that reference ${admin_ip}:

ParameterModuleDefault ValueDescription
repo_endpointINFRAhttp://${admin_ip}:80Software repo URL
repo_upstream.baseurlINFRAhttp://${admin_ip}/pigstyLocal repo baseurl
infra_portal.endpointINFRA${admin_ip}:<port>Nginx proxy backend
dns_recordsINFRA["${admin_ip} i.pigsty", ...]DNS records
node_default_etc_hostsNODE["${admin_ip} i.pigsty"]Default static DNS
node_etc_hostsNODE-Custom static DNS
node_dns_serversNODE["${admin_ip}"]Dynamic DNS servers
node_ntp_serversNODE-NTP servers (optional)

Typically the admin node and INFRA node coincide. With multiple INFRA nodes, the admin node is usually the first one; others serve as backups.

In large-scale production deployments, you might separate the Ansible admin node from INFRA module nodes. For example, use 1-2 small dedicated hosts under the DBA team as the control hub (ADMIN nodes), and 2-3 high-spec physical machines as monitoring infrastructure (INFRA nodes).

Typical node counts by deployment scale:

ScaleADMININFRAETCDMINIOPGSQL
Single-node11101
3-node13303
Small prod1230N
Large prod2354+N

3.1.2 - Infrastructure

Infrastructure module architecture, components, and functionality in Pigsty.

Running production-grade, highly available PostgreSQL clusters typically requires a comprehensive set of infrastructure services (foundation) for support, such as monitoring and alerting, log collection, time synchronization, DNS resolution, and local software repositories. Pigsty provides the INFRA module to address this—it’s an optional module, but we strongly recommend enabling it.


Overview

The diagram below shows the architecture of a single-node deployment. The right half represents the components included in the INFRA module:

ComponentTypeDescription
NginxWeb ServerUnified entry for WebUI, local repo, reverse proxy for internal services
RepoSoftware RepoAPT/DNF repository with all RPM/DEB packages needed for deployment
GrafanaVisualizationDisplays metrics, logs, and traces; hosts dashboards, reports, and custom data apps
VictoriaMetricsTime Series DBScrapes all metrics, Prometheus API compatible, provides VMUI query interface
VictoriaLogsLog PlatformCentralized log storage; all nodes run Vector by default, pushing logs here
VictoriaTracesTracingCollects slow SQL, service traces, and other tracing data
VMAlertAlert EngineEvaluates alerting rules, pushes events to Alertmanager
AlertManagerAlert ManagerAggregates alerts, dispatches notifications via email, Webhook, etc.
BlackboxExporterBlackbox ProbeProbes reachability of IPs/VIPs/URLs
DNSMASQDNS ServiceProvides DNS resolution for domains used within Pigsty [Optional]
ChronydTime SyncProvides NTP time synchronization to ensure consistent time across nodes [Optional]
CACertificateIssues encryption certificates within the environment
AnsibleOrchestrationBatch, declarative, agentless tool for managing large numbers of servers

pigsty-arch


Nginx

Nginx is the access entry point for all WebUI services in Pigsty, using ports 80 / 443 for HTTP/HTTPS by default. Live Demo

IP Access (replace)Domain (HTTP)Domain (HTTPS)Public Demo
http://10.10.10.10http://i.pigstyhttps://i.pigstyhttps://demo.pigsty.io

Infrastructure components with WebUIs can be exposed uniformly through Nginx, such as Grafana, VictoriaMetrics (VMUI), AlertManager, and HAProxy console. Additionally, the local software repository and other static resources are served via Nginx.

Nginx configures local web servers or reverse proxy servers based on definitions in infra_portal.

infra_portal:
  home : { domain: i.pigsty }

By default, it exposes Pigsty’s admin homepage: i.pigsty. Different endpoints on this page proxy different components:

EndpointComponentNative PortNotesPublic Demo
/Nginx80/443Homepage, local repo, file serverdemo.pigsty.io
/ui/Grafana3000Grafana dashboard entrydemo.pigsty.io/ui/
/vmetrics/VictoriaMetrics8428Time series DB Web UIdemo.pigsty.io/vmetrics/
/vlogs/VictoriaLogs9428Log DB Web UIdemo.pigsty.io/vlogs/
/vtraces/VictoriaTraces10428Tracing Web UIdemo.pigsty.io/vtraces/
/vmalert/VMAlert8880Alert rule managementdemo.pigsty.io/vmalert/
/alertmgr/AlertManager9059Alert management Web UIdemo.pigsty.io/alertmgr/
/blackbox/Blackbox9115Blackbox probe

Pigsty allows rich customization of Nginx as a local file server or reverse proxy, with self-signed or real HTTPS certificates.

For more information, see: Tutorial: Nginx—Expose Web Services via Proxy and Tutorial: Certbot—Request and Renew HTTPS Certificates


Repo

Pigsty creates a local software repository on the Infra node during installation to accelerate subsequent software installations. Live Demo

This repository defaults to the /www/pigsty directory, served by Nginx and mounted at the /pigsty path:

IP Access (replace)Domain (HTTP)Domain (HTTPS)Public Demo
http://10.10.10.10/pigstyhttp://i.pigsty/pigstyhttps://i.pigsty/pigstyhttps://demo.pigsty.io/pigsty

Pigsty supports offline installation, which essentially pre-copies a prepared local software repository to the target environment. When Pigsty performs production deployment and needs to create a local software repository, if it finds the /www/pigsty/repo_complete marker file already exists locally, it skips downloading packages from upstream and uses existing packages directly, avoiding internet downloads.

For more information, see: Config: INFRA - REPO


Grafana

Grafana is the core component of Pigsty’s monitoring system, used for visualizing metrics, logs, and various information. Live Demo

Grafana listens on port 3000 by default and is proxied via Nginx at the /ui path:

IP Access (replace)Domain (HTTP)Domain (HTTPS)Public Demo
http://10.10.10.10/uihttp://i.pigsty/uihttps://i.pigsty/uihttps://demo.pigsty.io/ui

Pigsty provides pre-built dashboards based on VictoriaMetrics / Logs / Traces, with one-click drill-down and roll-up via URL jumps for rapid troubleshooting.

Grafana can also serve as a low-code visualization platform, so ECharts, victoriametrics-datasource, victorialogs-datasource plugins are installed by default, with Vector / Victoria datasources registered uniformly as vmetrics-*, vlogs-*, vtraces-* for easy custom dashboard extension.

For more information, see: Config: INFRA - GRAFANA.


VictoriaMetrics

VictoriaMetrics is Pigsty’s time series database, responsible for scraping and storing all monitoring metrics. Live Demo

It listens on port 8428 by default, mounted at Nginx /vmetrics path, and also accessible via the p.pigsty domain:

IP Access (replace)Domain (HTTP)Domain (HTTPS)Public Demo
http://10.10.10.10/vmetricshttp://p.pigstyhttps://i.pigsty/vmetricshttps://demo.pigsty.io/vmetrics

VictoriaMetrics is fully compatible with the Prometheus API, supporting PromQL queries, remote read/write protocols, and the Alertmanager API. The built-in VMUI provides an ad-hoc query interface for exploring metrics data directly, and also serves as a Grafana datasource.

For more information, see: Config: INFRA - VICTORIA


VictoriaLogs

VictoriaLogs is Pigsty’s log platform, centrally storing structured logs from all nodes. Live Demo

It listens on port 9428 by default, mounted at Nginx /vlogs path:

IP Access (replace)Domain (HTTP)Domain (HTTPS)Public Demo
http://10.10.10.10/vlogshttp://i.pigsty/vlogshttps://i.pigsty/vlogshttps://demo.pigsty.io/vlogs

All managed nodes run Vector Agent by default, collecting system logs, PostgreSQL logs, Patroni logs, Pgbouncer logs, etc., processing them into structured format and pushing to VictoriaLogs. The built-in Web UI supports log search and filtering, and can be integrated with Grafana’s victorialogs-datasource plugin for visual analysis.

For more information, see: Config: INFRA - VICTORIA


VictoriaTraces

VictoriaTraces is used for collecting trace data and slow SQL records. Live Demo

It listens on port 10428 by default, mounted at Nginx /vtraces path:

IP Access (replace)Domain (HTTP)Domain (HTTPS)Public Demo
http://10.10.10.10/vtraceshttp://i.pigsty/vtraceshttps://i.pigsty/vtraceshttps://demo.pigsty.io/vtraces

VictoriaTraces provides a Jaeger-compatible interface for analyzing service call chains and database slow queries. Combined with Grafana dashboards, it enables rapid identification of performance bottlenecks and root cause tracing.

For more information, see: Config: INFRA - VICTORIA


VMAlert

VMAlert is the alerting rule computation engine, responsible for evaluating alert rules and pushing triggered events to Alertmanager. Live Demo

It listens on port 8880 by default, mounted at Nginx /vmalert path:

IP Access (replace)Domain (HTTP)Domain (HTTPS)Public Demo
http://10.10.10.10/vmalerthttp://i.pigsty/vmalerthttps://i.pigsty/vmalerthttps://demo.pigsty.io/vmalert

VMAlert reads metrics data from VictoriaMetrics and periodically evaluates alerting rules. Pigsty provides pre-built alerting rules for PGSQL, NODE, REDIS, and other modules, covering common failure scenarios out of the box.

For more information, see: Config: INFRA - PROMETHEUS


AlertManager

AlertManager handles alert event aggregation, deduplication, grouping, and dispatch. Live Demo

It listens on port 9059 by default, mounted at Nginx /alertmgr path, and also accessible via the a.pigsty domain:

IP Access (replace)Domain (HTTP)Domain (HTTPS)Public Demo
http://10.10.10.10/alertmgrhttp://a.pigstyhttps://i.pigsty/alertmgrhttps://demo.pigsty.io/alertmgr

AlertManager supports multiple notification channels: email, Webhook, Slack, PagerDuty, WeChat Work, etc. Through alert routing rules, differentiated dispatch based on severity level and module type is possible, with support for silencing, inhibition, and other advanced features.

For more information, see: Config: INFRA - PROMETHEUS


BlackboxExporter

Blackbox Exporter is used for active probing of target reachability, enabling blackbox monitoring.

It listens on port 9115 by default, mounted at Nginx /blackbox path:

IP Access (replace)Domain (HTTP)Domain (HTTPS)
http://10.10.10.10/blackboxhttp://i.pigsty/blackboxhttps://i.pigsty/blackbox

It supports multiple probe methods including ICMP Ping, TCP ports, and HTTP/HTTPS endpoints. Useful for monitoring VIP reachability, service port availability, external dependency health, etc.—an important tool for assessing failure impact scope.

For more information, see: Config: INFRA - PROMETHEUS


Ansible

Ansible is Pigsty’s core orchestration tool; all deployment, configuration, and management operations are performed through Ansible Playbooks.

Pigsty automatically installs Ansible on the admin node (Infra node) during installation. It adopts a declarative configuration style and idempotent playbook design: the same playbook can be run repeatedly, and the system automatically converges to the desired state without side effects.

Ansible’s core advantages:

  • Agentless: Executes remotely via SSH, no additional software needed on target nodes.
  • Declarative: Describes the desired state rather than execution steps; configuration is documentation.
  • Idempotent: Multiple executions produce consistent results; supports retry after partial failures.

For more information, see: Playbooks: Pigsty Playbook


DNSMASQ

DNSMASQ provides DNS resolution within the environment, resolving domain names used internally by Pigsty to their corresponding IP addresses.

Note that DNS is completely optional; Pigsty functions normally without DNS.

It listens on port 53 (UDP/TCP) by default, providing DNS resolution for all nodes in the environment:

ProtocolPortConfig Directory
UDP/TCP53/infra/hosts/

Other modules automatically register their domain names with the DNSMASQ service on INFRA nodes during deployment.

Client nodes can configure INFRA nodes as their DNS servers, allowing access to services via domain names without remembering IP addresses.

For more information, see: Config: INFRA - DNS and Tutorial: DNS—Configure Domain Resolution


Chronyd

Chronyd provides NTP time synchronization service, ensuring consistent clocks across all nodes in the environment.

It listens on port 123 (UDP) by default, serving as the time source within the environment:

ProtocolPortDescription
UDP123NTP time sync service

Time synchronization is critical for distributed systems: log analysis requires aligned timestamps, certificate validation depends on accurate clocks, and PostgreSQL streaming replication is sensitive to clock drift. In isolated network environments, the INFRA node can serve as an internal NTP server with other nodes synchronizing to it.

For more information, see: Config: NODE - NTP


Node Relationships

Regular nodes reference an INFRA node via the admin_ip parameter as their infrastructure provider.

For example, when you configure global admin_ip = 10.10.10.10, typically all nodes will use infrastructure services at this IP.

Parameters that reference ${admin_ip}:

ParameterModuleDefault ValueDescription
repo_endpointINFRAhttp://${admin_ip}:80Software repo URL
repo_upstream.baseurlINFRAhttp://${admin_ip}/pigstyLocal repo baseurl
infra_portal.endpointINFRA${admin_ip}:<port>Nginx proxy backend
dns_recordsINFRA["${admin_ip} i.pigsty", ...]DNS records
node_default_etc_hostsNODE["${admin_ip} i.pigsty"]Default static DNS
node_etc_hostsNODE[]Custom static DNS
node_dns_serversNODE["${admin_ip}"]Dynamic DNS servers
node_ntp_serversNODE["${admin_ip}"]NTP servers (optional)

This is a weak dependency relationship.

Typically the admin node and INFRA node coincide. With multiple INFRA nodes, the admin node is usually the first one; others serve as backups.

In large-scale production deployments, you might separate the Ansible admin node from nodes running the INFRA module for various reasons. For example, use 1-2 small dedicated hosts belonging to the DBA team as the control hub (ADMIN nodes), and 2-3 high-spec physical machines as monitoring infrastructure (INFRA nodes).

The table below shows typical node counts for different deployment scales:

Deployment ScaleADMININFRAETCDMINIOPGSQL
Single-node dev11101
Three-node13303
Small production1230N
Large production2354+N

3.1.3 - PostgreSQL

PostgreSQL module component interactions and data flow.

The PGSQL module organizes PostgreSQL in production as clusterslogical entities composed of a group of database instances associated by primary-replica relationships.

Each cluster is an autonomous business unit consisting of at least one primary instance, exposing capabilities through services.

There are four core entities in Pigsty’s PGSQL module:

  • Cluster: An autonomous PostgreSQL business unit serving as the top-level namespace for other entities.
  • Service: A named abstraction that exposes capabilities, routes traffic, and exposes services using node ports.
  • Instance: A single PostgreSQL server consisting of running processes and database files on a single node.
  • Node: A hardware resource abstraction running Linux + Systemd environment—can be bare metal, VM, container, or Pod.

Along with two business entities—“Database” and “Role”—these form the complete logical view as shown below:

pigsty-er.jpg

Naming Conventions

  • Cluster names should be valid DNS domain names without any dots, regex: [a-zA-Z0-9-]+
  • Service names should be prefixed with the cluster name and suffixed with specific words: primary, replica, offline, delayed, connected by -.
  • Instance names are prefixed with the cluster name and suffixed with a positive integer instance number, connected by -, e.g., ${cluster}-${seq}.
  • Nodes are identified by their primary internal IP address; since databases and hosts are deployed 1:1 in the PGSQL module, hostnames typically match instance names.

Overview

The diagram below illustrates the PGSQL module architecture, showing interactions between components:

ComponentTypeDescription
PostgreSQLDatabaseThe world’s most advanced open-source relational database, core of PGSQL
PatroniHAManages PostgreSQL processes, coordinates failover, leader election, config changes
etcdDCSDistributed consistent store for cluster metadata and leader information
PgbouncerConnection PoolLightweight connection pooling middleware, reduces overhead, adds flexibility
HAProxyLoad BalancerExposes service ports, routes traffic to primary or replicas based on role
vip-managerVIP ManagementBinds L2 VIP to current primary node for transparent failover [Optional]
pgBackRestBackup/RecoveryFull/incremental backup and WAL archiving, supports local and object storage
pg_exporterMetrics ExportExports PostgreSQL monitoring metrics for Prometheus scraping
pgbouncer_exporterMetrics ExportExports Pgbouncer connection pool metrics
pgbackrest_exporterMetrics ExportExports backup status metrics
VectorLog CollectionCollects PostgreSQL, Patroni, Pgbouncer logs and ships to central store

pigsty-arch


PostgreSQL

PostgreSQL is the core of the PGSQL module, listening on port 5432 by default for relational database services.

ProtocolPortDescription
TCP5432PostgreSQL database service

Installing the PGSQL module on multiple nodes with the same pg_cluster automatically forms a high-availability cluster based on streaming replication. Instance roles are defined by pg_role: primary, replica, or offline.

PostgreSQL processes are managed by Patroni by default. Configuration templates can be switched via pg_conf for OLTP/OLAP/CRIT/TINY workloads, and any parameter can be overridden through pg_parameters.

For more information, see: Config: PGSQL - PG_BOOTSTRAP


Patroni

Patroni is the PostgreSQL high-availability controller, listening on port 8008 by default for its REST API.

ProtocolPortDescription
TCP8008Patroni REST API / Health Check

Patroni takes over PostgreSQL startup, shutdown, configuration, and health status, writing leader and member information to etcd. It handles automatic failover, maintains replication factor, coordinates parameter changes, and provides a REST API for HAProxy, monitoring, and administrators.

HAProxy uses Patroni health check endpoints to determine instance roles and route traffic to the correct primary or replica. vip-manager monitors the leader key in etcd and automatically migrates the VIP when the primary changes.

For more information, see: Config: PGSQL - PG_BOOTSTRAP


Pgbouncer

Pgbouncer is a lightweight connection pooling middleware, listening on port 6432 by default.

ProtocolPortDescription
TCP6432Pgbouncer connection pool

Pgbouncer runs statelessly on each instance, connecting to PostgreSQL via local Unix socket, absorbing burst connections, stabilizing sessions, and providing additional metrics.

By default, Pigsty routes production traffic (read-write service 5433 / read-only service 5434) through Pgbouncer, while only the default service (5436) and offline service (5438) bypass the connection pool for direct PostgreSQL connections.

Pool mode is controlled by pgbouncer_poolmode, defaulting to transaction (transaction-level pooling). Connection pooling can be disabled via pgbouncer_enabled.

For more information, see: Config: PGSQL - PG_ACCESS


HAProxy

HAProxy serves as the service entry point and load balancer, exposing multiple database service ports.

PortServiceTargetDescription
9101Admin-HAProxy statistics and admin page
5433primaryPrimary PgbouncerRead-write service, routes to primary pool
5434replicaReplica PgbouncerRead-only service, routes to replica pool
5436defaultPrimary PostgresDefault service, direct to primary (bypasses pool)
5438offlineOffline PostgresOffline service, direct to offline replica (ETL/analytics)

HAProxy uses Patroni REST API health checks to determine instance roles and route traffic to the appropriate primary or replica. Service definitions are composed from pg_default_services and pg_services.

A dedicated HAProxy node group can be specified via pg_service_provider to handle higher traffic; by default, HAProxy on local nodes publishes services.

For more information, see: Service Access and Config: PGSQL - PG_ACCESS


vip-manager

vip-manager binds an L2 VIP to the current primary node for transparent failover.

ProtocolDescription
L2Virtual IP bound to primary node NIC

vip-manager runs on each PG node, monitoring the leader key written by Patroni in etcd, and binds pg_vip_address to the current primary node’s network interface.

During failover, vip-manager immediately releases the VIP from the old primary and rebinds it on the new primary, ensuring the old primary stops responding to requests and preventing split-brain.

This component is optional, enabled via pg_vip_enabled. When enabled, ensure all nodes are in the same VLAN; otherwise, VIP migration will fail.

For more information, see: Tutorial: VIP Configuration and Config: PGSQL - PG_ACCESS


pgBackRest

pgBackRest is a professional PostgreSQL backup and recovery tool supporting full/incremental/differential backups and WAL archiving.

FeatureDescription
Full BackupComplete database backup
IncrementalBacks up only changed data blocks
WAL ArchivingContinuous WAL archiving, enables PITR
RepositoryLocal disk (default) or object storage like MinIO

pgBackRest works with PostgreSQL to create backup repositories on the primary, executing backup and archiving tasks. By default, it uses a local backup repository (pgbackrest_method = local), but can be configured for MinIO or other object storage for centralized backup management.

After initialization, pgbackrest_init_backup can automatically trigger the first full backup. Recovery integrates with Patroni, supporting bootstrapping replicas as new primaries or standbys.

For more information, see: Backup & Recovery and Config: PGSQL - PG_BACKUP


pg_exporter

pg_exporter exports PostgreSQL monitoring metrics, listening on port 9630 by default.

ProtocolPortDescription
TCP9630pg_exporter metrics port

pg_exporter runs on each PG node, connecting to PostgreSQL via local Unix socket, exporting rich metrics covering sessions, buffer hits, replication lag, transaction rates, etc., scraped by VictoriaMetrics on INFRA nodes.

Collection configuration is specified by pg_exporter_config, with support for automatic database discovery (pg_exporter_auto_discovery), and tiered cache strategies via pg_exporter_cache_ttls.

For more information, see: Config: PGSQL - PG_MONITOR


pgbouncer_exporter

pgbouncer_exporter exports Pgbouncer connection pool metrics, listening on port 9631 by default.

ProtocolPortDescription
TCP9631pgbouncer_exporter metrics port

pgbouncer_exporter reads Pgbouncer statistics views, providing metrics on pool utilization, wait queues, and hit rates. If Pgbouncer is disabled, this component should also be disabled.

For more information, see: Config: PGSQL - PG_MONITOR


pgbackrest_exporter

pgbackrest_exporter exports backup status metrics, listening on port 9854 by default.

ProtocolPortDescription
TCP9854pgbackrest_exporter metrics port

pgbackrest_exporter parses pgBackRest status, generating metrics for most recent backup time, size, type, etc. Combined with alerting policies, it quickly detects expired or failed backups, ensuring data safety.

For more information, see: Config: PGSQL - PG_MONITOR


Summary

The PGSQL module provides production-grade PostgreSQL high-availability clusters for Pigsty, serving as the core of the entire system.

ComponentPortDescription
PostgreSQL5432Database service
Patroni8008HA controller REST API
Pgbouncer6432Connection pool
HAProxy543xService entry and load balancer
vip-manager-L2 VIP management (Optional)
pgBackRest-Backup and recovery
pg_exporter9630PostgreSQL metrics export
pgbouncer_exporter9631Pgbouncer metrics export
pgbackrest_exporter9854Backup status metrics export

Typical access path: Client → DNS/VIP → HAProxy (service port) → Pgbouncer → PostgreSQL.

Patroni and etcd work together for automatic failover, pgBackRest ensures data recoverability, and the three Exporters combined with VictoriaMetrics provide complete observability.

For more information, see: PGSQL Module and Components & Interactions

3.2 - Cluster Model

How Pigsty abstracts different functionalities into modules, and the logical model of these modules.

In Pigsty, functional modules are organized as “clusters”. Each cluster is an Ansible group containing several node resources with defined instances.

PGSQL Module Overview: Key Concepts and Architecture Details

The PGSQL module is organized as clusters in production environments, which are logical entities composed of a set of database instances associated by primary-replica relationships. Each database cluster is an autonomous business service unit consisting of at least one database (primary) instance.


Entity Relationship

Let’s start with the ER diagram. In Pigsty’s PGSQL module, there are four core entities:

  • Cluster: An autonomous PostgreSQL business unit, serving as the top-level namespace for other entities.
  • Service: A named abstraction of cluster capability that routes traffic and exposes PostgreSQL services using node ports.
  • Instance: A single PostgreSQL server consisting of a running process and database files on a single node.
  • Node: An abstraction of hardware resources, which can be bare metal, virtual machines, or even Kubernetes pods.

Naming Conventions

  • Cluster names should be valid DNS domain names without dots, matching the regex: [a-zA-Z0-9-]+
  • Service names should be prefixed with the cluster name and suffixed with specific words: primary, replica, offline, delayed, connected by -.
  • Instance names are prefixed with the cluster name and suffixed with a positive integer instance number, connected by -, e.g., ${cluster}-${seq}.
  • Nodes are identified by their primary internal IP address. Since databases and hosts are deployed 1:1 in the PGSQL module, the hostname is usually the same as the instance name.

Identity Parameters

Pigsty uses identity parameters to identify entities: PG_ID.

Besides the node IP address, pg_cluster, pg_role, and pg_seq are the minimum required parameters for defining a PostgreSQL cluster. Using the sandbox environment test cluster pg-test as an example:

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

The three cluster members are shown below:

ClusterSeqRoleHost / IPInstanceServiceNode Name
pg-test1primary10.10.10.11pg-test-1pg-test-primarypg-test-1
pg-test2replica10.10.10.12pg-test-2pg-test-replicapg-test-2
pg-test3replica10.10.10.13pg-test-3pg-test-replicapg-test-3

This includes:

  • One cluster: The cluster is named pg-test.
  • Two roles: primary and replica.
  • Three instances: The cluster consists of three instances: pg-test-1, pg-test-2, pg-test-3.
  • Three nodes: The cluster is deployed on three nodes: 10.10.10.11, 10.10.10.12, and 10.10.10.13.
  • Four services:

In the monitoring system (Prometheus/Grafana/Loki), corresponding metrics will be labeled with these identity parameters:

pg_up{cls="pg-meta", ins="pg-meta-1", ip="10.10.10.10", job="pgsql"}
pg_up{cls="pg-test", ins="pg-test-1", ip="10.10.10.11", job="pgsql"}
pg_up{cls="pg-test", ins="pg-test-2", ip="10.10.10.12", job="pgsql"}
pg_up{cls="pg-test", ins="pg-test-3", ip="10.10.10.13", job="pgsql"}

3.3 - Infra as Code

Pigsty uses Infrastructure as Code (IaC) philosophy to manage all components, providing declarative management for large-scale clusters.

Pigsty follows the IaC and GitOPS philosophy: use a declarative config inventory to describe the entire environment, and materialize it through idempotent playbooks.

Users describe their desired state declaratively through parameters, and playbooks idempotently adjust target nodes to reach that state. This is similar to Kubernetes CRDs & Operators, but Pigsty implements this functionality on bare metal and virtual machines through Ansible.

Pigsty was born to solve the operational management problem of ultra-large-scale PostgreSQL clusters. The idea behind it is simple — we need the ability to replicate the entire infrastructure (100+ database clusters + PG/Redis + observability) on ready servers within ten minutes. No GUI + ClickOps can complete such a complex task in such a short time, making CLI + IaC the only choice — it provides precise, efficient control.

The config inventory pigsty.yml file describes the state of the entire deployment. Whether it’s production (prod), staging, test, or development (devbox) environments, the difference between infrastructures lies only in the config inventory, while the deployment delivery logic is exactly the same.

You can use git for version control and auditing of this deployment “seed/gene”, and Pigsty even supports storing the config inventory as database tables in PostgreSQL CMDB, further achieving Infra as Data capability. Seamlessly integrate with your existing workflows.

IaC is designed for professional users and enterprise scenarios but is also deeply optimized for individual developers and SMBs. Even if you’re not a professional DBA, you don’t need to understand these hundreds of adjustment knobs and switches. All parameters come with well-performing default values. You can get an out-of-the-box single-node database with zero configuration; Simply add two more IP addresses to get an enterprise-grade high-availability PostgreSQL cluster.


Declare Modules

Take the following default config snippet as an example. This config describes a node 10.10.10.10 with INFRA, NODE, ETCD, and PGSQL modules installed.

# monitoring, alerting, DNS, NTP and other infrastructure cluster...
infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

# minio cluster, s3 compatible object storage
minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

# etcd cluster, used as DCS for PostgreSQL high availability
etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

# PGSQL example cluster: pg-meta
pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary }, vars: { pg_cluster: pg-meta } }

To actually install these modules, execute the following playbooks:

./infra.yml -l 10.10.10.10  # Initialize infra module on node 10.10.10.10
./etcd.yml  -l 10.10.10.10  # Initialize etcd module on node 10.10.10.10
./minio.yml -l 10.10.10.10  # Initialize minio module on node 10.10.10.10
./pgsql.yml -l 10.10.10.10  # Initialize pgsql module on node 10.10.10.10

Declare Clusters

You can declare PostgreSQL database clusters by installing the PGSQL module on multiple nodes, making them a service unit:

For example, to deploy a three-node high-availability PostgreSQL cluster using streaming replication on the following three Pigsty-managed nodes, you can add the following definition to the all.children section of the config file pigsty.yml:

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: offline }
  vars:  { pg_cluster: pg-test }

After defining, you can use playbooks to create the cluster:

bin/pgsql-add pg-test   # Create the pg-test cluster

pigsty-iac.jpg

You can use different instance roles such as primary, replica, offline, delayed, sync standby; as well as different clusters: such as standby clusters, Citus clusters, and even Redis / MinIO / Etcd clusters


Customize Cluster Content

Not only can you define clusters declaratively, but you can also define databases, users, services, and HBA rules within the cluster. For example, the following config file deeply customizes the content of the default pg-meta single-node database cluster:

Including: declaring six business databases and seven business users, adding an extra standby service (synchronous standby, providing read capability with no replication delay), defining some additional pg_hba rules, an L2 VIP address pointing to the cluster primary, and a customized backup strategy.

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary , pg_offline_query: true } }
  vars:
    pg_cluster: pg-meta
    pg_databases:                       # define business databases on this cluster, array of database definition
      - name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
        baseline: cmdb.sql              # optional, database sql baseline path, (relative path among ansible search path, e.g files/)
        pgbouncer: true                 # optional, add this database to pgbouncer database list? true by default
        schemas: [pigsty]               # optional, additional schemas to be created, array of schema names
        extensions:                     # optional, additional extensions to be installed: array of `{name[,schema]}`
          - { name: postgis , schema: public }
          - { name: timescaledb }
        comment: pigsty meta database   # optional, comment string for this database
        owner: postgres                # optional, database owner, postgres by default
        template: template1            # optional, which template to use, template1 by default
        encoding: UTF8                 # optional, database encoding, UTF8 by default. (MUST same as template database)
        locale: C                      # optional, database locale, C by default.  (MUST same as template database)
        lc_collate: C                  # optional, database collate, C by default. (MUST same as template database)
        lc_ctype: C                    # optional, database ctype, C by default.   (MUST same as template database)
        tablespace: pg_default         # optional, default tablespace, 'pg_default' by default.
        allowconn: true                # optional, allow connection, true by default. false will disable connect at all
        revokeconn: false              # optional, revoke public connection privilege. false by default. (leave connect with grant option to owner)
        register_datasource: true      # optional, register this database to grafana datasources? true by default
        connlimit: -1                  # optional, database connection limit, default -1 disable limit
        pool_auth_user: dbuser_meta    # optional, all connection to this pgbouncer database will be authenticated by this user
        pool_mode: transaction         # optional, pgbouncer pool mode at database level, default transaction
        pool_size: 64                  # optional, pgbouncer pool size at database level, default 64
        pool_size_reserve: 32          # optional, pgbouncer pool size reserve at database level, default 32
        pool_size_min: 0               # optional, pgbouncer pool size min at database level, default 0
        pool_max_db_conn: 100          # optional, max database connections at database level, default 100
      - { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
      - { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
      - { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
      - { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
      - { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }
    pg_users:                           # define business users/roles on this cluster, array of user definition
      - name: dbuser_meta               # REQUIRED, `name` is the only mandatory field of a user definition
        password: DBUser.Meta           # optional, password, can be a scram-sha-256 hash string or plain text
        login: true                     # optional, can log in, true by default  (new biz ROLE should be false)
        superuser: false                # optional, is superuser? false by default
        createdb: false                 # optional, can create database? false by default
        createrole: false               # optional, can create role? false by default
        inherit: true                   # optional, can this role use inherited privileges? true by default
        replication: false              # optional, can this role do replication? false by default
        bypassrls: false                # optional, can this role bypass row level security? false by default
        pgbouncer: true                 # optional, add this user to pgbouncer user-list? false by default (production user should be true explicitly)
        connlimit: -1                   # optional, user connection limit, default -1 disable limit
        expire_in: 3650                 # optional, now + n days when this role is expired (OVERWRITE expire_at)
        expire_at: '2030-12-31'         # optional, YYYY-MM-DD 'timestamp' when this role is expired  (OVERWRITTEN by expire_in)
        comment: pigsty admin user      # optional, comment string for this user/role
        roles: [dbrole_admin]           # optional, belonged roles. default roles are: dbrole_{admin,readonly,readwrite,offline}
        parameters: {}                  # optional, role level parameters with `ALTER ROLE SET`
        pool_mode: transaction          # optional, pgbouncer pool mode at user level, transaction by default
        pool_connlimit: -1              # optional, max database connections at user level, default -1 disable limit
      - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly], comment: read-only viewer for meta database}
      - {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database   }
      - {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database  }
      - {name: dbuser_kong     ,password: DBUser.Kong     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway   }
      - {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service      }
      - {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service    }
    pg_services:                        # extra services in addition to pg_default_services, array of service definition
      # standby service will route {ip|name}:5435 to sync replica's pgbouncer (5435->6432 standby)
      - name: standby                   # required, service name, the actual svc name will be prefixed with `pg_cluster`, e.g: pg-meta-standby
        port: 5435                      # required, service exposed port (work as kubernetes service node port mode)
        ip: "*"                         # optional, service bind ip address, `*` for all ip by default
        selector: "[]"                  # required, service member selector, use JMESPath to filter inventory
        dest: default                   # optional, destination port, default|postgres|pgbouncer|<port_number>, 'default' by default
        check: /sync                    # optional, health check url path, / by default
        backup: "[? pg_role == `primary`]"  # backup server selector
        maxconn: 3000                   # optional, max allowed front-end connection
        balance: roundrobin             # optional, haproxy load balance algorithm (roundrobin by default, other: leastconn)
        options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'
    pg_hba_rules:
      - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
    pg_vip_enabled: true
    pg_vip_address: 10.10.10.2/24
    pg_vip_interface: eth1
    node_crontab:  # make a full backup 1 am everyday
      - '00 01 * * * postgres /pg/bin/pg-backup full'

Declare Access Control

You can also deeply customize Pigsty’s access control capabilities through declarative configuration. For example, the following config file provides deep security customization for the pg-meta cluster:

Uses the three-node core cluster template: crit.yml, to ensure data consistency is prioritized with zero data loss during failover. Enables L2 VIP and restricts database and connection pool listening addresses to local loopback IP + internal network IP + VIP three specific addresses. The template enforces Patroni’s SSL API and Pgbouncer’s SSL, and in HBA rules, enforces SSL usage for accessing the database cluster. Also enables the $libdir/passwordcheck extension in pg_libs to enforce password strength security policy.

Finally, a separate pg-meta-delay cluster is declared as pg-meta’s delayed replica from one hour ago, for emergency data deletion recovery.

pg-meta:      # 3 instance postgres cluster `pg-meta`
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary }
    10.10.10.11: { pg_seq: 2, pg_role: replica }
    10.10.10.12: { pg_seq: 3, pg_role: replica , pg_offline_query: true }
  vars:
    pg_cluster: pg-meta
    pg_conf: crit.yml
    pg_users:
      - { name: dbuser_meta , password: DBUser.Meta   , pgbouncer: true , roles: [ dbrole_admin ] , comment: pigsty admin user }
      - { name: dbuser_view , password: DBUser.Viewer , pgbouncer: true , roles: [ dbrole_readonly ] , comment: read-only viewer for meta database }
    pg_databases:
      - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: postgis, schema: public}, {name: timescaledb}]}
    pg_default_service_dest: postgres
    pg_services:
      - { name: standby ,src_ip: "*" ,port: 5435 , dest: default ,selector: "[]" , backup: "[? pg_role == `primary`]" }
    pg_vip_enabled: true
    pg_vip_address: 10.10.10.2/24
    pg_vip_interface: eth1
    pg_listen: '${ip},${vip},${lo}'
    patroni_ssl_enabled: true
    pgbouncer_sslmode: require
    pgbackrest_method: minio
    pg_libs: 'timescaledb, $libdir/passwordcheck, pg_stat_statements, auto_explain' # add passwordcheck extension to enforce strong password
    pg_default_roles:                 # default roles and users in postgres cluster
      - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
      - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
      - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly]               ,comment: role for global read-write access }
      - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite]  ,comment: role for object creation }
      - { 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 }
    pg_default_hba_rules:             # postgres host-based auth rules by default
      - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  }
      - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' }
      - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: ssl   ,title: 'replicator replication from localhost'}
      - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: ssl   ,title: 'replicator replication from intranet' }
      - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: ssl   ,title: 'replicator postgres db from intranet' }
      - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' }
      - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: ssl   ,title: 'monitor from infra host with password'}
      - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   }
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: cert  ,title: 'admin @ everywhere with ssl & cert'   }
      - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: ssl   ,title: 'pgbouncer read/write via local socket'}
      - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: ssl   ,title: 'read/write biz user via password'     }
      - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: ssl   ,title: 'allow etl offline tasks from intranet'}
    pgb_default_hba_rules:            # pgbouncer host-based authentication rules
      - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident'}
      - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' }
      - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: ssl   ,title: 'monitor access via intranet with pwd' }
      - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' }
      - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: ssl   ,title: 'admin access via intranet with pwd'   }
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   }
      - {user: 'all'        ,db: all         ,addr: intra     ,auth: ssl   ,title: 'allow all user intra access with pwd' }

# OPTIONAL delayed cluster for pg-meta
pg-meta-delay:                    # delayed instance for pg-meta (1 hour ago)
  hosts: { 10.10.10.13: { pg_seq: 1, pg_role: primary, pg_upstream: 10.10.10.10, pg_delay: 1h } }
  vars: { pg_cluster: pg-meta-delay }

Citus Distributed Cluster

Below is a declarative configuration for a four-node Citus distributed cluster:

all:
  children:
    pg-citus0: # citus coordinator, pg_group = 0
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus0 , pg_group: 0 }
    pg-citus1: # citus data node 1
      hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus1 , pg_group: 1 }
    pg-citus2: # citus data node 2
      hosts: { 10.10.10.12: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus2 , pg_group: 2 }
    pg-citus3: # citus data node 3, with an extra replica
      hosts:
        10.10.10.13: { pg_seq: 1, pg_role: primary }
        10.10.10.14: { pg_seq: 2, pg_role: replica }
      vars: { pg_cluster: pg-citus3 , pg_group: 3 }
  vars:                               # global parameters for all citus clusters
    pg_mode: citus                    # pgsql cluster mode: citus
    pg_shard: pg-citus                # citus shard name: pg-citus
    patroni_citus_db: meta            # citus distributed database name
    pg_dbsu_password: DBUser.Postgres # all dbsu password access for citus cluster
    pg_users: [ { name: dbuser_meta ,password: DBUser.Meta ,pgbouncer: true ,roles: [ dbrole_admin ] } ]
    pg_databases: [ { name: meta ,extensions: [ { name: citus }, { name: postgis }, { name: timescaledb } ] } ]
    pg_hba_rules:
      - { user: 'all' ,db: all  ,addr: 127.0.0.1/32 ,auth: ssl ,title: 'all user ssl access from localhost' }
      - { user: 'all' ,db: all  ,addr: intra        ,auth: ssl ,title: 'all user ssl access from intranet'  }

Redis Clusters

Below are declarative configuration examples for Redis primary-replica cluster, sentinel cluster, and Redis Cluster:

redis-ms: # redis classic primary & replica
  hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
  vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

redis-meta: # redis sentinel x 3
  hosts: { 10.10.10.11: { redis_node: 1 , redis_instances: { 26379: { } ,26380: { } ,26381: { } } } }
  vars:
    redis_cluster: redis-meta
    redis_password: 'redis.meta'
    redis_mode: sentinel
    redis_max_memory: 16MB
    redis_sentinel_monitor: # primary list for redis sentinel, use cls as name, primary ip:port
      - { name: redis-ms, host: 10.10.10.10, port: 6379 ,password: redis.ms, quorum: 2 }

redis-test: # redis native cluster: 3m x 3s
  hosts:
    10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
    10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
  vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }

ETCD Cluster

Below is a declarative configuration example for a three-node Etcd cluster:

etcd: # dcs service for postgres/patroni ha consensus
  hosts:  # 1 node for testing, 3 or 5 for production
    10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
    10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
    10.10.10.12: { etcd_seq: 3 }  # odd number please
  vars: # cluster level parameter override roles/etcd
    etcd_cluster: etcd  # mark etcd cluster name etcd
    etcd_safeguard: false # safeguard against purging
    etcd_clean: true # purge etcd during init process

MinIO Cluster

Below is a declarative configuration example for a three-node MinIO cluster:

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 }
    10.10.10.11: { minio_seq: 2 }
    10.10.10.12: { minio_seq: 3 }
  vars:
    minio_cluster: minio
    minio_data: '/data{1...2}'          # use two disks per node
    minio_node: '${minio_cluster}-${minio_seq}.pigsty' # node name pattern
    haproxy_services:
      - name: minio                     # [required] service name, must be unique
        port: 9002                      # [required] service port, must be unique
        options:
          - option httpchk
          - option http-keep-alive
          - http-check send meth OPTIONS uri /minio/health/live
          - http-check expect status 200
        servers:
          - { name: minio-1 ,ip: 10.10.10.10 , port: 9000 , options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-2 ,ip: 10.10.10.11 , port: 9000 , options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-3 ,ip: 10.10.10.12 , port: 9000 , options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

3.3.1 - Inventory

Describe your infrastructure and clusters using declarative configuration files

Every Pigsty deployment corresponds to an Inventory that describes key properties of the infrastructure and database clusters.


Configuration File

Pigsty uses Ansible YAML configuration format by default, with a single YAML configuration file pigsty.yml as the inventory.

~/pigsty
  ^---- pigsty.yml   # <---- Default configuration file

You can directly edit this configuration file to customize your deployment, or use the configure wizard script provided by Pigsty to automatically generate an appropriate configuration file.


Configuration Structure

The inventory uses standard Ansible YAML configuration format, consisting of two parts: global parameters (all.vars) and multiple groups (all.children).

You can define new clusters in all.children and describe the infrastructure using global variables: all.vars, which looks like this:

all:                  # Top-level object: all
  vars: {...}         # Global parameters
  children:           # Group definitions
    infra:            # Group definition: 'infra'
      hosts: {...}        # Group members: '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'
    # ...

Cluster Definition

Each Ansible group may represent a cluster, which can be a node cluster, PostgreSQL cluster, Redis cluster, Etcd cluster, MinIO cluster, etc.

A cluster definition consists of two parts: cluster members (hosts) and cluster parameters (vars). You can define cluster members in <cls>.hosts and describe the cluster using configuration parameters in <cls>.vars. Here’s an example of a 3-node high-availability PostgreSQL cluster definition:

all:
  children:    # Ansible group list
    pg-test:   # Ansible group name
      hosts:   # Ansible group instances (cluster members)
        10.10.10.11: { pg_seq: 1, pg_role: primary } # Host 1
        10.10.10.12: { pg_seq: 2, pg_role: replica } # Host 2
        10.10.10.13: { pg_seq: 3, pg_role: offline } # Host 3
      vars:    # Ansible group variables (cluster parameters)
        pg_cluster: pg-test

Cluster-level vars (cluster parameters) override global parameters, and instance-level vars override both cluster parameters and global parameters.


Splitting Configuration

If your deployment is large or you want to better organize configuration files, you can split the inventory into multiple files for easier management and maintenance.

inventory/
├── hosts.yml              # Host and cluster definitions
├── group_vars/
│   ├── all.yml            # Global default variables (corresponds to all.vars)
│   ├── infra.yml          # infra group variables
│   ├── etcd.yml           # etcd group variables
│   └── pg-meta.yml        # pg-meta cluster variables
└── host_vars/
    ├── 10.10.10.10.yml    # Specific host variables
    └── 10.10.10.11.yml

You can place cluster member definitions in the hosts.yml file and put cluster-level configuration parameters in corresponding files under the group_vars directory.


Switching Configuration

You can temporarily specify a different inventory file when running playbooks using the -i parameter.

./pgsql.yml -i another_config.yml
./infra.yml -i nginx_config.yml

Additionally, Ansible supports multiple configuration methods. You can use local yaml|ini configuration files, or use CMDB and any dynamic configuration scripts as configuration sources.

In Pigsty, we specify pigsty.yml in the same directory as the default inventory through ansible.cfg in the Pigsty home directory. You can modify it as needed.

[defaults]
inventory = pigsty.yml

Additionally, Pigsty supports using a CMDB metabase to store the inventory, facilitating integration with existing systems.

3.3.2 - Configure

Use the configure script to automatically generate recommended configuration files based on your environment.

Pigsty provides a configure script as a configuration wizard that automatically generates an appropriate pigsty.yml configuration file based on your current environment.

This is an optional script: if you already understand how to configure Pigsty, you can directly edit the pigsty.yml configuration file and skip the wizard.


Quick Start

Enter the pigsty source home directory and run ./configure to automatically start the configuration wizard. Without any arguments, it defaults to the meta single-node configuration template:

cd ~/pigsty
./configure          # Interactive configuration wizard, auto-detect environment and generate config

This command will use the selected template as a base, detect the current node’s IP address and region, and generate a pigsty.yml configuration file suitable for the current environment.

Features

The configure script performs the following adjustments based on environment and input, generating a pigsty.yml configuration file in the current directory.

  • Detects the current node IP address; if multiple IPs exist, prompts the user to input a primary IP address as the node’s identity
  • Uses the IP address to replace the placeholder 10.10.10.10 in the configuration template and sets it as the admin_ip parameter value
  • Detects the current region, setting region to default (global default repos) or china (using Chinese mirror repos)
  • For micro instances (vCPU < 4), uses the tiny parameter template for node_tune and pg_conf to optimize resource usage
  • If -v PG major version is specified, sets pg_version and all PG alias parameters to the corresponding major version
  • If -g is specified, replaces all default passwords with randomly generated strong passwords for enhanced security (strongly recommended)
  • When PG major version ≥ 17, prioritizes the built-in C.UTF-8 locale, or the OS-supported C.UTF-8
  • Checks if the core dependency ansible for deployment is available in the current environment
  • Also checks if the deployment target node is SSH-reachable and can execute commands with sudo (-s to skip)

Usage Examples

# Basic usage
./configure                       # Interactive configuration wizard
./configure -i 10.10.10.10        # Specify primary IP address

# Specify configuration template
./configure -c meta               # Use default single-node template (default)
./configure -c rich               # Use feature-rich single-node template
./configure -c slim               # Use minimal template (PGSQL + ETCD only)
./configure -c ha/full            # Use 4-node HA sandbox template
./configure -c ha/trio            # Use 3-node HA template
./configure -c app/supa           # Use Supabase self-hosted template

# Specify PostgreSQL version
./configure -v 17                 # Use PostgreSQL 17
./configure -v 16                 # Use PostgreSQL 16
./configure -c rich -v 16         # rich template + PG 16

# Region and proxy
./configure -r china              # Use Chinese mirrors
./configure -r europe             # Use European mirrors
./configure -x                    # Import current proxy environment variables

# Skip and automation
./configure -s                    # Skip IP detection, keep placeholder
./configure -n -i 10.10.10.10     # Non-interactive mode with specified IP
./configure -c ha/full -s         # 4-node template, skip IP replacement

# Security enhancement
./configure -g                    # Generate random passwords
./configure -c meta -g -i 10.10.10.10  # Complete production configuration

# Specify output and SSH port
./configure -o prod.yml           # Output to prod.yml
./configure -p 2222               # Use SSH port 2222

Command Arguments

./configure
    [-c|--conf <template>]      # Configuration template name (meta|rich|slim|ha/full|...)
    [-i|--ip <ipaddr>]          # Specify primary IP address
    [-v|--version <pgver>]      # PostgreSQL major version (13|14|15|16|17|18)
    [-r|--region <region>]      # Upstream software repo region (default|china|europe)
    [-o|--output <file>]        # Output configuration file path (default: pigsty.yml)
    [-s|--skip]                 # Skip IP address detection and replacement
    [-x|--proxy]                # Import proxy settings from environment variables
    [-n|--non-interactive]      # Non-interactive mode (don't ask any questions)
    [-p|--port <port>]          # Specify SSH port
    [-g|--generate]             # Generate random passwords
    [-h|--help]                 # Display help information

Argument Details

ArgumentDescription
-c, --confGenerate config from conf/<template>.yml, supports subdirectories like ha/full
-i, --ipReplace placeholder 10.10.10.10 in config template with specified IP
-v, --versionSpecify PostgreSQL major version (13-18), keeps template default if not specified
-r, --regionSet software repo mirror region: default, china (Chinese mirrors), europe (European)
-o, --outputSpecify output file path, defaults to pigsty.yml
-s, --skipSkip IP address detection and replacement, keep 10.10.10.10 placeholder in template
-x, --proxyWrite current environment proxy variables (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, NO_PROXY) to config
-n, --non-interactiveNon-interactive mode, don’t ask any questions (requires -i to specify IP)
-p, --portSpecify SSH port (when using non-default port 22)
-g, --generateGenerate random values for passwords in config file, improving security (strongly recommended)

Execution Flow

The configure script executes detection and configuration in the following order:

┌─────────────────────────────────────────────────────────────┐
│                  configure Execution Flow                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. check_region          Detect network region (GFW check) │
│         ↓                                                   │
│  2. check_version         Validate PostgreSQL version       │
│         ↓                                                   │
│  3. check_kernel          Detect OS kernel (Linux/Darwin)   │
│         ↓                                                   │
│  4. check_machine         Detect CPU arch (x86_64/aarch64)  │
│         ↓                                                   │
│  5. check_package_manager Detect package manager (dnf/yum/apt) │
│         ↓                                                   │
│  6. check_vendor_version  Detect OS distro and version      │
│         ↓                                                   │
│  7. check_sudo            Detect passwordless sudo          │
│         ↓                                                   │
│  8. check_ssh             Detect passwordless SSH to self   │
│         ↓                                                   │
│  9. check_proxy           Handle proxy environment vars     │
│         ↓                                                   │
│ 10. check_ipaddr          Detect/input primary IP address   │
│         ↓                                                   │
│ 11. check_admin           Validate admin SSH + Sudo access  │
│         ↓                                                   │
│ 12. check_conf            Select configuration template     │
│         ↓                                                   │
│ 13. check_config          Generate configuration file       │
│         ↓                                                   │
│ 14. check_utils           Check if Ansible etc. installed   │
│         ↓                                                   │
│     ✓ Configuration complete, output pigsty.yml             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Automatic Behaviors

Region Detection

The script automatically detects the network environment to determine if you’re in mainland China (behind GFW):

# Check network environment by accessing Google
curl -I -s --connect-timeout 1 www.google.com
  • If Google is inaccessible, automatically sets region: china to use domestic mirrors
  • If accessible, uses region: default default mirrors
  • Can manually specify region via -r argument

IP Address Handling

The script determines the primary IP address in the following priority:

  1. Command line argument: If IP is specified via -i, use it directly
  2. Single IP detection: If the current node has only one IP, use it automatically
  3. Demo IP detection: If 10.10.10.10 is detected, select it automatically (for sandbox environments)
  4. Interactive input: When multiple IPs exist, prompt user to choose or input
[WARN] Multiple IP address candidates found:
    (1) 192.168.1.100   inet 192.168.1.100/24 scope global eth0
    (2) 10.10.10.10     inet 10.10.10.10/24 scope global eth1
[ IN ] INPUT primary_ip address (of current meta node, e.g 10.10.10.10):
=> 10.10.10.10

Low-End Hardware Optimization

When CPU core count ≤ 4 is detected, the script automatically adjusts configuration:

[WARN] replace oltp template with tiny due to cpu < 4

This ensures smooth operation on low-spec virtual machines.

Locale Settings

The script automatically enables C.UTF-8 as the default locale when:

  • PostgreSQL version ≥ 17 (built-in Locale Provider support)
  • Or the current system supports C.UTF-8 / C.utf8 locale
pg_locale: C.UTF-8
pg_lc_collate: C.UTF-8
pg_lc_ctype: C.UTF-8

China Region Special Handling

When region is set to china, the script automatically:

  • Enables docker_registry_mirrors Docker mirror acceleration
  • Enables PIP_MIRROR_URL Python mirror acceleration

Password Generation

When using the -g argument, the script generates 24-character random strings for the following passwords:

Password ParameterDescription
grafana_admin_passwordGrafana admin password
pg_admin_passwordPostgreSQL admin password
pg_monitor_passwordPostgreSQL monitor user password
pg_replication_passwordPostgreSQL replication user password
patroni_passwordPatroni API password
haproxy_admin_passwordHAProxy admin password
minio_secret_keyMinIO Secret Key
etcd_root_passwordETCD Root password

It also replaces the following placeholder passwords:

  • DBUser.Meta → random password
  • DBUser.Viewer → random password
  • S3User.Backup → random password
  • S3User.Meta → random password
  • S3User.Data → random password
$ ./configure -g
[INFO] generating random passwords...
    grafana_admin_password   : xK9mL2nP4qR7sT1vW3yZ5bD8
    pg_admin_password        : aB3cD5eF7gH9iJ1kL2mN4oP6
    ...
[INFO] random passwords generated, check and save them

Configuration Templates

The script reads configuration templates from the conf/ directory, supporting the following templates:

Core Templates

TemplateDescription
metaDefault template: Single-node installation with INFRA + NODE + ETCD + PGSQL
richFeature-rich version: Includes almost all extensions, MinIO, local repo
slimMinimal version: PostgreSQL + ETCD only, no monitoring infrastructure
fatComplete version: rich base with more extensions installed
pgsqlPure PostgreSQL template
infraPure infrastructure template

HA Templates (ha/)

TemplateDescription
ha/dual2-node HA cluster
ha/trio3-node HA cluster
ha/full4-node complete sandbox environment
ha/safeSecurity-hardened HA configuration
ha/simu42-node large-scale simulation environment

Application Templates (app/)

TemplateDescription
supabaseSupabase self-hosted configuration
app/difyDify AI platform configuration
app/odooOdoo ERP configuration
app/teableTeable table database configuration
app/registryDocker Registry configuration

Special Kernel Templates

TemplateDescription
ivoryIvorySQL: Oracle-compatible PostgreSQL
mssqlBabelfish: SQL Server-compatible PostgreSQL
polarPolarDB: Alibaba Cloud open-source distributed PostgreSQL
citusCitus: Distributed PostgreSQL
orioleOrioleDB: Next-generation storage engine

Demo Templates (demo/)

TemplateDescription
demo/demoDemo environment configuration
demo/redisRedis cluster demo
demo/minioMinIO cluster demo

Output Example

$ ./configure
configure pigsty v4.0.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.10	    inet 10.10.10.10/24 brd 10.10.10.255 scope global noprefixroute eth1
[ OK ] primary_ip = 10.10.10.10 (from demo)
[ OK ] admin = [email protected] ok
[ OK ] mode = meta (el9)
[ OK ] locale  = C.UTF-8
[ OK ] ansible = ready
[ OK ] pigsty configured
[WARN] don't forget to check it and change passwords!
proceed with ./deploy.yml

Environment Variables

The script supports the following environment variables:

Environment VariableDescriptionDefault
PIGSTY_HOMEPigsty installation directory~/pigsty
METADB_URLMetabase connection URLservice=meta
HTTP_PROXYHTTP proxy-
HTTPS_PROXYHTTPS proxy-
ALL_PROXYUniversal proxy-
NO_PROXYProxy whitelistBuilt-in default

Notes

  1. Passwordless access: Before running configure, ensure the current user has passwordless sudo privileges and passwordless SSH to localhost. This can be automatically configured via the bootstrap script.

  2. IP address selection: Choose an internal IP as the primary IP address, not a public IP or 127.0.0.1.

  3. Password security: In production environments, always modify default passwords in the configuration file, or use the -g argument to generate random passwords.

  4. Configuration review: After the script completes, it’s recommended to review the generated pigsty.yml file to confirm the configuration meets expectations.

  5. Multiple executions: You can run configure multiple times to regenerate configuration; each run will overwrite the existing pigsty.yml.

  6. macOS limitations: When running on macOS, the script skips some Linux-specific checks and uses placeholder IP 10.10.10.10. macOS can only serve as an admin node.


FAQ

How to use a custom configuration template?

Place your configuration file in the conf/ directory, then specify it with the -c argument:

cp my-config.yml ~/pigsty/conf/myconf.yml
./configure -c myconf

How to generate different configurations for multiple clusters?

Use the -o argument to specify different output files:

./configure -c ha/full -o cluster-a.yml
./configure -c ha/trio -o cluster-b.yml

Then specify the configuration file when running playbooks:

./deploy.yml -i cluster-a.yml

How to handle multiple IPs in non-interactive mode?

You must explicitly specify the IP address using the -i argument:

./configure -n -i 10.10.10.10

How to keep the placeholder IP in the template?

Use the -s argument to skip IP replacement:

./configure -c ha/full -s   # Keep 10.10.10.10 placeholder

  • Inventory: Understand the Ansible inventory structure
  • Parameters: Understand Pigsty parameter hierarchy and priority
  • Templates: View all available configuration templates
  • Installation: Understand the complete installation process
  • Metabase: Use PostgreSQL as a dynamic configuration source

3.3.3 - Parameters

Fine-tune Pigsty customization using configuration parameters

In the inventory, you can use various parameters to fine-tune Pigsty customization. These parameters cover everything from infrastructure settings to database configuration.


Parameter List

Pigsty provides approximately 380+ configuration parameters distributed across 8 default modules for fine-grained control of various system aspects. See Reference - Parameter List for the complete list.

ModuleGroupsParamsDescription
PGSQL9123Core configuration for PostgreSQL database clusters
INFRA1082Infrastructure: repos, Nginx, DNS, monitoring, Grafana, etc.
NODE1183Host node tuning: identity, DNS, packages, tuning, security, admin, time, VIP, etc.
ETCD213Distributed configuration store and service discovery
REDIS121Redis cache and data structure server
MINIO221S3-compatible object storage service
FERRET19MongoDB-compatible database FerretDB
DOCKER18Docker container engine

Parameter Form

Parameters are key-value pairs that describe entities. The Key is a string, and the Value can be one of five types: boolean, string, number, array, or object.

all:                            # <------- Top-level object: all
  vars:
    admin_ip: 10.10.10.10       # <------- Global configuration parameter
  children:
    pg-meta:                    # <------- pg-meta group
      vars:
        pg_cluster: pg-meta     # <------- Cluster-level parameter
      hosts:
        10.10.10.10:            # <------- Host node IP
          pg_seq: 1
          pg_role: primary      # <------- Instance-level parameter

Parameter Priority

Parameters can be set at different levels with the following priority:

LevelLocationDescriptionPriority
CLI-e command line argumentPassed via command lineHighest (5)
Host/Instance<group>.hosts.<host>Parameters specific to a single hostHigher (4)
Group/Cluster<group>.varsParameters shared by hosts in group/clusterMedium (3)
Globalall.varsParameters shared by all hostsLower (2)
Default<roles>/default/main.ymlRole implementation defaultsLowest (1)

Here are some examples of parameter priority:

  • Use command line parameter -e grafana_clean=true when running playbooks to wipe Grafana data
  • Use instance-level parameter pg_role on host variables to override pg instance role
  • Use cluster-level parameter pg_cluster on group variables to override pg cluster name
  • Use global parameter node_ntp_servers on global variables to specify global NTP servers
  • If pg_version is not set, Pigsty will use the default value from the pgsql role implementation (default is 18)

Except for identity parameters, every parameter has an appropriate default value, so explicit setting is not required.


Identity Parameters

Identity parameters are special parameters that serve as entity ID identifiers, therefore they have no default values and must be explicitly set.

ModuleIdentity Parameters
PGSQLpg_cluster, pg_seq, pg_role, …
NODEnodename, node_cluster
ETCDetcd_cluster, etcd_seq
MINIOminio_cluster, minio_seq
REDISredis_cluster, redis_node, redis_instances
INFRAinfra_seq

Exceptions are etcd_cluster and minio_cluster which have default values. This assumes each deployment has only one etcd cluster for DCS and one optional MinIO cluster for centralized backup storage, so they are assigned default cluster names etcd and minio. However, you can still deploy multiple etcd or MinIO clusters using different names.

3.3.4 - Conf Templates

Use pre-made configuration templates to quickly generate configuration files adapted to your environment

In Pigsty, deployment blueprint details are defined by the inventory, which is the pigsty.yml configuration file. You can customize it through declarative configuration.

However, writing configuration files directly can be daunting for new users. To address this, we provide some ready-to-use configuration templates covering common usage scenarios.

Each template is a predefined pigsty.yml configuration file containing reasonable defaults suitable for specific scenarios.

You can choose a template as your customization starting point, then modify it as needed to meet your specific requirements.


Using Templates

Pigsty provides the configure script as an optional configuration wizard that generates an inventory with good defaults based on your environment and input.

Use ./configure -c <conf> to specify a configuration template, where <conf> is the path relative to the conf directory (the .yml suffix can be omitted).

./configure                     # Default to meta.yml configuration template
./configure -c meta             # Explicitly specify meta.yml single-node template
./configure -c rich             # Use feature-rich template with all extensions and MinIO
./configure -c slim             # Use minimal single-node template

# Use different database kernels
./configure -c pgsql            # Native PostgreSQL kernel, basic features (13~18)
./configure -c citus            # Citus distributed HA PostgreSQL (14~17)
./configure -c mssql            # Babelfish kernel, SQL Server protocol compatible (15)
./configure -c polar            # PolarDB PG kernel, Aurora/RAC style (15)
./configure -c ivory            # IvorySQL kernel, Oracle syntax compatible (18)
./configure -c mysql            # OpenHalo kernel, MySQL compatible (14)
./configure -c pgtde            # Percona PostgreSQL Server transparent encryption (18)
./configure -c oriole           # OrioleDB kernel, OLTP enhanced (17)
./configure -c supabase         # Supabase self-hosted configuration (15~18)

# Use multi-node HA templates
./configure -c ha/dual          # Use 2-node HA template
./configure -c ha/trio          # Use 3-node HA template
./configure -c ha/full          # Use 4-node HA template

If no template is specified, Pigsty defaults to the meta.yml single-node configuration template.


Template List

Main Templates

The following are single-node configuration templates for installing Pigsty on a single server:

TemplateDescription
meta.ymlDefault template, single-node PostgreSQL online installation
rich.ymlFeature-rich template with local repo, MinIO, and more examples
slim.ymlMinimal template, PostgreSQL only without monitoring and infrastructure

Database Kernel Templates

Templates for various database management systems and kernels:

TemplateDescription
pgsql.ymlNative PostgreSQL kernel, basic features (13~18)
citus.ymlCitus distributed HA PostgreSQL (14~17)
mssql.ymlBabelfish kernel, SQL Server protocol compatible (15)
polar.ymlPolarDB PG kernel, Aurora/RAC style (15)
ivory.ymlIvorySQL kernel, Oracle syntax compatible (17)
mysql.ymlOpenHalo kernel, MySQL compatible (14)
pgtde.ymlPercona PostgreSQL Server transparent encryption (17)
oriole.ymlOrioleDB kernel, OLTP enhanced (17, Debian pkg pending)
supabase.ymlSupabase self-hosted configuration (15~17)

You can add more nodes later or use HA templates to plan your cluster from the start.


HA Templates

You can configure Pigsty to run on multiple nodes, forming a high-availability (HA) cluster:

TemplateDescription
dual.yml2-node semi-HA deployment
trio.yml3-node standard HA deployment
full.yml4-node standard deployment
safe.yml4-node security-enhanced deployment with delayed replica
simu.yml20-node production environment simulation

Application Templates

You can use the following templates to run Docker applications/software:

TemplateDescription
supa.ymlStart single-node Supabase
odoo.ymlStart Odoo ERP system
dify.ymlStart Dify AI workflow system
electric.ymlStart Electric sync engine

Demo Templates

Besides main templates, Pigsty provides a set of demo templates for different scenarios:

TemplateDescription
el.ymlFull-parameter config file for EL 8/9 systems
debian.ymlFull-parameter config file for Debian/Ubuntu systems
remote.ymlExample config for monitoring remote PostgreSQL clusters or RDS
redis.ymlRedis cluster example configuration
minio.yml3-node MinIO cluster example configuration
demo.ymlConfiguration file for Pigsty public demo site

Build Templates

The following configuration templates are for development and testing purposes:

TemplateDescription
build.ymlOpen source build config for EL 9/10, Debian 12/13, Ubuntu 22.04/24.04

3.3.5 - Use CMDB as Config Inventory

Use PostgreSQL as a CMDB metabase to store Ansible inventory.

Pigsty allows you to use a PostgreSQL metabase as a dynamic configuration source, replacing static YAML configuration files for more powerful configuration management capabilities.


Overview

CMDB (Configuration Management Database) is a method of storing configuration information in a database for management.

In Pigsty, the default configuration source is a static YAML file pigsty.yml, which serves as Ansible’s inventory.

This approach is simple and direct, but when infrastructure scales and requires complex, fine-grained management and external integration, a single static file becomes insufficient.

FeatureStatic YAML FileCMDB Metabase
QueryingManual search/grepSQL queries with any conditions, aggregation analysis
VersioningDepends on Git or manual backupDatabase transactions, audit logs, time-travel snapshots
Access ControlFile system permissions, coarse-grainedPostgreSQL fine-grained access control
Concurrent EditingRequires file locking or merge conflictsDatabase transactions naturally support concurrency
External IntegrationRequires YAML parsingStandard SQL interface, easy integration with any language
ScalabilityDifficult to maintain when file becomes too largeScales to physical limits
Dynamic GenerationStatic file, changes require manual applicationImmediate effect, real-time configuration changes

Pigsty provides the CMDB database schema in the sample database pg-meta.meta schema baseline definition.


How It Works

The core idea of CMDB is to replace the static configuration file with a dynamic script. Ansible supports using executable scripts as inventory, as long as the script outputs inventory data in JSON format. When you enable CMDB, Pigsty creates a dynamic inventory script named inventory.sh:

#!/bin/bash
psql ${METADB_URL} -AXtwc 'SELECT text FROM pigsty.inventory;'

This script’s function is simple: every time Ansible needs to read the inventory, it queries configuration data from the PostgreSQL database’s pigsty.inventory view and returns it in JSON format.

The overall architecture is as follows:

flowchart LR
    conf["bin/inventory_conf"]
    tocmdb["bin/inventory_cmdb"]
    load["bin/inventory_load"]
    ansible["🚀 Ansible"]

    subgraph static["📄 Static Config Mode"]
        yml[("pigsty.yml")]
    end

    subgraph dynamic["🗄️ CMDB Dynamic Mode"]
        sh["inventory.sh"]
        cmdb[("PostgreSQL CMDB")]
    end

    conf -->|"switch"| yml
    yml -->|"load config"| load
    load -->|"write"| cmdb
    tocmdb -->|"switch"| sh
    sh --> cmdb

    yml --> ansible
    cmdb --> ansible

Data Model

The CMDB database schema is defined in files/cmdb.sql, with all objects in the pigsty schema.

Core Tables

TableDescriptionPrimary Key
pigsty.groupCluster/group definitions, corresponds to Ansible groupscls
pigsty.hostHost definitions, belongs to a group(cls, ip)
pigsty.global_varGlobal variables, corresponds to all.varskey
pigsty.group_varGroup variables, corresponds to all.children.<cls>.vars(cls, key)
pigsty.host_varHost variables, host-level variables(cls, ip, key)
pigsty.default_varDefault variable definitions, stores parameter metadatakey
pigsty.jobJob records table, records executed tasksid

Table Structure Details

Cluster Table pigsty.group

CREATE TABLE pigsty.group (
    cls     TEXT PRIMARY KEY,        -- Cluster name, primary key
    ctime   TIMESTAMPTZ DEFAULT now(), -- Creation time
    mtime   TIMESTAMPTZ DEFAULT now()  -- Modification time
);

Host Table pigsty.host

CREATE TABLE pigsty.host (
    cls    TEXT NOT NULL REFERENCES pigsty.group(cls),  -- Parent cluster
    ip     INET NOT NULL,                               -- Host IP address
    ctime  TIMESTAMPTZ DEFAULT now(),
    mtime  TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (cls, ip)
);

Global Variables Table pigsty.global_var

CREATE TABLE pigsty.global_var (
    key   TEXT PRIMARY KEY,           -- Variable name
    value JSONB NULL,                 -- Variable value (JSON format)
    mtime TIMESTAMPTZ DEFAULT now()   -- Modification time
);

Group Variables Table pigsty.group_var

CREATE TABLE pigsty.group_var (
    cls   TEXT NOT NULL REFERENCES pigsty.group(cls),
    key   TEXT NOT NULL,
    value JSONB NULL,
    mtime TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (cls, key)
);

Host Variables Table pigsty.host_var

CREATE TABLE pigsty.host_var (
    cls   TEXT NOT NULL,
    ip    INET NOT NULL,
    key   TEXT NOT NULL,
    value JSONB NULL,
    mtime TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (cls, ip, key),
    FOREIGN KEY (cls, ip) REFERENCES pigsty.host(cls, ip)
);

Core Views

CMDB provides a series of views for querying and displaying configuration data:

ViewDescription
pigsty.inventoryCore view: Generates Ansible dynamic inventory JSON
pigsty.raw_configRaw configuration in JSON format
pigsty.global_configGlobal config view, merges defaults and global vars
pigsty.group_configGroup config view, includes host list and group vars
pigsty.host_configHost config view, merges group and host-level vars
pigsty.pg_clusterPostgreSQL cluster view
pigsty.pg_instancePostgreSQL instance view
pigsty.pg_databasePostgreSQL database definition view
pigsty.pg_usersPostgreSQL user definition view
pigsty.pg_servicePostgreSQL service definition view
pigsty.pg_hbaPostgreSQL HBA rules view
pigsty.pg_remoteRemote PostgreSQL instance view

pigsty.inventory is the core view that converts database configuration data to the JSON format required by Ansible:

SELECT text FROM pigsty.inventory;

Utility Scripts

Pigsty provides three convenience scripts for managing CMDB:

ScriptFunction
bin/inventory_loadLoad YAML configuration file into PostgreSQL database
bin/inventory_cmdbSwitch configuration source to CMDB (dynamic inventory script)
bin/inventory_confSwitch configuration source to static config file pigsty.yml

inventory_load

Parse and import YAML configuration file into CMDB:

bin/inventory_load                     # Load default pigsty.yml to default CMDB
bin/inventory_load -p /path/to/conf.yml  # Specify configuration file path
bin/inventory_load -d "postgres://..."   # Specify database connection URL
bin/inventory_load -n myconfig           # Specify configuration name

The script performs the following operations:

  1. Clears existing data in the pigsty schema
  2. Parses the YAML configuration file
  3. Writes global variables to the global_var table
  4. Writes cluster definitions to the group table
  5. Writes cluster variables to the group_var table
  6. Writes host definitions to the host table
  7. Writes host variables to the host_var table

Environment Variables

  • PIGSTY_HOME: Pigsty installation directory, defaults to ~/pigsty
  • METADB_URL: Database connection URL, defaults to service=meta

inventory_cmdb

Switch Ansible to use CMDB as the configuration source:

bin/inventory_cmdb

The script performs the following operations:

  1. Creates dynamic inventory script ${PIGSTY_HOME}/inventory.sh
  2. Modifies ansible.cfg to set inventory to inventory.sh

The generated inventory.sh contents:

#!/bin/bash
psql ${METADB_URL} -AXtwc 'SELECT text FROM pigsty.inventory;'

inventory_conf

Switch back to using static YAML configuration file:

bin/inventory_conf

The script modifies ansible.cfg to set inventory back to pigsty.yml.


Usage Workflow

First-time CMDB Setup

  1. Initialize CMDB schema (usually done automatically during Pigsty installation):
psql -f ~/pigsty/files/cmdb.sql
  1. Load configuration to database:
bin/inventory_load
  1. Switch to CMDB mode:
bin/inventory_cmdb
  1. Verify configuration:
ansible all --list-hosts          # List all hosts
ansible-inventory --list          # View complete inventory

Query Configuration

After enabling CMDB, you can flexibly query configuration using SQL:

-- View all clusters
SELECT cls FROM pigsty.group;

-- View all hosts in a cluster
SELECT ip FROM pigsty.host WHERE cls = 'pg-meta';

-- View global variables
SELECT key, value FROM pigsty.global_var;

-- View cluster variables
SELECT key, value FROM pigsty.group_var WHERE cls = 'pg-meta';

-- View all PostgreSQL clusters
SELECT cls, name, pg_databases, pg_users FROM pigsty.pg_cluster;

-- View all PostgreSQL instances
SELECT cls, ins, ip, seq, role FROM pigsty.pg_instance;

-- View all database definitions
SELECT cls, datname, owner, encoding FROM pigsty.pg_database;

-- View all user definitions
SELECT cls, name, login, superuser FROM pigsty.pg_users;

Modify Configuration

You can modify configuration directly via SQL:

-- Add new cluster
INSERT INTO pigsty.group (cls) VALUES ('pg-new');

-- Add cluster variable
INSERT INTO pigsty.group_var (cls, key, value)
VALUES ('pg-new', 'pg_cluster', '"pg-new"');

-- Add host
INSERT INTO pigsty.host (cls, ip) VALUES ('pg-new', '10.10.10.20');

-- Add host variables
INSERT INTO pigsty.host_var (cls, ip, key, value)
VALUES ('pg-new', '10.10.10.20', 'pg_seq', '1'),
       ('pg-new', '10.10.10.20', 'pg_role', '"primary"');

-- Modify global variable
UPDATE pigsty.global_var SET value = '"new-value"' WHERE key = 'some_param';

-- Delete cluster (cascades to hosts and variables)
DELETE FROM pigsty.group WHERE cls = 'pg-old';

Changes take effect immediately without reloading or restarting any service.

Switch Back to Static Configuration

To switch back to static configuration file mode:

bin/inventory_conf

Advanced Usage

Export Configuration

Export CMDB configuration to YAML format:

psql service=meta -AXtwc "SELECT jsonb_pretty(jsonb_build_object('all', jsonb_build_object('children', children, 'vars', vars))) FROM pigsty.raw_config;"

Or use the ansible-inventory command:

ansible-inventory --list --yaml > exported_config.yml

Configuration Auditing

Track configuration changes using the mtime field:

-- View recently modified global variables
SELECT key, value, mtime FROM pigsty.global_var
ORDER BY mtime DESC LIMIT 10;

-- View changes after a specific time
SELECT * FROM pigsty.group_var
WHERE mtime > '2024-01-01'::timestamptz;

Integration with External Systems

CMDB uses standard PostgreSQL, making it easy to integrate with other systems:

  • Web Management Interface: Expose configuration data through REST API (e.g., PostgREST)
  • CI/CD Pipelines: Read/write database directly in deployment scripts
  • Monitoring & Alerting: Generate monitoring rules based on configuration data
  • ITSM Systems: Sync with enterprise CMDB systems

Considerations

  1. Data Consistency: After modifying configuration, you need to re-run the corresponding Ansible playbooks to apply changes to the actual environment

  2. Backup: Configuration data in CMDB is critical, ensure regular backups

  3. Permissions: Configure appropriate database access permissions for CMDB to avoid accidental modifications

  4. Transactions: When making batch configuration changes, perform them within a transaction for rollback on errors

  5. Connection Pooling: The inventory.sh script creates a new connection on each execution; if Ansible runs frequently, consider using connection pooling


Summary

CMDB is Pigsty’s advanced configuration management solution, suitable for scenarios requiring large-scale cluster management, complex queries, external integration, or fine-grained access control. By storing configuration data in PostgreSQL, you can fully leverage the database’s powerful capabilities to manage infrastructure configuration.

FeatureDescription
StoragePostgreSQL pigsty schema
Dynamic Inventoryinventory.sh script
Config Loadbin/inventory_load
Switch to CMDBbin/inventory_cmdb
Switch to YAMLbin/inventory_conf
Core Viewpigsty.inventory

3.4 - High Availability

Pigsty uses Patroni to implement PostgreSQL high availability, ensuring automatic failover when the primary becomes unavailable.

Overview

Pigsty’s PostgreSQL clusters come with out-of-the-box high availability, powered by Patroni, Etcd, and HAProxy.

When your PostgreSQL cluster has two or more instances, you automatically have self-healing database high availability without any additional configuration — as long as any instance in the cluster survives, the cluster can provide complete service. Clients only need to connect to any node in the cluster to get full service without worrying about primary-replica topology changes.

With default configuration, the primary failure Recovery Time Objective (RTO) ≈ 30s, and Recovery Point Objective (RPO) < 1MB; for replica failures, RPO = 0 and RTO ≈ 0 (brief interruption). In consistency-first mode, failover can guarantee zero data loss: RPO = 0. All these metrics can be configured as needed based on your actual hardware conditions and reliability requirements.

Pigsty includes built-in HAProxy load balancers for automatic traffic switching, providing DNS/VIP/LVS and other access methods for clients. Failover and switchover are almost transparent to the business side except for brief interruptions - applications don’t need to modify connection strings or restart. The minimal maintenance window requirements bring great flexibility and convenience: you can perform rolling maintenance and upgrades on the entire cluster without application coordination. The feature that hardware failures can wait until the next day to handle lets developers, operations, and DBAs sleep well during incidents.

pigsty-ha

Many large organizations and core institutions have been using Pigsty in production for extended periods. The largest deployment has 25K CPU cores and 220+ PostgreSQL ultra-large instances (64c / 512g / 3TB NVMe SSD). In this deployment case, dozens of hardware failures and various incidents occurred over five years, yet overall availability of over 99.999% was maintained.


What problems does High Availability solve?

  • Elevates data security C/IA availability to a new level: RPO ≈ 0, RTO < 30s.
  • Gains seamless rolling maintenance capability, minimizing maintenance window requirements and bringing great convenience.
  • Hardware failures can self-heal immediately without human intervention, allowing operations and DBAs to sleep well.
  • Replicas can handle read-only requests, offloading primary load and fully utilizing resources.

What are the costs of High Availability?

  • Infrastructure dependency: HA requires DCS (etcd/zk/consul) for consensus.
  • Higher starting threshold: A meaningful HA deployment requires at least three nodes.
  • Extra resource consumption: Each new replica consumes additional resources, though this is usually not a major concern.
  • Significantly increased complexity: Backup costs increase significantly, requiring tools to manage complexity.

Limitations of High Availability

Since replication happens in real-time, all changes are immediately applied to replicas. Therefore, streaming replication-based HA solutions cannot handle data deletion or modification caused by human errors and software defects. (e.g., DROP TABLE or DELETE data) Such failures require using delayed clusters or performing point-in-time recovery using previous base backups and WAL archives.

Configuration StrategyRTORPO
Standalone + Nothing Data permanently lost, unrecoverable All data lost
Standalone + Base Backup Depends on backup size and bandwidth (hours) Lose data since last backup (hours to days)
Standalone + Base Backup + WAL Archive Depends on backup size and bandwidth (hours) Lose unarchived data (tens of MB)
Primary-Replica + Manual Failover ~10 minutes Lose data in replication lag (~100KB)
Primary-Replica + Auto Failover Within 1 minute Lose data in replication lag (~100KB)
Primary-Replica + Auto Failover + Sync Commit Within 1 minute No data loss

How It Works

In Pigsty, the high availability architecture works as follows:

  • PostgreSQL uses standard streaming replication to build physical replicas; replicas take over when the primary fails.
  • Patroni manages PostgreSQL server processes and handles high availability matters.
  • Etcd provides distributed configuration storage (DCS) capability and is used for leader election after failures.
  • Patroni relies on Etcd to reach cluster leader consensus and provides health check interfaces externally.
  • HAProxy exposes cluster services externally and uses Patroni health check interfaces to automatically distribute traffic to healthy nodes.
  • vip-manager provides an optional Layer 2 VIP, retrieves leader information from Etcd, and binds the VIP to the node where the cluster primary resides.

When the primary fails, a new round of leader election is triggered. The healthiest replica in the cluster (highest LSN position, minimum data loss) wins and is promoted to the new primary. After the winning replica is promoted, read-write traffic is immediately routed to the new primary. The impact of primary failure is brief write service unavailability: write requests will be blocked or fail directly from primary failure until new primary promotion, with unavailability typically lasting 15 to 30 seconds, usually not exceeding 1 minute.

When a replica fails, read-only traffic is routed to other replicas. Only when all replicas fail will read-only traffic ultimately be handled by the primary. The impact of replica failure is partial read-only query interruption: queries currently running on that replica will abort due to connection reset and be immediately taken over by other available replicas.

Failure detection is performed jointly by Patroni and Etcd. The cluster leader holds a lease; if the cluster leader fails to renew the lease in time (10s) due to failure, the lease is released, triggering a Failover and new cluster election.

Even without any failures, you can proactively change the cluster primary through Switchover. In this case, write queries on the primary will experience a brief interruption and be immediately routed to the new primary. This operation is typically used for rolling maintenance/upgrades of database servers.


Tradeoffs

Recovery Time Objective (RTO) and Recovery Point Objective (RPO) are two parameters that require careful tradeoffs when designing high availability clusters.

The default RTO and RPO values used by Pigsty meet reliability requirements for most scenarios. You can adjust them based on your hardware level, network quality, and business requirements.

The upper limit of unavailability during failover is controlled by the pg_rto parameter. RTO defaults to 30s. Increasing it will result in longer primary failure write unavailability, while decreasing it will increase the rate of false positive failovers (e.g., repeated switching due to brief network jitter).

The upper limit of potential data loss is controlled by the pg_rpo parameter, defaulting to 1MB. Reducing this value can lower the data loss ceiling during failover but also increases the probability of refusing automatic failover when replicas are not healthy enough (lagging too far behind).

Pigsty uses availability-first mode by default, meaning it will failover as quickly as possible when the primary fails, and data not yet replicated to replicas may be lost (under typical 10GbE networks, replication lag is usually a few KB to 100KB).

If you need to ensure zero data loss during failover, you can use the crit.yml template to ensure no data loss during failover, but this sacrifices some performance as a tradeoff.


pg_rto

Parameter name: pg_rto, Type: int, Level: C

Recovery Time Objective (RTO) in seconds. This is used to calculate Patroni’s TTL value, defaulting to 30 seconds.

If the primary instance is missing for this long, a new leader election will be triggered. This value is not always better when lower; it involves tradeoffs: Reducing this value can decrease unavailability during cluster failover (inability to write), but makes the cluster more sensitive to short-term network jitter, increasing the probability of false positive failover triggers. You need to configure this value based on network conditions and business constraints, making a tradeoff between failure probability and failure impact.

pg_rpo

Parameter name: pg_rpo, Type: int, Level: C

Recovery Point Objective (RPO) in bytes, default: 1048576.

Defaults to 1MiB, meaning up to 1MiB of data loss can be tolerated during failover.

When the primary goes down and all replicas are lagging, you must make a difficult choice: Either promote a replica to become the new primary immediately, accepting acceptable data loss (e.g., less than 1MB), and restore service as quickly as possible. Or wait for the primary to come back online (which may never happen) to avoid any data loss, or abandon automatic failover and wait for human intervention to make the final decision. You need to configure this value based on business preference, making a tradeoff between availability and consistency.

Additionally, you can always ensure RPO = 0 by enabling synchronous commit (e.g., using the crit.yml template), sacrificing some cluster latency/throughput performance to guarantee data consistency.

3.4.1 - Service Access

Pigsty uses HAProxy to provide service access, with optional pgBouncer for connection pooling, and optional L2 VIP and DNS access.

Split read and write operations, route traffic correctly, and deliver PostgreSQL cluster capabilities reliably.

Service is an abstraction: it represents the form in which database clusters expose their capabilities externally, encapsulating underlying cluster details.

Services are crucial for stable access in production environments, showing their value during automatic failover in high availability clusters. Personal users typically don’t need to worry about this concept.


Personal Users

The concept of “service” is for production environments. Personal users with single-node clusters can skip the complexity and directly use instance names or IP addresses to access the database.

For example, Pigsty’s default single-node pg-meta.meta database can be connected directly using three different users:

psql postgres://dbuser_dba:[email protected]/meta     # Connect directly with DBA superuser
psql postgres://dbuser_meta:[email protected]/meta   # Connect with default business admin user
psql postgres://dbuser_view:DBUser.View@pg-meta/meta       # Connect with default read-only user via instance domain name

Service Overview

In real-world production environments, we use primary-replica database clusters based on replication. Within a cluster, one and only one instance serves as the leader (primary) that can accept writes. Other instances (replicas) continuously fetch change logs from the cluster leader to stay synchronized. Replicas can also handle read-only requests, significantly offloading the primary in read-heavy, write-light scenarios. Therefore, distinguishing write requests from read-only requests is a common practice.

Additionally, for production environments with high-frequency, short-lived connections, we pool requests through connection pool middleware (Pgbouncer) to reduce connection and backend process creation overhead. However, for scenarios like ETL and change execution, we need to bypass the connection pool and directly access the database. Meanwhile, high-availability clusters may undergo failover during failures, causing cluster leadership changes. Therefore, high-availability database solutions require write traffic to automatically adapt to cluster leadership changes. These varying access needs (read-write separation, pooled vs. direct connections, failover auto-adaptation) ultimately lead to the abstraction of the Service concept.

Typically, database clusters must provide this most basic service:

  • Read-write service (primary): Can read from and write to the database

For production database clusters, at least these two services should be provided:

  • Read-write service (primary): Write data: Can only be served by the primary.
  • Read-only service (replica): Read data: Can be served by replicas; falls back to primary when no replicas are available

Additionally, depending on specific business scenarios, there may be other services, such as:

  • Default direct service (default): Allows (admin) users to bypass the connection pool and directly access the database
  • Offline replica service (offline): Dedicated replica not serving online read traffic, used for ETL and analytical queries
  • Sync replica service (standby): Read-only service with no replication delay, handled by synchronous standby/primary for read queries
  • Delayed replica service (delayed): Access data from the same cluster as it was some time ago, handled by delayed replicas

Access Services

Pigsty’s service delivery boundary stops at the cluster’s HAProxy. Users can access these load balancers through various means.

The typical approach is to use DNS or VIP access, binding them to all or any number of load balancers in the cluster.

pigsty-access.jpg

You can use different host & port combinations, which provide PostgreSQL service in different ways.

Host

TypeSampleDescription
Cluster Domain Namepg-testAccess via cluster domain name (resolved by dnsmasq @ infra nodes)
Cluster VIP Address10.10.10.3Access via L2 VIP address managed by vip-manager, bound to primary node
Instance Hostnamepg-test-1Access via any instance hostname (resolved by dnsmasq @ infra nodes)
Instance IP Address10.10.10.11Access any instance’s IP address

Port

Pigsty uses different ports to distinguish pg services

PortServiceTypeDescription
5432postgresDatabaseDirect access to postgres server
6432pgbouncerMiddlewareAccess postgres through connection pool middleware
5433primaryServiceAccess primary pgbouncer (or postgres)
5434replicaServiceAccess replica pgbouncer (or postgres)
5436defaultServiceAccess primary postgres
5438offlineServiceAccess offline postgres

Combinations

# Access via cluster domain
postgres://test@pg-test:5432/test # DNS -> L2 VIP -> primary direct connection
postgres://test@pg-test:6432/test # DNS -> L2 VIP -> primary connection pool -> primary
postgres://test@pg-test:5433/test # DNS -> L2 VIP -> HAProxy -> primary connection pool -> primary
postgres://test@pg-test:5434/test # DNS -> L2 VIP -> HAProxy -> replica connection pool -> replica
postgres://dbuser_dba@pg-test:5436/test # DNS -> L2 VIP -> HAProxy -> primary direct connection (for admin)
postgres://dbuser_stats@pg-test:5438/test # DNS -> L2 VIP -> HAProxy -> offline direct connection (for ETL/personal queries)

# Access via cluster VIP directly
postgres://[email protected]:5432/test # L2 VIP -> primary direct access
postgres://[email protected]:6432/test # L2 VIP -> primary connection pool -> primary
postgres://[email protected]:5433/test # L2 VIP -> HAProxy -> primary connection pool -> primary
postgres://[email protected]:5434/test # L2 VIP -> HAProxy -> replica connection pool -> replica
postgres://[email protected]:5436/test # L2 VIP -> HAProxy -> primary direct connection (for admin)
postgres://[email protected]::5438/test # L2 VIP -> HAProxy -> offline direct connection (for ETL/personal queries)

# Directly specify any cluster instance name
postgres://test@pg-test-1:5432/test # DNS -> database instance direct connection (singleton access)
postgres://test@pg-test-1:6432/test # DNS -> connection pool -> database
postgres://test@pg-test-1:5433/test # DNS -> HAProxy -> connection pool -> database read/write
postgres://test@pg-test-1:5434/test # DNS -> HAProxy -> connection pool -> database read-only
postgres://dbuser_dba@pg-test-1:5436/test # DNS -> HAProxy -> database direct connection
postgres://dbuser_stats@pg-test-1:5438/test # DNS -> HAProxy -> database offline read/write

# Directly specify any cluster instance IP access
postgres://[email protected]:5432/test # Database instance direct connection (directly specify instance, no automatic traffic distribution)
postgres://[email protected]:6432/test # Connection pool -> database
postgres://[email protected]:5433/test # HAProxy -> connection pool -> database read/write
postgres://[email protected]:5434/test # HAProxy -> connection pool -> database read-only
postgres://[email protected]:5436/test # HAProxy -> database direct connection
postgres://[email protected]:5438/test # HAProxy -> database offline read-write

# Smart client: read/write separation via URL
postgres://[email protected]:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=primary
postgres://[email protected]:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=prefer-standby

3.5 - Point-in-Time Recovery

Pigsty uses pgBackRest to implement PostgreSQL point-in-time recovery, allowing users to roll back to any point in time within the backup policy window.

Overview

You can restore and roll back your cluster to any point in the past, avoiding data loss caused by software defects and human errors.

Pigsty’s PostgreSQL clusters come with auto-configured Point-in-Time Recovery (PITR) capability, powered by the backup component pgBackRest and optional object storage repository MinIO.

High availability solutions can address hardware failures but are powerless against data deletion/overwriting/database drops caused by software defects and human errors. For such situations, Pigsty provides out-of-the-box Point-in-Time Recovery (PITR) capability, enabled by default without additional configuration.

Pigsty provides default configurations for base backups and WAL archiving. You can use local directories and disks, or dedicated MinIO clusters or S3 object storage services to store backups and achieve geo-redundant disaster recovery. When using local disks, the default capability to recover to any point within the past day is retained. When using MinIO or S3, the default capability to recover to any point within the past week is retained. As long as storage space permits, you can retain any arbitrarily long recoverable time window, as your budget allows.


What problems does PITR solve?

  • Enhanced disaster recovery: RPO drops from ∞ to tens of MB, RTO drops from ∞ to hours/minutes.
  • Ensures data security: Data integrity in C/I/A: avoids data consistency issues caused by accidental deletion.
  • Ensures data security: Data availability in C/I/A: provides fallback for “permanently unavailable” disaster scenarios
Standalone Configuration StrategyEventRTORPO
NothingCrash Permanently lost All lost
Base BackupCrash Depends on backup size and bandwidth (hours) Lose data since last backup (hours to days)
Base Backup + WAL ArchiveCrash Depends on backup size and bandwidth (hours) Lose unarchived data (tens of MB)

What are the costs of PITR?

  • Reduces C in data security: Confidentiality, creates additional leak points, requires additional backup protection.
  • Extra resource consumption: Local storage or network traffic/bandwidth overhead, usually not a concern.
  • Increased complexity: Users need to pay backup management costs.

Limitations of PITR

If only PITR is used for failure recovery, RTO and RPO metrics are inferior compared to high availability solutions, and typically both should be used together.

  • RTO: With only standalone + PITR, recovery time depends on backup size and network/disk bandwidth, ranging from tens of minutes to hours or days.
  • RPO: With only standalone + PITR, some data may be lost during crashes - one or several WAL segment files may not yet be archived, losing 16 MB to tens of MB of data.

Besides PITR, you can also use delayed clusters in Pigsty to address data deletion/modification caused by human errors or software defects.


How It Works

Point-in-time recovery allows you to restore and roll back your cluster to “any point” in the past, avoiding data loss caused by software defects and human errors. To achieve this, two preparations are needed: Base Backup and WAL Archiving. Having a base backup allows users to restore the database to its state at backup time, while having WAL archives starting from a base backup allows users to restore the database to any point after the base backup time.

fig-10-02.png

For specific operations, refer to PGSQL Admin: Backup and Recovery.

Base Backup

Pigsty uses pgBackRest to manage PostgreSQL backups. pgBackRest initializes empty repositories on all cluster instances but only actually uses the repository on the cluster primary.

pgBackRest supports three backup modes: full backup, incremental backup, and differential backup, with the first two being most commonly used. Full backup takes a complete physical snapshot of the database cluster at the current moment; incremental backup records the differences between the current database cluster and the previous full backup.

Pigsty provides a wrapper command for backups: /pg/bin/pg-backup [full|incr]. You can schedule regular base backups as needed through Crontab or any other task scheduling system.

WAL Archiving

Pigsty enables WAL archiving on the cluster primary by default and uses the pgbackrest command-line tool to continuously push WAL segment files to the backup repository.

pgBackRest automatically manages required WAL files and timely cleans up expired backups and their corresponding WAL archive files based on the backup retention policy.

If you don’t need PITR functionality, you can disable WAL archiving by configuring the cluster: archive_mode: off and remove node_crontab to stop scheduled backup tasks.


Implementation

By default, Pigsty provides two preset backup strategies: The default uses local filesystem backup repository, performing one full backup daily to ensure users can roll back to any point within the past day. The alternative strategy uses dedicated MinIO clusters or S3 storage for backups, with weekly full backups, daily incremental backups, and two weeks of backup and WAL archive retention by default.

Pigsty uses pgBackRest to manage backups, receive WAL archives, and perform PITR. Backup repositories can be flexibly configured (pgbackrest_repo): defaults to primary’s local filesystem (local), but can also use other disk paths, or the included optional MinIO service (minio) and cloud S3 services.

pgbackrest_enabled: true          # enable pgBackRest on pgsql host?
pgbackrest_clean: true            # remove pg backup data during init?
pgbackrest_log_dir: /pg/log/pgbackrest # pgbackrest log dir, `/pg/log/pgbackrest` by default
pgbackrest_method: local          # pgbackrest repo method: local, minio, [user-defined...]
pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
  local:                          # default pgbackrest repo with local posix fs
    path: /pg/backup              # local backup directory, `/pg/backup` by default
    retention_full_type: count    # retention full backup by count
    retention_full: 2             # keep at most 3 full backup, at least 2, when using local fs repo
  minio:                          # optional minio repo for pgbackrest
    type: s3                      # minio is s3-compatible, so use s3
    s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
    s3_region: us-east-1          # minio region, us-east-1 by default, not used for minio
    s3_bucket: pgsql              # minio bucket name, `pgsql` by default
    s3_key: pgbackrest            # minio user access key for pgbackrest
    s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
    s3_uri_style: path            # use path style uri for minio rather than host style
    path: /pgbackrest             # minio backup path, `/pgbackrest` by default
    storage_port: 9000            # minio port, 9000 by default
    storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
    bundle: y                     # bundle small files into a single file
    cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
    cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
    retention_full_type: time     # retention full backup by time on minio repo
    retention_full: 14            # keep full backup for last 14 days
  # You can also add other optional backup repos, such as S3, for geo-redundant disaster recovery

Pigsty parameter pgbackrest_repo target repositories are converted to repository definitions in the /etc/pgbackrest/pgbackrest.conf configuration file. For example, if you define a US West S3 repository for storing cold backups, you can use the following reference configuration.

s3:    # ------> /etc/pgbackrest/pgbackrest.conf
  repo1-type: s3                                   # ----> repo1-type=s3
  repo1-s3-region: us-west-1                       # ----> repo1-s3-region=us-west-1
  repo1-s3-endpoint: s3-us-west-1.amazonaws.com    # ----> repo1-s3-endpoint=s3-us-west-1.amazonaws.com
  repo1-s3-key: '<your_access_key>'                # ----> repo1-s3-key=<your_access_key>
  repo1-s3-key-secret: '<your_secret_key>'         # ----> repo1-s3-key-secret=<your_secret_key>
  repo1-s3-bucket: pgsql                           # ----> repo1-s3-bucket=pgsql
  repo1-s3-uri-style: host                         # ----> repo1-s3-uri-style=host
  repo1-path: /pgbackrest                          # ----> repo1-path=/pgbackrest
  repo1-bundle: y                                  # ----> repo1-bundle=y
  repo1-cipher-type: aes-256-cbc                   # ----> repo1-cipher-type=aes-256-cbc
  repo1-cipher-pass: pgBackRest                    # ----> repo1-cipher-pass=pgBackRest
  repo1-retention-full-type: time                  # ----> repo1-retention-full-type=time
  repo1-retention-full: 90                         # ----> repo1-retention-full=90

Recovery

You can directly use the following wrapper commands for PostgreSQL database cluster point-in-time recovery.

Pigsty uses incremental differential parallel recovery by default, allowing you to recover to a specified point in time at maximum speed.

pg-pitr                                 # Restore to the end of WAL archive stream (e.g., for entire datacenter failure)
pg-pitr -i                              # Restore to the most recent backup completion time (rarely used)
pg-pitr --time="2022-12-30 14:44:44+08" # Restore to a specified point in time (for database or table drops)
pg-pitr --name="my-restore-point"       # Restore to a named restore point created with pg_create_restore_point
pg-pitr --lsn="0/7C82CB8" -X            # Restore to immediately before the LSN
pg-pitr --xid="1234567" -X -P           # Restore to immediately before the specified transaction ID, then promote cluster to primary
pg-pitr --backup=latest                 # Restore to the latest backup set
pg-pitr --backup=20221108-105325        # Restore to a specific backup set, backup sets can be listed with pgbackrest info

pg-pitr                                 # pgbackrest --stanza=pg-meta restore
pg-pitr -i                              # pgbackrest --stanza=pg-meta --type=immediate restore
pg-pitr -t "2022-12-30 14:44:44+08"     # pgbackrest --stanza=pg-meta --type=time --target="2022-12-30 14:44:44+08" restore
pg-pitr -n "my-restore-point"           # pgbackrest --stanza=pg-meta --type=name --target=my-restore-point restore
pg-pitr -b 20221108-105325F             # pgbackrest --stanza=pg-meta --type=name --set=20221230-120101F restore
pg-pitr -l "0/7C82CB8" -X               # pgbackrest --stanza=pg-meta --type=lsn --target="0/7C82CB8" --target-exclusive restore
pg-pitr -x 1234567 -X -P                # pgbackrest --stanza=pg-meta --type=xid --target="0/7C82CB8" --target-exclusive --target-action=promote restore

When performing PITR, you can use Pigsty’s monitoring system to observe the cluster LSN position status and determine whether recovery to the specified point in time, transaction point, LSN position, or other point was successful.

pitr




3.6 - Monitoring System

How Pigsty’s monitoring system is architected and how monitored targets are automatically managed.

3.7 - Security and Compliance

Authentication, access control, encrypted communication, audit logs—meeting SOC2 compliance requirements.

Pigsty’s Security Philosophy

Secure by Default: Out-of-the-box security configuration—basic protection without additional setup.

Progressive Configuration: Enterprise users can gradually enhance security measures through configuration.

Defense in Depth: Multiple security layers—even if one layer is breached, others remain protective.

Least Privilege: Grant users only the minimum permissions needed to complete tasks, reducing risk.


Default Security Configuration

Pigsty enables these security features by default:

FeatureDefault ConfigDescription
Password Encryptionscram-sha-256PostgreSQL’s most secure password hash algorithm
SSL SupportEnabledClients can optionally use SSL encrypted connections
Local CAAuto-generatedSelf-signed CA issues server certificates
HBA LayeringSource-based controlDifferent auth strength for different sources
Role SystemFour-tier permissionsRead-only/Read-write/Admin/Offline
Data ChecksumsEnabledDetects storage-layer data corruption
Audit LogsEnabledRecords connections and slow queries

Enhanced Configuration

Additional configuration enables higher security levels:

FeatureConfiguration MethodSecurity Level
Password strength checkEnable passwordcheck extensionEnterprise
Enforce SSLHBA uses hostsslEnterprise
Client certificatesHBA uses cert authFinancial-grade
Backup encryptionConfigure cipher_typeCompliance
FirewallConfigure node_firewall_modeInfrastructure

If you only have one minute, remember this diagram:

flowchart TB
    subgraph L1["Layer 1: Network Security"]
        L1A["Firewall + SSL/TLS Encryption + HAProxy Proxy"]
        L1B["Who can connect? Is the connection encrypted?"]
    end

    subgraph L2["Layer 2: Authentication"]
        L2A["HBA Rules + SCRAM-SHA-256 Passwords + Certificate Auth"]
        L2B["Who are you? How do you prove it?"]
    end

    subgraph L3["Layer 3: Access Control"]
        L3A["Role System + Object Permissions + Database Isolation"]
        L3B["What can you do? What data can you access?"]
    end

    subgraph L4["Layer 4: Data Security"]
        L4A["Data Checksums + Backup Encryption + Audit Logs"]
        L4B["Is data intact? Are operations logged?"]
    end

    L1 --> L2 --> L3 --> L4

Core Value: Enterprise-grade security configuration out of the box, best practices enabled by default, additional configuration achieves SOC 2 compliance.


Contents

SectionDescriptionCore Question
Security OverviewSecurity capability overview and checklistWhat’s the overall security architecture?
AuthenticationHBA rules, password policies, certificate authHow to verify user identity?
Access ControlRole system, permission model, database isolationHow to control user permissions?
Encrypted CommunicationSSL/TLS, local CA, certificate managementHow to protect data in transit?
Compliance ChecklistDetailed SOC2 mappingHow to meet compliance requirements?

Why Security Matters

The Cost of Data Breaches

flowchart LR
    Breach["Data Breach"]

    subgraph Direct["Direct Losses"]
        D1["Regulatory Fines<br/>GDPR up to 4% global revenue"]
        D2["Legal Costs"]
        D3["Customer Compensation"]
    end

    subgraph Indirect["Indirect Losses"]
        I1["Brand Reputation Damage"]
        I2["Customer Trust Loss"]
        I3["Business Disruption"]
    end

    subgraph Compliance["Compliance Risk"]
        C1["Liability"]
        C2["SOC 2: Certification Revocation"]
        C3["Industry Access: Banned from Operating"]
    end

    Breach --> Direct
    Breach --> Indirect
    Breach --> Compliance

Default Users and Passwords

Pigsty creates these system users by default:

UserPurposeDefault PasswordPost-Deploy Action
postgresSystem superuserNo password (local only)Keep passwordless
dbuser_dbaAdmin userDBUser.DBAMust change
dbuser_monitorMonitor userDBUser.MonitorMust change
replicatorReplication userDBUser.ReplicatorMust change
# pigsty.yml - Change default passwords
pg_admin_password: 'YourSecurePassword123!'
pg_monitor_password: 'AnotherSecurePass456!'
pg_replication_password: 'ReplicationPass789!'

Important: After production deployment, immediately change these default passwords!


Role and Permission System

Pigsty provides a four-tier role system out of the box:

flowchart TB
    subgraph Admin["dbrole_admin (Admin)"]
        A1["Inherits dbrole_readwrite"]
        A2["Can CREATE/DROP/ALTER objects (DDL)"]
        A3["For: Business admins, apps needing table creation"]
    end

    subgraph RW["dbrole_readwrite (Read-Write)"]
        RW1["Inherits dbrole_readonly"]
        RW2["Can INSERT/UPDATE/DELETE"]
        RW3["For: Production business accounts"]
    end

    subgraph RO["dbrole_readonly (Read-Only)"]
        RO1["Can SELECT all tables"]
        RO2["For: Reporting, data analysis"]
    end

    subgraph Offline["dbrole_offline (Offline)"]
        OFF1["Can only access offline instances"]
        OFF2["For: ETL, personal analysis, slow queries"]
    end

    Admin --> |inherits| RW
    RW --> |inherits| RO

Creating Business Users

pg_users:
  # Read-only user - for reporting
  - name: dbuser_report
    password: ReportUser123
    roles: [dbrole_readonly]
    pgbouncer: true

  # Read-write user - for production
  - name: dbuser_app
    password: AppUser456
    roles: [dbrole_readwrite]
    pgbouncer: true

  # Admin user - for DDL operations
  - name: dbuser_admin
    password: AdminUser789
    roles: [dbrole_admin]
    pgbouncer: true

HBA Access Control

HBA (Host-Based Authentication) controls “who can connect from where”:

flowchart LR
    subgraph Sources["Connection Sources"]
        S1["Local Socket"]
        S2["localhost"]
        S3["Intranet CIDR"]
        S4["Admin Nodes"]
        S5["External"]
    end

    subgraph Auth["Auth Methods"]
        A1["ident/peer<br/>OS user mapping, most secure"]
        A2["scram-sha-256<br/>Password auth"]
        A3["scram-sha-256 + SSL<br/>Enforce SSL"]
    end

    S1 --> A1
    S2 --> A2
    S3 --> A2
    S4 --> A3
    S5 --> A3

    Note["Rules matched in order<br/>First matching rule applies"]

Custom HBA Rules

pg_hba_rules:
  # Allow app servers from intranet
  - {user: dbuser_app, db: mydb, addr: '10.10.10.0/24', auth: scram-sha-256}

  # Force SSL for certain users
  - {user: admin, db: all, addr: world, auth: ssl}

  # Require certificate auth (highest security)
  - {user: secure_user, db: all, addr: world, auth: cert}

Encrypted Communication

SSL/TLS Architecture

sequenceDiagram
    participant Client as Client
    participant Server as PostgreSQL

    Client->>Server: 1. ClientHello
    Server->>Client: 2. ServerHello
    Server->>Client: 3. Server Certificate
    Client->>Server: 4. Client Key
    Client->>Server: 5. Encrypted Channel Established
    Server->>Client: 5. Encrypted Channel Established

    rect rgb(200, 255, 200)
        Note over Client,Server: Encrypted Data Transfer
        Client->>Server: 6. Application Data (encrypted)
        Server->>Client: 6. Application Data (encrypted)
    end

    Note over Client,Server: Prevents eavesdropping, tampering, verifies server identity

Local CA

Pigsty automatically generates a local CA and issues certificates:

/etc/pki/
├── ca.crt              # CA certificate (public)
├── ca.key              # CA private key (keep secret!)
└── server.crt/key      # Server certificate/key

Important: Securely back up ca.key—if lost, all certificates must be reissued!


Compliance Mapping

SOC 2 Type II

Control PointPigsty SupportDescription
CC6.1 Logical Access ControlYesHBA + Role System
CC6.6 Transmission EncryptionYesSSL/TLS
CC7.2 System MonitoringYesPrometheus + Grafana
CC9.1 Business ContinuityYesHA + PITR
A1.2 Data RecoveryYespgBackRest Backup

Legend: Yes = Default satisfaction · Partial = Needs additional config


Security Checklist

Before Deployment

  • Prepare strong passwords (use password manager)
  • Plan network partitions (intranet/external CIDRs)
  • Decide SSL strategy (self-signed/external CA)

After Deployment (Required)

  • Change all default passwords
  • Verify HBA rules match expectations
  • Test SSL connections work
  • Configure auth failure alerts
  • Securely back up CA private key

Regular Maintenance

  • Audit user permissions
  • Check for expired accounts
  • Update certificates (if needed)
  • Review audit logs

Quick Config Examples

Production Security Configuration

# pigsty.yml - Production security config example
all:
  vars:
    # Change default passwords (required!)
    pg_admin_password: 'SecureDBAPassword2024!'
    pg_monitor_password: 'SecureMonitorPass2024!'
    pg_replication_password: 'SecureReplPass2024!'

    # Enable password strength check
    pg_libs: 'passwordcheck, pg_stat_statements, auto_explain'

    # Custom HBA rules
    pg_hba_rules:
      # App servers
      - {user: app, db: appdb, addr: '10.10.10.0/24', auth: scram-sha-256}
      # Admin enforce SSL
      - {user: dbuser_dba, db: all, addr: world, auth: ssl}

Financial-Grade Security Configuration

# Financial-grade config - enable certificate auth
pg_hba_rules:
  # Trading system uses certificate auth
  - {user: trade_user, db: trade, addr: world, auth: cert}
  # Other systems use SSL + password
  - {user: all, db: all, addr: world, auth: ssl}

# Enable backup encryption
pgbackrest_repo:
  minio:
    cipher_type: aes-256-cbc
    cipher_pass: 'YourBackupEncryptionKey'

Next Steps

Deep dive into security configuration details:

  • Security Overview: Overall security architecture and checklist
  • Authentication: HBA rules and password policies
  • Access Control: Role system and permission model
  • Encrypted Communication: SSL/TLS and certificate management
  • Compliance Checklist: Detailed SOC2 mapping

Related topics:

3.7.1 - Local CA

Pigsty includes a self-signed CA PKI infrastructure for issuing SSL certificates and encrypting network traffic.

Pigsty enables security best practices by default: using SSL to encrypt network traffic and HTTPS for web interfaces.

To achieve this, Pigsty includes a local self-signed CA for issuing SSL certificates and encrypting network communications.

By default, SSL and HTTPS are enabled but not enforced. For environments with higher security requirements, you can enforce SSL and HTTPS usage.


Local CA

During initialization, Pigsty generates a self-signed CA in the Pigsty source directory (~/pigsty) on the ADMIN node. This CA can be used for SSL, HTTPS, digital signatures, issuing database client certificates, and advanced security features.

Each Pigsty deployment uses a unique CA—CAs from different Pigsty deployments are not mutually trusted.

The local CA consists of two files, located in the files/pki/ca directory by default:

  • ca.crt: Self-signed CA root certificate, distributed to all managed nodes for certificate verification.
  • ca.key: CA private key for issuing certificates and verifying CA identity—keep this file secure and prevent leakage!

Using an Existing CA

If you already have your own CA PKI infrastructure, Pigsty can be configured to use your existing CA.

Simply place your CA public key and private key files in the files/pki/ca directory:

files/pki/ca/ca.key     # Core CA private key file, must exist; if missing, a new one is randomly generated
files/pki/ca/ca.crt     # If certificate file is missing, Pigsty auto-generates a new root certificate from the CA private key

When Pigsty executes the install.yml or infra.yml playbooks, if a ca.key private key file exists in files/pki/ca, the existing CA will be used. Since ca.crt can be generated from the ca.key private key, Pigsty will automatically regenerate the root certificate file if it’s missing.


Trusting the CA

During Pigsty installation, ca.crt is distributed to all nodes at /etc/pki/ca.crt during the node_ca task in the node.yml playbook.

EL-family and Debian-family operating systems have different default trusted CA certificate paths, so the distribution path and update methods differ:

rm -rf /etc/pki/ca-trust/source/anchors/ca.crt
ln -s /etc/pki/ca.crt /etc/pki/ca-trust/source/anchors/ca.crt
/bin/update-ca-trust
rm -rf /usr/local/share/ca-certificates/ca.crt
ln -s /etc/pki/ca.crt /usr/local/share/ca-certificates/ca.crt
/usr/sbin/update-ca-certificates

Pigsty issues HTTPS certificates for domain names used by web systems on infrastructure nodes by default, allowing HTTPS access to Pigsty’s web interfaces.

If you want to avoid “untrusted CA certificate” warnings in client browsers, distribute ca.crt to the trusted certificate directory on client machines.

You can double-click the ca.crt file to add it to your system keychain. For example, on MacOS, open “Keychain Access,” search for pigsty-ca, and set it to “trust” this root certificate.


Viewing Certificate Contents

Use the following command to view the Pigsty CA certificate contents:

openssl x509 -text -in /etc/pki/ca.crt
Local CA Root Certificate Content Example
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            50:29:e3:60:96:93:f4:85:14:fe:44:81:73:b5:e1:09:2a:a8:5c:0a
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: O=pigsty, OU=ca, CN=pigsty-ca
        Validity
            Not Before: Feb  7 00:56:27 2023 GMT
            Not After : Jan 14 00:56:27 2123 GMT
        Subject: O=pigsty, OU=ca, CN=pigsty-ca
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    00:c1:41:74:4f:28:c3:3c:2b:13:a2:37:05:87:31:
                    ....
                    e6:bd:69:a5:5b:e3:b4:c0:65:09:6e:84:14:e9:eb:
                    90:f7:61
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:pigsty-ca
            X509v3 Key Usage:
                Digital Signature, Certificate Sign, CRL Sign
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:1
            X509v3 Subject Key Identifier:
                C5:F6:23:CE:BA:F3:96:F6:4B:48:A5:B1:CD:D4:FA:2B:BD:6F:A6:9C
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        89:9d:21:35:59:6b:2c:9b:c7:6d:26:5b:a9:49:80:93:81:18:
        ....
        9e:dd:87:88:0d:c4:29:9e
-----BEGIN CERTIFICATE-----
...
cXyWAYcvfPae3YeIDcQpng==
-----END CERTIFICATE-----

Issuing Certificates

If you want to use client certificate authentication, you can use the local CA and the cert.yml playbook to manually issue PostgreSQL client certificates.

Set the certificate’s CN field to the database username:

./cert.yml -e cn=dbuser_dba
./cert.yml -e cn=dbuser_monitor

Issued certificates are generated in files/pki/misc/<cn>.{key,crt} by default.

3.7.2 - Access Control

Pigsty provides standard security practices with an out-of-the-box role and permission model.

Pigsty provides an out-of-the-box access control model based on the Role System and Permission System.

Access control is important, but many users struggle to implement it properly. Pigsty provides a streamlined access control model that serves as a security baseline for your cluster.


Role System

Pigsty’s default role system includes four default roles and four default users:

Role NameAttributesMember OfDescription
dbrole_readonlyNOLOGINRole: Global read-only
dbrole_readwriteNOLOGINdbrole_readonlyRole: Global read-write
dbrole_adminNOLOGINpg_monitor,dbrole_readwriteRole: Admin/Object creation
dbrole_offlineNOLOGINRole: Restricted read-only
postgresSUPERUSERSystem superuser
replicatorREPLICATIONpg_monitor,dbrole_readonlySystem replication user
dbuser_dbaSUPERUSERdbrole_adminPostgreSQL admin user
dbuser_monitorpg_monitorPostgreSQL monitor user

These roles and users are defined as follows:

pg_default_roles:                 # Global default roles and system users
  - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
  - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
  - { name: postgres     ,superuser: true  ,comment: system superuser }
  - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator }
  - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
  - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

Default Roles

Pigsty has four default roles:

  • Business Read-Only (dbrole_readonly): Role for global read-only access. Use this if other services need read-only access to this database.
  • Business Read-Write (dbrole_readwrite): Role for global read-write access. Production accounts for primary business should have database read-write permissions.
  • Business Admin (dbrole_admin): Role with DDL permissions. Typically used for business administrators or scenarios requiring table creation in applications.
  • Offline Read-Only (dbrole_offline): Restricted read-only access role (can only access offline instances). Usually for personal users or ETL tool accounts.

Default roles are defined in pg_default_roles. Unless you know what you’re doing, don’t change the default role names.

- { name: dbrole_readonly  , login: false , comment: role for global read-only access  }
- { name: dbrole_offline ,   login: false , comment: role for restricted read-only access (offline instance) }
- { name: dbrole_readwrite , login: false , roles: [dbrole_readonly], comment: role for global read-write access }
- { name: dbrole_admin , login: false , roles: [pg_monitor, dbrole_readwrite] , comment: role for object creation }

Default Users

Pigsty also has four default users (system users):

  • Superuser (postgres): Cluster owner and creator, same name as OS dbsu.
  • Replication User (replicator): System user for primary-replica replication.
  • Monitor User (dbuser_monitor): User for monitoring database and connection pool metrics.
  • Admin User (dbuser_dba): Administrator for daily operations and database changes.

These 4 default users’ username/password are defined by 4 pairs of dedicated parameters and referenced in many places:

Remember to change these passwords in production deployments—don’t use defaults!

pg_dbsu: postgres                             # Database superuser name, recommended not to change
pg_dbsu_password: ''                          # Database superuser password, recommended to leave empty!
pg_replication_username: replicator           # System replication username
pg_replication_password: DBUser.Replicator    # System replication password, must change!
pg_monitor_username: dbuser_monitor           # System monitor username
pg_monitor_password: DBUser.Monitor           # System monitor password, must change!
pg_admin_username: dbuser_dba                 # System admin username
pg_admin_password: DBUser.DBA                 # System admin password, must change!

Permission System

Pigsty has an out-of-the-box permission model that works with default roles.

  • All users can access all schemas.
  • Read-only users (dbrole_readonly) can read from all tables. (SELECT, EXECUTE)
  • Read-write users (dbrole_readwrite) can write to all tables and run DML. (INSERT, UPDATE, DELETE)
  • Admin users (dbrole_admin) can create objects and run DDL. (CREATE, USAGE, TRUNCATE, REFERENCES, TRIGGER)
  • Offline users (dbrole_offline) are similar to read-only but with restricted access—only offline instances (pg_role = 'offline' or pg_offline_query = true)
  • Objects created by admin users will have correct permissions.
  • Default privileges are configured on all databases, including template databases.
  • Database connection permissions are managed by database definition.
  • CREATE privilege on databases and public schema is revoked from PUBLIC by default.

Object Privileges

Default privileges for newly created objects are controlled by pg_default_privileges:

- GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
- GRANT SELECT     ON TABLES    TO dbrole_readonly
- GRANT SELECT     ON SEQUENCES TO dbrole_readonly
- GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
- GRANT USAGE      ON SCHEMAS   TO dbrole_offline
- GRANT SELECT     ON TABLES    TO dbrole_offline
- GRANT SELECT     ON SEQUENCES TO dbrole_offline
- GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
- GRANT INSERT     ON TABLES    TO dbrole_readwrite
- GRANT UPDATE     ON TABLES    TO dbrole_readwrite
- GRANT DELETE     ON TABLES    TO dbrole_readwrite
- GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
- GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
- GRANT TRUNCATE   ON TABLES    TO dbrole_admin
- GRANT REFERENCES ON TABLES    TO dbrole_admin
- GRANT TRIGGER    ON TABLES    TO dbrole_admin
- GRANT CREATE     ON SCHEMAS   TO dbrole_admin

Objects newly created by admins will have the above privileges by default. Use \ddp+ to view these default privileges:

TypeAccess Privileges
Function=X
dbrole_readonly=X
dbrole_offline=X
dbrole_admin=X
Schemadbrole_readonly=U
dbrole_offline=U
dbrole_admin=UC
Sequencedbrole_readonly=r
dbrole_offline=r
dbrole_readwrite=wU
dbrole_admin=rwU
Tabledbrole_readonly=r
dbrole_offline=r
dbrole_readwrite=awd
dbrole_admin=arwdDxt

Default Privileges

The SQL statement ALTER DEFAULT PRIVILEGES lets you set privileges for future objects. It doesn’t affect existing objects or objects created by non-admin users.

In Pigsty, default privileges are defined for three roles:

{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE {{ pg_dbsu }} {{ priv }};
{% endfor %}

{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE {{ pg_admin_username }} {{ priv }};
{% endfor %}

-- For other business admins, they should SET ROLE dbrole_admin before executing DDL
{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE "dbrole_admin" {{ priv }};
{% endfor %}

To maintain correct object permissions, you must execute DDL with admin users:

  1. {{ pg_dbsu }}, defaults to postgres
  2. {{ pg_admin_username }}, defaults to dbuser_dba
  3. Business admin users granted dbrole_admin role (using SET ROLE to switch to dbrole_admin)

Using postgres as global object owner is wise. If creating objects as business admin, use SET ROLE dbrole_admin before creation to maintain correct permissions.


Database Privileges

In Pigsty, database-level privileges are covered in database definition.

Databases have three privilege levels: CONNECT, CREATE, TEMP, and a special ‘privilege’: OWNERSHIP.

- name: meta         # Required, `name` is the only required field
  owner: postgres    # Optional, database owner, defaults to postgres
  allowconn: true    # Optional, allow connections, default true
  revokeconn: false  # Optional, revoke public connect privilege, default false
  • If owner parameter exists, it becomes database owner instead of {{ pg_dbsu }}
  • If revokeconn is false, all users have database CONNECT privilege (default behavior)
  • If revokeconn is explicitly true:
    • Database CONNECT privilege is revoked from PUBLIC
    • CONNECT privilege is explicitly granted to {{ pg_replication_username }}, {{ pg_monitor_username }}, {{ pg_admin_username }}
    • CONNECT privilege with GRANT OPTION is granted to database owner
  • revokeconn can isolate cross-database access within the same cluster

CREATE Privilege

For security, Pigsty revokes CREATE privilege on databases from PUBLIC by default. This is also default behavior since PostgreSQL 15.

Database owners can always adjust CREATE privileges based on actual needs.

4 - Get Started

Deploy Pigsty single-node version on your laptop/cloud server, access DB and Web UI

Pigsty uses a scalable architecture design, suitable for both large-scale production environments and single-node development/demo environments. This guide focuses on the latter.

If you intend to learn about Pigsty, you can start with the Quick Start single-node deployment. A Linux virtual machine with 1C/2G is sufficient to run Pigsty.

You can use a Linux MiniPC, free/discounted virtual machines provided by cloud providers, Windows WSL, or create a virtual machine on your own laptop for Pigsty deployment. Pigsty provides out-of-the-box Vagrant templates and Terraform templates to help you provision Linux VMs with one click locally or in the cloud.

pigsty-arch

The single-node version of Pigsty includes all core features: 440+ PG extensions, self-contained Grafana/Victoria monitoring, IaC provisioning capabilities, and local PITR point-in-time recovery. If you have external object storage (for PostgreSQL PITR backup), then for scenarios like demos, personal websites, and small services, even a single-node environment can provide a certain degree of data persistence guarantee. However, single-node cannot achieve High Availability—automatic failover requires at least 3 nodes.

If you want to install Pigsty in an environment without internet connection, please refer to the Offline Install mode. If you only need the PostgreSQL database itself, please refer to the Slim Install mode. If you are ready to start serious multi-node production deployment, please refer to the Deployment Guide.


Quick Start

Prepare a node with compatible Linux system, and execute as an admin user with passwordless ssh and sudo privileges:

curl -fsSL https://repo.pigsty.cc/get | bash  # Install Pigsty and dependencies
cd ~/pigsty; ./configure -g                   # Generate config (use default single-node config template, -g parameter generates random passwords)
./deploy.yml                                  # Execute deployment playbook to complete deployment

Yes, it’s that simple. You can use pre-configured templates to bring up Pigsty with one click without understanding any details.

Next, you can explore the Graphical User Interface, access PostgreSQL database services; or perform configuration customization and execute playbooks to deploy more clusters.

4.1 - Single-Node Installation

Get started with Pigsty—complete single-node install on a fresh Linux host!

This is the Pigsty single-node install guide. For multi-node HA prod deployment, refer to the Deployment docs.

Pigsty single-node installation consists of three steps: Install, Configure, and Deploy.


Summary

Prepare a node with compatible OS, and run as an admin user with nopass ssh and sudo:

curl -fsSL https://repo.pigsty.io/get | bash;
curl -fsSL https://repo.pigsty.cc/get | bash;

This command runs the install script, downloads and extracts Pigsty source to your home directory and installs dependencies. Then complete Configure and Deploy:

cd ~/pigsty      # Enter Pigsty directory
./configure -g   # Generate config file (optional, skip if you know how to configure)
./deploy.yml     # Execute deployment playbook based on generated config

After installation, access the Web UI via IP/domain + port 80/443 through Nginx, and access the default PostgreSQL service via port 5432.

The complete process takes 3–10 minutes depending on server specs/network. Offline installation speeds this up significantly; for monitoring-free setups, use Slim Install for even faster deployment.

Video Example: Online Single-Node Installation (Debian 13, x86_64)


Prepare

Installing Pigsty involves some preparation work. Here’s a checklist.

For single-node installations, many constraints can be relaxed—typically you only need to know your IP address. If you don’t have a static IP, use 127.0.0.1.

ItemRequirementItemRequirement
Node1-node, at least 1C2G, no upper limitDisk/data mount point, xfs recommended
OSLinux x86_64 / aarch64, EL/Debian/UbuntuNetworkStatic IPv4; single-node without fixed IP can use 127.0.0.1
SSHnopass SSH login via public keySUDOsudo privilege, preferably with nopass option

Typically, you only need to focus on your local IP address—as an exception, for single-node deployment, use 127.0.0.1 if no static IP available.


Install

Use the following commands to auto-install Pigsty source to ~/pigsty (recommended). Deployment dependencies (Ansible) are installed automatically.

curl -fsSL https://repo.pigsty.io/get | bash            # Install latest stable version
curl -fsSL https://repo.pigsty.io/get | bash -s v4.0.0  # Install specific version
curl -fsSL https://repo.pigsty.cc/get | bash            # Install latest stable version
curl -fsSL https://repo.pigsty.cc/get | bash -s v4.0.0  # Install specific version

If you prefer not to run a remote script, you can manually download or clone the source. When using git, always checkout a specific version before use.

git clone https://github.com/pgsty/pigsty; cd pigsty;
git checkout v4.0.0-b4;  # Always checkout a specific version when using git

For manual download/clone installations, run the bootstrap script to install Ansible and other dependencies. You can also install them yourself.

./bootstrap           # Install ansible for subsequent deployment

Configure

In Pigsty, deployment blueprints are defined by the inventory, the pigsty.yml configuration file. You can customize through declarative configuration.

Pigsty provides the configure script as an optional configuration wizard, which generates an inventory with good defaults based on your environment and input:

./configure -g                # Use config wizard to generate config with random passwords

The generated config file is at ~/pigsty/pigsty.yml by default. Review and customize as needed before installation.

Many configuration templates are available for reference. You can skip the wizard and directly edit pigsty.yml:

./configure                  # Default template, install PG 18 with essential extensions
./configure -v 17            # Use PG 17 instead of default PG 18
./configure -c rich          # Create local repo, download all extensions, install major ones
./configure -c slim          # Minimal install template, use with ./slim.yml playbook
./configure -c app/supa      # Use app/supa self-hosted Supabase template
./configure -c ivory         # Use IvorySQL kernel instead of native PG
./configure -i 10.11.12.13   # Explicitly specify primary IP address
./configure -r china         # Use China mirrors instead of default repos
./configure -c ha/full -s    # Use 4-node sandbox template, skip IP replacement/detection
Example configure output
$ ./configure

configure pigsty v4.0.0 begin
[ OK ] region  = default
[ OK ] kernel  = Linux
[ OK ] machine = x86_64
[ OK ] package = rpm,dnf
[ OK ] vendor  = rocky (Rocky Linux)
[ OK ] version = 9 (9.6)
[ OK ] sudo = vagrant ok
[ OK ] ssh = [email protected] ok
[WARN] Multiple IP address candidates found:
    (1) 192.168.121.24	inet 192.168.121.24/24 brd 192.168.121.255 scope global dynamic noprefixroute eth0
    (2) 10.10.10.12	    inet 10.10.10.12/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.12    # <------- INPUT YOUR PRIMARY IPV4 ADDRESS HERE!
[ OK ] primary_ip = 10.10.10.12 (from input)
[ OK ] admin = [email protected] ok
[ OK ] mode = meta (el9)
[ OK ] locale  = C.UTF-8
[ OK ] configure pigsty done
proceed with ./deploy.yml

Common configure arguments:

ArgumentDescription
-i|--ipPrimary internal IP of current host, replaces placeholder 10.10.10.10
-c|--confConfig template name relative to conf/, without .yml suffix
-v|--versionPostgreSQL major version: 13, 14, 15, 16, 17, 18
-r|--regionUpstream repo region for faster downloads: (default|china|europe)
-n|--non-interactiveUse command-line args for primary IP, skip interactive wizard
-x|--proxyUse current env vars to configure proxy_env

If your machine has multiple IPs bound, use -i|--ip <ipaddr> to explicitly specify the primary IP, or provide it in the interactive prompt. The script replaces the placeholder 10.10.10.10 with your node’s primary IPv4 address. Choose a static IP; do not use public IPs.


Deploy

Pigsty’s deploy.yml playbook applies the blueprint from Configure to target nodes.

./deploy.yml     # Deploy all defined modules on current node at once
Example deployment output
......

TASK [pgsql : pgsql init done] *************************************************
ok: [10.10.10.11] => {
    "msg": "postgres://10.10.10.11/postgres | meta  | dbuser_meta dbuser_view "
}
......

TASK [pg_monitor : load grafana datasource meta] *******************************
changed: [10.10.10.11]

PLAY RECAP *********************************************************************
10.10.10.11                : ok=302  changed=232  unreachable=0    failed=0    skipped=65   rescued=0    ignored=1
localhost                  : ok=6    changed=3    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

When you see pgsql init done, PLAY RECAP and similar output at the end, installation is complete!



Interface

After single-node installation, you typically have four modules installed on the current node: PGSQL, INFRA, NODE, and ETCD.

IDNODEPGSQLINFRAETCD
110.10.10.10pg-meta-1infra-1etcd-1

The INFRA module provides a graphical management interface, accessible via Nginx on ports 80/443.

The PGSQL module provides a PostgreSQL database server, listening on 5432, also accessible via Pgbouncer/HAProxy proxies.


More

Use the current node as a base to deploy and monitor more clusters: add cluster definitions to the inventory and run:

bin/node-add   pg-test      # Add the 3 nodes of cluster pg-test to Pigsty management
bin/pgsql-add  pg-test      # Initialize a 3-node pg-test HA PG cluster
bin/redis-add  redis-ms     # Initialize Redis cluster: redis-ms

Most modules require the NODE module installed first. See available modules for details:

PGSQL, INFRA, NODE, ETCD, MINIO, REDIS, FERRET, DOCKER……

4.2 - Web Interface

Explore Pigsty’s Web graphical management interface, Grafana dashboards, and how to access them via domain names and HTTPS.

After single-node installation, you’ll have the INFRA module installed on the current node, which includes an out-of-the-box Nginx web server.

The default server configuration provides a WebUI graphical interface for displaying monitoring dashboards and unified proxy access to other component web interfaces.


Access

You can access this graphical interface by entering the deployment node’s IP address in your browser. By default, Nginx serves on standard ports 80/443.

Direct IP AccessDomain (HTTP)Domain (HTTPS)Demo
http://10.10.10.10http://i.pigstyhttps://i.pigstyhttps://demo.pigsty.io


Monitoring

To access Pigsty’s monitoring system dashboards (Grafana), visit the /ui endpoint on the server.

Direct IP AccessDomain (HTTP)Domain (HTTPS)Demo
http://10.10.10.10/uihttp://i.pigsty/uihttps://i.pigsty/uihttps://demo.pigsty.io/ui

If your service is exposed to Internet or office network, we recommend accessing via domain names and enabling HTTPS encryption—only minimal configuration is needed.


Endpoints

By default, Nginx exposes the following endpoints via different paths on the default server at ports 80/443:

EndpointComponentNative PortDescriptionPublic Demo
/Nginx80/443Homepage, local repo, file servicedemo.pigsty.io
/ui/Grafana3000Grafana dashboard portaldemo.pigsty.io/ui/
/vmetrics/VictoriaMetrics8428Time series database Web UIdemo.pigsty.io/vmetrics/
/vlogs/VictoriaLogs9428Log database Web UIdemo.pigsty.io/vlogs/
/vtraces/VictoriaTraces10428Distributed tracing Web UIdemo.pigsty.io/vtraces/
/vmalert/VMAlert8880Alert rule managementdemo.pigsty.io/vmalert/
/alertmgr/AlertManager9059Alert management Web UIdemo.pigsty.io/alertmgr/
/blackbox/Blackbox9115Blackbox exporter
/haproxy/*HAProxy9101Load balancer admin Web UI
/pevPEV280PostgreSQL execution plan visualizerdemo.pigsty.io/pev
/nginxNginx80Nginx status page (for metrics)

Domain Access

If you have your own domain name, you can point it to Pigsty server’s IP address to access various services via domain.

If you want to enable HTTPS, you should modify the home server configuration in the infra_portal parameter:

all:
  vars:
    infra_portal:
      home : { domain: i.pigsty } # Replace i.pigsty with your domain
all:
  vars:
    infra_portal:  # domain specifies the domain name  # certbot parameter specifies certificate name
      home : { domain: demo.pigsty.io ,certbot: mycert }

You can run make cert command after deployment to apply for a free Let’s Encrypt certificate for the domain. If you don’t define the certbot field, Pigsty will use the local CA to issue a self-signed HTTPS certificate by default. In this case, you must first trust Pigsty’s self-signed CA to access normally in your browser.

You can also mount local directories and other upstream services to Nginx. For more management details, refer to INFRA Management - Nginx.

4.3 - Getting Started with PostgreSQL

Get started with PostgreSQL—connect using CLI and graphical clients

PostgreSQL (abbreviated as PG) is the world’s most advanced and popular open-source relational database. Use it to store and retrieve multi-modal data.

This guide is for developers with basic Linux CLI experience but not very familiar with PostgreSQL, helping you quickly get started with PG in Pigsty.

We assume you’re a personal user deploying in the default single-node mode. For prod multi-node HA cluster access, refer to Prod Service Access.


Basics

In the default single-node installation template, you’ll create a PostgreSQL database cluster named pg-meta on the current node, with only one primary instance.

PostgreSQL listens on port 5432, and the cluster has a preset database meta available for use.

After installation, exit the current admin user ssh session and re-login to refresh environment variables. Then simply type p and press Enter to access the database cluster via the psql CLI tool:

vagrant@pg-meta-1:~$ p
psql (18.1 (Ubuntu 18.1-1.pgdg24.04+2))
Type "help" for help.

postgres=#

You can also switch to the postgres OS user and execute psql directly to connect to the default postgres admin database.


Connecting to Database

To access a PostgreSQL database, use a CLI tool or graphical client and fill in the PostgreSQL connection string:

postgres://username:password@host:port/dbname

Some drivers and tools may require you to fill in these parameters separately. The following five are typically required:

ParameterDescriptionExample ValueNotes
hostDatabase server address10.10.10.10Replace with your node IP or domain; can omit for localhost
portPort number5432PG default port, can be omitted
usernameUsernamedbuser_dbaPigsty default database admin
passwordPasswordDBUser.DBAPigsty default admin password (change this!)
dbnameDatabase namemetaDefault template database name

For personal use, you can directly use the Pigsty default database superuser dbuser_dba for connection and management. The dbuser_dba has full database privileges. By default, if you specified the configure -g parameter when configuring Pigsty, the password will be randomly generated and saved in ~/pigsty/pigsty.yml:

cat ~/pigsty/pigsty.yml | grep pg_admin_password

Default Accounts

Pigsty’s default single-node template presets the following database users, ready to use out of the box:

UsernamePasswordRolePurpose
dbuser_dbaDBUser.DBASuperuserDatabase admin (change this!)
dbuser_metaDBUser.MetaBusiness adminApp R/W (change this!)
dbuser_viewDBUser.ViewerRead-only userData viewing (change this!)

For example, you can connect to the meta database in the pg-meta cluster using three different connection strings with three different users:

postgres://dbuser_dba:[email protected]:5432/meta
postgres://dbuser_meta:[email protected]:5432/meta
postgres://dbuser_view:[email protected]:5432/meta

Note: These default passwords are automatically replaced with random strong passwords when using configure -g. Remember to replace the IP address and password with actual values.


Using CLI Tools

psql is the official PostgreSQL CLI client tool, powerful and the first choice for DBAs and developers.

On a server with Pigsty deployed, you can directly use psql to connect to the local database:

# Simplest way: use postgres system user for local connection (no password needed)
sudo -u postgres psql

# Use connection string (recommended, most universal)
psql 'postgres://dbuser_dba:[email protected]:5432/meta'

# Use parameter form
psql -h 10.10.10.10 -p 5432 -U dbuser_dba -d meta

# Use env vars to avoid password appearing in command line
export PGPASSWORD='DBUser.DBA'
psql -h 10.10.10.10 -p 5432 -U dbuser_dba -d meta

After successful connection, you’ll see a prompt like this:

psql (18.1)
Type "help" for help.

meta=#

Common psql Commands

After entering psql, you can execute SQL statements or use meta-commands starting with \:

CommandDescriptionCommandDescription
Ctrl+CInterrupt queryCtrl+DExit psql
\?Show all meta commands\hShow SQL command help
\lList all databases\c dbnameSwitch to database
\d tableView table structure\d+ tableView table details
\duList all users/roles\dxList installed extensions
\dnList all schemas\dtList all tables

Executing SQL

In psql, directly enter SQL statements ending with semicolon ;:

-- Check PostgreSQL version
SELECT version();

-- Check current time
SELECT now();

-- Create a test table
CREATE TABLE test (id SERIAL PRIMARY KEY, name TEXT, created_at TIMESTAMPTZ DEFAULT now());

-- Insert data
INSERT INTO test (name) VALUES ('hello'), ('world');

-- Query data
SELECT * FROM test;

-- Drop test table
DROP TABLE test;

Using Graphical Clients

If you prefer graphical interfaces, here are some popular PostgreSQL clients:

Grafana

Pigsty’s INFRA module includes Grafana with a pre-configured PostgreSQL data source (Meta). You can directly query the database using SQL from the Grafana Explore panel through the browser graphical interface, no additional client tools needed.

Grafana’s default username is admin, and the password can be found in the grafana_admin_password field in the inventory (default pigsty).

DataGrip

DataGrip is a professional database IDE from JetBrains, with powerful features. IntelliJ IDEA’s built-in Database Console can also connect to PostgreSQL in a similar way.

DBeaver

DBeaver is a free open-source universal database tool supporting almost all major databases. It’s a cross-platform desktop client.

pgAdmin

pgAdmin is the official PostgreSQL-specific GUI tool from PGDG, available through browser or as a desktop client.

Pigsty provides a configuration template for one-click pgAdmin service deployment using Docker in Software Template: pgAdmin.


Viewing Monitoring Dashboards

Pigsty provides many PostgreSQL monitoring dashboards, covering everything from cluster overview to single-table analysis.

We recommend starting with PGSQL Overview. Many elements in the dashboards are clickable, allowing you to drill down layer by layer to view details of each cluster, instance, database, and even internal database objects like tables, indexes, and functions.


Trying Extensions

One of PostgreSQL’s most powerful features is its extension ecosystem. Extensions can add new data types, functions, index methods, and more to the database.

Pigsty provides an unparalleled 440+ extensions in the PG ecosystem, covering 16 major categories including time-series, geographic, vector, and full-text search—install with one click. Start with three powerful and commonly used extensions that are automatically installed in Pigsty’s default template. You can also install more extensions as needed.

  • postgis: Geographic information system for processing maps and location data
  • pgvector: Vector database supporting AI embedding vector similarity search
  • timescaledb: Time-series database for efficient storage and querying of time-series data
\dx                            -- psql meta command, list installed extensions
TABLE pg_available_extensions; -- Query installed, available extensions
CREATE EXTENSION postgis;      -- Enable postgis extension

Next Steps

Congratulations on completing the PostgreSQL basics! Next, you can start configuring and customizing your database.

4.4 - Customize Pigsty with Configuration

Express your infra and clusters with declarative config files

Besides using the configuration wizard to auto-generate configs, you can write Pigsty config files from scratch. This tutorial guides you through building a complex inventory step by step.

If you define everything in the inventory upfront, a single deploy.yml playbook run completes all deployment—but it hides the details.

This doc breaks down all modules and playbooks, showing how to incrementally build from a simple config to a complete deployment.


Minimal Configuration

The simplest valid config only defines the admin_ip variable—the IP address of the node where Pigsty is installed (admin node):

all: { vars: { admin_ip: 10.10.10.10 } }
# Set region: china to use mirrors
all: { vars: { admin_ip: 10.10.10.10, region: china } }

This config deploys nothing, but running ./deploy.yml generates a self-signed CA in files/pki/ca for issuing certificates.

For convenience, you can also set region to specify which region’s software mirrors to use (default, china, europe).


Add Nodes

Pigsty’s NODE module manages cluster nodes. Any IP address in the inventory will be managed by Pigsty with the NODE module installed.

all:  # Remember to replace 10.10.10.10 with your actual IP
  children: { nodes: { hosts: { 10.10.10.10: {} } } }
  vars:
    admin_ip: 10.10.10.10                   # Current node IP
    region: default                         # Default repos
    node_repo_modules: node,pgsql,infra     # Add node, pgsql, infra repos
all:  # Remember to replace 10.10.10.10 with your actual IP
  children: { nodes: { hosts: { 10.10.10.10: {} } } }
  vars:
    admin_ip: 10.10.10.10                 # Current node IP
    region: china                         # Use mirrors
    node_repo_modules: node,pgsql,infra   # Add node, pgsql, infra repos

We added two global parameters: node_repo_modules specifies repos to add; region specifies which region’s mirrors to use.

These parameters enable the node to use correct repositories and install required packages. The NODE module offers many customization options: node names, DNS, repos, packages, NTP, kernel params, tuning templates, monitoring, log collection, etc. Even without changes, the defaults are sufficient.

Run deploy.yml or more precisely node.yml to bring the defined node under Pigsty management.

IDNODEINFRAETCDPGSQLDescription
110.10.10.10---Add node

Add Infrastructure

A full-featured RDS cloud database service needs infrastructure support: monitoring (metrics/log collection, alerting, visualization), NTP, DNS, and other foundational services.

Define a special group infra to deploy the INFRA module:

all:  # Simply changed group name from nodes -> infra and added infra_seq
  children: { infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } } }
  vars:
    admin_ip: 10.10.10.10
    region: default
    node_repo_modules: node,pgsql,infra
all:  # Simply changed group name from nodes -> infra and added infra_seq
  children: { infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } } }
  vars:
    admin_ip: 10.10.10.10
    region: china
    node_repo_modules: node,pgsql,infra

We also assigned an identity parameter: infra_seq to distinguish nodes in multi-node HA INFRA deployments.

Run infra.yml to install INFRA**](/docs/infra/) and [**NODE modules on 10.10.10.10:

./infra.yml   # Install INFRA module on infra group (includes NODE module)

NODE module is implicitly defined as long as an IP exists. NODE is idempotent—re-running has no side effects.

After completion, you’ll have complete observability infrastructure and node monitoring, but PostgreSQL database service is not yet deployed.

If your goal is just to set up this monitoring system (Grafana + Victoria), you’re done! The infra template is designed for this. Everything in Pigsty is modular: you can deploy only monitoring infra without databases; or vice versa—run HA PostgreSQL clusters without infra—Slim Install.

IDNODEINFRAETCDPGSQLDescription
110.10.10.10infra-1--Add infrastructure

Deploy Database Cluster

To provide PostgreSQL service, install the PGSQL` module and its dependency ETCD—just two lines of config:

all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq:  1 } } } # Add etcd cluster
    pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }, vars: { pg_cluster: pg-meta } } # Add pg cluster
  vars: { admin_ip: 10.10.10.10, region: default, node_repo_modules: node,pgsql,infra }
all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq:  1 } } } # Add etcd cluster
    pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }, vars: { pg_cluster: pg-meta } } # Add pg cluster
  vars: { admin_ip: 10.10.10.10, region: china, node_repo_modules: node,pgsql,infra }

We added two new groups: etcd and pg-meta, defining a single-node etcd cluster and a single-node PostgreSQL cluster.

Use ./deploy.yml to redeploy everything, or incrementally deploy:

./etcd.yml  -l etcd      # Install ETCD module on etcd group
./pgsql.yml -l pg-meta   # Install PGSQL module on pg-meta group

PGSQL depends on ETCD for HA consensus, so install ETCD first. After completion, you have a working PostgreSQL service!

IDNODEINFRAETCDPGSQLDescription
110.10.10.10infra-1etcd-1pg-meta-1Add etcd and PostgreSQL cluster

We used node.yml, infra.yml, etcd.yml, and pgsql.yml to deploy all four core modules on a single machine.


Define Databases and Users

In Pigsty, you can customize PostgreSQL cluster internals like databases and users through the inventory:

all:
  children:
    # Other groups and variables hidden for brevity
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:       # Define database users
          - { name: dbuser_meta ,password: DBUser.Meta ,pgbouncer: true ,roles: [dbrole_admin] ,comment: admin user  }
        pg_databases:   # Define business databases
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [vector] }
  • pg_users: Defines a new user dbuser_meta with password DBUser.Meta
  • pg_databases: Defines a new database meta with Pigsty CMDB schema (optional) and vector extension

Pigsty offers rich customization parameters covering all aspects of databases and users. If you define these parameters upfront, they’re automatically created during ./pgsql.yml execution. For existing clusters, you can incrementally create or modify users and databases:

bin/pgsql-user pg-meta dbuser_meta      # Ensure user dbuser_meta exists in pg-meta
bin/pgsql-db   pg-meta meta             # Ensure database meta exists in pg-meta

Configure PG Version and Extensions

You can install different major versions of PostgreSQL, and up to 440 extensions. Let’s remove the current default PG 18 and install PG 17:

./pgsql-rm.yml -l pg-meta   # Remove old pg-meta cluster (it's PG 18)

We can customize parameters to install and enable common extensions by default: timescaledb, postgis, and pgvector:

all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq:  1 } } } # Add etcd cluster
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_version: 17   # Specify PG version as 17
        pg_extensions: [ timescaledb, postgis, pgvector ]      # Install these extensions
        pg_libs: 'timescaledb,pg_stat_statements,auto_explain'  # Preload these extension libraries
        pg_databases: { { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [vector, postgis, timescaledb ] } }
        pg_users: { { name: dbuser_meta ,password: DBUser.Meta ,pgbouncer: true ,roles: [dbrole_admin] ,comment: admin user } }

  vars:
    admin_ip: 10.10.10.10
    region: default
    node_repo_modules: node,pgsql,infra
./pgsql.yml -l pg-meta   # Install PG17 and extensions, recreate pg-meta cluster

Add More Nodes

Add more nodes to the deployment, bring them under Pigsty management, deploy monitoring, configure repos, install software…

# Add entire cluster at once, or add nodes individually
bin/node-add pg-test

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

Deploy HA PostgreSQL Cluster

Now deploy a new database cluster pg-test on the three newly added nodes, using a three-node HA architecture:

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 }

Deploy Redis Cluster

Pigsty provides optional Redis support as a caching service in front of PostgreSQL:

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

Redis HA requires cluster mode or sentinel mode. See Redis Configuration.


Deploy MinIO Cluster

Pigsty provides optional open-source object storage, S3 alternative—MinIO support, as backup repository for PostgreSQL.

./minio.yml -l minio

Serious prod MinIO deployments typically require at least 4 nodes with 4 disks each (4N/16D).


Deploy Docker Module

If you want to use containers to run tools for managing PG or software using PostgreSQL, install the DOCKER module:

./docker.yml -l infra

Use pre-made application templates to launch common software tools with one click, such as the GUI tool for PG management: Pgadmin:

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

You can even self-host enterprise-grade Supabase with Pigsty, using external HA PostgreSQL clusters as the foundation and running stateless components in containers.

4.5 - Run Playbooks with Ansible

Use Ansible playbooks to deploy and manage Pigsty clusters

Pigsty uses Ansible to manage clusters, a very popular large-scale/batch/automation ops tool in the SRE community.

Ansible can use declarative approach for server configuration management. All module deployments are implemented through a series of idempotent Ansible playbooks.

For example, in single-node deployment, you’ll use the deploy.yml playbook. Pigsty has more built-in playbooks, you can choose to use as needed.

Understanding Ansible basics helps with better use of Pigsty, but this is not required, especially for single-node deployment.


Deploy Playbook

Pigsty provides a “one-stop” deploy playbook deploy.yml, installing all modules on the current env in one go (if defined in config):

PlaybookCommandGroupinfra[nodes]etcdminio[pgsql]
infra.yml./infra.yml-l infra
node.yml./node.yml
etcd.yml./etcd.yml-l etcd
minio.yml./minio.yml-l minio
pgsql.yml./pgsql.yml

This is the simplest deployment method. You can also follow instructions in Customization Guide to incrementally complete deployment of all modules and nodes step by step.


Install Ansible

When using the Pigsty installation script, or the bootstrap phase of offline installation, Pigsty will automatically install ansible and its dependencies for you.

If you want to manually install Ansible, refer to the following instructions. The minimum supported Ansible version is 2.9.

sudo apt install -y ansible python3-jmespath
sudo dnf install -y ansible python-jmespath         # EL 10
sudo dnf install -y ansible python3.12-jmespath     # EL 9/8
brew install ansible
pip3 install jmespath

Ansible is also available on macOS. You can use Homebrew to install Ansible on Mac, and use it as an admin node to manage remote cloud servers. This is convenient for single-node Pigsty deployment on cloud VPS, but not recommended in prod envs.


Execute Playbook

Ansible playbooks are executable YAML files containing a series of task definitions to execute. Running playbooks requires the ansible-playbook executable in your environment variable PATH. Running ./node.yml playbook is essentially executing the ansible-playbook node.yml command.

You can use some parameters to fine-tune playbook execution. The following 4 parameters are essential for effective Ansible use:

PurposeParameterDescription
Target-l|--limit <pattern>Limit execution to specific groups/hosts/patterns
Tasks-t|--tags <tags>Only run tasks with specific tags
Params-e|--extra-vars <vars>Extra command-line parameters
Config-i|--inventory <path>Use a specific inventory file
./node.yml                         # Run node playbook on all hosts
./pgsql.yml -l pg-test             # Run pgsql playbook on pg-test cluster
./infra.yml -t repo_build          # Run infra.yml subtask repo_build
./pgsql-rm.yml -e pg_rm_pkg=false  # Remove pgsql, but keep packages (don't uninstall software)
./infra.yml -i conf/mynginx.yml    # Use another location's config file

Limit Hosts

Playbook execution targets can be limited with -l|--limit <selector>. This is convenient when running playbooks on specific hosts/nodes or groups/clusters. Here are some host limit examples:

./pgsql.yml                              # Run on all hosts (dangerous!)
./pgsql.yml -l pg-test                   # Run on pg-test cluster
./pgsql.yml -l 10.10.10.10               # Run on single host 10.10.10.10
./pgsql.yml -l pg-*                      # Run on hosts/groups matching glob `pg-*`
./pgsql.yml -l '10.10.10.11,&pg-test'    # Run on 10.10.10.11 in pg-test group
./pgsql-rm.yml -l 'pg-test,!10.10.10.11' # Run on pg-test, except 10.10.10.11

See all details in Ansible documentation: Patterns: targeting hosts and groups


Limit Tasks

Execution tasks can be controlled with -t|--tags <tags>. If specified, only tasks with the given tags will execute instead of the entire playbook.

./infra.yml -t repo          # Create repo
./node.yml  -t node_pkg      # Install node packages
./pgsql.yml -t pg_install    # Install PG packages and extensions
./etcd.yml  -t etcd_purge    # Destroy ETCD cluster
./minio.yml -t minio_alias   # Write MinIO CLI config

To run multiple tasks, specify multiple tags separated by commas -t tag1,tag2:

./node.yml  -t node_repo,node_pkg   # Add repos, then install packages
./pgsql.yml -t pg_hba,pg_reload     # Configure, then reload pg hba rules

Extra Vars

You can override config parameters at runtime using CLI arguments, which have highest priority.

Extra command-line parameters are passed via -e|--extra-vars KEY=VALUE, usable multiple times:

# Create admin using another admin user
./node.yml -e ansible_user=admin -k -K -t node_admin

# Initialize a specific Redis instance: 10.10.10.11:6379
./redis.yml -l 10.10.10.10 -e redis_port=6379 -t redis

# Remove PostgreSQL but keep packages and data
./pgsql-rm.yml -e pg_rm_pkg=false -e pg_rm_data=false

For complex parameters, use JSON strings to pass multiple complex parameters at once:

# Add repo and install packages
./node.yml -t node_install -e '{"node_repo_modules":"infra","node_packages":["duckdb"]}'

Specify Inventory

The default config file is pigsty.yml in the Pigsty home directory.

You can use -i <path> to specify a different inventory file path.

./pgsql.yml -i conf/rich.yml            # Initialize single node with all extensions per rich config
./pgsql.yml -i conf/ha/full.yml         # Initialize 4-node cluster per full config
./pgsql.yml -i conf/app/supa.yml        # Initialize 1-node Supabase deployment per supa.yml

Convenience Scripts

Pigsty provides a series of convenience scripts to simplify common operations. These scripts are in the bin/ directory:

bin/node-add   <cls>            # Add nodes to Pigsty management: ./node.yml -l <cls>
bin/node-rm    <cls>            # Remove nodes from Pigsty: ./node-rm.yml -l <cls>
bin/pgsql-add  <cls>            # Initialize PG cluster: ./pgsql.yml -l <cls>
bin/pgsql-rm   <cls>            # Remove PG cluster: ./pgsql-rm.yml -l <cls>
bin/pgsql-user <cls> <username> # Add business user: ./pgsql-user.yml -l <cls> -e username=<user>
bin/pgsql-db   <cls> <dbname>   # Add business database: ./pgsql-db.yml -l <cls> -e dbname=<db>
bin/redis-add  <cls>            # Initialize Redis cluster: ./redis.yml -l <cls>
bin/redis-rm   <cls>            # Remove Redis cluster: ./redis-rm.yml -l <cls>

These scripts are simple wrappers around Ansible playbooks, making common operations more convenient.


Playbook List

Below are the built-in playbooks in Pigsty. You can also easily add your own playbooks, or customize and modify playbook implementation logic as needed.

ModulePlaybookFunction
INFRAdeploy.ymlOne-click deploy Pigsty on current node
INFRAinfra.ymlInitialize Pigsty infrastructure on infra nodes
INFRAinfra-rm.ymlRemove infrastructure components from infra nodes
INFRAcache.ymlCreate offline packages from target node
INFRAcert.ymlIssue certificates using Pigsty self-signed CA
NODEnode.ymlInitialize node, adjust to desired state
NODEnode-rm.ymlRemove node from Pigsty
PGSQLpgsql.ymlInitialize HA PostgreSQL cluster or add replica
PGSQLpgsql-rm.ymlRemove PostgreSQL cluster or replica
PGSQLpgsql-db.ymlAdd new business database to existing cluster
PGSQLpgsql-user.ymlAdd new business user to existing cluster
PGSQLpgsql-pitr.ymlPerform point-in-time recovery on cluster
PGSQLpgsql-monitor.ymlMonitor remote PostgreSQL with local exporter
PGSQLpgsql-migration.ymlGenerate migration manual and scripts
PGSQLslim.ymlInstall Pigsty with minimal components
REDISredis.ymlInitialize Redis cluster/node/instance
REDISredis-rm.ymlRemove Redis cluster/node/instance
ETCDetcd.ymlInitialize ETCD cluster or add new member
ETCDetcd-rm.ymlRemove ETCD cluster/data or shrink member
MINIOminio.ymlInitialize MinIO cluster (optional pgBackRest repo)
MINIOminio-rm.ymlRemove MinIO cluster and data
DOCKERdocker.ymlInstall Docker on nodes
DOCKERapp.ymlInstall applications using Docker Compose
FERRETmongo.ymlInstall Mongo/FerretDB on nodes

4.6 - Offline Installation

Install Pigsty in air-gapped env using offline packages

Pigsty installs from Internet upstream by default, but some envs are isolated from the Internet. To address this, Pigsty supports offline installation using offline packages. Think of them as Linux-native Docker images.


Overview

Offline packages bundle all required RPM/DEB packages and dependencies; they are snapshots of the local APT/YUM repo after a normal installation.

In serious prod deployments, we strongly recommend using offline packages. They ensure all future nodes have consistent software versions with the existing env, and avoid online installation failures caused by upstream changes (quite common!), guaranteeing you can run it independently forever.


Offline Packages

We typically release offline packages for the following Linux distros, using the latest OS minor version.

Linux DistributionSystem CodeMinor VersionPackage
RockyLinux 8 x86_64el8.x86_648.10pigsty-pkg-v4.0.0.el8.x86_64.tgz
RockyLinux 8 aarch64el8.aarch648.10pigsty-pkg-v4.0.0.el8.aarch64.tgz
RockyLinux 9 x86_64el9.x86_649.6pigsty-pkg-v4.0.0.el9.x86_64.tgz
RockyLinux 9 aarch64el9.aarch649.6pigsty-pkg-v4.0.0.el9.aarch64.tgz
RockyLinux 10 x86_64el10.x86_6410.0pigsty-pkg-v4.0.0.el10.x86_64.tgz
RockyLinux 10 aarch64el10.aarch6410.0pigsty-pkg-v4.0.0.el10.aarch64.tgz
Debian 12 x86_64d12.x86_6412.11pigsty-pkg-v4.0.0.d12.x86_64.tgz
Debian 12 aarch64d12.aarch6412.11pigsty-pkg-v4.0.0.d12.aarch64.tgz
Debian 13 x86_64d13.x86_6413.2pigsty-pkg-v4.0.0.d13.x86_64.tgz
Debian 13 aarch64d13.aarch6413.2pigsty-pkg-v4.0.0.d13.aarch64.tgz
Ubuntu 24.04 x86_64u24.x86_6424.04.2pigsty-pkg-v4.0.0.u24.x86_64.tgz
Ubuntu 24.04 aarch64u24.aarch6424.04.2pigsty-pkg-v4.0.0.u24.aarch64.tgz
Ubuntu 22.04 x86_64u22.x86_6422.04.5pigsty-pkg-v4.0.0.u22.x86_64.tgz
Ubuntu 22.04 aarch64u22.aarch6422.04.5pigsty-pkg-v4.0.0.u22.aarch64.tgz

If you use an OS from the list above (exact minor version match), we recommend using offline packages. Pigsty provides ready-to-use pre-made offline packages for these systems, freely downloadable from GitHub.

You can find these packages on the GitHub release page:

6a26fa44f90a16c7571d2aaf0e997d07  pigsty-v4.0.0.tgz
537839201c536a1211f0b794482d733b  pigsty-pkg-v4.0.0.el9.x86_64.tgz
85687cb56517acc2dce14245452fdc05  pigsty-pkg-v4.0.0.el9.aarch64.tgz
a333e8eb34bf93f475c85a9652605139  pigsty-pkg-v4.0.0.el10.x86_64.tgz
4b98b463e2ebc104c35ddc94097e5265  pigsty-pkg-v4.0.0.el10.aarch64.tgz
4f62851c9d79a490d403f59deb4823f4  pigsty-pkg-v4.0.0.el8.x86_64.tgz
66e283c9f6bfa80654f7ed3ffb9b53e5  pigsty-pkg-v4.0.0.el8.aarch64.tgz
f7971d9d6aab1f8f307556c2f64b701c  pigsty-pkg-v4.0.0.d12.x86_64.tgz
c4d870e5ef61ed05724c15fbccd1220b  pigsty-pkg-v4.0.0.d12.aarch64.tgz
408991c5ff028b5c0a86fac804d64b93  pigsty-pkg-v4.0.0.d13.x86_64.tgz
8d7c9404b97a11066c00eb7fc1330181  pigsty-pkg-v4.0.0.d13.aarch64.tgz
2a25eff283332d9006854f36af6602b2  pigsty-pkg-v4.0.0.u24.x86_64.tgz
a4fb30148a2d363bbfd3bec0daa14ab6  pigsty-pkg-v4.0.0.u24.aarch64.tgz
87bb91ef703293b6ec5b77ae3bb33d54  pigsty-pkg-v4.0.0.u22.x86_64.tgz
5c81bdaa560dad4751840dec736fe404  pigsty-pkg-v4.0.0.u22.aarch64.tgz

Using Offline Packages

Offline installation steps:

  1. Download Pigsty offline package, place it at /tmp/pkg.tgz
  2. Download Pigsty source package, extract and enter directory (assume extracted to home: cd ~/pigsty)
  3. ./bootstrap, it will extract the package and configure using local repo (and install ansible from it offline)
  4. ./configure -g -c rich, you can directly use the rich template configured for offline installation, or configure yourself
  5. Run ./deploy.yml as usual—it will install everything from the local repo

If you want to use the already extracted and configured offline package in your own config, modify and ensure these settings:

  • repo_enabled: Set to true, will build local software repo (explicitly disabled in most templates)
  • node_repo_modules: Set to local, then all nodes in the env will install from the local software repo
    • In most templates, this is explicitly set to: node,infra,pgsql, i.e., install directly from these upstream repos.
    • Setting it to local will use the local software repo to install all packages, fastest, no interference from other repos.
    • If you want to use both local and upstream repos, you can add other repo module names too, e.g., local,node,infra,pgsql

The first parameter, if enabled, Pigsty will create a local software repo. The second parameter, if contains local, then all nodes in the env will use this local software repo. If it only contains local, then it becomes the sole repo for all nodes. If you still want to install other packages from other upstream repos, you can add other repo module names too, e.g., local,node,infra,pgsql.

Hybrid Installation Mode

If your env has Internet access, there’s a hybrid approach combining advantages of offline and online installation. You can use the offline package as a base, and supplement missing packages online.

For example, if you’re using RockyLinux 9.5 but the official offline package is for RockyLinux 9.6. You can use the el9 offline package (though made for 9.6), then execute make repo-build before formal installation to re-download missing packages for 9.5. Pigsty will download the required increments from upstream repos.


Making Offline Packages

If your OS isn’t in the default list, you can make your own offline package with the built-in cache.yml playbook:

  1. Find a node running the exact same OS version with Internet access
  2. Use rich config template to perform online installation (configure -c rich)
  3. cd ~/pigsty; ./cache.yml: make and fetch the offline package to ~/pigsty/dist/${version}/
  4. Copy the offline package to the env without Internet access (ftp, scp, usb, etc.), extract and use via bootstrap

We offer paid services providing tested, pre-made offline packages for specific Linux major.minor versions (¥200).


Bootstrap

Pigsty relies on ansible to execute playbooks; this script is responsible for ensuring ansible is correctly installed in various ways.

./bootstrap       # Ensure ansible is correctly installed (if offline package exists, use offline installation and extract first)

Usually, you need to run this script in two cases:

  • You didn’t install Pigsty via the installation script, but by downloading or git clone of the source package, so ansible isn’t installed.
  • You’re preparing to install Pigsty via offline packages and need to use this script to install ansible from the offline package.

The bootstrap script will automatically detect if the offline package exists (-p to specify, default is /tmp/pkg.tgz). If it exists, it will extract and use it, then install ansible from it. If the offline package doesn’t exist, it will try to install ansible from the Internet. If that still fails, you’re on your own!

4.7 - Slim Installation

Install only HA PostgreSQL clusters with minimal dependencies

If you only want HA PostgreSQL database cluster itself without monitoring, infra, etc., consider Slim Installation.

Slim installation has no INFRA module, no monitoring, no local repo—just ETCD and PGSQL and partial NODE functionality.


Overview

To use slim installation, you need to:

  1. Use the slim.yml slim install config template (configure -c slim)
  2. Run the slim.yml playbook instead of the default deploy.yml
curl https://repo.pigsty.io/get | bash
./configure -g -c slim
./slim.yml

Description

Slim installation only installs/configures these components:

ComponentRequiredDescription
patroni⚠️ RequiredBootstrap HA PostgreSQL cluster
etcd⚠️ RequiredMeta database dependency (DCS) for Patroni
pgbouncer✔️ OptionalPostgreSQL connection pooler
vip-manager✔️ OptionalL2 VIP binding to PostgreSQL cluster primary
haproxy✔️ OptionalAuto-routing services via Patroni health checks
chronyd✔️ OptionalTime synchronization with NTP server
tuned✔️ OptionalNode tuning template and kernel parameter management

You can disable all optional components via configuration, keeping only the required patroni and etcd.

Because there’s no INFRA module’s Nginx providing local repo service, offline installation only works in single-node mode.


Configuration

Slim installation config file example: conf/slim.yml:

IDNODEPGSQLINFRAETCD
110.10.10.10pg-meta-1No INFRA moduleetcd-1
---
#==============================================================#
# File      :   slim.yml
# Desc      :   Pigsty slim installation config template
# Ctime     :   2020-05-22
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for slim / minimal installation
# No monitoring & infra will be installed, just raw postgresql
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c slim
#   ./slim.yml

all:
  children:

    etcd: # dcs service for postgres/patroni ha consensus
      hosts: # 1 node for testing, 3 or 5 for production
        10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
        #10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
        #10.10.10.12: { etcd_seq: 3 }  # odd number please
      vars: # cluster level parameter override roles/etcd
        etcd_cluster: etcd  # mark etcd cluster name etcd

    #----------------------------------------------#
    # PostgreSQL Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        #10.10.10.11: { pg_seq: 2, pg_role: replica } # you can add more!
        #10.10.10.12: { pg_seq: 3, pg_role: replica, pg_offline_query: true }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        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' ] # make a full backup every 1am

  vars:
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_version: 18                      # Default PostgreSQL Major Version is 18
    pg_packages: [ pgsql-main, pgsql-common ]   # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Deployment

Slim installation uses the slim.yml playbook instead of deploy.yml:

./slim.yml

HA Cluster

Slim installation can also deploy HA clusters—just add more nodes to the etcd and pg-meta groups. A three-node deployment example:

IDNODEPGSQLINFRAETCD
110.10.10.10pg-meta-1No INFRA moduleetcd-1
210.10.10.11pg-meta-2No INFRA moduleetcd-2
310.10.10.12pg-meta-3No INFRA moduleetcd-3
all:
  children:
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
        10.10.10.11: { etcd_seq: 2 }  # <-- New
        10.10.10.12: { etcd_seq: 3 }  # <-- New

    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        10.10.10.11: { pg_seq: 2, pg_role: replica } # <-- New
        10.10.10.12: { pg_seq: 3, pg_role: replica } # <-- New
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        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' ] # make a full backup every 1am
  vars:
    # omitted ……

4.8 - Security Tips

Three security hardening tips for single-node quick-start deployment

For Demo/Dev single-node deployments, Pigsty’s default config is secure enough as long as you change default passwords.

If your deployment is exposed to Internet or office network, consider adding firewall rules to restrict port access and source IPs for enhanced security.

Additionally, we recommend protecting Pigsty’s critical files (config files and CA private key) from unauthorized access and backing them up regularly.

For enterprise prod envs with strict security requirements, refer to the Deployment - Security Hardening documentation for advanced configuration.


Passwords

Pigsty is an open-source project with well-known default passwords. If your deployment is exposed to Internet or office network, you must change all default passwords!

ModuleParameterDefault Value
INFRAgrafana_admin_passwordpigsty
INFRAgrafana_view_passwordDBUser.Viewer
PGSQLpg_admin_passwordDBUser.DBA
PGSQLpg_monitor_passwordDBUser.Monitor
PGSQLpg_replication_passwordDBUser.Replicator
PGSQLpatroni_passwordPatroni.API
NODEhaproxy_admin_passwordpigsty
MINIOminio_secret_keyS3User.MinIO
ETCDetcd_root_passwordEtcd.Root

To avoid manually modifying passwords, Pigsty’s configuration wizard provides automatic random strong password generation using the -g argument with configure.

$ ./configure -g
configure pigsty v4.0.0 begin
[ OK ] region = china
[WARN] kernel  = Darwin, can be used as admin node only
[ OK ] machine = arm64
[ OK ] package = brew (macOS)
[WARN] primary_ip = default placeholder 10.10.10.10 (macOS)
[ OK ] mode = meta (unknown distro)
[ OK ] locale  = C.UTF-8
[ OK ] generating random passwords...
    grafana_admin_password   : CdG0bDcfm3HFT9H2cvFuv9w7
    pg_admin_password        : 86WqSGdokjol7WAU9fUxY8IG
    pg_monitor_password      : 0X7PtgMmLxuCd2FveaaqBuX9
    pg_replication_password  : 4iAjjXgEY32hbRGVUMeFH460
    patroni_password         : DsD38QLTSq36xejzEbKwEqBK
    haproxy_admin_password   : uhdWhepXrQBrFeAhK9sCSUDo
    minio_secret_key         : z6zrYUN1SbdApQTmfRZlyWMT
    etcd_root_password       : Bmny8op1li1wKlzcaAmvPiWc
    DBUser.Meta              : U5v3CmeXICcMdhMNzP9JN3KY
    DBUser.Viewer            : 9cGQF1QMNCtV3KlDn44AEzpw
    S3User.Backup            : 2gjgSCFYNmDs5tOAiviCqM2X
    S3User.Meta              : XfqkAKY6lBtuDMJ2GZezA15T
    S3User.Data              : OygorcpCbV7DpDmqKe3G6UOj
[ OK ] random passwords generated, check and save them
[ OK ] ansible = ready
[ OK ] pigsty configured
[WARN] don't forget to check it and change passwords!
proceed with ./deploy.yml

Firewall

For deployments exposed to Internet or office networks, we strongly recommend configuring firewall rules to limit access IP ranges and ports.

You can use your cloud provider’s security group features, or Linux distribution firewall services (like firewalld, ufw, iptables, etc.) to implement this.

DirectionProtocolPortServiceDescription
InboundTCP22SSHAllow SSH login access
InboundTCP80NginxAllow Nginx HTTP access
InboundTCP443NginxAllow Nginx HTTPS access
InboundTCP5432PostgreSQLRemote database access, enable as needed

Pigsty supports configuring firewall rules to allow 22/80/443/5432 from external networks, but this is not enabled by default.


Files

In Pigsty, you need to protect the following files:

  • pigsty.yml: Pigsty main config file, contains access information and passwords for all nodes
  • files/pki/ca/ca.key: Pigsty self-signed CA private key, used to issue all SSL certificates in the deployment (auto-generated during deployment)

We recommend strictly controlling access permissions for these two files, regularly backing them up, and storing them in a secure location.

5 - Deployment

Multi-node, high-availability Pigsty deployment for serious production environments.

Unlike Getting Started, production Pigsty deployments require more Architecture Planning and Preparation.

This chapter helps you understand the complete deployment process and provides best practices for production environments.


Before deploying to production, we recommend testing in Pigsty’s Sandbox to fully understand the workflow. Use Vagrant to create a local 4-node sandbox, or leverage Terraform to provision larger simulation environments in the cloud.

pigsty-sandbox

For production, you typically need at least three nodes for high availability. You should understand Pigsty’s core Concepts and common administration procedures, including Configuration, Ansible Playbooks, and Security Hardening for enterprise compliance.

5.1 - Install Pigsty for Production

How to install Pigsty on Linux hosts for production?

This is the Pigsty production multi-node deployment guide. For single-node Demo/Dev setups, see Getting Started.


Summary

Prepare nodes with SSH access following your architecture plan, install a compatible Linux OS, then execute with an admin user having passwordless ssh and sudo:

curl -fsSL https://repo.pigsty.io/get | bash;         # International
curl -fsSL https://repo.pigsty.cc/get | bash;         # China Mirror

This runs the install script, downloading and extracting Pigsty source to your home directory with dependencies installed. Complete configuration and deployment to finish.

Before running deploy.yml for deployment, review and edit the configuration inventory: pigsty.yml.

cd ~/pigsty      # Enter Pigsty directory
./configure -g   # Generate config file (optional, skip if you know how to configure)
./deploy.yml     # Execute deployment playbook based on generated config

After installation, access the WebUI via IP/domain + ports 80/443, and PostgreSQL service via port 5432.

Full installation takes 3-10 minutes depending on specs/network. Offline installation significantly speeds this up; slim installation further accelerates when monitoring isn’t needed.

Video Example: 20-node Production Simulation (Ubuntu 24.04 x86_64)


Prepare

Production Pigsty deployment involves preparation work. Here’s the complete checklist:

ItemRequirementItemRequirement
NodeAt least 1C2G, no upper limitPlanMultiple homogeneous nodes: 2/3/4 or more
Disk/data as default mount pointFSxfs recommended; ext4/zfs as needed
VIPL2 VIP, optional (unavailable in cloud)NetworkStatic IPv4, single-node can use 127.0.0.1
CASelf-signed CA or specify existing certsDomainLocal/public domain, optional, default h.pigsty
KernelLinux x86_64 / aarch64Linuxel8, el9, el10, d12, d13, u22, u24
LocaleC.UTF-8 or CFirewallPorts: 80/443/22/5432 (optional)
UserAvoid root and postgresSudosudo privilege, preferably with nopass
SSHPasswordless SSH via public keyAccessiblessh <ip|alias> sudo ls no error

Install

Use the following to automatically install the Pigsty source package to ~/pigsty (recommended). Deployment dependencies (Ansible) are auto-installed.

curl -fsSL https://repo.pigsty.io/get | bash            # Install latest stable version
curl -fsSL https://repo.pigsty.cc/get | bash            # China mirror
curl -fsSL https://repo.pigsty.io/get | bash -s v4.0.0  # Install specific version

If you prefer not to run remote scripts, manually download or clone the source. When using git, always checkout a specific version before use:

git clone https://github.com/pgsty/pigsty; cd pigsty;
git checkout v4.0.0-b4;  # Always checkout a specific version when using git

For manual download/clone, additionally run bootstrap to manually install Ansible and other dependencies, or install them yourself:

./bootstrap           # Install ansible for subsequent deployment

Configure

In Pigsty, deployment details are defined by the configuration inventory—the pigsty.yml config file. Customize through declarative configuration.

Pigsty provides configure as an optional configuration wizard, generating a configuration inventory with good defaults based on your environment:

./configure -g                # Use wizard to generate config with random passwords

The generated config defaults to ~/pigsty/pigsty.yml. Review and customize before installation.

Many configuration templates are available for reference. You can skip the wizard and directly edit pigsty.yml:

./configure -c ha/full -g       # Use 4-node sandbox template
./configure -c ha/trio -g       # Use 3-node minimal HA template
./configure -c ha/dual -g -v 17 # Use 2-node semi-HA template with PG 17
./configure -c ha/simu -s       # Use 20-node production simulation, skip IP check, no random passwords
Example configure output
vagrant@meta:~/pigsty$ ./configure
configure pigsty v4.0.0 begin
[ OK ] region = china
[ OK ] kernel  = Linux
[ OK ] machine = x86_64
[ OK ] package = deb,apt
[ OK ] vendor  = ubuntu (Ubuntu)
[ OK ] version = 22 (22.04)
[ OK ] sudo = vagrant ok
[ OK ] ssh = [email protected] ok
[WARN] Multiple IP address candidates found:
    (1) 192.168.121.38	    inet 192.168.121.38/24 metric 100 brd 192.168.121.255 scope global dynamic eth0
    (2) 10.10.10.10	    inet 10.10.10.10/24 brd 10.10.10.255 scope global eth1
[ OK ] primary_ip = 10.10.10.10 (from demo)
[ OK ] admin = [email protected] ok
[ OK ] mode = meta (ubuntu22.04)
[ OK ] locale  = C.UTF-8
[ OK ] ansible = ready
[ OK ] pigsty configured
[WARN] don't forget to check it and change passwords!
proceed with ./deploy.yml

The wizard only replaces the current node’s IP (use -s to skip replacement). For multi-node deployments, replace other node IPs manually. Also customize the config as needed—modify default passwords, add nodes, etc.

Common configure parameters:

ParameterDescription
-c|--confSpecify config template relative to conf/, without .yml suffix
-v|--versionPostgreSQL major version: 13, 14, 15, 16, 17, 18
-r|--regionUpstream repo region for faster downloads: default|china|europe
-n|--non-interactiveUse CLI params for primary IP, skip interactive wizard
-x|--proxyConfigure proxy_env from current environment variables

If your machine has multiple IPs, explicitly specify one with -i|--ip <ipaddr> or provide it interactively. The script replaces IP placeholder 10.10.10.10 with the current node’s primary IPv4. Use a static IP; never use public IPs.

Generated config is at ~/pigsty/pigsty.yml. Review and modify before installation.


Deploy

Pigsty’s deploy.yml playbook applies the configuration blueprint to all target nodes.

./deploy.yml     # Deploy everything on all nodes at once
Example deployment output
......

TASK [pgsql : pgsql init done] *************************************************
ok: [10.10.10.11] => {
    "msg": "postgres://10.10.10.11/postgres | meta  | dbuser_meta dbuser_view "
}
......

TASK [pg_monitor : load grafana datasource meta] *******************************
changed: [10.10.10.11]

PLAY RECAP *********************************************************************
10.10.10.11                : ok=302  changed=232  unreachable=0    failed=0    skipped=65   rescued=0    ignored=1
localhost                  : ok=6    changed=3    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

When output ends with pgsql init done, PLAY RECAP, etc., installation is complete!



Interface

Assuming the 4-node deployment template, your Pigsty environment should have a structure like:

IDNODEPGSQLINFRAETCD
110.10.10.10pg-meta-1infra-1etcd-1
210.10.10.11pg-test-1--
310.10.10.12pg-test-2--
410.10.10.13pg-test-3--

The INFRA module provides a graphical management interface via browser, accessible through Nginx’s 80/443 ports.

The PGSQL module provides a PostgreSQL database server on port 5432, also accessible via Pgbouncer/HAProxy proxies.

For production multi-node HA PostgreSQL clusters, use service access for automatic traffic routing.


More

After installation, explore the WebUI and access PostgreSQL service via port 5432.

Deploy and monitor more clusters—add definitions to the configuration inventory and run:

bin/node-add   pg-test      # Add pg-test cluster's 3 nodes to Pigsty management
bin/pgsql-add  pg-test      # Initialize a 3-node pg-test HA PG cluster
bin/redis-add  redis-ms     # Initialize Redis cluster: redis-ms

Most modules require the NODE module first. See available modules:

PGSQL, INFRA, NODE, ETCD, MINIO, REDIS, FERRET, DOCKER

5.2 - Prepare Resources for Serious Deployment

Production deployment preparation including hardware, nodes, disks, network, VIP, domain, software, and filesystem requirements.

Pigsty runs on nodes (physical machines or VMs). This document covers the planning and preparation required for deployment.


Node

Pigsty currently runs on Linux kernel with x86_64 / aarch64 architecture. A “node” refers to an SSH accessible resource that provides a bare Linux OS environment. It can be a physical machine, virtual machine, or a systemd-enabled container equipped with systemd, sudo, and sshd.

Deploying Pigsty requires at least 1 node. You can prepare more and deploy everything in one pass via playbooks, or add nodes later. The minimum spec requirement is 1C1G, but at least 1C2G is recommended. Higher is better—no upper limit. Parameters are auto-tuned based on available resources.

The number of nodes you need depends on your requirements. See Architecture Planning for details. Although a single-node deployment with external backup provides reasonable recovery guarantees, we recommend multiple nodes for production. A functioning HA setup requires at least 3 nodes; 2 nodes provide Semi-HA.


Disk

Pigsty uses /data as the default data directory. If you have a dedicated data disk, mount it there. Use /data1, /data2, /dataN for additional disk drives.

To use a different data directory, configure these parameters:

NameDescriptionDefault
node_dataNode main data directory/data
pg_fs_mainPG main data directory/data/postgres
pg_fs_backupPG backup directory/data/backups
etcd_dataETCD data directory/data/etcd
infra_dataInfra data directory/data/infra
nginx_dataNginx data directory/data/nginx
minio_dataMinIO data directory/data/minio
redis_fs_mainRedis data directory/data/redis

Filesystem

You can use any supported Linux filesystem for data disks. For production, we recommend xfs.

xfs is a Linux standard with excellent performance and CoW capabilities for instant large database cluster cloning. MinIO requires xfs. ext4 is another viable option with a richer data recovery tool ecosystem, but lacks CoW. zfs provides RAID and snapshot features but with significant performance overhead and requires separate installation.

Choose among these three based on your needs. Avoid NFS for database services.

Pigsty assumes /data is owned by root:root with 755 permissions. Admins can assign ownership for first-level directories; each application runs with a dedicated user in its subdirectory. See FHS for the directory structure reference.


Network

Pigsty defaults to online installation mode, requiring outbound Internet access. Offline installation eliminates the Internet requirement.

Internally, Pigsty requires a static network. Assign a fixed IPv4 address to each node.

The IP address serves as the node’s unique identifier—the primary IP bound to the main network interface for internal communications.

For single-node deployment without a fixed IP, use the loopback address 127.0.0.1 as a workaround.


VIP

Pigsty supports optional L2 VIP for NODE clusters (keepalived) and PGSQL clusters (vip-manager).

To use L2 VIP, you must explicitly assign an L2 VIP address for each node/database cluster. This is straightforward on your own hardware but may be challenging in public cloud environments.


CA

Pigsty generates a self-signed CA infrastructure for each deployment, issuing all encryption certificates.

If you have an existing enterprise CA or self-signed CA, you can use it to issue the certificates Pigsty requires.


Domain

Pigsty uses a local static domain i.pigsty by default for WebUI access. This is optional—IP addresses work too.

For production, domain names are recommended to enable HTTPS and encrypted data transmission. Domains also allow multiple services on the same port, differentiated by domain name.

For Internet-facing deployments, use public DNS providers (Cloudflare, AWS Route53, etc.) to manage resolution. Point your domain to the Pigsty node’s public IP address. For LAN/office network deployments, use internal DNS servers with the node’s internal IP address.

For local-only access, add the following to /etc/hosts on machines accessing the Pigsty WebUI:

10.10.10.10 i.pigsty    # Replace with your domain and Pigsty node IP

Linux

Pigsty runs on Linux. It supports 14 mainstream distributions: Compatible OS List

We recommend RockyLinux 10.0, Debian 13.2, or Ubuntu 24.04.2 as default options.

On macOS and Windows, use VM software or Docker systemd images to run Pigsty.

We strongly recommend a fresh OS installation. If your server already runs Nginx, PostgreSQL, or similar services, consider deploying on new nodes.


Locale

We recommend setting en_US as the primary OS language, or at minimum ensuring this locale is available, so PostgreSQL logs are in English.

Some distributions (e.g., Debian) may not provide the en_US locale by default. Enable it with:

localedef -i en_US -f UTF-8 en_US.UTF-8
localectl set-locale LANG=en_US.UTF-8

For PostgreSQL, we strongly recommend using the built-in C.UTF-8 collation (PG 17+) as the default.

The configuration wizard automatically sets C.UTF-8 as the collation when PG version and OS support are detected.


Ansible

Pigsty uses Ansible to control all managed nodes from the admin node. See Installing Ansible for details.

Pigsty installs Ansible on Infra nodes by default, making them usable as admin nodes (or backup admin nodes). For single-node deployment, the installation node serves as both the admin node running Ansible and the INFRA node hosting infrastructure.


Pigsty

You can install the latest stable Pigsty source with:

curl -fsSL https://repo.pigsty.io/get | bash;         # International
curl -fsSL https://repo.pigsty.cc/get | bash;         # China Mirror

To install a specific version, use the -s <version> parameter:

curl -fsSL https://repo.pigsty.io/get | bash -s v4.0.0
curl -fsSL https://repo.pigsty.cc/get | bash -s v4.0.0

To install the latest beta version:

curl -fsSL https://repo.pigsty.io/beta | bash;
curl -fsSL https://repo.pigsty.cc/beta | bash;

For developers or the latest development version, clone the repository directly:

git clone https://github.com/pgsty/pigsty.git;
cd pigsty; git checkout v4.0.0

If your environment lacks Internet access, download the source tarball from GitHub Releases or the Pigsty repository:

wget https://repo.pigsty.io/src/pigsty-v4.0.0.tgz
wget https://repo.pigsty.cc/src/pigsty-v4.0.0.tgz

5.3 - Planning Architecture and Nodes

How many nodes? Which modules need HA? How to plan based on available resources and requirements?

Pigsty uses a modular architecture. You can combine modules like building blocks and express your intent through declarative configuration.

Common Patterns

Here are common deployment patterns for reference. Customize based on your requirements:

PatternINFRAETCDPGSQLMINIODescription
Single-node (meta)111Single-node deployment default
Slim deploy (slim)11Database only, no monitoring infra
Infra-only (infra)1Monitoring infrastructure only
Rich deploy (rich)1111Single-node + object storage + local repo with all extensions
Multi-node PatternINFRAETCDPGSQLMINIODescription
Two-node (dual)112Semi-HA, tolerates specific node failure
Three-node (trio)333Standard HA, tolerates any one failure
Four-node (full)111+3Demo setup, single INFRA/ETCD
Production (simu)23nn2 INFRA, 3 ETCD
Large-scale (custom)35nn3 INFRA, 5 ETCD

Your architecture choice depends on reliability requirements and available resources. Serious production deployments require at least 3 nodes for HA configuration. With only 2 nodes, use Semi-HA configuration.


Trade-offs

  • Pigsty monitoring requires at least 1 INFRA node. Production typically uses 2; large-scale deployments use 3.
  • PostgreSQL HA requires at least 1 ETCD node. Production typically uses 3; large-scale uses 5. Must be odd numbers.
  • Object storage (MinIO) requires at least 1 MINIO node. Production typically uses 4+ nodes in MNMD clusters.
  • Production PG clusters typically use at least two-node primary-replica configuration; serious deployments use 3 nodes; high read loads can have dozens of replicas.
  • For PostgreSQL, you can also use advanced configurations: offline instances, sync instances, standby clusters, delayed clusters, etc.

Single-Node Setup

The simplest configuration with everything on a single node. Installs four essential modules by default. Typically used for demos, devbox, or testing.

IDNODEPGSQLINFRAETCD
1node-1pg-meta-1infra-1etcd-1

With an external S3/MinIO backup repository providing RTO/RPO guarantees, this configuration works for standard production environments.

Single-node variants:


Two-Node Setup

Two-node configuration enables database replication and Semi-HA capability with better data redundancy and limited failover support:

IDNODEPGSQLINFRAETCD
1node-1pg-meta-1 (replica)infra-1etcd-1
2node-2pg-meta-2 (primary)

Two-node HA auto-failover has limitations. This “Semi-HA” setup only auto-recovers from specific node failures:

  • If node-1 fails: No automatic failover—requires manual promotion of node-2
  • If node-2 fails: Automatic failover works—node-1 auto-promoted

Three-Node Setup

Three-node template provides true baseline HA configuration, tolerating any single node failure with automatic recovery.

IDNODEPGSQLINFRAETCD
1node-1pg-meta-1infra-1etcd-1
2node-2pg-meta-2infra-2etcd-2
3node-3pg-meta-3infra-3etcd-3

Four-Node Setup

Pigsty Sandbox uses the standard four-node configuration.

IDNODEPGSQLINFRAETCD
1node-1pg-meta-1infra-1etcd-1
2node-2pg-test-1
3node-3pg-test-2
4node-4pg-test-3

For demo purposes, INFRA / ETCD modules aren’t configured for HA. You can adjust further:

IDNODEPGSQLINFRAETCDMINIO
1node-1pg-meta-1infra-1etcd-1minio-1
2node-2pg-test-1infra-2etcd-2
3node-3pg-test-2etcd-3
4node-4pg-test-3

More Nodes

With proper virtualization infrastructure or abundant resources, you can use more nodes for dedicated deployment of each module, achieving optimal reliability, observability, and performance.

IDNODEINFRAETCDMINIOPGSQL
110.10.10.10infra-1pg-meta-1
210.10.10.11infra-2pg-meta-2
310.10.10.21etcd-1
410.10.10.22etcd-2
510.10.10.23etcd-3
610.10.10.31minio-1
710.10.10.32minio-2
810.10.10.33minio-3
910.10.10.34minio-4
1010.10.10.40pg-src-1
1110.10.10.41pg-src-2
1210.10.10.42pg-src-3
1310.10.10.50pg-test-1
1410.10.10.51pg-test-2
1510.10.10.52pg-test-3
16……

5.4 - Setup Admin User and Privileges

Admin user, sudo, SSH, accessibility verification, and firewall configuration

Pigsty requires an OS admin user with passwordless SSH and Sudo privileges on all managed nodes.

This user must be able to SSH to all managed nodes and execute sudo commands on them.


User

Typically use names like dba or admin, avoiding root and postgres:

  • Using root for deployment is possible but not a production best practice.
  • Using postgres (pg_dbsu) as admin user is strictly prohibited.

Passwordless

The passwordless requirement is optional if you can accept entering a password for every ssh and sudo command.

Use -k|--ask-pass when running playbooks to prompt for SSH password, and -K|--ask-become-pass to prompt for sudo password.

./deploy.yml -k -K

Some enterprise security policies may prohibit passwordless ssh or sudo. In such cases, use the options above, or consider configuring a sudoers rule with a longer password cache time to reduce password prompts.


Create Admin User

Typically, your server/VM provider creates an initial admin user.

If unsatisfied with that user, Pigsty’s deployment playbook can create a new admin user for you.

Assuming you have root access or an existing admin user on the node, create an admin user with Pigsty itself:

./node.yml -k -K -t node_admin -e ansible_user=[your_existing_admin]

This leverages the existing admin to create a new one—a dedicated dba (uid=88) user described by these parameters, with sudo/ssh properly configured:

NameDescriptionDefault
node_admin_enabledEnable node admin usertrue
node_admin_uidNode admin user UID88
node_admin_usernameNode admin usernamedba

Sudo

All admin users should have sudo privileges on all managed nodes, preferably with passwordless execution.

To configure an admin user with passwordless sudo from scratch, edit/create a sudoers file (assuming username vagrant):

echo '%vagrant ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/vagrant

For admin user dba, the /etc/sudoers.d/dba content should be:

%dba ALL=(ALL) NOPASSWD: ALL

If your security policy prohibits passwordless sudo, remove the NOPASSWD: part:

%dba ALL=(ALL) ALL

Ansible relies on sudo to execute commands with root privileges on managed nodes. In environments where sudo is unavailable (e.g., inside Docker containers), install sudo first.


SSH

Your current user should have passwordless SSH access to all managed nodes as the corresponding admin user.

Your current user can be the admin user itself, but this isn’t required—as long as you can SSH as the admin user.

SSH configuration is Linux 101, but here are the basics:

Generate SSH Key

If you don’t have an SSH key pair, generate one:

ssh-keygen -t rsa -b 2048 -N '' -f ~/.ssh/id_rsa -q

Pigsty will do this for you during the bootstrap stage if you lack a key pair.

Copy SSH Key

Distribute your generated public key to remote (and local) servers, placing it in the admin user’s ~/.ssh/authorized_keys file on all nodes. Use the ssh-copy-id utility:

ssh-copy-id <ip>                        # Interactive password entry
sshpass -p <password> ssh-copy-id <ip>  # Non-interactive (use with caution)

Using Alias

When direct SSH access is unavailable (jumpserver, non-standard port, different credentials), configure SSH aliases in ~/.ssh/config:

Host meta
    HostName 10.10.10.10
    User dba                      # Different user on remote
    IdentityFile /etc/dba/id_rsa  # Non-standard key
    Port 24                       # Non-standard port

Reference the alias in the inventory using ansible_host for the real SSH alias:

nodes:
  hosts:          # If node `10.10.10.10` requires SSH alias `meta`
    10.10.10.10: { ansible_host: meta }  # Access via `ssh meta`

SSH parameters work directly in Ansible. See Ansible Inventory Guide for details. This technique enables accessing nodes in private networks via jumpservers, or using different ports and credentials, or using your local laptop as an admin node.


Check Accessibility

You should be able to passwordlessly ssh from the admin node to all managed nodes as your current user. The remote user (admin user) should have privileges to run passwordless sudo commands.

To verify passwordless ssh/sudo works, run this command on the admin node for all managed nodes:

ssh <ip|alias> 'sudo ls'

If there’s no password prompt or error, passwordless ssh/sudo is working as expected.


Firewall

Production deployments typically require firewall configuration to block unauthorized port access.

By default, block inbound access from office/Internet networks except:

  • SSH port 22 for node access
  • HTTP (80) / HTTPS (443) for WebUI services
  • PostgreSQL port 5432 for database access

If accessing PostgreSQL via other ports, allow them accordingly. See used ports for the complete port list.

  • 5432: PostgreSQL database
  • 6432: Pgbouncer connection pooler
  • 5433: PG primary service
  • 5434: PG replica service
  • 5436: PG default service
  • 5438: PG offline service

5.5 - Sandbox

4-node sandbox environment for learning, testing, and demonstration

Pigsty provides a standard 4-node sandbox environment for learning, testing, and feature demonstration.

The sandbox uses fixed IP addresses and predefined identity identifiers, making it easy to reproduce various demo use cases.


Description

The default sandbox environment consists of 4 nodes, using the ha/full.yml configuration template.

IDIP AddressNodePostgreSQLINFRAETCDMINIO
110.10.10.10metapg-meta-1infra-1etcd-1minio-1
210.10.10.11node-1pg-test-1
310.10.10.12node-2pg-test-2
410.10.10.13node-3pg-test-3

The sandbox configuration can be summarized as the following config:

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq:  1 } }, vars: { etcd_cluster: etcd } }
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    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:
    version: v4.0.0
    admin_ip: 10.10.10.10
    region: default
    pg_version: 18

pigsty-sandbox

PostgreSQL Clusters

The sandbox comes with a single-instance PostgreSQL cluster pg-meta on the meta node:

10.10.10.10 meta pg-meta-1
10.10.10.2  pg-meta          # Optional L2 VIP

There’s also a 3-instance PostgreSQL HA cluster pg-test deployed on the other three nodes:

10.10.10.11 node-1 pg-test-1
10.10.10.12 node-2 pg-test-2
10.10.10.13 node-3 pg-test-3
10.10.10.3  pg-test          # Optional L2 VIP

Two optional L2 VIPs are bound to the primary instances of pg-meta and pg-test clusters respectively.

Infrastructure

The meta node also hosts:

  • ETCD cluster: Single-node etcd cluster providing DCS service for PostgreSQL HA
  • MinIO cluster: Single-node minio cluster providing S3-compatible object storage
10.10.10.10 etcd-1
10.10.10.10 minio-1

Creating Sandbox

Pigsty provides out-of-the-box templates. You can use Vagrant to create a local sandbox, or use Terraform to create a cloud sandbox.

Local Sandbox (Vagrant)

Local sandbox uses VirtualBox/libvirt to create local virtual machines, running free on your Mac / PC.

To run the full 4-node sandbox, your machine should have at least 4 CPU cores and 8GB memory.

cd ~/pigsty
make full       # Create 4-node sandbox with default RockyLinux 9 image
make full9      # Create 4-node sandbox with RockyLinux 9
make full12     # Create 4-node sandbox with Debian 12
make full24     # Create 4-node sandbox with Ubuntu 24.04

For more details, please refer to Vagrant documentation.

Cloud Sandbox (Terraform)

Cloud sandbox uses public cloud API to create virtual machines. Easy to create and destroy, pay-as-you-go, ideal for quick testing.

Use spec/aliyun-full.tf template to create a 4-node sandbox on Alibaba Cloud:

cd ~/pigsty/terraform
cp spec/aliyun-full.tf terraform.tf
terraform init
terraform apply

For more details, please refer to Terraform documentation.


Other Specs

Besides the standard 4-node sandbox, Pigsty also provides other environment specs:

Single Node Devbox (meta)

The simplest 1-node environment for quick start, development, and testing:

make meta       # Create single-node devbox

Two Node Environment (dual)

2-node environment for testing primary-replica replication:

make dual       # Create 2-node environment

Three Node Environment (trio)

3-node environment for testing basic high availability:

make trio       # Create 3-node environment

Production Simulation (simu)

20-node large simulation environment for full production environment testing:

make simu       # Create 20-node production simulation environment

This environment includes:

  • 3 infrastructure nodes (meta1, meta2, meta3)
  • 2 HAProxy proxy nodes
  • 4 MinIO nodes
  • 5 ETCD nodes
  • 6 PostgreSQL nodes (2 clusters, 3 nodes each)

5.6 - Vagrant

Create local virtual machine environment with Vagrant

Vagrant is a popular local virtualization tool that creates local virtual machines in a declarative manner.

Pigsty requires a Linux environment to run. You can use Vagrant to easily create Linux virtual machines locally for testing.


Quick Start

Install Dependencies

First, ensure you have Vagrant and a virtual machine provider (such as VirtualBox or libvirt) installed on your system.

On macOS, you can use Homebrew for one-click installation:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install vagrant virtualbox ansible

On Linux, you can use VirtualBox or vagrant-libvirt as the VM provider.

Create Virtual Machines

Use the Pigsty-provided make shortcuts to create virtual machines:

cd ~/pigsty

make meta       # 1 node devbox for quick start, development, and testing
make full       # 4 node sandbox for HA testing and feature demonstration
make simu       # 20 node simubox for production environment simulation

# Other less common specs
make dual       # 2 node environment
make trio       # 3 node environment
make deci       # 10 node environment

You can use variant aliases to specify different operating system images:

make meta9      # Create single node with RockyLinux 9
make full12     # Create 4-node sandbox with Debian 12
make simu24     # Create 20-node simubox with Ubuntu 24.04

Available OS suffixes: 7 (EL7), 8 (EL8), 9 (EL9), 10 (EL10), 11 (Debian 11), 12 (Debian 12), 13 (Debian 13), 20 (Ubuntu 20.04), 22 (Ubuntu 22.04), 24 (Ubuntu 24.04)

Build Environment

You can also use the following aliases to create Pigsty build environments. These templates won’t replace the base image:

make oss        # 3 node OSS build environment
make pro        # 5 node PRO build environment
make rpm        # 3 node EL7/8/9 build environment
make deb        # 5 node Debian11/12 Ubuntu20/22/24 build environment
make all        # 7 node full build environment

Spec Templates

Pigsty provides multiple predefined VM specs in the vagrant/spec/ directory:

TemplateNodesSpecDescriptionAlias
meta.rb1 node2c4g x 1Single-node devboxDevbox
dual.rb2 nodes1c2g x 2Two-node environment
trio.rb3 nodes1c2g x 3Three-node environment
full.rb4 nodes2c4g + 1c2g x 34-node full sandboxSandbox
deci.rb10 nodesMixed10-node environment
simu.rb20 nodesMixed20-node production simuboxSimubox
minio.rb4 nodes1c2g x 4 + diskMinIO test environment
oss.rb3 nodes1c2g x 33-node OSS build environment
pro.rb5 nodes1c2g x 55-node PRO build environment
rpm.rb3 nodes1c2g x 33-node EL build environment
deb.rb5 nodes1c2g x 55-node Deb build environment
all.rb7 nodes1c2g x 77-node full build environment

Each spec file contains a Specs variable describing the VM nodes. For example, full.rb contains the 4-node sandbox definition:

# full: pigsty full-featured 4-node sandbox for HA-testing & tutorial & practices

Specs = [
  { "name" => "meta"   , "ip" => "10.10.10.10" ,  "cpu" => "2" ,  "mem" => "4096" ,  "image" => "bento/rockylinux-9" },
  { "name" => "node-1" , "ip" => "10.10.10.11" ,  "cpu" => "1" ,  "mem" => "2048" ,  "image" => "bento/rockylinux-9" },
  { "name" => "node-2" , "ip" => "10.10.10.12" ,  "cpu" => "1" ,  "mem" => "2048" ,  "image" => "bento/rockylinux-9" },
  { "name" => "node-3" , "ip" => "10.10.10.13" ,  "cpu" => "1" ,  "mem" => "2048" ,  "image" => "bento/rockylinux-9" },
]

simu Spec Details

simu.rb provides a 20-node production environment simulation configuration:

  • 3 x infra nodes (meta1-3): 4c16g
  • 2 x haproxy nodes (proxy1-2): 1c2g
  • 4 x minio nodes (minio1-4): 1c2g
  • 5 x etcd nodes (etcd1-5): 1c2g
  • 6 x pgsql nodes (pg-src-1-3, pg-dst-1-3): 2c4g

Config Script

Use the vagrant/config script to generate the final Vagrantfile based on spec and options:

cd ~/pigsty
vagrant/config [spec] [image] [scale] [provider]

# Examples
vagrant/config meta                # Use 1-node spec with default EL9 image
vagrant/config dual el9            # Use 2-node spec with EL9 image
vagrant/config trio d12 2          # Use 3-node spec with Debian 12, double resources
vagrant/config full u22 4          # Use 4-node spec with Ubuntu 22, 4x resources
vagrant/config simu u24 1 libvirt  # Use 20-node spec with Ubuntu 24, libvirt provider

Image Aliases

The config script supports various image aliases:

DistroAliasVagrant Box
CentOS 7el7, 7, centosgeneric/centos7
Rocky 8el8, 8, rocky8bento/rockylinux-9
Rocky 9el9, 9, rocky9, elbento/rockylinux-9
Rocky 10el10, rocky10rockylinux/10
Debian 11d11, 11, debian11generic/debian11
Debian 12d12, 12, debian12generic/debian12
Debian 13d13, 13, debian13cloud-image/debian-13
Ubuntu 20.04u20, 20, ubuntu20generic/ubuntu2004
Ubuntu 22.04u22, 22, ubuntu22, ubuntugeneric/ubuntu2204
Ubuntu 24.04u24, 24, ubuntu24bento/ubuntu-24.04

Resource Scaling

You can use the VM_SCALE environment variable to adjust the resource multiplier (default is 1):

VM_SCALE=2 vagrant/config meta     # Double the CPU/memory resources for meta spec

For example, using VM_SCALE=4 with the meta spec will adjust the default 2c4g to 8c16g:

Specs = [
  { "name" => "meta" , "ip" => "10.10.10.10", "cpu" => "8" , "mem" => "16384" , "image" => "bento/rockylinux-9" },
]

VM Management

Pigsty provides a set of Makefile shortcuts for managing virtual machines:

make           # Equivalent to make start
make new       # Destroy existing VMs and create new ones
make ssh       # Write VM SSH config to ~/.ssh/ (must run after creation)
make dns       # Write VM DNS records to /etc/hosts (optional)
make start     # Start VMs and configure SSH (up + ssh)
make up        # Start VMs with vagrant up
make halt      # Shutdown VMs (alias: down, dw)
make clean     # Destroy VMs (alias: del, destroy)
make status    # Show VM status (alias: st)
make pause     # Pause VMs (alias: suspend)
make resume    # Resume VMs
make nuke      # Destroy all VMs and volumes with virsh (libvirt only)
make info      # Show libvirt info (VMs, networks, storage volumes)

SSH Keys

Pigsty Vagrant templates use your ~/.ssh/id_rsa[.pub] as the SSH key for VMs by default.

Before starting, ensure you have a valid SSH key pair. If not, generate one with:

ssh-keygen -t rsa -b 2048 -N '' -f ~/.ssh/id_rsa -q

Supported Images

Pigsty currently uses the following Vagrant Boxes for testing:

# x86_64 / amd64
el8 :  bento/rockylinux-8     (libvirt, 202502.21.0, (amd64))
el9 :  bento/rockylinux-9     (libvirt, 202502.21.0, (amd64))
el10:  rockylinux/10          (libvirt)

d11 :  generic/debian11       (libvirt, 4.3.12, (amd64))
d12 :  generic/debian12       (libvirt, 4.3.12, (amd64))
d13 :  cloud-image/debian-13  (libvirt)

u20 :  generic/ubuntu2004     (libvirt, 4.3.12, (amd64))
u22 :  generic/ubuntu2204     (libvirt, 4.3.12, (amd64))
u24 :  bento/ubuntu-24.04     (libvirt, 20250316.0.0, (amd64))

For Apple Silicon (aarch64) architecture, fewer images are available:

# aarch64 / arm64
bento/rockylinux-9 (virtualbox, 202502.21.0, (arm64))
bento/ubuntu-24.04 (virtualbox, 202502.21.0, (arm64))

You can find more available Box images on Vagrant Cloud.


Environment Variables

You can use the following environment variables to control Vagrant behavior:

export VM_SPEC='meta'              # Spec name
export VM_IMAGE='bento/rockylinux-9'  # Image name
export VM_SCALE='1'                # Resource scaling multiplier
export VM_PROVIDER='virtualbox'    # Virtualization provider
export VAGRANT_EXPERIMENTAL=disks  # Enable experimental disk features

Notes

5.7 - Terraform

Create virtual machine environment on public cloud with Terraform

Terraform is a popular “Infrastructure as Code” tool that you can use to create virtual machines on public clouds with one click.

Pigsty provides Terraform templates for Alibaba Cloud, AWS, and Tencent Cloud as examples.


Quick Start

Install Terraform

On macOS, you can use Homebrew to install Terraform:

brew install terraform

For other platforms, refer to the Terraform Official Installation Guide.

Initialize and Apply

Enter the Terraform directory, select a template, initialize provider plugins, and apply the configuration:

cd ~/pigsty/terraform
cp spec/aliyun-meta.tf terraform.tf   # Select template
terraform init                         # Install cloud provider plugins (first use)
terraform apply                        # Generate execution plan and create resources

After running the apply command, type yes to confirm when prompted. Terraform will create VMs and related cloud resources for you.

Get IP Address

After creation, print the public IP address of the admin node:

terraform output | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'

Configure SSH Access

Use the ssh script to automatically configure SSH aliases and distribute keys:

./ssh    # Write SSH config to ~/.ssh/pigsty_config and copy keys

This script writes the IP addresses from Terraform output to ~/.ssh/pigsty_config and automatically distributes SSH keys using the default password PigstyDemo4.

After configuration, you can login directly using hostnames:

ssh meta    # Login using hostname instead of IP

Destroy Resources

After testing, you can destroy all created cloud resources with one click:

terraform destroy

Template Specs

Pigsty provides multiple predefined cloud resource templates in the terraform/spec/ directory:

Template FileCloud ProviderDescription
aliyun-meta.tfAlibaba CloudSingle-node meta template, supports all distros and AMD/ARM (default)
aliyun-meta-s3.tfAlibaba CloudSingle-node template + OSS bucket for PITR backup
aliyun-full.tfAlibaba Cloud4-node sandbox template, supports all distros and AMD/ARM
aliyun-oss.tfAlibaba Cloud5-node build template, supports all distros and AMD/ARM
aliyun-pro.tfAlibaba CloudMulti-distro test template for cross-OS testing
aws-cn.tfAWSAWS China region 4-node environment
tencentcloud.tfTencent CloudTencent Cloud 4-node environment

When using a template, copy the template file to terraform.tf:

cd ~/pigsty/terraform
cp spec/aliyun-full.tf terraform.tf   # Use Alibaba Cloud 4-node sandbox template
terraform init && terraform apply

Variable Configuration

Pigsty’s Terraform templates use variables to control architecture, OS distribution, and resource configuration:

Architecture and Distribution

variable "architecture" {
  description = "Architecture type (amd64 or arm64)"
  type        = string
  default     = "amd64"    # Comment this line to use arm64
  #default     = "arm64"   # Uncomment to use arm64
}

variable "distro" {
  description = "Distribution code (el8,el9,el10,u22,u24,d12,d13)"
  type        = string
  default     = "el9"       # Default uses Rocky Linux 9
}

Resource Configuration

The following resource parameters can be configured in the locals block:

locals {
  bandwidth        = 100                    # Public bandwidth (Mbps)
  disk_size        = 40                     # System disk size (GB)
  spot_policy      = "SpotWithPriceLimit"   # Spot policy: NoSpot, SpotWithPriceLimit, SpotAsPriceGo
  spot_price_limit = 5                      # Max spot price (only effective with SpotWithPriceLimit)
}

Alibaba Cloud Configuration

Credential Setup

Add your Alibaba Cloud credentials to environment variables, for example in ~/.bash_profile or ~/.zshrc:

export ALICLOUD_ACCESS_KEY="<your_access_key>"
export ALICLOUD_SECRET_KEY="<your_secret_key>"
export ALICLOUD_REGION="cn-shanghai"

Supported Images

The following are commonly used ECS Public OS Image prefixes in Alibaba Cloud:

DistroCodex86_64 Image Prefixaarch64 Image Prefix
CentOS 7.9el7centos_7_9_x64-
Rocky 8.10el8rockylinux_8_10_x64rockylinux_8_10_arm64
Rocky 9.6el9rockylinux_9_6_x64rockylinux_9_6_arm64
Rocky 10.0el10rockylinux_10_0_x64rockylinux_10_0_arm64
Debian 11.11d11debian_11_11_x64-
Debian 12.11d12debian_12_11_x64debian_12_11_arm64
Debian 13.2d13debian_13_2_x64debian_13_2_arm64
Ubuntu 20.04u20ubuntu_20_04_x64-
Ubuntu 22.04u22ubuntu_22_04_x64ubuntu_22_04_arm64
Ubuntu 24.04u24ubuntu_24_04_x64ubuntu_24_04_arm64
Anolis 8.9an8anolisos_8_9_x64-
Alibaba Cloud Linux 3al3aliyun_3_0_x64-

OSS Storage Configuration

The aliyun-meta-s3.tf template additionally creates an OSS bucket and related permissions for PostgreSQL PITR backup:

  • OSS Bucket: Creates a private bucket named pigsty-oss
  • RAM User: Creates a dedicated pigsty-oss-user user
  • Access Key: Generates AccessKey and saves to ~/pigsty.sk
  • IAM Policy: Grants full access to the bucket

AWS Configuration

Credential Setup

Set up AWS configuration and credential files:

# ~/.aws/config
[default]
region = cn-northwest-1

# ~/.aws/credentials
[default]
aws_access_key_id = <YOUR_AWS_ACCESS_KEY>
aws_secret_access_key = <AWS_ACCESS_SECRET>

If you need to use SSH keys, place the key files at:

~/.aws/pigsty-key
~/.aws/pigsty-key.pub

Tencent Cloud Configuration

Credential Setup

Add Tencent Cloud credentials to environment variables:

export TENCENTCLOUD_SECRET_ID="<your_secret_id>"
export TENCENTCLOUD_SECRET_KEY="<your_secret_key>"
export TENCENTCLOUD_REGION="ap-beijing"

Shortcut Commands

Pigsty provides some Makefile shortcuts for Terraform operations:

cd ~/pigsty/terraform

make u          # terraform apply -auto-approve + configure SSH
make d          # terraform destroy -auto-approve
make apply      # terraform apply (interactive confirmation)
make destroy    # terraform destroy (interactive confirmation)
make out        # terraform output
make ssh        # Run ssh script to configure SSH access
make r          # Reset terraform.tf to repository state

Notes

5.8 - Security

Security considerations for production Pigsty deployment

Pigsty’s default configuration is sufficient to cover the security needs of most scenarios.

Pigsty already provides out-of-the-box authentication and access control models that are secure enough for most scenarios.

pigsty-acl.jpg

If you want to further harden system security, here are some recommendations:


Confidentiality

Important Files

Protect your pigsty.yml configuration file or CMDB

  • The pigsty.yml configuration file usually contains highly sensitive confidential information. You should ensure its security.
  • Strictly control access permissions to admin nodes, limiting access to DBAs or Infra administrators only.
  • Strictly control access permissions to the pigsty.yml configuration file repository (if you manage it with git)

Protect your CA private key and other certificates, these files are very important.

  • Related files are generated by default in the files/pki directory under the Pigsty source directory on the admin node.
  • You should regularly back them up to a secure location.


Passwords

You MUST change these passwords when deploying to production, don’t use defaults!

If using MinIO, change the default MinIO user passwords and references in pgbackrest

If using remote backup repositories, enable backup encryption and set encryption passwords

  • Set [pgbackrest_repo.*.cipher_type](/docs/pgsql/param#pgbackrest_repo) to aes-256-cbc`
  • You can use ${pg_cluster} as part of the password to avoid all clusters using the same password

Use secure and reliable password encryption algorithms for PostgreSQL

  • Use pg_pwd_enc default value scram-sha-256 instead of legacy md5
  • This is the default behavior. Unless there’s a special reason (supporting legacy old clients), don’t change it back to md5

Use passwordcheck extension to enforce strong passwords

  • Add $lib/passwordcheck to pg_libs to enforce password policies.

Encrypt remote backups with encryption algorithms

  • Use repo_cipher_type in pgbackrest_repo backup repository definitions to enable encryption

Configure automatic password expiration for business users

  • You should set an automatic password expiration time for each business user to meet compliance requirements.

  • After configuring auto-expiration, don’t forget to regularly update these passwords during maintenance.

    - { 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 log password change statements to postgres logs or other logs

SET log_statement TO 'none';
ALTER USER "{{ user.name }}" PASSWORD '{{ user.password }}';
SET log_statement TO DEFAULT;


IP Addresses

Bind specified IP addresses for postgres/pgbouncer/patroni, not all addresses.

  • The default pg_listen address is 0.0.0.0, meaning all IPv4 addresses.
  • Consider using pg_listen: '${ip},${vip},${lo}' to bind to specific IP address(es) for enhanced security.

Don’t expose any ports directly to public IP, except infrastructure egress Nginx ports (default 80/443)

  • For convenience, components like Prometheus/Grafana listen on all IP addresses by default and can be accessed directly via public IP ports
  • You can modify their configurations to listen only on internal IP addresses, restricting access through the Nginx portal via domain names only. You can also use security groups or firewall rules to implement these security restrictions.
  • For convenience, Redis servers listen on all IP addresses by default. You can modify redis_bind_address to listen only on internal IP addresses.

Use HBA to restrict postgres client access

  • There’s a security-enhanced configuration template: security.yml

Restrict patroni management access: only infra/admin nodes can call control APIs



Network Traffic

Use SSL and domain names to access infrastructure components through Nginx

Use SSL to protect Patroni REST API

  • patroni_ssl_enabled is disabled by default.
  • Because it affects health checks and API calls.
  • Note this is a global option; you must decide before deployment.

Use SSL to protect Pgbouncer client traffic

  • pgbouncer_sslmode defaults to disable
  • It has significant performance impact on Pgbouncer, so it’s disabled by default.

Integrity

Configure consistency-first mode for critical PostgreSQL database clusters (e.g., finance-related databases)

  • pg_conf database tuning template, using crit.yml will trade some availability for best data consistency.

Use crit node tuning template for better consistency.

  • node_tune host tuning template using crit can reduce dirty page ratio and lower data consistency risks.

Enable data checksums to detect silent data corruption.

  • pg_checksum defaults to off, but is recommended to enable.
  • When pg_conf = crit.yml is enabled, checksums are mandatory.

Log connection establishment/termination

  • This is disabled by default, but enabled by default in the crit.yml config template.
  • You can manually configure the cluster to enable log_connections and log_disconnections parameters.

Enable watchdog if you want to completely eliminate the possibility of split-brain during PG cluster failover

  • If your traffic goes through the recommended default HAProxy distribution, you won’t encounter split-brain even without watchdog.
  • If your machine hangs and Patroni is killed with kill -9, watchdog can serve as a fallback: automatic shutdown on timeout.
  • It’s best not to enable watchdog on infrastructure nodes.

Availability

Use sufficient nodes/instances for critical PostgreSQL database clusters

  • You need at least three nodes (able to tolerate one node failure) for production-grade high availability.
  • If you only have two nodes, you can tolerate specific standby node failures.
  • If you only have one node, use external S3/MinIO for cold backup and WAL archive storage.

For PostgreSQL, make trade-offs between availability and consistency

  • pg_rpo : Trade-off between availability and consistency
  • pg_rto : Trade-off between failure probability and impact

Don’t access databases directly via fixed IP addresses; use VIP, DNS, HAProxy, or combinations

  • Use HAProxy for service access
  • In case of failover/switchover, HAProxy will handle client traffic switching.

Use multiple infrastructure nodes in important production deployments (e.g., 1~3)

  • Small deployments or lenient scenarios can use a single infrastructure/admin node.
  • Large production deployments should have at least two infrastructure nodes as mutual backup.

Use sufficient etcd server instances, and use an odd number of instances (1,3,5,7)

6 - References

Detailed reference information and lists, including supported OS distros, available modules, monitor metrics, extensions, cost comparison and analysis, glossary

6.1 - Supported Linux

Pigsty compatible Linux OS distribution major versions and CPU architectures

Pigsty runs on Linux, supporting amd64/x86_64 and arm64/aarch64 arch, plus 3 major distros: EL, Debian, Ubuntu.

Pigsty runs bare-metal without containers. Supports latest 2 major releases for each of the 3 major distros across both archs.

Overview

Recommended OS versions: RockyLinux 10.0, Ubuntu 24.04, Debian 13.1.

DistroArchOS CodePG18PG17PG16PG15PG14PG13
RHEL / Rocky / Alma 10x86_64el10.x86_64
RHEL / Rocky / Alma 10aarch64el10.aarch64
Ubuntu 24.04 (noble)x86_64u24.x86_64
Ubuntu 24.04 (noble)aarch64u24.aarch64
Debian 13 (trixie)x86_64d13.x86_64
Debian 13 (trixie)aarch64d13.aarch64

EL

Pigsty supports RHEL / Rocky / Alma / Anolis / CentOS 8, 9, 10.

EL DistroArchOS CodePG18PG17PG16PG15PG14PG13
RHEL10 / Rocky10 / Alma10x86_64el10.x86_64
RHEL10 / Rocky10 / Alma10aarch64el10.aarch64
RHEL9 / Rocky9 / Alma9x86_64el9.x86_64
RHEL9 / Rocky9 / Alma9aarch64el9.aarch64
RHEL8 / Rocky8 / Alma8x86_64el8.x86_64
RHEL8 / Rocky8 / Alma8aarch64el8.aarch64
RHEL7 / CentOS7x86_64el7.x86_64
RHEL7 / CentOS7aarch64-

Ubuntu

Pigsty supports Ubuntu 24.04 / 22.04:

Ubuntu DistroArchOS CodePG18PG17PG16PG15PG14PG13
Ubuntu 24.04 (noble)x86_64u24.x86_64
Ubuntu 24.04 (noble)aarch64u24.aarch64
Ubuntu 22.04 (jammy)x86_64u22.x86_64
Ubuntu 22.04 (jammy)aarch64u22.aarch64
Ubuntu 20.04 (focal)x86_64u20.x86_64
Ubuntu 20.04 (focal)aarch64-

Debian

Pigsty supports Debian 12 / 13, latest Debian 13.1 recommended:

Debian DistroArchOS CodePG18PG17PG16PG15PG14PG13
Debian 13 (trixie)x86_64d13.x86_64
Debian 13 (trixie)aarch64d13.aarch64
Debian 12 (bookworm)x86_64d12.x86_64
Debian 12 (bookworm)aarch64d12.aarch64
Debian 11 (bullseye)x86_64d11.x86_64
Debian 11 (bullseye)aarch64-

Vagrant

For local VM deployment, use these Vagrant base images (same as used in Pigsty dev):


Terraform

For cloud deployment, use these Terraform base images (Aliyun example):

  • Rocky 8.10 : rockylinux_8_10_x64_20G_alibase_20240923.vhd
  • Rocky 9.6 : rockylinux_9_6_x64_20G_alibase_20250101.vhd
  • Ubuntu 22.04 : ubuntu_22_04_x64_20G_alibase_20240926.vhd
  • Ubuntu 24.04 : ubuntu_24_04_x64_20G_alibase_20240923.vhd
  • Debian 12.11 : debian_12_11_x64_20G_alibase_20241201.vhd
  • Debian 13 : debian_13_x64_20G_alibase_20250101.vhd

6.2 - Pigsty Modules

This article lists all available modules in Pigsty and the module roadmap.

Core Modules

Pigsty provides four core modules that are essential for delivering fully-featured, highly available PostgreSQL services:

  • PGSQL: Self-healing PostgreSQL clusters with HA, PITR, IaC, SOP, monitoring, and 440 extensions out of the box.
  • INFRA: Local software repo, VictoriaMetrics, Grafana, VictoriaLogs, AlertManager, PushGateway, Blackbox Exporter…
  • NODE: Tune nodes to desired state: hostname, timezone, NTP, ssh, sudo, haproxy, docker, vector, keepalived.
  • ETCD: Distributed key-value store serving as DCS for HA PostgreSQL clusters: consensus, config management, service discovery.

Kernel Modules

Pigsty provides four kernel modules as optional in-place replacements for the vanilla PostgreSQL kernel, offering different database flavors:

  • MSSQL: Microsoft SQL Server wire-protocol compatible PG kernel, powered by AWS, WiltonDB & Babelfish!
  • IVORY: Oracle-compatible PostgreSQL 16 kernel, from the IvorySQL open-source project by HighGo.
  • POLAR: “Cloud-native” PostgreSQL kernel open-sourced by Alibaba Cloud, an Aurora-style RAC PostgreSQL fork.
  • CITUS: Distributed PostgreSQL cluster via extension (Azure Hyperscale), with native Patroni HA support!

Extension Modules

Pigsty provides four extension modules that are not essential for core functionality but can enhance PostgreSQL capabilities:

  • MINIO: S3-compatible simple object storage server, serving as optional backup repository for PostgreSQL, with production deployment and monitoring support.
  • REDIS: Redis server, high-performance data structure server, supporting standalone, sentinel, and cluster deployment modes with comprehensive monitoring.
  • MONGO: Native FerretDB deployment support — adding MongoDB wire-protocol level API compatibility to PostgreSQL!
  • DOCKER: Docker daemon service, enabling one-click deployment of containerized stateless software templates to extend Pigsty’s capabilities!

Peripheral Modules

Pigsty also supports peripheral modules that are closely related to the PostgreSQL kernel (extensions, forks, derivatives, wrappers):

  • DUCKDB: Powerful embedded OLAP database. Pigsty provides binaries, dynamic libraries, and related PG extensions: pg_duckdb, pg_lakehouse, and duckdb_fdw.
  • SUPABASE: Pigsty allows running the popular Firebase open-source alternative — Supabase — on existing HA PostgreSQL clusters!
  • GREENPLUM: MPP data warehouse based on PostgreSQL 12 kernel, currently with monitoring and RPM installation support only. (Beta)
  • CLOUDBERRY: Open-source fork by original Greenplum developers after it went closed-source, based on PG 14 kernel, currently RPM installation support only. (Beta)
  • NEON: Serverless PostgreSQL kernel with database branching capabilities. (WIP)

Pilot Modules

Pigsty is adding support for some pilot modules related to the PostgreSQL ecosystem. These may become official Pigsty modules in the future:

  • KAFKA: Deploy KRaft-powered Kafka message queues with Pigsty, with out-of-the-box monitoring support. (Beta)
  • MYSQL: Deploy highly available MySQL 8.0 clusters with Pigsty, with out-of-the-box monitoring support (for critique/migration evaluation). (Beta)
  • KUBE: Production-grade Kubernetes deployment and monitoring using SealOS. (Alpha)
  • VICTORIA: Alternative Infra implementation based on VictoriaMetrics and VictoriaLogs, offering better performance and resource utilization. (Alpha)
  • JUPYTER: Out-of-the-box Jupyter Notebook environment for data analysis and machine learning scenarios. (Alpha)

Monitoring Other Databases

Pigsty’s INFRA module can be used standalone as an out-of-the-box monitoring infrastructure to monitor other nodes or existing PostgreSQL databases:

  • Existing PostgreSQL Services: Pigsty can monitor external PostgreSQL services not managed by Pigsty, still providing relatively complete monitoring support.
  • RDS PG: PostgreSQL RDS services provided by cloud vendors can be monitored as standard external Postgres instances.
  • PolarDB: Alibaba Cloud’s cloud-native database can be monitored as external PostgreSQL 11 / 14 instances.
  • KingBase: A Chinese domestic database provided by KINGBASE, monitored as external PostgreSQL 12 instances.
  • Greenplum / YMatrixDB monitoring: Currently monitored as horizontally sharded PostgreSQL clusters.

6.3 - Extensions

This article lists PostgreSQL extensions supported by Pigsty and their compatibility across different systems.

Pigsty has 440 extensions. See PGEXT.CLOUD for details, maintained by PIGSTY.

CategoryAllPGDGPIGSTYCONTRIBMISSPG18PG17PG16PG15PG14PG13
ALL440149268710408429428430415386
EL434143268716397421422424412382
Debian4261052507114394416414416404371

pigsty-ecosystem.jpg

6.4 - File Hierarchy

How Pigsty’s file system structure is designed and organized, and directory structures used by each module.

Pigsty FHS

Pigsty’s home directory is located at ~/pigsty by default. The file structure within this directory is as follows:

#------------------------------------------------------------------------------
# pigsty
#  ^-----@app                    # Extra application resources and examples
#  ^-----@bin                    # Utility scripts
#  ^-----@docs                   # Documentation (docsify-compatible)
#  ^-----@files                  # Ansible file resources
#            ^-----@victoria     # VictoriaMetrics rule definitions
#            ^-----@grafana      # Grafana dashboards
#            ^-----@postgres     # /pg/bin/ scripts
#            ^-----@migration    # PGSQL migration task definitions
#            ^-----@pki          # Self-signed CA and certificates
#  ^-----@roles                  # Ansible role implementations
#  ^-----@templates              # Ansible template files
#  ^-----@vagrant                # Vagrant sandbox VM templates
#  ^-----@terraform              # Terraform cloud VM provisioning templates
#  ^-----configure               # Configuration wizard script
#  ^-----ansible.cfg             # Ansible default configuration
#  ^-----pigsty.yml              # Pigsty default configuration file
#  ^-----*.yml                   # Ansible playbooks
#------------------------------------------------------------------------------
# /etc/pigsty/
#  ^-----@targets                # File-based service discovery targets
#  ^-----@dashboards             # Grafana monitoring dashboards
#  ^-----@datasources            # Grafana data sources
#  ^-----@playbooks              # Ansible playbooks
#------------------------------------------------------------------------------

CA FHS

Pigsty’s self-signed CA is located in files/pki/ under the Pigsty home directory.

You must keep the CA key file secure: files/pki/ca/ca.key. This key is generated by the ca role during deploy.yml or infra.yml execution.

# pigsty/files/pki
#  ^-----@ca                      # Self-signed CA key and certificate
#         ^[email protected]           # CRITICAL: Keep this secret
#         ^[email protected]           # CRITICAL: Trusted everywhere
#  ^-----@csr                     # Certificate signing requests
#  ^-----@misc                    # Miscellaneous certificates, issued certs
#  ^-----@etcd                    # ETCD server certificates
#  ^-----@minio                   # MinIO server certificates
#  ^-----@nginx                   # Nginx SSL certificates
#  ^-----@infra                   # Infra client certificates
#  ^-----@pgsql                   # PostgreSQL server certificates
#  ^-----@mongo                   # MongoDB/FerretDB server certificates
#  ^-----@mysql                   # MySQL server certificates (placeholder)

Nodes managed by Pigsty will have the following certificate files installed:

/etc/pki/ca.crt                             # Root certificate added to all nodes
/etc/pki/ca-trust/source/anchors/ca.crt     # Symlink to system trust anchors

All infra nodes will have the following certificates:

/etc/pki/infra.crt                          # Infra node certificate
/etc/pki/infra.key                          # Infra node private key

When your admin node fails, the files/pki directory and pigsty.yml file should be available on the backup admin node. You can use rsync to achieve this:

# run on meta-1, rsync to meta2
cd ~/pigsty;
rsync -avz ./ meta-2:~/pigsty

NODE FHS

The node data directory is specified by the node_data parameter, defaulting to /data, owned by root with permissions 0777.

Each component’s default data directory is located under this data directory:

/data
#  ^-----@postgres                   # PostgreSQL database directory
#  ^-----@backups                    # PostgreSQL backup directory (when no dedicated backup disk)
#  ^-----@redis                      # Redis data directory (shared by multiple instances)
#  ^-----@minio                      # MinIO data directory (single-node single-disk mode)
#  ^-----@etcd                       # ETCD main data directory
#  ^-----@infra                      # Infra module data directory
#  ^-----@docker                     # Docker data directory
#  ^-----@...                        # Other component data directories

Prometheus FHS

Prometheus main configuration file is located at roles/infra/templates/prometheus/prometheus.yml.j2 and is rendered to /etc/prometheus/prometheus.yml on all infrastructure nodes.

VictoriaMetrics-related scripts and rule definitions are placed in the files/victoria/ directory under the Pigsty home directory, and are copied to /etc/prometheus/ on all infrastructure nodes.

# /etc/prometheus/
#  ^-----prometheus.yml              # Prometheus main configuration file
#  ^-----@bin                        # Utility scripts: check config, show status, reload, rebuild
#  ^-----@rules                      # Recording and alerting rule definitions
#            ^-----infra.yml         # Infra rules and alerts
#            ^-----etcd.yml          # ETCD rules and alerts
#            ^-----node.yml          # Node rules and alerts
#            ^-----pgsql.yml         # PGSQL rules and alerts
#            ^-----redis.yml         # Redis rules and alerts
#            ^-----minio.yml         # MinIO rules and alerts
#            ^-----kafka.yml         # Kafka rules and alerts
#            ^-----mysql.yml         # MySQL rules and alerts
#  ^-----@targets                    # File-based service discovery target definitions
#            ^-----@infra            # Infra static target definitions
#            ^-----@node             # Node static target definitions
#            ^-----@pgsql            # PGSQL static target definitions
#            ^-----@pgrds            # PGSQL remote RDS targets
#            ^-----@redis            # Redis static target definitions
#            ^-----@minio            # MinIO static target definitions
#            ^-----@mongo            # MongoDB static target definitions
#            ^-----@mysql            # MySQL static target definitions
#            ^-----@etcd             # ETCD static target definitions
#            ^-----@ping             # Ping static target definitions
#            ^-----@patroni          # Patroni static targets (used when Patroni SSL is enabled)
#            ^-----@.....            # Other monitoring target definitions
# /etc/alertmanager.yml              # Alertmanager main configuration file
# /etc/blackbox.yml                  # Blackbox exporter main configuration file

PostgreSQL FHS

The following parameters are related to PostgreSQL database directory structure:

  • pg_dbsu_home: Postgres default user home directory, defaults to /var/lib/pgsql
  • pg_bin_dir: Postgres binary directory, defaults to /usr/pgsql/bin/
  • pg_data: Postgres database directory, defaults to /pg/data
  • pg_fs_main: Postgres main data disk mount point, defaults to /data
  • pg_fs_backup: Postgres backup disk mount point, defaults to /data/backups (optional, can also backup to a subdirectory on the main data disk)
# Working assumptions:
#   {{ pg_fs_main }} main data directory, default location: `/data`          [fast SSD]
#   {{ pg_fs_backup }} backup data disk, default location: `/data/backups`     [cheap HDD]
#--------------------------------------------------------------#
# Default configuration:
#     pg_fs_main = /data             High-speed SSD
#     pg_fs_backup = /data/backups     Cheap HDD (optional)
#
#     /pg      -> /data/postgres/pg-test-15    (symlink)
#     /pg/data -> /data/postgres/pg-test-15/data
#--------------------------------------------------------------#
- name: create postgresql directories
  tags: pg_dir
  become: yes
  block:

    - name: make main and backup data dir
      file: path={{ item }} state=directory owner=root mode=0777
      with_items:
        - "{{ pg_fs_main }}"
        - "{{ pg_fs_backup }}"

    # pg_cluster_dir:    "{{ pg_fs_main }}/postgres/{{ pg_cluster }}-{{ pg_version }}"
    - name: create postgres directories
      file: path={{ item }} state=directory owner={{ pg_dbsu }} group=postgres mode=0700
      with_items:
        - "{{ pg_fs_main }}/postgres"
        - "{{ pg_cluster_dir }}"
        - "{{ pg_cluster_dir }}/bin"
        - "{{ pg_cluster_dir }}/log"
        - "{{ pg_cluster_dir }}/tmp"
        - "{{ pg_cluster_dir }}/cert"
        - "{{ pg_cluster_dir }}/conf"
        - "{{ pg_cluster_dir }}/data"
        - "{{ pg_cluster_dir }}/meta"
        - "{{ pg_cluster_dir }}/stat"
        - "{{ pg_cluster_dir }}/change"
        - "{{ pg_backup_dir }}/backup"

Data File Structure

# Physical directories
{{ pg_fs_main }}     /data                      # Top-level data directory, typically fast SSD mount point
{{ pg_dir_main }}    /data/postgres             # Contains all Postgres instance data (may have multiple instances/versions)
{{ pg_cluster_dir }} /data/postgres/pg-test-15  # Contains `pg-test` cluster data (major version 15)
                     /data/postgres/pg-test-15/bin            # PostgreSQL utility scripts
                     /data/postgres/pg-test-15/log            # Logs: postgres/pgbouncer/patroni/pgbackrest
                     /data/postgres/pg-test-15/tmp            # Temporary files, e.g., rendered SQL files
                     /data/postgres/pg-test-15/cert           # PostgreSQL server certificates
                     /data/postgres/pg-test-15/conf           # PostgreSQL configuration file index
                     /data/postgres/pg-test-15/data           # PostgreSQL main data directory
                     /data/postgres/pg-test-15/meta           # PostgreSQL identity information
                     /data/postgres/pg-test-15/stat           # Statistics, log reports, summary digests
                     /data/postgres/pg-test-15/change         # Change records

{{ pg_fs_backup }}     /data/backups                            # Optional backup disk directory/mount point
                     /data/backups/postgres/pg-test-15/backup # Actual storage location for cluster backups

# Symlinks
/pg             ->   /data/postgres/pg-test-15                # pg root symlink
/pg/data        ->   /data/postgres/pg-test-15/data           # pg data directory
/pg/backup      ->   /var/backups/postgres/pg-test-15/backup  # pg backup directory

Binary File Structure

On EL-compatible distributions (using yum), PostgreSQL default installation location is:

/usr/pgsql-${pg_version}/

Pigsty creates a symlink named /usr/pgsql pointing to the actual version specified by the pg_version parameter, for example:

/usr/pgsql -> /usr/pgsql-15

Therefore, the default pg_bin_dir is /usr/pgsql/bin/, and this path is added to the system PATH environment variable, defined in: /etc/profile.d/pgsql.sh.

export PATH="/usr/pgsql/bin:/pg/bin:$PATH"
export PGHOME=/usr/pgsql
export PGDATA=/pg/data

On Ubuntu/Debian, the default PostgreSQL Deb package installation location is:

/usr/lib/postgresql/${pg_version}/bin

Pgbouncer FHS

Pgbouncer runs under the same user as {{ pg_dbsu }} (defaults to postgres), with configuration files located in /etc/pgbouncer.

  • pgbouncer.ini: Connection pool main configuration file
  • database.txt: Defines databases in the connection pool
  • userlist.txt: Defines users in the connection pool
  • pgb_hba.conf: Defines access permissions for the connection pool

Redis FHS

Pigsty provides basic support for Redis deployment and monitoring.

Redis binaries are installed in /bin/ via RPM packages or binary copy, including:

redis-server
redis-server
redis-cli
redis-sentinel
redis-check-rdb
redis-check-aof
redis-benchmark
/usr/libexec/redis-shutdown

For a Redis instance named redis-test-1-6379, the related resources are as follows:

/usr/lib/systemd/system/redis-test-1-6379.service               # Service (on Debian: /lib/systemd)
/etc/redis/redis-test-1-6379.conf                               # Configuration
/data/redis/redis-test-1-6379                                   # Database directory
/data/redis/redis-test-1-6379/redis-test-1-6379.rdb             # RDB file
/data/redis/redis-test-1-6379/redis-test-1-6379.aof             # AOF file
/var/log/redis/redis-test-1-6379.log                            # Log
/var/run/redis/redis-test-1-6379.pid                            # PID

For Ubuntu/Debian, the default systemd service directory is /lib/systemd/system/ instead of /usr/lib/systemd/system/.

6.5 - Parameters

Pigsty configuration parameter overview and navigation

Pigsty provides approximately 380+ configuration parameters distributed across 8 core modules, allowing fine-grained control over all aspects of the system.


Module Navigation

This page provides navigation and overview for all Pigsty configuration parameters. Click on a module name to jump to the detailed parameter documentation.

ModuleParameter GroupsTotal ParametersDescription
PGSQL9123PostgreSQL database cluster core configuration
INFRA1082Infrastructure components: repo, Nginx, DNS, monitoring, Grafana, etc.
NODE1183Host node tuning: identity, DNS, packages, tuning, security, admin, time, VIP, etc.
ETCD213Distributed configuration storage and service discovery
REDIS121Redis cache and data structure server
MINIO221S3-compatible object storage service
FERRET19MongoDB-compatible database FerretDB
DOCKER18Docker container engine

PGSQL

The PGSQL module provides 9 groups with 123 PostgreSQL-related configuration parameters.

Parameter GroupCountDescription
PG_ID11PostgreSQL cluster and instance identity parameters
PG_BUSINESS12Business users, databases, services, and access control rules
PG_INSTALL10PostgreSQL installation: version, paths, packages
PG_BOOTSTRAP38PostgreSQL cluster initialization: Patroni high availability
PG_PROVISION8PostgreSQL cluster template provisioning: roles, privileges, extensions
PG_BACKUP6pgBackRest backup and recovery configuration
PG_ACCESS17Service exposure, connection pool, VIP, DNS client access configuration
PG_MONITOR17PostgreSQL monitoring exporter configuration
PG_REMOVE4PostgreSQL instance cleanup and uninstallation configuration

INFRA

The INFRA module provides 10 groups with 82 infrastructure-related configuration parameters.

Parameter GroupCountDescription
META5Pigsty meta information: version, admin IP, region, language, proxy
CA3Self-signed CA certificate management
INFRA_ID3Infrastructure node identity and service portal
REPO10Local software repository configuration
INFRA_PACKAGE2Infrastructure node package installation
NGINX14Nginx web server and reverse proxy configuration
DNS3DNSMasq DNS resolution service configuration
VICTORIA19VictoriaMetrics/Logs/Traces observability suite
PROMETHEUS7Alertmanager and Blackbox Exporter
GRAFANA8Grafana visualization platform configuration

NODE

The NODE module provides 11 groups with 83 host node-related configuration parameters.

Parameter GroupCountDescription
NODE_ID5Node identity parameters
NODE_DNS6Node DNS configuration
NODE_PACKAGE4Node package management
NODE_TUNE10Node kernel tuning parameters
NODE_SEC4Node security parameters
NODE_ADMIN9Node admin user configuration
NODE_TIME5Node time synchronization
NODE_VIP8Node VIP configuration
HAPROXY10HAProxy load balancer configuration
NODE_EXPORTER3Node exporter configuration
VECTOR6Vector log collector configuration

ETCD

The ETCD module provides 2 groups with 13 distributed configuration storage parameters.

Parameter GroupCountDescription
ETCD10ETCD cluster deployment and configuration
ETCD_REMOVE3ETCD cluster removal: safeguard, data cleanup, etc.

REDIS

The REDIS module provides 21 Redis-related configuration parameters.

Parameter GroupCountDescription
REDIS21Redis cluster deployment and configuration

MINIO

The MINIO module provides 2 groups with 21 MinIO object storage parameters.

Parameter GroupCountDescription
MINIO18MinIO cluster deployment and configuration
MINIO_REMOVE3MinIO cluster removal: safeguard, data cleanup, etc.

FERRET

The FERRET module provides 9 FerretDB-related configuration parameters.

Parameter GroupCountDescription
FERRET9FerretDB deployment and configuration

DOCKER

The DOCKER module provides 8 Docker container engine configuration parameters.

Parameter GroupCountDescription
DOCKER8Docker container engine configuration

Parameter Overview

The following tables provide a comprehensive summary of all parameters, organized by module.

PGSQL Parameters

PG_ID parameter group defines PostgreSQL cluster and instance identity, including cluster name, instance number, role, shard, etc.

ParameterTypeDescription
pg_modeenumpgsql cluster mode: pgsql,citus,mssql,mysql,polar,ivory,oracle,gpsql
pg_clusterstringpgsql cluster name, required identity parameter
pg_seqintpgsql instance number, required identity parameter
pg_roleenumpgsql instance role, required, can be primary, replica, offline
pg_instancesdictDefine multiple pg instances on one node, using {port:ins_vars} format
pg_upstreamipUpstream node IP for cascaded replica or standby cluster
pg_shardstringpgsql shard name, required for citus and gpsql horizontal sharding clusters
pg_groupintpgsql shard number, positive integer, required for citus and gpsql clusters
gp_roleenumGreenplum role for this cluster, can be master or segment
pg_exportersdictSet up additional pg_exporters on this node to monitor remote postgres instances
pg_offline_queryboolSet to true to mark this replica as special offline instance for Offline service

PG_BUSINESS parameter group defines business users, databases, services, access control rules, and default system user credentials.

ParameterTypeDescription
pg_usersuser[]Postgres business users
pg_databasesdatabase[]Postgres business databases
pg_servicesservice[]Postgres business services
pg_hba_ruleshba[]Postgres business HBA rules
pgb_hba_ruleshba[]Pgbouncer business HBA rules
pg_replication_usernameusernamePostgres replication username, default replicator
pg_replication_passwordpasswordPostgres replication password, default DBUser.Replicator
pg_admin_usernameusernamePostgres admin username, default dbuser_dba
pg_admin_passwordpasswordPostgres admin password, default DBUser.DBA
pg_monitor_usernameusernamePostgres monitor username, default dbuser_monitor
pg_monitor_passwordpasswordPostgres monitor password, default DBUser.Monitor
pg_dbsu_passwordpassworddbsu password, empty string means no dbsu password, best not to set

PG_INSTALL parameter group configures PostgreSQL installation options, including version, paths, packages, and extensions.

ParameterTypeDescription
pg_dbsuusernameOS dbsu name, default postgres, best not to change
pg_dbsu_uidintOS dbsu uid and gid, default 26 for postgres user and group
pg_dbsu_sudoenumdbsu sudo privilege: none, limit, all, nopass, default limit
pg_dbsu_homepathPostgreSQL home directory, default /var/lib/pgsql
pg_dbsu_ssh_exchangeboolExchange postgres dbsu ssh keys between pgsql cluster
pg_versionenumPostgres major version to install, default 18
pg_bin_dirpathPostgres binary directory, default /usr/pgsql/bin
pg_log_dirpathPostgres log directory, default /pg/log/postgres
pg_packagesstring[]pg packages to install, ${pg_version} will be replaced
pg_extensionsstring[]pg extensions to install, ${pg_version} will be replaced

PG_BOOTSTRAP parameter group configures PostgreSQL cluster initialization, including Patroni HA, data directory, storage, connections, encoding, etc.

ParameterTypeDescription
pg_datapathPostgres data directory, default /pg/data
pg_fs_mainpathPostgres main data mount point, default /data/postgres
pg_fs_backuppathpg backup data mount point, default /data/backups
pg_storage_typeenumpg main data storage type: SSD, HDD, default SSD
pg_dummy_filesizesizeSize of /pg/dummy, default reserves 64MB for emergency
pg_listenip(s)postgres/pgbouncer listen address, default 0.0.0.0
pg_portportPostgres listen port, default 5432
pg_localhostpathPostgres Unix socket directory for local connections
pg_namespacepathTop-level key namespace in etcd, used by patroni & vip
patroni_enabledboolIf disabled, postgres cluster won’t be created during init
patroni_modeenumPatroni working mode: default, pause, remove
patroni_portportPatroni listen port, default 8008
patroni_log_dirpathPatroni log directory, default /pg/log/patroni
patroni_ssl_enabledboolSecure patroni RestAPI with SSL?
patroni_watchdog_modeenumPatroni watchdog mode: automatic, required, off, default off
patroni_usernameusernamePatroni restapi username, default postgres
patroni_passwordpasswordPatroni restapi password, default Patroni.API
pg_primary_dbstringPrimary database name in cluster, used by Citus, default postgres
pg_parametersdictOverride PostgreSQL parameters in postgresql.auto.conf
pg_filespath[]Extra files to copy to PGDATA directory (e.g., license files)
pg_confenumConfig template: oltp, olap, crit, tiny, default oltp.yml
pg_max_connintPostgres max connections, auto uses recommended value
pg_shared_buffer_ratiofloatPostgres shared buffer memory ratio, default 0.25, range 0.1~0.4
pg_rtointRecovery Time Objective (seconds), default 30s
pg_rpointRecovery Point Objective (bytes), default 1MiB
pg_libsstringPreloaded libraries, default pg_stat_statements,auto_explain
pg_delayintervalWAL replay delay for standby cluster, for delayed replica
pg_checksumboolEnable data checksums for postgres cluster?
pg_pwd_encenumPassword encryption algorithm: fixed to scram-sha-256
pg_encodingenumDatabase cluster encoding, default UTF8
pg_localeenumDatabase cluster locale setting, default C
pg_lc_collateenumDatabase cluster collation, default C
pg_lc_ctypeenumDatabase character type, default C
pg_io_methodenumPostgreSQL IO method: auto, sync, worker, io_uring
pg_etcd_passwordpasswordPassword for this PostgreSQL cluster in etcd, default uses cluster name
pgsodium_keystringpgsodium encryption master key, 64-bit hex, default sha256(pg_cluster)
pgsodium_getkey_scriptpathpgsodium getkey script path, default uses template pgsodium_getkey

PG_PROVISION parameter group configures PostgreSQL cluster template provisioning, including default roles, privileges, schemas, extensions, and HBA rules.

ParameterTypeDescription
pg_provisionboolProvision postgres cluster business objects after bootstrap?
pg_initstringCluster template initialization script, default pg-init
pg_default_rolesrole[]Default predefined roles and system users in postgres cluster
pg_default_privilegesstring[]Default privileges when admin user creates database objects
pg_default_schemasstring[]List of default schemas to create
pg_default_extensionsextension[]List of default extensions to create
pg_reloadboolReload postgres config immediately after HBA changes
pg_default_hba_ruleshba[]Postgres host-based authentication rules, global PG default HBA
pgb_default_hba_ruleshba[]Pgbouncer default host-based authentication rules, global PGB default HBA

PG_BACKUP parameter group configures pgBackRest backup and recovery, including repository type, path, retention policy, etc.

ParameterTypeDescription
pgbackrest_enabledboolEnable pgbackrest on pgsql host?
pgbackrest_cleanboolDelete previous pg backup data during init?
pgbackrest_log_dirpathpgbackrest log directory, default /pg/log/pgbackrest
pgbackrest_methodenumpgbackrest repo method: local, minio, etc.
pgbackrest_init_backupboolExecute full backup immediately after pgbackrest init? default true
pgbackrest_repodictpgbackrest repository definition

PG_ACCESS parameter group configures service exposure, connection pool, VIP, DNS, and other client access options.

ParameterTypeDescription
pgbouncer_enabledboolIf disabled, pgbouncer connection pool won’t be configured
pgbouncer_portportpgbouncer listen port, default 6432
pgbouncer_log_dirpathpgbouncer log directory, default /pg/log/pgbouncer
pgbouncer_auth_queryboolUse AuthQuery to fetch unlisted business users from postgres?
pgbouncer_poolmodeenumPooling mode: transaction, session, statement, default transaction
pgbouncer_sslmodeenumpgbouncer client SSL mode, default disabled
pgbouncer_ignore_paramstring[]pgbouncer ignore startup parameters list
pg_weightintRelative load balancing weight in service, default 100, range 0-255
pg_service_providerstringDedicated haproxy node group name, or empty for local haproxy
pg_default_service_destenumIf svc.dest=‘default’, default service points to postgres or pgbouncer
pg_default_servicesservice[]Postgres default service definition list, global shared
pg_vip_enabledboolEnable L2 VIP for pgsql primary node? default disabled
pg_vip_addresscidr4VIP address format <ipv4>/<mask>, required when vip enabled
pg_vip_interfacestringVIP network interface to listen, default eth0
pg_dns_suffixstringpgsql dns suffix, default empty
pg_dns_targetenumPG DNS resolves to: auto, primary, vip, none, or specific IP

PG_MONITOR parameter group configures PostgreSQL monitoring exporters, including pg_exporter, pgbouncer_exporter, and pgbackrest_exporter.

ParameterTypeDescription
pg_exporter_enabledboolEnable pg_exporter on pgsql host?
pg_exporter_configstringpg_exporter config file/template name
pg_exporter_cache_ttlsstringpg_exporter collector tiered TTL config, default ‘1,10,60,300’
pg_exporter_portportpg_exporter listen port, default 9630
pg_exporter_paramsstringExtra URL parameters passed in pg_exporter dsn
pg_exporter_urlpgurlIf specified, overrides auto-generated postgres DSN connection string
pg_exporter_auto_discoveryboolEnable monitoring auto database discovery? default enabled
pg_exporter_exclude_databasestringExcluded database names when auto discovery enabled, comma-separated
pg_exporter_include_databasestringOnly monitor databases in this list when auto discovery enabled
pg_exporter_connect_timeoutintpg_exporter connection timeout in ms, default 200
pg_exporter_optionsargpg_exporter extra command line options
pgbouncer_exporter_enabledboolEnable pgbouncer_exporter on pgsql host?
pgbouncer_exporter_portportpgbouncer_exporter listen port, default 9631
pgbouncer_exporter_urlpgurlIf specified, overrides auto-generated pgbouncer dsn connection string
pgbouncer_exporter_optionsargpgbouncer_exporter extra command line options
pgbackrest_exporter_enabledboolEnable pgbackrest_exporter on pgsql host?
pgbackrest_exporter_portportpgbackrest_exporter listen port, default 9854
pgbackrest_exporter_optionsargpgbackrest_exporter extra command line options

PG_REMOVE parameter group configures PostgreSQL instance cleanup and uninstallation behavior, including data directory, backup, and package removal control.

ParameterTypeDescription
pg_rm_databoolClean postgres data directory when removing pgsql instance?
pg_rm_backupboolClean pgbackrest backup when removing primary?
pg_rm_pkgboolUninstall related packages when removing pgsql instance?
pg_safeguardboolSafeguard to prevent accidental pgsql cleanup? default false

INFRA Parameters

META parameter group defines Pigsty meta information, including version number, admin node IP, repository region, default language, and proxy settings.

ParameterTypeDescription
versionstringPigsty version string
admin_ipipAdmin node IP address
regionenumUpstream mirror region: default, china, europe
languageenumDefault language, en or zh
proxy_envdictGlobal proxy environment variables for package downloads

CA parameter group configures Pigsty self-signed CA certificate management, including whether to create CA, CA name, and certificate validity.

ParameterTypeDescription
ca_createboolCreate CA if not exists? default true
ca_cnstringCA CN name, fixed to pigsty-ca
cert_validityintervalCertificate validity, default 20 years

INFRA_ID parameter group defines infrastructure node identity, including node sequence number, service portal configuration, and data directory.

ParameterTypeDescription
infra_seqintInfrastructure node sequence number, required identity parameter
infra_portaldictInfrastructure service list exposed via Nginx portal
infra_datapathInfrastructure data directory, default /data/infra

REPO parameter group configures local software repository, including repository enable switch, directory path, upstream source definitions, and packages to download.

ParameterTypeDescription
repo_enabledboolCreate software repository on this infra node?
repo_homepathSoftware repository home directory, default /www
repo_namestringSoftware repository name, default pigsty
repo_endpointurlRepository access point: domain or ip:port format
repo_removeboolRemove existing upstream repo source definition files when building local repo?
repo_modulesstringEnabled upstream repository module list, comma-separated
repo_upstreamupstream[]Upstream repository source definitions: where to download packages
repo_packagesstring[]Which packages to download from upstream
repo_extra_packagesstring[]Which extra packages to download from upstream
repo_url_packagesstring[]Extra packages to download by URL

INFRA_PACKAGE parameter group defines packages to install on infrastructure nodes, including RPM/DEB and PIP packages.

ParameterTypeDescription
infra_packagesstring[]Packages to install on infrastructure nodes
infra_packages_pipstringPackages to install via pip on infrastructure nodes

NGINX parameter group configures Nginx web server and reverse proxy, including enable switch, ports, SSL mode, certificates, and basic authentication.

ParameterTypeDescription
nginx_enabledboolEnable nginx on this infra node?
nginx_cleanboolClean existing nginx config during init?
nginx_exporter_enabledboolEnable nginx_exporter on this infra node?
nginx_exporter_portportnginx_exporter listen port, default 9113
nginx_sslmodeenumnginx SSL mode: disable, enable, enforce
nginx_cert_validitydurationnginx self-signed certificate validity, default 397d
nginx_homepathnginx content directory, default /www, symlinks to nginx_data
nginx_datapathnginx actual data directory, default /data/nginx
nginx_usersdictnginx basic auth users: username and password dictionary
nginx_portportnginx listen port, default 80
nginx_ssl_portportnginx SSL listen port, default 443
certbot_signboolUse certbot to sign certificates?
certbot_emailstringcertbot notification email address
certbot_optionsstringcertbot extra command line arguments

DNS parameter group configures DNSMasq DNS resolution service, including enable switch, listen port, and dynamic DNS records.

ParameterTypeDescription
dns_enabledboolSet up dnsmasq on this infra node?
dns_portportDNS server listen port, default 53
dns_recordsstring[]Dynamic DNS records resolved by dnsmasq

VICTORIA parameter group configures VictoriaMetrics/Logs/Traces observability suite, including enable switches, ports, data retention policies, etc.

ParameterTypeDescription
vmetrics_enabledboolEnable VictoriaMetrics on this infra node?
vmetrics_cleanboolClean VictoriaMetrics data during init?
vmetrics_portportVictoriaMetrics listen port, default 8428
vmetrics_scrape_intervalintervalGlobal scrape interval, default 10s
vmetrics_scrape_timeoutintervalGlobal scrape timeout, default 8s
vmetrics_optionsargVictoriaMetrics extra command line arguments
vlogs_enabledboolEnable VictoriaLogs on this infra node?
vlogs_cleanboolClean VictoriaLogs data during init?
vlogs_portportVictoriaLogs listen port, default 9428
vlogs_optionsargVictoriaLogs extra command line arguments
vtraces_enabledboolEnable VictoriaTraces on this infra node?
vtraces_cleanboolClean VictoriaTraces data during init?
vtraces_portportVictoriaTraces listen port, default 10428
vtraces_optionsargVictoriaTraces extra command line arguments
vmalert_enabledboolEnable VMAlert on this infra node?
vmalert_portportVMAlert listen port, default 8880
vmalert_optionsargVMAlert extra command line arguments

PROMETHEUS parameter group configures Alertmanager and Blackbox Exporter, providing alerting management and network probing.

ParameterTypeDescription
blackbox_enabledboolSet up blackbox_exporter on this infra node?
blackbox_portportblackbox_exporter listen port, default 9115
blackbox_optionsargblackbox_exporter extra command line options
alertmanager_enabledboolSet up alertmanager on this infra node?
alertmanager_portportAlertManager listen port, default 9059
alertmanager_optionsargalertmanager extra command line options
exporter_metrics_pathpathexporter metrics path, default /metrics

GRAFANA parameter group configures Grafana visualization platform, including enable switch, port, admin credentials, and data source configuration.

ParameterTypeDescription
grafana_enabledboolEnable Grafana on this infra node?
grafana_portportGrafana listen port, default 3000
grafana_cleanboolClean data during Grafana init?
grafana_admin_usernameusernameGrafana admin username, default admin
grafana_admin_passwordpasswordGrafana admin password, default pigsty
grafana_auth_proxyboolEnable Grafana auth proxy?
grafana_pgurlurlExternal PostgreSQL database URL (for Grafana persistence)
grafana_view_passwordpasswordGrafana metadb PG datasource password

NODE Parameters

NODE_ID parameter group defines node identity parameters, including node name, cluster name, and whether to borrow identity from PostgreSQL.

ParameterTypeDescription
nodenamestringNode instance identifier, uses hostname if missing, optional
node_clusterstringNode cluster identifier, uses ’nodes’ if missing, optional
nodename_overwriteboolOverwrite node hostname with nodename?
nodename_exchangeboolExchange nodename between playbook hosts?
node_id_from_pgboolBorrow postgres identity as node identity if possible?

NODE_DNS parameter group configures node DNS resolution, including static hosts records and dynamic DNS servers.

ParameterTypeDescription
node_write_etc_hostsboolModify /etc/hosts on target nodes?
node_default_etc_hostsstring[]Static DNS records in /etc/hosts
node_etc_hostsstring[]Extra static DNS records in /etc/hosts
node_dns_methodenumHow to handle existing DNS servers: add, none, overwrite
node_dns_serversstring[]Dynamic DNS server list in /etc/resolv.conf
node_dns_optionsstring[]DNS resolution options in /etc/resolv.conf

NODE_PACKAGE parameter group configures node software sources and package installation.

ParameterTypeDescription
node_repo_modulesenumWhich repo modules to enable on node? default local
node_repo_removeboolRemove existing repos on node when configuring node software repos?
node_packagesstring[]Packages to install on current node
node_default_packagesstring[]Default packages to install on all nodes

NODE_TUNE parameter group configures node kernel parameters, feature switches, and performance tuning templates.

ParameterTypeDescription
node_disable_numaboolDisable node NUMA, requires reboot
node_disable_swapboolDisable node Swap, use with caution
node_static_networkboolPreserve DNS resolver settings after reboot, i.e., static network, default enabled
node_disk_prefetchboolConfigure disk prefetch on HDD to improve performance
node_kernel_modulesstring[]Kernel modules to enable on this node
node_hugepage_countintNumber of 2MB hugepages allocated on host node, higher priority than ratio
node_hugepage_ratiofloatMemory hugepage ratio allocated on host node, 0 disables
node_overcommit_ratiofloatNode memory overcommit ratio (50-100), 0 disables
node_tuneenumNode tuning profile: none, oltp, olap, crit, tiny
node_sysctl_paramsdictExtra sysctl config parameters, k:v format

NODE_SEC parameter group configures node security options, including SELinux, firewall, etc.

ParameterTypeDescription
node_selinux_modeenumSELinux mode: disabled, permissive, enforcing
node_firewall_modeenumFirewall mode: off, none, zone
node_firewall_intranetcidr[]Intranet CIDR list for firewall rules
node_firewall_public_portport[]Public open port list, default [22, 80, 443, 5432]

NODE_ADMIN parameter group configures node admin user, data directory, and command aliases.

ParameterTypeDescription
node_datapathNode main data directory, default /data
node_admin_enabledboolCreate admin user on target node?
node_admin_uidintNode admin user uid and gid
node_admin_usernameusernameNode admin user name, default dba
node_admin_sudoenumAdmin user sudo privilege: limited, nopass, all, none
node_admin_ssh_exchangeboolExchange admin ssh keys between node clusters?
node_admin_pk_currentboolAdd current user’s ssh public key to admin’s authorized_keys?
node_admin_pk_liststring[]ssh public keys to add to admin user
node_aliasesdictShell alias commands to configure on host, KV dictionary

NODE_TIME parameter group configures node timezone, NTP time sync, and cron jobs.

ParameterTypeDescription
node_timezonestringSet host node timezone, empty string skips
node_ntp_enabledboolEnable chronyd time sync service?
node_ntp_serversstring[]NTP server list in /etc/chrony.conf
node_crontab_overwriteboolAppend or overwrite when writing /etc/crontab?
node_crontabstring[]Crontab entries in /etc/crontab

NODE_VIP parameter group configures node cluster L2 VIP, implemented by keepalived.

ParameterTypeDescription
vip_enabledboolEnable L2 VIP on this node cluster?
vip_addressipNode VIP address in ipv4 format, required when vip enabled
vip_vridintRequired integer 1-254, should be unique in same VLAN
vip_roleenumOptional, master/backup, default backup
vip_preemptboolOptional, true/false, default false, enable vip preemption
vip_interfacestringNode VIP network interface to listen, default eth0
vip_dns_suffixstringNode VIP DNS name suffix, default empty string
vip_auth_passpasswordVRRP auth password, auto-generated if empty
vip_exporter_portportkeepalived exporter listen port, default 9650

HAPROXY parameter group configures HAProxy load balancer and service exposure on nodes.

ParameterTypeDescription
haproxy_enabledboolEnable haproxy on this node?
haproxy_cleanboolClean all existing haproxy config?
haproxy_reloadboolReload haproxy after config?
haproxy_auth_enabledboolEnable haproxy admin page authentication?
haproxy_admin_usernameusernamehaproxy admin username, default admin
haproxy_admin_passwordpasswordhaproxy admin password, default pigsty
haproxy_exporter_portporthaproxy exporter port, default 9101
haproxy_client_timeoutintervalhaproxy client connection timeout, default 24h
haproxy_server_timeoutintervalhaproxy server connection timeout, default 24h
haproxy_servicesservice[]haproxy service list to expose on node

NODE_EXPORTER parameter group configures node monitoring exporter.

ParameterTypeDescription
node_exporter_enabledboolConfigure node_exporter on this node?
node_exporter_portportnode exporter listen port, default 9100
node_exporter_optionsargnode_exporter extra server options

VECTOR parameter group configures Vector log collector.

ParameterTypeDescription
vector_enabledboolEnable vector log collector?
vector_cleanboolClean vector data directory during init?
vector_datapathvector data directory, default /data/vector
vector_portportvector metrics listen port, default 9598
vector_read_fromenumvector reads logs from beginning or end
vector_log_endpointstring[]Log send destination endpoint, default sends to infra group

ETCD Parameters

ETCD parameter group is for etcd cluster deployment and configuration, including instance identity, cluster name, data directory, ports, and authentication password.

ParameterTypeDescription
etcd_seqintetcd instance identifier, required
etcd_clusterstringetcd cluster name, default fixed to etcd
etcd_learnerboolInitialize etcd instance as learner?
etcd_datapathetcd data directory, default /data/etcd
etcd_portportetcd client port, default 2379
etcd_peer_portportetcd peer port, default 2380
etcd_initenumetcd initial cluster state, new or existing
etcd_election_timeoutintetcd election timeout, default 1000ms
etcd_heartbeat_intervalintetcd heartbeat interval, default 100ms
etcd_root_passwordpasswordetcd root user password for RBAC authentication

ETCD_REMOVE parameter group controls etcd cluster removal behavior, including safeguard, data cleanup, and package uninstallation.

ParameterTypeDescription
etcd_safeguardbooletcd safeguard to prevent cleaning running etcd instance?
etcd_rm_databoolDelete etcd data when removing? default true
etcd_rm_pkgboolUninstall etcd package when removing? default false

REDIS Parameters

REDIS parameter group is for Redis cluster deployment and configuration, including identity, instance definitions, working mode, memory configuration, persistence, and monitoring.

ParameterTypeDescription
redis_clusterstringRedis database cluster name, required identity parameter
redis_instancesdictInstance definitions on Redis node
redis_nodeintRedis node number, positive integer, unique in cluster, required
redis_fs_mainpathRedis main data directory, default /data
redis_exporter_enabledboolRedis Exporter enabled?
redis_exporter_portportRedis Exporter listen port
redis_exporter_optionsstringRedis Exporter command arguments
redis_safeguardboolPrevent erasing existing Redis
redis_cleanboolErase existing instance when initializing Redis
redis_rmdataboolRemove data when removing Redis instance?
redis_modeenumRedis cluster mode: sentinel, cluster, standalone
redis_confstringRedis config file template, except sentinel
redis_bind_addressipRedis listen address, empty binds to host IP
redis_max_memorysizeRedis max available memory
redis_mem_policyenumRedis memory eviction policy
redis_passwordpasswordRedis password, empty disables password
redis_rdb_savestring[]Redis RDB save directives, empty array disables RDB
redis_aof_enabledboolRedis AOF enabled?
redis_rename_commandsdictRedis dangerous command rename list
redis_cluster_replicasintHow many replicas per master in Redis native cluster?
redis_sentinel_monitormaster[]Master list monitored by Redis sentinel, only for sentinel cluster

MINIO Parameters

MINIO parameter group is for MinIO cluster deployment and configuration, including identity, storage paths, ports, authentication credentials, and bucket/user provisioning.

ParameterTypeDescription
minio_seqintminio instance identifier, required
minio_clusterstringminio cluster name, default minio
minio_userusernameminio OS user, default minio
minio_httpsboolEnable HTTPS for MinIO? default true
minio_nodestringminio node name pattern
minio_datapathminio data directory, use {x...y} for multiple disks
minio_volumesstringminio core parameter, specifies member nodes and disks
minio_domainstringminio external domain, default sss.pigsty
minio_portportminio service port, default 9000
minio_admin_portportminio console port, default 9001
minio_access_keyusernameRoot access key, default minioadmin
minio_secret_keypasswordRoot secret key, default S3User.MinIO
minio_extra_varsstringExtra environment variables for minio server
minio_provisionboolExecute minio resource provisioning task? default true
minio_aliasstringminio deployment client alias
minio_endpointstringminio deployment client alias endpoint
minio_bucketsbucket[]minio buckets to create
minio_usersuser[]minio users to create

MINIO_REMOVE parameter group controls MinIO cluster removal behavior, including safeguard, data cleanup, and package uninstallation.

ParameterTypeDescription
minio_safeguardboolPrevent accidental deletion? default false
minio_rm_databoolDelete minio data when removing? default true
minio_rm_pkgboolUninstall minio package when removing? default false

FERRET Parameters

FERRET parameter group is for FerretDB deployment and configuration, including identity, underlying PostgreSQL connection, listen port, and SSL settings.

ParameterTypeDescription
mongo_seqintmongo instance number, required identity parameter
mongo_clusterstringmongo cluster name, required identity parameter
mongo_pgurlpgurlPGURL connection string for FerretDB backend
mongo_ssl_enabledboolEnable SSL? default false
mongo_listenipListen address, empty listens on all addresses
mongo_portportService port, default 27017
mongo_ssl_portportTLS listen port, default 27018
mongo_exporter_portportExporter port, default 9216
mongo_extra_varsstringExtra environment variables, default empty string

DOCKER Parameters

DOCKER parameter group is for Docker container engine deployment and configuration, including enable switch, data directory, storage driver, registry mirrors, and monitoring.

ParameterTypeDescription
docker_enabledboolEnable Docker on current node? default disabled
docker_datapathDocker data directory, default /data/docker
docker_storage_driverenumDocker storage driver, default overlay2
docker_cgroups_driverenumDocker CGroup filesystem driver: cgroupfs, systemd
docker_registry_mirrorsstring[]Docker registry mirror list
docker_exporter_portportDocker monitoring metrics export port, default 9323
docker_imagestring[]Docker images to pull, default empty list
docker_image_cachepathDocker image tarball path to import, default /tmp/docker/*.tgz

6.6 - Playbooks

Overview and navigation of Pigsty preset playbooks

Pigsty provides a series of Ansible playbooks for automated deployment and management of various modules. This page provides navigation and summary of all playbooks.


Module Navigation

ModuleDescription
INFRA3Infrastructure module playbooks
NODE2Node management module playbooks
ETCD2ETCD cluster management playbooks
PGSQL7PostgreSQL cluster management playbooks
REDIS2Redis cluster management playbooks
MINIO2MinIO object storage management playbooks
FERRET1FerretDB management playbook
DOCKER1Docker management playbook

Playbook Summary

The following table lists all available preset playbooks in Pigsty:

PlaybookModuleFunction
deploy.ymlADMINDeploy pigsty on current environment
infra.ymlINFRAInitialize pigsty infrastructure on infra nodes
infra-rm.ymlINFRARemove infrastructure components from infra nodes
node.ymlNODEManage nodes, adjust nodes to desired state
node-rm.ymlNODERemove managed nodes from Pigsty
etcd.ymlETCDInstall and configure Etcd cluster
etcd-rm.ymlETCDRemove Etcd cluster or members
pgsql.ymlPGSQLInitialize PostgreSQL cluster or add new replicas
pgsql-rm.ymlPGSQLRemove PostgreSQL cluster or instance
pgsql-user.ymlPGSQLAdd new business users to existing PostgreSQL cluster
pgsql-db.ymlPGSQLAdd new business databases to existing PostgreSQL cluster
pgsql-monitor.ymlPGSQLMonitor remote PostgreSQL instances
pgsql-migration.ymlPGSQLGenerate migration manuals and scripts for existing PostgreSQL clusters
pgsql-pitr.ymlPGSQLExecute PostgreSQL Point-in-Time Recovery (PITR)
redis.ymlREDISInitialize Redis cluster/node/instance
redis-rm.ymlREDISRemove Redis cluster/node/instance
minio.ymlMINIOInstall MinIO cluster
minio-rm.ymlMINIORemove MinIO cluster
mongo.ymlFERRETInstall FerretDB on nodes
docker.ymlDOCKERInstall Docker Daemon and Docker Compose

Playbook Usage Notes

Protection Mechanism

Multiple modules provide deletion protection through *_safeguard parameters:

  • PGSQL: pg_safeguard prevents accidental deletion of PostgreSQL clusters
  • ETCD: etcd_safeguard prevents accidental deletion of Etcd clusters
  • MINIO: minio_safeguard prevents accidental deletion of MinIO clusters

By default, these safeguard parameters are not enabled (undefined). It’s recommended to explicitly set them to true for initialized clusters in production environments.

When the protection switch is set to true, the corresponding *-rm.yml playbook will abort immediately. You can force override through command-line parameters:

./pgsql-rm.yml -l pg-test -e pg_safeguard=false
./etcd-rm.yml -e etcd_safeguard=false
./minio-rm.yml -l minio -e minio_safeguard=false

Limiting Execution Scope

When executing playbooks, it’s recommended to use the -l parameter to limit the execution scope:

./pgsql.yml -l pg-meta            # Limit execution to pg-meta cluster
./node.yml -l 10.10.10.10         # Limit execution to specific node
./redis.yml -l redis-test         # Limit execution to redis-test cluster

Idempotency

Most playbooks are idempotent and can be executed repeatedly. However, note:

  • infra.yml does not clear data by default and can be safely re-executed. All clean parameters (vmetrics_clean, vlogs_clean, vtraces_clean, grafana_clean, nginx_clean) default to false
  • To clear infrastructure data for rebuild, you need to explicitly set the corresponding clean parameter to true
  • Be extra careful when repeatedly executing *-rm.yml deletion playbooks

Task Tags

You can use the -t parameter to execute only specific task subsets:

./pgsql.yml -l pg-test -t pg_service    # Only refresh pg-test cluster services
./node.yml -t haproxy                   # Only set up haproxy on nodes
./etcd.yml -t etcd_launch               # Only restart etcd service

Quick Command Reference

./deploy.yml                     # One-pass deployment

INFRA Module

./infra.yml                      # Initialize infrastructure
./infra-rm.yml                   # Remove infrastructure

NODE Module

./node.yml -l <cls|ip>           # Add node
./node-rm.yml -l <cls|ip>        # Remove node
bin/node-add <cls|ip>            # Add node (wrapper script)
bin/node-rm <cls|ip>             # Remove node (wrapper script)

ETCD Module

./etcd.yml                       # Initialize etcd cluster
./etcd-rm.yml                    # Remove etcd cluster
bin/etcd-add <ip>                # Add etcd member (wrapper script)
bin/etcd-rm <ip>                 # Remove etcd member (wrapper script)

PGSQL Module

./pgsql.yml -l <cls>                            # Initialize PostgreSQL cluster
./pgsql-rm.yml -l <cls>                         # Remove PostgreSQL cluster
./pgsql-user.yml -l <cls> -e username=<user>    # Create business user
./pgsql-db.yml -l <cls> -e dbname=<db>          # Create business database
./pgsql-monitor.yml -e clsname=<cls>            # Monitor remote cluster
./pgsql-pitr.yml -l <cls> -e '{"pg_pitr": {}}'  # Execute PITR recovery
bin/pgsql-add <cls>              # Initialize cluster (wrapper script)
bin/pgsql-rm <cls>               # Remove cluster (wrapper script)
bin/pgsql-user <cls> <user>      # Create user (wrapper script)
bin/pgsql-db <cls> <db>          # Create database (wrapper script)

REDIS Module

./redis.yml -l <cls>             # Initialize Redis cluster
./redis-rm.yml -l <cls>          # Remove Redis cluster

MINIO Module

./minio.yml -l <cls>             # Initialize MinIO cluster
./minio-rm.yml -l <cls>          # Remove MinIO cluster

FERRET Module

./mongo.yml -l ferret            # Install FerretDB

DOCKER Module

./docker.yml -l <host>           # Install Docker

6.7 - Port List

Default ports used by Pigsty components, with related parameters and status.

This page lists default ports used by Pigsty module components. Adjust as needed or use as a reference for fine-grained firewall configuration.

ModuleComponentPortParameterStatus
NODEnode_exporter9100node_exporter_portEnabled
NODEhaproxy9101haproxy_exporter_portEnabled
NODEvector9598vector_portEnabled
NODEkeepalived_exporter9650vip_exporter_portOptional
NODEchronyd123-Enabled
DOCKERdocker9323docker_exporter_portOptional
INFRAnginx80nginx_portEnabled
INFRAnginx443nginx_ssl_portEnabled
INFRAgrafana3000grafana_portEnabled
INFRAvictoriaMetrics8428vmetrics_portEnabled
INFRAvictoriaLogs9428vlogs_portEnabled
INFRAvictoriaTraces10428vtraces_portEnabled
INFRAvmalert8880vmalert_portEnabled
INFRAalertmanager9059alertmanager_portEnabled
INFRAblackbox_exporter9115blackbox_portEnabled
INFRAdnsmasq53dns_portEnabled
ETCDetcd2379etcd_portEnabled
ETCDetcd2380etcd_peer_portEnabled
MINIOminio9000minio_portEnabled
MINIOminio9001minio_admin_portEnabled
REDISredis6379redis_portOptional
REDISredis_exporter9121redis_exporter_portOptional
FERRETferretdb27017mongo_portOptional
FERRETmongo_exporter9216mongo_exporter_portEnabled
PGSQLpostgres5432pg_portEnabled
PGSQLpgbouncer6432pgbouncer_portEnabled
PGSQLpatroni8008patroni_portEnabled
PGSQLpg_exporter9630pg_exporter_portEnabled
PGSQLpgbouncer_exporter9631pgbouncer_exporter_portEnabled
PGSQLpgbackrest_exporter9854pgbackrest_exporter_portEnabled
PGSQL{{ pg_cluster }}-primary5433pg_default_servicesEnabled
PGSQL{{ pg_cluster }}-replica5434pg_default_servicesEnabled
PGSQL{{ pg_cluster }}-default5436pg_default_servicesEnabled
PGSQL{{ pg_cluster }}-offline5438pg_default_servicesEnabled
PGSQL{{ pg_cluster }}-<service>543xpg_servicesOptional

7 - Applications

Software and tools that use PostgreSQL can be managed by the docker daemon

PostgreSQL is the most popular database in the world, and countless software is built on PostgreSQL, around PostgreSQL, or serves PostgreSQL itself, such as

  • Application software” that uses PostgreSQL as the preferred database
  • Tooling software” that serves PostgreSQL software development and management
  • Database software” that derives, wraps, forks, modifies, or extends PostgreSQL

And Pigsty just have a series of Docker Compose templates for these software, application and databases:

NameWebsiteTypeStatePortDomainDescription
SupabaseSupabaseDBGA8000supa.pigstyOSS Firebase Alternative, Backend as Platform
PolarDBPolarDBDBGA5532OSS RAC for PostgreSQL
FerretDBFerretDBDBGA27017OSS Mongo Alternative base on PostgreSQL
MinIOMinIODBGA9000sss.pigstyOSS AWS S3 Alternative, Simple Storage Service
EdgeDBEdgeDBDBTBDOSS Graph Database base on PostgreSQL
NocoDBNocoDBAPPGA8080noco.pigstyOSS Airtable Alternative over PostgreSQL
OdooOdooAPPGA8069odoo.pigstyOSS ERP Software base on PostgreSQL
DifyDifyAPPGA8001dify.pigstyOSS AI Workflow Orachestration & LLMOps Platform
JupyterJupyterAPPGAlab.pigstyOSS AI Python Notebook & Data Analysis IDE
GiteaGiteaAPPGA8889git.pigstyOSS DevOps Git Service
WikiWiki.jsAPPGA9002wiki.pigstyOSS Wiki Software
GitLabGitLabAPPTBDOSS GitHub Alternative, Code Management Platform
MastodonMastodonAPPTBDOSS Decentralized Social Network
KeycloakKeycloakAPPTBDOSS Identity & Access Management Component
HarbourHarbourAPPTBDOSS Docker/K8S Image Repository
ConfluenceConfluenceAPPTBDEnterprise Knowledge Management System
JiraJiraAPPTBDEnterprise Project Management Tools
ZabbixZabbix 7APPTBDOSS Monitoring Platform for Enterprise
GrafanaGrafanaAPPTBDDashboard, Data Visualization & Monitoring Platform
MetabaseMetabaseAPPGA9004mtbs.pigstyFast analysis of data from multiple data sources
ByteBaseByteBaseAPPGA8887ddl.pigstyDatabase Migration Tool for PostgreSQL
KongKongTOOLGA8000api.pigstyOSS API Gateway based on Nginx/OpenResty
PostgRESTPostgRESTTOOLGA8884api.pigstyGenerate RESTAPI from PostgreSQL Schemas
pgAdmin4pgAdmin4TOOLGA8885adm.pigstyPostgreSQL GUI Admin Tools
pgWebpgWebTOOLGA8886cli.pigstyPostgreSQL Web GUI Client
SchemaSpySchemaSpyTOOLTBDDump & Visualize PostgreSQL Schema
pgBadgerpgBadgerTOOLTBDPostgreSQL Log Analysis
pg_exporterpg_exporterTOOLGA9630Expose PostgreSQL & Pgbouncer Metrics for Prometheus

7.1 - Enterprise Self-Hosted Supabase

Self-host enterprise-grade Supabase with Pigsty, featuring monitoring, high availability, PITR, IaC, and 440+ PostgreSQL extensions.

Supabase is great, but having your own Supabase is even better. Pigsty can help you deploy enterprise-grade Supabase on your own servers (physical, virtual, or cloud) with a single command — more extensions, better performance, deeper control, and more cost-effective.

Pigsty is one of three self-hosting approaches listed on the Supabase official documentation: Self-hosting: Third-Party Guides


TL;DR

Prepare a Linux server, follow the Pigsty standard installation process with the supabase configuration template:

curl -fsSL https://repo.pigsty.cc/get | bash; cd ~/pigsty
./configure -c supabase    # Use supabase config (change credentials in pigsty.yml)
vi pigsty.yml              # Edit domain, passwords, keys...
./deploy.yml               # Install Pigsty
./docker.yml               # Install Docker Compose components
./app.yml                  # Start Supabase stateless components with Docker (may take time)

After installation, access Supa Studio on port 8000 with username supabase and password pigsty.


Table of Contents


What is Supabase?

Supabase is a BaaS (Backend as a Service), an open-source Firebase alternative, and the most popular database + backend solution in the AI Agent era. Supabase wraps PostgreSQL and provides authentication, messaging, edge functions, object storage, and automatically generates REST and GraphQL APIs based on your database schema.

Supabase aims to provide developers with a one-stop backend solution, reducing the complexity of developing and maintaining backend infrastructure. It allows developers to skip most backend development work — you only need to understand database design and frontend to ship quickly! Developers can use vibe coding to create a frontend and database schema to rapidly build complete applications.

Currently, Supabase is the most popular open-source project in the PostgreSQL ecosystem, with over 90,000 GitHub stars. Supabase also offers a “generous” free tier for small startups — free 500 MB storage, more than enough for storing user tables and analytics data.


Why Self-Host?

If Supabase cloud is so attractive, why self-host?

The most obvious reason is what we discussed in “Is Cloud Database an IQ Tax?”: when your data/compute scale exceeds the cloud computing sweet spot (Supabase: 4C/8G/500MB free storage), costs can explode. And nowadays, reliable local enterprise NVMe SSDs have three to four orders of magnitude cost advantage over cloud storage, and self-hosting can better leverage this.

Another important reason is functionality — Supabase cloud features are limited. Many powerful PostgreSQL extensions aren’t available in cloud services due to multi-tenant security challenges and licensing. Despite extensions being PostgreSQL’s core feature, only 64 extensions are available on Supabase cloud. Self-hosted Supabase with Pigsty provides up to 440 ready-to-use PostgreSQL extensions.

Additionally, self-control and vendor lock-in avoidance are important reasons for self-hosting. Although Supabase aims to provide a vendor-lock-free open-source Google Firebase alternative, self-hosting enterprise-grade Supabase is not trivial. Supabase includes a series of PostgreSQL extensions they develop and maintain, and plans to replace the native PostgreSQL kernel with OrioleDB (which they acquired). These kernels and extensions are not available in the official PGDG repository.

This is implicit vendor lock-in, preventing users from self-hosting in ways other than the supabase/postgres Docker image. Pigsty provides an open, transparent, and universal solution. We package all 10 missing Supabase extensions into ready-to-use RPM/DEB packages, ensuring they work on all major Linux distributions:

ExtensionDescription
pg_graphqlGraphQL support in PostgreSQL (Rust), provided by PIGSTY
pg_jsonschemaJSON Schema validation (Rust), provided by PIGSTY
wrappersSupabase foreign data wrapper bundle (Rust), provided by PIGSTY
index_advisorQuery index advisor (SQL), provided by PIGSTY
pg_netAsync non-blocking HTTP/HTTPS requests (C), provided by PIGSTY
vaultStore encrypted credentials in Vault (C), provided by PIGSTY
pgjwtJSON Web Token API implementation (SQL), provided by PIGSTY
pgsodiumTable data encryption TDE, provided by PIGSTY
supautilsSecurity utilities for cloud environments (C), provided by PIGSTY
pg_plan_filterFilter queries by execution plan cost (C), provided by PIGSTY

We also install most extensions by default in Supabase deployments. You can enable them as needed.

Pigsty also handles the underlying highly available PostgreSQL cluster, highly available MinIO object storage cluster, and even Docker deployment, Nginx reverse proxy, domain configuration, and HTTPS certificate issuance. You can spin up any number of stateless Supabase container clusters using Docker Compose and store state in external Pigsty-managed database services.

With this self-hosted architecture, you gain the freedom to use different kernels (PG 15-18, OrioleDB), install 437 extensions, scale Supabase/Postgres/MinIO, freedom from database operations, and freedom from vendor lock-in — running locally forever. Compared to cloud service costs, you only need to prepare servers and run a few commands.


Single-Node Quick Start

Let’s start with single-node Supabase deployment. We’ll cover multi-node high availability later.

Prepare a fresh Linux server, use the Pigsty supabase configuration template for standard installation, then run docker.yml and app.yml to start stateless Supabase containers (default ports 8000/8433).

curl -fsSL https://repo.pigsty.cc/get | bash; cd ~/pigsty
./configure -c supabase    # Use supabase config (change credentials in pigsty.yml)
vi pigsty.yml              # Edit domain, passwords, keys...
./deploy.yml               # Install Pigsty
./docker.yml               # Install Docker Compose components
./app.yml                  # Start Supabase stateless components with Docker

Before deploying Supabase, modify the auto-generated pigsty.yml configuration file (domain and passwords) according to your needs. For local development/testing, you can skip this and customize later.

If configured correctly, after about ten minutes, you can access the Supabase Studio GUI at http://<your_ip_address>:8000 on your local network. Default username and password are supabase and pigsty.

Notes:

  • In mainland China, Pigsty uses 1Panel and 1ms DockerHub mirrors by default, which may be slow.
  • You can configure your own proxy and registry mirror, then manually pull images with cd /opt/supabase; docker compose pull. We also offer expert consulting services including complete offline installation packages.
  • If you need object storage functionality, you must access Supabase via domain and HTTPS, otherwise errors will occur.
  • For serious production deployments, always change all default passwords!

Key Technical Decisions

Here are some key technical decisions for self-hosting Supabase:

Single-node deployment doesn’t provide PostgreSQL/MinIO high availability. However, single-node deployment still has significant advantages over the official pure Docker Compose approach: out-of-the-box monitoring, freedom to install extensions, component scaling capabilities, and point-in-time recovery as a safety net.

If you only have one server or choose to self-host on cloud servers, Pigsty recommends using external S3 instead of local MinIO for object storage to hold PostgreSQL backups and Supabase Storage. This deployment provides a minimum safety net RTO (hour-level recovery time) / RPO (MB-level data loss) disaster recovery in single-node conditions.

For serious production deployments, Pigsty recommends at least 3-4 nodes, ensuring both MinIO and PostgreSQL use enterprise-grade multi-node high availability deployments. You’ll need more nodes and disks, adjusting cluster configuration in pigsty.yml and Supabase cluster configuration to use high availability endpoints.

Some Supabase features require sending emails, so SMTP service is needed. Unless purely for internal use, production deployments should use SMTP cloud services. Self-hosted mail servers’ emails are often marked as spam.

If your service is directly exposed to the public internet, we strongly recommend using real domain names and HTTPS certificates via Nginx Portal.

Next, we’ll discuss advanced topics for improving Supabase security, availability, and performance beyond single-node deployment.


Advanced: Security Hardening

Pigsty Components

For serious production deployments, we strongly recommend changing Pigsty component passwords. These defaults are public and well-known — going to production without changing passwords is like running naked:

These are Pigsty component passwords. Strongly recommended to set before installation.

Supabase Keys

Besides Pigsty component passwords, you need to change Supabase keys, including:

Please follow the Supabase tutorial: Securing your services:

  • Generate a JWT_SECRET with at least 40 characters, then use the tutorial tools to issue ANON_KEY and SERVICE_ROLE_KEY JWTs.
  • Use the tutorial tools to generate an ANON_KEY JWT based on JWT_SECRET and expiration time — this is the anonymous user credential.
  • Use the tutorial tools to generate a SERVICE_ROLE_KEY — this is the higher-privilege service role credential.
  • Specify a random string of at least 32 characters for PG_META_CRYPTO_KEY to encrypt Studio UI and meta service interactions.
  • If using different PostgreSQL business user passwords, modify POSTGRES_PASSWORD accordingly.
  • If your object storage uses different passwords, modify S3_ACCESS_KEY and S3_SECRET_KEY accordingly.

After modifying Supabase credentials, restart Docker Compose to apply:

./app.yml -t app_config,app_launch   # Using playbook
cd /opt/supabase; make up            # Manual execution

Advanced: Domain Configuration

If using Supabase locally or on LAN, you can directly connect to Kong’s HTTP port 8000 via IP:Port.

You can use an internal static-resolved domain, but for serious production deployments, we recommend using a real domain + HTTPS to access Supabase. In this case, your server should have a public IP, you should own a domain, use cloud/DNS/CDN provider’s DNS resolution to point to the node’s public IP (optional fallback: local /etc/hosts static resolution).

The simple approach is to batch-replace the placeholder domain (supa.pigsty) with your actual domain, e.g., supa.pigsty.cc:

sed -ie 's/supa.pigsty/supa.pigsty.cc/g' ~/pigsty/pigsty.yml

If not configured beforehand, reload Nginx and Supabase configuration:

make cert       # Request certbot free HTTPS certificate
./app.yml       # Reload Supabase configuration

The modified configuration should look like:

all:
  vars:
    certbot_sign: true                # Use certbot to sign real certificates
    infra_portal:
      home: i.pigsty.cc               # Replace with your domain!
      supa:
        domain: supa.pigsty.cc        # Replace with your domain!
        endpoint: "10.10.10.10:8000"
        websocket: true
        certbot: supa.pigsty.cc       # Certificate name, usually same as domain

  children:
    supabase:
      vars:
        apps:
          supabase:                                         # Supabase app definition
            conf:                                           # Override /opt/supabase/.env
              SITE_URL: https://supa.pigsty.cc              # <------- Change to your external domain name
              API_EXTERNAL_URL: https://supa.pigsty.cc      # <------- Otherwise the storage API may not work!
              SUPABASE_PUBLIC_URL: https://supa.pigsty.cc   # <------- Don't forget to set this in infra_portal!

For complete domain/HTTPS configuration, see Certificate Management. You can also use Pigsty’s built-in local static resolution and self-signed HTTPS certificates as fallback.


Advanced: External Object Storage

You can use S3 or S3-compatible services for PostgreSQL backups and Supabase object storage. Here we use Alibaba Cloud OSS as an example.

Pigsty provides a terraform/spec/aliyun-s3.tf template for provisioning a server and OSS bucket on Alibaba Cloud.

First, modify the S3 configuration in all.children.supa.vars.apps.[supabase].conf to point to Alibaba Cloud OSS:

# if using s3/minio as file storage
S3_BUCKET: data                       # Replace with S3-compatible service info
S3_ENDPOINT: https://sss.pigsty:9000  # Replace with S3-compatible service info
S3_ACCESS_KEY: s3user_data            # Replace with S3-compatible service info
S3_SECRET_KEY: S3User.Data            # Replace with S3-compatible service info
S3_FORCE_PATH_STYLE: true             # Replace with S3-compatible service info
S3_REGION: stub                       # Replace with S3-compatible service info
S3_PROTOCOL: https                    # Replace with S3-compatible service info

Reload Supabase configuration:

./app.yml -t app_config,app_launch

You can also use S3 as PostgreSQL backup repository. Add an aliyun backup repository definition in all.vars.pgbackrest_repo:

all:
  vars:
    pgbackrest_method: aliyun          # pgbackrest backup method: local,minio,[user-defined repos...]
    pgbackrest_repo:                   # pgbackrest backup repo: https://pgbackrest.org/configuration.html#section-repository
      aliyun:                          # Define new backup repo 'aliyun'
        type: s3                       # Alibaba Cloud OSS is S3-compatible
        s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
        s3_region: oss-cn-beijing
        s3_bucket: pigsty-oss
        s3_key: xxxxxxxxxxxxxx
        s3_key_secret: xxxxxxxx
        s3_uri_style: host
        path: /pgbackrest
        bundle: y                         # bundle small files into a single file
        bundle_limit: 20MiB               # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB               # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc          # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest.MyPass    # Set encryption password for pgBackRest backup repo
        retention_full_type: time         # retention full backup by time on minio repo
        retention_full: 14                # keep full backup for the last 14 days

Then specify aliyun backup repository in all.vars.pgbackrest_method and reset pgBackrest:

./pgsql.yml -t pgbackrest

Pigsty will switch the backup repository to external object storage. For more backup configuration, see PostgreSQL Backup.


Advanced: Using SMTP

You can use SMTP for sending emails. Modify the supabase app configuration with SMTP information:

all:
  children:
    supabase:        # supa group
      vars:          # supa group vars
        apps:        # supa group app list
          supabase:  # the supabase app
            conf:    # the supabase app conf entries
              SMTP_HOST: smtpdm.aliyun.com:80
              SMTP_PORT: 80
              SMTP_USER: [email protected]
              SMTP_PASS: your_email_user_password
              SMTP_SENDER_NAME: MySupabase
              SMTP_ADMIN_EMAIL: [email protected]
              ENABLE_ANONYMOUS_USERS: false

Don’t forget to reload configuration with app.yml.


Advanced: True High Availability

After these configurations, you have enterprise-grade Supabase with public domain, HTTPS certificate, SMTP, PITR backup, monitoring, IaC, and 400+ extensions (basic single-node version). For high availability configuration, see other Pigsty documentation. We offer expert consulting services for hands-on Supabase self-hosting — $400 USD to save you the hassle.

Single-node RTO/RPO relies on external object storage as a safety net. If your node fails, backups in external S3 storage let you redeploy Supabase on a new node and restore from backup. This provides minimum safety net RTO (hour-level recovery) / RPO (MB-level data loss) disaster recovery.

For RTO < 30s with zero data loss on failover, use multi-node high availability deployment:

  • ETCD: DCS needs three or more nodes to tolerate one node failure.
  • PGSQL: PostgreSQL synchronous commit (no data loss) mode recommends at least three nodes.
  • INFRA: Monitoring infrastructure failure has less impact; production recommends dual replicas.
  • Supabase stateless containers can also be multi-node replicas for high availability.

In this case, you also need to modify PostgreSQL and MinIO endpoints to use DNS / L2 VIP / HAProxy high availability endpoints. For these parts, follow the documentation for each Pigsty module. Reference conf/ha/trio.yml and conf/ha/safe.yml for upgrading to three or more nodes.

7.2 - Odoo: Self-Hosted Open Source ERP

How to spin up an out-of-the-box enterprise application suite Odoo and use Pigsty to manage its backend PostgreSQL database.

Odoo is an open-source enterprise resource planning (ERP) software that provides a full suite of business applications, including CRM, sales, purchasing, inventory, production, accounting, and other management functions. Odoo is a typical web application that uses PostgreSQL as its underlying database.

All your business on one platform — Simple, efficient, yet affordable

Public Demo (may not always be available): http://odoo.pigsty.io, username: [email protected], password: pigsty


Quick Start

On a fresh Linux x86/ARM server running a compatible operating system:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap                # Install Ansible
./configure -c app/odoo    # Use Odoo configuration (change credentials in pigsty.yml)
./deploy.yml               # Install Pigsty
./docker.yml               # Install Docker Compose
./app.yml                  # Start Odoo stateless components with Docker

Odoo listens on port 8069 by default. Access http://<ip>:8069 in your browser. The default username and password are both admin.

You can add a DNS resolution record odoo.pigsty pointing to your server in the browser host’s /etc/hosts file, allowing you to access the Odoo web interface via http://odoo.pigsty.

If you want to access Odoo via SSL/HTTPS, you need to use a real SSL certificate or trust the self-signed CA certificate automatically generated by Pigsty. (In Chrome, you can also type thisisunsafe to bypass certificate verification)


Configuration Template

conf/app/odoo.yml defines a template configuration file containing the resources required for a single Odoo instance.

all:
  children:

    # Odoo application (default username and password: admin/admin)
    odoo:
      hosts: { 10.10.10.10: {} }
      vars:
        app: odoo   # Specify app name to install (in apps)
        apps:       # Define all applications
          odoo:     # App name, should have corresponding ~/pigsty/app/odoo folder
            file:   # Optional directories to create
              - { path: /data/odoo         ,state: directory, owner: 100, group: 101 }
              - { path: /data/odoo/webdata ,state: directory, owner: 100, group: 101 }
              - { path: /data/odoo/addons  ,state: directory, owner: 100, group: 101 }
            conf:   # Override /opt/<app>/.env config file
              PG_HOST: 10.10.10.10            # PostgreSQL host
              PG_PORT: 5432                   # PostgreSQL port
              PG_USERNAME: odoo               # PostgreSQL user
              PG_PASSWORD: DBUser.Odoo        # PostgreSQL password
              ODOO_PORT: 8069                 # Odoo app port
              ODOO_DATA: /data/odoo/webdata   # Odoo webdata
              ODOO_ADDONS: /data/odoo/addons  # Odoo plugins
              ODOO_DBNAME: odoo               # Odoo database name
              ODOO_VERSION: 19.0              # Odoo image version

    # Odoo database
    pg-odoo:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-odoo
        pg_users:
          - { name: odoo    ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_admin ] ,createdb: true ,comment: admin user for odoo service }
          - { name: odoo_ro ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_readonly ]  ,comment: read only user for odoo service  }
          - { name: odoo_rw ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_readwrite ] ,comment: read write user for odoo service }
        pg_databases:
          - { name: odoo ,owner: odoo ,revokeconn: true ,comment: odoo main database  }
        pg_hba_rules:
          - { user: all ,db: all ,addr: 172.17.0.0/16  ,auth: pwd ,title: 'allow access from local docker network' }
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # Full backup daily at 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # Global variables
    version: v4.0.0                   # Pigsty version string
    admin_ip: 10.10.10.10             # Admin node IP address
    region: default                   # Upstream mirror region: default|china|europe
    node_tune: oltp                   # Node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # PGSQL tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # Enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # Global proxy env for downloading packages & pulling docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345   # Add proxy env here for downloading packages or pulling images
      #https_proxy: 127.0.0.1:12345   # Usually format is http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                      # Domain names and upstream servers
      home  : { domain: i.pigsty }
      minio : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      odoo:                            # Nginx server config for odoo
        domain: odoo.pigsty            # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:8069"   # Odoo service endpoint: IP:PORT
        websocket: true                # Add websocket support
        certbot: odoo.pigsty           # Certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18

    #----------------------------------#
    # Credentials: MUST CHANGE THESE!
    #----------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root

Basics

Check the configurable environment variables in the .env file:

# https://hub.docker.com/_/odoo#
PG_HOST=10.10.10.10
PG_PORT=5432
PG_USER=dbuser_odoo
PG_PASS=DBUser.Odoo
ODOO_PORT=8069

Then start Odoo with:

make up  # docker compose up

Access http://odoo.pigsty or http://10.10.10.10:8069

Makefile

make up         # Start Odoo with docker compose in minimal mode
make run        # Start Odoo with docker, local data directory and external PostgreSQL
make view       # Print Odoo access endpoints
make log        # tail -f Odoo logs
make info       # Inspect Odoo with jq
make stop       # Stop Odoo container
make clean      # Remove Odoo container
make pull       # Pull latest Odoo image
make rmi        # Remove Odoo image
make save       # Save Odoo image to /tmp/docker/odoo.tgz
make load       # Load Odoo image from /tmp/docker/odoo.tgz

Using External PostgreSQL

You can use external PostgreSQL for Odoo. Odoo will create its own database during setup, so you don’t need to do that.

pg_users: [ { name: dbuser_odoo ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_admin ]    ,comment: admin user for odoo database } ]
pg_databases: [ { name: odoo ,owner: dbuser_odoo ,revokeconn: true ,comment: odoo primary database } ]

Create the business user and database with:

bin/pgsql-user  pg-meta  dbuser_odoo
#bin/pgsql-db    pg-meta  odoo     # Odoo will create the database during setup

Check connectivity:

psql postgres://dbuser_odoo:[email protected]:5432/odoo

Expose Odoo Service

Expose the Odoo web service via Nginx portal:

    infra_portal:                     # Domain names and upstream servers
      home         : { domain: h.pigsty }
      grafana      : { domain: g.pigsty    ,endpoint: "${admin_ip}:3000" , websocket: true }
      prometheus   : { domain: p.pigsty    ,endpoint: "${admin_ip}:9058" }
      alertmanager : { domain: a.pigsty    ,endpoint: "${admin_ip}:9059" }
      blackbox     : { endpoint: "${admin_ip}:9115" }
      loki         : { endpoint: "${admin_ip}:3100" }
      odoo         : { domain: odoo.pigsty, endpoint: "127.0.0.1:8069", websocket: true }  # <------ Add this line
./infra.yml -t nginx   # Setup nginx infra portal

Odoo Addons

There are many Odoo modules available in the community. You can install them by downloading and placing them in the addons folder.

volumes:
  - ./addons:/mnt/extra-addons

You can mount the ./addons directory to /mnt/extra-addons in the container, then download and extract addons to the addons folder.

To enable addon modules, first enter Developer mode:

Settings -> General Settings -> Developer Tools -> Activate the developer mode

Then go to Apps -> Update Apps List, and you’ll find the extra addons available to install from the panel.

Frequently used free addons: Accounting Kit


Demo

Check the public demo: http://odoo.pigsty.io, username: [email protected], password: pigsty

If you want to access Odoo via SSL, you must trust files/pki/ca/ca.crt in your browser (or use the dirty hack thisisunsafe in Chrome).

7.3 - Dify: AI Workflow Platform

How to self-host the AI Workflow LLMOps platform — Dify, using external PostgreSQL, PGVector, and Redis for storage with Pigsty?

Dify is a Generative AI Application Innovation Engine and open-source LLM application development platform. It provides capabilities from Agent building to AI workflow orchestration, RAG retrieval, and model management, helping users easily build and operate generative AI native applications.

Pigsty provides support for self-hosted Dify, allowing you to deploy Dify with a single command while storing critical state in externally managed PostgreSQL. You can use pgvector as a vector database in the same PostgreSQL instance, further simplifying deployment.

Current Pigsty v4.0 supported Dify version: v1.8.1


Quick Start

On a fresh Linux x86/ARM server running a compatible operating system:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap                # Install Pigsty dependencies
./configure -c app/dify    # Use Dify configuration template
vi pigsty.yml              # Edit passwords, domains, keys, etc.

./deploy.yml               # Install Pigsty
./docker.yml               # Install Docker and Compose
./app.yml                  # Install Dify

Dify listens on port 5001 by default. Access http://<ip>:5001 in your browser and set up your initial user credentials to log in.

Once Dify starts, you can install various extensions, configure system models, and start using it!


Why Self-Host

There are many reasons to self-host Dify, but the primary motivation is data security. The Docker Compose template provided by Dify uses basic default database images, lacking enterprise features like high availability, disaster recovery, monitoring, IaC, and PITR capabilities.

Pigsty elegantly solves these issues for Dify, deploying all components with a single command based on configuration files and using mirrors to address China region access challenges. This makes Dify deployment and delivery very smooth. It handles PostgreSQL primary database, PGVector vector database, MinIO object storage, Redis, Prometheus monitoring, Grafana visualization, Nginx reverse proxy, and free HTTPS certificates all at once.

Pigsty ensures all Dify state is stored in externally managed services, including metadata in PostgreSQL and other data in the file system. Dify instances launched via Docker Compose become stateless applications that can be destroyed and rebuilt at any time, greatly simplifying operations.


Installation

Let’s start with single-node Dify deployment. We’ll cover production high-availability deployment methods later.

First, use Pigsty’s standard installation process to install the PostgreSQL instance required by Dify:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap               # Prepare Pigsty dependencies
./configure -c app/dify   # Use Dify application template
vi pigsty.yml             # Edit configuration file, modify domains and passwords
./deploy.yml              # Install Pigsty and various databases

When you use the ./configure -c app/dify command, Pigsty automatically generates a configuration file based on the conf/app/dify.yml template and your current environment. You should modify passwords, domains, and other relevant parameters in the generated pigsty.yml configuration file according to your needs, then run ./deploy.yml to execute the standard installation process.

Next, run docker.yml to install Docker and Docker Compose, then use app.yml to complete Dify deployment:

./docker.yml              # Install Docker and Docker Compose
./app.yml                 # Deploy Dify stateless components with Docker

You can access the Dify Web admin interface at http://<your_ip_address>:5001 on your local network.

The first login will prompt you to set up default username, email, and password.

You can also use the locally resolved placeholder domain dify.pigsty, or follow the configuration below to use a real domain with an HTTPS certificate.


Configuration

When you use the ./configure -c app/dify command for configuration, Pigsty automatically generates a configuration file based on the conf/app/dify.yml template and your current environment. Here’s a detailed explanation of the default configuration:

---
#==============================================================#
# File      :   dify.yml
# Desc      :   pigsty config for running 1-node dify app
# Ctime     :   2025-02-24
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/app/odoo
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#
# Last Verified Dify Version: v1.8.1 on 2025-0908
# tutorial: https://doc.pgsty.com/app/dify
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap               # prepare local repo & ansible
# ./configure -c app/dify   # use this dify config template
# vi pigsty.yml             # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml              # install pigsty & pgsql & minio
# ./docker.yml              # install docker & docker-compose
# ./app.yml                 # install dify with docker-compose
#
# To replace domain name:
#   sed -ie 's/dify.pigsty/dify.pigsty.cc/g' pigsty.yml


all:
  children:

    # the dify application
    dify:
      hosts: { 10.10.10.10: {} }
      vars:
        app: dify   # specify app name to be installed (in the apps)
        apps:       # define all applications
          dify:     # app name, should have corresponding ~/pigsty/app/dify folder
            file:   # data directory to be created
              - { path: /data/dify ,state: directory ,mode: 0755 }
            conf:   # override /opt/dify/.env config file

              # change domain, mirror, proxy, secret key
              NGINX_SERVER_NAME: dify.pigsty
              # A secret key for signing and encryption, gen with `openssl rand -base64 42` (CHANGE PASSWORD!)
              SECRET_KEY: sk-somerandomkey
              # expose DIFY nginx service with port 5001 by default
              DIFY_PORT: 5001
              # where to store dify files? the default is ./volume, we'll use another volume created above
              DIFY_DATA: /data/dify

              # proxy and mirror settings
              #PIP_MIRROR_URL: https://pypi.tuna.tsinghua.edu.cn/simple
              #SANDBOX_HTTP_PROXY: http://10.10.10.10:12345
              #SANDBOX_HTTPS_PROXY: http://10.10.10.10:12345

              # database credentials
              DB_USERNAME: dify
              DB_PASSWORD: difyai123456
              DB_HOST: 10.10.10.10
              DB_PORT: 5432
              DB_DATABASE: dify
              VECTOR_STORE: pgvector
              PGVECTOR_HOST: 10.10.10.10
              PGVECTOR_PORT: 5432
              PGVECTOR_USER: dify
              PGVECTOR_PASSWORD: difyai123456
              PGVECTOR_DATABASE: dify
              PGVECTOR_MIN_CONNECTION: 2
              PGVECTOR_MAX_CONNECTION: 10

    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dify ,password: difyai123456 ,pgbouncer: true ,roles: [ dbrole_admin ] ,superuser: true ,comment: dify superuser }
        pg_databases:
          - { name: dify        ,owner: dify ,revokeconn: true ,comment: dify main database  }
          - { name: dify_plugin ,owner: dify ,revokeconn: true ,comment: dify plugin_daemon database }
        pg_hba_rules:
          - { user: dify ,db: all ,addr: 172.17.0.0/16  ,auth: pwd ,title: 'allow dify access from local docker network' }
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # domain names and upstream servers
      home   :  { domain: i.pigsty }
      #minio :  { domain: m.pigsty    ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      dify:                            # nginx server config for dify
        domain: dify.pigsty            # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:5001"   # dify service endpoint: IP:PORT
        websocket: true                # add websocket support
        certbot: dify.pigsty           # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Checklist

Here’s a checklist of configuration items you need to pay attention to:

  • Hardware/Software: Prepare required machine resources: Linux x86_64/arm64 server, fresh installation of a mainstream Linux OS
  • Network/Permissions: SSH passwordless login access, user with sudo privileges without password
  • Ensure the machine has a static IPv4 network address on the internal network and can access the internet
  • If accessing via public network, ensure you have a domain pointing to the node’s public IP address
  • Ensure you use the app/dify configuration template and modify parameters as needed
    • configure -c app/dify, enter the node’s internal primary IP address, or specify via -i <primary_ip> command line parameter
  • Have you changed all password-related configuration parameters? [Optional]
  • Have you changed the PostgreSQL cluster business user password and application configurations using these passwords?
    • Default username dify and password difyai123456 are generated by Pigsty for Dify; modify according to your needs
    • In the Dify configuration block, modify DB_USERNAME, DB_PASSWORD, PGVECTOR_USER, PGVECTOR_PASSWORD accordingly
  • Have you changed Dify’s default encryption key?
    • You can randomly generate a password string with openssl rand -base64 42 and fill in the SECRET_KEY parameter
  • Have you changed the domain used by Dify?
    • Replace placeholder domain dify.pigsty with your actual domain, e.g., dify.pigsty.cc
    • You can use sed -ie 's/dify.pigsty/dify.pigsty.cc/g' pigsty.yml to modify Dify’s domain

Domain and SSL

If you want to use a real domain with an HTTPS certificate, you need to modify the pigsty.yml configuration file:

  • The dify domain in the infra_portal parameter
  • It’s best to specify an email address certbot_email for certificate expiration notifications
  • Configure Dify’s NGINX_SERVER_NAME parameter to specify your actual domain
all:
  children:                            # Cluster definitions
    dify:                              # Dify group
      vars:                            # Dify group variables
        apps:                          # Application configuration
          dify:                        # Dify application definition
            conf:                      # Dify application configuration
              NGINX_SERVER_NAME: dify.pigsty

  vars:                                # Global parameters
    #certbot_sign: true                # Use Certbot for free HTTPS certificate
    certbot_email: [email protected]      # Email for certificate requests, for expiration notifications, optional
    infra_portal:                      # Configure Nginx servers
      dify:                            # Dify server definition
        domain: dify.pigsty            # Replace with your own domain here!
        endpoint: "10.10.10.10:5001"   # Specify Dify's IP and port here (auto-configured by default)
        websocket: true                # Dify requires websocket enabled
        certbot: dify.pigsty           # Specify Certbot certificate name

Use the following commands to request Nginx certificates:

# Request certificate, can also manually run /etc/nginx/sign-cert script
make cert

# The above Makefile shortcut actually runs the following playbook task:
./infra.yml -t nginx_certbot,nginx_reload -e certbot_sign=true

Run the app.yml playbook to redeploy Dify service for the NGINX_SERVER_NAME configuration to take effect:

./app.yml

File Backup

You can use restic to backup Dify’s file storage (default location /data/dify):

export RESTIC_REPOSITORY=/data/backups/dify   # Specify dify backup directory
export RESTIC_PASSWORD=some-strong-password   # Specify backup encryption password
mkdir -p ${RESTIC_REPOSITORY}                 # Create dify backup directory
restic init

After creating the Restic backup repository, you can backup Dify with:

export RESTIC_REPOSITORY=/data/backups/dify   # Specify dify backup directory
export RESTIC_PASSWORD=some-strong-password   # Specify backup encryption password

restic backup /data/dify                      # Backup /dify data directory to repository
restic snapshots                              # View backup snapshot list
restic restore -t /data/dify 0b11f778         # Restore snapshot xxxxxx to /data/dify
restic check                                  # Periodically check repository integrity

Another more reliable method is using JuiceFS to mount MinIO object storage to the /data/dify directory, allowing you to use MinIO/S3 for file state storage.

If you want to store all data in PostgreSQL, consider “storing file system data in PostgreSQL using JuiceFS”.

For example, you can create another dify_fs database and use it as JuiceFS metadata storage:

METAURL=postgres://dify:difyai123456@:5432/dify_fs
OPTIONS=(
  --storage postgres
  --bucket :5432/dify_fs
  --access-key dify
  --secret-key difyai123456
  ${METAURL}
  jfs
)
juicefs format "${OPTIONS[@]}"         # Create PG file system
juicefs mount ${METAURL} /data/dify -d # Mount to /data/dify directory in background
juicefs bench /data/dify               # Test performance
juicefs umount /data/dify              # Unmount

Reference

Dify Self-Hosting FAQ

7.4 - Enterprise Software

Enterprise-grade open source software templates

7.5 - NocoDB: Open-Source Airtable

Use NocoDB to transform PostgreSQL databases into smart spreadsheets, a no-code database application platform.

NocoDB is an open-source Airtable alternative that turns any database into a smart spreadsheet.

It provides a rich user interface that allows you to create powerful database applications without writing code. NocoDB supports PostgreSQL, MySQL, SQL Server, and more, making it ideal for building internal tools and data management systems.

Quick Start

Pigsty provides a Docker Compose configuration file for NocoDB in the software template directory:

cd ~/pigsty/app/nocodb

Review and modify the .env configuration file (adjust database connections as needed).

Start the service:

make up     # Start NocoDB with Docker Compose

Access NocoDB:

  • Default URL: http://nocodb.pigsty
  • Alternate URL: http://10.10.10.10:8080
  • First-time access requires creating an administrator account

Management Commands

Pigsty provides convenient Makefile commands to manage NocoDB:

make up      # Start NocoDB service
make run     # Start with Docker (connect to external PostgreSQL)
make view    # Display NocoDB access URL
make log     # View container logs
make info    # View service details
make stop    # Stop the service
make clean   # Stop and remove containers
make pull    # Pull the latest image
make rmi     # Remove NocoDB image
make save    # Save image to /tmp/nocodb.tgz
make load    # Load image from /tmp/nocodb.tgz

Connect to PostgreSQL

NocoDB can connect to PostgreSQL databases managed by Pigsty.

When adding a new project in the NocoDB interface, select “External Database” and enter the PostgreSQL connection information:

Host: 10.10.10.10
Port: 5432
Database Name: your_database
Username: your_username
Password: your_password
SSL: Disabled (or enable as needed)

After successful connection, NocoDB will automatically read the database table structure, and you can manage data through the visual interface.

Features

  • Smart Spreadsheet Interface: Excel/Airtable-like user experience
  • Multiple Views: Grid, form, kanban, calendar, gallery views
  • Collaboration Features: Team collaboration, permission management, comments
  • API Support: Auto-generated REST API
  • Integration Capabilities: Webhooks, Zapier integrations
  • Import/Export: CSV, Excel format support
  • Formulas and Validation: Complex data calculations and validation rules

Configuration

NocoDB configuration is in the .env file:

# Database connection (NocoDB metadata storage)
NC_DB=pg://postgres:[email protected]:5432/nocodb

# JWT secret (recommended to change)
NC_AUTH_JWT_SECRET=your-secret-key

# Other settings
NC_PUBLIC_URL=http://nocodb.pigsty
NC_DISABLE_TELE=true

Data Persistence

NocoDB metadata is stored by default in an external PostgreSQL database, and application data can also be stored in PostgreSQL.

If using local storage, data is saved in the /data/nocodb directory.

Security Recommendations

  1. Change Default Secret: Modify NC_AUTH_JWT_SECRET in the .env file
  2. Use Strong Passwords: Set strong passwords for administrator accounts
  3. Configure HTTPS: Enable HTTPS for production environments
  4. Restrict Access: Limit access through firewall or Nginx
  5. Regular Backups: Regularly back up the NocoDB metadata database

7.6 - Teable: AI No-Code Database

Build AI-powered no-code database applications with Teable to boost team productivity.

Teable is an AI-powered no-code database platform designed for team collaboration and automation.

Teable perfectly combines the power of databases with the ease of spreadsheets, integrating AI capabilities to help teams efficiently generate, automate, and collaborate on data.

Quick Start

Teable requires a complete Pigsty environment (including PostgreSQL, Redis, MinIO).

Prepare Environment

cd ~/pigsty
./bootstrap                # Prepare local repo and Ansible
./configure -c app/teable  # Important: modify default credentials!
./deploy.yml               # Install Pigsty, PostgreSQL, MinIO
./redis.yml                # Install Redis instance
./docker.yml               # Install Docker and Docker Compose
./app.yml                  # Install Teable with Docker Compose

Access Service

  • Default URL: http://teable.pigsty
  • Alternate URL: http://10.10.10.10:3000
  • First-time access requires registering an administrator account

Management Commands

Manage Teable in the Pigsty software template directory:

cd ~/pigsty/app/teable

make up      # Start Teable service
make down    # Stop Teable service
make log     # View container logs
make clean   # Clean up containers and data

Architecture

Teable depends on the following components:

  • PostgreSQL: Stores application data and metadata
  • Redis: Caching and session management
  • MinIO: Object storage (files, images, etc.)
  • Docker: Container runtime environment

Ensure these services are properly installed before deploying Teable.

Features

  • AI Integration: Built-in AI assistant for auto-generating data, formulas, and workflows
  • Smart Tables: Powerful table functionality with multiple field types
  • Automated Workflows: No-code automation to boost team efficiency
  • Multiple Views: Grid, form, kanban, calendar, and more
  • Team Collaboration: Real-time collaboration, permission management, comments
  • API and Integrations: Auto-generated API with Webhook support
  • Template Library: Rich application templates for quick project starts

Configuration

Teable configuration is managed through environment variables in docker-compose.yml:

# PostgreSQL connection
POSTGRES_HOST=10.10.10.10
POSTGRES_PORT=5432
POSTGRES_DB=teable
POSTGRES_USER=dbuser_teable
POSTGRES_PASSWORD=DBUser.Teable

# Redis connection
REDIS_HOST=10.10.10.10
REDIS_PORT=6379
REDIS_DB=0

# MinIO connection
MINIO_ENDPOINT=http://10.10.10.10:9000
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=minioadmin

# Application configuration
BACKEND_URL=http://teable.pigsty
PUBLIC_ORIGIN=http://teable.pigsty

Important: In production environments, modify all default passwords and keys!

Data Persistence

Teable data persistence relies on:

  • PostgreSQL: All structured data stored in PostgreSQL
  • MinIO: Files, images, and other unstructured data stored in MinIO
  • Redis: Cache data (optional persistence)

Regularly back up the PostgreSQL database and MinIO buckets to ensure data safety.

Security Recommendations

  1. Change Default Credentials: Modify all default usernames and passwords in configuration files
  2. Enable HTTPS: Configure SSL certificates for production environments
  3. Configure Firewall: Restrict access to services
  4. Regular Backups: Regularly back up PostgreSQL and MinIO data
  5. Update Components: Keep Teable and dependent components up to date

7.7 - Gitea: Simple Self-Hosting Git Service

Launch the self-hosting Git service with Gitea and Pigsty managed PostgreSQL

Public Demo: http://git.pigsty.cc

TL;DR

cd ~/pigsty/app/gitea; make up

Pigsty use 8889 port for gitea by default

http://git.pigsty or http://10.10.10.10:8889

make up      # pull up gitea with docker-compose in minimal mode
make run     # launch gitea with docker , local data dir and external PostgreSQL
make view    # print gitea access point
make log     # tail -f gitea logs
make info    # introspect gitea with jq
make stop    # stop gitea container
make clean   # remove gitea container
make pull    # pull latest gitea image
make rmi     # remove gitea image
make save    # save gitea image to /tmp/gitea.tgz
make load    # load gitea image from /tmp

PostgreSQL Preparation

Gitea use built-in SQLite as default metadata storage, you can let Gitea use external PostgreSQL by setting connection string environment variable

# postgres://dbuser_gitea:[email protected]:5432/gitea
db:   { name: gitea, owner: dbuser_gitea, comment: gitea primary database }
user: { name: dbuser_gitea , password: DBUser.gitea, roles: [ dbrole_admin ] }

7.8 - Wiki.js: OSS Wiki Software

How to self-hosting your own wikipedia with Wiki.js and use Pigsty managed PostgreSQL as the backend database

Public Demo: http://wiki.pigsty.cc

TL; DR

cd app/wiki ; docker-compose up -d

Postgres Preparation

# postgres://dbuser_wiki:[email protected]:5432/wiki
- { name: wiki, owner: dbuser_wiki, revokeconn: true , comment: wiki the api gateway database }
- { name: dbuser_wiki, password: DBUser.Wiki , pgbouncer: true , roles: [ dbrole_admin ] }
bin/pgsql-user pg-meta dbuser_wiki
bin/pgsql-db   pg-meta wiki

Configuration

version: "3"
services:
  wiki:
    container_name: wiki
    image: requarks/wiki:2
    environment:
      DB_TYPE: postgres
      DB_HOST: 10.10.10.10
      DB_PORT: 5432
      DB_USER: dbuser_wiki
      DB_PASS: DBUser.Wiki
      DB_NAME: wiki
    restart: unless-stopped
    ports:
      - "9002:3000"

Access

  • Default Port for wiki: 9002
# add to nginx_upstream
- { name: wiki  , domain: wiki.pigsty.cc , endpoint: "127.0.0.1:9002"   }
./infra.yml -t nginx_config
ansible all -b -a 'nginx -s reload'

7.9 - Mattermost: Open-Source IM

Build a private team collaboration platform with Mattermost, the open-source Slack alternative.

Mattermost is an open-source team collaboration and messaging platform.

Mattermost provides instant messaging, file sharing, audio/video calls, and more. It’s an open-source alternative to Slack and Microsoft Teams, particularly suitable for enterprises requiring self-hosted deployment.

Quick Start

cd ~/pigsty/app/mattermost
make up     # Start Mattermost with Docker Compose

Access URL: http://mattermost.pigsty or http://10.10.10.10:8065

First-time access requires creating an administrator account.

Features

  • Instant Messaging: Personal and group chat
  • Channel Management: Public and private channels
  • File Sharing: Secure file storage and sharing
  • Audio/Video Calls: Built-in calling functionality
  • Integration Capabilities: Webhooks, Bots, and plugins support
  • Mobile Apps: iOS and Android clients
  • Enterprise-grade: SSO, LDAP, compliance features

Connect to PostgreSQL

Mattermost uses PostgreSQL for data storage. Configure the connection information:

MM_SQLSETTINGS_DRIVERNAME=postgres
MM_SQLSETTINGS_DATASOURCE=postgres://dbuser_mm:[email protected]:5432/mattermost

7.10 - Maybe: Personal Finance

Manage personal finances with Maybe, the open-source Mint/Personal Capital alternative.

Maybe is an open-source personal finance management application.

Maybe provides financial tracking, budget management, investment analysis, and more. It’s an open-source alternative to Mint and Personal Capital, giving you complete control over your financial data.

Quick Start

cd ~/pigsty/app/maybe
cp .env.example .env
vim .env                    # Must modify SECRET_KEY_BASE
make up                      # Start Maybe service

Access URL: http://maybe.pigsty or http://10.10.10.10:5002

Configuration

Configure in the .env file:

SECRET_KEY_BASE=your-secret-key-here    # Must modify!
DATABASE_URL=postgresql://...

Important: You must modify SECRET_KEY_BASE before first deployment!

Features

  • Account Management: Track multiple bank accounts and credit cards
  • Budget Planning: Set up and track budgets
  • Investment Analysis: Monitor portfolio performance
  • Bill Reminders: Automatic reminders for upcoming bills
  • Privacy-first: Data is completely under your control

7.11 - Metabase: BI Analytics Tool

Use Metabase for rapid business intelligence analysis with a user-friendly interface for team self-service data exploration.

Metabase is a fast, easy-to-use open-source business intelligence tool that lets your team explore and visualize data without SQL knowledge.

Metabase provides a friendly user interface with rich chart types and supports connecting to various databases, making it an ideal choice for enterprise data analysis.

Quick Start

Pigsty provides a Docker Compose configuration file for Metabase in the software template directory:

cd ~/pigsty/app/metabase

Review and modify the .env configuration file:

vim .env    # Check configuration, recommend changing default credentials

Start the service:

make up     # Start Metabase with Docker Compose

Access Metabase:

  • Default URL: http://metabase.pigsty
  • Alternate URL: http://10.10.10.10:3001
  • First-time access requires initial setup

Management Commands

Pigsty provides convenient Makefile commands to manage Metabase:

make up      # Start Metabase service
make run     # Start with Docker (connect to external PostgreSQL)
make view    # Display Metabase access URL
make log     # View container logs
make info    # View service details
make stop    # Stop the service
make clean   # Stop and remove containers
make pull    # Pull the latest image
make rmi     # Remove Metabase image
make save    # Save image to file
make load    # Load image from file

Connect to PostgreSQL

Metabase can connect to PostgreSQL databases managed by Pigsty.

During Metabase initialization or when adding a database, select “PostgreSQL” and enter the connection information:

Database Type: PostgreSQL
Name: Custom name (e.g., "Production Database")
Host: 10.10.10.10
Port: 5432
Database Name: your_database
Username: dbuser_meta
Password: DBUser.Meta

After successful connection, Metabase will automatically scan the database schema, and you can start creating questions and dashboards.

Features

  • No SQL Required: Build queries through visual interface
  • Rich Chart Types: Line, bar, pie, map charts, and more
  • Interactive Dashboards: Create beautiful data dashboards
  • Auto Refresh: Schedule data and dashboard updates
  • Permission Management: Fine-grained user and data access control
  • SQL Mode: Advanced users can write SQL directly
  • Embedding: Embed charts into other applications
  • Alerting: Automatic notifications on data changes

Configuration

Metabase configuration is in the .env file:

# Metabase metadata database (PostgreSQL recommended)
MB_DB_TYPE=postgres
MB_DB_DBNAME=metabase
MB_DB_PORT=5432
MB_DB_USER=dbuser_metabase
MB_DB_PASS=DBUser.Metabase
MB_DB_HOST=10.10.10.10

# Application configuration
JAVA_OPTS=-Xmx2g

Recommended: Use a dedicated PostgreSQL database for storing Metabase metadata.

Data Persistence

Metabase metadata (users, questions, dashboards, etc.) is stored in the configured database.

If using H2 database (default), data is saved in the /data/metabase directory. Using PostgreSQL as the metadata database is strongly recommended for production environments.

Performance Optimization

  • Use PostgreSQL: Replace the default H2 database
  • Increase Memory: Add JVM memory with JAVA_OPTS=-Xmx4g
  • Database Indexes: Create indexes for frequently queried fields
  • Result Caching: Enable Metabase query result caching
  • Scheduled Updates: Set reasonable dashboard auto-refresh frequency

Security Recommendations

  1. Change Default Credentials: Modify metadata database username and password
  2. Enable HTTPS: Configure SSL certificates for production
  3. Configure Authentication: Enable SSO or LDAP authentication
  4. Restrict Access: Limit access through firewall
  5. Regular Backups: Back up the Metabase metadata database

7.12 - Kong: the Nginx API Gateway

Learn how to deploy Kong, the API gateway, with Docker Compose and use external PostgreSQL as the backend database

TL;DR

cd app/kong ; docker-compose up -d
make up         # pull up kong with docker-compose
make ui         # run swagger ui container
make log        # tail -f kong logs
make info       # introspect kong with jq
make stop       # stop kong container
make clean      # remove kong container
make rmui       # remove swagger ui container
make pull       # pull latest kong image
make rmi        # remove kong image
make save       # save kong image to /tmp/kong.tgz
make load       # load kong image from /tmp

Scripts

  • Default Port: 8000
  • Default SSL Port: 8443
  • Default Admin Port: 8001
  • Default Postgres Database: postgres://dbuser_kong:[email protected]:5432/kong
# postgres://dbuser_kong:[email protected]:5432/kong
- { name: kong, owner: dbuser_kong, revokeconn: true , comment: kong the api gateway database }
- { name: dbuser_kong, password: DBUser.Kong , pgbouncer: true , roles: [ dbrole_admin ] }

7.13 - Registry: Container Image Mirror

Deploy Docker Registry mirror service to accelerate Docker image pulls, especially useful for users in China.

Docker Registry mirror service caches images from Docker Hub and other registries.

Particularly useful for users in China or regions with slow Docker Hub access, significantly reducing image pull times.

Quick Start

cd ~/pigsty/app/registry
make up     # Start Registry mirror service

Access URL: http://registry.pigsty or http://10.10.10.10:5000

Features

  • Image Caching: Cache images from Docker Hub and other registries
  • Web Interface: Optional image management UI
  • High Performance: Local caching dramatically improves pull speed
  • Storage Management: Configurable cleanup and management policies
  • Health Checks: Built-in health check endpoints

Configure Docker

Configure Docker to use the local mirror:

# Edit /etc/docker/daemon.json
{
  "registry-mirrors": ["http://10.10.10.10:5000"]
}

# Restart Docker
systemctl restart docker

Storage Management

Image data is stored in the /data/registry directory. Reserve at least 100GB of space.

7.14 - Database Tools

Database management and development tools

7.15 - ByteBase: PG Schema Migration

Self-hosting bytebase with PostgreSQL managed by Pigsty

ByteBase

ByteBase is a database schema change management tool. The following command will start a ByteBase on the meta node 8887 port by default.

mkdir -p /data/bytebase/data;
docker run --init --name bytebase --restart always --detach --publish 8887:8887 --volume /data/bytebase/data:/var/opt/bytebase \
    bytebase/bytebase:1.0.4 --data /var/opt/bytebase --host http://ddl.pigsty --port 8887

Then visit http://10.10.10.10:8887/ or http://ddl.pigsty to access bytebase console. You have to “Create Project”, “Env”, “Instance”, “Database” to perform schema migration.

Public Demo: http://ddl.pigsty.cc

Default username & password: admin / pigsty


Bytebase Overview

Schema Migrator for PostgreSQL

cd app/bytebase; make up

Visit http://ddl.pigsty or http://10.10.10.10:8887

make up         # pull up bytebase with docker-compose in minimal mode
make run        # launch bytebase with docker , local data dir and external PostgreSQL
make view       # print bytebase access point
make log        # tail -f bytebase logs
make info       # introspect bytebase with jq
make stop       # stop bytebase container
make clean      # remove bytebase container
make pull       # pull latest bytebase image
make rmi        # remove bytebase image
make save       # save bytebase image to /tmp/bytebase.tgz
make load       # load bytebase image from /tmp

PostgreSQL Preparation

Bytebase use its internal PostgreSQL database by default, You can use external PostgreSQL for higher durability.

# postgres://dbuser_bytebase:[email protected]:5432/bytebase
db:   { name: bytebase, owner: dbuser_bytebase, comment: bytebase primary database }
user: { name: dbuser_bytebase , password: DBUser.Bytebase, roles: [ dbrole_admin ] }

if you wish to user an external PostgreSQL, drop monitor extensions and views & pg_repack

DROP SCHEMA monitor CASCADE;
DROP EXTENSION pg_repack;

After bytebase initialized, you can create them back with /pg/tmp/pg-init-template.sql

psql bytebase < /pg/tmp/pg-init-template.sql

7.16 - PGAdmin4: PG Admin GUI Tool

Launch pgAdmin4 with docker, and load Pigsty server list into it

pgAdmin4 is a useful PostgreSQL management tool. Execute the following command to launch the pgadmin service on the admin node:

cd ~/pigsty/app/pgadmin ; docker-compose up -d

The default port for pgadmin is 8885, and you can access it through the following address:

http://adm.pigsty


Demo

Public Demo: http://adm.pigsty.cc

Credentials: [email protected] / pigsty

TL; DR

cd ~/pigsty/app/pgadmin   # enter docker compose dir
make up                   # launch pgadmin container
make conf view            # load pigsty server list

Shortcuts:

make up         # pull up pgadmin with docker-compose
make run        # launch pgadmin with docker
make view       # print pgadmin access point
make log        # tail -f pgadmin logs
make info       # introspect pgadmin with jq
make stop       # stop pgadmin container
make clean      # remove pgadmin container
make conf       # provision pgadmin with pigsty pg servers list
make dump       # dump servers.json from pgadmin container
make pull       # pull latest pgadmin image
make rmi        # remove pgadmin image
make save       # save pgadmin image to /tmp/pgadmin.tgz
make load       # load pgadmin image from /tmp

7.17 - PGWeb: Browser-based PG Client

Launch pgweb to access PostgreSQL via web browser

PGWEB: https://github.com/sosedoff/pgweb

Simple web-based and cross-platform PostgreSQL database explorer.

Public Demo: http://cli.pigsty.cc

TL; DR

cd ~/pigsty/app/pgweb ; make up

Visit http://cli.pigsty or http://10.10.10.10:8886

Try connecting with example URLs:

postgres://dbuser_meta:[email protected]:5432/meta?sslmode=disable
postgres://test:[email protected]:5432/test?sslmode=disable
make up         # pull up pgweb with docker compose
make run        # launch pgweb with docker
make view       # print pgweb access point
make log        # tail -f pgweb logs
make info       # introspect pgweb with jq
make stop       # stop pgweb container
make clean      # remove pgweb container
make pull       # pull latest pgweb image
make rmi        # remove pgweb image
make save       # save pgweb image to /tmp/docker/pgweb.tgz
make load       # load pgweb image from /tmp/docker/pgweb.tgz

7.18 - PostgREST: Generate REST API from Schema

Launch postgREST to generate REST API from PostgreSQL schema automatically

PostgREST is a binary component that automatically generates a REST API based on the PostgreSQL database schema.

For example, the following command will launch postgrest with docker (local port 8884, using default admin user, and expose Pigsty CMDB schema):

docker run --init --name postgrest --restart always --detach --publish 8884:8081 postgrest/postgrest

Visit http://10.10.10.10:8884 will show all auto-generated API definitions and automatically expose API documentation using Swagger Editor.

If you wish to perform CRUD operations and design more fine-grained permission control, please refer to Tutorial 1 - The Golden Key to generate a signed JWT.

This is an example of creating pigsty cmdb API with PostgREST

cd ~/pigsty/app/postgrest ; docker-compose up -d

http://10.10.10.10:8884 is the default endpoint for PostgREST

http://10.10.10.10:8883 is the default api docs for PostgREST

make up         # pull up postgrest with docker-compose
make run        # launch postgrest with docker
make ui         # run swagger ui container
make view       # print postgrest access point
make log        # tail -f postgrest logs
make info       # introspect postgrest with jq
make stop       # stop postgrest container
make clean      # remove postgrest container
make rmui       # remove swagger ui container
make pull       # pull latest postgrest image
make rmi        # remove postgrest image
make save       # save postgrest image to /tmp/postgrest.tgz
make load       # load postgrest image from /tmp

Swagger UI

Launch a swagger OpenAPI UI and visualize PostgREST API on 8883 with:

docker run --init --name postgrest --name swagger -p 8883:8080 -e API_URL=http://10.10.10.10:8884 swaggerapi/swagger-ui
# docker run -d -e API_URL=http://10.10.10.10:8884 -p 8883:8080 swaggerapi/swagger-editor # swagger editor

Check http://10.10.10.10:8883/

7.19 - Electric: PGLite Sync Engine

Use Electric to solve PostgreSQL data synchronization challenges with partial replication and real-time data transfer.

Electric is a PostgreSQL sync engine that solves complex data synchronization problems.

Electric supports partial replication, fan-out delivery, and efficient data transfer, making it ideal for building real-time and offline-first applications.

Quick Start

cd ~/pigsty/app/electric
make up     # Start Electric service

Access URL: http://electric.pigsty or http://10.10.10.10:3000

Features

  • Partial Replication: Sync only the data you need
  • Real-time Sync: Millisecond-level data updates
  • Offline-first: Work offline with automatic sync
  • Conflict Resolution: Automatic handling of data conflicts
  • Type Safety: TypeScript support

7.20 - Jupyter: AI Notebook & IDE

Run Jupyter Lab in container, and access PostgreSQL database

Run jupyter notebook with docker, you have to:

    1. change the default password in .env: JUPYTER_TOKEN
    1. create data dir with proper permission: make dir, owned by 1000:100
    1. make up to pull up jupyter with docker compose
cd ~/pigsty/app/jupyter ; make dir up

Visit http://lab.pigsty or http://10.10.10.10:8888, the default password is pigsty

Prepare

Create a data directory /data/jupyter, with the default uid & gid 1000:100:

make dir   # mkdir -p /data/jupyter; chown -R 1000:100 /data/jupyter

Connect to Postgres

Use the jupyter terminal to install psycopg2-binary & psycopg2 package.

pip install psycopg2-binary psycopg2

# install with a mirror
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple psycopg2-binary psycopg2

pip install --upgrade pip
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

Or installation with conda:

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/

then use the driver in your notebook

import psycopg2

conn = psycopg2.connect('postgres://dbuser_dba:[email protected]:5432/meta')
cursor = conn.cursor()
cursor.execute('SELECT * FROM pg_stat_activity')
for i in cursor.fetchall():
    print(i)

Alias

make up         # pull up jupyter with docker compose
make dir        # create required /data/jupyter and set owner
make run        # launch jupyter with docker
make view       # print jupyter access point
make log        # tail -f jupyter logs
make info       # introspect jupyter with jq
make stop       # stop jupyter container
make clean      # remove jupyter container
make pull       # pull latest jupyter image
make rmi        # remove jupyter image
make save       # save jupyter image to /tmp/docker/jupyter.tgz
make load       # load jupyter image from /tmp/docker/jupyter.tgz

7.21 - Data Applications

PostgreSQL-based data visualization applications

7.22 - PGLOG: PostgreSQL Log Analysis Application

A sample Applet included with Pigsty for analyzing PostgreSQL CSV log samples

PGLOG is a sample application included with Pigsty that uses the pglog.sample table in MetaDB as its data source. You simply need to load logs into this table, then access the related dashboard.

Pigsty provides convenient commands for pulling CSV logs and loading them into the sample table. On the meta node, the following shortcut commands are available by default:

catlog  [node=localhost]  [date=today]   # Print CSV log to stdout
pglog                                    # Load CSVLOG from stdin
pglog12                                  # Load PG12 format CSVLOG
pglog13                                  # Load PG13 format CSVLOG
pglog14                                  # Load PG14 format CSVLOG (=pglog)

catlog | pglog                       # Analyze current node's log for today
catlog node-1 '2021-07-15' | pglog   # Analyze node-1's csvlog for 2021-07-15

Next, you can access the following links to view the sample log analysis interface.

  • PGLOG Overview: Present the entire CSV log sample details, aggregated by multiple dimensions.

  • PGLOG Session: Present detailed information about a specific connection in the log sample.

The catlog command pulls CSV database logs from a specific node for a specific date and writes to stdout

By default, catlog pulls logs from the current node for today. You can specify the node and date through parameters.

Using pglog and catlog together, you can quickly pull database CSV logs for analysis.

catlog | pglog                       # Analyze current node's log for today
catlog node-1 '2021-07-15' | pglog   # Analyze node-1's csvlog for 2021-07-15

7.23 - NOAA ISD Global Weather Station Historical Data Query

Demonstrate how to import data into a database using the ISD dataset as an example

If you have a database and don’t know what to do with it, why not try this open-source project: Vonng/isd

You can directly reuse the monitoring system Grafana to interactively browse sub-hourly meteorological data from nearly 30,000 surface weather stations over the past 120 years.

This is a fully functional data application that can query meteorological observation records from 30,000 global surface weather stations since 1901.

Project URL: https://github.com/Vonng/isd

Online Demo: https://demo.pigsty.io/d/isd-overview

isd-overview.jpg

Quick Start

Clone this repository

git clone https://github.com/Vonng/isd.git; cd isd;

Prepare a PostgreSQL instance

The PostgreSQL instance should have the PostGIS extension enabled. Use the PGURL environment variable to pass database connection information:

# Pigsty uses dbuser_dba as the default admin account with password DBUser.DBA
export PGURL=postgres://dbuser_dba:[email protected]:5432/meta?sslmode=disable
psql "${PGURL}" -c 'SELECT 1'  # Check if connection is available

Fetch and import ISD weather station metadata

This is a daily-updated weather station metadata file containing station longitude/latitude, elevation, name, country, province, and other information. Use the following command to download and import:

make reload-station   # Equivalent to downloading the latest station data then loading: get-station + load-station

Fetch and import the latest isd.daily data

isd.daily is a daily-updated dataset containing daily observation data summaries from global weather stations. Use the following command to download and import. Note that raw data downloaded directly from the NOAA website needs to be parsed before it can be loaded into the database, so you need to download or build an ISD data parser.

make get-parser       # Download the parser binary from Github, or you can build directly with go using make build
make reload-daily     # Download and import the latest isd.daily data for this year into the database

Load pre-parsed CSV dataset

The ISD Daily dataset has some dirty data and duplicate data. If you don’t want to manually parse and clean it, a stable pre-parsed CSV dataset is also provided here.

This dataset contains isd.daily data up to 2023-06-24. You can download and import it directly into PostgreSQL without needing a parser.

make get-stable       # Get the stable isd.daily historical dataset from Github
make load-stable      # Load the downloaded stable historical dataset into the PostgreSQL database

More Data

Two parts of the ISD dataset are updated daily: weather station metadata and the latest year’s isd.daily (e.g., the 2023 tarball).

You can use the following command to download and refresh these two parts. If the dataset hasn’t been updated, these commands won’t re-download the same data package:

make reload           # Actually: reload-station + reload-daily

You can also use the following commands to download and load isd.daily data for a specific year:

bin/get-daily  2022                   # Get daily weather observation summary for 2022 (1900-2023)
bin/load-daily "${PGURL}" 2022        # Load daily weather observation summary for 2022 (1900-2023)

In addition to the daily summary isd.daily, ISD also provides more detailed sub-hourly raw observation records isd.hourly. The download and load methods are similar:

bin/get-hourly  2022                  # Download hourly observation records for a specific year (e.g., 2022, options 1900-2023)
bin/load-hourly "${PGURL}" 2022       # Load hourly observation records for a specific year

Data

Dataset Overview

ISD provides four datasets: sub-hourly raw observation data, daily statistical summary data, monthly statistical summary, and yearly statistical summary

DatasetNotes
ISD HourlySub-hourly observation records
ISD DailyDaily statistical summary
ISD MonthlyNot used, can be calculated from isd.daily
ISD YearlyNot used, can be calculated from isd.daily

Daily Summary Dataset

  • Compressed package size 2.8GB (as of 2023-06-24)
  • Table size 24GB, index size 6GB, total size approximately 30GB in PostgreSQL
  • If timescaledb compression is enabled, total size can be compressed to 4.5 GB

Sub-hourly Observation Data

  • Total compressed package size 117GB
  • After loading into database: table size 1TB+, index size 600GB+, total size 1.6TB

Database Schema

Weather Station Metadata Table

CREATE TABLE isd.station
(
    station    VARCHAR(12) PRIMARY KEY,
    usaf       VARCHAR(6) GENERATED ALWAYS AS (substring(station, 1, 6)) STORED,
    wban       VARCHAR(5) GENERATED ALWAYS AS (substring(station, 7, 5)) STORED,
    name       VARCHAR(32),
    country    VARCHAR(2),
    province   VARCHAR(2),
    icao       VARCHAR(4),
    location   GEOMETRY(POINT),
    longitude  NUMERIC GENERATED ALWAYS AS (Round(ST_X(location)::NUMERIC, 6)) STORED,
    latitude   NUMERIC GENERATED ALWAYS AS (Round(ST_Y(location)::NUMERIC, 6)) STORED,
    elevation  NUMERIC,
    period     daterange,
    begin_date DATE GENERATED ALWAYS AS (lower(period)) STORED,
    end_date   DATE GENERATED ALWAYS AS (upper(period)) STORED
);

Daily Summary Table

CREATE TABLE IF NOT EXISTS isd.daily
(
    station     VARCHAR(12) NOT NULL, -- station number 6USAF+5WBAN
    ts          DATE        NOT NULL, -- observation date
    -- Temperature & Dew Point
    temp_mean   NUMERIC(3, 1),        -- mean temperature ℃
    temp_min    NUMERIC(3, 1),        -- min temperature ℃
    temp_max    NUMERIC(3, 1),        -- max temperature ℃
    dewp_mean   NUMERIC(3, 1),        -- mean dew point ℃
    -- Air Pressure
    slp_mean    NUMERIC(5, 1),        -- sea level pressure (hPa)
    stp_mean    NUMERIC(5, 1),        -- station pressure (hPa)
    -- Visibility
    vis_mean    NUMERIC(6),           -- visible distance (m)
    -- Wind Speed
    wdsp_mean   NUMERIC(4, 1),        -- average wind speed (m/s)
    wdsp_max    NUMERIC(4, 1),        -- max wind speed (m/s)
    gust        NUMERIC(4, 1),        -- max wind gust (m/s)
    -- Precipitation / Snow Depth
    prcp_mean   NUMERIC(5, 1),        -- precipitation (mm)
    prcp        NUMERIC(5, 1),        -- rectified precipitation (mm)
    sndp        NuMERIC(5, 1),        -- snow depth (mm)
    -- FRSHTT (Fog/Rain/Snow/Hail/Thunder/Tornado)
    is_foggy    BOOLEAN,              -- (F)og
    is_rainy    BOOLEAN,              -- (R)ain or Drizzle
    is_snowy    BOOLEAN,              -- (S)now or pellets
    is_hail     BOOLEAN,              -- (H)ail
    is_thunder  BOOLEAN,              -- (T)hunder
    is_tornado  BOOLEAN,              -- (T)ornado or Funnel Cloud
    -- Record counts used for statistical aggregation
    temp_count  SMALLINT,             -- record count for temp
    dewp_count  SMALLINT,             -- record count for dew point
    slp_count   SMALLINT,             -- record count for sea level pressure
    stp_count   SMALLINT,             -- record count for station pressure
    wdsp_count  SMALLINT,             -- record count for wind speed
    visib_count SMALLINT,             -- record count for visible distance
    -- Temperature flags
    temp_min_f  BOOLEAN,              -- aggregate min temperature
    temp_max_f  BOOLEAN,              -- aggregate max temperature
    prcp_flag   CHAR,                 -- precipitation flag: ABCDEFGHI
    PRIMARY KEY (station, ts)
); -- PARTITION BY RANGE (ts);

Sub-hourly Raw Observation Data Table

ISD Hourly
CREATE TABLE IF NOT EXISTS isd.hourly
(
    station    VARCHAR(12) NOT NULL, -- station id
    ts         TIMESTAMP   NOT NULL, -- timestamp
    -- air
    temp       NUMERIC(3, 1),        -- [-93.2,+61.8]
    dewp       NUMERIC(3, 1),        -- [-98.2,+36.8]
    slp        NUMERIC(5, 1),        -- [8600,10900]
    stp        NUMERIC(5, 1),        -- [4500,10900]
    vis        NUMERIC(6),           -- [0,160000]
    -- wind
    wd_angle   NUMERIC(3),           -- [1,360]
    wd_speed   NUMERIC(4, 1),        -- [0,90]
    wd_gust    NUMERIC(4, 1),        -- [0,110]
    wd_code    VARCHAR(1),           -- code that denotes the character of the WIND-OBSERVATION.
    -- cloud
    cld_height NUMERIC(5),           -- [0,22000]
    cld_code   VARCHAR(2),           -- cloud code
    -- water
    sndp       NUMERIC(5, 1),        -- mm snow
    prcp       NUMERIC(5, 1),        -- mm precipitation
    prcp_hour  NUMERIC(2),           -- precipitation duration in hour
    prcp_code  VARCHAR(1),           -- precipitation type code
    -- sky
    mw_code    VARCHAR(2),           -- manual weather observation code
    aw_code    VARCHAR(2),           -- auto weather observation code
    pw_code    VARCHAR(1),           -- weather code of past period of time
    pw_hour    NUMERIC(2),           -- duration of pw_code period
    -- misc
    -- remark     TEXT,
    -- eqd        TEXT,
    data       JSONB                 -- extra data
) PARTITION BY RANGE (ts);

Parser

The raw data provided by NOAA ISD is in a highly compressed proprietary format that needs to be processed through a parser before it can be converted into database table format.

For the Daily and Hourly datasets, two parsers are provided here: isdd and isdh. Both parsers take annual data compressed packages as input, produce CSV results as output, and work in pipeline mode as shown below:

NAME
        isd -- Intergrated Surface Dataset Parser

SYNOPSIS
        isd daily   [-i <input|stdin>] [-o <output|stout>] [-v]
        isd hourly  [-i <input|stdin>] [-o <output|stout>] [-v] [-d raw|ts-first|hour-first]

DESCRIPTION
        The isd program takes noaa isd daily/hourly raw tarball data as input.
        and generate parsed data in csv format as output. Works in pipe mode

        cat data/daily/2023.tar.gz | bin/isd daily -v | psql ${PGURL} -AXtwqc "COPY isd.daily FROM STDIN CSV;"

        isd daily  -v -i data/daily/2023.tar.gz  | psql ${PGURL} -AXtwqc "COPY isd.daily FROM STDIN CSV;"
        isd hourly -v -i data/hourly/2023.tar.gz | psql ${PGURL} -AXtwqc "COPY isd.hourly FROM STDIN CSV;"

OPTIONS
        -i  <input>     input file, stdin by default
        -o  <output>    output file, stdout by default
        -p  <profpath>  pprof file path, enable if specified
        -d              de-duplicate rows for hourly dataset (raw, ts-first, hour-first)
        -v              verbose mode
        -h              print help

User Interface

Several dashboards made with Grafana are provided here for exploring the ISD dataset and querying weather stations and historical meteorological data.


ISD Overview

Global overview with overall metrics and weather station navigation.

isd-overview.jpg


ISD Country

Display all weather stations within a single country/region.

isd-country.jpg


ISD Station

Display detailed information for a single weather station, including metadata and daily/monthly/yearly summary metrics.

ISD Station Dashboard

isd-station.jpg


ISD Detail

Display raw sub-hourly observation metric data for a weather station, requires the isd.hourly dataset.

ISD Station Dashboard

isd-detail.jpg




7.24 - WHO COVID-19 Pandemic Dashboard

A sample Applet included with Pigsty for visualizing World Health Organization official pandemic data

Covid is a sample Applet included with Pigsty for visualizing the World Health Organization’s official pandemic data dashboard.

You can browse COVID-19 infection and death cases for each country and region, as well as global pandemic trends.


Overview

GitHub Repository: https://github.com/pgsty/pigsty-app/tree/master/covid

Online Demo: https://demo.pigsty.io/d/covid


Installation

Enter the application directory on the admin node and execute make to complete the installation.

make            # Complete all configuration

Other sub-tasks:

make reload     # download latest data and pour it again
make ui         # install grafana dashboards
make sql        # install database schemas
make download   # download latest data
make load       # load downloaded data into database
make reload     # download latest data and pour it into database

7.25 - StackOverflow Global Developer Survey

Analyze database-related data from StackOverflow’s global developer survey over the past seven years

Overview

GitHub Repository: https://github.com/pgsty/pigsty-app/tree/master/db

Online Demo: https://demo.pigsty.io/d/sf-survey

7.26 - DB-Engines Database Popularity Trend Analysis

Analyze database management systems on DB-Engines and browse their popularity evolution

Overview

GitHub Repository: https://github.com/pgsty/pigsty-app/tree/master/db

Online Demo: https://demo.pigsty.io/d/db-engine

7.27 - AWS & Aliyun Server Pricing

Analyze compute and storage pricing on Aliyun / AWS (ECS/ESSD)

Overview

GitHub Repository: https://github.com/pgsty/pigsty-app/tree/master/cloud

Online Demo: https://demo.pigsty.io/d/ecs

Article: Analyzing Computing Costs: Has Aliyun Really Reduced Prices?

Data Source

Aliyun ECS pricing can be obtained as raw CSV data from Price Calculator - Pricing Details - Price Download.

Schema

Download Aliyun pricing details and import for analysis

CREATE EXTENSION file_fdw;
CREATE SERVER fs FOREIGN DATA WRAPPER file_fdw;

DROP FOREIGN TABLE IF EXISTS aliyun_ecs CASCADE;
CREATE FOREIGN TABLE aliyun_ecs
    (
        "region" text,
        "system" text,
        "network" text,
        "isIO" bool,
        "instanceId" text,
        "hourlyPrice" numeric,
        "weeklyPrice" numeric,
        "standard" numeric,
        "monthlyPrice" numeric,
        "yearlyPrice" numeric,
        "2yearPrice" numeric,
        "3yearPrice" numeric,
        "4yearPrice" numeric,
        "5yearPrice" numeric,
        "id" text,
        "instanceLabel" text,
        "familyId" text,
        "serverType" text,
        "cpu" text,
        "localStorage" text,
        "NvmeSupport" text,
        "InstanceFamilyLevel" text,
        "EniTrunkSupported" text,
        "InstancePpsRx" text,
        "GPUSpec" text,
        "CpuTurboFrequency" text,
        "InstancePpsTx" text,
        "InstanceTypeId" text,
        "GPUAmount" text,
        "InstanceTypeFamily" text,
        "SecondaryEniQueueNumber" text,
        "EniQuantity" text,
        "EniPrivateIpAddressQuantity" text,
        "DiskQuantity" text,
        "EniIpv6AddressQuantity" text,
        "InstanceCategory" text,
        "CpuArchitecture" text,
        "EriQuantity" text,
        "MemorySize" numeric,
        "EniTotalQuantity" numeric,
        "PhysicalProcessorModel" text,
        "InstanceBandwidthRx" numeric,
        "CpuCoreCount" numeric,
        "Generation" text,
        "CpuSpeedFrequency" numeric,
        "PrimaryEniQueueNumber" text,
        "LocalStorageCategory" text,
        "InstanceBandwidthTx" text,
        "TotalEniQueueQuantity" text
        ) SERVER fs OPTIONS ( filename '/tmp/aliyun-ecs.csv', format 'csv',header 'true');

Similarly for AWS EC2, you can download the price list from Vantage:


DROP FOREIGN TABLE IF EXISTS aws_ec2 CASCADE;
CREATE FOREIGN TABLE aws_ec2
    (
        "name" TEXT,
        "id" TEXT,
        "Memory" TEXT,
        "vCPUs" TEXT,
        "GPUs" TEXT,
        "ClockSpeed" TEXT,
        "InstanceStorage" TEXT,
        "NetworkPerformance" TEXT,
        "ondemand" TEXT,
        "reserve" TEXT,
        "spot" TEXT
        ) SERVER fs OPTIONS ( filename '/tmp/aws-ec2.csv', format 'csv',header 'true');



DROP VIEW IF EXISTS ecs;
CREATE VIEW ecs AS
SELECT "region"                                       AS region,
       "id"                                           AS id,
       "instanceLabel"                                AS name,
       "familyId"                                     AS family,
       "CpuCoreCount"                                 AS cpu,
       "MemorySize"                                   AS mem,
       round("5yearPrice" / "CpuCoreCount" / 60, 2)   AS ycm5, -- ¥ / (core·month)
       round("4yearPrice" / "CpuCoreCount" / 48, 2)   AS ycm4, -- ¥ / (core·month)
       round("3yearPrice" / "CpuCoreCount" / 36, 2)   AS ycm3, -- ¥ / (core·month)
       round("2yearPrice" / "CpuCoreCount" / 24, 2)   AS ycm2, -- ¥ / (core·month)
       round("yearlyPrice" / "CpuCoreCount" / 12, 2)  AS ycm1, -- ¥ / (core·month)
       round("standard" / "CpuCoreCount", 2)          AS ycmm, -- ¥ / (core·month)
       round("hourlyPrice" / "CpuCoreCount" * 720, 2) AS ycmh, -- ¥ / (core·month)
       "CpuSpeedFrequency"::NUMERIC                   AS freq,
       "CpuTurboFrequency"::NUMERIC                   AS freq_turbo,
       "Generation"                                   AS generation
FROM aliyun_ecs
WHERE system = 'linux';

DROP VIEW IF EXISTS ec2;
CREATE VIEW ec2 AS
SELECT id,
       name,
       split_part(id, '.', 1)                                                               as family,
       split_part(id, '.', 2)                                                               as spec,
       (regexp_match(split_part(id, '.', 1), '^[a-zA-Z]+(\d)[a-z0-9]*'))[1]                 as gen,
       regexp_substr("vCPUs", '^[0-9]+')::int                                               as cpu,
       regexp_substr("Memory", '^[0-9]+')::int                                              as mem,
       CASE spot
           WHEN 'unavailable' THEN NULL
           ELSE round((regexp_substr("spot", '([0-9]+.[0-9]+)')::NUMERIC * 7.2), 2) END     AS spot,
       CASE ondemand
           WHEN 'unavailable' THEN NULL
           ELSE round((regexp_substr("ondemand", '([0-9]+.[0-9]+)')::NUMERIC * 7.2), 2) END AS ondemand,
       CASE reserve
           WHEN 'unavailable' THEN NULL
           ELSE round((regexp_substr("reserve", '([0-9]+.[0-9]+)')::NUMERIC * 7.2), 2) END  AS reserve,
       "ClockSpeed"                                                                         AS freq
FROM aws_ec2;

Visualization

8 - Conf Templates

Batteries-included configuration templates for specific scenarios, with detailed explanations.

Pigsty provides various ready-to-use configuration templates for different deployment scenarios.

You can specify a configuration template with the -c option during configure. If no template is specified, the default meta template is used.

CategoryTemplates
Solo Templatesmeta, rich, fat, slim, infra
Kernel Templatespgsql, citus, mssql, polar, ivory, mysql, pgtde, oriole, supabase
HA Templatesha/simu, ha/full, ha/safe, ha/trio, ha/dual
App Templatesapp/odoo, app/dify, app/electric, app/maybe, app/teable, app/registry
Misc Templatesdemo/el, demo/debian, demo/demo, demo/minio, build/oss, build/pro

8.1 - Solo Templates

8.2 - meta

Default single-node installation template with extensive configuration parameter descriptions

The meta configuration template is Pigsty’s default template, designed to fulfill Pigsty’s core functionality—deploying PostgreSQL—on a single node.

To maximize compatibility, meta installs only the minimum required software set to ensure it runs across all operating system distributions and architectures.


Overview

  • Config Name: meta
  • Node Count: Single node
  • Description: Default single-node installation template with extensive configuration parameter descriptions and minimum required feature set.
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta, slim, fat

Usage: This is the default config template, so there’s no need to specify -c meta explicitly during configure:

./configure [-i <primary_ip>]

For example, if you want to install PostgreSQL 17 rather than the default 18, you can use the -v arg in configure:

./configure -v 17   # or 16,15,14,13....

Content

Source: pigsty/conf/meta.yml

---
#==============================================================#
# File      :   meta.yml
# Desc      :   Pigsty default 1-node online install config
# Ctime     :   2020-05-22
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the default 1-node configuration template, with:
# INFRA, NODE, PGSQL, ETCD, MINIO, DOCKER, APP (pgadmin)
# with basic pg extensions: postgis, pgvector
#
# Work with PostgreSQL 14-18 on all supported platform
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure
#   ./deploy.yml

all:

  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql
    #----------------------------------------------#
    # this is an example single-node postgres cluster with pgvector installed, with one biz database & two biz users
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary } # <---- primary instance with read-write capability
        #x.xx.xx.xx: { pg_seq: 2, pg_role: replica } # <---- read only replica for read-only online traffic
        #x.xx.xx.xy: { pg_seq: 3, pg_role: offline } # <---- offline instance of ETL & interactive queries
      vars:
        pg_cluster: pg-meta

        # install, load, create pg extensions: https://doc.pgsty.com/pgsql/extension
        pg_extensions: [ postgis, pgvector ]

        # define business users/roles : https://doc.pgsty.com/pgsql/user
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }

        # define business databases : https://doc.pgsty.com/pgsql/db
        pg_databases:
          - name: meta
            baseline: cmdb.sql
            comment: "pigsty meta database"
            schemas: [pigsty]
            # define extensions in database : https://doc.pgsty.com/pgsql/extension/create
            extensions: [ postgis, vector ]

        # define HBA rules : https://doc.pgsty.com/pgsql/hba
        pg_hba_rules:
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }

        # define backup policies: https://doc.pgsty.com/pgsql/backup
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every day 1am

        # define (OPTIONAL) L2 VIP that bind to primary
        #pg_vip_enabled: true
        #pg_vip_address: 10.10.10.2/24
        #pg_vip_interface: eth1


    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra
    #----------------------------------------------#
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        repo_enabled: false   # disable in 1-node mode :  https://doc.pgsty.com/admin/repo
        #repo_extra_packages: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # ETCD : https://doc.pgsty.com/etcd
    #----------------------------------------------#
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd
        etcd_safeguard: false             # prevent purging running etcd instance?

    #----------------------------------------------#
    # MINIO : https://doc.pgsty.com/minio
    #----------------------------------------------#
    #minio:
    #  hosts:
    #    10.10.10.10: { minio_seq: 1 }
    #  vars:
    #    minio_cluster: minio
    #    minio_users:                      # list of minio user to be created
    #      - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
    #      - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
    #      - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    #----------------------------------------------#
    # DOCKER : https://doc.pgsty.com/docker
    # APP    : https://doc.pgsty.com/app
    #----------------------------------------------#
    # launch example pgadmin app with: ./app.yml (http://10.10.10.10:8885 [email protected] / pigsty)
    app:
      hosts: { 10.10.10.10: {} }
      vars:
        docker_enabled: true                # enabled docker with ./docker.yml
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        app: pgadmin                        # specify the default app name to be installed (in the apps)
        apps:                               # define all applications, appname: definition
          pgadmin:                          # pgadmin app definition (app/pgadmin -> /opt/pgadmin)
            conf:                           # override /opt/pgadmin/.env
              PGADMIN_DEFAULT_EMAIL: [email protected]
              PGADMIN_DEFAULT_PASSWORD: pigsty


  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra
    #----------------------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: china                     # upstream mirror region: default|china|europe
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name
      pgadmin : { domain: adm.pigsty ,endpoint: "${admin_ip}:8885" }
      #minio  : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: false             # do not overwrite node hostname on single node mode
    node_tune: oltp                       # node tuning specs: oltp,olap,tiny,crit
    node_etc_hosts: [ '${admin_ip} i.pigsty sss.pigsty' ]
    node_repo_modules: 'node,infra,pgsql' # add these repos directly to the singleton node
    #node_repo_modules: local             # use this if you want to build & user local repo
    node_repo_remove: true                # remove existing node repo for node managed by pigsty
    #node_packages: [openssh-server]      # packages to be installed current nodes with the latest version

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # default postgres version
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_safeguard: false                 # prevent purging running postgres instance?
    pg_packages: [ pgsql-main, pgsql-common ]                 # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # BACKUP : https://doc.pgsty.com/pgsql/backup
    #----------------------------------------------#
    # if you want to use minio as backup repo instead of 'local' fs, uncomment this, and configure `pgbackrest_repo`
    # you can also use external object storage as backup repo
    #pgbackrest_method: minio          # if you want to use minio as backup repo instead of 'local' fs, uncomment this
    #pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
    #  local:                          # default pgbackrest repo with local posix fs
    #    path: /pg/backup              # local backup directory, `/pg/backup` by default
    #    retention_full_type: count    # retention full backups by count
    #    retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
    #  minio:                          # optional minio repo for pgbackrest
    #    type: s3                      # minio is s3-compatible, so s3 is used
    #    s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
    #    s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
    #    s3_bucket: pgsql              # minio bucket name, `pgsql` by default
    #    s3_key: pgbackrest            # minio user access key for pgbackrest
    #    s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
    #    s3_uri_style: path            # use path style uri for minio rather than host style
    #    path: /pgbackrest             # minio backup path, default is `/pgbackrest`
    #    storage_port: 9000            # minio port, 9000 by default
    #    storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
    #    block: y                      # Enable block incremental backup
    #    bundle: y                     # bundle small files into a single file
    #    bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
    #    bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
    #    cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
    #    cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
    #    retention_full_type: time     # retention full backup by time on minio repo
    #    retention_full: 14            # keep full backup for last 14 days
    #  s3: # aliyun oss (s3 compatible) object storage service
    #    type: s3                      # oss is s3-compatible
    #    s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
    #    s3_region: oss-cn-beijing
    #    s3_bucket: <your_bucket_name>
    #    s3_key: <your_access_key>
    #    s3_key_secret: <your_secret_key>
    #    s3_uri_style: host
    #    path: /pgbackrest
    #    bundle: y                     # bundle small files into a single file
    #    bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
    #    bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
    #    cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
    #    cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
    #    retention_full_type: time     # retention full backup by time on minio repo
    #    retention_full: 14            # keep full backup for last 14 days

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The meta template is Pigsty’s default getting-started configuration, designed for quick onboarding.

Use Cases:

  • First-time Pigsty users
  • Quick deployment in development and testing environments
  • Small production environments running on a single machine
  • As a base template for more complex deployments

Key Features:

  • Online installation mode without building local software repository (repo_enabled: false)
  • Default installs PostgreSQL 18 with postgis and pgvector extensions
  • Includes complete monitoring infrastructure (Grafana, Prometheus, Loki, etc.)
  • Preconfigured Docker and pgAdmin application examples
  • MinIO backup storage disabled by default, can be enabled as needed

Notes:

  • Default passwords are sample passwords; must be changed for production environments
  • Single-node etcd has no high availability guarantee, suitable for development and testing
  • If you need to build a local software repository, use the rich template

8.3 - rich

Feature-rich single-node configuration with local software repository, all extensions, MinIO backup, and complete examples

The rich configuration template is an enhanced version of meta, designed for users who need to experience complete functionality.

If you want to build a local software repository, use MinIO for backup storage, run Docker applications, or need preconfigured business databases, use this template.


Overview

  • Config Name: rich
  • Node Count: Single node
  • Description: Feature-rich single-node configuration, adding local software repository, MinIO backup, complete extensions, Docker application examples on top of meta
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta, slim, fat

This template’s main enhancements over meta:

  • Builds local software repository (repo_enabled: true), downloads all PG extensions
  • Enables single-node MinIO as PostgreSQL backup storage
  • Preinstalls TimescaleDB, pgvector, pg_wait_sampling and other extensions
  • Includes detailed user/database/service definition comment examples
  • Adds Redis primary-replica instance example
  • Preconfigures pg-test three-node HA cluster configuration stub

Usage:

./configure -c rich [-i <primary_ip>]

Content

Source: pigsty/conf/rich.yml

---
#==============================================================#
# File      :   rich.yml
# Desc      :   Pigsty feature-rich 1-node online install config
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the enhanced version of default meta.yml, which has:
# - almost all available postgres extensions
# - build local software repo for entire env
# - 1 node minio used as central backup repo
# - cluster stub for 3-node pg-test / ferret / redis
# - stub for nginx, certs, and website self-hosting config
# - detailed comments for database / user / service
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c rich
#   ./deploy.yml

all:

  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql
    #----------------------------------------------#
    # this is an example single-node postgres cluster with pgvector installed, with one biz database & two biz users
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary } # <---- primary instance with read-write capability
        #x.xx.xx.xx: { pg_seq: 2, pg_role: replica } # <---- read only replica for read-only online traffic
        #x.xx.xx.xy: { pg_seq: 3, pg_role: offline } # <---- offline instance of ETL & interactive queries
      vars:
        pg_cluster: pg-meta

        # install, load, create pg extensions: https://doc.pgsty.com/pgsql/extension
        pg_extensions: [ postgis, timescaledb, pgvector, pg_wait_sampling ]
        pg_libs: 'timescaledb, pg_stat_statements, auto_explain, pg_wait_sampling'

        # define business users/roles : https://doc.pgsty.com/pgsql/user
        pg_users:
          - name: dbuser_meta               # REQUIRED, `name` is the only mandatory field of a user definition
            password: DBUser.Meta           # optional, the password. can be a scram-sha-256 hash string or plain text
            #state: create                   # optional, create|absent, 'create' by default, use 'absent' to drop user
            #login: true                     # optional, can log in, true by default (new biz ROLE should be false)
            #superuser: false                # optional, is superuser? false by default
            #createdb: false                 # optional, can create databases? false by default
            #createrole: false               # optional, can create role? false by default
            #inherit: true                   # optional, can this role use inherited privileges? true by default
            #replication: false              # optional, can this role do replication? false by default
            #bypassrls: false                # optional, can this role bypass row level security? false by default
            #pgbouncer: true                 # optional, add this user to the pgbouncer user-list? false by default (production user should be true explicitly)
            #connlimit: -1                   # optional, user connection limit, default -1 disable limit
            #expire_in: 3650                 # optional, now + n days when this role is expired (OVERWRITE expire_at)
            #expire_at: '2030-12-31'         # optional, YYYY-MM-DD 'timestamp' when this role is expired (OVERWRITTEN by expire_in)
            #comment: pigsty admin user      # optional, comment string for this user/role
            #roles: [dbrole_admin]           # optional, belonged roles. default roles are: dbrole_{admin|readonly|readwrite|offline}
            #parameters: {}                  # optional, role level parameters with `ALTER ROLE SET`
            #pool_mode: transaction          # optional, pgbouncer pool mode at user level, transaction by default
            #pool_connlimit: -1              # optional, max database connections at user level, default -1 disable limit
            # Enhanced roles syntax (PG16+): roles can be string or object with options:
            #   - dbrole_readwrite                       # simple string: GRANT role
            #   - { name: role, admin: true }            # GRANT WITH ADMIN OPTION
            #   - { name: role, set: false }             # PG16: REVOKE SET OPTION
            #   - { name: role, inherit: false }         # PG16: REVOKE INHERIT OPTION
            #   - { name: role, state: absent }          # REVOKE membership
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly], comment: read-only viewer for meta database }
          #- {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin] ,comment: admin user for bytebase database   }
          #- {name: dbuser_remove ,state: absent }       # use state: absent to remove a user

        # define business databases : https://doc.pgsty.com/pgsql/db
        pg_databases:                       # define business databases on this cluster, array of database definition
          - name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
            #state: create                  # optional, create|absent|recreate, create by default
            baseline: cmdb.sql              # optional, database sql baseline path, (relative path among the ansible search path, e.g.: files/)
            schemas: [ pigsty ]             # optional, additional schemas to be created, array of schema names
            extensions:                     # optional, additional extensions to be installed: array of `{name[,schema]}`
              - vector                      # install pgvector for vector similarity search
              - postgis                     # install postgis for geospatial type & index
              - timescaledb                 # install timescaledb for time-series data
              - { name: pg_wait_sampling, schema: monitor } # install pg_wait_sampling on monitor schema
            comment: pigsty meta database   # optional, comment string for this database
            #pgbouncer: true                # optional, add this database to the pgbouncer database list? true by default
            #owner: postgres                # optional, database owner, current user if not specified
            #template: template1            # optional, which template to use, template1 by default
            #strategy: FILE_COPY            # optional, clone strategy: FILE_COPY or WAL_LOG (PG15+), default to PG's default
            #encoding: UTF8                 # optional, inherited from template / cluster if not defined (UTF8)
            #locale: C                      # optional, inherited from template / cluster if not defined (C)
            #lc_collate: C                  # optional, inherited from template / cluster if not defined (C)
            #lc_ctype: C                    # optional, inherited from template / cluster if not defined (C)
            #locale_provider: libc          # optional, locale provider: libc, icu, builtin (PG15+)
            #icu_locale: en-US              # optional, icu locale for icu locale provider (PG15+)
            #icu_rules: ''                  # optional, icu rules for icu locale provider (PG16+)
            #builtin_locale: C.UTF-8        # optional, builtin locale for builtin locale provider (PG17+)
            #tablespace: pg_default         # optional, default tablespace, pg_default by default
            #is_template: false             # optional, mark database as template, allowing clone by any user with CREATEDB privilege
            #allowconn: true                # optional, allow connection, true by default. false will disable connect at all
            #revokeconn: false              # optional, revoke public connection privilege. false by default. (leave connect with grant option to owner)
            #register_datasource: true      # optional, register this database to grafana datasources? true by default
            #connlimit: -1                  # optional, database connection limit, default -1 disable limit
            #pool_auth_user: dbuser_meta    # optional, all connection to this pgbouncer database will be authenticated by this user
            #pool_mode: transaction         # optional, pgbouncer pool mode at database level, default transaction
            #pool_size: 64                  # optional, pgbouncer pool size at database level, default 64
            #pool_size_reserve: 32          # optional, pgbouncer pool size reserve at database level, default 32
            #pool_size_min: 0               # optional, pgbouncer pool size min at database level, default 0
            #pool_max_db_conn: 100          # optional, max database connections at database level, default 100
          #- {name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }

        # define HBA rules : https://doc.pgsty.com/pgsql/hba
        pg_hba_rules:
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }

        # define backup policies: https://doc.pgsty.com/pgsql/backup
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every day 1am

        # define (OPTIONAL) L2 VIP that bind to primary
        #pg_vip_enabled: true
        #pg_vip_address: 10.10.10.2/24
        #pg_vip_interface: eth1

    #----------------------------------------------#
    # PGSQL HA Cluster Example: 3-node pg-test
    #----------------------------------------------#
    #pg-test:
    #  hosts:
    #    10.10.10.11: { pg_seq: 1, pg_role: primary }   # primary instance, leader of cluster
    #    10.10.10.12: { pg_seq: 2, pg_role: replica }   # replica instance, follower of leader
    #    10.10.10.13: { pg_seq: 3, pg_role: replica, pg_offline_query: true } # replica with offline access
    #  vars:
    #    pg_cluster: pg-test           # define pgsql cluster name
    #    pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
    #    pg_databases: [{ name: test }]
    #    # define business service here: https://doc.pgsty.com/pgsql/service
    #    pg_services:                        # extra services in addition to pg_default_services, array of service definition
    #      # standby service will route {ip|name}:5435 to sync replica's pgbouncer (5435->6432 standby)
    #      - name: standby                   # required, service name, the actual svc name will be prefixed with `pg_cluster`, e.g: pg-meta-standby
    #        port: 5435                      # required, service exposed port (work as kubernetes service node port mode)
    #        ip: "*"                         # optional, service bind ip address, `*` for all ip by default
    #        selector: "[]"                  # required, service member selector, use JMESPath to filter inventory
    #        dest: default                   # optional, destination port, default|postgres|pgbouncer|<port_number>, 'default' by default
    #        check: /sync                    # optional, health check url path, / by default
    #        backup: "[? pg_role == `primary`]"  # backup server selector
    #        maxconn: 3000                   # optional, max allowed front-end connection
    #        balance: roundrobin             # optional, haproxy load balance algorithm (roundrobin by default, other: leastconn)
    #        options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'
    #    pg_vip_enabled: true
    #    pg_vip_address: 10.10.10.3/24
    #    pg_vip_interface: eth1
    #    node_crontab:  # make a full backup on monday 1am, and an incremental backup during weekdays
    #      - '00 01 * * 1 postgres /pg/bin/pg-backup full'
    #      - '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'

    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra
    #----------------------------------------------#
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        repo_enabled: true    # build local repo, and install everything from it:  https://doc.pgsty.com/admin/repo
        # and download all extensions into local repo
        repo_extra_packages: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # ETCD : https://doc.pgsty.com/etcd
    #----------------------------------------------#
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd
        etcd_safeguard: false             # prevent purging running etcd instance?

    #----------------------------------------------#
    # MINIO : https://doc.pgsty.com/minio
    #----------------------------------------------#
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1 }
      vars:
        minio_cluster: minio
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    #----------------------------------------------#
    # DOCKER : https://doc.pgsty.com/docker
    # APP    : https://doc.pgsty.com/app
    #----------------------------------------------#
    # OPTIONAL, launch example pgadmin app with: ./app.yml & ./app.yml -e app=bytebase
    app:
      hosts: { 10.10.10.10: {} }
      vars:
        docker_enabled: true                # enabled docker with ./docker.yml
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        app: pgadmin                        # specify the default app name to be installed (in the apps)
        apps:                               # define all applications, appname: definition

          # Admin GUI for PostgreSQL, launch with: ./app.yml
          pgadmin:                          # pgadmin app definition (app/pgadmin -> /opt/pgadmin)
            conf:                           # override /opt/pgadmin/.env
              PGADMIN_DEFAULT_EMAIL: [email protected]   # default user name
              PGADMIN_DEFAULT_PASSWORD: pigsty         # default password

          # Schema Migration GUI for PostgreSQL, launch with: ./app.yml -e app=bytebase
          bytebase:
            conf:
              BB_DOMAIN: http://ddl.pigsty  # replace it with your public domain name and postgres database url
              BB_PGURL: "postgresql://dbuser_bytebase:[email protected]:5432/bytebase?sslmode=prefer"

    #----------------------------------------------#
    # REDIS : https://doc.pgsty.com/redis
    #----------------------------------------------#
    # OPTIONAL, launch redis clusters with: ./redis.yml
    redis-ms:
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }



  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra
    #----------------------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]

    certbot_sign: false               # enable certbot to sign https certificate for infra portal
    certbot_email: [email protected]     # replace your email address to receive expiration notice
    infra_portal:                     # infra services exposed via portal
      home      : { domain: i.pigsty }     # default domain name
      pgadmin   : { domain: adm.pigsty ,endpoint: "${admin_ip}:8885" }
      bytebase  : { domain: ddl.pigsty ,endpoint: "${admin_ip}:8887" }
      minio     : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

      #website:   # static local website example stub
      #  domain: repo.pigsty              # external domain name for static site
      #  certbot: repo.pigsty             # use certbot to sign https certificate for this static site
      #  path: /www/pigsty                # path to the static site directory

      #supabase:  # dynamic upstream service example stub
      #  domain: supa.pigsty          # external domain name for upstream service
      #  certbot: supa.pigsty         # use certbot to sign https certificate for this upstream server
      #  endpoint: "10.10.10.10:8000" # path to the static site directory
      #  websocket: true              # add websocket support
      #  certbot: supa.pigsty         # certbot cert name, apply with `make cert`

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: false             # do not overwrite node hostname on single node mode
    node_tune: oltp                       # node tuning specs: oltp,olap,tiny,crit
    node_etc_hosts:                       # add static domains to all nodes /etc/hosts
      - '${admin_ip} i.pigsty sss.pigsty'
      - '${admin_ip} adm.pigsty ddl.pigsty repo.pigsty supa.pigsty'
    node_repo_modules: local              # use pre-made local repo rather than install from upstream
    node_repo_remove: true                # remove existing node repo for node managed by pigsty
    #node_packages: [openssh-server]      # packages to be installed current nodes with latest version
    #node_timezone: Asia/Hong_Kong        # overwrite node timezone

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # default postgres version
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_safeguard: false                 # prevent purging running postgres instance?
    pg_packages: [ pgsql-main, pgsql-common ]                 # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # BACKUP : https://doc.pgsty.com/pgsql/backup
    #----------------------------------------------#
    # if you want to use minio as backup repo instead of 'local' fs, uncomment this, and configure `pgbackrest_repo`
    # you can also use external object storage as backup repo
    pgbackrest_method: minio          # if you want to use minio as backup repo instead of 'local' fs, uncomment this
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backups when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest [CHANGE ACCORDING to minio_users.pgbackrest]
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest [CHANGE ACCORDING to minio_users.pgbackrest]
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the last 14 days
      s3:                             # you can use cloud object storage as backup repo
        type: s3                      # Add your object storage credentials here!
        s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
        s3_region: oss-cn-beijing
        s3_bucket: <your_bucket_name>
        s3_key: <your_access_key>
        s3_key_secret: <your_secret_key>
        s3_uri_style: host
        path: /pgbackrest
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the last 14 days
...

Explanation

The rich template is Pigsty’s complete functionality showcase configuration, suitable for users who want to deeply experience all features.

Use Cases:

  • Offline environments requiring local software repository
  • Environments needing MinIO as PostgreSQL backup storage
  • Pre-planning multiple business databases and users
  • Running Docker applications (pgAdmin, Bytebase, etc.)
  • Learners wanting to understand complete configuration parameter usage

Main Differences from meta:

  • Enables local software repository building (repo_enabled: true)
  • Enables MinIO storage backup (pgbackrest_method: minio)
  • Preinstalls TimescaleDB, pg_wait_sampling and other additional extensions
  • Includes detailed parameter comments for understanding configuration meanings
  • Preconfigures HA cluster stub configuration (pg-test)

Notes:

  • Some extensions unavailable on ARM64 architecture, adjust as needed
  • Building local software repository requires longer time and larger disk space
  • Default passwords are sample passwords, must be changed for production

8.4 - slim

Minimal installation template without monitoring infrastructure, installs PostgreSQL directly from internet

The slim configuration template provides minimal installation capability, installing a PostgreSQL high-availability cluster directly from the internet without deploying Infra monitoring infrastructure.

When you only need an available database instance without the monitoring system, consider using the Slim Installation mode.


Overview

  • Config Name: slim
  • Node Count: Single node
  • Description: Minimal installation template without monitoring infrastructure, installs PostgreSQL directly
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c slim [-i <primary_ip>]
./slim.yml   # Execute slim installation

Content

Source: pigsty/conf/slim.yml

---
#==============================================================#
# File      :   slim.yml
# Desc      :   Pigsty slim installation config template
# Ctime     :   2020-05-22
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for slim / minimal installation
# No monitoring & infra will be installed, just raw postgresql
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c slim
#   ./slim.yml

all:
  children:

    etcd: # dcs service for postgres/patroni ha consensus
      hosts: # 1 node for testing, 3 or 5 for production
        10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
        #10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
        #10.10.10.12: { etcd_seq: 3 }  # odd number please
      vars: # cluster level parameter override roles/etcd
        etcd_cluster: etcd  # mark etcd cluster name etcd

    #----------------------------------------------#
    # PostgreSQL Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        #10.10.10.11: { pg_seq: 2, pg_role: replica } # you can add more!
        #10.10.10.12: { pg_seq: 3, pg_role: replica, pg_offline_query: true }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        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' ] # make a full backup every 1am

  vars:
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_version: 18                      # Default PostgreSQL Major Version is 18
    pg_packages: [ pgsql-main, pgsql-common ]   # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The slim template is Pigsty’s minimal installation configuration, designed for quick deployment of bare PostgreSQL clusters.

Use Cases:

  • Only need PostgreSQL database, no monitoring system required
  • Resource-limited small servers or edge devices
  • Quick deployment of temporary test databases
  • Already have monitoring system, only need PostgreSQL HA cluster

Key Features:

  • Uses slim.yml playbook instead of deploy.yml for installation
  • Installs software directly from internet, no local software repository
  • Retains core PostgreSQL HA capability (Patroni + etcd + HAProxy)
  • Minimized package downloads, faster installation
  • Default uses PostgreSQL 18

Differences from meta:

  • slim uses dedicated slim.yml playbook, skips Infra module installation
  • Faster installation, less resource usage
  • Suitable for “just need a database” scenarios

Notes:

  • After slim installation, cannot view database status through Grafana
  • If monitoring is needed, use meta or rich template
  • Can add replicas as needed for high availability

8.5 - fat

Feature-All-Test template, single-node installation of all extensions, builds local repo with PG 13-18 all versions

The fat configuration template is Pigsty’s Feature-All-Test template, installing all extension plugins on a single node and building a local software repository containing all extensions for PostgreSQL 13-18 (six major versions).

This is a full-featured configuration for testing and development, suitable for scenarios requiring complete software package cache or testing all extensions.


Overview

  • Config Name: fat
  • Node Count: Single node
  • Description: Feature-All-Test template, installs all extensions, builds local repo with PG 13-18 all versions
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta, slim, fat

Usage:

./configure -c fat [-i <primary_ip>]

To specify a particular PostgreSQL version:

./configure -c fat -v 17   # Use PostgreSQL 17

Content

Source: pigsty/conf/fat.yml

---
#==============================================================#
# File      :   fat.yml
# Desc      :   Pigsty Feature-All-Test config template
# Ctime     :   2020-05-22
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the 4-node sandbox for pigsty
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c fat [-v 18|17|16|15]
#   ./deploy.yml

all:

  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql
    #----------------------------------------------#
    # this is an example single-node postgres cluster with pgvector installed, with one biz database & two biz users
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary } # <---- primary instance with read-write capability
        #x.xx.xx.xx: { pg_seq: 2, pg_role: replica } # <---- read only replica for read-only online traffic
        #x.xx.xx.xy: { pg_seq: 3, pg_role: offline } # <---- offline instance of ETL & interactive queries
      vars:
        pg_cluster: pg-meta

        # install, load, create pg extensions: https://doc.pgsty.com/pgsql/extension
        pg_extensions: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
        pg_libs: 'timescaledb, pg_stat_statements, auto_explain, pg_wait_sampling'

        # define business users/roles : https://doc.pgsty.com/pgsql/user
        pg_users:
          - name: dbuser_meta               # REQUIRED, `name` is the only mandatory field of a user definition
            password: DBUser.Meta           # optional, the password. can be a scram-sha-256 hash string or plain text
            #state: create                   # optional, create|absent, 'create' by default, use 'absent' to drop user
            #login: true                     # optional, can log in, true by default (new biz ROLE should be false)
            #superuser: false                # optional, is superuser? false by default
            #createdb: false                 # optional, can create databases? false by default
            #createrole: false               # optional, can create role? false by default
            #inherit: true                   # optional, can this role use inherited privileges? true by default
            #replication: false              # optional, can this role do replication? false by default
            #bypassrls: false                # optional, can this role bypass row level security? false by default
            #pgbouncer: true                 # optional, add this user to the pgbouncer user-list? false by default (production user should be true explicitly)
            #connlimit: -1                   # optional, user connection limit, default -1 disable limit
            #expire_in: 3650                 # optional, now + n days when this role is expired (OVERWRITE expire_at)
            #expire_at: '2030-12-31'         # optional, YYYY-MM-DD 'timestamp' when this role is expired (OVERWRITTEN by expire_in)
            #comment: pigsty admin user      # optional, comment string for this user/role
            #roles: [dbrole_admin]           # optional, belonged roles. default roles are: dbrole_{admin|readonly|readwrite|offline}
            #parameters: {}                  # optional, role level parameters with `ALTER ROLE SET`
            #pool_mode: transaction          # optional, pgbouncer pool mode at user level, transaction by default
            #pool_connlimit: -1              # optional, max database connections at user level, default -1 disable limit
            # Enhanced roles syntax (PG16+): roles can be string or object with options:
            #   - dbrole_readwrite                       # simple string: GRANT role
            #   - { name: role, admin: true }            # GRANT WITH ADMIN OPTION
            #   - { name: role, set: false }             # PG16: REVOKE SET OPTION
            #   - { name: role, inherit: false }         # PG16: REVOKE INHERIT OPTION
            #   - { name: role, state: absent }          # REVOKE membership
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly], comment: read-only viewer for meta database }
          #- {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin] ,comment: admin user for bytebase database   }
          #- {name: dbuser_remove ,state: absent }       # use state: absent to remove a user

        # define business databases : https://doc.pgsty.com/pgsql/db
        pg_databases:                       # define business databases on this cluster, array of database definition
          - name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
            #state: create                  # optional, create|absent|recreate, create by default
            baseline: cmdb.sql              # optional, database sql baseline path, (relative path among the ansible search path, e.g.: files/)
            schemas: [ pigsty ]             # optional, additional schemas to be created, array of schema names
            extensions:                     # optional, additional extensions to be installed: array of `{name[,schema]}`
              - vector                      # install pgvector for vector similarity search
              - postgis                     # install postgis for geospatial type & index
              - timescaledb                 # install timescaledb for time-series data
              - { name: pg_wait_sampling, schema: monitor } # install pg_wait_sampling on monitor schema
            comment: pigsty meta database   # optional, comment string for this database
            #pgbouncer: true                # optional, add this database to the pgbouncer database list? true by default
            #owner: postgres                # optional, database owner, current user if not specified
            #template: template1            # optional, which template to use, template1 by default
            #strategy: FILE_COPY            # optional, clone strategy: FILE_COPY or WAL_LOG (PG15+), default to PG's default
            #encoding: UTF8                 # optional, inherited from template / cluster if not defined (UTF8)
            #locale: C                      # optional, inherited from template / cluster if not defined (C)
            #lc_collate: C                  # optional, inherited from template / cluster if not defined (C)
            #lc_ctype: C                    # optional, inherited from template / cluster if not defined (C)
            #locale_provider: libc          # optional, locale provider: libc, icu, builtin (PG15+)
            #icu_locale: en-US              # optional, icu locale for icu locale provider (PG15+)
            #icu_rules: ''                  # optional, icu rules for icu locale provider (PG16+)
            #builtin_locale: C.UTF-8        # optional, builtin locale for builtin locale provider (PG17+)
            #tablespace: pg_default         # optional, default tablespace, pg_default by default
            #is_template: false             # optional, mark database as template, allowing clone by any user with CREATEDB privilege
            #allowconn: true                # optional, allow connection, true by default. false will disable connect at all
            #revokeconn: false              # optional, revoke public connection privilege. false by default. (leave connect with grant option to owner)
            #register_datasource: true      # optional, register this database to grafana datasources? true by default
            #connlimit: -1                  # optional, database connection limit, default -1 disable limit
            #pool_auth_user: dbuser_meta    # optional, all connection to this pgbouncer database will be authenticated by this user
            #pool_mode: transaction         # optional, pgbouncer pool mode at database level, default transaction
            #pool_size: 64                  # optional, pgbouncer pool size at database level, default 64
            #pool_size_reserve: 32          # optional, pgbouncer pool size reserve at database level, default 32
            #pool_size_min: 0               # optional, pgbouncer pool size min at database level, default 0
            #pool_max_db_conn: 100          # optional, max database connections at database level, default 100
          #- {name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }

        # define HBA rules : https://doc.pgsty.com/pgsql/hba
        pg_hba_rules:
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }

        # define backup policies: https://doc.pgsty.com/pgsql/backup
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every day 1am

        # define (OPTIONAL) L2 VIP that bind to primary
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24
        pg_vip_interface: eth1


    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra
    #----------------------------------------------#
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        repo_enabled: true # build local repo:  https://doc.pgsty.com/admin/repo
        #repo_extra_packages: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
        repo_packages: [
          node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-utility, extra-modules,
          pg18-full,pg18-time,pg18-gis,pg18-rag,pg18-fts,pg18-olap,pg18-feat,pg18-lang,pg18-type,pg18-util,pg18-func,pg18-admin,pg18-stat,pg18-sec,pg18-fdw,pg18-sim,pg18-etl,
          pg17-full,pg17-time,pg17-gis,pg17-rag,pg17-fts,pg17-olap,pg17-feat,pg17-lang,pg17-type,pg17-util,pg17-func,pg17-admin,pg17-stat,pg17-sec,pg17-fdw,pg17-sim,pg17-etl,
          pg16-full,pg16-time,pg16-gis,pg16-rag,pg16-fts,pg16-olap,pg16-feat,pg16-lang,pg16-type,pg16-util,pg16-func,pg16-admin,pg16-stat,pg16-sec,pg16-fdw,pg16-sim,pg16-etl,
          pg15-full,pg15-time,pg15-gis,pg15-rag,pg15-fts,pg15-olap,pg15-feat,pg15-lang,pg15-type,pg15-util,pg15-func,pg15-admin,pg15-stat,pg15-sec,pg15-fdw,pg15-sim,pg15-etl,
          pg14-full,pg14-time,pg14-gis,pg14-rag,pg14-fts,pg14-olap,pg14-feat,pg14-lang,pg14-type,pg14-util,pg14-func,pg14-admin,pg14-stat,pg14-sec,pg14-fdw,pg14-sim,pg14-etl,
          pg13-full,pg13-time,pg13-gis,pg13-rag,pg13-fts,pg13-olap,pg13-feat,pg13-lang,pg13-type,pg13-util,pg13-func,pg13-admin,pg13-stat,pg13-sec,pg13-fdw,pg13-sim,pg13-etl,
          infra-extra, kafka, java-runtime, sealos, tigerbeetle, polardb, ivorysql
        ]

    #----------------------------------------------#
    # ETCD : https://doc.pgsty.com/etcd
    #----------------------------------------------#
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd
        etcd_safeguard: false             # prevent purging running etcd instance?

    #----------------------------------------------#
    # MINIO : https://doc.pgsty.com/minio
    #----------------------------------------------#
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1 }
      vars:
        minio_cluster: minio
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    #----------------------------------------------#
    # DOCKER : https://doc.pgsty.com/docker
    # APP    : https://doc.pgsty.com/app
    #----------------------------------------------#
    # OPTIONAL, launch example pgadmin app with: ./app.yml & ./app.yml -e app=bytebase
    app:
      hosts: { 10.10.10.10: {} }
      vars:
        docker_enabled: true                # enabled docker with ./docker.yml
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        app: pgadmin                        # specify the default app name to be installed (in the apps)
        apps:                               # define all applications, appname: definition

          # Admin GUI for PostgreSQL, launch with: ./app.yml
          pgadmin:                          # pgadmin app definition (app/pgadmin -> /opt/pgadmin)
            conf:                           # override /opt/pgadmin/.env
              PGADMIN_DEFAULT_EMAIL: [email protected]   # default user name
              PGADMIN_DEFAULT_PASSWORD: pigsty         # default password

          # Schema Migration GUI for PostgreSQL, launch with: ./app.yml -e app=bytebase
          bytebase:
            conf:
              BB_DOMAIN: http://ddl.pigsty  # replace it with your public domain name and postgres database url
              BB_PGURL: "postgresql://dbuser_bytebase:[email protected]:5432/bytebase?sslmode=prefer"


  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra
    #----------------------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]

    certbot_sign: false               # enable certbot to sign https certificate for infra portal
    certbot_email: [email protected]     # replace your email address to receive expiration notice
    infra_portal:                     # domain names and upstream servers
      home         : { domain: i.pigsty }
      pgadmin      : { domain: adm.pigsty ,endpoint: "${admin_ip}:8885" }
      bytebase     : { domain: ddl.pigsty ,endpoint: "${admin_ip}:8887" ,websocket: true}
      minio        : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

      #website:   # static local website example stub
      #  domain: repo.pigsty              # external domain name for static site
      #  certbot: repo.pigsty             # use certbot to sign https certificate for this static site
      #  path: /www/pigsty                # path to the static site directory

      #supabase:  # dynamic upstream service example stub
      #  domain: supa.pigsty          # external domain name for upstream service
      #  certbot: supa.pigsty         # use certbot to sign https certificate for this upstream server
      #  endpoint: "10.10.10.10:8000" # path to the static site directory
      #  websocket: true              # add websocket support
      #  certbot: supa.pigsty         # certbot cert name, apply with `make cert`

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: true              # overwrite node hostname on multi-node template
    node_tune: oltp                       # node tuning specs: oltp,olap,tiny,crit
    node_etc_hosts:                       # add static domains to all nodes /etc/hosts
      - 10.10.10.10 i.pigsty sss.pigsty
      - 10.10.10.10 adm.pigsty ddl.pigsty repo.pigsty supa.pigsty
    node_repo_modules: local,node,infra,pgsql # use pre-made local repo rather than install from upstream
    node_repo_remove: true                # remove existing node repo for node managed by pigsty
    #node_packages: [openssh-server]      # packages to be installed current nodes with latest version
    #node_timezone: Asia/Hong_Kong        # overwrite node timezone

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # default postgres version
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_safeguard: false                 # prevent purging running postgres instance?
    pg_packages: [ pgsql-main, pgsql-common ] # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # BACKUP : https://doc.pgsty.com/pgsql/backup
    #----------------------------------------------#
    # if you want to use minio as backup repo instead of 'local' fs, uncomment this, and configure `pgbackrest_repo`
    # you can also use external object storage as backup repo
    pgbackrest_method: minio          # if you want to use minio as backup repo instead of 'local' fs, uncomment this
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backups when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest [CHANGE ACCORDING to minio_users.pgbackrest]
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest [CHANGE ACCORDING to minio_users.pgbackrest]
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the last 14 days
      s3:                             # you can use cloud object storage as backup repo
        type: s3                      # Add your object storage credentials here!
        s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
        s3_region: oss-cn-beijing
        s3_bucket: <your_bucket_name>
        s3_key: <your_access_key>
        s3_key_secret: <your_secret_key>
        s3_uri_style: host
        path: /pgbackrest
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the last 14 days

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The fat template is Pigsty’s full-featured test configuration, designed for completeness testing and offline package building.

Key Features:

  • All Extensions: Installs all categorized extension packages for PostgreSQL 18
  • Multi-version Repository: Local repo contains all six major versions of PostgreSQL 13-18
  • Complete Component Stack: Includes MinIO backup, Docker applications, VIP, etc.
  • Enterprise Components: Includes Kafka, PolarDB, IvorySQL, TigerBeetle, etc.

Repository Contents:

CategoryDescription
PostgreSQL 13-18Six major versions’ kernels and all extensions
Extension Categoriestime, gis, rag, fts, olap, feat, lang, type, util, func, admin, stat, sec, fdw, sim, etl
Enterprise ComponentsKafka, Java Runtime, Sealos, TigerBeetle
Database KernelsPolarDB, IvorySQL

Differences from rich:

  • fat contains all six versions of PostgreSQL 13-18, rich only contains current default version
  • fat contains additional enterprise components (Kafka, PolarDB, IvorySQL, etc.)
  • fat requires larger disk space and longer build time

Use Cases:

  • Pigsty development testing and feature validation
  • Building complete multi-version offline software packages
  • Testing all extension compatibility scenarios
  • Enterprise environments pre-caching all software packages

Notes:

  • Requires large disk space (100GB+ recommended) for storing all packages
  • Building local software repository requires longer time
  • Some extensions unavailable on ARM64 architecture
  • Default passwords are sample passwords, must be changed for production

8.6 - infra

Only installs observability infrastructure, dedicated template without PostgreSQL and etcd

The infra configuration template only deploys Pigsty’s observability infrastructure components (VictoriaMetrics/Grafana/Loki/Nginx, etc.), without PostgreSQL and etcd.

Suitable for scenarios requiring a standalone monitoring stack, such as monitoring external PostgreSQL/RDS instances or other data sources.


Overview

  • Config Name: infra
  • Node Count: Single or multiple nodes
  • Description: Only installs observability infrastructure, without PostgreSQL and etcd
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c infra [-i <primary_ip>]
./infra.yml    # Only execute infra playbook

Content

Source: pigsty/conf/infra.yml

---
#==============================================================#
# File      :   infra.yml
# Desc      :   Infra Only Config
# Ctime     :   2025-12-16
# Mtime     :   2025-12-30
# Docs      :   https://doc.pgsty.com/infra
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for deploy victoria stack alone
# tutorial: https://doc.pgsty.com/infra
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c infra
#   ./infra.yml

all:
  children:
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
        #10.10.10.11: { infra_seq: 2 } # you can add more nodes if you want
        #10.10.10.12: { infra_seq: 3 } # don't forget to assign unique infra_seq for each node
      vars:
        docker_enabled: true            # enabled docker with ./docker.yml
        docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        pg_exporters:     # bin/pgmon-add pg-rds
          20001: { pg_cluster: pg-rds ,pg_seq: 1 ,pg_host: 10.10.10.10 ,pg_exporter_url: 'postgres://postgres:[email protected]:5432/postgres' }

  vars:                                 # global variables
    version: v4.0.0                     # pigsty version string
    admin_ip: 10.10.10.10               # admin node ip address
    region: default                     # upstream mirror region: default,china,europe
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit
    infra_portal:                       # infra services exposed via portal
      home : { domain: i.pigsty }       # default domain name
    repo_enabled: false                 # online installation without repo
    node_repo_modules: node,infra,pgsql # add these repos directly
    #haproxy_enabled: false              # enable haproxy on infra node?
    #vector_enabled: false               # enable vector on infra node?

    # DON't FORGET TO CHANGE DEFAULT PASSWORDS!
    grafana_admin_password: pigsty
...

Explanation

The infra template is Pigsty’s pure monitoring stack configuration, designed for standalone deployment of observability infrastructure.

Use Cases:

  • Monitoring external PostgreSQL instances (RDS, self-hosted, etc.)
  • Need standalone monitoring/alerting platform
  • Already have PostgreSQL clusters, only need to add monitoring
  • As a central console for multi-cluster monitoring

Included Components:

  • VictoriaMetrics: Time series database for storing metrics
  • VictoriaLogs: Log aggregation system
  • VictoriaTraces: Distributed tracing system
  • Grafana: Visualization dashboards
  • Alertmanager: Alert management
  • Nginx: Reverse proxy and web entry

Not Included:

  • PostgreSQL database cluster
  • etcd distributed coordination service
  • MinIO object storage

Monitoring External Instances: After configuration, add monitoring for external PostgreSQL instances via the pgsql-monitor.yml playbook:

pg_exporters:
  20001: { pg_cluster: pg-foo, pg_seq: 1, pg_host: 10.10.10.100 }
  20002: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.101 }

Notes:

  • This template will not install any databases
  • For full functionality, use meta or rich template
  • Can add multiple infra nodes for high availability as needed

8.7 - Kernel Templates

8.8 - pgsql

Native PostgreSQL kernel, supports deployment of PostgreSQL versions 13 to 18

The pgsql configuration template uses the native PostgreSQL kernel, which is Pigsty’s default database kernel, supporting PostgreSQL versions 13 to 18.


Overview

  • Config Name: pgsql
  • Node Count: Single node
  • Description: Native PostgreSQL kernel configuration template
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c pgsql [-i <primary_ip>]

To specify a particular PostgreSQL version (e.g., 17):

./configure -c pgsql -v 17

Content

Source: pigsty/conf/pgsql.yml

---
#==============================================================#
# File      :   pgsql.yml
# Desc      :   1-node PostgreSQL Config template
# Ctime     :   2025-02-23
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for basical PostgreSQL Kernel.
# Nothing special, just a basic setup with one node.
# tutorial: https://doc.pgsty.com/pgsql/kernel/postgres
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c pgsql
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # PostgreSQL Cluster
    #----------------------------------------------#
    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 }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: meta, baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ postgis, timescaledb, vector ]}
        pg_extensions: [ postgis, timescaledb, pgvector, pg_wait_sampling ]
        pg_libs: 'timescaledb, pg_stat_statements, auto_explain, pg_wait_sampling'
        pg_hba_rules:
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

  vars:
    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra/param
    #----------------------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: false             # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # Default PostgreSQL Major Version is 18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_packages: [ pgsql-main, pgsql-common ]   # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The pgsql template is Pigsty’s standard kernel configuration, using community-native PostgreSQL.

Version Support:

  • PostgreSQL 18 (default)
  • PostgreSQL 17, 16, 15, 14, 13

Use Cases:

  • Need to use the latest PostgreSQL features
  • Need the widest extension support
  • Standard production environment deployment
  • Same functionality as meta template, explicitly declaring native kernel usage

Differences from meta:

  • pgsql template explicitly declares using native PostgreSQL kernel
  • Suitable for scenarios needing clear distinction between different kernel types

8.9 - citus

Citus distributed PostgreSQL cluster, provides horizontal scaling and sharding capabilities

The citus configuration template deploys a distributed PostgreSQL cluster using the Citus extension, providing transparent horizontal scaling and data sharding capabilities.


Overview

  • Config Name: citus
  • Node Count: Five nodes (1 coordinator + 4 data nodes)
  • Description: Citus distributed PostgreSQL cluster
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64
  • Related: meta

Usage:

./configure -c citus [-i <primary_ip>]

Content

Source: pigsty/conf/citus.yml

---
#==============================================================#
# File      :   citus.yml
# Desc      :   1-node Citus (Distributive) Config Template
# Ctime     :   2020-05-22
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for Citus Distributive Cluster
# tutorial: https://doc.pgsty.com/pgsql/kernel/citus
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c citus
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # pg-citus: 10 node citus cluster
    #----------------------------------------------#
    pg-citus: # the citus group contains 5 clusters
      hosts:
        10.10.10.10: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.60/24 ,pg_seq: 0, pg_role: primary }
        #10.10.10.11: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.60/24 ,pg_seq: 1, pg_role: replica }
        #10.10.10.12: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.61/24 ,pg_seq: 0, pg_role: primary }
        #10.10.10.13: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.61/24 ,pg_seq: 1, pg_role: replica }
        #10.10.10.14: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.62/24 ,pg_seq: 0, pg_role: primary }
        #10.10.10.15: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.62/24 ,pg_seq: 1, pg_role: replica }
        #10.10.10.16: { pg_group: 3, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.63/24 ,pg_seq: 0, pg_role: primary }
        #10.10.10.17: { pg_group: 3, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.63/24 ,pg_seq: 1, pg_role: replica }
        #10.10.10.18: { pg_group: 4, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.64/24 ,pg_seq: 0, pg_role: primary }
        #10.10.10.19: { pg_group: 4, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.64/24 ,pg_seq: 1, pg_role: replica }
      vars:
        pg_mode: citus                            # pgsql cluster mode: citus
        pg_shard: pg-citus                        # citus shard name: pg-citus
        pg_primary_db: citus                      # primary database used by citus
        pg_dbsu_password: DBUser.Postgres         # enable dbsu password access for citus
        pg_extensions: [ citus, postgis, pgvector, topn, pg_cron, hll ]  # install these extensions
        pg_libs: 'citus, pg_cron, pg_stat_statements' # citus will be added by patroni automatically
        pg_users: [{ name: dbuser_citus ,password: DBUser.Citus ,pgbouncer: true ,roles: [ dbrole_admin ]    }]
        pg_databases: [{ name: citus ,owner: dbuser_citus ,extensions: [ citus, vector, topn, pg_cron, hll ] }]
        pg_parameters:
          cron.database_name: citus
          citus.node_conninfo: 'sslrootcert=/pg/cert/ca.crt sslmode=verify-full'
        pg_hba_rules:
          - { user: 'all' ,db: all  ,addr: 127.0.0.1/32  ,auth: ssl ,title: 'all user ssl access from localhost' }
          - { user: 'all' ,db: all  ,addr: intra         ,auth: ssl ,title: 'all user ssl access from intranet'  }
        pg_vip_enabled: true                      # enable vip for citus cluster
        pg_vip_interface: eth1                    # vip interface for all members (you can override this in each host)

  vars:                               # global variables
    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra/param
    #----------------------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: true            # overwrite hostname since this is a multi-node tempalte
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 17                      # Default PostgreSQL Major Version is 17
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_packages: [ pgsql-main, pgsql-common ]   # pg kernel and common utils
    #pg_extensions: [ pg17-time ,pg17-gis ,pg17-rag ,pg17-fts ,pg17-olap ,pg17-feat ,pg17-lang ,pg17-type ,pg17-util ,pg17-func ,pg17-admin ,pg17-stat ,pg17-sec ,pg17-fdw ,pg17-sim ,pg17-etl]
    #repo_extra_packages: [ pgsql-main, citus, postgis, pgvector, pg_cron, hll, topn ]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The citus template deploys a Citus distributed PostgreSQL cluster, suitable for large-scale data scenarios requiring horizontal scaling.

Key Features:

  • Transparent data sharding, automatically distributes data to multiple nodes
  • Parallel query execution, aggregates results from multiple nodes
  • Supports distributed transactions (2PC)
  • Maintains PostgreSQL SQL compatibility

Architecture:

  • Coordinator Node (pg-citus0): Receives queries, routes to data nodes
  • Data Nodes (pg-citus1~3): Stores sharded data

Use Cases:

  • Single table data volume exceeds single-node capacity
  • Need horizontal scaling for write and query performance
  • Multi-tenant SaaS applications
  • Real-time analytical workloads

Notes:

  • Citus supports PostgreSQL 14~17
  • Distributed tables require specifying a distribution column
  • Some PostgreSQL features may be limited (e.g., cross-shard foreign keys)
  • ARM64 architecture not supported

8.10 - mssql

WiltonDB / Babelfish kernel, provides Microsoft SQL Server protocol and syntax compatibility

The mssql configuration template uses WiltonDB / Babelfish database kernel instead of native PostgreSQL, providing Microsoft SQL Server wire protocol (TDS) and T-SQL syntax compatibility.

For the complete tutorial, see: Babelfish (MSSQL) Kernel Guide


Overview

  • Config Name: mssql
  • Node Count: Single node
  • Description: WiltonDB / Babelfish configuration template, provides SQL Server protocol compatibility
  • OS Distro: el8, el9, el10, u22, u24 (Debian not available)
  • OS Arch: x86_64
  • Related: meta

Usage:

./configure -c mssql [-i <primary_ip>]

Content

Source: pigsty/conf/mssql.yml

---
#==============================================================#
# File      :   mssql.yml
# Desc      :   Babelfish: WiltonDB (MSSQL Compatible) template
# Ctime     :   2020-08-01
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for Babelfish Kernel (WiltonDB),
# Which is a PostgreSQL 15 fork with SQL Server Compatibility
# tutorial: https://doc.pgsty.com/pgsql/kernel/babelfish
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c mssql
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # Babelfish Database Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: dbuser_mssql ,password: DBUser.MSSQL ,superuser: true, pgbouncer: true ,roles: [dbrole_admin], comment: superuser & owner for babelfish  }
        pg_databases:
          - name: mssql
            baseline: mssql.sql
            extensions: [uuid-ossp, babelfishpg_common, babelfishpg_tsql, babelfishpg_tds, babelfishpg_money, pg_hint_plan, system_stats, tds_fdw]
            owner: dbuser_mssql
            parameters: { 'babelfishpg_tsql.migration_mode' : 'multi-db' }
            comment: babelfish cluster, a MSSQL compatible pg cluster
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

        # Babelfish / WiltonDB Ad Hoc Settings
        pg_mode: mssql                     # Microsoft SQL Server Compatible Mode
        pg_version: 15
        pg_packages: [ wiltondb, pgsql-common, sqlcmd ]
        pg_libs: 'babelfishpg_tds, pg_stat_statements, auto_explain' # add timescaledb to shared_preload_libraries
        pg_default_hba_rules: # overwrite default HBA rules for babelfish cluster, order by `order`
          - { user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident' ,order: 100}
          - { user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' ,order: 150}
          - { user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost' ,order: 200}
          - { user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' ,order: 250}
          - { user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' ,order: 300}
          - { user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' ,order: 350}
          - { user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password' ,order: 400}
          - { user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl' ,order: 450}
          - { user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd' ,order: 500}
          - { user: dbuser_mssql ,db: mssql       ,addr: intra     ,auth: md5   ,title: 'allow mssql dbsu intranet access' ,order: 525} # <--- use md5 auth method for mssql user
          - { user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket' ,order: 550}
          - { user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password' ,order: 600}
          - { user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet' ,order: 650}
        pg_default_services: # route primary & replica service to mssql port 1433
          - { name: primary ,port: 5433 ,dest: 1433  ,check: /primary   ,selector: "[]" }
          - { name: replica ,port: 5434 ,dest: 1433  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
          - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
          - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]" }

  vars:
    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra/param
    #----------------------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: false                 # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql,mssql # extra mssql repo is required
    node_tune: oltp                           # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 15                            # Babelfish kernel is compatible with postgres 15
    pg_conf: oltp.yml                         # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The mssql template allows you to use SQL Server Management Studio (SSMS) or other SQL Server client tools to connect to PostgreSQL.

Key Features:

  • Uses TDS protocol (port 1433), compatible with SQL Server clients
  • Supports T-SQL syntax, low migration cost
  • Retains PostgreSQL’s ACID properties and extension ecosystem
  • Supports multi-db and single-db migration modes

Connection Methods:

# Using sqlcmd command line tool
sqlcmd -S 10.10.10.10,1433 -U dbuser_mssql -P DBUser.MSSQL -d mssql

# Using SSMS or Azure Data Studio
# Server: 10.10.10.10,1433
# Authentication: SQL Server Authentication
# Login: dbuser_mssql
# Password: DBUser.MSSQL

Use Cases:

  • Migrating from SQL Server to PostgreSQL
  • Applications needing to support both SQL Server and PostgreSQL clients
  • Leveraging PostgreSQL ecosystem while maintaining T-SQL compatibility

Notes:

  • WiltonDB is based on PostgreSQL 15, does not support higher version features
  • Some T-SQL syntax may have compatibility differences, refer to Babelfish compatibility documentation
  • Must use md5 authentication method (not scram-sha-256)

8.11 - polar

PolarDB for PostgreSQL kernel, provides Aurora-style storage-compute separation capability

The polar configuration template uses Alibaba Cloud’s PolarDB for PostgreSQL database kernel instead of native PostgreSQL, providing “cloud-native” Aurora-style storage-compute separation capability.

For the complete tutorial, see: PolarDB for PostgreSQL (POLAR) Kernel Guide


Overview

  • Config Name: polar
  • Node Count: Single node
  • Description: Uses PolarDB for PostgreSQL kernel
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64
  • Related: meta

Usage:

./configure -c polar [-i <primary_ip>]

Content

Source: pigsty/conf/polar.yml

---
#==============================================================#
# File      :   polar.yml
# Desc      :   Pigsty 1-node PolarDB Kernel Config Template
# Ctime     :   2020-08-05
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for PolarDB PG Kernel,
# Which is a PostgreSQL 15 fork with RAC flavor features
# tutorial: https://doc.pgsty.com/pgsql/kernel/polardb
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c polar
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # PolarDB Database Cluster
    #----------------------------------------------#
    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 }
          - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty]}
        pg_hba_rules:
          - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

        # PolarDB Ad Hoc Settings
        pg_version: 15                            # PolarDB PG is based on PG 15
        pg_mode: polar                            # PolarDB PG Compatible mode
        pg_packages: [ polardb, pgsql-common ]    # Replace PG kernel with PolarDB kernel
        pg_exporter_exclude_database: 'template0,template1,postgres,polardb_admin'
        pg_default_roles:                         # PolarDB require replicator as superuser
          - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
          - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
          - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
          - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
          - { name: postgres     ,superuser: true  ,comment: system superuser }
          - { name: replicator   ,superuser: true  ,replication: true ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator } # <- superuser is required for replication
          - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
          - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

  vars:                               # global variables
    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra/param
    #----------------------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 15                      # PolarDB is compatible with PG 15
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root

...

Explanation

The polar template uses Alibaba Cloud’s open-source PolarDB for PostgreSQL kernel, providing cloud-native database capabilities.

Key Features:

  • Storage-compute separation architecture, compute and storage nodes can scale independently
  • Supports one-write-multiple-read, read replicas scale in seconds
  • Compatible with PostgreSQL ecosystem, maintains SQL compatibility
  • Supports shared storage scenarios, suitable for cloud environment deployment

Use Cases:

  • Cloud-native scenarios requiring storage-compute separation architecture
  • Read-heavy write-light workloads
  • Scenarios requiring quick scaling of read replicas
  • Test environments for evaluating PolarDB features

Notes:

  • PolarDB is based on PostgreSQL 15, does not support higher version features
  • Replication user requires superuser privileges (different from native PostgreSQL)
  • Some PostgreSQL extensions may have compatibility issues
  • ARM64 architecture not supported

8.12 - ivory

IvorySQL kernel, provides Oracle syntax and PL/SQL compatibility

The ivory configuration template uses Highgo’s IvorySQL database kernel instead of native PostgreSQL, providing Oracle syntax and PL/SQL compatibility.

For the complete tutorial, see: IvorySQL (Oracle Compatible) Kernel Guide


Overview

  • Config Name: ivory
  • Node Count: Single node
  • Description: Uses IvorySQL Oracle-compatible kernel
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c ivory [-i <primary_ip>]

Content

Source: pigsty/conf/ivory.yml

---
#==============================================================#
# File      :   ivory.yml
# Desc      :   IvorySQL 4 (Oracle Compatible) template
# Ctime     :   2024-08-05
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/pgsql/kernel/ivorysql
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for IvorySQL 5 Kernel,
# Which is a PostgreSQL 18 fork with Oracle Compatibility
# tutorial: https://doc.pgsty.com/pgsql/kernel/ivorysql
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c ivory
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # IvorySQL Database Cluster
    #----------------------------------------------#
    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 }
          - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty]}
        pg_hba_rules:
          - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

        # IvorySQL Ad Hoc Settings
        pg_mode: ivory                                                 # Use IvorySQL Oracle Compatible Mode
        pg_packages: [ ivorysql, pgsql-common ]                        # install IvorySQL instead of postgresql kernel
        pg_libs: 'liboracle_parser, pg_stat_statements, auto_explain'  # pre-load oracle parser

  vars:                               # global variables
    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra/param
    #----------------------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # IvorySQL kernel is compatible with postgres 18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The ivory template uses Highgo’s open-source IvorySQL kernel, providing Oracle database compatibility.

Key Features:

  • Supports Oracle PL/SQL syntax
  • Compatible with Oracle data types (NUMBER, VARCHAR2, etc.)
  • Supports Oracle-style packages
  • Retains all standard PostgreSQL functionality

Use Cases:

  • Migrating from Oracle to PostgreSQL
  • Applications needing both Oracle and PostgreSQL syntax support
  • Leveraging PostgreSQL ecosystem while maintaining PL/SQL compatibility
  • Test environments for evaluating IvorySQL features

Notes:

  • IvorySQL 4 is based on PostgreSQL 18
  • Using liboracle_parser requires loading into shared_preload_libraries
  • pgbackrest may have checksum issues in Oracle-compatible mode, PITR capability is limited
  • Only supports EL8/EL9 systems, Debian/Ubuntu not supported

8.13 - mysql

OpenHalo kernel, provides MySQL protocol and syntax compatibility

The mysql configuration template uses OpenHalo database kernel instead of native PostgreSQL, providing MySQL wire protocol and SQL syntax compatibility.


Overview

  • Config Name: mysql
  • Node Count: Single node
  • Description: OpenHalo MySQL-compatible kernel configuration
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64
  • Related: meta

Usage:

./configure -c mysql [-i <primary_ip>]

Content

Source: pigsty/conf/mysql.yml

---
#==============================================================#
# File      :   mysql.yml
# Desc      :   1-node OpenHaloDB (MySQL Compatible) template
# Ctime     :   2025-04-03
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for OpenHalo PG Kernel,
# Which is a PostgreSQL 14 fork with MySQL Wire Compatibility
# tutorial: https://doc.pgsty.com/pgsql/kernel/openhalo
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c mysql
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # OpenHalo Database Cluster
    #----------------------------------------------#
    # connect with mysql client: mysql -h 10.10.10.10 -u dbuser_meta -D mysql (the actual database is 'postgres', and 'mysql' is a schema)
    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 }
          - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: postgres, extensions: [aux_mysql]} # the mysql compatible database
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty]}
        pg_hba_rules:
          - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

        # OpenHalo Ad Hoc Setting
        pg_mode: mysql                    # MySQL Compatible Mode by HaloDB
        pg_version: 14                    # The current HaloDB is compatible with PG Major Version 14
        pg_packages: [ openhalodb, pgsql-common ]  # install openhalodb instead of postgresql kernel

  vars:
    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra/param
    #----------------------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 14                      # OpenHalo is compatible with PG 14
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The mysql template uses the OpenHalo kernel, allowing you to connect to PostgreSQL using MySQL client tools.

Key Features:

  • Uses MySQL protocol (port 3306), compatible with MySQL clients
  • Supports a subset of MySQL SQL syntax
  • Retains PostgreSQL’s ACID properties and storage engine
  • Supports both PostgreSQL and MySQL protocol connections simultaneously

Connection Methods:

# Using MySQL client
mysql -h 10.10.10.10 -P 3306 -u dbuser_meta -pDBUser.Meta

# Also retains PostgreSQL connection capability
psql postgres://dbuser_meta:[email protected]:5432/meta

Use Cases:

  • Migrating from MySQL to PostgreSQL
  • Applications needing to support both MySQL and PostgreSQL clients
  • Leveraging PostgreSQL ecosystem while maintaining MySQL compatibility

Notes:

  • OpenHalo is based on PostgreSQL 14, does not support higher version features
  • Some MySQL syntax may have compatibility differences
  • Only supports EL8/EL9 systems
  • ARM64 architecture not supported

8.14 - pgtde

Percona PostgreSQL kernel, provides Transparent Data Encryption (pg_tde) capability

The pgtde configuration template uses Percona PostgreSQL database kernel, providing Transparent Data Encryption (TDE) capability.


Overview

  • Config Name: pgtde
  • Node Count: Single node
  • Description: Percona PostgreSQL transparent data encryption configuration
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64
  • Related: meta

Usage:

./configure -c pgtde [-i <primary_ip>]

Content

Source: pigsty/conf/pgtde.yml

---
#==============================================================#
# File      :   pgtde.yml
# Desc      :   PG TDE with Percona PostgreSQL 1-node template
# Ctime     :   2025-07-04
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for Percona PostgreSQL Distribution
# With pg_tde extension, which is compatible with PostgreSQL 18.1
# tutorial: https://doc.pgsty.com/pgsql/kernel/percona
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c pgtde
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # Percona Postgres Database Cluster
    #----------------------------------------------#
    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 }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - name: meta
            baseline: cmdb.sql
            comment: pigsty tde database
            schemas: [pigsty]
            extensions: [ vector, postgis, pg_tde ,pgaudit, { name: pg_stat_monitor, schema: monitor } ]
        pg_hba_rules:
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

        # Percona PostgreSQL TDE Ad Hoc Settings
        pg_packages: [ percona-main, pgsql-common ]  # install percona postgres packages
        pg_libs: 'pg_tde, pgaudit, pg_stat_statements, pg_stat_monitor, auto_explain'

  vars:
    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra/param
    #----------------------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: false             # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql,percona
    node_tune: oltp

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # Default Percona TDE PG Major Version is 18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The pgtde template uses Percona PostgreSQL kernel, providing enterprise-grade transparent data encryption capability.

Key Features:

  • Transparent Data Encryption: Data automatically encrypted on disk, transparent to applications
  • Key Management: Supports local keys and external Key Management Systems (KMS)
  • Table-level Encryption: Selectively encrypt sensitive tables
  • Full Compatibility: Fully compatible with native PostgreSQL

Use Cases:

  • Meeting data security compliance requirements (e.g., PCI-DSS, HIPAA)
  • Storing sensitive data (e.g., personal information, financial data)
  • Scenarios requiring data-at-rest encryption
  • Enterprise environments with strict data security requirements

Usage:

-- Create encrypted table
CREATE TABLE sensitive_data (
    id SERIAL PRIMARY KEY,
    ssn VARCHAR(11)
) USING pg_tde;

-- Or enable encryption on existing table
ALTER TABLE existing_table SET ACCESS METHOD pg_tde;

Notes:

  • Percona PostgreSQL is based on PostgreSQL 18
  • Encryption brings some performance overhead (typically 5-15%)
  • Encryption keys must be properly managed
  • ARM64 architecture not supported

8.15 - oriole

OrioleDB kernel, provides bloat-free OLTP enhanced storage engine

The oriole configuration template uses OrioleDB storage engine instead of PostgreSQL’s default Heap storage, providing bloat-free, high-performance OLTP capability.


Overview

  • Config Name: oriole
  • Node Count: Single node
  • Description: OrioleDB bloat-free storage engine configuration
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64
  • Related: meta

Usage:

./configure -c oriole [-i <primary_ip>]

Content

Source: pigsty/conf/oriole.yml

---
#==============================================================#
# File      :   oriole.yml
# Desc      :   1-node OrioleDB (OLTP Enhancement) template
# Ctime     :   2025-04-05
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for OrioleDB Kernel,
# Which is a Patched PostgreSQL 17 fork without bloat
# tutorial: https://doc.pgsty.com/pgsql/kernel/oriole
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c oriole
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # OrioleDB Database Cluster
    #----------------------------------------------#
    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 }
          - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty], extensions: [orioledb]}
        pg_hba_rules:
          - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

        # OrioleDB Ad Hoc Settings
        pg_mode: oriole                                         # oriole compatible mode
        pg_packages: [ oriole, pgsql-common ]                   # install OrioleDB kernel
        pg_libs: 'orioledb, pg_stat_statements, auto_explain'   # Load OrioleDB Extension

  vars:                               # global variables
    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra/param
    #----------------------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 17                      # OrioleDB Kernel is based on PG 17
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The oriole template uses OrioleDB storage engine, fundamentally solving PostgreSQL table bloat problems.

Key Features:

  • Bloat-free Design: Uses UNDO logs instead of Multi-Version Concurrency Control (MVCC)
  • No VACUUM Required: Eliminates performance jitter from autovacuum
  • Row-level WAL: More efficient logging and replication
  • Compressed Storage: Built-in data compression, reduces storage space

Use Cases:

  • High-frequency update OLTP workloads
  • Applications sensitive to write latency
  • Need for stable response times (eliminates VACUUM impact)
  • Large tables with frequent updates causing bloat

Usage:

-- Create table using OrioleDB storage
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    customer_id INT,
    amount DECIMAL(10,2)
) USING orioledb;

-- Existing tables cannot be directly converted, need to be rebuilt

Notes:

  • OrioleDB is based on PostgreSQL 17
  • Need to add orioledb to shared_preload_libraries
  • Some PostgreSQL features may not be fully supported
  • ARM64 architecture not supported

8.16 - supabase

Self-host Supabase using Pigsty-managed PostgreSQL, an open-source Firebase alternative

The supabase configuration template provides a reference configuration for self-hosting Supabase, using Pigsty-managed PostgreSQL as the underlying storage.

For more details, see Supabase Self-Hosting Tutorial


Overview

  • Config Name: supabase
  • Node Count: Single node
  • Description: Self-host Supabase using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta, rich

Usage:

./configure -c supabase [-i <primary_ip>]

Content

Source: pigsty/conf/supabase.yml

---
#==============================================================#
# File      :   supabase.yml
# Desc      :   Pigsty configuration for self-hosting supabase
# Ctime     :   2023-09-19
# Mtime     :   2025-12-28
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# supabase is available on el8/el9/u22/u24/d12 with pg15,16,17,18
# tutorial: https://doc.pgsty.com/app/supabase
# Usage:
#   curl https://repo.pigsty.io/get | bash    # install pigsty
#   ./configure -c supabase   # use this supabase conf template
#   ./deploy.yml              # install pigsty & pgsql & minio
#   ./docker.yml              # install docker & docker compose
#   ./app.yml                 # launch supabase with docker compose

all:
  children:


    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra
    #----------------------------------------------#
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        repo_enabled: false    # disable local repo

    #----------------------------------------------#
    # ETCD : https://doc.pgsty.com/etcd
    #----------------------------------------------#
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd
        etcd_safeguard: false  # enable to prevent purging running etcd instance

    #----------------------------------------------#
    # MINIO : https://doc.pgsty.com/minio
    #----------------------------------------------#
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1 }
      vars:
        minio_cluster: minio
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    #----------------------------------------------#
    # PostgreSQL cluster for Supabase self-hosting
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          # supabase roles: anon, authenticated, dashboard_user
          - { name: anon           ,login: false }
          - { name: authenticated  ,login: false }
          - { name: dashboard_user ,login: false ,replication: true ,createdb: true ,createrole: true }
          - { name: service_role   ,login: false ,bypassrls: true }
          # supabase users: please use the same password
          - { name: supabase_admin             ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: true   ,roles: [ dbrole_admin ] ,superuser: true ,replication: true ,createdb: true ,createrole: true ,bypassrls: true }
          - { name: authenticator              ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin, authenticated ,anon ,service_role ] }
          - { name: supabase_auth_admin        ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin ] ,createrole: true }
          - { name: supabase_storage_admin     ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin, authenticated ,anon ,service_role ] ,createrole: true }
          - { name: supabase_functions_admin   ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin ] ,createrole: true }
          - { name: supabase_replication_admin ,password: 'DBUser.Supa' ,replication: true ,roles: [ dbrole_admin ]}
          - { name: supabase_etl_admin         ,password: 'DBUser.Supa' ,replication: true ,roles: [ pg_read_all_data ]}
          - { name: supabase_read_only_user    ,password: 'DBUser.Supa' ,bypassrls: true ,roles:   [ pg_read_all_data, dbrole_readonly ]}
        pg_databases:
          - name: postgres
            baseline: supabase.sql
            owner: supabase_admin
            comment: supabase postgres database
            schemas: [ extensions ,auth ,realtime ,storage ,graphql_public ,supabase_functions ,_analytics ,_realtime ]
            extensions:
              - { name: pgcrypto         ,schema: extensions } # cryptographic functions
              - { name: pg_net           ,schema: extensions } # async HTTP
              - { name: pgjwt            ,schema: extensions } # json web token API for postgres
              - { name: uuid-ossp        ,schema: extensions } # generate universally unique identifiers (UUIDs)
              - { name: pgsodium         ,schema: extensions } # pgsodium is a modern cryptography library for Postgres.
              - { name: supabase_vault   ,schema: extensions } # Supabase Vault Extension
              - { name: pg_graphql       ,schema: extensions } # pg_graphql: GraphQL support
              - { name: pg_jsonschema    ,schema: extensions } # pg_jsonschema: Validate json schema
              - { name: wrappers         ,schema: extensions } # wrappers: FDW collections
              - { name: http             ,schema: extensions } # http: allows web page retrieval inside the database.
              - { name: pg_cron          ,schema: extensions } # pg_cron: Job scheduler for PostgreSQL
              - { name: timescaledb      ,schema: extensions } # timescaledb: Enables scalable inserts and complex queries for time-series data
              - { name: pg_tle           ,schema: extensions } # pg_tle: Trusted Language Extensions for PostgreSQL
              - { name: vector           ,schema: extensions } # pgvector: the vector similarity search
              - { name: pgmq             ,schema: extensions } # pgmq: A lightweight message queue like AWS SQS and RSMQ
          - { name: supabase ,owner: supabase_admin ,comment: supabase analytics database ,schemas: [ extensions, _analytics ] }

        # supabase required extensions
        pg_libs: 'timescaledb, pgsodium, plpgsql, plpgsql_check, pg_cron, pg_net, pg_stat_statements, auto_explain, pg_wait_sampling, pg_tle, plan_filter'
        pg_extensions: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
        pg_parameters: { cron.database_name: postgres }
        pg_hba_rules: # supabase hba rules, require access from docker network
          - { user: all ,db: postgres  ,addr: intra         ,auth: pwd ,title: 'allow supabase access from intranet'    }
          - { user: all ,db: postgres  ,addr: 172.17.0.0/16 ,auth: pwd ,title: 'allow access from local docker network' }
        node_crontab:
          - '00 01 * * * postgres /pg/bin/pg-backup full'  # make a full backup every 1am
          - '*  *  * * * postgres /pg/bin/supa-kick'       # kick supabase _analytics lag per minute: https://github.com/pgsty/pigsty/issues/581

    #----------------------------------------------#
    # Supabase
    #----------------------------------------------#
    # ./docker.yml
    # ./app.yml

    # the supabase stateless containers (default username & password: supabase/pigsty)
    supabase:
      hosts:
        10.10.10.10: {}
      vars:
        docker_enabled: true                              # enable docker on this group
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        app: supabase                                     # specify app name (supa) to be installed (in the apps)
        apps:                                             # define all applications
          supabase:                                       # the definition of supabase app
            conf:                                         # override /opt/supabase/.env

              # IMPORTANT: CHANGE JWT_SECRET AND REGENERATE CREDENTIAL ACCORDING!!!!!!!!!!!
              # https://supabase.com/docs/guides/self-hosting/docker#securing-your-services
              JWT_SECRET: your-super-secret-jwt-token-with-at-least-32-characters-long
              ANON_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
              SERVICE_ROLE_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
              PG_META_CRYPTO_KEY: your-encryption-key-32-chars-min

              DASHBOARD_USERNAME: supabase
              DASHBOARD_PASSWORD: pigsty

              # 32~64 random characters string for logflare
              LOGFLARE_PUBLIC_ACCESS_TOKEN: 1234567890abcdef1234567890abcdef
              LOGFLARE_PRIVATE_ACCESS_TOKEN: fedcba0987654321fedcba0987654321

              # postgres connection string (use the correct ip and port)
              POSTGRES_HOST: 10.10.10.10      # point to the local postgres node
              POSTGRES_PORT: 5436             # access via the 'default' service, which always route to the primary postgres
              POSTGRES_DB: postgres           # the supabase underlying database
              POSTGRES_PASSWORD: DBUser.Supa  # password for supabase_admin and multiple supabase users

              # expose supabase via domain name
              SITE_URL: https://supa.pigsty                # <------- Change This to your external domain name
              API_EXTERNAL_URL: https://supa.pigsty        # <------- Otherwise the storage api may not work!
              SUPABASE_PUBLIC_URL: https://supa.pigsty     # <------- DO NOT FORGET TO PUT IT IN infra_portal!

              # if using s3/minio as file storage
              S3_BUCKET: data
              S3_ENDPOINT: https://sss.pigsty:9000
              S3_ACCESS_KEY: s3user_data
              S3_SECRET_KEY: S3User.Data
              S3_FORCE_PATH_STYLE: true
              S3_PROTOCOL: https
              S3_REGION: stub
              MINIO_DOMAIN_IP: 10.10.10.10  # sss.pigsty domain name will resolve to this ip statically

              # if using SMTP (optional)
              #SMTP_ADMIN_EMAIL: [email protected]
              #SMTP_HOST: supabase-mail
              #SMTP_PORT: 2500
              #SMTP_USER: fake_mail_user
              #SMTP_PASS: fake_mail_password
              #SMTP_SENDER_NAME: fake_sender
              #ENABLE_ANONYMOUS_USERS: false


  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra
    #----------------------------------------------#
    version: v4.0.0                       # pigsty version string
    admin_ip: 10.10.10.10                 # admin node ip address
    region: default                       # upstream mirror region: default|china|europe
    proxy_env:                            # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    certbot_sign: false                   # enable certbot to sign https certificate for infra portal
    certbot_email: [email protected]         # replace your email address to receive expiration notice
    infra_portal:                         # infra services exposed via portal
      home      : { domain: i.pigsty }    # default domain name
      pgadmin   : { domain: adm.pigsty ,endpoint: "${admin_ip}:8885" }
      bytebase  : { domain: ddl.pigsty ,endpoint: "${admin_ip}:8887" }
      #minio     : { domain: m.pigsty   ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

      # Nginx / Domain / HTTPS : https://doc.pgsty.com/admin/portal
      supa :                              # nginx server config for supabase
        domain: supa.pigsty               # REPLACE IT WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:8000"      # supabase service endpoint: IP:PORT
        websocket: true                   # add websocket support
        certbot: supa.pigsty              # certbot cert name, apply with `make cert`

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    nodename_overwrite: false             # do not overwrite node hostname on single node mode
    node_tune: oltp                       # node tuning specs: oltp,olap,tiny,crit
    node_etc_hosts:                       # add static domains to all nodes /etc/hosts
      - 10.10.10.10 i.pigsty sss.pigsty supa.pigsty
    node_repo_modules: node,pgsql,infra   # use pre-made local repo rather than install from upstream
    node_repo_remove: true                # remove existing node repo for node managed by pigsty
    #node_packages: [openssh-server]      # packages to be installed current nodes with latest version
    #node_timezone: Asia/Hong_Kong        # overwrite node timezone

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 18                        # default postgres version
    pg_conf: oltp.yml                     # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_safeguard: false                   # prevent purging running postgres instance?
    pg_default_schemas: [ monitor, extensions ] # add new schema: exxtensions
    pg_default_extensions:                # default extensions to be created
      - { name: pg_stat_statements ,schema: monitor     }
      - { name: pgstattuple        ,schema: monitor     }
      - { name: pg_buffercache     ,schema: monitor     }
      - { name: pageinspect        ,schema: monitor     }
      - { name: pg_prewarm         ,schema: monitor     }
      - { name: pg_visibility      ,schema: monitor     }
      - { name: pg_freespacemap    ,schema: monitor     }
      - { name: pg_wait_sampling   ,schema: monitor     }
      # move default extensions to `extensions` schema for supabase
      - { name: postgres_fdw       ,schema: extensions  }
      - { name: file_fdw           ,schema: extensions  }
      - { name: btree_gist         ,schema: extensions  }
      - { name: btree_gin          ,schema: extensions  }
      - { name: pg_trgm            ,schema: extensions  }
      - { name: intagg             ,schema: extensions  }
      - { name: intarray           ,schema: extensions  }
      - { name: pg_repack          ,schema: extensions  }

    #----------------------------------------------#
    # BACKUP : https://doc.pgsty.com/pgsql/backup
    #----------------------------------------------#
    minio_endpoint: https://sss.pigsty:9000 # explicit overwrite minio endpoint with haproxy port
    pgbackrest_method: minio              # pgbackrest repo method: local,minio,[user-defined...]
    pgbackrest_repo:                      # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                              # default pgbackrest repo with local posix fs
        path: /pg/backup                  # local backup directory, `/pg/backup` by default
        retention_full_type: count        # retention full backups by count
        retention_full: 2                 # keep 2, at most 3 full backups when using local fs repo
      minio:                              # optional minio repo for pgbackrest
        type: s3                          # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty           # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1              # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql                  # minio bucket name, `pgsql` by default
        s3_key: pgbackrest                # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup      # minio user secret key for pgbackrest <------------------ HEY, DID YOU CHANGE THIS?
        s3_uri_style: path                # use path style uri for minio rather than host style
        path: /pgbackrest                 # minio backup path, default is `/pgbackrest`
        storage_port: 9000                # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                          # Enable block incremental backup
        bundle: y                         # bundle small files into a single file
        bundle_limit: 20MiB               # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB               # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc          # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest           # AES encryption password, default is 'pgBackRest'  <----- HEY, DID YOU CHANGE THIS?
        retention_full_type: time         # retention full backup by time on minio repo
        retention_full: 14                # keep full backup for the last 14 days
      s3:                                 # you can use cloud object storage as backup repo
        type: s3                          # Add your object storage credentials here!
        s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
        s3_region: oss-cn-beijing
        s3_bucket: <your_bucket_name>
        s3_key: <your_access_key>
        s3_key_secret: <your_secret_key>
        s3_uri_style: host
        path: /pgbackrest
        bundle: y                         # bundle small files into a single file
        bundle_limit: 20MiB               # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB               # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc          # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest           # AES encryption password, default is 'pgBackRest'
        retention_full_type: time         # retention full backup by time on minio repo
        retention_full: 14                # keep full backup for the last 14 days

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Installation Demo


Explanation

The supabase template provides a complete self-hosted Supabase solution, allowing you to run this open-source Firebase alternative on your own infrastructure.

Architecture:

  • PostgreSQL: Production-grade Pigsty-managed PostgreSQL (with HA support)
  • Docker Containers: Supabase stateless services (Auth, Storage, Realtime, Edge Functions, etc.)
  • MinIO: S3-compatible object storage for file storage and PostgreSQL backup
  • Nginx: Reverse proxy and HTTPS termination

Key Features:

  • Uses Pigsty-managed PostgreSQL instead of Supabase’s built-in database container
  • Supports PostgreSQL high availability (can be expanded to three-node cluster)
  • Installs all Supabase-required extensions (pg_net, pgjwt, pg_graphql, vector, etc.)
  • Integrated MinIO object storage for file uploads and backups
  • HTTPS support with Let’s Encrypt automatic certificates

Deployment Steps:

curl https://repo.pigsty.io/get | bash   # Download Pigsty
./configure -c supabase                   # Use supabase config template
./deploy.yml                              # Install Pigsty, PostgreSQL, MinIO
./docker.yml                              # Install Docker
./app.yml                                 # Start Supabase containers

Access:

# Supabase Studio
https://supa.pigsty   (username: supabase, password: pigsty)

# Direct PostgreSQL connection
psql postgres://supabase_admin:[email protected]:5432/postgres

Use Cases:

  • Need to self-host BaaS (Backend as a Service) platform
  • Want full control over data and infrastructure
  • Need enterprise-grade PostgreSQL HA and backups
  • Compliance or cost concerns with Supabase cloud service

Notes:

  • Must change JWT_SECRET: Use at least 32-character random string, and regenerate ANON_KEY and SERVICE_ROLE_KEY
  • Configure proper domain names (SITE_URL, API_EXTERNAL_URL)
  • Production environments should enable HTTPS (can use certbot for auto certificates)
  • Docker network needs access to PostgreSQL (172.17.0.0/16 HBA rule configured)

8.17 - HA Templates

8.18 - ha/simu

20-node production environment simulation for large-scale deployment testing

The ha/simu configuration template is a 20-node production environment simulation, requiring a powerful host machine to run.


Overview

  • Config Name: ha/simu
  • Node Count: 20 nodes, pigsty/vagrant/spec/simu.rb
  • Description: 20-node production environment simulation, requires powerful host machine
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64

Usage:

./configure -c ha/simu [-i <primary_ip>]

Content

Source: pigsty/conf/ha/simu.yml

---
#==============================================================#
# File      :   simu.yml
# Desc      :   Pigsty Simubox: a 20 node prod simulation env
# Ctime     :   2023-07-20
# Mtime     :   2025-12-23
# Docs      :   https://doc.pgsty.com/config
# License   :   AGPLv3 @ https://doc.pgsty.com/about/license
# Copyright :   2018-2025  Ruohang Feng / Vonng ([email protected])
#==============================================================#

all:

  children:

    #==========================================================#
    # infra: 3 nodes
    #==========================================================#
    # ./infra.yml -l infra
    # ./docker.yml -l infra (optional)
    infra:
      hosts:
        10.10.10.10: {}
        10.10.10.11: { repo_enabled: false }
        10.10.10.12: { repo_enabled: false }
      vars:
        docker_enabled: true
        node_conf: oltp         # use oltp template for infra nodes
        pg_conf: oltp.yml       # use oltp template for infra pgsql
        pg_exporters:           # bin/pgmon-add pg-meta2/pg-src2/pg-dst2
          20001: {pg_cluster: pg-meta2   ,pg_seq: 1 ,pg_host: 10.10.10.10, pg_databases: [{ name: meta }]}
          20002: {pg_cluster: pg-meta2   ,pg_seq: 2 ,pg_host: 10.10.10.11, pg_databases: [{ name: meta }]}
          20003: {pg_cluster: pg-meta2   ,pg_seq: 3 ,pg_host: 10.10.10.12, pg_databases: [{ name: meta }]}

          20004: {pg_cluster: pg-src2    ,pg_seq: 1 ,pg_host: 10.10.10.31, pg_databases: [{ name: src }]}
          20005: {pg_cluster: pg-src2    ,pg_seq: 2 ,pg_host: 10.10.10.32, pg_databases: [{ name: src }]}
          20006: {pg_cluster: pg-src2    ,pg_seq: 3 ,pg_host: 10.10.10.33, pg_databases: [{ name: src }]}

          20007: {pg_cluster: pg-dst2    ,pg_seq: 1 ,pg_host: 10.10.10.41, pg_databases: [{ name: dst }]}
          20008: {pg_cluster: pg-dst2    ,pg_seq: 2 ,pg_host: 10.10.10.42, pg_databases: [{ name: dst }]}
          20009: {pg_cluster: pg-dst2    ,pg_seq: 3 ,pg_host: 10.10.10.43, pg_databases: [{ name: dst }]}


    #==========================================================#
    # nodes: 23 nodes
    #==========================================================#
    # ./node.yml
    nodes:
      hosts:
        10.10.10.10 : { nodename: meta1  ,node_cluster: meta   ,pg_cluster: pg-meta  ,pg_seq: 1 ,pg_role: primary, infra_seq: 1 }
        10.10.10.11 : { nodename: meta2  ,node_cluster: meta   ,pg_cluster: pg-meta  ,pg_seq: 2 ,pg_role: replica, infra_seq: 2 }
        10.10.10.12 : { nodename: meta3  ,node_cluster: meta   ,pg_cluster: pg-meta  ,pg_seq: 3 ,pg_role: replica, infra_seq: 3 }
        10.10.10.18 : { nodename: proxy1 ,node_cluster: proxy  ,vip_address: 10.10.10.20 ,vip_vrid: 20 ,vip_interface: eth1 ,vip_role: master }
        10.10.10.19 : { nodename: proxy2 ,node_cluster: proxy  ,vip_address: 10.10.10.20 ,vip_vrid: 20 ,vip_interface: eth1 ,vip_role: backup }
        10.10.10.21 : { nodename: minio1 ,node_cluster: minio  ,minio_cluster: minio ,minio_seq: 1 }
        10.10.10.22 : { nodename: minio2 ,node_cluster: minio  ,minio_cluster: minio ,minio_seq: 2 }
        10.10.10.23 : { nodename: minio3 ,node_cluster: minio  ,minio_cluster: minio ,minio_seq: 3 }
        10.10.10.24 : { nodename: minio4 ,node_cluster: minio  ,minio_cluster: minio ,minio_seq: 4 }
        10.10.10.25 : { nodename: etcd1  ,node_cluster: etcd   ,etcd_cluster: etcd ,etcd_seq: 1 }
        10.10.10.26 : { nodename: etcd2  ,node_cluster: etcd   ,etcd_cluster: etcd ,etcd_seq: 2 }
        10.10.10.27 : { nodename: etcd3  ,node_cluster: etcd   ,etcd_cluster: etcd ,etcd_seq: 3 }
        10.10.10.28 : { nodename: etcd4  ,node_cluster: etcd   ,etcd_cluster: etcd ,etcd_seq: 4 }
        10.10.10.29 : { nodename: etcd5  ,node_cluster: etcd   ,etcd_cluster: etcd ,etcd_seq: 5 }
        10.10.10.31 : { nodename: pg-src-1 ,node_cluster: pg-src ,node_id_from_pg: true }
        10.10.10.32 : { nodename: pg-src-2 ,node_cluster: pg-src ,node_id_from_pg: true }
        10.10.10.33 : { nodename: pg-src-3 ,node_cluster: pg-src ,node_id_from_pg: true }
        10.10.10.41 : { nodename: pg-dst-1 ,node_cluster: pg-dst ,node_id_from_pg: true }
        10.10.10.42 : { nodename: pg-dst-2 ,node_cluster: pg-dst ,node_id_from_pg: true }
        10.10.10.43 : { nodename: pg-dst-3 ,node_cluster: pg-dst ,node_id_from_pg: true }

    #==========================================================#
    # etcd: 5 nodes dedicated etcd cluster
    #==========================================================#
    # ./etcd.yml -l etcd;
    etcd:
      hosts:
        10.10.10.25: {}
        10.10.10.26: {}
        10.10.10.27: {}
        10.10.10.28: {}
        10.10.10.29: {}
      vars: {}

    #==========================================================#
    # minio: 4 nodes dedicated minio cluster
    #==========================================================#
    # ./minio.yml -l minio;
    minio:
      hosts:
        10.10.10.21: {}
        10.10.10.22: {}
        10.10.10.23: {}
        10.10.10.24: {}
      vars:
        minio_data: '/data{1...4}' # 4 node x 4 disk
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }


    #==========================================================#
    # proxy: 2 nodes used as dedicated haproxy server
    #==========================================================#
    # ./node.yml -l proxy
    proxy:
      hosts:
        10.10.10.18: {}
        10.10.10.19: {}
      vars:
        vip_enabled: true
        haproxy_services:      # expose minio service : sss.pigsty:9000
          - name: minio        # [REQUIRED] service name, unique
            port: 9000         # [REQUIRED] service port, unique
            balance: leastconn # Use leastconn algorithm and minio health check
            options: [ "option httpchk", "option http-keep-alive", "http-check send meth OPTIONS uri /minio/health/live", "http-check expect status 200" ]
            servers:           # reload service with ./node.yml -t haproxy_config,haproxy_reload
              - { name: minio-1 ,ip: 10.10.10.21 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-2 ,ip: 10.10.10.22 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-3 ,ip: 10.10.10.23 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-4 ,ip: 10.10.10.24 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

    #==========================================================#
    # pg-meta: reuse infra node as meta cmdb
    #==========================================================#
    # ./pgsql.yml -l pg-meta
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1 , pg_role: primary }
        10.10.10.11: { pg_seq: 2 , pg_role: replica }
        10.10.10.12: { pg_seq: 3 , pg_role: replica }
      vars:
        pg_cluster: pg-meta
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24
        pg_vip_interface: eth1
        pg_users:
          - {name: dbuser_meta     ,password: DBUser.Meta     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
          - {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database    }
          - {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database   }
          - {name: dbuser_kong     ,password: DBUser.Kong     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway    }
          - {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service       }
          - {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service     }
          - {name: dbuser_noco     ,password: DBUser.Noco     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for nocodb service      }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: vector}]}
          - { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
          - { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
          - { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
          - { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
          - { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }
          - { name: noco     ,owner: dbuser_noco     ,revokeconn: true ,comment: nocodb database }
        pg_hba_rules:
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
        pg_libs: 'pg_stat_statements, auto_explain' # add timescaledb to shared_preload_libraries
        node_crontab:  # make a full backup on monday 1am, and an incremental backup during weekdays
          - '00 01 * * 1 postgres /pg/bin/pg-backup full'
          - '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'

    #==========================================================#
    # pg-src: dedicate 3 node source cluster
    #==========================================================#
    # ./pgsql.yml -l pg-src
    pg-src:
      hosts:
        10.10.10.31: { pg_seq: 1 ,pg_role: primary }
        10.10.10.32: { pg_seq: 2 ,pg_role: replica }
        10.10.10.33: { pg_seq: 3 ,pg_role: replica }
      vars:
        pg_cluster: pg-src
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.3/24
        pg_vip_interface: eth1
        pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
        pg_databases: [{ name: src }]


    #==========================================================#
    # pg-dst: dedicate 3 node destination cluster
    #==========================================================#
    # ./pgsql.yml -l pg-dst
    pg-dst:
      hosts:
        10.10.10.41: { pg_seq: 1 ,pg_role: primary }
        10.10.10.42: { pg_seq: 2 ,pg_role: replica }
        10.10.10.43: { pg_seq: 3 ,pg_role: replica }
      vars:
        pg_cluster: pg-dst
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.4/24
        pg_vip_interface: eth1
        pg_users: [ { name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] } ]
        pg_databases: [ { name: dst } ]


    #==========================================================#
    # redis-meta: reuse the 5 etcd nodes as redis sentinel
    #==========================================================#
    # ./redis.yml -l redis-meta
    redis-meta:
      hosts:
        10.10.10.25: { redis_node: 1 , redis_instances: { 26379: {} } }
        10.10.10.26: { redis_node: 2 , redis_instances: { 26379: {} } }
        10.10.10.27: { redis_node: 3 , redis_instances: { 26379: {} } }
        10.10.10.28: { redis_node: 4 , redis_instances: { 26379: {} } }
        10.10.10.29: { redis_node: 5 , redis_instances: { 26379: {} } }
      vars:
        redis_cluster: redis-meta
        redis_password: 'redis.meta'
        redis_mode: sentinel
        redis_max_memory: 256MB
        redis_sentinel_monitor:  # primary list for redis sentinel, use cls as name, primary ip:port
          - { name: redis-src, host: 10.10.10.31, port: 6379 ,password: redis.src, quorum: 1 }
          - { name: redis-dst, host: 10.10.10.41, port: 6379 ,password: redis.dst, quorum: 1 }

    #==========================================================#
    # redis-src: reuse pg-src 3 nodes for redis
    #==========================================================#
    # ./redis.yml -l redis-src
    redis-src:
      hosts:
        10.10.10.31: { redis_node: 1 , redis_instances: {6379: {  } }}
        10.10.10.32: { redis_node: 2 , redis_instances: {6379: { replica_of: '10.10.10.31 6379' }, 6380: { replica_of: '10.10.10.32 6379' } }}
        10.10.10.33: { redis_node: 3 , redis_instances: {6379: { replica_of: '10.10.10.31 6379' }, 6380: { replica_of: '10.10.10.33 6379' } }}
      vars:
        redis_cluster: redis-src
        redis_password: 'redis.src'
        redis_max_memory: 64MB

    #==========================================================#
    # redis-dst: reuse pg-dst 3 nodes for redis
    #==========================================================#
    # ./redis.yml -l redis-dst
    redis-dst:
      hosts:
        10.10.10.41: { redis_node: 1 , redis_instances: {6379: {  }                               }}
        10.10.10.42: { redis_node: 2 , redis_instances: {6379: { replica_of: '10.10.10.41 6379' } }}
        10.10.10.43: { redis_node: 3 , redis_instances: {6379: { replica_of: '10.10.10.41 6379' } }}
      vars:
        redis_cluster: redis-dst
        redis_password: 'redis.dst'
        redis_max_memory: 64MB

    #==========================================================#
    # pg-tmp: reuse proxy nodes as pgsql cluster
    #==========================================================#
    # ./pgsql.yml -l pg-tmp
    pg-tmp:
      hosts:
        10.10.10.18: { pg_seq: 1 ,pg_role: primary }
        10.10.10.19: { pg_seq: 2 ,pg_role: replica }
      vars:
        pg_cluster: pg-tmp
        pg_users: [ { name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] } ]
        pg_databases: [ { name: tmp } ]

    #==========================================================#
    # pg-etcd: reuse etcd nodes as pgsql cluster
    #==========================================================#
    # ./pgsql.yml -l pg-etcd
    pg-etcd:
      hosts:
        10.10.10.25: { pg_seq: 1 ,pg_role: primary }
        10.10.10.26: { pg_seq: 2 ,pg_role: replica }
        10.10.10.27: { pg_seq: 3 ,pg_role: replica }
        10.10.10.28: { pg_seq: 4 ,pg_role: replica }
        10.10.10.29: { pg_seq: 5 ,pg_role: offline }
      vars:
        pg_cluster: pg-etcd
        pg_users: [ { name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] } ]
        pg_databases: [ { name: etcd } ]

    #==========================================================#
    # pg-minio: reuse minio nodes as pgsql cluster
    #==========================================================#
    # ./pgsql.yml -l pg-minio
    pg-minio:
      hosts:
        10.10.10.21: { pg_seq: 1 ,pg_role: primary }
        10.10.10.22: { pg_seq: 2 ,pg_role: replica }
        10.10.10.23: { pg_seq: 3 ,pg_role: replica }
        10.10.10.24: { pg_seq: 4 ,pg_role: replica }
      vars:
        pg_cluster: pg-minio
        pg_users: [ { name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] } ]
        pg_databases: [ { name: minio } ]

    #==========================================================#
    # ferret: reuse pg-src as mongo (ferretdb)
    #==========================================================#
    # ./mongo.yml -l ferret
    ferret:
      hosts:
        10.10.10.31: { mongo_seq: 1 }
        10.10.10.32: { mongo_seq: 2 }
        10.10.10.33: { mongo_seq: 3 }
      vars:
        mongo_cluster: ferret
        mongo_pgurl: 'postgres://test:[email protected]:5432/src'


  #============================================================#
  # Global Variables
  #============================================================#
  vars:

    #==========================================================#
    # INFRA
    #==========================================================#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: china                     # upstream mirror region: default|china|europe
    infra_portal:                     # infra services exposed via portal
      home         : { domain: i.pigsty }     # default domain name
      minio        : { domain: m.pigsty    ,endpoint: "10.10.10.21:9001" ,scheme: https ,websocket: true }
      postgrest    : { domain: api.pigsty  ,endpoint: "127.0.0.1:8884" }
      pgadmin      : { domain: adm.pigsty  ,endpoint: "127.0.0.1:8885" }
      pgweb        : { domain: cli.pigsty  ,endpoint: "127.0.0.1:8886" }
      bytebase     : { domain: ddl.pigsty  ,endpoint: "127.0.0.1:8887" }
      jupyter      : { domain: lab.pigsty  ,endpoint: "127.0.0.1:8888"  , websocket: true }
      supa         : { domain: supa.pigsty ,endpoint: "10.10.10.10:8000", websocket: true }

    #==========================================================#
    # NODE
    #==========================================================#
    node_id_from_pg: false            # use nodename rather than pg identity as hostname
    node_conf: tiny                   # use small node template
    node_timezone: Asia/Hong_Kong     # use Asia/Hong_Kong Timezone
    node_dns_servers:                 # DNS servers in /etc/resolv.conf
      - 10.10.10.10
      - 10.10.10.11
    node_etc_hosts:
      - 10.10.10.10 i.pigsty
      - 10.10.10.20 sss.pigsty        # point minio service domain to the L2 VIP of proxy cluster
    node_ntp_servers:                 # NTP servers in /etc/chrony.conf
      - pool cn.pool.ntp.org iburst
      - pool 10.10.10.10 iburst
    node_admin_ssh_exchange: false    # exchange admin ssh key among node cluster

    #==========================================================#
    # PGSQL
    #==========================================================#
    pg_conf: tiny.yml
    pgbackrest_method: minio          # USE THE HA MINIO THROUGH A LOAD BALANCER
    pg_dbsu_ssh_exchange: false       # do not exchange dbsu ssh key among pgsql cluster
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `//pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for last 14 days


    #==========================================================#
    # Repo
    #==========================================================#
    repo_packages: [
      node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-utility, extra-modules,
      pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl
    ]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The ha/simu template is a large-scale production environment simulation for testing and validating complex scenarios.

Architecture:

  • 2-node HA INFRA (monitoring/alerting/Nginx/DNS)
  • 5-node HA ETCD and MinIO (multi-disk)
  • 2-node Proxy (HAProxy + Keepalived VIP)
  • Multiple PostgreSQL clusters:
    • pg-meta: 2-node HA
    • pg-v12~v17: Single-node multi-version testing
    • pg-pitr: Single-node PITR testing
    • pg-test: 4-node HA
    • pg-src/pg-dst: 3+2 node replication testing
    • pg-citus: 10-node distributed cluster
  • Multiple Redis modes: primary-replica, sentinel, cluster

Use Cases:

  • Large-scale deployment testing and validation
  • High availability failover drills
  • Performance benchmarking
  • New feature preview and evaluation

Notes:

  • Requires powerful host machine (64GB+ RAM recommended)
  • Uses Vagrant virtual machines for simulation

8.19 - ha/full

Four-node complete feature demonstration environment with two PostgreSQL clusters, MinIO, Redis, etc.

The ha/full configuration template is Pigsty’s recommended sandbox demonstration environment, deploying two PostgreSQL clusters across four nodes for testing and demonstrating various Pigsty capabilities.

Most Pigsty tutorials and examples are based on this template’s sandbox environment.


Overview

  • Config Name: ha/full
  • Node Count: Four nodes
  • Description: Four-node complete feature demonstration environment with two PostgreSQL clusters, MinIO, Redis, etc.
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: ha/trio, ha/safe, demo/demo

Usage:

./configure -c ha/full [-i <primary_ip>]

After configuration, modify the IP addresses of the other three nodes.


Content

Source: pigsty/conf/ha/full.yml

---
#==============================================================#
# File      :   full.yml
# Desc      :   Pigsty Local Sandbox 4-node Demo Config
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


all:

  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:

    # infra: monitor, alert, repo, etc..
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        docker_enabled: true      # enabled docker with ./docker.yml
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    # etcd cluster for HA postgres DCS
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd

    # minio (single node, used as backup repo)
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1 }
      vars:
        minio_cluster: minio
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    # postgres cluster: pg-meta
    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 }
          - { name: dbuser_view ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [ dbrole_readonly ] ,comment: read-only viewer for meta database }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [ pigsty ] }
        pg_hba_rules:
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24
        pg_vip_interface: eth1
        node_crontab:  # make a full backup 1 am everyday
          - '00 01 * * * postgres /pg/bin/pg-backup full'

    # pgsql 3 node ha cluster: pg-test
    pg-test:
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }   # primary instance, leader of cluster
        10.10.10.12: { pg_seq: 2, pg_role: replica }   # replica instance, follower of leader
        10.10.10.13: { pg_seq: 3, pg_role: replica, pg_offline_query: true } # replica with offline access
      vars:
        pg_cluster: pg-test           # define pgsql cluster name
        pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
        pg_databases: [{ name: test }]
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.3/24
        pg_vip_interface: eth1
        node_crontab:  # make a full backup on monday 1am, and an incremental backup during weekdays
          - '00 01 * * 1 postgres /pg/bin/pg-backup full'
          - '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'

    #----------------------------------#
    # redis ms, sentinel, native cluster
    #----------------------------------#
    redis-ms: # redis classic primary & replica
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

    redis-meta: # redis sentinel x 3
      hosts: { 10.10.10.11: { redis_node: 1 , redis_instances: { 26379: { } ,26380: { } ,26381: { } } } }
      vars:
        redis_cluster: redis-meta
        redis_password: 'redis.meta'
        redis_mode: sentinel
        redis_max_memory: 16MB
        redis_sentinel_monitor: # primary list for redis sentinel, use cls as name, primary ip:port
          - { name: redis-ms, host: 10.10.10.10, port: 6379 ,password: redis.ms, quorum: 2 }

    redis-test: # redis native cluster: 3m x 3s
      hosts:
        10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
        10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
      vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }


  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name
      #minio : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

    #----------------------------------#
    # MinIO Related Options
    #----------------------------------#
    node_etc_hosts: [ '${admin_ip} i.pigsty sss.pigsty' ]
    pgbackrest_method: minio          # if you want to use minio as backup repo instead of 'local' fs, uncomment this
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for last 14 days

    #----------------------------------#
    # Repo, Node, Packages
    #----------------------------------#
    repo_remove: true                 # remove existing repo on admin node during repo bootstrap
    node_repo_remove: true            # remove existing node repo for node managed by pigsty
    repo_extra_packages: [ pg18-main ] #,pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_version: 18                    # default postgres version
    #pg_extensions: [pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl ,pg18-olap]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The ha/full template is Pigsty’s complete feature demonstration configuration, showcasing the collaboration of various components.

Components Overview:

ComponentNode DistributionDescription
INFRANode 1Monitoring/Alerting/Nginx/DNS
ETCDNode 1DCS Service
MinIONode 1S3-compatible Storage
pg-metaNode 1Single-node PostgreSQL
pg-testNodes 2-4Three-node HA PostgreSQL
redis-msNode 1Redis Primary-Replica Mode
redis-metaNode 2Redis Sentinel Mode
redis-testNodes 3-4Redis Native Cluster Mode

Use Cases:

  • Pigsty feature demonstration and learning
  • Development testing environments
  • Evaluating HA architecture
  • Comparing different Redis modes

Differences from ha/trio:

  • Added second PostgreSQL cluster (pg-test)
  • Added three Redis cluster mode examples
  • Infrastructure uses single node (instead of three nodes)

Notes:

  • This template is mainly for demonstration and testing; for production, refer to ha/trio or ha/safe
  • MinIO backup enabled by default; comment out related config if not needed

8.20 - ha/safe

Security-hardened HA configuration template with high-standard security best practices

The ha/safe configuration template is based on the ha/trio template, providing a security-hardened configuration with high-standard security best practices.


Overview

  • Config Name: ha/safe
  • Node Count: Three nodes (optional delayed replica)
  • Description: Security-hardened HA configuration with high-standard security best practices
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64 (some security extensions unavailable on ARM64)
  • Related: ha/trio, ha/full

Usage:

./configure -c ha/safe [-i <primary_ip>]

Security Hardening Measures

The ha/safe template implements the following security hardening:

  • Mandatory SSL Encryption: SSL enabled for both PostgreSQL and PgBouncer
  • Strong Password Policy: passwordcheck extension enforces password complexity
  • User Expiration: All users set to 20-year expiration
  • Minimal Connection Scope: Limit PostgreSQL/Patroni/PgBouncer listen addresses
  • Strict HBA Rules: Mandatory SSL authentication, admin requires certificate
  • Audit Logs: Record connection and disconnection events
  • Delayed Replica: Optional 1-hour delayed replica for recovery from mistakes
  • Critical Template: Uses crit.yml tuning template for zero data loss

Content

Source: pigsty/conf/ha/safe.yml

---
#==============================================================#
# File      :   safe.yml
# Desc      :   Pigsty 3-node security enhance template
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


#===== SECURITY ENHANCEMENT CONFIG TEMPLATE WITH 3 NODES ======#
#   * 3 infra nodes, 3 etcd nodes, single minio node
#   * 3-instance pgsql cluster with an extra delayed instance
#   * crit.yml templates, no data loss, checksum enforced
#   * enforce ssl on postgres & pgbouncer, use postgres by default
#   * enforce an expiration date for all users (20 years by default)
#   * enforce strong password policy with passwordcheck extension
#   * enforce changing default password for all users
#   * log connections and disconnections
#   * restrict listen ip address for postgres/patroni/pgbouncer


all:
  children:

    infra: # infra cluster for proxy, monitor, alert, etc
      hosts: # 1 for common usage, 3 nodes for production
        10.10.10.10: { infra_seq: 1 } # identity required
        10.10.10.11: { infra_seq: 2, repo_enabled: false }
        10.10.10.12: { infra_seq: 3, repo_enabled: false }
      vars: { patroni_watchdog_mode: off }

    minio: # minio cluster, s3 compatible object storage
      hosts: { 10.10.10.10: { minio_seq: 1 } }
      vars: { minio_cluster: minio }

    etcd: # dcs service for postgres/patroni ha consensus
      hosts: # 1 node for testing, 3 or 5 for production
        10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
        10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
        10.10.10.12: { etcd_seq: 3 }  # odd number please
      vars: # cluster level parameter override roles/etcd
        etcd_cluster: etcd  # mark etcd cluster name etcd
        etcd_safeguard: false # safeguard against purging
        etcd_clean: true # purge etcd during init process

    pg-meta: # 3 instance postgres cluster `pg-meta`
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        10.10.10.11: { pg_seq: 2, pg_role: replica }
        10.10.10.12: { pg_seq: 3, pg_role: replica , pg_offline_query: true }
      vars:
        pg_cluster: pg-meta
        pg_conf: crit.yml
        pg_users:
          - { 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 }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [ pigsty ] ,extensions: [ { name: vector } ] }
        pg_services:
          - { name: standby , ip: "*" ,port: 5435 , dest: default ,selector: "[]" , backup: "[? pg_role == `primary`]" }
        pg_listen: '${ip},${vip},${lo}'
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24
        pg_vip_interface: eth1

    # OPTIONAL delayed cluster for pg-meta
    #pg-meta-delay: # delayed instance for pg-meta (1 hour ago)
    #  hosts: { 10.10.10.13: { pg_seq: 1, pg_role: primary, pg_upstream: 10.10.10.10, pg_delay: 1h } }
    #  vars: { pg_cluster: pg-meta-delay }


  ####################################################################
  #                          Parameters                              #
  ####################################################################
  vars: # global variables
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
    patroni_ssl_enabled: true         # secure patroni RestAPI communications with SSL?
    pgbouncer_sslmode: require        # pgbouncer client ssl mode: disable|allow|prefer|require|verify-ca|verify-full, disable by default
    pg_default_service_dest: postgres # default service destination to postgres instead of pgbouncer
    pgbackrest_method: minio          # pgbackrest repo method: local,minio,[user-defined...]

    #----------------------------------#
    # MinIO Related Options
    #----------------------------------#
    minio_users: # and configure `pgbackrest_repo` & `minio_users` accordingly
      - { access_key: dba , secret_key: S3User.DBA.Strong.Password, policy: consoleAdmin }
      - { access_key: pgbackrest , secret_key: Min10.bAckup ,policy: readwrite }
    pgbackrest_repo: # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local: # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
      minio: # optional minio repo for pgbackrest
        s3_key: pgbackrest            # <-------- CHANGE THIS, SAME AS `minio_users` access_key
        s3_key_secret: Min10.bAckup   # <-------- CHANGE THIS, SAME AS `minio_users` secret_key
        cipher_pass: 'pgBR.${pg_cluster}'  # <-------- CHANGE THIS, you can use cluster name as part of password
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for last 14 days


    #----------------------------------#
    # Access Control
    #----------------------------------#
    # add passwordcheck extension to enforce strong password policy
    pg_libs: '$libdir/passwordcheck, pg_stat_statements, auto_explain'
    pg_extensions:
      - passwordcheck, supautils, pgsodium, pg_vault, pg_session_jwt, anonymizer, pgsmcrypto, pgauditlogtofile, pgaudit #, pgaudit17, pgaudit16, pgaudit15, pgaudit14
      - pg_auth_mon, credcheck, pgcryptokey, pg_jobmon, logerrors, login_hook, set_user, pgextwlist, pg_auditor, sslutils, noset #pg_tde #pg_snakeoil
    pg_default_roles: # default roles and users in postgres cluster
      - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access }
      - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
      - { name: dbrole_readwrite ,login: false ,roles: [ dbrole_readonly ]               ,comment: role for global read-write access }
      - { name: dbrole_admin     ,login: false ,roles: [ pg_monitor, dbrole_readwrite ]  ,comment: role for object creation }
      - { 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 }
    pg_default_hba_rules: # postgres host-based auth rules by default, order by `order`
      - { user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'   ,order: 100}
      - { user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident'  ,order: 150}
      - { user: '${repl}'    ,db: replication ,addr: localhost ,auth: ssl   ,title: 'replicator replication from localhost' ,order: 200}
      - { user: '${repl}'    ,db: replication ,addr: intra     ,auth: ssl   ,title: 'replicator replication from intranet'  ,order: 250}
      - { user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: ssl   ,title: 'replicator postgres db from intranet'  ,order: 300}
      - { user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password'  ,order: 350}
      - { user: '${monitor}' ,db: all         ,addr: infra     ,auth: ssl   ,title: 'monitor from infra host with password' ,order: 400}
      - { user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'    ,order: 450}
      - { user: '${admin}'   ,db: all         ,addr: world     ,auth: cert  ,title: 'admin @ everywhere with ssl & cert'    ,order: 500}
      - { user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: ssl   ,title: 'pgbouncer read/write via local socket' ,order: 550}
      - { user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: ssl   ,title: 'read/write biz user via password'      ,order: 600}
      - { user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: ssl   ,title: 'allow etl offline tasks from intranet' ,order: 650}
    pgb_default_hba_rules: # pgbouncer host-based authentication rules, order by `order`
      - { user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident' ,order: 100}
      - { user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd'  ,order: 150}
      - { user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: ssl   ,title: 'monitor access via intranet with pwd'  ,order: 200}
      - { user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr'  ,order: 250}
      - { user: '${admin}'   ,db: all         ,addr: intra     ,auth: ssl   ,title: 'admin access via intranet with pwd'    ,order: 300}
      - { user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'    ,order: 350}
      - { user: 'all'        ,db: all         ,addr: intra     ,auth: ssl   ,title: 'allow all user intra access with pwd'  ,order: 400}

    #----------------------------------#
    # Repo, Node, Packages
    #----------------------------------#
    repo_remove: true                 # remove existing repo on admin node during repo bootstrap
    node_repo_remove: true            # remove existing node repo for node managed by pigsty
    #node_selinux_mode: enforcing     # set selinux mode: enforcing,permissive,disabled
    node_firewall_mode: zone          # firewall mode: off, none, zone, zone by default

    repo_extra_packages: [ pg18-main ] #,pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_version: 18                    # default postgres version
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    #grafana_admin_username: admin
    grafana_admin_password: You.Have2Use-A_VeryStrongPassword
    grafana_view_password: DBUser.Viewer
    #pg_admin_username: dbuser_dba
    pg_admin_password: PessWorb.Should8eStrong-eNough
    #pg_monitor_username: dbuser_monitor
    pg_monitor_password: MekeSuerYour.PassWordI5secured
    #pg_replication_username: replicator
    pg_replication_password: doNotUseThis-PasswordFor.AnythingElse
    #patroni_username: postgres
    patroni_password: don.t-forget-to-change-thEs3-password
    #haproxy_admin_username: admin
    haproxy_admin_password: GneratePasswordWith-pwgen-s-16-1
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The ha/safe template is Pigsty’s security-hardened configuration, designed for production environments with high security requirements.

Security Features Summary:

Security MeasureDescription
SSL EncryptionFull-chain SSL for PostgreSQL/PgBouncer/Patroni
Strong Passwordpasswordcheck extension enforces complexity
User ExpirationAll users expire in 20 years (expire_in: 7300)
Strict HBAAdmin remote access requires certificate
Encrypted BackupMinIO backup with AES-256-CBC encryption
Audit Logspgaudit extension for SQL audit logging
Delayed Replica1-hour delayed replica for mistake recovery

Use Cases:

  • Finance, healthcare, government sectors with high security requirements
  • Environments needing compliance audit requirements
  • Critical business with extremely high data security demands

Notes:

  • Some security extensions unavailable on ARM64 architecture, enable appropriately
  • All default passwords must be changed to strong passwords
  • Recommend using with regular security audits

8.21 - ha/trio

Three-node standard HA configuration, tolerates any single server failure

Three nodes is the minimum scale for achieving true high availability. The ha/trio template uses a three-node standard HA architecture, with INFRA, ETCD, and PGSQL all deployed across three nodes, tolerating any single server failure.


Overview

  • Config Name: ha/trio
  • Node Count: Three nodes
  • Description: Three-node standard HA architecture, tolerates any single server failure
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: ha/dual, ha/full, ha/safe

Usage:

./configure -c ha/trio [-i <primary_ip>]

After configuration, modify placeholder IPs 10.10.10.11 and 10.10.10.12 to actual node IP addresses.


Content

Source: pigsty/conf/ha/trio.yml

---
#==============================================================#
# File      :   trio.yml
# Desc      :   Pigsty 3-node security enhance template
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# 3 infra node, 3 etcd node, 3 pgsql node, and 1 minio node

all:

  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:

    #----------------------------------#
    # infra: monitor, alert, repo, etc..
    #----------------------------------#
    infra: # infra cluster for proxy, monitor, alert, etc
      hosts: # 1 for common usage, 3 nodes for production
        10.10.10.10: { infra_seq: 1 } # identity required
        10.10.10.11: { infra_seq: 2, repo_enabled: false }
        10.10.10.12: { infra_seq: 3, repo_enabled: false }
      vars:
        patroni_watchdog_mode: off # do not fencing infra

    etcd: # dcs service for postgres/patroni ha consensus
      hosts: # 1 node for testing, 3 or 5 for production
        10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
        10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
        10.10.10.12: { etcd_seq: 3 }  # odd number please
      vars: # cluster level parameter override roles/etcd
        etcd_cluster: etcd  # mark etcd cluster name etcd
        etcd_safeguard: false # safeguard against purging
        etcd_clean: true # purge etcd during init process

    minio: # minio cluster, s3 compatible object storage
      hosts: { 10.10.10.10: { minio_seq: 1 } }
      vars: { minio_cluster: minio }

    pg-meta: # 3 instance postgres cluster `pg-meta`
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        10.10.10.11: { pg_seq: 2, pg_role: replica }
        10.10.10.12: { pg_seq: 3, pg_role: replica , pg_offline_query: true }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta , password: DBUser.Meta ,pgbouncer: true ,roles: [ dbrole_admin ]    ,comment: pigsty admin user }
          - { name: dbuser_view , password: DBUser.View ,pgbouncer: true ,roles: [ dbrole_readonly ] ,comment: read-only viewer for meta database }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [ pigsty ] ,extensions: [ { name: vector } ] }
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24
        pg_vip_interface: eth1


  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------#
    # Meta Data
    #----------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    infra_portal:                     # infra services exposed via portal
      home         : { domain: i.pigsty }     # default domain name
      #minio        : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

    #----------------------------------#
    # Repo, Node, Packages
    #----------------------------------#
    repo_remove: true                 # remove existing repo on admin node during repo bootstrap
    node_repo_remove: true            # remove existing node repo for node managed by pigsty
    repo_extra_packages: [ pg18-main ] #,pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_version: 18                    # default postgres version
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The ha/trio template is Pigsty’s standard HA configuration, providing true automatic failover capability.

Architecture:

  • Three-node INFRA: Distributed deployment of Prometheus/Grafana/Nginx
  • Three-node ETCD: DCS majority election, tolerates single-point failure
  • Three-node PostgreSQL: One primary, two replicas, automatic failover
  • Single-node MinIO: Can be expanded to multi-node as needed

HA Guarantees:

  • Three-node ETCD tolerates one node failure, maintains majority
  • PostgreSQL primary failure triggers automatic Patroni election for new primary
  • L2 VIP follows primary, applications don’t need to modify connection config

Use Cases:

  • Minimum HA deployment for production environments
  • Critical business requiring automatic failover
  • Foundation architecture for larger scale deployments

Extension Suggestions:

  • For stronger data security, refer to ha/safe template
  • For more demo features, refer to ha/full template
  • Production environments should enable pgbackrest_method: minio for remote backup

8.22 - ha/dual

Two-node configuration, limited HA deployment tolerating specific server failure

The ha/dual template uses two-node deployment, implementing a “semi-HA” architecture with one primary and one standby. If you only have two servers, this is a pragmatic choice.


Overview

  • Config Name: ha/dual
  • Node Count: Two nodes
  • Description: Two-node limited HA deployment, tolerates specific server failure
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: ha/trio, slim

Usage:

./configure -c ha/dual [-i <primary_ip>]

After configuration, modify placeholder IP 10.10.10.11 to actual standby node IP address.


Content

Source: pigsty/conf/ha/dual.yml

---
#==============================================================#
# File      :   dual.yml
# Desc      :   Pigsty deployment example for two nodes
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


# It is recommended to use at least three nodes in production deployment.
# But sometimes, there are only two nodes available, that's dual.yml for
#
# In this setup, we have two nodes, .10 (admin_node) and .11 (pgsql_priamry):
#
# If .11 is down, .10 will take over since the dcs:etcd is still alive
# If .10 is down, .11 (pgsql primary) will still be functioning as a primary if:
#   - Only dcs:etcd is down
#   - Only pgsql is down
# if both etcd & pgsql are down (e.g. node down), the primary will still demote itself.


all:
  children:

    # infra cluster for proxy, monitor, alert, etc..
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

    # etcd cluster for ha postgres
    etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # minio cluster, optional backup repo for pgbackrest
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    # postgres cluster 'pg-meta' with single primary instance
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: replica }
        10.10.10.11: { pg_seq: 2, pg_role: primary }  # <----- use this as primary by default
      vars:
        pg_cluster: pg-meta
        pg_databases: [ { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [ pigsty ] ,extensions: [ { name: vector }] } ]
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [ dbrole_admin ]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [ dbrole_readonly ] ,comment: read-only viewer for meta database }
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24
        pg_vip_interface: eth1

  vars:                               # global parameters
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
    infra_portal:                     # domain names and upstream servers
      home   : { domain: i.pigsty }
      #minio : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

    #----------------------------------#
    # Repo, Node, Packages
    #----------------------------------#
    repo_remove: true                 # remove existing repo on admin node during repo bootstrap
    node_repo_remove: true            # remove existing node repo for node managed by pigsty
    repo_extra_packages: [ pg18-main ] #,pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_version: 18                    # default postgres version
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The ha/dual template is Pigsty’s two-node limited HA configuration, designed for scenarios with only two servers.

Architecture:

  • Node A (10.10.10.10): Admin node, runs Infra + etcd + PostgreSQL replica
  • Node B (10.10.10.11): Data node, runs PostgreSQL primary only

Failure Scenario Analysis:

Failed NodeImpactAuto Recovery
Node B downPrimary switches to Node AAuto
Node A etcd downPrimary continues running (no DCS)Manual
Node A pgsql downPrimary continues runningManual
Node A complete failurePrimary degrades to standaloneManual

Use Cases:

  • Budget-limited environments with only two servers
  • Acceptable that some failure scenarios need manual intervention
  • Transitional solution before upgrading to three-node HA

Notes:

  • True HA requires at least three nodes (DCS needs majority)
  • Recommend upgrading to three-node architecture as soon as possible
  • L2 VIP requires network environment support (same broadcast domain)

8.23 - App Templates

8.24 - app/odoo

Deploy Odoo open-source ERP system using Pigsty-managed PostgreSQL

The app/odoo configuration template provides a reference configuration for self-hosting Odoo open-source ERP system, using Pigsty-managed PostgreSQL as the database.

For more details, see Odoo Deployment Tutorial


Overview

  • Config Name: app/odoo
  • Node Count: Single node
  • Description: Deploy Odoo ERP using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/odoo [-i <primary_ip>]

Content

Source: pigsty/conf/app/odoo.yml

---
#==============================================================#
# File      :   odoo.yml
# Desc      :   pigsty config for running 1-node odoo app
# Ctime     :   2025-01-11
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/app/odoo
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# tutorial: https://doc.pgsty.com/app/odoo
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap               # prepare local repo & ansible
# ./configure -c app/odoo   # Use this odoo config template
# vi pigsty.yml             # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml              # install pigsty & pgsql & minio
# ./docker.yml              # install docker & docker-compose
# ./app.yml                 # install odoo

all:
  children:

    # the odoo application (default username & password: admin/admin)
    odoo:
      hosts: { 10.10.10.10: {} }
      vars:
        app: odoo   # specify app name to be installed (in the apps)
        apps:       # define all applications
          odoo:     # app name, should have corresponding ~/pigsty/app/odoo folder
            file:   # optional directory to be created
              - { path: /data/odoo         ,state: directory, owner: 100, group: 101 }
              - { path: /data/odoo/webdata ,state: directory, owner: 100, group: 101 }
              - { path: /data/odoo/addons  ,state: directory, owner: 100, group: 101 }
            conf:   # override /opt/<app>/.env config file
              PG_HOST: 10.10.10.10            # postgres host
              PG_PORT: 5432                   # postgres port
              PG_USERNAME: odoo               # postgres user
              PG_PASSWORD: DBUser.Odoo        # postgres password
              ODOO_PORT: 8069                 # odoo app port
              ODOO_DATA: /data/odoo/webdata   # odoo webdata
              ODOO_ADDONS: /data/odoo/addons  # odoo plugins
              ODOO_DBNAME: odoo               # odoo database name
              ODOO_VERSION: 19.0              # odoo image version

    # the odoo database
    pg-odoo:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-odoo
        pg_users:
          - { name: odoo    ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_admin ] ,createdb: true ,comment: admin user for odoo service }
          - { name: odoo_ro ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_readonly ]  ,comment: read only user for odoo service  }
          - { name: odoo_rw ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_readwrite ] ,comment: read write user for odoo service }
        pg_databases:
          - { name: odoo ,owner: odoo ,revokeconn: true ,comment: odoo main database  }
        pg_hba_rules:
          - { user: all ,db: all ,addr: 172.17.0.0/16  ,auth: pwd ,title: 'allow access from local docker network' }
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # domain names and upstream servers
      home  : { domain: i.pigsty }
      minio : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      odoo:                           # nginx server config for odoo
        domain: odoo.pigsty           # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:8069"  # odoo service endpoint: IP:PORT
        websocket: true               # add websocket support
        certbot: odoo.pigsty          # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/odoo template provides a one-click deployment solution for Odoo open-source ERP system.

What is Odoo:

  • World’s most popular open-source ERP system
  • Covers CRM, Sales, Purchasing, Inventory, Finance, HR, and other enterprise management modules
  • Supports thousands of community and official application extensions
  • Provides web interface and mobile support

Key Features:

  • Uses Pigsty-managed PostgreSQL instead of Odoo’s built-in database
  • Supports Odoo 19.0 latest version
  • Data persisted to independent directory /data/odoo
  • Supports custom plugin directory /data/odoo/addons

Access:

# Odoo Web interface
http://odoo.pigsty:8069

# Default admin account
Username: admin
Password: admin (set on first login)

Use Cases:

  • SMB ERP systems
  • Alternative to SAP, Oracle ERP and other commercial solutions
  • Enterprise applications requiring customized business processes

Notes:

  • Odoo container runs as uid=100, gid=101, data directory needs correct permissions
  • First access requires creating database and setting admin password
  • Production environments should enable HTTPS
  • Custom modules can be installed via /data/odoo/addons

8.25 - app/dify

Deploy Dify AI application development platform using Pigsty-managed PostgreSQL

The app/dify configuration template provides a reference configuration for self-hosting Dify AI application development platform, using Pigsty-managed PostgreSQL and pgvector as vector storage.

For more details, see Dify Deployment Tutorial


Overview

  • Config Name: app/dify
  • Node Count: Single node
  • Description: Deploy Dify using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/dify [-i <primary_ip>]

Content

Source: pigsty/conf/app/dify.yml

---
#==============================================================#
# File      :   dify.yml
# Desc      :   pigsty config for running 1-node dify app
# Ctime     :   2025-02-24
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/app/odoo
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#
# Last Verified Dify Version: v1.8.1 on 2025-0908
# tutorial: https://doc.pgsty.com/app/dify
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap               # prepare local repo & ansible
# ./configure -c app/dify   # use this dify config template
# vi pigsty.yml             # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml              # install pigsty & pgsql & minio
# ./docker.yml              # install docker & docker-compose
# ./app.yml                 # install dify with docker-compose
#
# To replace domain name:
#   sed -ie 's/dify.pigsty/dify.pigsty.cc/g' pigsty.yml


all:
  children:

    # the dify application
    dify:
      hosts: { 10.10.10.10: {} }
      vars:
        app: dify   # specify app name to be installed (in the apps)
        apps:       # define all applications
          dify:     # app name, should have corresponding ~/pigsty/app/dify folder
            file:   # data directory to be created
              - { path: /data/dify ,state: directory ,mode: 0755 }
            conf:   # override /opt/dify/.env config file

              # change domain, mirror, proxy, secret key
              NGINX_SERVER_NAME: dify.pigsty
              # A secret key for signing and encryption, gen with `openssl rand -base64 42` (CHANGE PASSWORD!)
              SECRET_KEY: sk-somerandomkey
              # expose DIFY nginx service with port 5001 by default
              DIFY_PORT: 5001
              # where to store dify files? the default is ./volume, we'll use another volume created above
              DIFY_DATA: /data/dify

              # proxy and mirror settings
              #PIP_MIRROR_URL: https://pypi.tuna.tsinghua.edu.cn/simple
              #SANDBOX_HTTP_PROXY: http://10.10.10.10:12345
              #SANDBOX_HTTPS_PROXY: http://10.10.10.10:12345

              # database credentials
              DB_USERNAME: dify
              DB_PASSWORD: difyai123456
              DB_HOST: 10.10.10.10
              DB_PORT: 5432
              DB_DATABASE: dify
              VECTOR_STORE: pgvector
              PGVECTOR_HOST: 10.10.10.10
              PGVECTOR_PORT: 5432
              PGVECTOR_USER: dify
              PGVECTOR_PASSWORD: difyai123456
              PGVECTOR_DATABASE: dify
              PGVECTOR_MIN_CONNECTION: 2
              PGVECTOR_MAX_CONNECTION: 10

    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dify ,password: difyai123456 ,pgbouncer: true ,roles: [ dbrole_admin ] ,superuser: true ,comment: dify superuser }
        pg_databases:
          - { name: dify        ,owner: dify ,revokeconn: true ,comment: dify main database  }
          - { name: dify_plugin ,owner: dify ,revokeconn: true ,comment: dify plugin_daemon database }
        pg_hba_rules:
          - { user: dify ,db: all ,addr: 172.17.0.0/16  ,auth: pwd ,title: 'allow dify access from local docker network' }
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # domain names and upstream servers
      home   :  { domain: i.pigsty }
      #minio :  { domain: m.pigsty    ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      dify:                            # nginx server config for dify
        domain: dify.pigsty            # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:5001"   # dify service endpoint: IP:PORT
        websocket: true                # add websocket support
        certbot: dify.pigsty           # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/dify template provides a one-click deployment solution for Dify AI application development platform.

What is Dify:

  • Open-source LLM application development platform
  • Supports RAG, Agent, Workflow and other AI application modes
  • Provides visual Prompt orchestration and application building interface
  • Supports multiple LLM backends (OpenAI, Claude, local models, etc.)

Key Features:

  • Uses Pigsty-managed PostgreSQL instead of Dify’s built-in database
  • Uses pgvector as vector storage (replaces Weaviate/Qdrant)
  • Supports HTTPS and custom domain names
  • Data persisted to independent directory /data/dify

Access:

# Dify Web interface
http://dify.pigsty:5001

# Or via Nginx proxy
https://dify.pigsty

Use Cases:

  • Enterprise internal AI application development platform
  • RAG knowledge base Q&A systems
  • LLM-driven automated workflows
  • AI Agent development and deployment

Notes:

  • Must change SECRET_KEY, generate with openssl rand -base64 42
  • Configure LLM API keys (e.g., OpenAI API Key)
  • Docker network needs access to PostgreSQL (172.17.0.0/16 HBA rule configured)
  • Recommend configuring proxy to accelerate Python package downloads

8.26 - app/electric

Deploy Electric real-time sync service using Pigsty-managed PostgreSQL

The app/electric configuration template provides a reference configuration for deploying Electric SQL real-time sync service, enabling real-time data synchronization from PostgreSQL to clients.


Overview

  • Config Name: app/electric
  • Node Count: Single node
  • Description: Deploy Electric real-time sync using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/electric [-i <primary_ip>]

Content

Source: pigsty/conf/app/electric.yml

---
#==============================================================#
# File      :   electric.yml
# Desc      :   pigsty config for running 1-node electric app
# Ctime     :   2025-03-29
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/app/odoo
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# tutorial: https://doc.pgsty.com/app/electric
# quick start: https://electric-sql.com/docs/quickstart
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap                 # prepare local repo & ansible
# ./configure -c app/electric # use this dify config template
# vi pigsty.yml               # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml                # install pigsty & pgsql & minio
# ./docker.yml                # install docker & docker-compose
# ./app.yml                   # install dify with docker-compose

all:
  children:
    # infra cluster for proxy, monitor, alert, etc..
    infra:
      hosts: { 10.10.10.10: { infra_seq: 1 } }
      vars:

        app: electric
        apps:       # define all applications
          electric: # app name, should have corresponding ~/pigsty/app/electric folder
            conf:   # override /opt/electric/.env config file : https://electric-sql.com/docs/api/config
              DATABASE_URL: 'postgresql://electric:[email protected]:5432/electric?sslmode=require'
              ELECTRIC_PORT: 8002
              ELECTRIC_PROMETHEUS_PORT: 8003
              ELECTRIC_INSECURE: true
              #ELECTRIC_SECRET: 1U6ItbhoQb4kGUU5wXBLbxvNf

    # etcd cluster for ha postgres
    etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # minio cluster, s3 compatible object storage
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    # postgres example cluster: pg-meta
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: electric ,password: DBUser.Electric ,pgbouncer: true , replication: true ,roles: [dbrole_admin] ,comment: electric main user }
        pg_databases: [{ name: electric , owner: electric }]
        pg_hba_rules:
          - { user: electric , db: replication ,addr: infra ,auth: ssl ,title: 'allow electric intranet/docker ssl access' }

  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------#
    # Meta Data
    #----------------------------------#
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    infra_portal:                     # domain names and upstream servers
      home : { domain: i.pigsty }
      electric:
        domain: elec.pigsty
        endpoint: "${admin_ip}:8002"
        websocket: true               # apply free ssl cert with certbot: make cert
        certbot: odoo.pigsty          # <----- replace with your own domain name!

    #----------------------------------#
    # Safe Guard
    #----------------------------------#
    # you can enable these flags after bootstrap, to prevent purging running etcd / pgsql instances
    etcd_safeguard: false             # prevent purging running etcd instance?
    pg_safeguard: false               # prevent purging running postgres instance? false by default

    #----------------------------------#
    # Repo, Node, Packages
    #----------------------------------#
    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18                    # default postgres version
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/electric template provides a one-click deployment solution for Electric SQL real-time sync service.

What is Electric:

  • PostgreSQL to client real-time data sync service
  • Supports Local-first application architecture
  • Real-time syncs data changes via logical replication
  • Provides HTTP API for frontend application consumption

Key Features:

  • Uses Pigsty-managed PostgreSQL as data source
  • Captures data changes via Logical Replication
  • Supports SSL encrypted connections
  • Built-in Prometheus metrics endpoint

Access:

# Electric API endpoint
http://elec.pigsty:8002

# Prometheus metrics
http://elec.pigsty:8003/metrics

Use Cases:

  • Building Local-first applications
  • Real-time data sync to clients
  • Mobile and PWA data synchronization
  • Real-time updates for collaborative applications

Notes:

  • Electric user needs replication permission
  • PostgreSQL logical replication must be enabled
  • Production environments should use SSL connection (configured with sslmode=require)

8.27 - app/maybe

Deploy Maybe personal finance management system using Pigsty-managed PostgreSQL

The app/maybe configuration template provides a reference configuration for deploying Maybe open-source personal finance management system, using Pigsty-managed PostgreSQL as the database.


Overview

  • Config Name: app/maybe
  • Node Count: Single node
  • Description: Deploy Maybe finance management using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/maybe [-i <primary_ip>]

Content

Source: pigsty/conf/app/maybe.yml

---
#==============================================================#
# File      :   maybe.yml
# Desc      :   pigsty config for running 1-node maybe app
# Ctime     :   2025-09-08
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/app/maybe
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# tutorial: https://doc.pgsty.com/app/maybe
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap               # prepare local repo & ansible
# ./configure -c app/maybe  # Use this maybe config template
# vi pigsty.yml             # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml              # install pigsty & pgsql
# ./docker.yml              # install docker & docker-compose
# ./app.yml                 # install maybe

all:
  children:

    # the maybe application (personal finance management)
    maybe:
      hosts: { 10.10.10.10: {} }
      vars:
        app: maybe   # specify app name to be installed (in the apps)
        apps:        # define all applications
          maybe:     # app name, should have corresponding ~/pigsty/app/maybe folder
            file:    # optional directory to be created
              - { path: /data/maybe             ,state: directory ,mode: 0755 }
              - { path: /data/maybe/storage     ,state: directory ,mode: 0755 }
            conf:    # override /opt/<app>/.env config file
              # Core Configuration
              MAYBE_VERSION: latest                    # Maybe image version
              MAYBE_PORT: 5002                         # Port to expose Maybe service
              MAYBE_DATA: /data/maybe                  # Data directory for Maybe
              APP_DOMAIN: maybe.pigsty                 # Domain name for Maybe
              
              # REQUIRED: Generate with: openssl rand -hex 64
              SECRET_KEY_BASE: sk-somerandomkey
              
              # Database Configuration
              DB_HOST: 10.10.10.10                    # PostgreSQL host
              DB_PORT: 5432                           # PostgreSQL port
              DB_USERNAME: maybe                      # PostgreSQL username
              DB_PASSWORD: MaybeFinance2025           # PostgreSQL password (CHANGE THIS!)
              DB_DATABASE: maybe_production           # PostgreSQL database name
              
              # Optional: API Integration
              #SYNTH_API_KEY:                         # Get from synthfinance.com

    # the maybe database
    pg-maybe:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-maybe
        pg_users:
          - { name: maybe    ,password: MaybeFinance2025 ,pgbouncer: true ,roles: [ dbrole_admin ] ,createdb: true ,comment: admin user for maybe service }
          - { name: maybe_ro ,password: MaybeFinance2025 ,pgbouncer: true ,roles: [ dbrole_readonly ]  ,comment: read only user for maybe service  }
          - { name: maybe_rw ,password: MaybeFinance2025 ,pgbouncer: true ,roles: [ dbrole_readwrite ] ,comment: read write user for maybe service }
        pg_databases:
          - { name: maybe_production ,owner: maybe ,revokeconn: true ,comment: maybe main database  }
        pg_hba_rules:
          - { user: maybe ,db: all ,addr: 172.17.0.0/16  ,auth: pwd ,title: 'allow maybe access from local docker network' }
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # infra services exposed via portal
      home  : { domain: i.pigsty }    # default domain name
      minio : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      maybe:                          # nginx server config for maybe
        domain: maybe.pigsty          # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:5002"  # maybe service endpoint: IP:PORT
        websocket: true               # add websocket support

    repo_enabled: false
    node_repo_modules: node,infra,pgsql

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root

...

Explanation

The app/maybe template provides a one-click deployment solution for Maybe open-source personal finance management system.

What is Maybe:

  • Open-source personal and family finance management system
  • Supports multi-account, multi-currency asset tracking
  • Provides investment portfolio analysis and net worth calculation
  • Beautiful modern web interface

Key Features:

  • Uses Pigsty-managed PostgreSQL instead of Maybe’s built-in database
  • Data persisted to independent directory /data/maybe
  • Supports HTTPS and custom domain names
  • Multi-user permission management

Access:

# Maybe Web interface
http://maybe.pigsty:5002

# Or via Nginx proxy
https://maybe.pigsty

Use Cases:

  • Personal or family finance management
  • Investment portfolio tracking and analysis
  • Multi-account asset aggregation
  • Alternative to commercial services like Mint, YNAB

Notes:

  • Must change SECRET_KEY_BASE, generate with openssl rand -hex 64
  • First access requires registering an admin account
  • Optionally configure Synth API for stock price data

8.28 - app/teable

Deploy Teable open-source Airtable alternative using Pigsty-managed PostgreSQL

The app/teable configuration template provides a reference configuration for deploying Teable open-source no-code database, using Pigsty-managed PostgreSQL as the database.


Overview

  • Config Name: app/teable
  • Node Count: Single node
  • Description: Deploy Teable using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/teable [-i <primary_ip>]

Content

Source: pigsty/conf/app/teable.yml

---
#==============================================================#
# File      :   teable.yml
# Desc      :   pigsty config for running 1-node teable app
# Ctime     :   2025-02-24
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/app/odoo
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# tutorial: https://doc.pgsty.com/app/teable
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap               # prepare local repo & ansible
# ./configure -c app/teable # use this teable config template
# vi pigsty.yml             # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml              # install pigsty & pgsql & minio
# ./docker.yml              # install docker & docker-compose
# ./app.yml                 # install teable with docker-compose
#
# To replace domain name:
#   sed -ie 's/teable.pigsty/teable.pigsty.cc/g' pigsty.yml

all:
  children:

    # the teable application
    teable:
      hosts: { 10.10.10.10: {} }
      vars:
        app: teable   # specify app name to be installed (in the apps)
        apps:         # define all applications
          teable:     # app name, ~/pigsty/app/teable folder
            conf:     # override /opt/teable/.env config file
              # https://github.com/teableio/teable/blob/develop/dockers/examples/standalone/.env
              # https://help.teable.io/en/deploy/env
              POSTGRES_HOST: "10.10.10.10"
              POSTGRES_PORT: "5432"
              POSTGRES_DB: "teable"
              POSTGRES_USER: "dbuser_teable"
              POSTGRES_PASSWORD: "DBUser.Teable"
              PRISMA_DATABASE_URL: "postgresql://dbuser_teable:[email protected]:5432/teable"
              PUBLIC_ORIGIN: "http://tea.pigsty"
              PUBLIC_DATABASE_PROXY: "10.10.10.10:5432"
              TIMEZONE: "UTC"

              # Need to support sending emails to enable the following configurations
              #BACKEND_MAIL_HOST: smtp.teable.io
              #BACKEND_MAIL_PORT: 465
              #BACKEND_MAIL_SECURE: true
              #BACKEND_MAIL_SENDER: noreply.teable.io
              #BACKEND_MAIL_SENDER_NAME: Teable
              #BACKEND_MAIL_AUTH_USER: username
              #BACKEND_MAIL_AUTH_PASS: password


    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_teable ,password: DBUser.Teable ,pgbouncer: true ,roles: [ dbrole_admin ] ,superuser: true ,comment: teable superuser }
        pg_databases:
          - { name: teable ,owner: dbuser_teable ,comment: teable database }
        pg_hba_rules:
          - { user: teable ,db: all ,addr: 172.17.0.0/16  ,auth: pwd ,title: 'allow teable access from local docker network' }
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345
    infra_portal:                        # domain names and upstream servers
      home   : { domain: i.pigsty }
      #minio : { domain: m.pigsty    ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

      teable:                            # nginx server config for teable
        domain: tea.pigsty               # REPLACE IT WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:8890"     # teable service endpoint: IP:PORT
        websocket: true                  # add websocket support
        certbot: tea.pigsty              # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/teable template provides a one-click deployment solution for Teable open-source no-code database.

What is Teable:

  • Open-source Airtable alternative
  • No-code database built on PostgreSQL
  • Supports table, kanban, calendar, form, and other views
  • Provides API and automation workflows

Key Features:

  • Uses Pigsty-managed PostgreSQL as underlying storage
  • Data is stored in real PostgreSQL tables
  • Supports direct SQL queries
  • Can integrate with other PostgreSQL tools and extensions

Access:

# Teable Web interface
http://tea.pigsty:8890

# Or via Nginx proxy
https://tea.pigsty

# Direct SQL access to underlying data
psql postgresql://dbuser_teable:[email protected]:5432/teable

Use Cases:

  • Need Airtable-like functionality but want to self-host
  • Team collaboration data management
  • Need both API and SQL access
  • Want data stored in real PostgreSQL

Notes:

  • Teable user needs superuser privileges
  • Must configure PUBLIC_ORIGIN to external access address
  • Supports email notifications (optional SMTP configuration)

8.29 - app/registry

Deploy Docker Registry image proxy and private registry using Pigsty

The app/registry configuration template provides a reference configuration for deploying Docker Registry as an image proxy, usable as Docker Hub mirror acceleration or private image registry.


Overview

  • Config Name: app/registry
  • Node Count: Single node
  • Description: Deploy Docker Registry image proxy and private registry
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/registry [-i <primary_ip>]

Content

Source: pigsty/conf/app/registry.yml

---
#==============================================================#
# File      :   registry.yml
# Desc      :   pigsty config for running Docker Registry Mirror
# Ctime     :   2025-07-01
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/app/registry
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# tutorial: https://doc.pgsty.com/app/registry
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./configure -c app/registry   # use this registry config template
# vi pigsty.yml                 # IMPORTANT: CHANGE DOMAIN & CREDENTIALS!
# ./deploy.yml                  # install pigsty
# ./docker.yml                  # install docker & docker-compose
# ./app.yml                     # install registry with docker-compose
#
# To replace domain name:
#   sed -ie 's/registry.pigsty/registry.your-domain.com/g' pigsty.yml

#==============================================================#
# Usage Instructions:
#==============================================================#
#
# 1. Deploy the registry:
#    ./configure -c conf/app/registry.yml && ./deploy.yml && ./docker.yml && ./app.yml
#
# 2. Configure Docker clients to use the mirror:
#    Edit /etc/docker/daemon.json:
#    {
#      "registry-mirrors": ["https://registry.your-domain.com"],
#      "insecure-registries": ["registry.your-domain.com"]
#    }
#
# 3. Restart Docker daemon:
#    sudo systemctl restart docker
#
# 4. Test the registry:
#    docker pull nginx:latest  # This will now use your mirror
#
# 5. Access the web UI (optional):
#    https://registry-ui.your-domain.com
#
# 6. Monitor the registry:
#    curl https://registry.your-domain.com/v2/_catalog
#    curl https://registry.your-domain.com/v2/nginx/tags/list
#
#==============================================================#


all:
  children:

    # the docker registry mirror application
    registry:
      hosts: { 10.10.10.10: {} }
      vars:
        app: registry                    # specify app name to be installed
        apps:                            # define all applications
          registry:
            file:                        # create data directory for registry
              - { path: /data/registry ,state: directory ,mode: 0755 }
            conf:                        # environment variables for registry
              REGISTRY_DATA: /data/registry
              REGISTRY_PORT: 5000
              REGISTRY_UI_PORT: 5080
              REGISTRY_STORAGE_DELETE_ENABLED: true
              REGISTRY_LOG_LEVEL: info
              REGISTRY_PROXY_REMOTEURL: https://registry-1.docker.io
              REGISTRY_PROXY_TTL: 168h

    # basic infrastructure
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

  vars:
    #----------------------------------------------#
    # INFRA : https://doc.pgsty.com/infra/param
    #----------------------------------------------#
    version: v4.0.0                      # pigsty version string
    admin_ip: 10.10.10.10                # admin node ip address
    region: default                      # upstream mirror region: default,china,europe
    infra_portal:                        # infra services exposed via portal
      home : { domain: i.pigsty }        # default domain name

      # Docker Registry Mirror service configuration
      registry:                          # nginx server config for registry
        domain: d.pigsty                 # REPLACE IT WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:5000"     # registry service endpoint: IP:PORT
        websocket: false                 # registry doesn't need websocket
        certbot: d.pigsty                # certbot cert name, apply with `make cert`

      # Optional: Registry Web UI
      registry-ui:                       # nginx server config for registry UI
        domain: dui.pigsty               # REPLACE IT WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:5080"     # registry UI endpoint: IP:PORT
        websocket: false                 # UI doesn't need websocket
        certbot: d.pigsty                # certbot cert name for UI

    #----------------------------------------------#
    # NODE : https://doc.pgsty.com/node/param
    #----------------------------------------------#
    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://doc.pgsty.com/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # Default PostgreSQL Major Version is 18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_packages: [ pgsql-main, pgsql-common ]   # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/registry template provides a one-click deployment solution for Docker Registry image proxy.

What is Registry:

  • Docker’s official image registry implementation
  • Can serve as Docker Hub pull-through cache
  • Can also serve as private image registry
  • Supports image caching and local storage

Key Features:

  • Acts as proxy cache for Docker Hub to accelerate image pulls
  • Caches images to local storage /data/registry
  • Provides Web UI to view cached images
  • Supports custom cache expiration time

Configure Docker Client:

# Edit /etc/docker/daemon.json
{
  "registry-mirrors": ["https://d.pigsty"],
  "insecure-registries": ["d.pigsty"]
}

# Restart Docker
sudo systemctl restart docker

Access:

# Registry API
https://d.pigsty/v2/_catalog

# Web UI
http://dui.pigsty:5080

# Pull images (automatically uses proxy)
docker pull nginx:latest

Use Cases:

  • Accelerate Docker image pulls (especially in mainland China)
  • Reduce external network dependency
  • Enterprise internal private image registry
  • Offline environment image distribution

Notes:

  • Requires sufficient disk space to store cached images
  • Default cache TTL is 7 days (REGISTRY_PROXY_TTL: 168h)
  • Can configure HTTPS certificates (via certbot)

8.30 - Misc Templates

8.31 - demo/el

Configuration template optimized for Enterprise Linux (RHEL/Rocky/Alma)

The demo/el configuration template is optimized for Enterprise Linux family distributions (RHEL, Rocky Linux, Alma Linux, Oracle Linux).


Overview

  • Config Name: demo/el
  • Node Count: Single node
  • Description: Enterprise Linux optimized configuration template
  • OS Distro: el8, el9, el10
  • OS Arch: x86_64, aarch64
  • Related: meta, demo/debian

Usage:

./configure -c demo/el [-i <primary_ip>]

Content

Source: pigsty/conf/demo/el.yml

---
#==============================================================#
# File      :   el.yml
# Desc      :   Default parameters for EL System in Pigsty
# Ctime     :   2020-05-22
# Mtime     :   2025-12-27
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


#==============================================================#
#                        Sandbox (4-node)                      #
#==============================================================#
# admin user : vagrant  (nopass ssh & sudo already set)        #
# 1.  meta    :    10.10.10.10     (2 Core | 4GB)    pg-meta   #
# 2.  node-1  :    10.10.10.11     (1 Core | 1GB)    pg-test-1 #
# 3.  node-2  :    10.10.10.12     (1 Core | 1GB)    pg-test-2 #
# 4.  node-3  :    10.10.10.13     (1 Core | 1GB)    pg-test-3 #
# (replace these ip if your 4-node env have different ip addr) #
# VIP 2: (l2 vip is available inside same LAN )                #
#     pg-meta --->  10.10.10.2 ---> 10.10.10.10                #
#     pg-test --->  10.10.10.3 ---> 10.10.10.1{1,2,3}          #
#==============================================================#


all:

  ##################################################################
  #                            CLUSTERS                            #
  ##################################################################
  # meta nodes, nodes, pgsql, redis, pgsql clusters are defined as
  # k:v pair inside `all.children`. Where the key is cluster name
  # and value is cluster definition consist of two parts:
  # `hosts`: cluster members ip and instance level variables
  # `vars` : cluster level variables
  ##################################################################
  children:                                 # groups definition

    # infra cluster for proxy, monitor, alert, etc..
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

    # etcd cluster for ha postgres
    etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # minio cluster, s3 compatible object storage
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    #----------------------------------#
    # pgsql cluster: pg-meta (CMDB)    #
    #----------------------------------#
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary , pg_offline_query: true } }
      vars:
        pg_cluster: pg-meta

        # define business databases here: https://doc.pgsty.com/pgsql/db
        pg_databases:                       # define business databases on this cluster, array of database definition
          - name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
            #state: create                  # optional, create|absent|recreate, create by default
            baseline: cmdb.sql              # optional, database sql baseline path, (relative path among ansible search path, e.g: files/)
            schemas: [pigsty]               # optional, additional schemas to be created, array of schema names
            extensions:                     # optional, additional extensions to be installed: array of `{name[,schema]}`
              - { name: vector }            # install pgvector extension on this database by default
            comment: pigsty meta database   # optional, comment string for this database
            #pgbouncer: true                # optional, add this database to pgbouncer database list? true by default
            #owner: postgres                # optional, database owner, current user if not specified
            #template: template1            # optional, which template to use, template1 by default
            #strategy: FILE_COPY            # optional, clone strategy: FILE_COPY or WAL_LOG (PG15+), default to PG's default
            #encoding: UTF8                 # optional, inherited from template / cluster if not defined (UTF8)
            #locale: C                      # optional, inherited from template / cluster if not defined (C)
            #lc_collate: C                  # optional, inherited from template / cluster if not defined (C)
            #lc_ctype: C                    # optional, inherited from template / cluster if not defined (C)
            #locale_provider: libc          # optional, locale provider: libc, icu, builtin (PG15+)
            #icu_locale: en-US              # optional, icu locale for icu locale provider (PG15+)
            #icu_rules: ''                  # optional, icu rules for icu locale provider (PG16+)
            #builtin_locale: C.UTF-8        # optional, builtin locale for builtin locale provider (PG17+)
            #tablespace: pg_default         # optional, default tablespace, pg_default by default
            #is_template: false             # optional, mark database as template, allowing clone by any user with CREATEDB privilege
            #allowconn: true                # optional, allow connection, true by default. false will disable connect at all
            #revokeconn: false              # optional, revoke public connection privilege. false by default. (leave connect with grant option to owner)
            #register_datasource: true      # optional, register this database to grafana datasources? true by default
            #connlimit: -1                  # optional, database connection limit, default -1 disable limit
            #pool_auth_user: dbuser_meta    # optional, all connection to this pgbouncer database will be authenticated by this user
            #pool_mode: transaction         # optional, pgbouncer pool mode at database level, default transaction
            #pool_size: 64                  # optional, pgbouncer pool size at database level, default 64
            #pool_size_reserve: 32          # optional, pgbouncer pool size reserve at database level, default 32
            #pool_size_min: 0               # optional, pgbouncer pool size min at database level, default 0
            #pool_max_db_conn: 100          # optional, max database connections at database level, default 100
          #- { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
          #- { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
          #- { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
          #- { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
          #- { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }

        # define business users here: https://doc.pgsty.com/pgsql/user
        pg_users:                           # define business users/roles on this cluster, array of user definition
          - name: dbuser_meta               # REQUIRED, `name` is the only mandatory field of a user definition
            password: DBUser.Meta           # optional, password, can be a scram-sha-256 hash string or plain text
            #login: true                     # optional, can log in, true by default  (new biz ROLE should be false)
            #superuser: false                # optional, is superuser? false by default
            #createdb: false                 # optional, can create database? false by default
            #createrole: false               # optional, can create role? false by default
            #inherit: true                   # optional, can this role use inherited privileges? true by default
            #replication: false              # optional, can this role do replication? false by default
            #bypassrls: false                # optional, can this role bypass row level security? false by default
            #pgbouncer: true                 # optional, add this user to pgbouncer user-list? false by default (production user should be true explicitly)
            #connlimit: -1                   # optional, user connection limit, default -1 disable limit
            #expire_in: 3650                 # optional, now + n days when this role is expired (OVERWRITE expire_at)
            #expire_at: '2030-12-31'         # optional, YYYY-MM-DD 'timestamp' when this role is expired  (OVERWRITTEN by expire_in)
            #comment: pigsty admin user      # optional, comment string for this user/role
            #roles: [dbrole_admin]           # optional, belonged roles. default roles are: dbrole_{admin,readonly,readwrite,offline}
            #parameters: {}                  # optional, role level parameters with `ALTER ROLE SET`
            #pool_mode: transaction          # optional, pgbouncer pool mode at user level, transaction by default
            #pool_connlimit: -1              # optional, max database connections at user level, default -1 disable limit
          - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly], comment: read-only viewer for meta database}
          #- {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database   }
          #- {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database  }
          #- {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service      }
          #- {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service    }

        # define business service here: https://doc.pgsty.com/pgsql/service
        pg_services:                        # extra services in addition to pg_default_services, array of service definition
          # standby service will route {ip|name}:5435 to sync replica's pgbouncer (5435->6432 standby)
          - name: standby                   # required, service name, the actual svc name will be prefixed with `pg_cluster`, e.g: pg-meta-standby
            port: 5435                      # required, service exposed port (work as kubernetes service node port mode)
            ip: "*"                         # optional, service bind ip address, `*` for all ip by default
            selector: "[]"                  # required, service member selector, use JMESPath to filter inventory
            dest: default                   # optional, destination port, default|postgres|pgbouncer|<port_number>, 'default' by default
            check: /sync                    # optional, health check url path, / by default
            backup: "[? pg_role == `primary`]"  # backup server selector
            maxconn: 3000                   # optional, max allowed front-end connection
            balance: roundrobin             # optional, haproxy load balance algorithm (roundrobin by default, other: leastconn)
            options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'

        # define pg extensions: https://doc.pgsty.com/pgsql/extension
        pg_libs: 'pg_stat_statements, auto_explain' # add timescaledb to shared_preload_libraries
        #pg_extensions: [] # extensions to be installed on this cluster

        # define HBA rules here: https://doc.pgsty.com/pgsql/hba
        pg_hba_rules:
          - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}

        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24
        pg_vip_interface: eth1

        node_crontab:  # make a full backup 1 am everyday
          - '00 01 * * * postgres /pg/bin/pg-backup full'

    #----------------------------------#
    # pgsql cluster: pg-test (3 nodes) #
    #----------------------------------#
    # pg-test --->  10.10.10.3 ---> 10.10.10.1{1,2,3}
    pg-test:                          # define the new 3-node cluster pg-test
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }   # primary instance, leader of cluster
        10.10.10.12: { pg_seq: 2, pg_role: replica }   # replica instance, follower of leader
        10.10.10.13: { pg_seq: 3, pg_role: replica, pg_offline_query: true } # replica with offline access
      vars:
        pg_cluster: pg-test           # define pgsql cluster name
        pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
        pg_databases: [{ name: test }] # create a database and user named 'test'
        node_tune: tiny
        pg_conf: tiny.yml
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.3/24
        pg_vip_interface: eth1
        node_crontab:  # make a full backup on monday 1am, and an incremental backup during weekdays
          - '00 01 * * 1 postgres /pg/bin/pg-backup full'
          - '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'

    #----------------------------------#
    # redis ms, sentinel, native cluster
    #----------------------------------#
    redis-ms: # redis classic primary & replica
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

    redis-meta: # redis sentinel x 3
      hosts: { 10.10.10.11: { redis_node: 1 , redis_instances: { 26379: { } ,26380: { } ,26381: { } } } }
      vars:
        redis_cluster: redis-meta
        redis_password: 'redis.meta'
        redis_mode: sentinel
        redis_max_memory: 16MB
        redis_sentinel_monitor: # primary list for redis sentinel, use cls as name, primary ip:port
          - { name: redis-ms, host: 10.10.10.10, port: 6379 ,password: redis.ms, quorum: 2 }

    redis-test: # redis native cluster: 3m x 3s
      hosts:
        10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
        10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
      vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }


  ####################################################################
  #                             VARS                                 #
  ####################################################################
  vars:                               # global variables


    #================================================================#
    #                         VARS: INFRA                            #
    #================================================================#

    #-----------------------------------------------------------------
    # META
    #-----------------------------------------------------------------
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    language: en                      # default language: en, zh
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]

    #-----------------------------------------------------------------
    # CA
    #-----------------------------------------------------------------
    ca_create: true                   # create ca if not exists? or just abort
    ca_cn: pigsty-ca                  # ca common name, fixed as pigsty-ca
    cert_validity: 7300d              # cert validity, 20 years by default

    #-----------------------------------------------------------------
    # INFRA_IDENTITY
    #-----------------------------------------------------------------
    #infra_seq: 1                     # infra node identity, explicitly required
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name
    infra_data: /data/infra           # default data path for infrastructure data

    #-----------------------------------------------------------------
    # REPO
    #-----------------------------------------------------------------
    repo_enabled: true                # create a yum repo on this infra node?
    repo_home: /www                   # repo home dir, `/www` by default
    repo_name: pigsty                 # repo name, pigsty by default
    repo_endpoint: http://${admin_ip}:80 # access point to this repo by domain or ip:port
    repo_remove: true                 # remove existing upstream repo
    repo_modules: infra,node,pgsql    # which repo modules are installed in repo_upstream
    repo_upstream:                    # where to download
      - { name: pigsty-local   ,description: 'Pigsty Local'       ,module: local   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://${admin_ip}/pigsty'  }} # used by intranet nodes
      - { name: pigsty-infra   ,description: 'Pigsty INFRA'       ,module: infra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/yum/infra/$basearch' ,china: 'https://repo.pigsty.cc/yum/infra/$basearch' }}
      - { name: pigsty-pgsql   ,description: 'Pigsty PGSQL'       ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/yum/pgsql/el$releasever.$basearch' ,china: 'https://repo.pigsty.cc/yum/pgsql/el$releasever.$basearch' }}
      - { name: nginx          ,description: 'Nginx Repo'         ,module: infra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://nginx.org/packages/rhel/$releasever/$basearch/' }}
      - { name: docker-ce      ,description: 'Docker CE'          ,module: infra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.docker.com/linux/centos/$releasever/$basearch/stable'    ,china: 'https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/$basearch/stable' ,europe: 'https://mirrors.xtom.de/docker-ce/linux/centos/$releasever/$basearch/stable' }}
      - { name: baseos         ,description: 'EL 8+ BaseOS'       ,module: node    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/BaseOS/$basearch/os/'     ,china: 'https://mirrors.aliyun.com/rockylinux/$releasever/BaseOS/$basearch/os/'         ,europe: 'https://mirrors.xtom.de/rocky/$releasever/BaseOS/$basearch/os/'     }}
      - { name: appstream      ,description: 'EL 8+ AppStream'    ,module: node    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/AppStream/$basearch/os/'  ,china: 'https://mirrors.aliyun.com/rockylinux/$releasever/AppStream/$basearch/os/'      ,europe: 'https://mirrors.xtom.de/rocky/$releasever/AppStream/$basearch/os/'  }}
      - { name: extras         ,description: 'EL 8+ Extras'       ,module: node    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/extras/$basearch/os/'     ,china: 'https://mirrors.aliyun.com/rockylinux/$releasever/extras/$basearch/os/'         ,europe: 'https://mirrors.xtom.de/rocky/$releasever/extras/$basearch/os/'     }}
      - { name: powertools     ,description: 'EL 8 PowerTools'    ,module: node    ,releases: [8     ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/PowerTools/$basearch/os/' ,china: 'https://mirrors.aliyun.com/rockylinux/$releasever/PowerTools/$basearch/os/'     ,europe: 'https://mirrors.xtom.de/rocky/$releasever/PowerTools/$basearch/os/' }}
      - { name: crb            ,description: 'EL 9 CRB'           ,module: node    ,releases: [  9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/CRB/$basearch/os/'        ,china: 'https://mirrors.aliyun.com/rockylinux/$releasever/CRB/$basearch/os/'            ,europe: 'https://mirrors.xtom.de/rocky/$releasever/CRB/$basearch/os/'        }}
      - { name: epel           ,description: 'EL 8+ EPEL'         ,module: node    ,releases: [8,9   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://mirrors.edge.kernel.org/fedora-epel/$releasever/Everything/$basearch/' ,china: 'https://mirrors.aliyun.com/epel/$releasever/Everything/$basearch/'         ,europe: 'https://mirrors.xtom.de/epel/$releasever/Everything/$basearch/'     }}
      - { name: epel           ,description: 'EL 10 EPEL'         ,module: node    ,releases: [    10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://mirrors.edge.kernel.org/fedora-epel/$releasever.0/Everything/$basearch/' ,china: 'https://mirrors.aliyun.com/epel/$releasever.0/Everything/$basearch/'     ,europe: 'https://mirrors.xtom.de/epel/$releasever.0/Everything/$basearch/'   }}
      - { name: pgdg-common    ,description: 'PostgreSQL Common'  ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/common/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/common/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/common/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg-el8fix    ,description: 'PostgreSQL EL8FIX'  ,module: pgsql   ,releases: [8     ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/common/pgdg-centos8-sysupdates/redhat/rhel-8-$basearch/'  ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/common/pgdg-centos8-sysupdates/redhat/rhel-8-$basearch/'  ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/common/pgdg-centos8-sysupdates/redhat/rhel-8-$basearch/'  }}
      - { name: pgdg-el9fix    ,description: 'PostgreSQL EL9FIX'  ,module: pgsql   ,releases: [  9   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/common/pgdg-rocky9-sysupdates/redhat/rhel-9-$basearch/'   ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/common/pgdg-rocky9-sysupdates/redhat/rhel-9-$basearch/'   ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/common/pgdg-rocky9-sysupdates/redhat/rhel-9-$basearch/'   }}
      - { name: pgdg-el10fix   ,description: 'PostgreSQL EL10FIX' ,module: pgsql   ,releases: [    10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/common/pgdg-rocky10-sysupdates/redhat/rhel-10-$basearch/' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/common/pgdg-rocky10-sysupdates/redhat/rhel-10-$basearch/' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/common/pgdg-rocky10-sysupdates/redhat/rhel-10-$basearch/' }}
      - { name: pgdg13         ,description: 'PostgreSQL 13'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/13/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/13/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/13/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg14         ,description: 'PostgreSQL 14'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/14/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/14/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/14/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg15         ,description: 'PostgreSQL 15'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/15/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/15/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/15/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg16         ,description: 'PostgreSQL 16'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/16/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/16/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/16/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg17         ,description: 'PostgreSQL 17'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/17/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/17/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/17/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg18         ,description: 'PostgreSQL 18'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/18/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/18/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/18/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg-beta      ,description: 'PostgreSQL Testing' ,module: beta    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  }}
      - { name: pgdg-extras    ,description: 'PostgreSQL Extra'   ,module: extra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/extras/redhat/rhel-$releasever-$basearch'      ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/extras/redhat/rhel-$releasever-$basearch'      ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/extras/redhat/rhel-$releasever-$basearch'      }}
      - { name: pgdg13-nonfree ,description: 'PostgreSQL 13+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/13/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/non-free/13/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/13/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg14-nonfree ,description: 'PostgreSQL 14+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/14/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/non-free/14/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/14/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg15-nonfree ,description: 'PostgreSQL 15+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/15/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/non-free/15/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/15/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg16-nonfree ,description: 'PostgreSQL 16+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/16/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/non-free/16/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/16/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg17-nonfree ,description: 'PostgreSQL 17+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/17/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/non-free/17/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/17/redhat/rhel-$releasever-$basearch' }}
      - { name: pgdg18-nonfree ,description: 'PostgreSQL 18+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/18/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/non-free/18/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/18/redhat/rhel-$releasever-$basearch' }}
      - { name: timescaledb    ,description: 'TimescaleDB'        ,module: extra   ,releases: [8,9   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packagecloud.io/timescale/timescaledb/el/$releasever/$basearch'  }}
      - { name: percona        ,description: 'Percona TDE'        ,module: percona ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/yum/percona/el$releasever.$basearch' ,china: 'https://repo.pigsty.cc/yum/percona/el$releasever.$basearch' ,origin: 'http://repo.percona.com/ppg-18.1/yum/release/$releasever/RPMS/$basearch'  }}
      - { name: wiltondb       ,description: 'WiltonDB'           ,module: mssql   ,releases: [8,9   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/yum/mssql/el$releasever.$basearch', china: 'https://repo.pigsty.cc/yum/mssql/el$releasever.$basearch' , origin: 'https://download.copr.fedorainfracloud.org/results/wiltondb/wiltondb/epel-$releasever-$basearch/' }}
      - { name: groonga        ,description: 'Groonga'            ,module: groonga ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.groonga.org/almalinux/$releasever/$basearch/' }}
      - { name: mysql          ,description: 'MySQL'              ,module: mysql   ,releases: [8,9   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.mysql.com/yum/mysql-8.4-community/el/$releasever/$basearch/' }}
      - { name: mongo          ,description: 'MongoDB'            ,module: mongo   ,releases: [8,9   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/8.0/$basearch/' ,china: 'https://mirrors.aliyun.com/mongodb/yum/redhat/$releasever/mongodb-org/8.0/$basearch/' }}
      - { name: redis          ,description: 'Redis'              ,module: redis   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://rpmfind.net/linux/remi/enterprise/$releasever/redis72/$basearch/' }}
      - { name: grafana        ,description: 'Grafana'            ,module: grafana ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://rpm.grafana.com', china: 'https://mirrors.aliyun.com/grafana/yum/' }}
      - { name: kubernetes     ,description: 'Kubernetes'         ,module: kube    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://pkgs.k8s.io/core:/stable:/v1.33/rpm/', china: 'https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.33/rpm/' }}
      - { name: gitlab-ee      ,description: 'Gitlab EE'          ,module: gitlab  ,releases: [8,9   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ee/el/$releasever/$basearch' }}
      - { name: gitlab-ce      ,description: 'Gitlab CE'          ,module: gitlab  ,releases: [8,9   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ce/el/$releasever/$basearch' }}
      - { name: clickhouse     ,description: 'ClickHouse'         ,module: click   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.clickhouse.com/rpm/stable/', china: 'https://mirrors.aliyun.com/clickhouse/rpm/stable/' }}

    repo_packages: [ node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-utility, extra-modules ]
    repo_extra_packages: [ pgsql-main ]
    repo_url_packages: []

    #-----------------------------------------------------------------
    # INFRA_PACKAGE
    #-----------------------------------------------------------------
    infra_packages:                   # packages to be installed on infra nodes
      - grafana,grafana-plugins,grafana-victorialogs-ds,grafana-victoriametrics-ds,victoria-metrics,victoria-logs,victoria-traces,vmutils,vlogscli,alertmanager
      - node_exporter,blackbox_exporter,nginx_exporter,pg_exporter,pev2,nginx,dnsmasq,ansible,etcd,python3-requests,redis,mcli,restic,certbot,python3-certbot-nginx
    infra_packages_pip: ''            # pip installed packages for infra nodes

    #-----------------------------------------------------------------
    # NGINX
    #-----------------------------------------------------------------
    nginx_enabled: true               # enable nginx on this infra node?
    nginx_clean: false                # clean existing nginx config during init?
    nginx_exporter_enabled: true      # enable nginx_exporter on this infra node?
    nginx_exporter_port: 9113         # nginx_exporter listen port, 9113 by default
    nginx_sslmode: enable             # nginx ssl mode? disable,enable,enforce
    nginx_cert_validity: 397d         # nginx self-signed cert validity, 397d by default
    nginx_home: /www                  # nginx content dir, `/www` by default (soft link to nginx_data)
    nginx_data: /data/nginx           # nginx actual data dir, /data/nginx by default
    nginx_users: { admin : pigsty }   # nginx basic auth users: name and pass dict
    nginx_port: 80                    # nginx listen port, 80 by default
    nginx_ssl_port: 443               # nginx ssl listen port, 443 by default
    certbot_sign: false               # sign nginx cert with certbot during setup?
    certbot_email: [email protected]     # certbot email address, used for free ssl
    certbot_options: ''               # certbot extra options

    #-----------------------------------------------------------------
    # DNS
    #-----------------------------------------------------------------
    dns_enabled: true                 # setup dnsmasq on this infra node?
    dns_port: 53                      # dns server listen port, 53 by default
    dns_records:                      # dynamic dns records resolved by dnsmasq
      - "${admin_ip} i.pigsty"
      - "${admin_ip} m.pigsty supa.pigsty api.pigsty adm.pigsty cli.pigsty ddl.pigsty"

    #-----------------------------------------------------------------
    # VICTORIA
    #-----------------------------------------------------------------
    vmetrics_enabled: true            # enable victoria-metrics on this infra node?
    vmetrics_clean: false             # whether clean existing victoria metrics data during init?
    vmetrics_port: 8428               # victoria-metrics listen port, 8428 by default
    vmetrics_scrape_interval: 10s     # victoria global scrape interval, 10s by default
    vmetrics_scrape_timeout: 8s       # victoria global scrape timeout, 8s by default
    vmetrics_options: >-
      -retentionPeriod=15d
      -promscrape.fileSDCheckInterval=5s
    vlogs_enabled: true               # enable victoria-logs on this infra node?
    vlogs_clean: false                # clean victoria-logs data during init?
    vlogs_port: 9428                  # victoria-logs listen port, 9428 by default
    vlogs_options: >-
      -retentionPeriod=15d
      -retention.maxDiskSpaceUsageBytes=50GiB
      -insert.maxLineSizeBytes=1MB
      -search.maxQueryDuration=120s
    vtraces_enabled: true             # enable victoria-traces on this infra node?
    vtraces_clean: false                # clean victoria-trace data during inti?
    vtraces_port: 10428               # victoria-traces listen port, 10428 by default
    vtraces_options: >-
      -retentionPeriod=15d
      -retention.maxDiskSpaceUsageBytes=50GiB
    vmalert_enabled: true             # enable vmalert on this infra node?
    vmalert_port: 8880                # vmalert listen port, 8880 by default
    vmalert_options: ''              # vmalert extra server options

    #-----------------------------------------------------------------
    # PROMETHEUS
    #-----------------------------------------------------------------
    blackbox_enabled: true            # setup blackbox_exporter on this infra node?
    blackbox_port: 9115               # blackbox_exporter listen port, 9115 by default
    blackbox_options: ''              # blackbox_exporter extra server options
    alertmanager_enabled: true        # setup alertmanager on this infra node?
    alertmanager_port: 9059           # alertmanager listen port, 9059 by default
    alertmanager_options: ''          # alertmanager extra server options
    exporter_metrics_path: /metrics   # exporter metric path, `/metrics` by default

    #-----------------------------------------------------------------
    # GRAFANA
    #-----------------------------------------------------------------
    grafana_enabled: true             # enable grafana on this infra node?
    grafana_port: 3000                # default listen port for grafana
    grafana_clean: false              # clean grafana data during init?
    grafana_admin_username: admin     # grafana admin username, `admin` by default
    grafana_admin_password: pigsty    # grafana admin password, `pigsty` by default
    grafana_auth_proxy: false         # enable grafana auth proxy?
    grafana_pgurl: ''                 # external postgres database url for grafana if given
    grafana_view_password: DBUser.Viewer # password for grafana meta pg datasource


    #================================================================#
    #                         VARS: NODE                             #
    #================================================================#

    #-----------------------------------------------------------------
    # NODE_IDENTITY
    #-----------------------------------------------------------------
    #nodename:           # [INSTANCE] # node instance identity, use hostname if missing, optional
    node_cluster: nodes   # [CLUSTER] # node cluster identity, use 'nodes' if missing, optional
    nodename_overwrite: true          # overwrite node's hostname with nodename?
    nodename_exchange: false          # exchange nodename among play hosts?
    node_id_from_pg: true             # use postgres identity as node identity if applicable?

    #-----------------------------------------------------------------
    # NODE_DNS
    #-----------------------------------------------------------------
    node_write_etc_hosts: true        # modify `/etc/hosts` on target node?
    node_default_etc_hosts:           # static dns records in `/etc/hosts`
      - "${admin_ip} i.pigsty"
    node_etc_hosts: []                # extra static dns records in `/etc/hosts`
    node_dns_method: add              # how to handle dns servers: add,none,overwrite
    node_dns_servers: ['${admin_ip}'] # dynamic nameserver in `/etc/resolv.conf`
    node_dns_options:                 # dns resolv options in `/etc/resolv.conf`
      - options single-request-reopen timeout:1

    #-----------------------------------------------------------------
    # NODE_PACKAGE
    #-----------------------------------------------------------------
    node_repo_modules: local          # upstream repo to be added on node, local by default
    node_repo_remove: true            # remove existing repo on node?
    node_packages: [openssh-server]   # packages to be installed current nodes with latest version
    node_default_packages:            # default packages to be installed on all nodes
      - lz4,unzip,bzip2,pv,jq,git,ncdu,make,patch,bash,lsof,wget,uuid,tuned,nvme-cli,numactl,sysstat,iotop,htop,rsync,tcpdump
      - python3,python3-pip,socat,lrzsz,net-tools,ipvsadm,telnet,ca-certificates,openssl,keepalived,etcd,haproxy,chrony,pig
      - zlib,yum,audit,bind-utils,readline,vim-minimal,node_exporter,grubby,openssh-server,openssh-clients,chkconfig,vector

    #-----------------------------------------------------------------
    # NODE_SEC
    #-----------------------------------------------------------------
    node_selinux_mode: permissive     # set selinux mode: enforcing,permissive,disabled
    node_firewall_mode: zone          # firewall mode: off, none, zone, zone by default
    node_firewall_intranet:           # which intranet cidr considered as internal network
      - 10.0.0.0/8
      - 192.168.0.0/16
      - 172.16.0.0/12
    node_firewall_public_port:        # expose these ports to public network in (zone, strict) mode
      - 22                            # enable ssh access
      - 80                            # enable http access
      - 443                           # enable https access
      - 5432                          # enable postgresql access (think twice before exposing it!)

    #-----------------------------------------------------------------
    # NODE_TUNE
    #-----------------------------------------------------------------
    node_disable_numa: false          # disable node numa, reboot required
    node_disable_swap: false          # disable node swap, use with caution
    node_static_network: true         # preserve dns resolver settings after reboot
    node_disk_prefetch: false         # setup disk prefetch on HDD to increase performance
    node_kernel_modules: [ softdog, ip_vs, ip_vs_rr, ip_vs_wrr, ip_vs_sh ]
    node_hugepage_count: 0            # number of 2MB hugepage, take precedence over ratio
    node_hugepage_ratio: 0            # node mem hugepage ratio, 0 disable it by default
    node_overcommit_ratio: 0          # node mem overcommit ratio, 0 disable it by default
    node_tune: oltp                   # node tuned profile: none,oltp,olap,crit,tiny
    node_sysctl_params: { }           # sysctl parameters in k:v format in addition to tuned

    #-----------------------------------------------------------------
    # NODE_ADMIN
    #-----------------------------------------------------------------
    node_data: /data                  # node main data directory, `/data` by default
    node_admin_enabled: true          # create a admin user on target node?
    node_admin_uid: 88                # uid and gid for node admin user
    node_admin_username: dba          # name of node admin user, `dba` by default
    node_admin_sudo: nopass           # admin sudo privilege, all,nopass. nopass by default
    node_admin_ssh_exchange: true     # exchange admin ssh key among node cluster
    node_admin_pk_current: true       # add current user's ssh pk to admin authorized_keys
    node_admin_pk_list: []            # ssh public keys to be added to admin user
    node_aliases: {}                  # extra shell aliases to be added, k:v dict

    #-----------------------------------------------------------------
    # NODE_TIME
    #-----------------------------------------------------------------
    node_timezone: ''                 # setup node timezone, empty string to skip
    node_ntp_enabled: true            # enable chronyd time sync service?
    node_ntp_servers:                 # ntp servers in `/etc/chrony.conf`
      - pool pool.ntp.org iburst
    node_crontab_overwrite: true      # overwrite or append to `/etc/crontab`?
    node_crontab: [ ]                 # crontab entries in `/etc/crontab`

    #-----------------------------------------------------------------
    # NODE_VIP
    #-----------------------------------------------------------------
    vip_enabled: false                # enable vip on this node cluster?
    # vip_address:         [IDENTITY] # node vip address in ipv4 format, required if vip is enabled
    # vip_vrid:            [IDENTITY] # required, integer, 1-254, should be unique among same VLAN
    vip_role: backup                  # optional, `master|backup`, backup by default, use as init role
    vip_preempt: false                # optional, `true/false`, false by default, enable vip preemption
    vip_interface: eth0               # node vip network interface to listen, `eth0` by default
    vip_dns_suffix: ''                # node vip dns name suffix, empty string by default
    vip_exporter_port: 9650           # keepalived exporter listen port, 9650 by default

    #-----------------------------------------------------------------
    # HAPROXY
    #-----------------------------------------------------------------
    haproxy_enabled: true             # enable haproxy on this node?
    haproxy_clean: false              # cleanup all existing haproxy config?
    haproxy_reload: true              # reload haproxy after config?
    haproxy_auth_enabled: true        # enable authentication for haproxy admin page
    haproxy_admin_username: admin     # haproxy admin username, `admin` by default
    haproxy_admin_password: pigsty    # haproxy admin password, `pigsty` by default
    haproxy_exporter_port: 9101       # haproxy admin/exporter port, 9101 by default
    haproxy_client_timeout: 24h       # client side connection timeout, 24h by default
    haproxy_server_timeout: 24h       # server side connection timeout, 24h by default
    haproxy_services: []              # list of haproxy service to be exposed on node

    #-----------------------------------------------------------------
    # NODE_EXPORTER
    #-----------------------------------------------------------------
    node_exporter_enabled: true       # setup node_exporter on this node?
    node_exporter_port: 9100          # node exporter listen port, 9100 by default
    node_exporter_options: '--no-collector.softnet --no-collector.nvme --collector.tcpstat --collector.processes'

    #-----------------------------------------------------------------
    # VECTOR
    #-----------------------------------------------------------------
    vector_enabled: true              # enable vector log collector?
    vector_clean: false               # purge vector data dir during init?
    vector_data: /data/vector         # vector data dir, /data/vector by default
    vector_port: 9598                 # vector metrics port, 9598 by default
    vector_read_from: beginning       # vector read from beginning or end
    vector_log_endpoint: [ infra ]    # if defined, sending vector log to this endpoint.


    #================================================================#
    #                        VARS: DOCKER                            #
    #================================================================#
    docker_enabled: false             # enable docker on this node?
    docker_data: /data/docker         # docker data directory, /data/docker by default
    docker_storage_driver: overlay2   # docker storage driver, can be zfs, btrfs
    docker_cgroups_driver: systemd    # docker cgroup fs driver: cgroupfs,systemd
    docker_registry_mirrors: []       # docker registry mirror list
    docker_exporter_port: 9323        # docker metrics exporter port, 9323 by default
    docker_image: []                  # docker image to be pulled after bootstrap
    docker_image_cache: /tmp/docker/*.tgz # docker image cache glob pattern

    #================================================================#
    #                         VARS: ETCD                             #
    #================================================================#
    #etcd_seq: 1                      # etcd instance identifier, explicitly required
    etcd_cluster: etcd                # etcd cluster & group name, etcd by default
    etcd_safeguard: false             # prevent purging running etcd instance?
    etcd_clean: true                  # purging existing etcd during initialization?
    etcd_data: /data/etcd             # etcd data directory, /data/etcd by default
    etcd_port: 2379                   # etcd client port, 2379 by default
    etcd_peer_port: 2380              # etcd peer port, 2380 by default
    etcd_init: new                    # etcd initial cluster state, new or existing
    etcd_election_timeout: 1000       # etcd election timeout, 1000ms by default
    etcd_heartbeat_interval: 100      # etcd heartbeat interval, 100ms by default
    etcd_root_password: Etcd.Root     # etcd root password for RBAC, change it!


    #================================================================#
    #                         VARS: MINIO                            #
    #================================================================#
    #minio_seq: 1                     # minio instance identifier, REQUIRED
    minio_cluster: minio              # minio cluster identifier, REQUIRED
    minio_clean: false                # cleanup minio during init?, false by default
    minio_user: minio                 # minio os user, `minio` by default
    minio_https: true                 # use https for minio, true by default
    minio_node: '${minio_cluster}-${minio_seq}.pigsty' # minio node name pattern
    minio_data: '/data/minio'         # minio data dir(s), use {x...y} to specify multi drivers
    #minio_volumes:                   # minio data volumes, override defaults if specified
    minio_domain: sss.pigsty          # minio external domain name, `sss.pigsty` by default
    minio_port: 9000                  # minio service port, 9000 by default
    minio_admin_port: 9001            # minio console port, 9001 by default
    minio_access_key: minioadmin      # root access key, `minioadmin` by default
    minio_secret_key: S3User.MinIO    # root secret key, `S3User.MinIO` by default
    minio_extra_vars: ''              # extra environment variables
    minio_provision: true             # run minio provisioning tasks?
    minio_alias: sss                  # alias name for local minio deployment
    #minio_endpoint: https://sss.pigsty:9000 # if not specified, overwritten by defaults
    minio_buckets:                    # list of minio bucket to be created
      - { name: pgsql }
      - { name: meta ,versioning: true }
      - { name: data }
    minio_users:                      # list of minio user to be created
      - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
      - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
      - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }


    #================================================================#
    #                         VARS: REDIS                            #
    #================================================================#
    #redis_cluster:        <CLUSTER> # redis cluster name, required identity parameter
    #redis_node: 1            <NODE> # redis node sequence number, node int id required
    #redis_instances: {}      <NODE> # redis instances definition on this redis node
    redis_fs_main: /data              # redis main data mountpoint, `/data` by default
    redis_exporter_enabled: true      # install redis exporter on redis nodes?
    redis_exporter_port: 9121         # redis exporter listen port, 9121 by default
    redis_exporter_options: ''        # cli args and extra options for redis exporter
    redis_safeguard: false            # prevent purging running redis instance?
    redis_clean: true                 # purging existing redis during init?
    redis_rmdata: true                # remove redis data when purging redis server?
    redis_mode: standalone            # redis mode: standalone,cluster,sentinel
    redis_conf: redis.conf            # redis config template path, except sentinel
    redis_bind_address: '0.0.0.0'     # redis bind address, empty string will use host ip
    redis_max_memory: 1GB             # max memory used by each redis instance
    redis_mem_policy: allkeys-lru     # redis memory eviction policy
    redis_password: ''                # redis password, empty string will disable password
    redis_rdb_save: ['1200 1']        # redis rdb save directives, disable with empty list
    redis_aof_enabled: false          # enable redis append only file?
    redis_rename_commands: {}         # rename redis dangerous commands
    redis_cluster_replicas: 1         # replica number for one master in redis cluster
    redis_sentinel_monitor: []        # sentinel master list, works on sentinel cluster only


    #================================================================#
    #                         VARS: PGSQL                            #
    #================================================================#

    #-----------------------------------------------------------------
    # PG_IDENTITY
    #-----------------------------------------------------------------
    pg_mode: pgsql          #CLUSTER  # pgsql cluster mode: pgsql,citus,gpsql,mssql,mysql,ivory,polar
    # pg_cluster:           #CLUSTER  # pgsql cluster name, required identity parameter
    # pg_seq: 0             #INSTANCE # pgsql instance seq number, required identity parameter
    # pg_role: replica      #INSTANCE # pgsql role, required, could be primary,replica,offline
    # pg_instances: {}      #INSTANCE # define multiple pg instances on node in `{port:ins_vars}` format
    # pg_upstream:          #INSTANCE # repl upstream ip addr for standby cluster or cascade replica
    # pg_shard:             #CLUSTER  # pgsql shard name, optional identity for sharding clusters
    # pg_group: 0           #CLUSTER  # pgsql shard index number, optional identity for sharding clusters
    # gp_role: master       #CLUSTER  # greenplum role of this cluster, could be master or segment
    pg_offline_query: false #INSTANCE # set to true to enable offline queries on this instance

    #-----------------------------------------------------------------
    # PG_BUSINESS
    #-----------------------------------------------------------------
    # postgres business object definition, overwrite in group vars
    pg_users: []                      # postgres business users
    pg_databases: []                  # postgres business databases
    pg_services: []                   # postgres business services
    pg_hba_rules: []                  # business hba rules for postgres
    pgb_hba_rules: []                 # business hba rules for pgbouncer
    # global credentials, overwrite in global vars
    pg_dbsu_password: ''              # dbsu password, empty string means no dbsu password by default
    pg_replication_username: replicator
    pg_replication_password: DBUser.Replicator
    pg_admin_username: dbuser_dba
    pg_admin_password: DBUser.DBA
    pg_monitor_username: dbuser_monitor
    pg_monitor_password: DBUser.Monitor

    #-----------------------------------------------------------------
    # PG_INSTALL
    #-----------------------------------------------------------------
    pg_dbsu: postgres                 # os dbsu name, postgres by default, better not change it
    pg_dbsu_uid: 26                   # os dbsu uid and gid, 26 for default postgres users and groups
    pg_dbsu_sudo: limit               # dbsu sudo privilege, none,limit,all,nopass. limit by default
    pg_dbsu_home: /var/lib/pgsql      # postgresql home directory, `/var/lib/pgsql` by default
    pg_dbsu_ssh_exchange: true        # exchange postgres dbsu ssh key among same pgsql cluster
    pg_version: 18                    # postgres major version to be installed, 17 by default
    pg_bin_dir: /usr/pgsql/bin        # postgres binary dir, `/usr/pgsql/bin` by default
    pg_log_dir: /pg/log/postgres      # postgres log dir, `/pg/log/postgres` by default
    pg_packages:                      # pg packages to be installed, alias can be used
      - pgsql-main pgsql-common
    pg_extensions: []                 # pg extensions to be installed, alias can be used

    #-----------------------------------------------------------------
    # PG_BOOTSTRAP
    #-----------------------------------------------------------------
    pg_data: /pg/data                 # postgres data directory, `/pg/data` by default
    pg_fs_main: /data/postgres        # postgres main data directory, `/data/postgres` by default
    pg_fs_backup: /data/backups       # postgres backup data directory, `/data/backups` by default
    pg_storage_type: SSD              # storage type for pg main data, SSD,HDD, SSD by default
    pg_dummy_filesize: 64MiB          # size of `/pg/dummy`, hold 64MB disk space for emergency use
    pg_listen: '0.0.0.0'              # postgres/pgbouncer listen addresses, comma separated list
    pg_port: 5432                     # postgres listen port, 5432 by default
    pg_localhost: /var/run/postgresql # postgres unix socket dir for localhost connection
    patroni_enabled: true             # if disabled, no postgres cluster will be created during init
    patroni_mode: default             # patroni working mode: default,pause,remove
    pg_namespace: /pg                 # top level key namespace in etcd, used by patroni & vip
    patroni_port: 8008                # patroni listen port, 8008 by default
    patroni_log_dir: /pg/log/patroni  # patroni log dir, `/pg/log/patroni` by default
    patroni_ssl_enabled: false        # secure patroni RestAPI communications with SSL?
    patroni_watchdog_mode: off        # patroni watchdog mode: automatic,required,off. off by default
    patroni_username: postgres        # patroni restapi username, `postgres` by default
    patroni_password: Patroni.API     # patroni restapi password, `Patroni.API` by default
    pg_etcd_password: ''              # etcd password for this pg cluster, '' to use pg_cluster
    pg_primary_db: postgres           # primary database name, used by citus,etc... ,postgres by default
    pg_parameters: {}                 # extra parameters in postgresql.auto.conf
    pg_files: []                      # extra files to be copied to postgres data directory (e.g. license)
    pg_conf: oltp.yml                 # config template: oltp,olap,crit,tiny. `oltp.yml` by default
    pg_max_conn: auto                 # postgres max connections, `auto` will use recommended value
    pg_shared_buffer_ratio: 0.25      # postgres shared buffers ratio, 0.25 by default, 0.1~0.4
    pg_io_method: worker              # io method for postgres, auto,fsync,worker,io_uring, worker by default
    pg_rto: 30                        # recovery time objective in seconds,  `30s` by default
    pg_rpo: 1048576                   # recovery point objective in bytes, `1MiB` at most by default
    pg_libs: 'pg_stat_statements, auto_explain'  # preloaded libraries, `pg_stat_statements,auto_explain` by default
    pg_delay: 0                       # replication apply delay for standby cluster leader
    pg_checksum: true                 # enable data checksum for postgres cluster?
    pg_encoding: UTF8                 # database cluster encoding, `UTF8` by default
    pg_locale: C                      # database cluster local, `C` by default
    pg_lc_collate: C                  # database cluster collate, `C` by default
    pg_lc_ctype: C                    # database character type, `C` by default
    #pgsodium_key: ""                 # pgsodium key, 64 hex digit, default to sha256(pg_cluster)
    #pgsodium_getkey_script: ""       # pgsodium getkey script path, pgsodium_getkey by default

    #-----------------------------------------------------------------
    # PG_PROVISION
    #-----------------------------------------------------------------
    pg_provision: true                # provision postgres cluster after bootstrap
    pg_init: pg-init                  # provision init script for cluster template, `pg-init` by default
    pg_default_roles:                 # default roles and users in postgres cluster
      - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
      - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
      - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
      - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
      - { name: postgres     ,superuser: true  ,comment: system superuser }
      - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator }
      - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
      - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }
    pg_default_privileges:            # default privileges when created by admin user
      - GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
      - GRANT SELECT     ON TABLES    TO dbrole_readonly
      - GRANT SELECT     ON SEQUENCES TO dbrole_readonly
      - GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
      - GRANT USAGE      ON SCHEMAS   TO dbrole_offline
      - GRANT SELECT     ON TABLES    TO dbrole_offline
      - GRANT SELECT     ON SEQUENCES TO dbrole_offline
      - GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
      - GRANT INSERT     ON TABLES    TO dbrole_readwrite
      - GRANT UPDATE     ON TABLES    TO dbrole_readwrite
      - GRANT DELETE     ON TABLES    TO dbrole_readwrite
      - GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
      - GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
      - GRANT TRUNCATE   ON TABLES    TO dbrole_admin
      - GRANT REFERENCES ON TABLES    TO dbrole_admin
      - GRANT TRIGGER    ON TABLES    TO dbrole_admin
      - GRANT CREATE     ON SCHEMAS   TO dbrole_admin
    pg_default_schemas: [ monitor ]   # default schemas to be created
    pg_default_extensions:            # default extensions to be created
      - { name: pg_stat_statements ,schema: monitor }
      - { name: pgstattuple        ,schema: monitor }
      - { name: pg_buffercache     ,schema: monitor }
      - { name: pageinspect        ,schema: monitor }
      - { name: pg_prewarm         ,schema: monitor }
      - { name: pg_visibility      ,schema: monitor }
      - { name: pg_freespacemap    ,schema: monitor }
      - { name: postgres_fdw       ,schema: public  }
      - { name: file_fdw           ,schema: public  }
      - { name: btree_gist         ,schema: public  }
      - { name: btree_gin          ,schema: public  }
      - { name: pg_trgm            ,schema: public  }
      - { name: intagg             ,schema: public  }
      - { name: intarray           ,schema: public  }
      - { name: pg_repack }
    pg_reload: true                   # reload postgres after hba changes
    pg_default_hba_rules:             # postgres default host-based authentication rules, order by `order`
      - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  ,order: 100}
      - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' ,order: 150}
      - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost',order: 200}
      - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' ,order: 250}
      - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' ,order: 300}
      - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' ,order: 350}
      - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password',order: 400}
      - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   ,order: 450}
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    ,order: 500}
      - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket',order: 550}
      - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     ,order: 600}
      - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet',order: 650}
    pgb_default_hba_rules:            # pgbouncer default host-based authentication rules, order by `order`
      - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident',order: 100}
      - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' ,order: 150}
      - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' ,order: 200}
      - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' ,order: 250}
      - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   ,order: 300}
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   ,order: 350}
      - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' ,order: 400}

    #-----------------------------------------------------------------
    # PG_BACKUP
    #-----------------------------------------------------------------
    pgbackrest_enabled: true          # enable pgbackrest on pgsql host?
    pgbackrest_log_dir: /pg/log/pgbackrest # pgbackrest log dir, `/pg/log/pgbackrest` by default
    pgbackrest_method: local          # pgbackrest repo method: local,minio,[user-defined...]
    pgbackrest_init_backup: true      # take a full backup after pgbackrest is initialized?
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backups when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the the last 14 days

    #-----------------------------------------------------------------
    # PG_ACCESS
    #-----------------------------------------------------------------
    pgbouncer_enabled: true           # if disabled, pgbouncer will not be launched on pgsql host
    pgbouncer_port: 6432              # pgbouncer listen port, 6432 by default
    pgbouncer_log_dir: /pg/log/pgbouncer  # pgbouncer log dir, `/pg/log/pgbouncer` by default
    pgbouncer_auth_query: false       # query postgres to retrieve unlisted business users?
    pgbouncer_poolmode: transaction   # pooling mode: transaction,session,statement, transaction by default
    pgbouncer_sslmode: disable        # pgbouncer client ssl mode, disable by default
    pgbouncer_ignore_param: [ extra_float_digits, application_name, TimeZone, DateStyle, IntervalStyle, search_path ]
    pg_weight: 100          #INSTANCE # relative load balance weight in service, 100 by default, 0-255
    pg_service_provider: ''           # dedicate haproxy node group name, or empty string for local nodes by default
    pg_default_service_dest: pgbouncer # default service destination if svc.dest='default'
    pg_default_services:              # postgres default service definitions
      - { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
      - { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
      - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
      - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}
    pg_vip_enabled: false             # enable a l2 vip for pgsql primary? false by default
    pg_vip_address: 127.0.0.1/24      # vip address in `<ipv4>/<mask>` format, require if vip is enabled
    pg_vip_interface: eth0            # vip network interface to listen, eth0 by default
    pg_dns_suffix: ''                 # pgsql dns suffix, '' by default
    pg_dns_target: auto               # auto, primary, vip, none, or ad hoc ip

    #-----------------------------------------------------------------
    # PG_MONITOR
    #-----------------------------------------------------------------
    pg_exporter_enabled: true              # enable pg_exporter on pgsql hosts?
    pg_exporter_config: pg_exporter.yml    # pg_exporter configuration file name
    pg_exporter_cache_ttls: '1,10,60,300'  # pg_exporter collector ttl stage in seconds, '1,10,60,300' by default
    pg_exporter_port: 9630                 # pg_exporter listen port, 9630 by default
    pg_exporter_params: 'sslmode=disable'  # extra url parameters for pg_exporter dsn
    pg_exporter_url: ''                    # overwrite auto-generate pg dsn if specified
    pg_exporter_auto_discovery: true       # enable auto database discovery? enabled by default
    pg_exporter_exclude_database: 'template0,template1,postgres' # csv of database that WILL NOT be monitored during auto-discovery
    pg_exporter_include_database: ''       # csv of database that WILL BE monitored during auto-discovery
    pg_exporter_connect_timeout: 200       # pg_exporter connect timeout in ms, 200 by default
    pg_exporter_options: ''                # overwrite extra options for pg_exporter
    pgbouncer_exporter_enabled: true       # enable pgbouncer_exporter on pgsql hosts?
    pgbouncer_exporter_port: 9631          # pgbouncer_exporter listen port, 9631 by default
    pgbouncer_exporter_url: ''             # overwrite auto-generate pgbouncer dsn if specified
    pgbouncer_exporter_options: ''         # overwrite extra options for pgbouncer_exporter
    pgbackrest_exporter_enabled: true      # enable pgbackrest_exporter on pgsql hosts?
    pgbackrest_exporter_port: 9854         # pgbackrest_exporter listen port, 9854 by default
    pgbackrest_exporter_options: >
      --collect.interval=120
      --log.level=info

    #-----------------------------------------------------------------
    # PG_REMOVE
    #-----------------------------------------------------------------
    pg_safeguard: false               # stop pg_remove running if pg_safeguard is enabled, false by default
    pg_rm_data: true                  # remove postgres data during remove? true by default
    pg_rm_backup: true                # remove pgbackrest backup during primary remove? true by default
    pg_rm_pkg: true                   # uninstall postgres packages during remove? true by default

...

Explanation

The demo/el template is optimized for Enterprise Linux family distributions.

Supported Distributions:

  • RHEL 8/9/10
  • Rocky Linux 8/9/10
  • Alma Linux 8/9/10
  • Oracle Linux 8/9

Key Features:

  • Uses EPEL and PGDG repositories
  • Optimized for YUM/DNF package manager
  • Supports EL-specific package names

Use Cases:

  • Enterprise production environments (RHEL/Rocky/Alma recommended)
  • Long-term support and stability requirements
  • Environments using Red Hat ecosystem

8.32 - demo/debian

Configuration template optimized for Debian/Ubuntu

The demo/debian configuration template is optimized for Debian and Ubuntu distributions.


Overview

  • Config Name: demo/debian
  • Node Count: Single node
  • Description: Debian/Ubuntu optimized configuration template
  • OS Distro: d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta, demo/el

Usage:

./configure -c demo/debian [-i <primary_ip>]

Content

Source: pigsty/conf/demo/debian.yml

---
#==============================================================#
# File      :   debian.yml
# Desc      :   Default parameters for Debian/Ubuntu in Pigsty
# Ctime     :   2020-05-22
# Mtime     :   2025-12-27
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


#==============================================================#
#                        Sandbox (4-node)                      #
#==============================================================#
# admin user : vagrant  (nopass ssh & sudo already set)        #
# 1.  meta    :    10.10.10.10     (2 Core | 4GB)    pg-meta   #
# 2.  node-1  :    10.10.10.11     (1 Core | 1GB)    pg-test-1 #
# 3.  node-2  :    10.10.10.12     (1 Core | 1GB)    pg-test-2 #
# 4.  node-3  :    10.10.10.13     (1 Core | 1GB)    pg-test-3 #
# (replace these ip if your 4-node env have different ip addr) #
# VIP 2: (l2 vip is available inside same LAN )                #
#     pg-meta --->  10.10.10.2 ---> 10.10.10.10                #
#     pg-test --->  10.10.10.3 ---> 10.10.10.1{1,2,3}          #
#==============================================================#


all:

  ##################################################################
  #                            CLUSTERS                            #
  ##################################################################
  # meta nodes, nodes, pgsql, redis, pgsql clusters are defined as
  # k:v pair inside `all.children`. Where the key is cluster name
  # and value is cluster definition consist of two parts:
  # `hosts`: cluster members ip and instance level variables
  # `vars` : cluster level variables
  ##################################################################
  children:                                 # groups definition

    # infra cluster for proxy, monitor, alert, etc..
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

    # etcd cluster for ha postgres
    etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # minio cluster, s3 compatible object storage
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    #----------------------------------#
    # pgsql cluster: pg-meta (CMDB)    #
    #----------------------------------#
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary , pg_offline_query: true } }
      vars:
        pg_cluster: pg-meta

        # define business databases here: https://doc.pgsty.com/pgsql/db
        pg_databases:                       # define business databases on this cluster, array of database definition
          - name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
            #state: create                  # optional, create|absent|recreate, create by default
            baseline: cmdb.sql              # optional, database sql baseline path, (relative path among ansible search path, e.g: files/)
            schemas: [pigsty]               # optional, additional schemas to be created, array of schema names
            extensions:                     # optional, additional extensions to be installed: array of `{name[,schema]}`
              - { name: vector }            # install pgvector extension on this database by default
            comment: pigsty meta database   # optional, comment string for this database
            #pgbouncer: true                # optional, add this database to pgbouncer database list? true by default
            #owner: postgres                # optional, database owner, current user if not specified
            #template: template1            # optional, which template to use, template1 by default
            #strategy: FILE_COPY            # optional, clone strategy: FILE_COPY or WAL_LOG (PG15+), default to PG's default
            #encoding: UTF8                 # optional, inherited from template / cluster if not defined (UTF8)
            #locale: C                      # optional, inherited from template / cluster if not defined (C)
            #lc_collate: C                  # optional, inherited from template / cluster if not defined (C)
            #lc_ctype: C                    # optional, inherited from template / cluster if not defined (C)
            #locale_provider: libc          # optional, locale provider: libc, icu, builtin (PG15+)
            #icu_locale: en-US              # optional, icu locale for icu locale provider (PG15+)
            #icu_rules: ''                  # optional, icu rules for icu locale provider (PG16+)
            #builtin_locale: C.UTF-8        # optional, builtin locale for builtin locale provider (PG17+)
            #tablespace: pg_default         # optional, default tablespace, pg_default by default
            #is_template: false             # optional, mark database as template, allowing clone by any user with CREATEDB privilege
            #allowconn: true                # optional, allow connection, true by default. false will disable connect at all
            #revokeconn: false              # optional, revoke public connection privilege. false by default. (leave connect with grant option to owner)
            #register_datasource: true      # optional, register this database to grafana datasources? true by default
            #connlimit: -1                  # optional, database connection limit, default -1 disable limit
            #pool_auth_user: dbuser_meta    # optional, all connection to this pgbouncer database will be authenticated by this user
            #pool_mode: transaction         # optional, pgbouncer pool mode at database level, default transaction
            #pool_size: 64                  # optional, pgbouncer pool size at database level, default 64
            #pool_size_reserve: 32          # optional, pgbouncer pool size reserve at database level, default 32
            #pool_size_min: 0               # optional, pgbouncer pool size min at database level, default 0
            #pool_max_db_conn: 100          # optional, max database connections at database level, default 100
          #- { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
          #- { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
          #- { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
          #- { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
          #- { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }

        # define business users here: https://doc.pgsty.com/pgsql/user
        pg_users:                           # define business users/roles on this cluster, array of user definition
          - name: dbuser_meta               # REQUIRED, `name` is the only mandatory field of a user definition
            password: DBUser.Meta           # optional, password, can be a scram-sha-256 hash string or plain text
            #login: true                     # optional, can log in, true by default  (new biz ROLE should be false)
            #superuser: false                # optional, is superuser? false by default
            #createdb: false                 # optional, can create database? false by default
            #createrole: false               # optional, can create role? false by default
            #inherit: true                   # optional, can this role use inherited privileges? true by default
            #replication: false              # optional, can this role do replication? false by default
            #bypassrls: false                # optional, can this role bypass row level security? false by default
            #pgbouncer: true                 # optional, add this user to pgbouncer user-list? false by default (production user should be true explicitly)
            #connlimit: -1                   # optional, user connection limit, default -1 disable limit
            #expire_in: 3650                 # optional, now + n days when this role is expired (OVERWRITE expire_at)
            #expire_at: '2030-12-31'         # optional, YYYY-MM-DD 'timestamp' when this role is expired  (OVERWRITTEN by expire_in)
            #comment: pigsty admin user      # optional, comment string for this user/role
            #roles: [dbrole_admin]           # optional, belonged roles. default roles are: dbrole_{admin,readonly,readwrite,offline}
            #parameters: {}                  # optional, role level parameters with `ALTER ROLE SET`
            #pool_mode: transaction          # optional, pgbouncer pool mode at user level, transaction by default
            #pool_connlimit: -1              # optional, max database connections at user level, default -1 disable limit
          - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly], comment: read-only viewer for meta database}
          #- {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database   }
          #- {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database  }
          #- {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service      }
          #- {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service    }

        # define business service here: https://doc.pgsty.com/pgsql/service
        pg_services:                        # extra services in addition to pg_default_services, array of service definition
          # standby service will route {ip|name}:5435 to sync replica's pgbouncer (5435->6432 standby)
          - name: standby                   # required, service name, the actual svc name will be prefixed with `pg_cluster`, e.g: pg-meta-standby
            port: 5435                      # required, service exposed port (work as kubernetes service node port mode)
            ip: "*"                         # optional, service bind ip address, `*` for all ip by default
            selector: "[]"                  # required, service member selector, use JMESPath to filter inventory
            dest: default                   # optional, destination port, default|postgres|pgbouncer|<port_number>, 'default' by default
            check: /sync                    # optional, health check url path, / by default
            backup: "[? pg_role == `primary`]"  # backup server selector
            maxconn: 3000                   # optional, max allowed front-end connection
            balance: roundrobin             # optional, haproxy load balance algorithm (roundrobin by default, other: leastconn)
            options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'

        # define pg extensions: https://doc.pgsty.com/pgsql/extension
        pg_libs: 'pg_stat_statements, auto_explain' # add timescaledb to shared_preload_libraries
        #pg_extensions: [] # extensions to be installed on this cluster

        # define HBA rules here: https://doc.pgsty.com/pgsql/hba
        pg_hba_rules:
          - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}

        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24
        pg_vip_interface: eth1

        node_crontab:  # make a full backup 1 am everyday
          - '00 01 * * * postgres /pg/bin/pg-backup full'

    #----------------------------------#
    # pgsql cluster: pg-test (3 nodes) #
    #----------------------------------#
    # pg-test --->  10.10.10.3 ---> 10.10.10.1{1,2,3}
    pg-test:                          # define the new 3-node cluster pg-test
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }   # primary instance, leader of cluster
        10.10.10.12: { pg_seq: 2, pg_role: replica }   # replica instance, follower of leader
        10.10.10.13: { pg_seq: 3, pg_role: replica, pg_offline_query: true } # replica with offline access
      vars:
        pg_cluster: pg-test           # define pgsql cluster name
        pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
        pg_databases: [{ name: test }] # create a database and user named 'test'
        node_tune: tiny
        pg_conf: tiny.yml
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.3/24
        pg_vip_interface: eth1
        node_crontab:  # make a full backup on monday 1am, and an incremental backup during weekdays
          - '00 01 * * 1 postgres /pg/bin/pg-backup full'
          - '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'

    #----------------------------------#
    # redis ms, sentinel, native cluster
    #----------------------------------#
    redis-ms: # redis classic primary & replica
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

    redis-meta: # redis sentinel x 3
      hosts: { 10.10.10.11: { redis_node: 1 , redis_instances: { 26379: { } ,26380: { } ,26381: { } } } }
      vars:
        redis_cluster: redis-meta
        redis_password: 'redis.meta'
        redis_mode: sentinel
        redis_max_memory: 16MB
        redis_sentinel_monitor: # primary list for redis sentinel, use cls as name, primary ip:port
          - { name: redis-ms, host: 10.10.10.10, port: 6379 ,password: redis.ms, quorum: 2 }

    redis-test: # redis native cluster: 3m x 3s
      hosts:
        10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
        10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
      vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }


  ####################################################################
  #                             VARS                                 #
  ####################################################################
  vars:                               # global variables


    #================================================================#
    #                         VARS: INFRA                            #
    #================================================================#

    #-----------------------------------------------------------------
    # META
    #-----------------------------------------------------------------
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    language: en                      # default language: en, zh
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]

    #-----------------------------------------------------------------
    # CA
    #-----------------------------------------------------------------
    ca_create: true                   # create ca if not exists? or just abort
    ca_cn: pigsty-ca                  # ca common name, fixed as pigsty-ca
    cert_validity: 7300d              # cert validity, 20 years by default

    #-----------------------------------------------------------------
    # INFRA_IDENTITY
    #-----------------------------------------------------------------
    #infra_seq: 1                     # infra node identity, explicitly required
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name
    infra_data: /data/infra           # default data path for infrastructure data

    #-----------------------------------------------------------------
    # REPO
    #-----------------------------------------------------------------
    repo_enabled: true                # create a yum repo on this infra node?
    repo_home: /www                   # repo home dir, `/www` by default
    repo_name: pigsty                 # repo name, pigsty by default
    repo_endpoint: http://${admin_ip}:80 # access point to this repo by domain or ip:port
    repo_remove: true                 # remove existing upstream repo
    repo_modules: infra,node,pgsql    # which repo modules are installed in repo_upstream
    repo_upstream:                    # where to download
      - { name: pigsty-local   ,description: 'Pigsty Local'       ,module: local   ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://${admin_ip}/pigsty ./' }}
      - { name: pigsty-pgsql   ,description: 'Pigsty PgSQL'       ,module: pgsql   ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/apt/pgsql/${distro_codename} ${distro_codename} main', china: 'https://repo.pigsty.cc/apt/pgsql/${distro_codename} ${distro_codename} main' }}
      - { name: pigsty-infra   ,description: 'Pigsty Infra'       ,module: infra   ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/apt/infra/ generic main' ,china: 'https://repo.pigsty.cc/apt/infra/ generic main' }}
      - { name: nginx          ,description: 'Nginx'              ,module: infra   ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://nginx.org/packages/${distro_name} ${distro_codename} nginx' }}
      - { name: docker-ce      ,description: 'Docker'             ,module: infra   ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.docker.com/linux/${distro_name} ${distro_codename} stable'                               ,china: 'https://mirrors.aliyun.com/docker-ce/linux/${distro_name} ${distro_codename} stable' }}
      - { name: base           ,description: 'Debian Basic'       ,module: node    ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://deb.debian.org/debian/ ${distro_codename} main non-free-firmware'                                  ,china: 'https://mirrors.aliyun.com/debian/ ${distro_codename} main restricted universe multiverse' }}
      - { name: updates        ,description: 'Debian Updates'     ,module: node    ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://deb.debian.org/debian/ ${distro_codename}-updates main non-free-firmware'                          ,china: 'https://mirrors.aliyun.com/debian/ ${distro_codename}-updates main restricted universe multiverse' }}
      - { name: security       ,description: 'Debian Security'    ,module: node    ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://security.debian.org/debian-security ${distro_codename}-security main non-free-firmware'            ,china: 'https://mirrors.aliyun.com/debian-security/ ${distro_codename}-security main non-free-firmware' }}
      - { name: base           ,description: 'Ubuntu Basic'       ,module: node    ,releases: [         20,22,24] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}           main universe multiverse restricted' ,china: 'https://mirrors.aliyun.com/ubuntu/ ${distro_codename}           main restricted universe multiverse' }}
      - { name: updates        ,description: 'Ubuntu Updates'     ,module: node    ,releases: [         20,22,24] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}-backports main restricted universe multiverse' ,china: 'https://mirrors.aliyun.com/ubuntu/ ${distro_codename}-updates   main restricted universe multiverse' }}
      - { name: backports      ,description: 'Ubuntu Backports'   ,module: node    ,releases: [         20,22,24] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}-security  main restricted universe multiverse' ,china: 'https://mirrors.aliyun.com/ubuntu/ ${distro_codename}-backports main restricted universe multiverse' }}
      - { name: security       ,description: 'Ubuntu Security'    ,module: node    ,releases: [         20,22,24] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}-updates   main restricted universe multiverse' ,china: 'https://mirrors.aliyun.com/ubuntu/ ${distro_codename}-security  main restricted universe multiverse' }}
      - { name: base           ,description: 'Ubuntu Basic'       ,module: node    ,releases: [         20,22,24] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}             main universe multiverse restricted' ,china: 'https://mirrors.aliyun.com/ubuntu-ports/ ${distro_codename}           main restricted universe multiverse' }}
      - { name: updates        ,description: 'Ubuntu Updates'     ,module: node    ,releases: [         20,22,24] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}-backports   main restricted universe multiverse' ,china: 'https://mirrors.aliyun.com/ubuntu-ports/ ${distro_codename}-updates   main restricted universe multiverse' }}
      - { name: backports      ,description: 'Ubuntu Backports'   ,module: node    ,releases: [         20,22,24] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}-security    main restricted universe multiverse' ,china: 'https://mirrors.aliyun.com/ubuntu-ports/ ${distro_codename}-backports main restricted universe multiverse' }}
      - { name: security       ,description: 'Ubuntu Security'    ,module: node    ,releases: [         20,22,24] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}-updates     main restricted universe multiverse' ,china: 'https://mirrors.aliyun.com/ubuntu-ports/ ${distro_codename}-security  main restricted universe multiverse' }}
      - { name: pgdg           ,description: 'PGDG'               ,module: pgsql   ,releases: [11,12,13,   22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://apt.postgresql.org/pub/repos/apt/ ${distro_codename}-pgdg main' ,china: 'https://mirrors.aliyun.com/postgresql/repos/apt/ ${distro_codename}-pgdg main' }}
      - { name: pgdg-beta      ,description: 'PGDG Beta'          ,module: beta    ,releases: [11,12,13,   22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://apt.postgresql.org/pub/repos/apt/ ${distro_codename}-pgdg-testing main 19' ,china: 'https://mirrors.aliyun.com/postgresql/repos/apt/ ${distro_codename}-pgdg-testing main 19' }}
      - { name: timescaledb    ,description: 'TimescaleDB'        ,module: extra   ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packagecloud.io/timescale/timescaledb/${distro_name}/ ${distro_codename} main' }}
      - { name: citus          ,description: 'Citus'              ,module: extra   ,releases: [11,12,   20,22   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packagecloud.io/citusdata/community/${distro_name}/ ${distro_codename} main' } }
      - { name: percona        ,description: 'Percona TDE'        ,module: percona ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/apt/percona ${distro_codename} main' ,china: 'https://repo.pigsty.cc/apt/percona ${distro_codename} main' ,origin: 'http://repo.percona.com/ppg-18.1/apt ${distro_codename} main' }}
      - { name: wiltondb       ,description: 'WiltonDB'           ,module: mssql   ,releases: [         20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/apt/mssql/ ${distro_codename} main'  ,china: 'https://repo.pigsty.cc/apt/mssql/ ${distro_codename} main'  ,origin: 'https://ppa.launchpadcontent.net/wiltondb/wiltondb/ubuntu/ ${distro_codename} main'  }}
      - { name: groonga        ,description: 'Groonga Debian'     ,module: groonga ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.groonga.org/debian/ ${distro_codename} main' }}
      - { name: groonga        ,description: 'Groonga Ubuntu'     ,module: groonga ,releases: [         20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://ppa.launchpadcontent.net/groonga/ppa/ubuntu/ ${distro_codename} main' }}
      - { name: mysql          ,description: 'MySQL'              ,module: mysql   ,releases: [11,12,   20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.mysql.com/apt/${distro_name} ${distro_codename} mysql-8.0 mysql-tools', china: 'https://mirrors.tuna.tsinghua.edu.cn/mysql/apt/${distro_name} ${distro_codename} mysql-8.0 mysql-tools' }}
      - { name: mongo          ,description: 'MongoDB'            ,module: mongo   ,releases: [11,12,   20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.mongodb.org/apt/${distro_name} ${distro_codename}/mongodb-org/8.0 multiverse', china: 'https://mirrors.aliyun.com/mongodb/apt/${distro_name} ${distro_codename}/mongodb-org/8.0 multiverse' }}
      - { name: redis          ,description: 'Redis'              ,module: redis   ,releases: [11,12,   20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.redis.io/deb ${distro_codename} main' }}
      - { name: llvm           ,description: 'LLVM'               ,module: llvm    ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://apt.llvm.org/${distro_codename}/ llvm-toolchain-${distro_codename} main' ,china: 'https://mirrors.tuna.tsinghua.edu.cn/llvm-apt/${distro_codename}/ llvm-toolchain-${distro_codename} main' }}
      - { name: haproxyd       ,description: 'Haproxy Debian'     ,module: haproxy ,releases: [11,12            ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://haproxy.debian.net/ ${distro_codename}-backports-3.1 main' }}
      - { name: haproxyu       ,description: 'Haproxy Ubuntu'     ,module: haproxy ,releases: [         20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://ppa.launchpadcontent.net/vbernat/haproxy-3.1/ubuntu/ ${distro_codename} main' }}
      - { name: grafana        ,description: 'Grafana'            ,module: grafana ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://apt.grafana.com stable main' ,china: 'https://mirrors.aliyun.com/grafana/apt/ stable main' }}
      - { name: kubernetes     ,description: 'Kubernetes'         ,module: kube    ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /', china: 'https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.33/deb/ /' }}
      - { name: gitlab-ee      ,description: 'Gitlab EE'          ,module: gitlab  ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ee/${distro_name}/ ${distro_codename} main' }}
      - { name: gitlab-ce      ,description: 'Gitlab CE'          ,module: gitlab  ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ce/${distro_name}/ ${distro_codename} main' }}
      - { name: clickhouse     ,description: 'ClickHouse'         ,module: click   ,releases: [11,12,13,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.clickhouse.com/deb/ stable main', china: 'https://mirrors.aliyun.com/clickhouse/deb/ stable main' }}

    repo_packages: [ node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-utility, extra-modules ]
    repo_extra_packages: [ pgsql-main ]
    repo_url_packages: []

    #-----------------------------------------------------------------
    # INFRA_PACKAGE
    #-----------------------------------------------------------------
    infra_packages:                   # packages to be installed on infra nodes
      - grafana,grafana-plugins,grafana-victorialogs-ds,grafana-victoriametrics-ds,victoria-metrics,victoria-logs,victoria-traces,vmutils,vlogscli,alertmanager
      - node-exporter,blackbox-exporter,nginx-exporter,pg-exporter,pev2,nginx,dnsmasq,ansible,etcd,python3-requests,redis,mcli,restic,certbot,python3-certbot-nginx
    infra_packages_pip: ''            # pip installed packages for infra nodes

    #-----------------------------------------------------------------
    # NGINX
    #-----------------------------------------------------------------
    nginx_enabled: true               # enable nginx on this infra node?
    nginx_clean: false                # clean existing nginx config during init?
    nginx_exporter_enabled: true      # enable nginx_exporter on this infra node?
    nginx_exporter_port: 9113         # nginx_exporter listen port, 9113 by default
    nginx_sslmode: enable             # nginx ssl mode? disable,enable,enforce
    nginx_cert_validity: 397d         # nginx self-signed cert validity, 397d by default
    nginx_home: /www                  # nginx content dir, `/www` by default (soft link to nginx_data)
    nginx_data: /data/nginx           # nginx actual data dir, /data/nginx by default
    nginx_users: { admin : pigsty }   # nginx basic auth users: name and pass dict
    nginx_port: 80                    # nginx listen port, 80 by default
    nginx_ssl_port: 443               # nginx ssl listen port, 443 by default
    certbot_sign: false               # sign nginx cert with certbot during setup?
    certbot_email: [email protected]     # certbot email address, used for free ssl
    certbot_options: ''               # certbot extra options

    #-----------------------------------------------------------------
    # DNS
    #-----------------------------------------------------------------
    dns_enabled: true                 # setup dnsmasq on this infra node?
    dns_port: 53                      # dns server listen port, 53 by default
    dns_records:                      # dynamic dns records resolved by dnsmasq
      - "${admin_ip} i.pigsty"
      - "${admin_ip} m.pigsty supa.pigsty api.pigsty adm.pigsty cli.pigsty ddl.pigsty"

    #-----------------------------------------------------------------
    # VICTORIA
    #-----------------------------------------------------------------
    vmetrics_enabled: true            # enable victoria-metrics on this infra node?
    vmetrics_clean: false             # whether clean existing victoria metrics data during init?
    vmetrics_port: 8428               # victoria-metrics listen port, 8428 by default
    vmetrics_scrape_interval: 10s     # victoria global scrape interval, 10s by default
    vmetrics_scrape_timeout: 8s       # victoria global scrape timeout, 8s by default
    vmetrics_options: >-
      -retentionPeriod=15d
      -promscrape.fileSDCheckInterval=5s
    vlogs_enabled: true               # enable victoria-logs on this infra node?
    vlogs_clean: false                # clean victoria-logs data during init?
    vlogs_port: 9428                  # victoria-logs listen port, 9428 by default
    vlogs_options: >-
      -retentionPeriod=15d
      -retention.maxDiskSpaceUsageBytes=50GiB
      -insert.maxLineSizeBytes=1MB
      -search.maxQueryDuration=120s
    vtraces_enabled: true             # enable victoria-traces on this infra node?
    vtraces_clean: false                # clean victoria-trace data during inti?
    vtraces_port: 10428               # victoria-traces listen port, 10428 by default
    vtraces_options: >-
      -retentionPeriod=15d
      -retention.maxDiskSpaceUsageBytes=50GiB
    vmalert_enabled: true             # enable vmalert on this infra node?
    vmalert_port: 8880                # vmalert listen port, 8880 by default
    vmalert_options: ''              # vmalert extra server options

    #-----------------------------------------------------------------
    # PROMETHEUS
    #-----------------------------------------------------------------
    blackbox_enabled: true            # setup blackbox_exporter on this infra node?
    blackbox_port: 9115               # blackbox_exporter listen port, 9115 by default
    blackbox_options: ''              # blackbox_exporter extra server options
    alertmanager_enabled: true        # setup alertmanager on this infra node?
    alertmanager_port: 9059           # alertmanager listen port, 9059 by default
    alertmanager_options: ''          # alertmanager extra server options
    exporter_metrics_path: /metrics   # exporter metric path, `/metrics` by default

    #-----------------------------------------------------------------
    # GRAFANA
    #-----------------------------------------------------------------
    grafana_enabled: true             # enable grafana on this infra node?
    grafana_port: 3000                # default listen port for grafana
    grafana_clean: false              # clean grafana data during init?
    grafana_admin_username: admin     # grafana admin username, `admin` by default
    grafana_admin_password: pigsty    # grafana admin password, `pigsty` by default
    grafana_auth_proxy: false         # enable grafana auth proxy?
    grafana_pgurl: ''                 # external postgres database url for grafana if given
    grafana_view_password: DBUser.Viewer # password for grafana meta pg datasource


    #================================================================#
    #                         VARS: NODE                             #
    #================================================================#

    #-----------------------------------------------------------------
    # NODE_IDENTITY
    #-----------------------------------------------------------------
    #nodename:           # [INSTANCE] # node instance identity, use hostname if missing, optional
    node_cluster: nodes   # [CLUSTER] # node cluster identity, use 'nodes' if missing, optional
    nodename_overwrite: true          # overwrite node's hostname with nodename?
    nodename_exchange: false          # exchange nodename among play hosts?
    node_id_from_pg: true             # use postgres identity as node identity if applicable?

    #-----------------------------------------------------------------
    # NODE_DNS
    #-----------------------------------------------------------------
    node_write_etc_hosts: true        # modify `/etc/hosts` on target node?
    node_default_etc_hosts:           # static dns records in `/etc/hosts`
      - "${admin_ip} i.pigsty"
    node_etc_hosts: []                # extra static dns records in `/etc/hosts`
    node_dns_method: add              # how to handle dns servers: add,none,overwrite
    node_dns_servers: ['${admin_ip}'] # dynamic nameserver in `/etc/resolv.conf`
    node_dns_options:                 # dns resolv options in `/etc/resolv.conf`
      - options single-request-reopen timeout:1

    #-----------------------------------------------------------------
    # NODE_PACKAGE
    #-----------------------------------------------------------------
    node_repo_modules: local          # upstream repo to be added on node, local by default
    node_repo_remove: true            # remove existing repo on node?
    node_packages: [openssh-server]   # packages to be installed current nodes with latest version
    node_default_packages:            # default packages to be installed on all nodes
      - lz4,unzip,bzip2,pv,jq,git,ncdu,make,patch,bash,lsof,wget,uuid,tuned,nvme-cli,numactl,sysstat,iotop,htop,rsync,tcpdump
      - python3,python3-pip,socat,lrzsz,net-tools,ipvsadm,telnet,ca-certificates,openssl,keepalived,etcd,haproxy,chrony,pig
      - zlib1g,acl,dnsutils,libreadline-dev,vim-tiny,node-exporter,openssh-server,openssh-client,vector

    #-----------------------------------------------------------------
    # NODE_SEC
    #-----------------------------------------------------------------
    node_selinux_mode: permissive     # set selinux mode: enforcing,permissive,disabled
    node_firewall_mode: zone          # firewall mode: off, none, zone, zone by default
    node_firewall_intranet:           # which intranet cidr considered as internal network
      - 10.0.0.0/8
      - 192.168.0.0/16
      - 172.16.0.0/12
    node_firewall_public_port:        # expose these ports to public network in (zone, strict) mode
      - 22                            # enable ssh access
      - 80                            # enable http access
      - 443                           # enable https access
      - 5432                          # enable postgresql access (think twice before exposing it!)

    #-----------------------------------------------------------------
    # NODE_TUNE
    #-----------------------------------------------------------------
    node_disable_numa: false          # disable node numa, reboot required
    node_disable_swap: false          # disable node swap, use with caution
    node_static_network: true         # preserve dns resolver settings after reboot
    node_disk_prefetch: false         # setup disk prefetch on HDD to increase performance
    node_kernel_modules: [ softdog, ip_vs, ip_vs_rr, ip_vs_wrr, ip_vs_sh ]
    node_hugepage_count: 0            # number of 2MB hugepage, take precedence over ratio
    node_hugepage_ratio: 0            # node mem hugepage ratio, 0 disable it by default
    node_overcommit_ratio: 0          # node mem overcommit ratio, 0 disable it by default
    node_tune: oltp                   # node tuned profile: none,oltp,olap,crit,tiny
    node_sysctl_params: { }           # sysctl parameters in k:v format in addition to tuned

    #-----------------------------------------------------------------
    # NODE_ADMIN
    #-----------------------------------------------------------------
    node_data: /data                  # node main data directory, `/data` by default
    node_admin_enabled: true          # create a admin user on target node?
    node_admin_uid: 88                # uid and gid for node admin user
    node_admin_username: dba          # name of node admin user, `dba` by default
    node_admin_sudo: nopass           # admin sudo privilege, all,nopass. nopass by default
    node_admin_ssh_exchange: true     # exchange admin ssh key among node cluster
    node_admin_pk_current: true       # add current user's ssh pk to admin authorized_keys
    node_admin_pk_list: []            # ssh public keys to be added to admin user
    node_aliases: {}                  # extra shell aliases to be added, k:v dict

    #-----------------------------------------------------------------
    # NODE_TIME
    #-----------------------------------------------------------------
    node_timezone: ''                 # setup node timezone, empty string to skip
    node_ntp_enabled: true            # enable chronyd time sync service?
    node_ntp_servers:                 # ntp servers in `/etc/chrony.conf`
      - pool pool.ntp.org iburst
    node_crontab_overwrite: true      # overwrite or append to `/etc/crontab`?
    node_crontab: [ ]                 # crontab entries in `/etc/crontab`

    #-----------------------------------------------------------------
    # NODE_VIP
    #-----------------------------------------------------------------
    vip_enabled: false                # enable vip on this node cluster?
    # vip_address:         [IDENTITY] # node vip address in ipv4 format, required if vip is enabled
    # vip_vrid:            [IDENTITY] # required, integer, 1-254, should be unique among same VLAN
    vip_role: backup                  # optional, `master|backup`, backup by default, use as init role
    vip_preempt: false                # optional, `true/false`, false by default, enable vip preemption
    vip_interface: eth0               # node vip network interface to listen, `eth0` by default
    vip_dns_suffix: ''                # node vip dns name suffix, empty string by default
    vip_exporter_port: 9650           # keepalived exporter listen port, 9650 by default

    #-----------------------------------------------------------------
    # HAPROXY
    #-----------------------------------------------------------------
    haproxy_enabled: true             # enable haproxy on this node?
    haproxy_clean: false              # cleanup all existing haproxy config?
    haproxy_reload: true              # reload haproxy after config?
    haproxy_auth_enabled: true        # enable authentication for haproxy admin page
    haproxy_admin_username: admin     # haproxy admin username, `admin` by default
    haproxy_admin_password: pigsty    # haproxy admin password, `pigsty` by default
    haproxy_exporter_port: 9101       # haproxy admin/exporter port, 9101 by default
    haproxy_client_timeout: 24h       # client side connection timeout, 24h by default
    haproxy_server_timeout: 24h       # server side connection timeout, 24h by default
    haproxy_services: []              # list of haproxy service to be exposed on node

    #-----------------------------------------------------------------
    # NODE_EXPORTER
    #-----------------------------------------------------------------
    node_exporter_enabled: true       # setup node_exporter on this node?
    node_exporter_port: 9100          # node exporter listen port, 9100 by default
    node_exporter_options: '--no-collector.softnet --no-collector.nvme --collector.tcpstat --collector.processes'

    #-----------------------------------------------------------------
    # VECTOR
    #-----------------------------------------------------------------
    vector_enabled: true              # enable vector log collector?
    vector_clean: false               # purge vector data dir during init?
    vector_data: /data/vector         # vector data dir, /data/vector by default
    vector_port: 9598                 # vector metrics port, 9598 by default
    vector_read_from: beginning       # vector read from beginning or end
    vector_log_endpoint: [ infra ]    # if defined, sending vector log to this endpoint.


    #================================================================#
    #                        VARS: DOCKER                            #
    #================================================================#
    docker_enabled: false             # enable docker on this node?
    docker_data: /data/docker         # docker data directory, /data/docker by default
    docker_storage_driver: overlay2   # docker storage driver, can be zfs, btrfs
    docker_cgroups_driver: systemd    # docker cgroup fs driver: cgroupfs,systemd
    docker_registry_mirrors: []       # docker registry mirror list
    docker_exporter_port: 9323        # docker metrics exporter port, 9323 by default
    docker_image: []                  # docker image to be pulled after bootstrap
    docker_image_cache: /tmp/docker/*.tgz # docker image cache glob pattern

    #================================================================#
    #                         VARS: ETCD                             #
    #================================================================#
    #etcd_seq: 1                      # etcd instance identifier, explicitly required
    etcd_cluster: etcd                # etcd cluster & group name, etcd by default
    etcd_safeguard: false             # prevent purging running etcd instance?
    etcd_clean: true                  # purging existing etcd during initialization?
    etcd_data: /data/etcd             # etcd data directory, /data/etcd by default
    etcd_port: 2379                   # etcd client port, 2379 by default
    etcd_peer_port: 2380              # etcd peer port, 2380 by default
    etcd_init: new                    # etcd initial cluster state, new or existing
    etcd_election_timeout: 1000       # etcd election timeout, 1000ms by default
    etcd_heartbeat_interval: 100      # etcd heartbeat interval, 100ms by default
    etcd_root_password: Etcd.Root     # etcd root password for RBAC, change it!


    #================================================================#
    #                         VARS: MINIO                            #
    #================================================================#
    #minio_seq: 1                     # minio instance identifier, REQUIRED
    minio_cluster: minio              # minio cluster identifier, REQUIRED
    minio_clean: false                # cleanup minio during init?, false by default
    minio_user: minio                 # minio os user, `minio` by default
    minio_https: true                 # use https for minio, true by default
    minio_node: '${minio_cluster}-${minio_seq}.pigsty' # minio node name pattern
    minio_data: '/data/minio'         # minio data dir(s), use {x...y} to specify multi drivers
    #minio_volumes:                   # minio data volumes, override defaults if specified
    minio_domain: sss.pigsty          # minio external domain name, `sss.pigsty` by default
    minio_port: 9000                  # minio service port, 9000 by default
    minio_admin_port: 9001            # minio console port, 9001 by default
    minio_access_key: minioadmin      # root access key, `minioadmin` by default
    minio_secret_key: S3User.MinIO    # root secret key, `S3User.MinIO` by default
    minio_extra_vars: ''              # extra environment variables
    minio_provision: true             # run minio provisioning tasks?
    minio_alias: sss                  # alias name for local minio deployment
    #minio_endpoint: https://sss.pigsty:9000 # if not specified, overwritten by defaults
    minio_buckets:                    # list of minio bucket to be created
      - { name: pgsql }
      - { name: meta ,versioning: true }
      - { name: data }
    minio_users:                      # list of minio user to be created
      - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
      - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
      - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }


    #================================================================#
    #                         VARS: REDIS                            #
    #================================================================#
    #redis_cluster:        <CLUSTER> # redis cluster name, required identity parameter
    #redis_node: 1            <NODE> # redis node sequence number, node int id required
    #redis_instances: {}      <NODE> # redis instances definition on this redis node
    redis_fs_main: /data              # redis main data mountpoint, `/data` by default
    redis_exporter_enabled: true      # install redis exporter on redis nodes?
    redis_exporter_port: 9121         # redis exporter listen port, 9121 by default
    redis_exporter_options: ''        # cli args and extra options for redis exporter
    redis_safeguard: false            # prevent purging running redis instance?
    redis_clean: true                 # purging existing redis during init?
    redis_rmdata: true                # remove redis data when purging redis server?
    redis_mode: standalone            # redis mode: standalone,cluster,sentinel
    redis_conf: redis.conf            # redis config template path, except sentinel
    redis_bind_address: '0.0.0.0'     # redis bind address, empty string will use host ip
    redis_max_memory: 1GB             # max memory used by each redis instance
    redis_mem_policy: allkeys-lru     # redis memory eviction policy
    redis_password: ''                # redis password, empty string will disable password
    redis_rdb_save: ['1200 1']        # redis rdb save directives, disable with empty list
    redis_aof_enabled: false          # enable redis append only file?
    redis_rename_commands: {}         # rename redis dangerous commands
    redis_cluster_replicas: 1         # replica number for one master in redis cluster
    redis_sentinel_monitor: []        # sentinel master list, works on sentinel cluster only


    #================================================================#
    #                         VARS: PGSQL                            #
    #================================================================#

    #-----------------------------------------------------------------
    # PG_IDENTITY
    #-----------------------------------------------------------------
    pg_mode: pgsql          #CLUSTER  # pgsql cluster mode: pgsql,citus,gpsql,mssql,mysql,ivory,polar
    # pg_cluster:           #CLUSTER  # pgsql cluster name, required identity parameter
    # pg_seq: 0             #INSTANCE # pgsql instance seq number, required identity parameter
    # pg_role: replica      #INSTANCE # pgsql role, required, could be primary,replica,offline
    # pg_instances: {}      #INSTANCE # define multiple pg instances on node in `{port:ins_vars}` format
    # pg_upstream:          #INSTANCE # repl upstream ip addr for standby cluster or cascade replica
    # pg_shard:             #CLUSTER  # pgsql shard name, optional identity for sharding clusters
    # pg_group: 0           #CLUSTER  # pgsql shard index number, optional identity for sharding clusters
    # gp_role: master       #CLUSTER  # greenplum role of this cluster, could be master or segment
    pg_offline_query: false #INSTANCE # set to true to enable offline queries on this instance

    #-----------------------------------------------------------------
    # PG_BUSINESS
    #-----------------------------------------------------------------
    # postgres business object definition, overwrite in group vars
    pg_users: []                      # postgres business users
    pg_databases: []                  # postgres business databases
    pg_services: []                   # postgres business services
    pg_hba_rules: []                  # business hba rules for postgres
    pgb_hba_rules: []                 # business hba rules for pgbouncer
    # global credentials, overwrite in global vars
    pg_dbsu_password: ''              # dbsu password, empty string means no dbsu password by default
    pg_replication_username: replicator
    pg_replication_password: DBUser.Replicator
    pg_admin_username: dbuser_dba
    pg_admin_password: DBUser.DBA
    pg_monitor_username: dbuser_monitor
    pg_monitor_password: DBUser.Monitor

    #-----------------------------------------------------------------
    # PG_INSTALL
    #-----------------------------------------------------------------
    pg_dbsu: postgres                 # os dbsu name, postgres by default, better not change it
    pg_dbsu_uid: 543                  # os dbsu uid and gid, 26 for default postgres users and groups
    pg_dbsu_sudo: limit               # dbsu sudo privilege, none,limit,all,nopass. limit by default
    pg_dbsu_home: /var/lib/pgsql      # postgresql home directory, `/var/lib/pgsql` by default
    pg_dbsu_ssh_exchange: true        # exchange postgres dbsu ssh key among same pgsql cluster
    pg_version: 18                    # postgres major version to be installed, 18 by default
    pg_bin_dir: /usr/pgsql/bin        # postgres binary dir, `/usr/pgsql/bin` by default
    pg_log_dir: /pg/log/postgres      # postgres log dir, `/pg/log/postgres` by default
    pg_packages:                      # pg packages to be installed, alias can be used
      - pgsql-main pgsql-common
    pg_extensions: []                 # pg extensions to be installed, alias can be used

    #-----------------------------------------------------------------
    # PG_BOOTSTRAP
    #-----------------------------------------------------------------
    pg_data: /pg/data                 # postgres data directory, `/pg/data` by default
    pg_fs_main: /data/postgres        # postgres main data directory, `/data/postgres` by default
    pg_fs_backup: /data/backups       # postgres backup data directory, `/data/backups` by default
    pg_storage_type: SSD              # storage type for pg main data, SSD,HDD, SSD by default
    pg_dummy_filesize: 64MiB          # size of `/pg/dummy`, hold 64MB disk space for emergency use
    pg_listen: '0.0.0.0'              # postgres/pgbouncer listen addresses, comma separated list
    pg_port: 5432                     # postgres listen port, 5432 by default
    pg_localhost: /var/run/postgresql # postgres unix socket dir for localhost connection
    patroni_enabled: true             # if disabled, no postgres cluster will be created during init
    patroni_mode: default             # patroni working mode: default,pause,remove
    pg_namespace: /pg                 # top level key namespace in etcd, used by patroni & vip
    patroni_port: 8008                # patroni listen port, 8008 by default
    patroni_log_dir: /pg/log/patroni  # patroni log dir, `/pg/log/patroni` by default
    patroni_ssl_enabled: false        # secure patroni RestAPI communications with SSL?
    patroni_watchdog_mode: off        # patroni watchdog mode: automatic,required,off. off by default
    patroni_username: postgres        # patroni restapi username, `postgres` by default
    patroni_password: Patroni.API     # patroni restapi password, `Patroni.API` by default
    pg_etcd_password: ''              # etcd password for this pg cluster, '' to use pg_cluster
    pg_primary_db: postgres           # primary database name, used by citus,etc... ,postgres by default
    pg_parameters: {}                 # extra parameters in postgresql.auto.conf
    pg_files: []                      # extra files to be copied to postgres data directory (e.g. license)
    pg_conf: oltp.yml                 # config template: oltp,olap,crit,tiny. `oltp.yml` by default
    pg_max_conn: auto                 # postgres max connections, `auto` will use recommended value
    pg_shared_buffer_ratio: 0.25      # postgres shared buffers ratio, 0.25 by default, 0.1~0.4
    pg_io_method: worker              # io method for postgres, auto,fsync,worker,io_uring, worker by default
    pg_rto: 30                        # recovery time objective in seconds,  `30s` by default
    pg_rpo: 1048576                   # recovery point objective in bytes, `1MiB` at most by default
    pg_libs: 'pg_stat_statements, auto_explain'  # preloaded libraries, `pg_stat_statements,auto_explain` by default
    pg_delay: 0                       # replication apply delay for standby cluster leader
    pg_checksum: true                 # enable data checksum for postgres cluster?
    pg_encoding: UTF8                 # database cluster encoding, `UTF8` by default
    pg_locale: C                      # database cluster local, `C` by default
    pg_lc_collate: C                  # database cluster collate, `C` by default
    pg_lc_ctype: C                    # database character type, `C` by default
      #pgsodium_key: ""                 # pgsodium key, 64 hex digit, default to sha256(pg_cluster)
      #pgsodium_getkey_script: ""       # pgsodium getkey script path, pgsodium_getkey by default

    #-----------------------------------------------------------------
    # PG_PROVISION
    #-----------------------------------------------------------------
    pg_provision: true                # provision postgres cluster after bootstrap
    pg_init: pg-init                  # provision init script for cluster template, `pg-init` by default
    pg_default_roles:                 # default roles and users in postgres cluster
      - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
      - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
      - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
      - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
      - { name: postgres     ,superuser: true  ,comment: system superuser }
      - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator }
      - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
      - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }
    pg_default_privileges:            # default privileges when created by admin user
      - GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
      - GRANT SELECT     ON TABLES    TO dbrole_readonly
      - GRANT SELECT     ON SEQUENCES TO dbrole_readonly
      - GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
      - GRANT USAGE      ON SCHEMAS   TO dbrole_offline
      - GRANT SELECT     ON TABLES    TO dbrole_offline
      - GRANT SELECT     ON SEQUENCES TO dbrole_offline
      - GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
      - GRANT INSERT     ON TABLES    TO dbrole_readwrite
      - GRANT UPDATE     ON TABLES    TO dbrole_readwrite
      - GRANT DELETE     ON TABLES    TO dbrole_readwrite
      - GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
      - GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
      - GRANT TRUNCATE   ON TABLES    TO dbrole_admin
      - GRANT REFERENCES ON TABLES    TO dbrole_admin
      - GRANT TRIGGER    ON TABLES    TO dbrole_admin
      - GRANT CREATE     ON SCHEMAS   TO dbrole_admin
    pg_default_schemas: [ monitor ]   # default schemas to be created
    pg_default_extensions:            # default extensions to be created
      - { name: pg_stat_statements ,schema: monitor }
      - { name: pgstattuple        ,schema: monitor }
      - { name: pg_buffercache     ,schema: monitor }
      - { name: pageinspect        ,schema: monitor }
      - { name: pg_prewarm         ,schema: monitor }
      - { name: pg_visibility      ,schema: monitor }
      - { name: pg_freespacemap    ,schema: monitor }
      - { name: postgres_fdw       ,schema: public  }
      - { name: file_fdw           ,schema: public  }
      - { name: btree_gist         ,schema: public  }
      - { name: btree_gin          ,schema: public  }
      - { name: pg_trgm            ,schema: public  }
      - { name: intagg             ,schema: public  }
      - { name: intarray           ,schema: public  }
      - { name: pg_repack }
    pg_reload: true                   # reload postgres after hba changes
    pg_default_hba_rules:             # postgres default host-based authentication rules, order by `order`
      - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  ,order: 100}
      - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' ,order: 150}
      - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost',order: 200}
      - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' ,order: 250}
      - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' ,order: 300}
      - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' ,order: 350}
      - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password',order: 400}
      - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   ,order: 450}
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    ,order: 500}
      - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket',order: 550}
      - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     ,order: 600}
      - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet',order: 650}
    pgb_default_hba_rules:            # pgbouncer default host-based authentication rules, order by `order`
      - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident',order: 100}
      - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' ,order: 150}
      - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' ,order: 200}
      - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' ,order: 250}
      - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   ,order: 300}
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   ,order: 350}
      - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' ,order: 400}

    #-----------------------------------------------------------------
    # PG_BACKUP
    #-----------------------------------------------------------------
    pgbackrest_enabled: true          # enable pgbackrest on pgsql host?
    pgbackrest_log_dir: /pg/log/pgbackrest # pgbackrest log dir, `/pg/log/pgbackrest` by default
    pgbackrest_method: local          # pgbackrest repo method: local,minio,[user-defined...]
    pgbackrest_init_backup: true      # take a full backup after pgbackrest is initialized?
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backups when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the the last 14 days

    #-----------------------------------------------------------------
    # PG_ACCESS
    #-----------------------------------------------------------------
    pgbouncer_enabled: true           # if disabled, pgbouncer will not be launched on pgsql host
    pgbouncer_port: 6432              # pgbouncer listen port, 6432 by default
    pgbouncer_log_dir: /pg/log/pgbouncer  # pgbouncer log dir, `/pg/log/pgbouncer` by default
    pgbouncer_auth_query: false       # query postgres to retrieve unlisted business users?
    pgbouncer_poolmode: transaction   # pooling mode: transaction,session,statement, transaction by default
    pgbouncer_sslmode: disable        # pgbouncer client ssl mode, disable by default
    pgbouncer_ignore_param: [ extra_float_digits, application_name, TimeZone, DateStyle, IntervalStyle, search_path ]
    pg_weight: 100          #INSTANCE # relative load balance weight in service, 100 by default, 0-255
    pg_service_provider: ''           # dedicate haproxy node group name, or empty string for local nodes by default
    pg_default_service_dest: pgbouncer # default service destination if svc.dest='default'
    pg_default_services:              # postgres default service definitions
      - { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
      - { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
      - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
      - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}
    pg_vip_enabled: false             # enable a l2 vip for pgsql primary? false by default
    pg_vip_address: 127.0.0.1/24      # vip address in `<ipv4>/<mask>` format, require if vip is enabled
    pg_vip_interface: eth0            # vip network interface to listen, eth0 by default
    pg_dns_suffix: ''                 # pgsql dns suffix, '' by default
    pg_dns_target: auto               # auto, primary, vip, none, or ad hoc ip

    #-----------------------------------------------------------------
    # PG_MONITOR
    #-----------------------------------------------------------------
    pg_exporter_enabled: true              # enable pg_exporter on pgsql hosts?
    pg_exporter_config: pg_exporter.yml    # pg_exporter configuration file name
    pg_exporter_cache_ttls: '1,10,60,300'  # pg_exporter collector ttl stage in seconds, '1,10,60,300' by default
    pg_exporter_port: 9630                 # pg_exporter listen port, 9630 by default
    pg_exporter_params: 'sslmode=disable'  # extra url parameters for pg_exporter dsn
    pg_exporter_url: ''                    # overwrite auto-generate pg dsn if specified
    pg_exporter_auto_discovery: true       # enable auto database discovery? enabled by default
    pg_exporter_exclude_database: 'template0,template1,postgres' # csv of database that WILL NOT be monitored during auto-discovery
    pg_exporter_include_database: ''       # csv of database that WILL BE monitored during auto-discovery
    pg_exporter_connect_timeout: 200       # pg_exporter connect timeout in ms, 200 by default
    pg_exporter_options: ''                # overwrite extra options for pg_exporter
    pgbouncer_exporter_enabled: true       # enable pgbouncer_exporter on pgsql hosts?
    pgbouncer_exporter_port: 9631          # pgbouncer_exporter listen port, 9631 by default
    pgbouncer_exporter_url: ''             # overwrite auto-generate pgbouncer dsn if specified
    pgbouncer_exporter_options: ''         # overwrite extra options for pgbouncer_exporter
    pgbackrest_exporter_enabled: true      # enable pgbackrest_exporter on pgsql hosts?
    pgbackrest_exporter_port: 9854         # pgbackrest_exporter listen port, 9854 by default
    pgbackrest_exporter_options: >
      --collect.interval=120
      --log.level=info

    #-----------------------------------------------------------------
    # PG_REMOVE
    #-----------------------------------------------------------------
    pg_safeguard: false               # stop pg_remove running if pg_safeguard is enabled, false by default
    pg_rm_data: true                  # remove postgres data during remove? true by default
    pg_rm_backup: true                # remove pgbackrest backup during primary remove? true by default
    pg_rm_pkg: true                   # uninstall postgres packages during remove? true by default

...

Explanation

The demo/debian template is optimized for Debian and Ubuntu distributions.

Supported Distributions:

  • Debian 12 (Bookworm)
  • Debian 13 (Trixie)
  • Ubuntu 22.04 LTS (Jammy)
  • Ubuntu 24.04 LTS (Noble)

Key Features:

  • Uses PGDG APT repositories
  • Optimized for APT package manager
  • Supports Debian/Ubuntu-specific package names

Use Cases:

  • Cloud servers (Ubuntu widely used)
  • Container environments (Debian commonly used as base image)
  • Development and testing environments

8.33 - demo/demo

Pigsty public demo site configuration, showcasing SSL certificates, domain exposure, and full extension installation

The demo/demo configuration template is used by Pigsty’s public demo site, demonstrating how to expose services publicly, configure SSL certificates, and install all available extensions.

If you want to set up your own public service on a cloud server, you can use this template as a reference.


Overview

  • Config Name: demo/demo
  • Node Count: Single node
  • Description: Pigsty public demo site configuration
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64
  • Related: meta, rich

Usage:

./configure -c demo/demo [-i <primary_ip>]

Key Features

This template enhances the meta template with:

  • SSL certificate and custom domain configuration (e.g., pigsty.cc)
  • Downloads and installs all available PostgreSQL 18 extensions
  • Enables Docker with image acceleration
  • Deploys MinIO object storage
  • Pre-configures multiple business databases and users
  • Adds Redis primary-replica instance examples
  • Adds FerretDB MongoDB-compatible cluster
  • Adds Kafka sample cluster

Content

Source: pigsty/conf/demo/demo.yml

---
#==============================================================#
# File      :   demo.yml
# Desc      :   Pigsty Public Demo Configuration
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


all:
  children:

    # infra cluster for proxy, monitor, alert, etc..
    infra:
      hosts: { 10.10.10.10: { infra_seq: 1 } }
      vars:
        nodename: pigsty.cc       # overwrite the default hostname
        node_id_from_pg: false    # do not use the pg identity as hostname
        docker_enabled: true      # enable docker on this node
        docker_registry_mirrors: ["https://mirror.ccs.tencentyun.com", "https://docker.1ms.run"]
        # ./pgsql-monitor.yml -l infra     # monitor 'external' PostgreSQL instance
        pg_exporters:             # treat local postgres as RDS for demonstration purpose
          20001: { pg_cluster: pg-foo, pg_seq: 1, pg_host: 10.10.10.10 }
          #20002: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.11 , pg_port: 5432 }
          #20003: { pg_cluster: pg-bar, pg_seq: 2, pg_host: 10.10.10.12 , pg_exporter_url: 'postgres://dbuser_monitor:[email protected]:5432/postgres?sslmode=disable' }
          #20004: { pg_cluster: pg-bar, pg_seq: 3, pg_host: 10.10.10.13 , pg_monitor_username: dbuser_monitor, pg_monitor_password: DBUser.Monitor }

    # etcd cluster for ha postgres
    etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # minio cluster, s3 compatible object storage
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    # postgres example cluster: pg-meta
    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 }
          - {name: dbuser_view       ,password: DBUser.Viewer     ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
          - {name: dbuser_grafana    ,password: DBUser.Grafana    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database    }
          - {name: dbuser_bytebase   ,password: DBUser.Bytebase   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database   }
          - {name: dbuser_kong       ,password: DBUser.Kong       ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway    }
          - {name: dbuser_gitea      ,password: DBUser.Gitea      ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service       }
          - {name: dbuser_wiki       ,password: DBUser.Wiki       ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service     }
          - {name: dbuser_noco       ,password: DBUser.Noco       ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for nocodb service      }
          - {name: dbuser_odoo       ,password: DBUser.Odoo       ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for odoo service ,createdb: true } #,superuser: true}
          - {name: dbuser_mattermost ,password: DBUser.MatterMost ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for mattermost ,createdb: true }
        pg_databases:
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: vector},{name: postgis},{name: timescaledb}]}
          - {name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database  }
          - {name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
          - {name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong api gateway database }
          - {name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
          - {name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database  }
          - {name: noco     ,owner: dbuser_noco     ,revokeconn: true ,comment: nocodb database     }
          #- {name: odoo     ,owner: dbuser_odoo     ,revokeconn: true ,comment: odoo main database  }
          - {name: mattermost ,owner: dbuser_mattermost ,revokeconn: true ,comment: mattermost main database }
        pg_hba_rules:
          - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
        pg_libs: 'timescaledb,pg_stat_statements, auto_explain'  # add timescaledb to shared_preload_libraries
        pg_extensions: # extensions to be installed on this cluster
          - timescaledb timescaledb_toolkit pg_timeseries periods temporal_tables emaj table_version pg_cron pg_task pg_later pg_background
          - postgis pgrouting pointcloud pg_h3 q3c ogr_fdw geoip pg_polyline pg_geohash #mobilitydb
          - pgvector vchord pgvectorscale pg_vectorize pg_similarity smlar pg_summarize pg_tiktoken pg4ml #pgml
          - pg_search pgroonga pg_bigm zhparser pg_bestmatch vchord_bm25 hunspell
          - citus hydra pg_analytics pg_duckdb pg_mooncake duckdb_fdw pg_parquet pg_fkpart pg_partman plproxy #pg_strom
          - age hll rum pg_graphql pg_jsonschema jsquery pg_hint_plan hypopg index_advisor pg_plan_filter imgsmlr pg_ivm pg_incremental pgmq pgq pg_cardano omnigres #rdkit
          - pg_tle plv8 pllua plprql pldebugger plpgsql_check plprofiler plsh pljava #plr #pgtap #faker #dbt2
          - pg_prefix pg_semver pgunit pgpdf pglite_fusion md5hash asn1oid roaringbitmap pgfaceting pgsphere pg_country pg_xenophile pg_currency pg_collection pgmp numeral pg_rational pguint pg_uint128 hashtypes ip4r pg_uri pgemailaddr pg_acl timestamp9 chkpass #pg_duration #debversion #pg_rrule
          - pg_gzip pg_bzip pg_zstd pg_http pg_net pg_curl pgjq pgjwt pg_smtp_client pg_html5_email_address url_encode pgsql_tweaks pg_extra_time pgpcre icu_ext pgqr pg_protobuf envvar floatfile pg_readme ddl_historization data_historization pg_schedoc pg_hashlib pg_xxhash shacrypt cryptint pg_ecdsa pgsparql
          - pg_idkit pg_uuidv7 permuteseq pg_hashids sequential_uuids topn quantile lower_quantile count_distinct omnisketch ddsketch vasco pgxicor tdigest first_last_agg extra_window_functions floatvec aggs_for_vecs aggs_for_arrays pg_arraymath pg_math pg_random pg_base36 pg_base62 pg_base58 pg_financial
          - pg_repack pg_squeeze pg_dirtyread pgfincore pg_cooldown pg_ddlx pg_prioritize pg_checksums pg_readonly pg_upless pg_permissions pgautofailover pg_catcheck preprepare pgcozy pg_orphaned pg_crash pg_cheat_funcs pg_fio pg_savior safeupdate pg_drop_events table_log #pgagent #pgpool
          - pg_profile pg_tracing pg_show_plans pg_stat_kcache pg_stat_monitor pg_qualstats pg_store_plans pg_track_settings pg_wait_sampling system_stats pg_meta pgnodemx pg_sqlog bgw_replstatus pgmeminfo toastinfo pg_explain_ui pg_relusage pagevis powa
          - passwordcheck supautils pgsodium pg_vault pg_session_jwt pg_anon pg_tde pgsmcrypto pgaudit pgauditlogtofile pg_auth_mon credcheck pgcryptokey pg_jobmon logerrors login_hook set_user pg_snakeoil pgextwlist pg_auditor sslutils pg_noset
          - wrappers multicorn odbc_fdw jdbc_fdw mysql_fdw tds_fdw sqlite_fdw pgbouncer_fdw mongo_fdw redis_fdw pg_redis_pubsub kafka_fdw hdfs_fdw firebird_fdw aws_s3 log_fdw #oracle_fdw #db2_fdw
          - documentdb orafce pgtt session_variable pg_statement_rollback pg_dbms_metadata pg_dbms_lock pgmemcache #pg_dbms_job #wiltondb
          - pglogical pglogical_ticker pgl_ddl_deploy pg_failover_slots db_migrator wal2json wal2mongo decoderbufs decoder_raw mimeo pg_fact_loader pg_bulkload #repmgr

    redis-ms: # redis classic primary & replica
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' }, 6381: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

    # ./mongo.yml -l pg-mongo
    pg-mongo:
      hosts: { 10.10.10.10: { mongo_seq: 1 } }
      vars:
        mongo_cluster: pg-mongo
        mongo_pgurl: 'postgres://dbuser_meta:[email protected]:5432/grafana'

    # ./kafka.yml -l kf-main
    kf-main:
      hosts: { 10.10.10.10: { kafka_seq: 1, kafka_role: controller } }
      vars:
        kafka_cluster: kf-main
        kafka_peer_port: 9093


  vars:                               # global variables
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: china                     # upstream mirror region: default|china|europe

    infra_portal:                     # infra services exposed via portal
      home         : { domain: i.pigsty }     # default domain name
      cc           : { domain: pigsty.cc      ,path:     "/www/pigsty.cc"   ,cert: /etc/cert/pigsty.cc.crt ,key: /etc/cert/pigsty.cc.key }
      minio        : { domain: m.pigsty.cc    ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      postgrest    : { domain: api.pigsty.cc  ,endpoint: "127.0.0.1:8884"   }
      pgadmin      : { domain: adm.pigsty.cc  ,endpoint: "127.0.0.1:8885"   }
      pgweb        : { domain: cli.pigsty.cc  ,endpoint: "127.0.0.1:8886"   }
      bytebase     : { domain: ddl.pigsty.cc  ,endpoint: "127.0.0.1:8887"   }
      jupyter      : { domain: lab.pigsty.cc  ,endpoint: "127.0.0.1:8888", websocket: true }
      gitea        : { domain: git.pigsty.cc  ,endpoint: "127.0.0.1:8889" }
      wiki         : { domain: wiki.pigsty.cc ,endpoint: "127.0.0.1:9002" }
      noco         : { domain: noco.pigsty.cc ,endpoint: "127.0.0.1:9003" }
      supa         : { domain: supa.pigsty.cc ,endpoint: "10.10.10.10:8000" ,websocket: true }
      dify         : { domain: dify.pigsty.cc ,endpoint: "10.10.10.10:8001" ,websocket: true }
      odoo         : { domain: odoo.pigsty.cc ,endpoint: "127.0.0.1:8069"   ,websocket: true }
      mm           : { domain: mm.pigsty.cc   ,endpoint: "10.10.10.10:8065" ,websocket: true }
    # scp -r ~/pgsty/cc/cert/*       pj:/etc/cert/       # copy https certs
    # scp -r ~/dev/pigsty.cc/public  pj:/www/pigsty.cc   # copy pigsty.cc website


    node_etc_hosts: [ "${admin_ip} sss.pigsty" ]
    node_timezone: Asia/Hong_Kong
    node_ntp_servers:
      - pool cn.pool.ntp.org iburst
      - pool ${admin_ip} iburst       # assume non-admin nodes does not have internet access
    pgbackrest_enabled: false         # do not take backups since this is disposable demo env
    #prometheus_options: '--storage.tsdb.retention.time=15d' # prometheus extra server options
    prometheus_options: '--storage.tsdb.retention.size=3GB' # keep 3GB data at most on demo env

    # install all postgresql18 extensions
    pg_version: 18                    # default postgres version
    repo_extra_packages: [ pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_extensions: [pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl ] #,pg18-olap]

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The demo/demo template is Pigsty’s public demo configuration, showcasing a complete production-grade deployment example.

Key Features:

  • HTTPS certificate and custom domain configuration
  • All available PostgreSQL extensions installed
  • Integration with Redis, FerretDB, Kafka, and other components
  • Docker image acceleration configured

Use Cases:

  • Setting up public demo sites
  • Scenarios requiring complete feature demonstration
  • Learning Pigsty advanced configuration

Notes:

  • SSL certificate files must be prepared
  • DNS resolution must be configured
  • Some extensions are not available on ARM64 architecture

8.34 - demo/minio

Four-node x four-drive high-availability multi-node multi-disk MinIO cluster demo

The demo/minio configuration template demonstrates how to deploy a four-node x four-drive, 16-disk total high-availability MinIO cluster, providing S3-compatible object storage services.

For more tutorials, see the MINIO module documentation.


Overview

  • Config Name: demo/minio
  • Node Count: Four nodes
  • Description: High-availability multi-node multi-disk MinIO cluster demo
  • OS Distro: el8, el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c demo/minio

Note: This is a four-node template. You need to modify the IP addresses of the other three nodes after generating the configuration.


Content

Source: pigsty/conf/demo/minio.yml

---
#==============================================================#
# File      :   minio.yml
# Desc      :   pigsty: 4 node x 4 disk MNMD minio clusters
# Ctime     :   2023-01-07
# Mtime     :   2025-12-12
# Docs      :   https://doc.pgsty.com/config
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# One pass installation with:
# ./deploy.yml
#==============================================================#
# 1.  minio-1 @ 10.10.10.10:9000 -  - (9002) svc <-x  10.10.10.9:9002
# 2.  minio-2 @ 10.10.10.11:9000 -xx- (9002) svc <-x <----------------
# 3.  minio-3 @ 10.10.10.12:9000 -xx- (9002) svc <-x  sss.pigsty:9002
# 4.  minio-4 @ 10.10.10.12:9000 -  - (9002) svc <-x  (intranet dns)
#==============================================================#
# use minio load balancer service (9002) instead of direct access (9000)
# mcli alias set sss https://sss.pigsty:9002 minioadmin S3User.MinIO
#==============================================================#
# https://min.io/docs/minio/linux/operations/install-deploy-manage/deploy-minio-multi-node-multi-drive.html
# MINIO_VOLUMES="https://minio-{1...4}.pigsty:9000/data{1...4}/minio"


all:
  children:

    # infra cluster for proxy, monitor, alert, etc..
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

    # minio cluster with 4 nodes and 4 drivers per node
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1 , nodename: minio-1 }
        10.10.10.11: { minio_seq: 2 , nodename: minio-2 }
        10.10.10.12: { minio_seq: 3 , nodename: minio-3 }
        10.10.10.13: { minio_seq: 4 , nodename: minio-4 }
      vars:
        minio_cluster: minio
        minio_data: '/data{1...4}'
        minio_buckets:                    # list of minio bucket to be created
          - { name: pgsql }
          - { name: meta ,versioning: true }
          - { name: data }
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

        # bind a node l2 vip (10.10.10.9) to minio cluster (optional)
        node_cluster: minio
        vip_enabled: true
        vip_vrid: 128
        vip_address: 10.10.10.9
        vip_interface: eth1

        # expose minio service with haproxy on all nodes
        haproxy_services:
          - name: minio                    # [REQUIRED] service name, unique
            port: 9002                     # [REQUIRED] service port, unique
            balance: leastconn             # [OPTIONAL] load balancer algorithm
            options:                       # [OPTIONAL] minio health check
              - option httpchk
              - option http-keep-alive
              - http-check send meth OPTIONS uri /minio/health/live
              - http-check expect status 200
            servers:
              - { name: minio-1 ,ip: 10.10.10.10 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-2 ,ip: 10.10.10.11 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-3 ,ip: 10.10.10.12 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-4 ,ip: 10.10.10.13 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

  vars:
    version: v4.0.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

      # domain names to access minio web console via nginx web portal (optional)
      minio        : { domain: m.pigsty     ,endpoint: "10.10.10.10:9001" ,scheme: https ,websocket: true }
      minio10      : { domain: m10.pigsty   ,endpoint: "10.10.10.10:9001" ,scheme: https ,websocket: true }
      minio11      : { domain: m11.pigsty   ,endpoint: "10.10.10.11:9001" ,scheme: https ,websocket: true }
      minio12      : { domain: m12.pigsty   ,endpoint: "10.10.10.12:9001" ,scheme: https ,websocket: true }
      minio13      : { domain: m13.pigsty   ,endpoint: "10.10.10.13:9001" ,scheme: https ,websocket: true }

    minio_endpoint: https://sss.pigsty:9002   # explicit overwrite minio endpoint with haproxy port
    node_etc_hosts: ["10.10.10.9 sss.pigsty"] # domain name to access minio from all nodes (required)

    #----------------------------------------------#
    # PASSWORD : https://doc.pgsty.com/config/security
    #----------------------------------------------#
    grafana_admin_password: pigsty
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
...

Explanation

The demo/minio template is a production-grade reference configuration for MinIO, showcasing Multi-Node Multi-Drive (MNMD) architecture.

Key Features:

  • Multi-Node Multi-Drive Architecture: 4 nodes × 4 drives = 16-drive erasure coding group
  • L2 VIP High Availability: Virtual IP binding via Keepalived
  • HAProxy Load Balancing: Unified access endpoint on port 9002
  • Fine-grained Permissions: Separate users and buckets for different applications

Access:

# Configure MinIO alias with mcli (via HAProxy load balancing)
mcli alias set sss https://sss.pigsty:9002 minioadmin S3User.MinIO

# List buckets
mcli ls sss/

# Use console
# Visit https://m.pigsty or https://m10-m13.pigsty

Use Cases:

  • Environments requiring S3-compatible object storage
  • PostgreSQL backup storage (pgBackRest remote repository)
  • Data lake for big data and AI workloads
  • Production environments requiring high-availability object storage

Notes:

  • Each node requires 4 independent disks mounted at /data1 - /data4
  • Production environments recommend at least 4 nodes for erasure coding redundancy
  • VIP requires proper network interface configuration (vip_interface)

8.35 - build/oss

Pigsty open-source edition offline package build environment configuration

The build/oss configuration template is the build environment configuration for Pigsty open-source edition offline packages, used to batch-build offline installation packages across multiple operating systems.

This configuration is intended for developers and contributors only.


Overview

  • Config Name: build/oss
  • Node Count: Six nodes (el9, el10, d12, d13, u22, u24)
  • Description: Pigsty open-source edition offline package build environment
  • OS Distro: el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64

Usage:

cp conf/build/oss.yml pigsty.yml

Note: This is a build template with fixed IP addresses, intended for internal use only.


Content

Source: pigsty/conf/build/oss.yml

---
#==============================================================#
# File      :   oss.yml
# Desc      :   Pigsty 3-node building env (PG18)
# Ctime     :   2024-10-22
# Mtime     :   2025-12-12
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

all:
  vars:
    version: v4.0.0
    admin_ip: 10.10.10.24
    region: china
    etcd_clean: true
    proxy_env:
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn,*.pigsty.cc"

    # building spec
    pg_version: 18
    cache_pkg_dir: 'dist/${version}'
    repo_modules: infra,node,pgsql
    repo_packages: [ node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-utility, extra-modules ]
    repo_extra_packages: [pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_extensions:                 [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap, pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

  children:
    #el8:  { hosts: { 10.10.10.8:  { pg_cluster: el8 ,pg_seq: 1 ,pg_role: primary }}}
    el9:  { hosts: { 10.10.10.9:  { pg_cluster: el9  ,pg_seq: 1 ,pg_role: primary }}}
    el10: { hosts: { 10.10.10.10: { pg_cluster: el10 ,pg_seq: 1 ,pg_role: primary }}}
    d12:  { hosts: { 10.10.10.12: { pg_cluster: d12  ,pg_seq: 1 ,pg_role: primary }}}
    d13:  { hosts: { 10.10.10.13: { pg_cluster: d13  ,pg_seq: 1 ,pg_role: primary }}}
    u22:  { hosts: { 10.10.10.22: { pg_cluster: u22  ,pg_seq: 1 ,pg_role: primary }}}
    u24:  { hosts: { 10.10.10.24: { pg_cluster: u24  ,pg_seq: 1 ,pg_role: primary }}}
    etcd: { hosts: { 10.10.10.24:  { etcd_seq: 1 }}, vars: { etcd_cluster: etcd    }}
    infra:
      hosts:
        #10.10.10.8:  { infra_seq: 1, admin_ip: 10.10.10.8  ,ansible_host: el8  } #, ansible_python_interpreter: /usr/bin/python3.12 }
        10.10.10.9:  { infra_seq: 2, admin_ip: 10.10.10.9  ,ansible_host: el9  }
        10.10.10.10: { infra_seq: 3, admin_ip: 10.10.10.10 ,ansible_host: el10 }
        10.10.10.12: { infra_seq: 4, admin_ip: 10.10.10.12 ,ansible_host: d12  }
        10.10.10.13: { infra_seq: 5, admin_ip: 10.10.10.13 ,ansible_host: d13  }
        10.10.10.22: { infra_seq: 6, admin_ip: 10.10.10.22 ,ansible_host: u22  }
        10.10.10.24: { infra_seq: 7, admin_ip: 10.10.10.24 ,ansible_host: u24  }
      vars: { node_conf: oltp }

...

Explanation

The build/oss template is the build configuration for Pigsty open-source edition offline packages.

Build Contents:

  • PostgreSQL 18 and all categorized extension packages
  • Infrastructure packages (Prometheus, Grafana, Nginx, etc.)
  • Node packages (monitoring agents, tools, etc.)
  • Extra modules

Supported Operating Systems:

  • EL9 (Rocky/Alma/RHEL 9)
  • EL10 (Rocky 10 / RHEL 10)
  • Debian 12 (Bookworm)
  • Debian 13 (Trixie)
  • Ubuntu 22.04 (Jammy)
  • Ubuntu 24.04 (Noble)

Build Process:

# 1. Prepare build environment
cp conf/build/oss.yml pigsty.yml

# 2. Download packages on each node
./infra.yml -t repo_build

# 3. Package offline installation files
make cache

Use Cases:

  • Pigsty developers building new versions
  • Contributors testing new extensions
  • Enterprise users customizing offline packages

8.36 - build/pro

Pigsty professional edition offline package build environment configuration (multi-version)

The build/pro configuration template is the build environment configuration for Pigsty professional edition offline packages, including PostgreSQL 13-18 all versions and additional commercial components.

This configuration is intended for developers and contributors only.


Overview

  • Config Name: build/pro
  • Node Count: Six nodes (el9, el10, d12, d13, u22, u24)
  • Description: Pigsty professional edition offline package build environment (multi-version)
  • OS Distro: el9, el10, d12, d13, u22, u24
  • OS Arch: x86_64

Usage:

cp conf/build/pro.yml pigsty.yml

Note: This is a build template with fixed IP addresses, intended for internal use only.


Content

Source: pigsty/conf/build/pro.yml

---
#==============================================================#
# File      :   pro.yml
# Desc      :   Pigsty 6-node pro building env (PG 13-18)
# Ctime     :   2024-10-22
# Mtime     :   2025-12-15
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

all:
  vars:
    version: v4.0.0
    admin_ip: 10.10.10.24
    region: china
    etcd_clean: true
    proxy_env:
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn,*.pigsty.cc"

    # building spec
    pg_version: 18
    cache_pkg_dir: 'dist/${version}/pro'
    repo_modules: infra,node,pgsql
    pg_extensions: []
    repo_packages: [
      node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-utility, extra-modules,
      pg18-full,pg18-time,pg18-gis,pg18-rag,pg18-fts,pg18-olap,pg18-feat,pg18-lang,pg18-type,pg18-util,pg18-func,pg18-admin,pg18-stat,pg18-sec,pg18-fdw,pg18-sim,pg18-etl,
      pg17-full,pg17-time,pg17-gis,pg17-rag,pg17-fts,pg17-olap,pg17-feat,pg17-lang,pg17-type,pg17-util,pg17-func,pg17-admin,pg17-stat,pg17-sec,pg17-fdw,pg17-sim,pg17-etl,
      pg16-full,pg16-time,pg16-gis,pg16-rag,pg16-fts,pg16-olap,pg16-feat,pg16-lang,pg16-type,pg16-util,pg16-func,pg16-admin,pg16-stat,pg16-sec,pg16-fdw,pg16-sim,pg16-etl,
      pg15-full,pg15-time,pg15-gis,pg15-rag,pg15-fts,pg15-olap,pg15-feat,pg15-lang,pg15-type,pg15-util,pg15-func,pg15-admin,pg15-stat,pg15-sec,pg15-fdw,pg15-sim,pg15-etl,
      pg14-full,pg14-time,pg14-gis,pg14-rag,pg14-fts,pg14-olap,pg14-feat,pg14-lang,pg14-type,pg14-util,pg14-func,pg14-admin,pg14-stat,pg14-sec,pg14-fdw,pg14-sim,pg14-etl,
      pg13-full,pg13-time,pg13-gis,pg13-rag,pg13-fts,pg13-olap,pg13-feat,pg13-lang,pg13-type,pg13-util,pg13-func,pg13-admin,pg13-stat,pg13-sec,pg13-fdw,pg13-sim,pg13-etl,
      infra-extra, kafka, java-runtime, sealos, tigerbeetle, polardb, ivorysql
    ]

  children:
    #el8:  { hosts: { 10.10.10.8:  { pg_cluster: el8 ,pg_seq: 1  ,pg_role: primary }}}
    el9:  { hosts: { 10.10.10.9:  { pg_cluster: el9  ,pg_seq: 1 ,pg_role: primary }}}
    el10: { hosts: { 10.10.10.10: { pg_cluster: el10 ,pg_seq: 1 ,pg_role: primary }}}
    d12:  { hosts: { 10.10.10.12: { pg_cluster: d12  ,pg_seq: 1 ,pg_role: primary }}}
    d13:  { hosts: { 10.10.10.13: { pg_cluster: d13  ,pg_seq: 1 ,pg_role: primary }}}
    u22:  { hosts: { 10.10.10.22: { pg_cluster: u22  ,pg_seq: 1 ,pg_role: primary }}}
    u24:  { hosts: { 10.10.10.24: { pg_cluster: u24  ,pg_seq: 1 ,pg_role: primary }}}
    etcd: { hosts: { 10.10.10.24:  { etcd_seq: 1 }}, vars: { etcd_cluster: etcd    }}
    infra:
      hosts:
        #10.10.10.8:  { infra_seq: 9, admin_ip: 10.10.10.8  ,ansible_host: el8  } #, ansible_python_interpreter: /usr/bin/python3.12 }
        10.10.10.9:  { infra_seq: 1, admin_ip: 10.10.10.9  ,ansible_host: el9  }
        10.10.10.10: { infra_seq: 2, admin_ip: 10.10.10.10 ,ansible_host: el10 }
        10.10.10.12: { infra_seq: 3, admin_ip: 10.10.10.12 ,ansible_host: d12  }
        10.10.10.13: { infra_seq: 4, admin_ip: 10.10.10.13 ,ansible_host: d13  }
        10.10.10.22: { infra_seq: 5, admin_ip: 10.10.10.22 ,ansible_host: u22  }
        10.10.10.24: { infra_seq: 6, admin_ip: 10.10.10.24 ,ansible_host: u24  }
      vars: { node_conf: oltp }

...

Explanation

The build/pro template is the build configuration for Pigsty professional edition offline packages, containing more content than the open-source edition.

Differences from OSS Edition:

  • Includes all six major PostgreSQL versions 13-18
  • Includes additional commercial/enterprise components: Kafka, PolarDB, IvorySQL, etc.
  • Includes Java runtime and Sealos tools
  • Output directory is dist/${version}/pro/

Build Contents:

  • PostgreSQL 13, 14, 15, 16, 17, 18 all versions
  • All categorized extension packages for each version
  • Kafka message queue
  • PolarDB and IvorySQL kernels
  • TigerBeetle distributed database
  • Sealos container platform

Use Cases:

  • Enterprise customers requiring multi-version support
  • Need for Oracle/MySQL compatible kernels
  • Need for Kafka message queue integration
  • Long-term support versions (LTS) requirements

Build Process:

# 1. Prepare build environment
cp conf/build/pro.yml pigsty.yml

# 2. Download packages on each node
./infra.yml -t repo_build

# 3. Package offline installation files
make cache-pro

9 - Modules

10 - Module: PGSQL

Deploy and manage world’s most advanced open-source relational database — PostgreSQL, customizable and production-ready!

The world’s most advanced open-source relational database!

Pigsty brings it to full potential: batteries-included, reliable, observable, maintainable, and scalable! Config | Admin | Playbooks | Dashboards | Parameters


Overview

Learn key topics and concepts about PostgreSQL.


Config

Describe your desired PostgreSQL cluster


Admin

Manage your PostgreSQL clusters.


Playbooks

Use idempotent playbooks to materialize your config.

Example: Install PGSQL Module

asciicast

Example: Remove PGSQL Module

asciicast


Monitoring

Check PostgreSQL status via Grafana dashboards.

Pigsty has 26 PostgreSQL-related dashboards:

OverviewClusterInstanceDatabase
PGSQL OverviewPGSQL ClusterPGSQL InstancePGSQL Database
PGSQL AlertPGRDS ClusterPGRDS InstancePGCAT Database
PGSQL ShardPGSQL ActivityPGCAT InstancePGSQL Tables
PGSQL ReplicationPGSQL PersistPGSQL Table
PGSQL ServicePGSQL ProxyPGCAT Table
PGSQL DatabasesPGSQL PgbouncerPGSQL Query
PGSQL PatroniPGSQL SessionPGCAT Query
PGSQL PITRPGSQL XactsPGCAT Locks
PGSQL ExporterPGCAT Schema

Parameters

Config params for the PGSQL module

  • PG_ID: Calculate & validate PostgreSQL instance identity
  • PG_BUSINESS: PostgreSQL biz object definitions
  • PG_INSTALL: Install PostgreSQL kernel, pkgs & extensions
  • PG_BOOTSTRAP: Init HA PostgreSQL cluster with Patroni
  • PG_PROVISION: Create PostgreSQL users, databases & in-db objects
  • PG_BACKUP: Setup backup repo with pgbackrest
  • PG_ACCESS: Expose PostgreSQL services, bindVIP (optional), register DNS
  • PG_MONITOR: Add monitoring for PostgreSQL instance and register to infra
  • PG_REMOVE: Remove PostgreSQL cluster, instance and related resources
Full Parameter List
ParameterSectionTypeLevelDescription
pg_modePG_IDenumCpgsql cluster mode: pgsql,citus,gpsql
pg_clusterPG_IDstringCpgsql cluster name, REQUIRED identity param
pg_seqPG_IDintIpgsql instance seq number, REQUIRED identity param
pg_rolePG_IDenumIpgsql role, REQUIRED, could be primary,replica,offline
pg_instancesPG_IDdictIdefine multiple pg instances on node in {port:ins_vars} format
pg_upstreamPG_IDipIrepl upstream ip for standby cluster or cascade replica
pg_shardPG_IDstringCpgsql shard name, optional identity for sharding clusters
pg_groupPG_IDintCpgsql shard index number, optional identity for sharding clusters
gp_rolePG_IDenumCgreenplum role of this cluster, could be master or segment
pg_exportersPG_IDdictCadditional pg_exporters to monitor remote postgres instances
pg_offline_queryPG_IDboolIset true to enable offline query on this instance
pg_usersPG_BUSINESSuser[]Cpostgres biz users
pg_databasesPG_BUSINESSdatabase[]Cpostgres biz databases
pg_servicesPG_BUSINESSservice[]Cpostgres biz services
pg_hba_rulesPG_BUSINESShba[]Cbiz hba rules for postgres
pgb_hba_rulesPG_BUSINESShba[]Cbiz hba rules for pgbouncer
pg_replication_usernamePG_BUSINESSusernameGpostgres replication username, replicator by default
pg_replication_passwordPG_BUSINESSpasswordGpostgres replication password, DBUser.Replicator by default
pg_admin_usernamePG_BUSINESSusernameGpostgres admin username, dbuser_dba by default
pg_admin_passwordPG_BUSINESSpasswordGpostgres admin password in plain text, DBUser.DBA by default
pg_monitor_usernamePG_BUSINESSusernameGpostgres monitor username, dbuser_monitor by default
pg_monitor_passwordPG_BUSINESSpasswordGpostgres monitor password, DBUser.Monitor by default
pg_dbsu_passwordPG_BUSINESSpasswordG/Cdbsu password, empty string means no dbsu password by default
pg_dbsuPG_INSTALLusernameCos dbsu name, postgres by default, better not change it
pg_dbsu_uidPG_INSTALLintCos dbsu uid and gid, 26 for default postgres users and groups
pg_dbsu_sudoPG_INSTALLenumCdbsu sudo privilege, none,limit,all,nopass. limit by default
pg_dbsu_homePG_INSTALLpathCpostgresql home dir, /var/lib/pgsql by default
pg_dbsu_ssh_exchangePG_INSTALLboolCexchange postgres dbsu ssh key among same pgsql cluster
pg_versionPG_INSTALLenumCpostgres major version to install, 18 by default
pg_bin_dirPG_INSTALLpathCpostgres binary dir, /usr/pgsql/bin by default
pg_log_dirPG_INSTALLpathCpostgres log dir, /pg/log/postgres by default
pg_packagesPG_INSTALLstring[]Cpg pkgs to install, ${pg_version} will be replaced
pg_extensionsPG_INSTALLstring[]Cpg extensions to install, ${pg_version} will be replaced
pg_cleanPG_BOOTSTRAPboolG/C/Apurge existing postgres during pgsql init? true by default
pg_dataPG_BOOTSTRAPpathCpostgres data dir, /pg/data by default
pg_fs_mainPG_BOOTSTRAPpathCmountpoint/path for postgres main data, /data by default
pg_fs_bkupPG_BOOTSTRAPpathCmountpoint/path for pg backup data, /data/backup by default
pg_storage_typePG_BOOTSTRAPenumCstorage type for pg main data, SSD,HDD, SSD by default
pg_dummy_filesizePG_BOOTSTRAPsizeCsize of /pg/dummy, hold 64MB disk space for emergency use
pg_listenPG_BOOTSTRAPip(s)C/Ipostgres/pgbouncer listen addr, comma separated list
pg_portPG_BOOTSTRAPportCpostgres listen port, 5432 by default
pg_localhostPG_BOOTSTRAPpathCpostgres unix socket dir for localhost connection
pg_namespacePG_BOOTSTRAPpathCtop level key namespace in etcd, used by patroni & vip
patroni_enabledPG_BOOTSTRAPboolCif disabled, no postgres cluster will be created during init
patroni_modePG_BOOTSTRAPenumCpatroni working mode: default,pause,remove
patroni_portPG_BOOTSTRAPportCpatroni listen port, 8008 by default
patroni_log_dirPG_BOOTSTRAPpathCpatroni log dir, /pg/log/patroni by default
patroni_ssl_enabledPG_BOOTSTRAPboolGsecure patroni RestAPI comms with SSL?
patroni_watchdog_modePG_BOOTSTRAPenumCpatroni watchdog mode: automatic,required,off. off by default
patroni_usernamePG_BOOTSTRAPusernameCpatroni restapi username, postgres by default
patroni_passwordPG_BOOTSTRAPpasswordCpatroni restapi password, Patroni.API by default
pg_etcd_passwordPG_BOOTSTRAPpasswordCetcd password for this pg cluster, empty to use pg_cluster
pg_primary_dbPG_BOOTSTRAPstringCprimary database in this cluster, optional, postgres by default
pg_parametersPG_BOOTSTRAPdictCextra params in postgresql.auto.conf
pg_filesPG_BOOTSTRAPpath[]Cextra files to copy to postgres data dir
pg_confPG_BOOTSTRAPenumCconfig template: oltp,olap,crit,tiny. oltp.yml by default
pg_max_connPG_BOOTSTRAPintCpostgres max connections, auto will use recommended value
pg_shared_buffer_ratioPG_BOOTSTRAPfloatCpostgres shared buffer mem ratio, 0.25 by default, 0.1~0.4
pg_io_methodPG_BOOTSTRAPenumCio method for postgres: auto,sync,worker,io_uring, worker by default
pg_rtoPG_BOOTSTRAPintCrecovery time objective in seconds, 30s by default
pg_rpoPG_BOOTSTRAPintCrecovery point objective in bytes, 1MiB at most by default
pg_libsPG_BOOTSTRAPstringCpreloaded libs, timescaledb,pg_stat_statements,auto_explain by default
pg_delayPG_BOOTSTRAPintervalIreplication apply delay for standby cluster leader
pg_checksumPG_BOOTSTRAPboolCenable data checksum for postgres cluster?
pg_pwd_encPG_BOOTSTRAPenumCpassword encryption algo: md5,scram-sha-256
pg_encodingPG_BOOTSTRAPenumCdatabase cluster encoding, UTF8 by default
pg_localePG_BOOTSTRAPenumCdatabase cluster locale, C by default
pg_lc_collatePG_BOOTSTRAPenumCdatabase cluster collate, C by default
pg_lc_ctypePG_BOOTSTRAPenumCdatabase char type, C by default
pgsodium_keyPG_BOOTSTRAPstringCpgsodium key, 64 hex digit, default to sha256(pg_cluster)
pgsodium_getkey_scriptPG_BOOTSTRAPpathCpgsodium getkey script path
pgbouncer_enabledPG_ACCESSboolCif disabled, pgbouncer will not be launched on pgsql host
pgbouncer_portPG_ACCESSportCpgbouncer listen port, 6432 by default
pgbouncer_log_dirPG_ACCESSpathCpgbouncer log dir, /pg/log/pgbouncer by default
pgbouncer_auth_queryPG_ACCESSboolCquery postgres to retrieve unlisted biz users?
pgbouncer_poolmodePG_ACCESSenumCpooling mode: transaction,session,statement, transaction by default
pgbouncer_sslmodePG_ACCESSenumCpgbouncer client ssl mode, disable by default
pgbouncer_ignore_paramPG_ACCESSstring[]Cpgbouncer ignore_startup_parameters list
pg_provisionPG_PROVISIONboolCprovision postgres cluster after bootstrap
pg_initPG_PROVISIONstringG/Cprovision init script for cluster template, pg-init by default
pg_default_rolesPG_PROVISIONrole[]G/Cdefault roles and users in postgres cluster
pg_default_privilegesPG_PROVISIONstring[]G/Cdefault privileges when created by admin user
pg_default_schemasPG_PROVISIONstring[]G/Cdefault schemas to be created
pg_default_extensionsPG_PROVISIONextension[]G/Cdefault extensions to be created
pg_reloadPG_PROVISIONboolAreload postgres after hba changes
pg_default_hba_rulesPG_PROVISIONhba[]G/Cpostgres default host-based auth rules
pgb_default_hba_rulesPG_PROVISIONhba[]G/Cpgbouncer default host-based auth rules
pgbackrest_enabledPG_BACKUPboolCenable pgbackrest on pgsql host?
pgbackrest_cleanPG_BACKUPboolCremove pg backup data during init?
pgbackrest_log_dirPG_BACKUPpathCpgbackrest log dir, /pg/log/pgbackrest by default
pgbackrest_methodPG_BACKUPenumCpgbackrest repo method: local,minio,etc…
pgbackrest_init_backupPG_BACKUPboolCtake a full backup after pgbackrest init?
pgbackrest_repoPG_BACKUPdictG/Cpgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
pg_weightPG_ACCESSintIrelative load balance weight in service, 100 by default, 0-255
pg_service_providerPG_ACCESSenumG/Cdedicated haproxy node group name, or empty string for local nodes by default
pg_default_service_destPG_ACCESSenumG/Cdefault service dest if svc.dest=‘default’
pg_default_servicesPG_ACCESSservice[]G/Cpostgres default service definitions
pg_vip_enabledPG_ACCESSboolCenable L2 VIP for pgsql primary? false by default
pg_vip_addressPG_ACCESScidr4Cvip addr in <ipv4>/<mask> format, required if vip is enabled
pg_vip_interfacePG_ACCESSstringC/Ivip network interface to listen, eth0 by default
pg_dns_suffixPG_ACCESSstringCpgsql dns suffix, ’’ by default
pg_dns_targetPG_ACCESSenumCauto, primary, vip, none, or ad hoc ip
pg_exporter_enabledPG_MONITORboolCenable pg_exporter on pgsql hosts?
pg_exporter_configPG_MONITORstringCpg_exporter config file name
pg_exporter_cache_ttlsPG_MONITORstringCpg_exporter collector ttl stage in seconds, ‘1,10,60,300’ by default
pg_exporter_portPG_MONITORportCpg_exporter listen port, 9630 by default
pg_exporter_paramsPG_MONITORstringCextra url params for pg_exporter dsn
pg_exporter_urlPG_MONITORpgurlCoverwrite auto-gen pg dsn if specified
pg_exporter_auto_discoveryPG_MONITORboolCenable auto database discovery? enabled by default
pg_exporter_exclude_databasePG_MONITORstringCcsv of database that WILL NOT be monitored during auto-discovery
pg_exporter_include_databasePG_MONITORstringCcsv of database that WILL BE monitored during auto-discovery
pg_exporter_connect_timeoutPG_MONITORintCpg_exporter connect timeout in ms, 200 by default
pg_exporter_optionsPG_MONITORargCoverwrite extra options for pg_exporter
pgbouncer_exporter_enabledPG_MONITORboolCenable pgbouncer_exporter on pgsql hosts?
pgbouncer_exporter_portPG_MONITORportCpgbouncer_exporter listen port, 9631 by default
pgbouncer_exporter_urlPG_MONITORpgurlCoverwrite auto-gen pgbouncer dsn if specified
pgbouncer_exporter_optionsPG_MONITORargCoverwrite extra options for pgbouncer_exporter
pgbackrest_exporter_enabledPG_MONITORboolCenable pgbackrest_exporter on pgsql hosts?
pgbackrest_exporter_portPG_MONITORportCpgbackrest_exporter listen port, 9854 by default
pgbackrest_exporter_optionsPG_MONITORargCoverwrite extra options for pgbackrest_exporter
pg_safeguardPG_REMOVEboolG/C/Aprevent purging running postgres instance? false by default
pg_rm_dataPG_REMOVEboolG/C/Aremove postgres data during remove? true by default
pg_rm_backupPG_REMOVEboolG/C/Aremove pgbackrest backup during primary remove? true by default
pg_rm_pkgPG_REMOVEboolG/C/Auninstall postgres pkgs during remove? true by default

Tutorials

Tutorials for using/managing PostgreSQL in Pigsty.

  • Clone an existing PostgreSQL cluster
  • Create an online standby cluster of existing PostgreSQL cluster
  • Create a delayed standby cluster of existing PostgreSQL cluster
  • Monitor an existing postgres instance
  • Migrate from external PostgreSQL to Pigsty-managed PostgreSQL using logical replication
  • Use MinIO as centralized pgBackRest backup repo
  • Use dedicated etcd cluster as PostgreSQL / Patroni DCS
  • Use dedicated haproxy load balancer cluster to expose PostgreSQL services
  • Use pg-meta CMDB instead of pigsty.yml as inventory source
  • Use PostgreSQL as Grafana backend storage
  • Use PostgreSQL as Prometheus backend storage

10.1 - Core Concepts

Core concepts and architecture design

10.2 - Architecture

Introduction to the overall architecture and implementation details of PostgreSQL clusters.

10.2.1 - Entity-Relationship

Introduction to the entity-relationship model, ER diagram, entity definitions, and naming conventions for PostgreSQL clusters in Pigsty.

First understand “what objects exist and how they reference each other” before discussing deployment and operations. Pigsty’s PGSQL module is built around a stable ER diagram of several core entities. Understanding this diagram helps you design clear configurations and automation workflows.

The PGSQL module organizes in the form of clusters in production environments. These clusters are logical entities composed of a group of database instances associated through primary-replica relationships.

Each cluster is an autonomous business unit consisting of at least one primary instance and exposes capabilities through services.

There are four types of core entities in Pigsty’s PGSQL module:

  • Cluster: An autonomous PostgreSQL business unit, serving as the top-level namespace for other entities.
  • Service: A named abstraction for exposing capabilities, routing traffic, and exposing services via node ports.
  • Instance: A single PostgreSQL server consisting of running processes and database files on a single node.
  • Node: An abstraction of hardware resources running Linux + Systemd environment, which can be bare metal, VMs, containers, or Pods.

Together with two business entities “Database” and “Role”, they form a complete logical view, as shown below:

pigsty-er.jpg

Naming Conventions (following Pigsty’s early constraints)

  • Cluster names should be valid DNS domain names without any dots, matching the regex: [a-zA-Z0-9-]+
  • Service names should be prefixed with the cluster name and suffixed with specific words: primary, replica, offline, delayed, connected with -.
  • Instance names are prefixed with the cluster name and suffixed with a positive integer instance number, connected with -, e.g., ${cluster}-${seq}.
  • Nodes are identified by their primary internal IP address. Since the PGSQL module deploys database and host 1:1, the hostname is typically the same as the instance name.

10.2.2 - Components

Introduction to the components in PostgreSQL clusters in Pigsty, as well as their interactions and dependencies.

Overview

The following is a detailed description of PostgreSQL module components and their interactions, from top to bottom:

  • Cluster DNS is resolved by DNSMASQ on infra nodes
  • Cluster VIP is managed by the vip-manager component, which binds pg_vip_address to the cluster primary node.
    • vip-manager obtains cluster leader information written by patroni from the etcd cluster
  • Cluster services are exposed by Haproxy on nodes, with different services distinguished by different node ports (543x).
    • Haproxy port 9101: monitoring metrics & statistics & admin page
    • Haproxy port 5433: routes to primary pgbouncer by default: read-write service
    • Haproxy port 5434: routes to replica pgbouncer by default: read-only service
    • Haproxy port 5436: routes to primary postgres by default: default service
    • Haproxy port 5438: routes to offline postgres by default: offline service
    • HAProxy routes traffic based on health check information provided by patroni.
  • Pgbouncer is a connection pool middleware that listens on port 6432 by default, capable of buffering connections, exposing additional metrics, and providing extra flexibility.
    • Pgbouncer is stateless and deployed 1:1 with the Postgres server via local Unix socket.
    • Production traffic (primary/replica) will go through pgbouncer by default (can be skipped by specifying pg_default_service_dest)
    • Default/offline services will always bypass pgbouncer and connect directly to the target Postgres.
  • PostgreSQL listens on port 5432, providing relational database services
    • Installing the PGSQL module on multiple nodes with the same cluster name will automatically form a high-availability cluster based on streaming replication
    • PostgreSQL processes are managed by patroni by default.
  • Patroni listens on port 8008 by default, supervising the PostgreSQL server process
    • Patroni spawns the Postgres server as a child process
    • Patroni uses etcd as DCS: storing configuration, fault detection, and leader election.
    • Patroni provides Postgres information through health checks (such as primary/replica), and HAProxy uses this information to distribute service traffic
    • Patroni metrics will be scraped by VictoriaMetrics on infra nodes
  • PG Exporter exposes postgres metrics on port 9630
    • PostgreSQL metrics will be scraped by VictoriaMetrics on infra nodes
  • Pgbouncer Exporter exposes pgbouncer metrics on port 9631
    • Pgbouncer metrics will be scraped by VictoriaMetrics on infra nodes
  • pgBackRest uses local backup repository by default (pgbackrest_method = local)
    • If local (default) is used as the backup repository, pgBackRest will create a local repository under the primary node’s pg_fs_bkup
    • If minio is used as the backup repository, pgBackRest will create a backup repository on a dedicated MinIO cluster: pgbackrest_repo.minio
  • Postgres-related logs (postgres, pgbouncer, patroni, pgbackrest) are collected by vector
    • Vector listens on port 9598 and also exposes its own monitoring metrics to VictoriaMetrics on infra nodes
    • Vector sends logs to VictoriaLogs on infra nodes

Cluster DNS

Cluster DNS service is maintained by DNSMASQ on infra nodes, providing stable FQDNs (<cluster>.<pg_dns_suffix>) for each pg_cluster. DNS records point to the primary or VIP, for access by business sides, automation processes, and cross-cluster data services without needing to directly care about real-time node IPs. DNS relies on inventory information written during deployment and only updates during VIP or primary node drift at runtime. Its upstream is vip-manager and the primary node status in etcd.

DNS’s downstream includes clients and third-party service endpoints, and it also provides unified target addresses for intermediate layers like HAProxy. This component is optional; it can be skipped when the cluster runs in an isolated network or when business ends directly use IPs, but it is recommended for most production environments to avoid hard-coding node addresses.

Key Parameters

  • pg_dns_suffix: Defines the unified suffix for cluster DNS records.
  • pg_dns_target: Controls whether the resolution target points to VIP, primary, or explicit IP.

Primary Virtual IP (vip-manager)

vip-manager runs on each PG node, monitors the leader key written by Patroni in etcd, and binds pg_vip_address to the current primary node, achieving transparent L2 drift. It depends on the health status of the DCS and requires that the target network interface can be controlled by the current node, so that VIP is immediately released and rebound during failover, ensuring the old primary does not continue responding.

VIP’s downstream includes DNS, self-built clients, legacy systems, and other accessors needing fixed endpoints. This component is optional: only enabled when pg_vip_enabled is true and business requires static addresses. When enabled, all participating nodes must have the same VLAN access, otherwise VIP cannot drift correctly.

Key Parameters

Service Entry and Traffic Scheduling (HAProxy)

HAProxy is installed on PG nodes (or dedicated service nodes), uniformly exposing database service port groups: 5433/5434 (read-write/read-only, via Pgbouncer), 5436/5438 (direct primary/offline), and 9101 management interface. Each backend pool relies on role and health information provided by patroni REST API for routing decisions and forwards traffic to corresponding instances or connection pools.

This component is the entry point for the entire cluster, with downstream directly facing applications, ETL, and management tools. You can point pg_service_provider to dedicated HA nodes to carry higher traffic, or publish locally on instances. HAProxy has no dependency on VIP but usually works with DNS and VIP to create a unified access point. Service definitions are composed of pg_default_services and pg_services, allowing fine-grained configuration of ports, load balancing strategies, and targets.

Key Parameters

  • pg_default_services: Defines global default service ports, targets, and check methods.
  • pg_services: Appends or overrides business services for specific clusters.
  • pg_service_provider: Specifies HAProxy node group publishing services (empty means local).
  • pg_default_service_dest: Determines whether default service forwards to Pgbouncer or Postgres.
  • pg_weight: Configures a single instance’s weight in specific services.

Connection Pool (Pgbouncer)

Pgbouncer runs in a stateless manner on each instance, preferentially connecting to PostgreSQL via local Unix Socket, used to absorb transient connections, stabilize sessions, and provide additional metrics. Pigsty routes production traffic (5433/5434) via Pgbouncer by default, with only default/offline services bypassing it to directly connect to PostgreSQL. Pgbouncer has no dependency on VIP and can scale independently with HAProxy and Patroni. When Pgbouncer stops, PostgreSQL can still provide direct connection services.

Pgbouncer’s downstream consists of massive short-connection clients and the unified entry HAProxy. It allows dynamic user loading based on auth_query and can configure SSL as needed. Component is optional. When disabled via pgbouncer_enabled, default services will point directly to PostgreSQL, requiring corresponding adjustments to connection counts and session management strategies.

Key Parameters

Database Instance (PostgreSQL)

The PostgreSQL process is the core of the entire module, listening on 5432 by default and managed by Patroni. Installing the PGSQL module on multiple nodes with the same pg_cluster will automatically build a primary-replica topology based on physical streaming replication; primary/replica/offline roles are controlled by pg_role, and multiple instances can run on the same node via pg_instances when necessary. Instances depend on local data disks, OS kernel tuning, and system services provided by the NODE module.

This component’s downstream includes business read-write traffic, pgBackRest, pg_exporter, etc.; upstream includes Patroni, Ansible bootstrap scripts, and metadata in etcd. You can switch OLTP/OLAP configurations via pg_conf templates and define cascading replication via pg_upstream. If using citus/gpsql, further set pg_shard and pg_group. pg_hba_rules and pg_default_hba_rules determine access control policies.

Key Parameters

  • pg_mode: Instance running mode (standard PG, Citus, MSSQL compatibility, etc.).
  • pg_seq: Instance sequence number, used to lock replication topology and service weight.
  • pg_role: Defines instance role (primary/replica/offline).
  • pg_instances: Mapping for deploying multiple instances on a single node.
  • pg_upstream: Cascading replica’s replication source.
  • pg_conf: Loaded configuration template, determining resources and connection limits.
  • pg_hba_rules / pg_default_hba_rules: Access control lists.

High Availability Controller (Patroni + etcd)

Patroni listens on 8008, taking over PostgreSQL’s startup, configuration, and health status, writing leader and member information to etcd (namespace defined by pg_namespace). It is responsible for automatic failover, maintaining replication factor, coordinating parameters, and providing REST API for HAProxy, monitoring, and administrators to query. Patroni can enable watchdog to forcibly isolate the old primary to avoid split-brain.

Patroni’s upstream includes etcd cluster and system services (systemd, Keepalive), and downstream includes vip-manager, HAProxy, Pgbackrest, and monitoring components. You can switch to pause/remove mode via patroni_mode for maintenance or cluster deletion. Disabling Patroni is only used when managing external PG instances.

Key Parameters

Backup Subsystem (pgBackRest)

pgBackRest creates local or remote repositories on the primary for full/incremental backups and WAL archiving. It cooperates with PostgreSQL to execute control commands, supports multiple targets like local disk (default) and MinIO, and can cover PITR, backup chain verification, and remote bootstrap. Upstream is the primary’s data and archive stream, downstream is object storage or local backup disk, and observability provided by pgbackrest_exporter.

Component can run on-demand, usually initiating a full backup immediately after initialization completion; also supports disabling (experimental environments or external backup systems). When enabling minio repository, a reachable object storage service and credentials are needed. Recovery process integrates with Patroni, and replicas can be bootstrapped as new primary or replica via pgbackrest command.

Key Parameters

PostgreSQL Metrics (pg_exporter)

pg_exporter runs on PG nodes, logs in using local socket, exports metrics covering sessions, buffer hits, replication lag, transaction rate, etc., for Prometheus on infra nodes to scrape. It is tightly coupled with PostgreSQL, automatically reconnecting when PostgreSQL restarts, listening externally on 9630 (default). Exporter has no dependency on VIP and decouples from HA topology.

Key Parameters

Connection Pool Metrics (pgbouncer_exporter)

pgbouncer_exporter starts on nodes, reads Pgbouncer’s statistics view, providing metrics for connection pool utilization, wait queue, and hit rate. It depends on Pgbouncer’s admin user and exposes to Prometheus via independent port. If Pgbouncer is disabled, this component should also be disabled.

Key Parameters

Backup Metrics (pgbackrest_exporter)

pgbackrest_exporter parses pgBackRest status on this node, generating metrics for recent backup time, size, type, etc. Prometheus collects these metrics via 9854 (default), combined with alert policies to quickly detect backup expiration or failure. Component depends on pgBackRest metadata directory and should also be disabled when backup system is turned off.

Key Parameters

Log Collection (Vector)

Vector resides on nodes, tracking log directories of PostgreSQL, Pgbouncer, Patroni, and pgBackRest.

Key Parameters (located in NODE module’s VECTOR component)

pigsty-arch

10.2.3 - Identity

Introduction to entity identity identifiers for PostgreSQL clusters in Pigsty: naming conventions, design philosophy, and usage.

Pigsty uses the PG_ID parameter group to assign deterministic identities to each entity in the PGSQL module.


Core Identity Parameters

Three mandatory parameters constitute the minimal ID set for PGSQL:

ParameterLevelPurposeConstraints
pg_clusterClusterBusiness namespace[a-z][a-z0-9-]*
pg_seqInstanceInstance sequence number within clusterIncrementally assigned natural number, unique and non-reusable
pg_roleInstanceReplication roleprimary / replica / offline / delayed
  • pg_cluster determines all derived names: instances, services, monitoring labels.
  • pg_seq binds 1:1 with nodes, expressing topology order and expected priority.
  • pg_role drives Patroni/HAProxy behavior: primary is unique, replica serves online read-only, offline only accepts offline services, delayed is used for delayed clusters.

Pigsty does not provide default values for the above parameters and they must be explicitly specified in the inventory.


Entity Identifiers

Pigsty’s PostgreSQL entity identifiers are automatically generated based on the core identity parameters above:

EntityGeneration RuleExample
Instance{{ pg_cluster }}-{{ pg_seq }}pg-test-1
Service{{ pg_cluster }}-{{ pg_role }}pg-test-primary
Node NameDefaults to instance name, but can be explicitly overriddenpg-test-1

Service suffixes follow built-in conventions: primary, replica, default, offline, delayed, etc. HAProxy/pgbouncer read these identifiers to automatically build routing. Naming maintains prefix consistency, allowing direct queries or filtering via pg-test-*.


Monitoring Label System

In the PGSQL module, all monitoring metrics use the following label system:

  • cls: Cluster name: {{ pg_cluster }}.
  • ins: Instance name: {{ pg_cluster }}-{{ pg_seq }}.
  • ip: IP of the node where the instance resides.

For VictoriaMetrics, the job name for collecting PostgreSQL metrics is fixed as pgsql; The job name for monitoring remote PG instances is fixed as pgrds.

For VictoriaLogs, the job name for collecting PostgreSQL CSV logs is fixed as postgres; The job name for collecting pgbackrest logs is fixed as pgbackrest, while other components collect logs via syslog.


Example: pg-test Identity View

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, pg_offline_query: true }
  vars:
    pg_cluster: pg-test
ClusterSeqRoleNode/IPInstanceService Endpoints
pg-test1primary10.10.10.11pg-test-1pg-test-primary
pg-test2replica10.10.10.12pg-test-2pg-test-replica
pg-test3replica+offline10.10.10.13pg-test-3pg-test-replica / pg-test-offline

Prometheus label example:

pg_up{cls="pg-test", ins="pg-test-1", ip="10.10.10.11", job="pgsql"}
pg_up{cls="pg-test", ins="pg-test-2", ip="10.10.10.12", job="pgsql"}
pg_up{cls="pg-test", ins="pg-test-3", ip="10.10.10.13", job="pgsql"}

10.2.4 - High Availability Cluster

In-depth introduction to the architecture design, component interaction, failure scenarios and recovery mechanisms of PostgreSQL high availability clusters in Pigsty.

Pigsty’s PostgreSQL clusters come with an out-of-the-box high availability solution, powered by Patroni, Etcd, and HAProxy.

When your PostgreSQL cluster contains two or more instances, you gain hardware failure self-healing database high availability capability without any configuration — as long as any instance in the cluster is alive, the cluster can provide complete service to the outside world. Clients only need to connect to any node in the cluster to obtain complete service without worrying about primary-replica topology changes.

With default configuration, the primary failure Recovery Time Objective (RTO) ≈ 30s, Recovery Point Objective (RPO) < 1MB; replica failure RPO = 0, RTO ≈ 0 (brief interruption); in consistency-first mode, zero data loss during failover can be ensured: RPO = 0. All these metrics can be configured on-demand according to your actual hardware conditions and reliability requirements.

Pigsty has built-in HAProxy load balancer for automatic traffic switching, providing various access methods such as DNS/VIP/LVS for clients to choose from. Failover and switchover are almost imperceptible to the business side except for occasional brief interruptions, and applications do not need to modify connection strings and restart. The minimal maintenance window requirement brings great flexibility and convenience: you can perform rolling maintenance and upgrades of the entire cluster without application cooperation. The feature that hardware failures can be handled the next day allows developers, operations, and DBAs to sleep soundly during failures.

Many large organizations and core institutions have been using Pigsty in production environments for a long time. The largest deployment has 25K CPU cores and 220+ PostgreSQL extra-large instances (64c / 512g / 3TB NVMe SSD); in this deployment case, dozens of hardware failures and various incidents occurred within five years, but it still maintained an overall availability record of more than 99.999%.


Architecture Overview

Pigsty’s high availability architecture consists of four core components that work together to achieve automatic failure detection, leader election, and traffic switching:

flowchart TB
    subgraph Client["🖥️ Client Access Layer"]
        C[("Client")]
        ACCESS["DNS / VIP / HAProxy / L4 LVS"]
    end

    subgraph Node1["📦 Node 1"]
        HAP1["HAProxy :9101<br/>Primary :5433 | Replica :5434"]
        subgraph Stack1["Patroni :8008"]
            PG1[("PostgreSQL<br/>[Primary] :5432")]
            PGB1["PgBouncer :6432"]
        end
    end

    subgraph Node2["📦 Node 2"]
        HAP2["HAProxy :9101<br/>Primary :5433 | Replica :5434"]
        subgraph Stack2["Patroni :8008"]
            PG2[("PostgreSQL<br/>[Replica] :5432")]
            PGB2["PgBouncer :6432"]
        end
    end

    subgraph Node3["📦 Node 3"]
        HAP3["HAProxy :9101<br/>Primary :5433 | Replica :5434"]
        subgraph Stack3["Patroni :8008"]
            PG3[("PostgreSQL<br/>[Replica] :5432")]
            PGB3["PgBouncer :6432"]
        end
    end

    subgraph ETCD["🔐 Etcd Cluster (Raft Consensus)"]
        E1[("Etcd-1<br/>:2379")]
        E2[("Etcd-2<br/>:2379")]
        E3[("Etcd-3<br/>:2379")]
    end

    C --> ACCESS
    ACCESS --> HAP1 & HAP2 & HAP3

    HAP1 -.->|"HTTP Health Check"| Stack1
    HAP2 -.->|"HTTP Health Check"| Stack2
    HAP3 -.->|"HTTP Health Check"| Stack3

    HAP1 --> PGB1
    HAP2 --> PGB2
    HAP3 --> PGB3

    PG1 ==>|"Streaming Replication"| PG2
    PG1 ==>|"Streaming Replication"| PG3

    Stack1 <-->|"Leader Lease"| ETCD
    Stack2 <-->|"Leader Lease"| ETCD
    Stack3 <-->|"Leader Lease"| ETCD

    E1 <--> E2 <--> E3
    E1 <--> E3

    style PG1 fill:#4CAF50,color:#fff
    style PG2 fill:#2196F3,color:#fff
    style PG3 fill:#2196F3,color:#fff
    style ETCD fill:#FF9800,color:#fff

Component Details

PostgreSQL

PostgreSQL is the core database service, using standard Streaming Replication to build physical replicas:

  • Primary: Accepts read-write requests, generates WAL logs
  • Replica: Receives WAL in real-time through streaming replication, provides read-only queries
  • Replication Slot: Ensures WAL is not cleaned up prematurely
  • Synchronous Commit: Optional synchronous replication mode, ensuring RPO = 0

Key configuration (dynamically managed by Patroni):

wal_level: logical                    # Enable logical replication level
max_wal_senders: 50                   # Maximum WAL sender processes
max_replication_slots: 50             # Maximum replication slots
hot_standby: on                       # Replica readable
wal_log_hints: on                     # Support pg_rewind
track_commit_timestamp: on            # Track transaction timestamps
synchronous_standby_names: ''         # Synchronous standby list (dynamically managed)

Patroni

Patroni is the core engine of high availability, responsible for managing PostgreSQL lifecycle and cluster state:

Core Responsibilities:

  • Manage PostgreSQL process start/stop and configuration
  • Maintain leader lease
  • Execute automatic failover and switchover
  • Provide REST API for health checks and cluster management
  • Handle replica auto-rebuild and pg_rewind

Key Timing Parameters (controlling RTO):

ParameterDefaultDescription
ttl30sLeader lease validity period, i.e., failure detection time window
loop_wait10sPatroni main loop interval
retry_timeout10sDCS and PostgreSQL operation retry timeout
primary_start_timeout10sPrimary startup timeout
primary_stop_timeout30sPrimary graceful stop timeout (effective in sync mode)

These parameters are uniformly calculated and derived by pg_rto. The default 30s RTO corresponds to:

ttl: 30                               # Leader lease TTL
loop_wait: 10                         # Main loop interval = RTO/3
retry_timeout: 10                     # Retry timeout = RTO/3
primary_start_timeout: 10             # Primary start timeout = RTO/3

Constraint: ttl >= loop_wait + retry_timeout * 2

Health Check Endpoints (used by HAProxy):

EndpointPurposeReturn 200 Condition
/primaryPrimary serviceCurrent node is Leader
/replicaReplica serviceCurrent node is Replica
/read-onlyRead-only serviceNode is readable (primary or replica)
/healthHealth checkPostgreSQL running normally
/leaderLeader checkHolds leader lock
/asyncAsync replicaAsynchronous replication replica
/syncSync replicaSynchronous replication replica

Etcd

Etcd serves as the distributed configuration store (DCS), providing cluster consensus capability:

Core Responsibilities:

  • Store cluster configuration and state information
  • Provide atomic operations for leader election
  • Implement failure detection through lease mechanism
  • Store PostgreSQL dynamic configuration

Storage Structure (using /pg namespace as example):

/pg/
├── <cluster_name>/
│   ├── leader          # Current leader identifier
│   ├── config          # Cluster configuration (DCS configuration)
│   ├── history         # Failover history
│   ├── initialize      # Cluster initialization flag
│   ├── members/        # Member information directory
│   │   ├── pg-test-1   # Instance 1 metadata
│   │   ├── pg-test-2   # Instance 2 metadata
│   │   └── pg-test-3   # Instance 3 metadata
│   └── sync            # Synchronous standby state

Key Configuration:

election_timeout: 1000ms              # Election timeout (affects Etcd's own HA)
heartbeat_interval: 100ms             # Heartbeat interval
quota_backend_bytes: 16GB             # Storage quota
auto_compaction_mode: periodic        # Auto compaction
auto_compaction_retention: 24h        # Retain 24 hours of history

Etcd Cluster Requirements:

  • Must be odd number of nodes: 3, 5, 7 nodes, ensuring majority quorum
  • Recommend independent deployment on management nodes, separated from PostgreSQL nodes
  • Network latency should be kept within 10ms

HAProxy

HAProxy is responsible for service discovery and traffic distribution:

Core Responsibilities:

  • Discover primary/replica roles through HTTP health checks
  • Route traffic to correct backend nodes
  • Provide load balancing and connection pooling functions
  • Implement automatic service failover

Default Service Definitions:

Service NamePortTargetHealth CheckPurpose
primary5433pgbouncer/primaryRead-write service, route to primary
replica5434pgbouncer/read-onlyRead-only service, prefer routing to replica
default5436postgres/primaryDirect connection to primary (bypass connection pool)
offline5438postgres/replicaOffline replica (ETL/backup)

Health Check Configuration:

listen pg-test-primary
    bind *:5433
    mode tcp
    option httpchk
    http-check send meth OPTIONS uri /primary
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3
                   on-marked-down shutdown-sessions slowstart 30s
                   maxconn 3000 maxqueue 128 weight 100
    server pg-test-1 10.10.10.11:6432 check port 8008
    server pg-test-2 10.10.10.12:6432 check port 8008 backup
    server pg-test-3 10.10.10.13:6432 check port 8008 backup

Health Check Timing Parameters (affecting RTO sensitivity):

ParameterDefaultDescription
inter3sNormal check interval
fastinter1sFast check interval after state change
downinter5sCheck interval after node down
rise3Consecutive successes required for node recovery
fall3Consecutive failures required for node down

Traffic Switching Timing (primary failure):

  • Failure detection: fall × inter = 3 × 3s = 9s
  • Fast probing: Once anomaly detected, switch to fastinter (1s)
  • Service recovery: After new primary promoted, rise × fastinter = 3 × 1s = 3s

VIP Manager (Optional)

vip-manager provides optional Layer 2 VIP support:

Working Principle:

  1. Listen to leader key in Etcd (/pg/<cluster>/leader)
  2. When this node becomes leader, bind VIP to specified NIC
  3. Send gratuitous ARP to notify network devices to update MAC mapping
  4. When losing leader status, unbind VIP

Configuration Example:

interval: 1000                        # Check interval (milliseconds)
trigger-key: "/pg/pg-test/leader"     # Etcd key to listen to
trigger-value: "pg-test-1"            # Leader value to match
ip: 10.10.10.100                      # VIP address
netmask: 24                           # Subnet mask
interface: eth0                       # Bind NIC
dcs-type: etcd                        # DCS type
retry-num: 2                          # Retry count
retry-after: 250                      # Retry interval (milliseconds)

Usage Limitations:

  • Requires all nodes in the same Layer 2 network
  • Cloud environments usually don’t support, need to use cloud provider VIP or DNS solutions
  • Switching time about 1-2 seconds

Control Flow and Data Flow

Normal Operation State

Control Flow: Heartbeat and lease management between Patroni and Etcd

flowchart LR
    subgraph Control["⚙️ Control Flow"]
        direction LR
        P1["Patroni<br/>(Primary)"]
        P2["Patroni<br/>(Replica)"]
        ETCD[("Etcd<br/>Cluster")]

        P1 -->|"Renew/Heartbeat"| ETCD
        P2 -->|"Renew/Heartbeat"| ETCD
        ETCD -->|"Lease/Config"| P1
        ETCD -->|"Lease/Config"| P2
    end

    style ETCD fill:#FF9800,color:#fff

Data Flow: Client requests and WAL replication

flowchart LR
    subgraph Data["📊 Data Flow"]
        direction LR
        CLIENT["Client"]
        HAP["HAProxy"]
        PGB["PgBouncer"]
        PG_P[("PostgreSQL<br/>[Primary]")]
        PG_R[("PostgreSQL<br/>[Replica]")]
        PATRONI["Patroni :8008"]

        CLIENT -->|"SQL Request"| HAP
        HAP -->|"Route"| PGB
        PGB --> PG_P
        HAP -.->|"Health Check<br/>/primary /replica"| PATRONI
        PG_P ==>|"WAL Stream"| PG_R
    end

    style PG_P fill:#4CAF50,color:#fff
    style PG_R fill:#2196F3,color:#fff

Failover Process

When primary failure occurs, the system goes through the following phases:

sequenceDiagram
    autonumber
    participant Primary as 🟢 Primary
    participant Patroni_P as Patroni (Primary)
    participant Etcd as 🟠 Etcd Cluster
    participant Patroni_R as Patroni (Replica)
    participant Replica as 🔵 Replica
    participant HAProxy as HAProxy

    Note over Primary: T=0s Primary failure occurs

    rect rgb(255, 235, 235)
        Note right of Primary: Failure Detection Phase (0-10s)
        Primary-x Patroni_P: Process crash
        Patroni_P--x Etcd: Stop lease renewal
        HAProxy--x Patroni_P: Health check fails
        Etcd->>Etcd: Lease countdown starts
    end

    rect rgb(255, 248, 225)
        Note right of Etcd: Election Phase (10-20s)
        Etcd->>Etcd: Lease expires, release leader lock
        Patroni_R->>Etcd: Check eligibility (LSN, replication lag)
        Etcd->>Patroni_R: Grant leader lock
    end

    rect rgb(232, 245, 233)
        Note right of Replica: Promotion Phase (20-30s)
        Patroni_R->>Replica: Execute PROMOTE
        Replica-->>Replica: Promote to new primary
        Patroni_R->>Etcd: Update state
        HAProxy->>Patroni_R: Health check /primary
        Patroni_R-->>HAProxy: 200 OK
    end

    Note over HAProxy: T≈30s Service recovery
    HAProxy->>Replica: Route write traffic to new primary

Key Timing Formula:

RTO ≈ TTL + Election_Time + Promote_Time + HAProxy_Detection

Where:
- TTL = pg_rto (default 30s)
- Election_Time ≈ 1-2s
- Promote_Time ≈ 1-5s
- HAProxy_Detection = fall × inter + rise × fastinter ≈ 12s

Actual RTO usually between 15-40s, depending on:
- Network latency
- Replica WAL replay progress
- PostgreSQL recovery speed

High Availability Deployment Modes

Three-Node Standard Mode

Most recommended production deployment mode, providing complete automatic failover capability:

flowchart TB
    subgraph Cluster["🏢 Three-Node HA Architecture"]
        direction TB

        subgraph Node1["Node 1"]
            E1[("Etcd")]
            H1["HAProxy"]
            P1["Patroni + PostgreSQL<br/>🟢 Primary"]
        end

        subgraph Node2["Node 2"]
            E2[("Etcd")]
            H2["HAProxy"]
            P2["Patroni + PostgreSQL<br/>🔵 Replica"]
        end

        subgraph Node3["Node 3"]
            E3[("Etcd")]
            H3["HAProxy"]
            P3["Patroni + PostgreSQL<br/>🔵 Replica"]
        end
    end

    E1 <-->|"Raft"| E2
    E2 <-->|"Raft"| E3
    E1 <-->|"Raft"| E3

    P1 ==>|"Replication"| P2
    P1 ==>|"Replication"| P3

    style P1 fill:#4CAF50,color:#fff
    style P2 fill:#2196F3,color:#fff
    style P3 fill:#2196F3,color:#fff
    style E1 fill:#FF9800,color:#fff
    style E2 fill:#FF9800,color:#fff
    style E3 fill:#FF9800,color:#fff

Fault Tolerance:

  • ✅ Any 1 node failure: Automatic switch, service continues
  • ⚠️ 2 nodes failure: Manual intervention required

Configuration Example:

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

Five-Node Enhanced Mode

Deployment with higher availability requirements, can tolerate 2 node failures:

flowchart LR
    subgraph Cluster["🏛️ Five-Node HA Architecture"]
        direction TB

        subgraph Row1[""]
            direction LR
            N1["Node 1<br/>Etcd + 🟢 Primary"]
            N2["Node 2<br/>Etcd + 🔵 Replica"]
            N3["Node 3<br/>Etcd + 🔵 Replica"]
            N4["Node 4<br/>Etcd + 🔵 Replica"]
            N5["Node 5<br/>Etcd + 🔵 Replica"]
        end
    end

    N1 ==> N2 & N3 & N4 & N5

    N1 <-.->|"Etcd Raft"| N2
    N2 <-.->|"Etcd Raft"| N3
    N3 <-.->|"Etcd Raft"| N4
    N4 <-.->|"Etcd Raft"| N5

    style N1 fill:#4CAF50,color:#fff
    style N2 fill:#2196F3,color:#fff
    style N3 fill:#2196F3,color:#fff
    style N4 fill:#2196F3,color:#fff
    style N5 fill:#2196F3,color:#fff

Etcd Quorum: 3/5 majority | PostgreSQL: 1 primary 4 replicas

Fault Tolerance:

  • ✅ Any 2 node failures: Automatic switch
  • ⚠️ 3 node failures: Manual intervention required

Use Cases:

  • Financial core systems
  • Cross-datacenter deployment (2+2+1 distribution)
  • Scenarios requiring dedicated offline replicas

Two-Node Semi-HA Mode

Compromise solution when resources are limited, provides limited automatic switching capability:

flowchart TB
    subgraph Cluster["⚠️ Two-Node Semi-HA Architecture"]
        direction LR

        subgraph Node1["Node 1 (Infra)"]
            E1[("Etcd")]
            H1["HAProxy"]
            P1["Patroni + PostgreSQL<br/>🟢 Primary"]
        end

        subgraph Node2["Node 2"]
            E2[("Etcd")]
            H2["HAProxy"]
            P2["Patroni + PostgreSQL<br/>🔵 Replica"]
        end

        subgraph Arbiter["❓ Arbiter Needed"]
            E3[("Etcd<br/>(External)")]
        end
    end

    E1 <-->|"Cannot form majority"| E2
    E1 <-.-> E3
    E2 <-.-> E3

    P1 ==>|"Replication"| P2

    style P1 fill:#4CAF50,color:#fff
    style P2 fill:#2196F3,color:#fff
    style E1 fill:#FF9800,color:#fff
    style E2 fill:#FF9800,color:#fff
    style E3 fill:#9E9E9E,color:#fff,stroke-dasharray: 5 5

Problem: Etcd has only 2 nodes, cannot form majority

Solutions:

  1. Add a 3rd Etcd node externally (pure arbiter)
  2. Use failsafe_mode to prevent split-brain
  3. Accept asymmetric failover

Asymmetric Failover:

  • Replica failure: ✅ Auto-handled, primary continues service
  • Primary failure: ⚠️ Manual intervention required (cannot auto-elect)

Configuration Recommendations:

# Enable failsafe mode to prevent false switching
patroni_watchdog_mode: off            # Disable watchdog
pg_rto: 60                            # Increase RTO to reduce false positives

Dual-Datacenter Same-City Mode

Same-city disaster recovery deployment, datacenter-level fault tolerance:

flowchart TB
    subgraph DualDC["🌐 Dual Datacenter Architecture"]
        direction TB

        subgraph DCA["📍 Datacenter A"]
            direction LR
            N1["Node 1<br/>Etcd + 🟢 Primary"]
            N2["Node 2<br/>Etcd + 🔵 Replica"]
        end

        subgraph DCB["📍 Datacenter B"]
            direction LR
            N3["Node 3<br/>Etcd + 🔵 Replica"]
            N4["Node 4<br/>Etcd + 🔵 Replica"]
        end

        subgraph Arbiter["🏠 Third-party DC"]
            N5["Node 5<br/>Etcd (Arbiter)"]
        end
    end

    N1 ==>|"Replication"| N2 & N3 & N4

    N1 & N2 <-->|"< 5ms"| N3 & N4
    N1 & N2 & N3 & N4 <-.->|"Etcd Raft"| N5

    style N1 fill:#4CAF50,color:#fff
    style N2 fill:#2196F3,color:#fff
    style N3 fill:#2196F3,color:#fff
    style N4 fill:#2196F3,color:#fff
    style N5 fill:#FF9800,color:#fff

Network Requirements:

  • Inter-datacenter latency < 5ms (sync replication) or < 20ms (async replication)
  • Sufficient bandwidth, ensure WAL transmission
  • Arbiter node can be lightweight VM

Failure Scenarios:

FailureImpactRecovery Method
DC-A single node failureNo impactAutomatic
DC-B single node failureNo impactAutomatic
DC-A overall failureSwitch to DC-BAutomatic (requires arbiter node)
DC-B overall failureNo impactAutomatic
Arbiter node failureDegrade to 4 nodesTolerate 1 node failure

Geo-Distributed Mode

Cross-region deployment, need to consider latency and bandwidth:

flowchart LR
    subgraph GeoDR["🌍 Geo Disaster Recovery Architecture"]
        direction LR

        subgraph Beijing["🏙️ Primary DC (Beijing)"]
            direction TB
            BJ_E[("Etcd<br/>3 nodes")]
            BJ1["🟢 Primary"]
            BJ2["🔵 Replica"]
        end

        subgraph Shanghai["🏙️ DR DC (Shanghai)"]
            direction TB
            SH_E[("Etcd<br/>Independent cluster")]
            SH1["🔵 Replica"]
            SH2["🔵 Replica"]
        end
    end

    BJ1 ==>|"Async Replication<br/>Latency: 20-50ms"| SH1
    BJ1 --> BJ2
    SH1 --> SH2

    style BJ1 fill:#4CAF50,color:#fff
    style BJ2 fill:#2196F3,color:#fff
    style SH1 fill:#9C27B0,color:#fff
    style SH2 fill:#9C27B0,color:#fff
    style BJ_E fill:#FF9800,color:#fff
    style SH_E fill:#607D8B,color:#fff

Deployment Strategy:

  1. Primary DC: Complete HA cluster (3+ nodes)
  2. DR DC: Cascading replicas (Standby Cluster)
  3. Async replication: Tolerate network latency
  4. Independent Etcd: Avoid cross-region quorum

Cascading Replica Configuration:

# DR cluster configuration
pg-standby:
  hosts:
    10.20.10.11: { pg_seq: 1, pg_role: primary }  # Cascading leader
    10.20.10.12: { pg_seq: 2, pg_role: replica }
  vars:
    pg_cluster: pg-standby
    pg_upstream: 10.10.10.11          # Point to primary cluster
    pg_delay: 1h                       # Optional: delayed replication

Failure Scenario Analysis

Single Node Failure

Primary Process Crash

Scenario: PostgreSQL primary process killed with kill -9 or crashes

flowchart LR
    subgraph Detection["🔍 Failure Detection"]
        D1["Patroni detects process missing"]
        D2["Attempt to restart PostgreSQL"]
        D3["Restart fails, stop lease renewal"]
        D1 --> D2 --> D3
    end

    subgraph Failover["🔄 Failover"]
        F1["Etcd lease expires (~10s)"]
        F2["Trigger election, most up-to-date replica wins"]
        F3["New primary promoted"]
        F4["HAProxy detects new primary"]
        F1 --> F2 --> F3 --> F4
    end

    subgraph Impact["📊 Impact"]
        I1["Write service interruption: 15-30s"]
        I2["Read service: Brief interruption"]
        I3["Data loss: < 1MB or 0"]
    end

    Detection --> Failover --> Impact

    style D1 fill:#ffcdd2
    style F3 fill:#c8e6c9
    style I1 fill:#fff9c4

Patroni Process Failure

Scenario: Patroni process killed or crashes

flowchart TB
    FAULT["Patroni process failure"]

    subgraph Detection["Failure Detection"]
        D1["Patroni stops lease renewal"]
        D2["PostgreSQL continues running<br/>(orphan state)"]
        D3["Etcd lease countdown"]
    end

    subgraph FailsafeOn["failsafe_mode: true"]
        FS1["Check if can access other Patroni"]
        FS2["✅ Yes → Continue as primary"]
        FS3["❌ No → Self-demote"]
    end

    subgraph FailsafeOff["failsafe_mode: false"]
        FF1["Trigger switch after lease expires"]
        FF2["Original primary demoted"]
    end

    FAULT --> Detection
    Detection --> FailsafeOn
    Detection --> FailsafeOff

    style FAULT fill:#f44336,color:#fff
    style FS2 fill:#4CAF50,color:#fff
    style FS3 fill:#ff9800,color:#fff

Replica Failure

Scenario: Any replica node failure

Impact:

  • Read-only traffic redistributed to other replicas
  • If no other replicas, primary handles read-only traffic
  • ✅ Write service completely unaffected

Recovery:

  • Node recovers, Patroni automatically starts
  • Automatically resync from primary
  • Recover as replica role

Multiple Node Failures

Three Nodes, Two Failed (2/3 Failure)

Scenario: 3-node cluster, 2 nodes fail simultaneously

flowchart TB
    subgraph Analysis["Situation Analysis"]
        A1["Etcd loses majority (1/3 < 2/3)"]
        A2["Cannot perform leader election"]
        A3["Auto-switch mechanism fails"]
    end

    subgraph Survivor["Surviving Node Situation"]
        S1{"Surviving node is?"}
        S2["🟢 Primary<br/>Continue running under failsafe_mode"]
        S3["🔵 Replica<br/>Cannot auto-promote"]
    end

    A1 --> A2 --> A3 --> S1
    S1 -->|"Primary"| S2
    S1 -->|"Replica"| S3

    style A1 fill:#ffcdd2
    style S2 fill:#c8e6c9
    style S3 fill:#fff9c4

Emergency Recovery Process:

# 1. Confirm surviving node status
patronictl -c /etc/patroni/patroni.yml list

# 2. If surviving node is replica, manually promote
pg_ctl promote -D /pg/data

# 3. Or use pg-promote script
/pg/bin/pg-promote

# 4. Modify HAProxy config, point directly to surviving node
# Comment out health checks, hard-code routing

# 5. After Etcd cluster recovers, reinitialize

Two Nodes, One Failed (1/2 Failure)

Scenario: 2-node cluster, primary fails

Problem:

  • Etcd has only 2 nodes, no majority
  • Cannot complete election
  • Replica cannot auto-promote

Solutions:

  1. Solution 1: Add external Etcd arbiter node
  2. Solution 2: Manual intervention to promote replica
  3. Solution 3: Use Witness node

Manual Promotion Steps:

  1. Confirm primary is truly unrecoverable
  2. Stop replica Patroni: systemctl stop patroni
  3. Manual promotion: pg_ctl promote -D /pg/data
  4. Start PostgreSQL directly: systemctl start postgres
  5. Update application connection strings or HAProxy config

Etcd Cluster Failure

Etcd Single Node Failure

Scenario: 3-node Etcd cluster, 1 node fails

Impact:

  • ✅ Etcd still has majority (2/3)
  • ✅ Service operates normally
  • ✅ PostgreSQL HA unaffected

Recovery:

  • Fix failed node
  • Use etcd-add to rejoin
  • Or replace with new node

Etcd Majority Lost

Scenario: 3-node Etcd cluster, 2 nodes fail

flowchart TB
    subgraph Impact["❌ Impact"]
        I1["Etcd cannot write"]
        I2["Patroni cannot renew lease"]
        I3["failsafe_mode activated"]
        I4["Cannot perform failover"]
    end

    subgraph PG["PostgreSQL Behavior"]
        P1["🟢 Primary: Continue running"]
        P2["🔵 Replica: Continue replication"]
        P3["✅ New writes can continue"]
    end

    subgraph Limit["⚠️ Limitations"]
        L1["Cannot switchover"]
        L2["Cannot failover"]
        L3["Config changes won't take effect"]
    end

    Impact --> PG --> Limit

    style I1 fill:#ffcdd2
    style P1 fill:#c8e6c9
    style L1 fill:#fff9c4

Recovery Priority:

  1. Restore Etcd majority
  2. Verify PostgreSQL status
  3. Check if Patroni is renewing leases normally

Network Partition

Primary Network Isolation

Scenario: Primary network disconnected from Etcd/other nodes

flowchart LR
    subgraph Isolated["🔒 Isolated Side (Primary)"]
        P1["Primary"]
        CHECK{"failsafe_mode<br/>check"}
        CONT["Continue running"]
        DEMOTE["Self-demote"]

        P1 --> CHECK
        CHECK -->|"Can access other Patroni"| CONT
        CHECK -->|"Cannot access"| DEMOTE
    end

    subgraph Majority["✅ Majority Side"]
        E[("Etcd")]
        P2["Replica"]
        ELECT["Trigger election"]
        NEWPRI["New primary emerges"]

        E --> ELECT --> P2 --> NEWPRI
    end

    Isolated -.->|"Network partition"| Majority

    style P1 fill:#ff9800,color:#fff
    style DEMOTE fill:#f44336,color:#fff
    style NEWPRI fill:#4CAF50,color:#fff

Split-Brain Protection:

  • Patroni failsafe_mode
  • Old primary self-detection
  • Fencing (optional)
  • Watchdog (optional)

Watchdog Mechanism

Protection in extreme cases:

watchdog:
  mode: automatic                     # off|automatic|required
  device: /dev/watchdog
  safety_margin: 5                    # Safety margin (seconds)

Working Principle:

  • Patroni periodically writes to watchdog device
  • If Patroni unresponsive, kernel triggers reboot
  • Ensure old primary won’t continue serving
  • Prevent severe split-brain scenarios

RTO / RPO Deep Analysis

RTO Timing Breakdown

Recovery Time Objective (RTO) consists of multiple phases:

gantt
    title RTO Time Breakdown (Default config pg_rto=30s)
    dateFormat ss
    axisFormat %S seconds

    section Failure Detection
    Patroni detect/stop renewal    :a1, 00, 10s

    section Election Phase
    Etcd lease expires           :a2, after a1, 2s
    Candidate election (compare LSN)    :a3, after a2, 3s

    section Promotion Phase
    Execute promote            :a4, after a3, 3s
    Update Etcd state          :a5, after a4, 2s

    section Traffic Switch
    HAProxy detect new primary      :a6, after a5, 5s
    HAProxy confirm (rise)     :a7, after a6, 3s
    Service recovery                :milestone, after a7, 0s

Key Parameters Affecting RTO

ParameterImpactTuning Recommendation
pg_rtoBaseline for TTL/loop_wait/retry_timeoutCan reduce to 15-20s with stable network
ttlFailure detection time window= pg_rto
loop_waitPatroni check interval= pg_rto / 3
interHAProxy health check intervalCan reduce to 1-2s
fallFailure determination countCan reduce to 2
riseRecovery determination countCan reduce to 2

Aggressive Configuration (RTO ≈ 15s):

pg_rto: 15                            # Shorter TTL

# HAProxy configuration
default-server inter 1s fastinter 500ms fall 2 rise 2

Warning: Too short RTO increases risk of false-positive switching!


RPO Timing Breakdown

Recovery Point Objective (RPO) depends on replication mode:

Asynchronous Replication Mode (Default)

sequenceDiagram
    participant P as 🟢 Primary
    participant W as WAL
    participant R as 🔵 Replica

    Note over P: T=0 Commit

    P->>W: WAL write locally
    P-->>P: Return success to client

    Note over P,R: T+Δ (replication lag)

    P->>R: WAL send
    R->>R: WAL receive & replay

    Note over P: T+X Failure occurs
    Note over P: ❌ Unsent WAL lost

    Note over R: RPO = Δ ≈ tens of KB ~ 1MB

Replication Lag Monitoring:

-- Check replication lag
SELECT client_addr,
       state,
       sent_lsn,
       write_lsn,
       flush_lsn,
       replay_lsn,
       pg_wal_lsn_diff(sent_lsn, replay_lsn) AS lag_bytes
FROM pg_stat_replication;

Synchronous Replication Mode (RPO = 0)

sequenceDiagram
    participant P as 🟢 Primary
    participant W as WAL
    participant R as 🔵 Sync Replica

    Note over P: T=0 Commit

    P->>W: WAL write locally
    P->>R: WAL send
    R->>R: WAL receive
    R-->>P: Confirm receipt ✓
    P-->>P: Return success to client

    Note over P: Failure occurs
    Note over R: ✅ All committed data on replica
    Note over P,R: RPO = 0 (zero data loss)

Enable Synchronous Replication:

# Use crit.yml template
pg_conf: crit.yml

# Or set RPO = 0
pg_rpo: 0

# Patroni will auto-configure:
# synchronous_mode: true
# synchronous_standby_names: '*'

RTO / RPO Trade-off Matrix

Config Modepg_rtopg_rpoActual RTOActual RPOUse Case
Default (OLTP)30s1MB20-40s< 1MBRegular business systems
Fast Switch15s1MB10-20s< 1MBLow latency requirements
Zero Loss (CRIT)30s020-40s0Financial core systems
Conservative60s1MB40-80s< 1MBUnstable network

Configuration Examples:

# Fast switch mode
pg_rto: 15
pg_rpo: 1048576
pg_conf: oltp.yml

# Zero loss mode
pg_rto: 30
pg_rpo: 0
pg_conf: crit.yml

# Conservative mode (unstable network)
pg_rto: 60
pg_rpo: 1048576
pg_conf: oltp.yml

Trade-offs

Availability-First vs Consistency-First

DimensionAvailability-First (Default)Consistency-First (crit)
Sync ReplicationOffOn
FailoverFast, may lose dataCautious, zero data loss
Write LatencyLowHigh (one more network round-trip)
ThroughputHighLower
Replica Failure ImpactNoneMay block writes
RPO< 1MB= 0

RTO Trade-offs

Smaller RTOLarger RTO
✅ Fast failure recovery✅ Low false-positive risk
✅ Short business interruption✅ High network jitter tolerance
❌ High false-positive switching risk❌ Slow failure recovery
❌ Strict network requirements❌ Long business interruption

RPO Trade-offs

Larger RPORPO = 0
✅ High performance✅ Zero data loss
✅ High availability (single replica failure no impact)✅ Financial compliance
❌ May lose data on failure❌ Increased write latency
❌ Sync replica failure affects writes

Best Practices

Production Environment Checklist

Infrastructure:

  • At least 3 nodes (PostgreSQL)
  • At least 3 nodes (Etcd, can share with PG)
  • Nodes distributed across different failure domains (racks/availability zones)
  • Network latency < 10ms (same city) or < 50ms (cross-region)
  • 10 Gigabit network (recommended)

Parameter Configuration:

  • pg_rto adjust according to network conditions (15-60s)
  • pg_rpo set according to business requirements (0 or 1MB)
  • pg_conf choose appropriate template (oltp/crit)
  • patroni_watchdog_mode evaluate if needed

Monitoring & Alerting:

  • Patroni status monitoring (leader/replication lag)
  • Etcd cluster health monitoring
  • Replication lag alerting (lag > 1MB)
  • failsafe_mode activation alerting

Disaster Recovery Drills:

  • Regularly execute failover drills
  • Verify RTO/RPO meets expectations
  • Test backup recovery process
  • Verify monitoring alert effectiveness

Common Issue Troubleshooting

Failover Failure:

# Check Patroni status
patronictl -c /etc/patroni/patroni.yml list

# Check Etcd cluster health
etcdctl endpoint health

# Check replication lag
psql -c "SELECT * FROM pg_stat_replication"

# View Patroni logs
journalctl -u patroni -f

Split-Brain Scenario Handling:

# 1. Confirm which is the "true" primary
psql -c "SELECT pg_is_in_recovery()"

# 2. Stop "false" primary
systemctl stop patroni

# 3. Use pg_rewind to sync
pg_rewind --target-pgdata=/pg/data --source-server="host=<true_primary>"

# 4. Restart Patroni
systemctl start patroni

pg_rto

Parameter name: pg_rto, Type: int, Level: C

Recovery Time Objective (RTO) in seconds. Default is 30 seconds.

This parameter is used to derive Patroni’s key timing parameters:

  • ttl = pg_rto
  • loop_wait = pg_rto / 3
  • retry_timeout = pg_rto / 3
  • primary_start_timeout = pg_rto / 3

Reducing this value can speed up failure recovery, but increases risk of false-positive switching.

pg_rpo

Parameter name: pg_rpo, Type: int, Level: C

Recovery Point Objective (RPO) in bytes, default is 1048576 (1MB).

  • Set to 0 to enable synchronous replication, ensuring zero data loss
  • Set to larger value to allow more replication lag, improving availability
  • This value is also used for maximum_lag_on_failover parameter

pg_conf

Parameter name: pg_conf, Type: string, Level: C

Patroni configuration template, default is oltp.yml. Options:

TemplatePurposeSync ReplicationUse Case
oltp.ymlOLTP workloadNoRegular business systems
olap.ymlOLAP workloadNoAnalytical applications
crit.ymlCritical systemsYesFinancial core systems
tiny.ymlTiny instancesNoDev/test environments

patroni_watchdog_mode

Parameter name: patroni_watchdog_mode, Type: string, Level: C

Watchdog mode, default is off. Options:

  • off: Disable watchdog
  • automatic: Use if available
  • required: Must use, refuse to start otherwise

Watchdog is used to ensure node self-reboot in extreme cases (like Patroni hanging), preventing split-brain.

pg_vip_enabled

Parameter name: pg_vip_enabled, Type: bool, Level: C

Whether to enable L2 VIP, default is false.

When enabled, need to configure:

  • pg_vip_address: VIP address (CIDR format)
  • pg_vip_interface: Bind NIC

Note: Cloud environments usually don’t support L2 VIP.


References

10.2.5 - Point-in-Time Recovery

Introduction to the implementation architecture, principles, trade-offs and implementation details of PostgreSQL Point-in-Time Recovery in Pigsty.

You can restore and roll back your cluster to any point in the past, avoiding data loss caused by software defects and human errors.

Pigsty’s PostgreSQL clusters come with automatically configured Point-in-Time Recovery (PITR) solution, provided by backup component pgBackRest and optional object storage repository MinIO.

The High Availability solution can solve hardware failures, but is powerless against data deletion/overwrite/database drops caused by software defects and human errors. For this situation, Pigsty provides out-of-the-box Point-in-Time Recovery (PITR) capability, enabled by default without additional configuration.

Pigsty provides default configuration for base backups and WAL archiving. You can use local directories and disks, or dedicated MinIO clusters or S3 object storage services to store backups and implement off-site disaster recovery. When using local disks, by default, the ability to recover to any point in time within the past day is retained. When using MinIO or S3, by default, the ability to recover to any point in time within the past week is retained. As long as storage space is sufficient, you can keep any length of recoverable time period, depending on your needs.


What problems does Point-in-Time Recovery (PITR) solve?

  • Enhanced disaster recovery capability: RPO reduced from ∞ to tens of MB, RTO reduced from ∞ to several hours/quarters.
  • Ensure data security: Data Integrity in C/I/A: avoid data consistency issues caused by accidental deletion.
  • Ensure data security: Data Availability in C/I/A: provide fallback for “permanently unavailable” disaster situations
Single Instance Configuration StrategyEventRTORPO
Do NothingOutage Permanent Loss Total Loss
Base BackupOutage Depends on backup size and bandwidth (hours) Loss of data since last backup (hours to days)
Base Backup + WAL ArchiveOutage Depends on backup size and bandwidth (hours) Loss of last unarchived data (tens of MB)

What is the cost of Point-in-Time Recovery?

  • Reduced confidentiality in data security: Confidentiality: creates additional leakage points, requires additional protection of backups.
  • Additional resource consumption: local storage or network traffic/bandwidth overhead, usually not a problem.
  • Increased complexity cost: users need to bear backup management costs.

Limitations of Point-in-Time Recovery

If only PITR is used for failure recovery, RTO and RPO metrics are inferior compared to the High Availability solution. Usually, both should be used in combination.

  • RTO: If only single instance + PITR, recovery time depends on backup size and network/disk bandwidth, ranging from tens of minutes to hours or days.
  • RPO: If only single instance + PITR, some data may be lost during outage, one or several WAL log segment files may not yet be archived, with data loss ranging from 16 MB to tens of MB.

In addition to PITR, you can also use Delayed Clusters in Pigsty to solve data misoperation or software defect-induced data deletion and modification problems.


Principles

Point-in-Time Recovery allows you to restore and roll back your cluster to any “moment” in the past, avoiding data loss caused by software defects and human errors. To do this, two preparatory tasks are required: Base Backup and WAL Archive. Having Base Backup allows users to restore the database to the state at the time of backup, while having WAL Archive starting from a base backup allows users to restore the database to any point in time after the base backup moment.

fig-10-02.png

For detailed operations, refer to PGSQL Admin: Backup & Recovery.

Base Backup

Pigsty uses pgbackrest to manage PostgreSQL backups. pgBackRest initializes empty repositories on all cluster instances, but only actually uses the repository on the cluster primary.

pgBackRest supports three backup modes: Full Backup, Incremental Backup, and Differential Backup, with the first two being most commonly used. Full backup takes a complete physical snapshot of the database cluster at the current moment, while incremental backup records the difference between the current database cluster and the previous full backup.

Pigsty provides wrapper commands for backups: /pg/bin/pg-backup [full|incr]. You can schedule base backups as needed through Crontab or any other task scheduling system.

WAL Archive

Pigsty enables WAL archiving on the cluster primary by default, using the pgbackrest command-line tool to continuously push WAL segment files to the backup repository.

pgBackRest automatically manages required WAL files and timely cleans up expired backups and their corresponding WAL archive files according to the backup retention policy.

If you don’t need PITR functionality, you can disable WAL archiving through Cluster Configuration: archive_mode: off, and remove the node_crontab to stop scheduled backup tasks.


Implementation

By default, Pigsty provides two preset backup strategies: the default uses a local filesystem backup repository, where a full backup is performed daily to ensure users can roll back to any point in time within one day. The alternative strategy uses a dedicated MinIO cluster or S3 storage for backups, with weekly full backups and daily incremental backups, retaining two weeks of backups and WAL archives by default.

Pigsty uses pgBackRest to manage backups, receive WAL archives, and execute PITR. The backup repository can be flexibly configured (pgbackrest_repo): the default uses the primary’s local filesystem (local), but can also use other disk paths, or use the optional built-in MinIO service (minio) or cloud-based S3 services.

pgbackrest_enabled: true          # Enable pgBackRest on pgsql hosts?
pgbackrest_clean: true            # Remove pg backup data during init?
pgbackrest_log_dir: /pg/log/pgbackrest # pgbackrest log directory, default `/pg/log/pgbackrest`
pgbackrest_method: local          # pgbackrest repo method: local, minio, [user-defined...]
pgbackrest_repo:                  # pgbackrest repository: https://pgbackrest.org/configuration.html#section-repository
  local:                          # default pgbackrest repo using local posix fs
    path: /pg/backup              # local backup directory, default `/pg/backup`
    retention_full_type: count    # retain full backup by count
    retention_full: 2             # keep 3 full backups at most, 2 at least with local fs repo
  minio:                          # optional minio repo for pgbackrest
    type: s3                      # minio is s3-compatible, so use s3
    s3_endpoint: sss.pigsty       # minio endpoint domain name, default `sss.pigsty`
    s3_region: us-east-1          # minio region, default us-east-1, useless for minio
    s3_bucket: pgsql              # minio bucket name, default `pgsql`
    s3_key: pgbackrest            # minio user access key for pgbackrest
    s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
    s3_uri_style: path            # use path style uri for minio rather than host style
    path: /pgbackrest             # minio backup path, default `/pgbackrest`
    storage_port: 9000            # minio port, default 9000
    storage_ca_file: /etc/pki/ca.crt  # minio ca file path, default `/etc/pki/ca.crt`
    bundle: y                     # bundle small files into a single file
    cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
    cipher_pass: pgBackRest       # AES encryption password, default 'pgBackRest'
    retention_full_type: time     # retain full backup by time on minio repo
    retention_full: 14            # keep full backup in last 14 days
  # You can also add other optional backup repositories, such as S3, for off-site disaster recovery

Pigsty parameter pgbackrest_repo target repositories are converted to repository definitions in the /etc/pgbackrest/pgbackrest.conf configuration file. For example, if you define an S3 repository in US West region for cold backup storage, you can use the following reference configuration.

s3:    # ------> /etc/pgbackrest/pgbackrest.conf
  repo1-type: s3                                   # ----> repo1-type=s3
  repo1-s3-region: us-west-1                       # ----> repo1-s3-region=us-west-1
  repo1-s3-endpoint: s3-us-west-1.amazonaws.com    # ----> repo1-s3-endpoint=s3-us-west-1.amazonaws.com
  repo1-s3-key: '<your_access_key>'                # ----> repo1-s3-key=<your_access_key>
  repo1-s3-key-secret: '<your_secret_key>'         # ----> repo1-s3-key-secret=<your_secret_key>
  repo1-s3-bucket: pgsql                           # ----> repo1-s3-bucket=pgsql
  repo1-s3-uri-style: host                         # ----> repo1-s3-uri-style=host
  repo1-path: /pgbackrest                          # ----> repo1-path=/pgbackrest
  repo1-bundle: y                                  # ----> repo1-bundle=y
  repo1-cipher-type: aes-256-cbc                   # ----> repo1-cipher-type=aes-256-cbc
  repo1-cipher-pass: pgBackRest                    # ----> repo1-cipher-pass=pgBackRest
  repo1-retention-full-type: time                  # ----> repo1-retention-full-type=time
  repo1-retention-full: 90                         # ----> repo1-retention-full=90

Recovery

You can directly use the following wrapper commands for Point-in-Time Recovery of PostgreSQL database clusters.

Pigsty uses incremental differential parallel recovery by default, allowing you to restore to a specified point in time at the fastest speed.

pg-pitr                                 # Restore to the end of WAL archive stream (use in case of entire data center failure)
pg-pitr -i                              # Restore to the time when the most recent backup completed (less common)
pg-pitr --time="2022-12-30 14:44:44+08" # Restore to specified point in time (use when database or table was dropped)
pg-pitr --name="my-restore-point"       # Restore to named restore point created with pg_create_restore_point
pg-pitr --lsn="0/7C82CB8" -X            # Restore immediately before LSN
pg-pitr --xid="1234567" -X -P           # Restore immediately before specified transaction ID, then promote cluster directly to primary

pg-pitr --backup=latest                 # Restore to latest backup set
pg-pitr --backup=20221108-105325        # Restore to specific backup set, backup sets can be listed using pgbackrest info

pg-pitr                                 # pgbackrest --stanza=pg-meta restore
pg-pitr -i                              # pgbackrest --stanza=pg-meta --type=immediate restore
pg-pitr -t "2022-12-30 14:44:44+08"     # pgbackrest --stanza=pg-meta --type=time --target="2022-12-30 14:44:44+08" restore
pg-pitr -n "my-restore-point"           # pgbackrest --stanza=pg-meta --type=name --target=my-restore-point restore
pg-pitr -b 20221108-105325F             # pgbackrest --stanza=pg-meta --type=name --set=20221230-120101F restore
pg-pitr -l "0/7C82CB8" -X               # pgbackrest --stanza=pg-meta --type=lsn --target="0/7C82CB8" --target-exclusive restore
pg-pitr -x 1234567 -X -P                # pgbackrest --stanza=pg-meta --type=xid --target="0/7C82CB8" --target-exclusive --target-action=promote restore

When executing PITR, you can use the Pigsty monitoring system to observe the cluster LSN position status to determine whether you have successfully restored to the specified point in time, transaction point, LSN position, or other points.

pitr

10.2.6 - Security and Compliance

Detailed explanation of security features and compliance capabilities of PostgreSQL clusters in Pigsty

Pigsty v4.0 provides Enterprise-grade PostgreSQL security configuration, covering multiple dimensions including identity authentication, access control, communication encryption, audit logging, data integrity, backup and recovery, etc.

This document uses China Level 3 MLPS (GB/T 22239-2019) and SOC 2 Type II security compliance requirements as reference, comparing and verifying Pigsty’s security capabilities item by item.

Each security dimension includes two parts:

  • Default Configuration: Security compliance status when using conf/meta.yml and default parameters (Personal use)
  • Available Configuration: Enhanced security status achievable by adjusting Pigsty parameters (Enterprise-grade configuration achievable)

Compliance Summary

Level 3 MLPS Core Requirements Comparison

RequirementDefault MetConfig AvailableDescription
Identity UniquenessRole system ensures unique user identification
Password Complexity⚠️Can enable passwordcheck / credcheck to enforce password complexity
Password Periodic Change⚠️Set user validity period via expire_in/expire_at and refresh periodically
Login Failure Handling⚠️Failed login requests recorded in logs, can work with fail2ban for auto-blocking
Two-Factor Auth⚠️Password + Client SSL certificate auth
Access ControlHBA rules + RBAC + SELinux
Least PrivilegeTiered role system
Privilege SeparationDBA / Monitor / App Read/Write/ETL/Personal user separation
Communication EncryptionSSL enabled by default, can enforce SSL
Data IntegrityData checksums enabled by default
Storage Encryption⚠️Backup encryption + Percona TDE kernel support
Audit LoggingLogs record DDL and sensitive operations, can record all operations
Log ProtectionFile permission isolation, VictoriaLogs centralized collection for tamper-proofing
Backup RecoverypgBackRest automatic backup
Network IsolationFirewall + HBA

SOC 2 Type II Control Points Comparison

Control PointDefault MetConfig AvailableDescription
CC6.1 Logical Access ControlHBA + RBAC + SELinux
CC6.2 User Registration AuthAnsible declarative management
CC6.3 Least PrivilegeTiered roles
CC6.6 Transmission EncryptionSSL/TLS globally enabled
CC6.7 Static Encryption⚠️Can use Percona PGTDE kernel, and pgsodium/vault extensions
CC6.8 Malware Protection⚠️Minimal installation + audit
CC7.1 Intrusion Detection⚠️Set log Auth Fail monitoring alert rules
CC7.2 System MonitoringVictoriaMetrics + Grafana
CC7.3 Event ResponseAlertmanager
CC9.1 Business ContinuityHA + automatic failover
A1.2 Data RecoveryPITR backup recovery

Legend: ✅ Default met ⚠️ Requires additional configuration


Identity Authentication

MLPS Requirement: Users logging in should be identified and authenticated, with unique identity identification; two or more combined authentication techniques such as passwords, cryptographic technology, and biometric technology should be used.

SOC 2: CC6.1 - Logical and physical access control; user authentication mechanisms.

User Identity Identification

PostgreSQL implements user identity identification through the Role system, with each user having a unique role name.

Config ItemDefaultDescription
pg_default_roles4 default roles + 4 system usersPredefined role system
pg_users[]Business user definition list

Default Configuration: Pigsty presets a tiered role system:

pg_default_roles:
  - { name: dbrole_readonly  ,login: false ,comment: 'Global read-only role' }
  - { name: dbrole_offline   ,login: false ,comment: 'Restricted read-only role (offline queries)' }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: 'Global read-write role' }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor,dbrole_readwrite] ,comment: 'Object management role' }
  - { name: postgres         ,superuser: true  ,comment: 'System superuser' }
  - { name: replicator       ,replication: true,roles: [pg_monitor,dbrole_readonly] ,comment: 'Replication user' }
  - { name: dbuser_dba       ,superuser: true  ,roles: [dbrole_admin] ,pgbouncer: true ,comment: 'Admin user' }
  - { name: dbuser_monitor   ,roles: [pg_monitor,dbrole_readonly] ,pgbouncer: true ,comment: 'Monitor user' }

Available Configuration: Users can define business users via pg_users, supporting account validity period, connection limits, etc.:

pg_users:
  - name: dbuser_app
    password: 'SecurePass123!'
    roles: [dbrole_readwrite]
    expire_in: 365           # Expires after 365 days
    connlimit: 100           # Maximum 100 connections
    comment: 'Application user'

Password Policy

Config ItemDefaultDescription
pg_pwd_encscram-sha-256Password encryption algorithm
pg_dbsu_password'' (empty)Database superuser password

Default Configuration:

  • Password encryption uses SCRAM-SHA-256 algorithm, the most secure password hash algorithm currently supported by PostgreSQL
  • Passwords automatically use SET log_statement TO 'none' when set to prevent plaintext leakage to logs
  • Database superuser postgres has no password by default, only allows local Unix Socket access via ident authentication

Available Configuration:

  • Enable passwordcheck extension to enforce password complexity:

    pg_libs: 'passwordcheck, pg_stat_statements, auto_explain'
    
  • Use credcheck extension for richer password policies (length, complexity, history, etc.)

  • Set user account validity period:

    pg_users:
      - { name: temp_user, password: 'xxx', expire_in: 30 }  # Expires after 30 days
      - { name: temp_user, password: 'xxx', expire_at: '2025-12-31' }  # Expires on specified date
    

Authentication Mechanisms

Config ItemDefaultDescription
pg_default_hba_rules12 rulesDefault HBA authentication rules
pg_hba_rules[]Business HBA rules

Default Configuration: Pigsty implements tiered authentication strategy based on source address:

pg_default_hba_rules:
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu local ident auth'}
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu local replication'}
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replication user local password auth'}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replication user intranet password auth'}
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replication user intranet access postgres'}
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor user local password auth'}
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor user access from infra nodes'}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin SSL+password auth'}
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin global SSL+password auth'}
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'readonly role local password auth'}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'readonly role intranet password auth'}
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'offline role intranet password auth'}

Supported authentication method aliases:

AliasActual MethodDescription
denyrejectReject connection
pwdscram-sha-256Password auth (default encrypted)
sslscram-sha-256 + hostsslSSL + password auth
certcertClient certificate auth
os/ident/peerident/peerOS user mapping
trusttrustUnconditional trust (not recommended)

Available Configuration:

  • Enable client certificate authentication for two-factor auth:

    pg_hba_rules:
      - {user: 'secure_user', db: all, addr: world, auth: cert, title: 'Certificate auth user'}
    
  • Restrict specific user to access from specified IP only:

    pg_hba_rules:
      - {user: 'app_user', db: 'appdb', addr: '192.168.1.100/32', auth: ssl}
    

Access Control

MLPS Requirement: Management users should be granted minimum necessary privileges, implementing privilege separation for management users; access control policies should be configured by authorized entities.

SOC 2: CC6.3 - Role-based access control and least privilege principle.

Privilege Separation

Default Configuration: Pigsty implements clear separation of duties model:

RolePrivilegesPurpose
postgresSUPERUSERSystem superuser, local OS auth only
dbuser_dbaSUPERUSER + dbrole_adminDatabase administrator
replicatorREPLICATION + pg_monitorReplication and monitoring
dbuser_monitorpg_monitor + dbrole_readonlyRead-only monitoring
dbrole_adminCREATE + dbrole_readwriteObject management (DDL)
dbrole_readwriteINSERT/UPDATE/DELETE + dbrole_readonlyData read-write
dbrole_readonlySELECTRead-only access
dbrole_offlineSELECT (restricted)Offline/ETL queries

Available Configuration:

  • Fine-grained privilege control implemented via pg_default_privileges:

    pg_default_privileges:
      - GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
      - GRANT SELECT     ON TABLES    TO dbrole_readonly
      - GRANT SELECT     ON SEQUENCES TO dbrole_readonly
      - GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
      - GRANT INSERT     ON TABLES    TO dbrole_readwrite
      - GRANT UPDATE     ON TABLES    TO dbrole_readwrite
      - GRANT DELETE     ON TABLES    TO dbrole_readwrite
      - GRANT TRUNCATE   ON TABLES    TO dbrole_admin
      - GRANT CREATE     ON SCHEMAS   TO dbrole_admin
    

Operating System Level Privileges

Config ItemDefaultDescription
pg_dbsupostgresDatabase superuser OS account
pg_dbsu_sudolimitsudo privilege level
node_admin_sudonopassAdmin sudo privileges

Default Configuration:

  • Database superuser postgres sudo privileges are limit, only allowing execution of specific service management commands:
    • Start/stop/restart PostgreSQL related services
    • Load softdog kernel module (for watchdog)
%postgres ALL=NOPASSWD: /bin/systemctl stop postgres
%postgres ALL=NOPASSWD: /bin/systemctl start postgres
%postgres ALL=NOPASSWD: /bin/systemctl reload patroni
# ... other restricted commands

Available Configuration:

  • pg_dbsu_sudo: none - Completely disable sudo privileges (strictest)
  • pg_dbsu_sudo: all - Full sudo requiring password (balanced solution)
  • pg_dbsu_sudo: nopass - Full sudo without password (not recommended)

Row Level Security (RLS)

PostgreSQL natively supports Row Level Security (RLS), can set user attributes via pg_users:

pg_users:
  - name: secure_user
    bypassrls: false  # Don't allow bypassing RLS
    roles: [dbrole_readwrite]

Combined with RLS policies in database, can implement fine-grained data access control.


Communication Security

MLPS Requirement: Cryptographic technology should be used to ensure data integrity and confidentiality during communication.

SOC 2: CC6.6 - Data transmission security; CC6.7 - Encryption controls.

SSL/TLS Encryption

Config ItemDefaultDescription
ssl (postgresql.conf)onServer-side SSL switch
patroni_ssl_enabledfalsePatroni API SSL
pgbouncer_sslmodedisablePgBouncer client SSL
nginx_sslmodeenableNginx HTTPS

Default Configuration:

  • PostgreSQL server enables SSL by default, supports encrypted connections
  • Admin users (${admin}) forced to use hostssl connections
  • Automatically generates and distributes SSL certificates to all database nodes
# SSL configuration in patroni.yml
ssl: 'on'
ssl_cert_file: '/pg/cert/server.crt'
ssl_key_file: '/pg/cert/server.key'
ssl_ca_file: '/pg/cert/ca.crt'

Available Configuration:

  • Enable Patroni REST API SSL encryption:

    patroni_ssl_enabled: true
    
  • Enable PgBouncer client SSL:

    pgbouncer_sslmode: require  # or verify-ca, verify-full
    
  • Force all connections to use SSL:

    pg_hba_rules:
      - {user: all, db: all, addr: world, auth: ssl, title: 'Force SSL'}
    

PKI Certificate Management

Config ItemDefaultDescription
cert_validity7300dCertificate validity period (20 years)
CA Certificate Validity100 yearsSelf-signed CA validity

Default Configuration:

Pigsty uses self-built PKI system, automatically manages certificate lifecycle:

files/pki/
├── ca/           # CA root certificate
│   ├── ca.crt    # CA public key certificate
│   └── ca.key    # CA private key
├── csr/          # Certificate signing requests
├── pgsql/        # PostgreSQL cluster certificates
├── etcd/         # ETCD cluster certificates
├── infra/        # Infrastructure node certificates
└── minio/        # MinIO certificates
  • Each PostgreSQL cluster shares one private key, each instance has independent certificate
  • Certificates include correct SAN (Subject Alternative Name) configuration
  • CA certificate automatically distributed to /etc/pki/ca.crt and /pg/cert/ca.crt

Available Configuration:

  • Use externally CA-signed certificates: Place certificates in files/pki/ directory, set ca_create: false
  • Adjust certificate validity: cert_validity: 365d (1 year)

ETCD Communication Security

ETCD as Patroni’s DCS (Distributed Configuration Store), uses mTLS (mutual TLS) authentication by default:

etcd3:
  hosts: '10.10.10.10:2379'
  protocol: https
  cacert: /pg/cert/ca.crt
  cert:   /pg/cert/server.crt
  key:    /pg/cert/server.key
  username: 'pg-meta'        # Cluster-specific account
  password: 'pg-meta'        # Default same as cluster name

Data Encryption

MLPS Requirement: Cryptographic technology should be used to ensure confidentiality of important data during storage.

SOC 2: CC6.1 - Data encryption storage.

Backup Encryption

Config ItemDefaultDescription
cipher_typeaes-256-cbcBackup encryption algorithm (MinIO repo)
cipher_passpgBackRestEncryption password (needs modification)

Default Configuration:

  • Local backup (pgbackrest_method: local) not encrypted by default
  • Remote object storage backup supports AES-256-CBC encryption

Available Configuration:

Enable backup encryption (recommended for remote storage):

pgbackrest_method: minio
pgbackrest_repo:
  minio:
    type: s3
    s3_endpoint: sss.pigsty
    s3_bucket: pgsql
    s3_key: pgbackrest
    s3_key_secret: S3User.Backup
    cipher_type: aes-256-cbc
    cipher_pass: 'YourSecureBackupPassword!'  # Must modify!
    retention_full_type: time
    retention_full: 14

Transparent Data Encryption (TDE)

PostgreSQL community edition doesn’t support native TDE, but storage encryption can be implemented via:

  • Filesystem-level encryption: Use LUKS/dm-crypt to encrypt storage volumes
  • pgsodium extension: Supports column-level encryption
# Enable pgsodium column-level encryption
pg_libs: 'pgsodium, pg_stat_statements, auto_explain'

# Custom encryption key (64-bit hex)
pgsodium_key: 'a1b2c3d4e5f6...'  # Or use external key management script

Data Integrity Verification

Config ItemDefaultDescription
pg_checksumtrueData checksums

Default Configuration:

  • Data checksums enabled by default, can detect storage layer data corruption
  • crit.yml template enforces data checksums
  • Supports pg_rewind for failure recovery
pg_checksum: true  # Strongly recommend keeping enabled

Security Auditing

MLPS Requirement: Security auditing should be enabled, covering each user, auditing important user behaviors and security events.

SOC 2: CC7.2 - System monitoring and logging; CC7.3 - Security event detection.

Database Audit Logging

Config ItemDefaultDescription
logging_collectoronEnable log collector
log_destinationcsvlogCSV format logs
log_statementddlRecord DDL statements
log_min_duration_statement100msSlow query threshold
log_connectionsauthorization (PG18) / onConnection audit
log_disconnectionson (crit template)Disconnection audit
log_checkpointsonCheckpoint logs
log_lock_waitsonLock wait logs
log_replication_commandsonReplication command logs

Default Configuration:

# oltp.yml template audit configuration
log_destination: csvlog
logging_collector: 'on'
log_directory: /pg/log/postgres
log_filename: 'postgresql-%a.log'    # Rotate by weekday
log_file_mode: '0640'                # Restrict log file permissions
log_rotation_age: '1d'
log_truncate_on_rotation: 'on'
log_checkpoints: 'on'
log_lock_waits: 'on'
log_replication_commands: 'on'
log_statement: ddl                   # Record all DDL
log_min_duration_statement: 100      # Record slow queries >100ms

Available Configuration (crit.yml critical business template):

# crit.yml provides more comprehensive auditing
log_connections: 'receipt,authentication,authorization'  # PG18 full connection audit
log_disconnections: 'on'             # Record disconnections
log_lock_failures: 'on'              # Record lock failures (PG18)
track_activity_query_size: 32768     # Full query recording

Enable pgaudit extension for fine-grained auditing:

pg_libs: 'pgaudit, pg_stat_statements, auto_explain'
pg_parameters:
  pgaudit.log: 'all'
  pgaudit.log_catalog: 'on'
  pgaudit.log_relation: 'on'

Performance and Execution Auditing

ExtensionDefault EnabledDescription
pg_stat_statementsYesSQL statistics
auto_explainYesSlow query execution plans
pg_wait_samplingConfig availableWait event sampling

Default Configuration:

pg_libs: 'pg_stat_statements, auto_explain'

# auto_explain configuration
auto_explain.log_min_duration: 1s    # Record query plans >1s
auto_explain.log_analyze: 'on'
auto_explain.log_verbose: 'on'
auto_explain.log_timing: 'on'

# pg_stat_statements configuration
pg_stat_statements.max: 10000
pg_stat_statements.track: all

Centralized Log Management

Default Configuration:

  • PostgreSQL logs: /pg/log/postgres/
  • Patroni logs: /pg/log/patroni/
  • PgBouncer logs: /pg/log/pgbouncer/
  • pgBackRest logs: /pg/log/pgbackrest/

Available Configuration:

Send logs to VictoriaLogs for centralized storage via Vector:

# Logs automatically collected to VictoriaLogs
vlogs_enabled: true
vlogs_port: 9428
vlogs_options: >-
  -retentionPeriod=15d
  -retention.maxDiskSpaceUsageBytes=50GiB

Network Security

MLPS Requirement: Access control devices should be deployed at network boundaries to implement access control for data flows entering and leaving the network.

SOC 2: CC6.1 - Boundary protection and network security.

Firewall Configuration

Config ItemDefaultDescription
node_firewall_modezoneFirewall mode
node_firewall_intranetRFC1918 segmentsIntranet CIDR
node_firewall_public_port[22,80,443,5432]Public ports

Default Configuration:

node_firewall_mode: zone             # Enable zone firewall
node_firewall_intranet:              # Define intranet addresses
  - 10.0.0.0/8
  - 192.168.0.0/16
  - 172.16.0.0/12
node_firewall_public_port:           # Public ports
  - 22    # SSH
  - 80    # HTTP
  - 443   # HTTPS
  - 5432  # PostgreSQL (open cautiously)

Firewall rules:

  • Intranet addresses automatically added to trusted zone
  • Only specified ports open to public
  • Supports firewalld (RHEL-based) and ufw (Debian-based)

Available Configuration:

  • node_firewall_mode: off - Disable firewall (not recommended)
  • node_firewall_mode: none - Don’t modify existing config
  • Remove port 5432, only allow intranet database access

Service Access Control

Config ItemDefaultDescription
pg_listen0.0.0.0PostgreSQL listen address
patroni_allowlistinfra + clusterPatroni API whitelist

Default Configuration:

Patroni REST API only allows access from following addresses:

# Automatically calculated whitelist
pg_allow_list = [admin_ip] + pg_cluster_members + groups["infra"]

Available Configuration:

Restrict PostgreSQL to listen on specific NIC only:

pg_listen: '${ip}'  # Only listen on host IP, not 0.0.0.0

SELinux

Config ItemDefaultDescription
node_selinux_modepermissiveSELinux mode

Default Configuration: SELinux set to permissive mode (log but don’t block)

Available Configuration:

node_selinux_mode: enforcing  # Enforcing mode (requires additional policy configuration)

Availability and Recovery

MLPS Requirement: Should provide data backup and recovery functions; should provide automatic failure recovery.

SOC 2: CC9.1 - Business continuity; A1.2 - Data backup and recovery.

High Availability Architecture

Config ItemDefaultDescription
patroni_enabledtrueEnable Patroni HA
pg_rto30Recovery time objective (seconds)
pg_rpo1048576Recovery point objective (1MB)

Default Configuration:

  • Patroni automatic failure detection and switching (RTO < 30s)
  • Asynchronous replication, max data loss 1MB (RPO)
  • failsafe_mode: true prevents split-brain

Available Configuration:

Enable synchronous replication for RPO = 0:

pg_rpo: 0                    # Zero data loss
pg_conf: crit.yml            # Use critical business template
# crit.yml automatically enables synchronous_mode: true

Enable hardware watchdog:

patroni_watchdog_mode: automatic  # or required

Backup Recovery

Config ItemDefaultDescription
pgbackrest_enabledtrueEnable pgBackRest
pgbackrest_methodlocalBackup storage method
retention_full2Retain full backup count

Default Configuration:

pgbackrest_enabled: true
pgbackrest_method: local
pgbackrest_repo:
  local:
    path: /pg/backup
    retention_full_type: count
    retention_full: 2            # Retain 2 full backups

Available Configuration:

Off-site backup to object storage:

pgbackrest_method: minio
pgbackrest_repo:
  minio:
    type: s3
    s3_endpoint: sss.pigsty
    s3_bucket: pgsql
    cipher_type: aes-256-cbc     # Encrypt backups
    retention_full_type: time
    retention_full: 14           # Retain 14 days
    block: y                     # Block-level incremental backup
    bundle: y                    # Small file merging

Scheduled backup strategy:

node_crontab:
  - '00 01 * * * postgres /pg/bin/pg-backup full'   # Daily 1am full backup
  - '00 */4 * * * postgres /pg/bin/pg-backup diff'  # Every 4 hours differential backup

Intrusion Prevention

MLPS Requirement: Should follow minimal installation principle, only installing necessary components and applications; should be able to detect intrusion attempts on important nodes, providing alerts for serious intrusion events.

SOC 2: CC6.8 - Malware protection; CC7.1 - Intrusion detection.

Minimal Installation

Default Configuration:

  • Only install necessary PostgreSQL components and extensions
  • Precisely control installation content via pg_packages and pg_extensions
  • Production systems don’t install development tools and debug symbols
pg_packages: [ pgsql-main, pgsql-common ]  # Minimal installation
pg_extensions: []                          # Add extensions as needed

Security Extensions

Pigsty provides the following security-related extensions, can be installed and enabled as needed:

Extension/PackageVersionDescription
passwordcheck_cracklib3.1.0Strengthen PG user passwords using cracklib
supautils3.0.2Ensure database cluster security in cloud environment
pgsodium3.1.9Table data encryption storage TDE
supabase_vault / pg_vault0.3.1Extension for storing encrypted credentials in Vault (supabase)
pg_session_jwt0.4.0Session authentication using JWT
anon2.5.1Data anonymization tool
pgsmcrypto0.1.1Provide SM algorithms for PostgreSQL: SM2,SM3,SM4
pg_enigma0.5.0PostgreSQL encrypted data types
pgaudit18.0Provide audit functionality
pgauditlogtofile1.7.6pgAudit sub-extension, write audit logs to separate files
pg_auditor0.2Audit data changes and provide flashback capability
logerrors2.1.5Functions for collecting message statistics in log files
pg_auth_mon3.0Monitor connection attempts per user
pg_jobmon1.4.1Record and monitor functions
credcheck4.2Plaintext credential checker
pgcryptokey0.85PG key management
login_hook1.7Execute login_hook.login() function on user login
set_user4.2.0SET ROLE with added logging
pg_snakeoil1.4PostgreSQL dynamic library anti-virus functionality
pgextwlist1.19PostgreSQL extension whitelist functionality
sslutils1.4Manage SSL certificates using SQL
noset0.3.0Prevent non-superusers from using SET/RESET to set variables
pg_tde1.0Percona encrypted storage engine
sepgsql-SELinux label-based mandatory access control
auth_delay-Pause before returning auth failure, avoid brute force
pgcrypto1.3Utility encryption/decryption functions
passwordcheck-Extension to force reject weak password changes

Install all security extension packages:

pg_extensions: [ pg18-sec ]  # Install security extension group

Alerting and Monitoring

Default Configuration:

  • VictoriaMetrics + Alertmanager provide monitoring and alerting
  • Preset PostgreSQL alert rules
  • Grafana visualization dashboards

Key security-related alerts:

  • Excessive authentication failures
  • Excessive replication lag
  • Backup failures
  • Disk space shortage
  • Connection exhaustion

10.3 - Configuration

Choose the appropriate instance and cluster types based on your requirements to configure PostgreSQL database clusters that meet your needs.

Pigsty is a “configuration-driven” PostgreSQL platform: all behaviors come from the combination of inventory files in ~/pigsty/conf/*.yml and PGSQL parameters. Once you’ve written the configuration, you can replicate a customized cluster with instances, users, databases, access control, extensions, and tuning policies in just a few minutes.


Configuration Entry

  1. Prepare Inventory: Copy a pigsty/conf/*.yml template or write an Ansible Inventory from scratch, placing cluster groups (all.children.<cls>.hosts) and global variables (all.vars) in the same file.
  2. Define Parameters: Override the required PGSQL parameters in the vars block. The override order from global → cluster → host determines the final value.
  3. Apply Configuration: Run ./configure -c <conf> or bin/pgsql-add <cls> and other playbooks to apply the configuration. Pigsty will generate the configuration files needed for Patroni/pgbouncer/pgbackrest based on the parameters.

Pigsty’s default demo inventory conf/pgsql.yml is a minimal example: one pg-meta cluster, global pg_version: 18, and a few business user and database definitions. You can expand with more clusters from this base.


Focus Areas & Documentation Index

Pigsty’s PostgreSQL configuration can be organized from the following dimensions. Subsequent documentation will explain “how to configure” each:

  • Cluster & Instances: Define instance topology (standalone, primary-replica, standby cluster, delayed cluster, Citus, etc.) through pg_cluster / pg_role / pg_seq / pg_upstream.
  • Kernel Version: Select the core version, flavor, and tuning templates using pg_version, pg_mode, pg_packages, pg_extensions, pg_conf, and other parameters.
  • Users/Roles: Declare system roles, business accounts, password policies, and connection pool attributes in pg_default_roles and pg_users.
  • Database Objects: Create databases as needed using pg_databases, baseline, schemas, extensions, pool_* fields and automatically integrate with pgbouncer/Grafana.
  • Access Control (HBA): Maintain host-based authentication policies using pg_default_hba_rules and pg_hba_rules to ensure access boundaries for different roles/networks.
  • Privilege Model (ACL): Converge object privileges through pg_default_privileges, pg_default_roles, pg_revoke_public parameters, providing an out-of-the-box layered role system.

After understanding these parameters, you can write declarative inventory manifests as “configuration as infrastructure” for any business requirement. Pigsty will handle execution and ensure idempotency.


A Typical Example

The following snippet shows how to control instance topology, kernel version, extensions, users, and databases in the same configuration file:

all:
  children:
    pg-analytics:
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }
        10.10.10.12: { pg_seq: 2, pg_role: replica, pg_offline_query: true }
      vars:
        pg_cluster: pg-analytics
        pg_conf: olap.yml
        pg_extensions: [ postgis, timescaledb, pgvector ]
        pg_databases:
          - { name: bi, owner: dbuser_bi, schemas: [mart], extensions: [timescaledb], pool_mode: session }
        pg_users:
          - { name: dbuser_bi, password: DBUser.BI, roles: [dbrole_admin], pgbouncer: true }
  vars:
    pg_version: 17
    pg_packages: [ pgsql-main pgsql-common ]
    pg_hba_rules:
      - { user: dbuser_bi, db: bi, addr: intra, auth: ssl, title: 'BI only allows intranet SSL access' }
  • The pg-analytics cluster contains one primary and one offline replica.
  • Global settings specify pg_version: 17 with a set of extension examples and load olap.yml tuning.
  • Declare business objects in pg_databases and pg_users, automatically generating schema/extension and connection pool entries.
  • Additional pg_hba_rules restrict access sources and authentication methods.

Modify and apply this inventory to get a customized PostgreSQL cluster without manual configuration.

10.3.1 - Cluster & Instances

Choose the appropriate instance and cluster types based on your requirements to configure PostgreSQL database clusters that meet your needs.

Choose the appropriate instance and cluster types based on your requirements to configure PostgreSQL database clusters that meet your needs.

You can define different types of instances and clusters. Here are several common PostgreSQL instance/cluster types in Pigsty:

  • Primary: Define a single instance cluster.
  • Replica: Define a basic HA cluster with one primary and one replica.
  • Offline: Define an instance dedicated to OLAP/ETL/interactive queries
  • Sync Standby: Enable synchronous commit to ensure no data loss.
  • Quorum Commit: Use quorum sync commit for a higher consistency level.
  • Standby Cluster: Clone an existing cluster and follow it
  • Delayed Cluster: Clone an existing cluster for emergency data recovery
  • Citus Cluster: Define a Citus distributed database cluster

Primary

We start with the simplest case: a single instance cluster consisting of one primary:

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
  vars:
    pg_cluster: pg-test

This configuration is concise and self-describing, consisting only of identity parameters. Note that the Ansible Group name should match pg_cluster.

Use the following command to create this cluster:

bin/pgsql-add pg-test

For demos, development testing, hosting temporary requirements, or performing non-critical analytical tasks, a single database instance may not be a big problem. However, such a single-node cluster has no high availability. When hardware failures occur, you’ll need to use PITR or other recovery methods to ensure the cluster’s RTO/RPO. For this reason, you may consider adding several read-only replicas to the cluster.


Replica

To add a read-only replica instance, you can add a new node to pg-test and set its pg_role to replica.

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
    10.10.10.12: { pg_seq: 2, pg_role: replica }  # <--- newly added replica
  vars:
    pg_cluster: pg-test

If the entire cluster doesn’t exist, you can directly create the complete cluster. If the cluster primary has already been initialized, you can add a replica to the existing cluster:

bin/pgsql-add pg-test               # initialize the entire cluster at once
bin/pgsql-add pg-test 10.10.10.12   # add replica to existing cluster

When the cluster primary fails, the read-only instance (Replica) can take over the primary’s work with the help of the high availability system. Additionally, read-only instances can be used to execute read-only queries: many businesses have far more read requests than write requests, and most read-only query loads can be handled by replica instances.


Offline

Offline instances are dedicated read-only replicas specifically for serving slow queries, ETL, OLAP traffic, and interactive queries. Slow queries/long transactions have adverse effects on the performance and stability of online business, so it’s best to isolate them from online business.

To add an offline instance, assign it a new instance and set pg_role to offline.

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: offline }  # <--- newly added offline replica
  vars:
    pg_cluster: pg-test

Dedicated offline instances work similarly to common replica instances, but they serve as backup servers in the pg-test-replica service. That is, only when all replica instances are down will the offline and primary instances provide this read-only service.

In many cases, database resources are limited, and using a separate server as an offline instance is not economical. As a compromise, you can select an existing replica instance and mark it with the pg_offline_query flag to indicate it can handle “offline queries”. In this case, this read-only replica will handle both online read-only requests and offline queries. You can use pg_default_hba_rules and pg_hba_rules for additional access control on offline instances.


Sync Standby

When Sync Standby is enabled, PostgreSQL will select one replica as the sync standby, with all other replicas as candidates. The primary database will wait for the standby instance to flush to disk before confirming commits. The standby instance always has the latest data with no replication lag, and primary-standby switchover to the sync standby will have no data loss.

PostgreSQL uses asynchronous streaming replication by default, which may have small replication lag (on the order of 10KB/10ms). When the primary fails, there may be a small data loss window (which can be controlled using pg_rpo), but this is acceptable for most scenarios.

However, in some critical scenarios (e.g., financial transactions), data loss is completely unacceptable, or read replication lag is unacceptable. In such cases, you can use synchronous commit to solve this problem. To enable sync standby mode, you can simply use the crit.yml template in pg_conf.

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
    pg_conf: crit.yml   # <--- use crit template

To enable sync standby on an existing cluster, configure the cluster and enable synchronous_mode:

$ pg edit-config pg-test    # run as admin user on admin node
+++
-synchronous_mode: false    # <--- old value
+synchronous_mode: true     # <--- new value
 synchronous_mode_strict: false

Apply these changes? [y/N]: y

In this case, the PostgreSQL configuration parameter synchronous_standby_names is automatically managed by Patroni. One replica will be elected as the sync standby, and its application_name will be written to the PostgreSQL primary configuration file and applied.


Quorum Commit

Quorum Commit provides more powerful control than sync standby: especially when you have multiple replicas, you can set criteria for successful commits, achieving higher/lower consistency levels (and trade-offs with availability).

If you want at least two replicas to confirm commits, you can adjust the synchronous_node_count parameter through Patroni cluster configuration and apply it:

synchronous_mode: true          # ensure synchronous commit is enabled
synchronous_node_count: 2       # specify "at least" how many replicas must successfully commit

If you want to use more sync replicas, modify the synchronous_node_count value. When the cluster size changes, you should ensure this configuration is still valid to avoid service unavailability.

In this case, the PostgreSQL configuration parameter synchronous_standby_names is automatically managed by Patroni.

synchronous_standby_names = '2 ("pg-test-3","pg-test-2")'
Example: Using multiple sync standbys
$ pg edit-config pg-test
---
+synchronous_node_count: 2

Apply these changes? [y/N]: y

After applying the configuration, two sync standbys appear.

+ Cluster: pg-test (7080814403632534854) +---------+----+-----------+-----------------+
| Member    | Host        | Role         | State   | TL | Lag in MB | Tags            |
+-----------+-------------+--------------+---------+----+-----------+-----------------+
| pg-test-1 | 10.10.10.10 | Leader       | running |  1 |           | clonefrom: true |
| pg-test-2 | 10.10.10.11 | Sync Standby | running |  1 |         0 | clonefrom: true |
| pg-test-3 | 10.10.10.12 | Sync Standby | running |  1 |         0 | clonefrom: true |
+-----------+-------------+--------------+---------+----+-----------+-----------------+

Another scenario is using any n replicas to confirm commits. In this case, the configuration is slightly different. For example, if we only need any one replica to confirm commits:

synchronous_mode: quorum        # use quorum commit
postgresql:
  parameters:                   # modify PostgreSQL's configuration parameter synchronous_standby_names, using `ANY n ()` syntax
    synchronous_standby_names: 'ANY 1 (*)'  # you can specify a specific replica list or use * to wildcard all replicas.
Example: Enable ANY quorum commit
$ pg edit-config pg-test

+    synchronous_standby_names: 'ANY 1 (*)' # in ANY mode, this parameter is needed
- synchronous_node_count: 2  # in ANY mode, this parameter is not needed

Apply these changes? [y/N]: y

After applying, the configuration takes effect, and all standbys become regular replicas in Patroni. However, in pg_stat_replication, you can see sync_state becomes quorum.


Standby Cluster

You can clone an existing cluster and create a standby cluster for data migration, horizontal splitting, multi-region deployment, or disaster recovery.

Under normal circumstances, the standby cluster will follow the upstream cluster and keep content synchronized. You can promote the standby cluster to become a truly independent cluster.

The standby cluster definition is basically the same as a normal cluster definition, except that the pg_upstream parameter is additionally defined on the primary. The primary of the standby cluster is called the Standby Leader.

For example, below defines a pg-test cluster and its standby cluster pg-test2. The configuration inventory might look like this:

# pg-test is the original cluster
pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
  vars: { pg_cluster: pg-test }

# pg-test2 is the standby cluster of pg-test
pg-test2:
  hosts:
    10.10.10.12: { pg_seq: 1, pg_role: primary , pg_upstream: 10.10.10.11 } # <--- pg_upstream defined here
    10.10.10.13: { pg_seq: 2, pg_role: replica }
  vars: { pg_cluster: pg-test2 }

The primary node pg-test2-1 of the pg-test2 cluster will be a downstream replica of pg-test and serve as the Standby Leader in the pg-test2 cluster.

Just ensure the pg_upstream parameter is configured on the standby cluster’s primary node to automatically pull backups from the original upstream.

bin/pgsql-add pg-test     # create original cluster
bin/pgsql-add pg-test2    # create standby cluster
Example: Change replication upstream

If necessary (e.g., upstream primary-standby switchover/failover), you can change the standby cluster’s replication upstream through cluster configuration.

To do this, simply change standby_cluster.host to the new upstream IP address and apply.

$ pg edit-config pg-test2

 standby_cluster:
   create_replica_methods:
   - basebackup
-  host: 10.10.10.13     # <--- old upstream
+  host: 10.10.10.12     # <--- new upstream
   port: 5432

 Apply these changes? [y/N]: y
Example: Promote standby cluster

You can promote the standby cluster to an independent cluster at any time, so the cluster can independently handle write requests and diverge from the original cluster.

To do this, you must configure the cluster and completely erase the standby_cluster section, then apply.

$ pg edit-config pg-test2
-standby_cluster:
-  create_replica_methods:
-  - basebackup
-  host: 10.10.10.11
-  port: 5432

Apply these changes? [y/N]: y
Example: Cascade replication

If you specify pg_upstream on a replica instead of the primary, you can configure cascade replication for the cluster.

When configuring cascade replication, you must use the IP address of an instance in the cluster as the parameter value, otherwise initialization will fail. The replica performs streaming replication from a specific instance rather than the primary.

The instance acting as a WAL relay is called a Bridge Instance. Using a bridge instance can share the burden of sending WAL from the primary. When you have dozens of replicas, using bridge instance cascade replication is a good idea.

pg-test:
  hosts: # pg-test-1 ---> pg-test-2 ---> pg-test-3
    10.10.10.11: { pg_seq: 1, pg_role: primary }
    10.10.10.12: { pg_seq: 2, pg_role: replica } # <--- bridge instance
    10.10.10.13: { pg_seq: 3, pg_role: replica, pg_upstream: 10.10.10.12 }
    # ^--- replicate from pg-test-2 (bridge) instead of pg-test-1 (primary)
  vars: { pg_cluster: pg-test }

Delayed Cluster

A Delayed Cluster is a special type of standby cluster used to quickly recover “accidentally deleted” data.

For example, if you want a cluster named pg-testdelay whose data content is the same as the pg-test cluster from one hour ago:

# pg-test is the original cluster
pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
  vars: { pg_cluster: pg-test }

# pg-testdelay is the delayed cluster of pg-test
pg-testdelay:
  hosts:
    10.10.10.12: { pg_seq: 1, pg_role: primary , pg_upstream: 10.10.10.11, pg_delay: 1d }
    10.10.10.13: { pg_seq: 2, pg_role: replica }
  vars: { pg_cluster: pg-testdelay }

You can also configure a “replication delay” on an existing standby cluster.

$ pg edit-config pg-testdelay
 standby_cluster:
   create_replica_methods:
   - basebackup
   host: 10.10.10.11
   port: 5432
+  recovery_min_apply_delay: 1h    # <--- add delay duration here, e.g. 1 hour

Apply these changes? [y/N]: y

When some tuples and tables are accidentally deleted, you can modify this parameter to advance this delayed cluster to an appropriate point in time, read data from it, and quickly fix the original cluster.

Delayed clusters require additional resources, but are much faster than PITR and have much less impact on the system. For very critical clusters, consider setting up delayed clusters.


Citus Cluster

Pigsty natively supports Citus. You can refer to files/pigsty/citus.yml and prod.yml as examples.

To define a Citus cluster, you need to specify the following parameters:

  • pg_mode must be set to citus, not the default pgsql
  • The shard name pg_shard and shard number pg_group must be defined on each shard cluster
  • pg_primary_db must be defined to specify the database managed by Patroni.
  • If you want to use pg_dbsu postgres instead of the default pg_admin_username to execute admin commands, then pg_dbsu_password must be set to a non-empty plaintext password

Additionally, extra hba rules are needed to allow SSL access from localhost and other data nodes. As shown below:

all:
  children:
    pg-citus0: # citus shard 0
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus0 , pg_group: 0 }
    pg-citus1: # citus shard 1
      hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus1 , pg_group: 1 }
    pg-citus2: # citus shard 2
      hosts: { 10.10.10.12: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus2 , pg_group: 2 }
    pg-citus3: # citus shard 3
      hosts:
        10.10.10.13: { pg_seq: 1, pg_role: primary }
        10.10.10.14: { pg_seq: 2, pg_role: replica }
      vars: { pg_cluster: pg-citus3 , pg_group: 3 }
  vars:                               # global parameters for all Citus clusters
    pg_mode: citus                    # pgsql cluster mode must be set to: citus
    pg_shard: pg-citus                # citus horizontal shard name: pg-citus
    pg_primary_db: meta               # citus database name: meta
    pg_dbsu_password: DBUser.Postgres # if using dbsu, need to configure a password for it
    pg_users: [ { name: dbuser_meta ,password: DBUser.Meta ,pgbouncer: true ,roles: [ dbrole_admin ] } ]
    pg_databases: [ { name: meta ,extensions: [ { name: citus }, { name: postgis }, { name: timescaledb } ] } ]
    pg_hba_rules:
      - { user: 'all' ,db: all  ,addr: 127.0.0.1/32 ,auth: ssl ,title: 'all user ssl access from localhost' }
      - { user: 'all' ,db: all  ,addr: intra        ,auth: ssl ,title: 'all user ssl access from intranet'  }

On the coordinator node, you can create distributed tables and reference tables and query them from any data node. Starting from 11.2, any Citus database node can act as a coordinator.

SELECT create_distributed_table('pgbench_accounts', 'aid'); SELECT truncate_local_data_after_distributing_table($$public.pgbench_accounts$$);
SELECT create_reference_table('pgbench_branches')         ; SELECT truncate_local_data_after_distributing_table($$public.pgbench_branches$$);
SELECT create_reference_table('pgbench_history')          ; SELECT truncate_local_data_after_distributing_table($$public.pgbench_history$$);
SELECT create_reference_table('pgbench_tellers')          ; SELECT truncate_local_data_after_distributing_table($$public.pgbench_tellers$$);

10.3.2 - Kernel Version

How to choose the appropriate PostgreSQL kernel and major version.

Choosing a “kernel” in Pigsty means determining the PostgreSQL major version, mode/distribution, packages to install, and tuning templates to load.

Pigsty supports PostgreSQL from version 10 onwards. The current version packages core software for versions 13-18 by default and provides a complete extension set for 17/18. The following content shows how to make these choices through configuration files.


Major Version and Packages

  • pg_version: Specify the PostgreSQL major version (default 18). Pigsty will automatically map to the correct package name prefix based on the version.
  • pg_packages: Define the core package set to install, supports using package aliases (default pgsql-main pgsql-common, includes kernel + patroni/pgbouncer/pgbackrest and other common tools).
  • pg_extensions: List of additional extension packages to install, also supports aliases; defaults to empty meaning only core dependencies are installed.
all:
  vars:
    pg_version: 17
    pg_packages: [ pgsql-main pgsql-common ]
    pg_extensions: [ postgis, timescaledb, pgvector, pgml ]

Effect: Ansible will pull packages corresponding to pg_version=17 during installation, pre-install extensions to the system, and database initialization scripts can then directly CREATE EXTENSION.

Extension support varies across versions in Pigsty’s offline repository: 12/13 only provide core and tier-1 extensions, while 15/17/18 cover all extensions. If an extension is not pre-packaged, it can be added via repo_packages_extra.


Kernel Mode (pg_mode)

pg_mode controls the kernel “flavor” to deploy. Default pgsql indicates standard PostgreSQL. Pigsty currently supports the following modes:

ModeScenario
pgsqlStandard PostgreSQL, HA + replication
citusCitus distributed cluster, requires additional pg_shard / pg_group
gpsqlGreenplum / MatrixDB
mssqlBabelfish for PostgreSQL
mysqlOpenGauss/HaloDB compatible with MySQL protocol
polarAlibaba PolarDB (based on pg polar distribution)
ivoryIvorySQL (Oracle-compatible syntax)
orioleOrioleDB storage engine
oraclePostgreSQL + ora compatibility (pg_mode: oracle)

After selecting a mode, Pigsty will automatically load corresponding templates, dependency packages, and Patroni configurations. For example, deploying Citus:

all:
  children:
    pg-citus0:
      hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus0, pg_group: 0 }
    pg-citus1:
      hosts: { 10.10.10.12: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus1, pg_group: 1 }
  vars:
    pg_mode: citus
    pg_shard: pg-citus
    patroni_citus_db: meta

Effect: All members will install Citus-related packages, Patroni writes to etcd in shard mode, and automatically CREATE EXTENSION citus in the meta database.


Extensions and Pre-installed Objects

Besides system packages, you can control components automatically loaded after database startup through the following parameters:

  • pg_libs: List to write to shared_preload_libraries. For example: pg_libs: 'timescaledb, pg_stat_statements, auto_explain'.
  • pg_default_extensions / pg_default_schemas: Control schemas and extensions pre-created in template1 and postgres by initialization scripts.
  • pg_parameters: Append ALTER SYSTEM SET for all instances (written to postgresql.auto.conf).

Example: Enable TimescaleDB, pgvector and customize some system parameters.

pg-analytics:
  vars:
    pg_cluster: pg-analytics
    pg_libs: 'timescaledb, pg_stat_statements, pgml'
    pg_default_extensions:
      - { name: timescaledb }
      - { name: pgvector }
    pg_parameters:
      timescaledb.max_background_workers: 8
      shared_preload_libraries: "'timescaledb,pg_stat_statements,pgml'"

Effect: During initialization, template1 creates extensions, Patroni’s postgresql.conf injects corresponding parameters, and all business databases inherit these settings.


Tuning Template (pg_conf)

pg_conf points to Patroni templates in roles/pgsql/templates/*.yml. Pigsty includes four built-in general templates:

TemplateApplicable Scenario
oltp.ymlDefault template, for 4–128 core TP workload
olap.ymlOptimized for analytical scenarios
crit.ymlEmphasizes sync commit/minimal latency, suitable for zero-loss scenarios like finance
tiny.ymlLightweight machines / edge scenarios / resource-constrained environments

You can directly replace the template or customize a YAML file in templates/, then specify it in cluster vars.

pg-ledger:
  hosts: { 10.10.10.21: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-ledger
    pg_conf: crit.yml
    pg_parameters:
      synchronous_commit: 'remote_apply'
      max_wal_senders: 16
      wal_keep_size: '2GB'

Effect: Copy crit.yml as Patroni configuration, overlay pg_parameters written to postgresql.auto.conf, making instances run immediately in synchronous commit mode.


Combined Instance: A Complete Example

pg-rag:
  hosts:
    10.10.10.31: { pg_seq: 1, pg_role: primary }
    10.10.10.32: { pg_seq: 2, pg_role: replica }
  vars:
    pg_cluster: pg-rag
    pg_version: 18
    pg_mode: pgsql
    pg_conf: olap.yml
    pg_packages: [ pgsql-main pgsql-common ]
    pg_extensions: [ pgvector, pgml, postgis ]
    pg_libs: 'pg_stat_statements, pgvector, pgml'
    pg_parameters:
      max_parallel_workers: 8
      shared_buffers: '32GB'
  • First primary + one replica, using olap.yml tuning.
  • Install PG18 + RAG common extensions, automatically load pgvector/pgml at system level.
  • Patroni/pgbouncer/pgbackrest generated by Pigsty, no manual intervention needed.

Replace the above parameters according to business needs to complete all kernel-level customization.

10.3.3 - Package Alias

Pigsty provides a package alias translation mechanism that shields the differences in binary package details across operating systems, making installation easier.

PostgreSQL package naming conventions vary significantly across different operating systems:

  • EL systems (RHEL/Rocky/Alma/…) use formats like pgvector_17, postgis36_17*
  • Debian/Ubuntu systems use formats like postgresql-17-pgvector, postgresql-17-postgis-3

This difference adds cognitive burden to users: you need to remember different package name rules for different systems, and handle the embedding of PostgreSQL version numbers.

Package Alias

Pigsty solves this problem through the Package Alias mechanism: you only need to use unified aliases, and Pigsty will handle all the details:

# Using aliases - simple, unified, cross-platform
pg_extensions: [ postgis, pgvector, timescaledb ]

# Equivalent to actual package names on EL9 + PG17
pg_extensions: [ postgis36_17*, pgvector_17*, timescaledb-tsl_17* ]

# Equivalent to actual package names on Ubuntu 24 + PG17
pg_extensions: [ postgresql-17-postgis-3, postgresql-17-pgvector, postgresql-17-timescaledb-tsl ]

Alias Translation

Aliases can also group a set of packages as a whole. For example, Pigsty’s default installed packages - the default value of pg_packages is:

pg_packages:                      # pg packages to be installed, alias can be used
  - pgsql-main pgsql-common

Pigsty will query the current operating system alias list (assuming el10.x86_64) and translate it to PGSQL kernel, extensions, and toolkits:

pgsql-main:    "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit pg_repack_$v* wal2json_$v* pgvector_$v*"
pgsql-common:  "patroni patroni-etcd pgbouncer pgbackrest pg_exporter pgbackrest_exporter vip-manager"

Next, Pigsty further translates pgsql-main using the currently specified PG major version (assuming pg_version = 18):

pg18-main:   "postgresql18 postgresql18-server postgresql18-libs postgresql18-contrib postgresql18-plperl postgresql18-plpython3 postgresql18-pltcl postgresql18-llvmjit pg_repack_18* wal2json_18* pgvector_18*"

Through this approach, Pigsty shields the complexity of packages, allowing users to simply specify the functional components they want.


Which Variables Can Use Aliases?

You can use package aliases in the following four parameters, and the aliases will be automatically converted to actual package names according to the translation process:


Alias List

You can find the alias mapping files for each operating system and architecture in the roles/node_id/vars/ directory of the Pigsty project source code:


How It Works

Alias Translation Process

User config alias --> Detect OS -->  Find alias mapping table ---> Replace $v placeholder ---> Install actual packages
     ↓                 ↓                   ↓                                   ↓
  postgis          el9.x86_64         postgis36_$v*                   postgis36_17*
  postgis          u24.x86_64         postgresql-$v-postgis-3         postgresql-17-postgis-3

Version Placeholder

Pigsty’s alias system uses $v as a placeholder for the PostgreSQL version number. When you specify a PostgreSQL version using pg_version, all $v in aliases will be replaced with the actual version number.

For example, when pg_version: 17:

Alias Definition (EL)Expanded Result
postgresql$v*postgresql17*
pgvector_$v*pgvector_17*
timescaledb-tsl_$v*timescaledb-tsl_17*
Alias Definition (Debian/Ubuntu)Expanded Result
postgresql-$vpostgresql-17
postgresql-$v-pgvectorpostgresql-17-pgvector
postgresql-$v-timescaledb-tslpostgresql-17-timescaledb-tsl

Wildcard Matching

On EL systems, many aliases use the * wildcard to match related subpackages. For example:

  • postgis36_17* will match postgis36_17, postgis36_17-client, postgis36_17-utils, etc.
  • postgresql17* will match postgresql17, postgresql17-server, postgresql17-libs, postgresql17-contrib, etc.

This design ensures you don’t need to list each subpackage individually - one alias can install the complete extension.

10.3.4 - User/Role

User/Role refers to logical objects created by the SQL command CREATE USER/ROLE within a database cluster.

In this context, user refers to logical objects created by the SQL command CREATE USER/ROLE within a database cluster.

In PostgreSQL, users belong directly to the database cluster rather than a specific database. Therefore, when creating business databases and business users, the principle of “users first, databases later” should be followed.


Define Users

Pigsty defines roles and users in database clusters through two config parameters:

  • pg_default_roles: Define globally shared roles and users
  • pg_users: Define business users and roles at the database cluster level

The former defines roles and users shared across the entire env, while the latter defines business roles and users specific to a single cluster. Both have the same format as arrays of user definition objects.

You can define multiple users/roles. They will be created sequentially: first global, then cluster, and finally by array order. So later users can belong to roles defined earlier.

Here is the business user definition in the default pg-meta cluster in the Pigsty demo env:

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 }
      - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
      - {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database    }
      - {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database   }
      - {name: dbuser_kong     ,password: DBUser.Kong     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway    }
      - {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service       }
      - {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service     }
      - {name: dbuser_noco     ,password: DBUser.Noco     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for nocodb service      }
      - {name: dbuser_remove   ,state: absent }  # use state: absent to delete user

Each user/role definition is an object that may include the following fields, using dbuser_meta user as an example:

- name: dbuser_meta               # Required, `name` is the only mandatory field
  state: create                   # Optional, user state: create (default), absent (delete)
  password: DBUser.Meta           # Optional, password, can be scram-sha-256 hash or plaintext
  login: true                     # Optional, can login by default
  superuser: false                # Optional, default false, is it a superuser?
  createdb: false                 # Optional, default false, can create databases?
  createrole: false               # Optional, default false, can create roles?
  inherit: true                   # Optional, can this role use inherited privileges by default?
  replication: false              # Optional, default false, can this role perform replication?
  bypassrls: false                # Optional, default false, can bypass row-level security?
  pgbouncer: true                 # Optional, default false, add to pgbouncer user list? (prod users should set to true)
  connlimit: -1                   # Optional, user connection limit, default -1 disables limit
  expire_in: 3650                 # Optional, expire after n days from creation (higher priority than expire_at)
  expire_at: '2030-12-31'         # Optional, expiration date in YYYY-MM-DD format (lower priority than expire_in)
  comment: pigsty admin user      # Optional, description and comment string
  roles: [dbrole_admin]           # Optional, default roles: dbrole_{admin,readonly,readwrite,offline}
  parameters:                     # Optional, role-level params via `ALTER ROLE SET`
    search_path: public           # e.g., set default search_path
  pool_mode: transaction          # Optional, pgbouncer pool mode, default transaction
  pool_connlimit: -1              # Optional, user-level max pool connections, -1 disables limit
  • The only required field is name, which should be a valid and unique username in the PostgreSQL cluster.
  • Username must match regex ^[a-z_][a-z0-9_]{0,62}$ (lowercase letters, digits, underscores, starts with letter or underscore, max 63 chars).
  • Roles don’t need password, but for login-able business users, a password is usually needed.
  • password can be plaintext or scram-sha-256 / md5 hash string. Please avoid using plaintext passwords.
  • Users/roles are created sequentially in array order, so ensure role/group definitions come before their members.
  • login, superuser, createdb, createrole, inherit, replication, bypassrls are boolean flags.
  • pgbouncer is disabled by default: to add business users to the pgbouncer user list, you should explicitly set it to true.

Parameter Overview

FieldCategoryTypeMutabilityDescription
nameBasicstringRequiredUsername, must be valid and unique identifier
stateBasicenumOptionalUser state: create (default), absent
passwordBasicstringMutableUser password, plaintext or hash
commentBasicstringMutableUser comment/description
loginPrivilegeboolMutableCan login, default true
superuserPrivilegeboolMutableIs superuser, default false
createdbPrivilegeboolMutableCan create database, default false
createrolePrivilegeboolMutableCan create role, default false
inheritPrivilegeboolMutableInherit role privileges, default true
replicationPrivilegeboolMutableCan replicate, default false
bypassrlsPrivilegeboolMutableCan bypass RLS, default false
connlimitPrivilegeintMutableConnection limit, -1 means no limit
expire_inValidityintMutableExpire N days from now (higher priority than expire_at)
expire_atValiditystringMutableExpiration date, YYYY-MM-DD format
rolesRolearrayIncrementalRoles array, supports string or object format
parametersParamsobjectMutableRole-level parameters
pgbouncerPoolboolMutableAdd to connection pool, default false
pool_modePoolenumMutablePool mode: transaction (default)
pool_connlimitPoolintMutablePool user max connections

Mutability Notes

MutabilityMeaning
RequiredMust be specified
OptionalOptional field with default value
MutableCan be modified by re-running playbook
IncrementalOnly adds new content, doesn’t remove existing

Basic Parameters

name

  • Type: string
  • Mutability: Required
  • Description: Username, unique identifier within cluster

Username must be a valid PostgreSQL identifier matching regex ^[a-z_][a-z0-9_]{0,62}$:

  • Starts with lowercase letter or underscore
  • Contains only lowercase letters, digits, underscores
  • Max 63 characters
- name: dbuser_app         # standard naming
- name: app_readonly       # underscore separated
- name: _internal          # underscore prefix (for internal roles)

state

  • Type: enum
  • Mutability: Optional
  • Default: create
  • Values: create, absent
  • Description: Target user state
StateDescription
createCreate user (default), update if exists
absentDelete user via DROP ROLE
- name: dbuser_app             # state defaults to create
- name: dbuser_old
  state: absent                # delete user

Note: These system users cannot be deleted via state: absent:

  • postgres (superuser)
  • replicator (or pg_replication_username configured user)
  • dbuser_dba (or pg_admin_username configured user)
  • dbuser_monitor (or pg_monitor_username configured user)

password

  • Type: string
  • Mutability: Mutable
  • Default: None
  • Description: User password

Password can be one of:

  • Plaintext: DBUser.Meta (not recommended for prod)
  • SCRAM-SHA-256 hash: SCRAM-SHA-256$4096:... (recommended)
  • MD5 hash: md5... (legacy compatibility)
# Plaintext (logged to config file, not recommended)
- name: dbuser_app
  password: MySecretPassword

# SCRAM-SHA-256 hash (recommended)
- name: dbuser_app
  password: 'SCRAM-SHA-256$4096:xxx$yyy:zzz'

comment

  • Type: string
  • Mutability: Mutable
  • Default: business user {name}
  • Description: User comment/description

Executes COMMENT ON ROLE statement. Supports special chars (single quotes auto-escaped).

- name: dbuser_app
  comment: 'Main business application account'

Privilege Parameters

login

  • Type: bool
  • Mutability: Mutable
  • Default: true
  • Description: Can login

Set to false creates a Role rather than User, typically used for permission grouping.

# Create login-able user
- name: dbuser_app
  login: true

# Create role (no login)
- name: dbrole_custom
  login: false

superuser

  • Type: bool
  • Mutability: Mutable
  • Default: false
  • Description: Is superuser

createdb

  • Type: bool
  • Mutability: Mutable
  • Default: false
  • Description: Can create databases

createrole

  • Type: bool
  • Mutability: Mutable
  • Default: false
  • Description: Can create roles

inherit

  • Type: bool
  • Mutability: Mutable
  • Default: true
  • Description: Auto-inherit privileges from member roles

Set to false requires explicit SET ROLE to use inherited privileges.

replication

  • Type: bool
  • Mutability: Mutable
  • Default: false
  • Description: Can initiate streaming replication

Usually only replication users (like replicator) need this privilege.

bypassrls

  • Type: bool
  • Mutability: Mutable
  • Default: false
  • Description: Can bypass row-level security (RLS) policies

connlimit

  • Type: int
  • Mutability: Mutable
  • Default: -1 (no limit)
  • Description: Max concurrent connections for user
- name: dbuser_app
  connlimit: 100           # max 100 concurrent connections

- name: dbuser_batch
  connlimit: 10            # limit batch user connections

Validity Parameters

expire_in

  • Type: int
  • Mutability: Mutable
  • Description: Expire N days from current date

This param has higher priority than expire_at. Expiration time recalculated on each playbook run.

- name: temp_user
  expire_in: 30            # expire in 30 days

- name: long_term_user
  expire_in: 3650          # expire in ~10 years

expire_at

  • Type: string
  • Mutability: Mutable
  • Description: Specify expiration date

Format YYYY-MM-DD or special value infinity (never expires).

- name: contractor_user
  expire_at: '2024-12-31'  # expire on specific date

- name: permanent_user
  expire_at: 'infinity'    # never expires

Note: expire_in has higher priority than expire_at. If both specified, only expire_in takes effect.


Role Membership Parameter

roles

  • Type: array
  • Mutability: Incremental
  • Description: Roles this user belongs to

roles array supports two formats:

Simple Format (String)

- name: dbuser_app
  roles:
    - dbrole_readwrite
    - pg_read_all_data

Generated SQL:

GRANT "dbrole_readwrite" TO "dbuser_app";
GRANT "pg_read_all_data" TO "dbuser_app";

Extended Format (Object)

Object format supports finer-grained role membership control:

- name: dbuser_app
  roles:
    - dbrole_readwrite                              # simple string: GRANT role
    - { name: dbrole_admin, admin: true }           # GRANT WITH ADMIN OPTION
    - { name: pg_monitor, set: false }              # PG16+: REVOKE SET OPTION
    - { name: pg_signal_backend, inherit: false }   # PG16+: REVOKE INHERIT OPTION
    - { name: old_role, state: absent }             # REVOKE role membership

Object Format Parameters

ParamTypeDescription
namestringRole name (required)
stateenumgrant (default) or absent/revoke: control membership
adminbooltrue: WITH ADMIN OPTION / false: REVOKE ADMIN
setboolPG16+: true: WITH SET TRUE / false: REVOKE SET
inheritboolPG16+: true: WITH INHERIT TRUE / false: REVOKE INHERIT

PostgreSQL 16+ New Features

PostgreSQL 16 introduced finer-grained role membership control:

  • ADMIN OPTION: Allow granting role to other users
  • SET OPTION: Allow using SET ROLE to switch to this role
  • INHERIT OPTION: Auto-inherit this role’s privileges
# PostgreSQL 16+ complete example
- name: dbuser_app
  roles:
    # Normal membership
    - dbrole_readwrite

    # Can grant dbrole_admin to other users
    - { name: dbrole_admin, admin: true }

    # Cannot SET ROLE to pg_monitor (can only inherit privileges)
    - { name: pg_monitor, set: false }

    # Don't auto-inherit pg_execute_server_program privileges (need explicit SET ROLE)
    - { name: pg_execute_server_program, inherit: false }

    # Revoke old_role membership
    - { name: old_role, state: absent }

Note: set and inherit options only work in PostgreSQL 16+. On earlier versions they’re ignored with warning comments.


Role-Level Parameters

parameters

  • Type: object
  • Mutability: Mutable
  • Description: Role-level config parameters

Set via ALTER ROLE ... SET, params apply to all sessions for this user.

- name: dbuser_analyst
  parameters:
    work_mem: '256MB'
    statement_timeout: '5min'
    search_path: 'analytics,public'
    log_statement: 'all'

Generated SQL:

ALTER USER "dbuser_analyst" SET "work_mem" = '256MB';
ALTER USER "dbuser_analyst" SET "statement_timeout" = '5min';
ALTER USER "dbuser_analyst" SET "search_path" = 'analytics,public';
ALTER USER "dbuser_analyst" SET "log_statement" = 'all';

Reset Parameter to Default

Use special value DEFAULT (case-insensitive) to reset param to PostgreSQL default:

- name: dbuser_app
  parameters:
    work_mem: DEFAULT         # reset to PostgreSQL default
    statement_timeout: '30s'  # set new value

Common Role-Level Parameters

ParameterDescriptionExample
work_memQuery work memory'64MB'
statement_timeoutStatement timeout'30s'
lock_timeoutLock wait timeout'10s'
idle_in_transaction_session_timeoutIdle transaction timeout'10min'
search_pathSchema search path'app,public'
log_statementLog level'ddl'
temp_file_limitTemp file size limit'10GB'

Connection Pool Parameters

These params control user behavior in Pgbouncer connection pool.

pgbouncer

  • Type: bool
  • Mutability: Mutable
  • Default: false
  • Description: Add user to Pgbouncer user list
# Prod user: needs connection pool
- name: dbuser_app
  password: DBUser.App
  pgbouncer: true

# Internal user: no connection pool needed
- name: dbuser_internal
  password: DBUser.Internal
  pgbouncer: false           # default, can be omitted

pool_mode

  • Type: enum
  • Mutability: Mutable
  • Values: transaction, session, statement
  • Default: transaction
  • Description: User-level pool mode
ModeDescriptionUse Case
transactionReturn connection after txn (default)Most OLTP apps
sessionReturn connection after sessionApps needing session state
statementReturn connection after statementSimple stateless queries
# DBA user: session mode (may need SET commands etc.)
- name: dbuser_dba
  pgbouncer: true
  pool_mode: session

# Normal business user: transaction mode
- name: dbuser_app
  pgbouncer: true
  pool_mode: transaction

pool_connlimit

  • Type: int
  • Mutability: Mutable
  • Default: -1 (no limit)
  • Description: User-level max pool connections
- name: dbuser_app
  pgbouncer: true
  pool_connlimit: 50         # max 50 pool connections for this user

ACL System

Pigsty has a built-in, out-of-the-box access control / ACL system. You only need to assign these four default roles to business users:

  • dbrole_readwrite: Global read-write access role (primary business prod accounts should have this)
  • dbrole_readonly: Global read-only access role (for other businesses needing read-only access)
  • dbrole_admin: DDL privileges role (business admins, scenarios requiring table creation in apps)
  • dbrole_offline: Restricted read-only role (can only access offline instances, typically for individual users)

If you want to redesign your own ACL system, consider customizing:


Pgbouncer Users

Pgbouncer is enabled by default as connection pool middleware, with users managed automatically.

Pigsty adds all users in pg_users with explicit pgbouncer: true flag to the pgbouncer user list.

Users in Pgbouncer connection pool are listed in /etc/pgbouncer/userlist.txt:

"postgres" ""
"dbuser_wiki" "SCRAM-SHA-256$4096:+77dyhrPeFDT/TptHs7/7Q==$KeatuohpKIYzHPCt/tqBu85vI11o9mar/by0hHYM2W8=:X9gig4JtjoS8Y/o1vQsIX/gY1Fns8ynTXkbWOjUfbRQ="
"dbuser_view" "SCRAM-SHA-256$4096:DFoZHU/DXsHL8MJ8regdEw==$gx9sUGgpVpdSM4o6A2R9PKAUkAsRPLhLoBDLBUYtKS0=:MujSgKe6rxcIUMv4GnyXJmV0YNbf39uFRZv724+X1FE="
"dbuser_monitor" "SCRAM-SHA-256$4096:fwU97ZMO/KR0ScHO5+UuBg==$CrNsmGrx1DkIGrtrD1Wjexb/aygzqQdirTO1oBZROPY=:L8+dJ+fqlMQh7y4PmVR/gbAOvYWOr+KINjeMZ8LlFww="
"dbuser_meta" "SCRAM-SHA-256$4096:leB2RQPcw1OIiRnPnOMUEg==$eyC+NIMKeoTxshJu314+BmbMFpCcspzI3UFZ1RYfNyU=:fJgXcykVPvOfro2MWNkl5q38oz21nSl1dTtM65uYR1Q="

User-level connection pool params are maintained in /etc/pgbouncer/useropts.txt:

dbuser_dba                  = pool_mode=session max_user_connections=16
dbuser_monitor              = pool_mode=session max_user_connections=8

When you create users, Pgbouncer’s user list definition file will be refreshed and take effect via online config reload, without affecting existing connections.

Pgbouncer runs with the same dbsu as PostgreSQL, defaulting to the postgres OS user. You can use the pgb alias to access pgbouncer admin functions using dbsu.

Note that the pgbouncer_auth_query param allows dynamic query for connection pool user auth—a compromise when you’re lazy about managing pool users.

For user management operations, see User Management.

For user access privileges, see ACL: Role Privileges.

10.3.5 - Database

Database refers to logical objects created by the SQL command CREATE DATABASE within a database cluster.

In this context, database refers to logical objects created by the SQL command CREATE DATABASE within a database cluster.

A PostgreSQL server can serve multiple databases simultaneously. In Pigsty, you can define the required databases in the cluster config.

Pigsty modifies and customizes the default template database template1, creating default schemas, installing default extensions, and configuring default privileges. Newly created databases will inherit these settings from template1 by default.

By default, all business databases are added 1:1 to the Pgbouncer connection pool; pg_exporter will automatically discover all business databases through an auto-discovery mechanism and monitor objects within them.


Define Database

Business databases are defined in the cluster parameter pg_databases, which is an array of database definition objects. Databases in the array are created sequentially in definition order, so databases defined later can use previously defined databases as templates.

Here is the database definition in the default pg-meta cluster in the Pigsty demo env:

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 ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: postgis, schema: public}, {name: timescaledb}]}
      - { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
      - { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
      - { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
      - { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
      - { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }
      - { name: noco     ,owner: dbuser_noco     ,revokeconn: true ,comment: nocodb database }

Each database definition is an object that may include the following fields, using the meta database as an example:

- name: meta                      # Required, `name` is the only mandatory field
  state: create                   # Optional, database state: create (default), absent (delete), recreate (rebuild)
  baseline: cmdb.sql              # Optional, SQL baseline file path (relative to ansible search path, e.g., files/)
  pgbouncer: true                 # Optional, add to pgbouncer database list? Default true
  schemas: [pigsty]               # Optional, schemas to create, array of schema names
  extensions:                     # Optional, extensions to install: array of extension objects
    - { name: postgis , schema: public }  # can specify schema for extension
    - { name: timescaledb }               # some extensions create their own fixed schemas
  comment: pigsty meta database   # Optional, database comment
  owner: postgres                 # Optional, database owner, default postgres
  template: template1             # Optional, template to use, default template1
  strategy: FILE_COPY             # Optional, clone strategy: FILE_COPY or WAL_LOG (PG15+)
  encoding: UTF8                  # Optional, inherits from template/cluster config (UTF8)
  locale: C                       # Optional, inherits from template/cluster config (C)
  lc_collate: C                   # Optional, inherits from template/cluster config (C)
  lc_ctype: C                     # Optional, inherits from template/cluster config (C)
  locale_provider: libc           # Optional, locale provider: libc, icu, builtin (PG15+)
  icu_locale: en-US               # Optional, ICU locale rule (PG15+)
  icu_rules: ''                   # Optional, ICU collation rule (PG16+)
  builtin_locale: C.UTF-8         # Optional, builtin locale provider rule (PG17+)
  tablespace: pg_default          # Optional, default tablespace, default 'pg_default'
  is_template: false              # Optional, mark as template database, allows any user with CREATEDB to clone
  allowconn: true                 # Optional, allow connections, default true. Explicit false prohibits all connections
  revokeconn: false               # Optional, revoke public connect privilege. Default false, true revokes CONNECT from non-owner/admin
  register_datasource: true       # Optional, register as grafana datasource? Default true, false skips registration
  connlimit: -1                   # Optional, connection limit, default -1 (no limit)
  parameters:                     # Optional, database-level params via ALTER DATABASE SET
    work_mem: '64MB'
    statement_timeout: '30s'
  pool_auth_user: dbuser_meta     # Optional, auth user for this pgbouncer database (requires pgbouncer_auth_query)
  pool_mode: transaction          # Optional, database-level pgbouncer pool mode, default transaction
  pool_size: 64                   # Optional, database-level pool size, default 64
  pool_reserve: 32                # Optional, database-level pool reserve, default 32
  pool_size_min: 0                # Optional, database-level min pool size, default 0
  pool_connlimit: 100             # Optional, database-level max connections, default 100

The only required field is name, which should be a valid and unique database name in the current PostgreSQL cluster.


Parameter Overview

FieldCategoryTypeMutabilityDescription
nameBasicstringRequiredDatabase name, must be valid and unique identifier
stateBasicenumOptionalDatabase state: create (default), absent, recreate
ownerBasicstringMutableDatabase owner, default postgres
commentBasicstringMutableDatabase comment
templateTemplatestringImmutableTemplate database to clone from, default template1
strategyTemplateenumImmutableClone strategy: FILE_COPY or WAL_LOG (PG15+)
encodingEncodingstringImmutableCharacter encoding, inherits from template (UTF8)
localeEncodingstringImmutableLocale rule, inherits from template (C)
lc_collateEncodingstringImmutableCollation rule, inherits from template (C)
lc_ctypeEncodingstringImmutableCharacter classification, inherits from template (C)
locale_providerEncodingenumImmutableLocale provider: libc, icu, builtin (PG15+)
icu_localeEncodingstringImmutableICU locale rule (PG15+)
icu_rulesEncodingstringImmutableICU collation custom rule (PG16+)
builtin_localeEncodingstringImmutableBuiltin locale provider rule (PG17+)
tablespaceStoragestringMutableDefault tablespace, may trigger data migration
is_templatePrivilegeboolMutableMark as template database
allowconnPrivilegeboolMutableAllow connections, default true
revokeconnPrivilegeboolMutableRevoke PUBLIC CONNECT privilege
connlimitPrivilegeintMutableConnection limit, -1 means no limit
baselineInitstringOne-timeSQL baseline file path, runs only on first creation
schemasInit(string|object)[]IncrementalSchema definitions to create
extensionsInitobject[]IncrementalExtension definitions to install
parametersInitobjectMutableDatabase-level parameters
pgbouncerPoolboolMutableAdd to connection pool, default true
pool_modePoolenumMutablePool mode: transaction (default)
pool_sizePoolintMutableDefault pool size, default 64
pool_size_minPoolintMutableMin pool size, default 0
pool_reservePoolintMutableReserve pool size, default 32
pool_connlimitPoolintMutableMax database connections, default 100
pool_auth_userPoolstringMutableAuth query user
register_datasourceMonitorboolMutableRegister to Grafana datasource, default true

Mutability Notes

MutabilityMeaning
RequiredMust be specified
OptionalOptional field with default value
ImmutableOnly effective at creation, requires rebuild to change
MutableCan be modified by re-running playbook
One-timeOnly runs on first creation, skipped if db exists
IncrementalOnly adds new content, doesn’t remove existing

Basic Parameters

name

  • Type: string
  • Mutability: Required
  • Description: Database name, unique identifier within cluster

Database name should be a valid PostgreSQL identifier. Recommend lowercase letters, digits, and underscores.

- name: myapp              # simple naming
- name: my_application     # underscore separated
- name: app_v2             # with version number

state

  • Type: enum
  • Mutability: Optional
  • Default: create
  • Values: create, absent, recreate
  • Description: Target database state
StateDescription
createCreate database (default), skip if exists
absentDelete database via DROP DATABASE WITH (FORCE)
recreateDelete then create, used to reset database
- name: myapp                # state defaults to create
- name: olddb
  state: absent              # delete database
- name: testdb
  state: recreate            # rebuild database

owner

  • Type: string
  • Mutability: Mutable
  • Default: postgres (current user)
  • Description: Database owner

Specified user must already exist. Changing owner executes:

ALTER DATABASE "myapp" OWNER TO "new_owner";
GRANT ALL PRIVILEGES ON DATABASE "myapp" TO "new_owner";

comment

  • Type: string
  • Mutability: Mutable
  • Default: business database {name}
  • Description: Database comment

Executes COMMENT ON DATABASE statement. Supports special chars (single quotes auto-escaped).


Template & Clone Parameters

template

  • Type: string
  • Mutability: Immutable
  • Default: template1
  • Description: Template database for creation

Common templates:

TemplateDescription
template1Default template, includes Pigsty preconfigured extensions and privileges
template0Clean template, required when specifying different encoding/locale
Custom DBCan use existing database as template to clone

Important: When using icu or builtin locale provider, you must specify template: template0.

- name: myapp_icu
  template: template0        # required when using ICU
  locale_provider: icu
  icu_locale: en-US

strategy

  • Type: enum
  • Mutability: Immutable
  • Version: PostgreSQL 15+
  • Values: FILE_COPY, WAL_LOG
  • Description: Strategy for cloning from template
StrategyDescriptionUse Case
FILE_COPYDirect file copy (PG15+ default)Large templates, general use
WAL_LOGCopy via WAL logsSmall templates, non-blocking

Ignored on PostgreSQL 14 and earlier versions.


Encoding & Locale Parameters

encoding

  • Type: string
  • Mutability: Immutable
  • Default: Inherits from template (usually UTF8)
  • Description: Database character encoding

Common encodings: UTF8, LATIN1, SQL_ASCII

locale

  • Type: string
  • Mutability: Immutable
  • Default: Inherits from template (usually C)
  • Description: Database locale rule, sets both lc_collate and lc_ctype

lc_collate

  • Type: string
  • Mutability: Immutable
  • Default: Inherits from template (usually C)
  • Description: String collation rule

Common values: C, C.UTF-8, en_US.UTF-8, zh_CN.UTF-8

lc_ctype

  • Type: string
  • Mutability: Immutable
  • Default: Inherits from template (usually C)
  • Description: Character classification rule (upper/lower case, digits, etc.)

locale_provider

  • Type: enum
  • Mutability: Immutable
  • Version: PostgreSQL 15+
  • Values: libc, icu, builtin
  • Default: libc
  • Description: Locale implementation provider
ProviderVersionDescription
libc-Uses OS C library, traditional default
icuPG15+Uses ICU library, cross-platform consistent
builtinPG17+PostgreSQL built-in, most efficient for C/C.UTF-8

Note: When using icu or builtin, you must specify template: template0.

icu_locale

  • Type: string
  • Mutability: Immutable
  • Version: PostgreSQL 15+
  • Description: ICU locale identifier

Common values:

ValueDescription
en-USAmerican English
en-GBBritish English
zh-HansSimplified Chinese
zh-HantTraditional Chinese
ja-JPJapanese
ko-KRKorean
- name: chinese_db
  template: template0
  locale_provider: icu
  icu_locale: zh-Hans
  encoding: UTF8

icu_rules

  • Type: string
  • Mutability: Immutable
  • Version: PostgreSQL 16+
  • Description: ICU collation custom rule

Used to customize sorting behavior with ICU rule syntax.

- name: custom_sort_db
  template: template0
  locale_provider: icu
  icu_locale: en-US
  icu_rules: '&V << w <<< W'  # customize V/W sorting

builtin_locale

  • Type: string
  • Mutability: Immutable
  • Version: PostgreSQL 17+
  • Values: C, C.UTF-8
  • Description: Builtin locale provider rule

builtin provider is faster than libc, especially suitable when only C or C.UTF-8 collation is needed.

- name: fast_db
  template: template0
  locale_provider: builtin
  builtin_locale: C.UTF-8
  encoding: UTF8

Storage & Privilege Parameters

tablespace

  • Type: string
  • Mutability: Mutable
  • Default: pg_default
  • Description: Database default tablespace

Changing tablespace triggers physical data migration, may take long time for large databases.

- name: archive_db
  tablespace: slow_hdd       # use slow storage for archive data

is_template

  • Type: bool
  • Mutability: Mutable
  • Default: false
  • Description: Mark as template database

When set to true, any user with CREATEDB privilege can use this database as template to clone new databases.

- name: app_template
  is_template: true          # allow normal users to clone
  schemas: [core, api]
  extensions: [postgis]

Note: Databases marked is_template: true will first execute ALTER DATABASE ... IS_TEMPLATE false when deleted.

allowconn

  • Type: bool
  • Mutability: Mutable
  • Default: true
  • Description: Allow connections to this database

Setting to false completely prohibits any user from connecting (including superusers).

- name: archive_db
  allowconn: false           # prohibit connections

revokeconn

  • Type: bool
  • Mutability: Mutable
  • Default: false
  • Description: Revoke PUBLIC CONNECT privilege

When set to true:

  • Revokes PUBLIC CONNECT privilege
  • Grants replicator, monitor connection privilege
  • Grants admin, owner connection privilege (WITH GRANT OPTION)

When set to false:

  • Restores PUBLIC CONNECT privilege
- name: secure_db
  owner: dbuser_secure
  revokeconn: true           # only specified users can connect

connlimit

  • Type: int
  • Mutability: Mutable
  • Default: -1 (no limit)
  • Description: Database max connection limit
- name: limited_db
  connlimit: 50              # max 50 concurrent connections

Initialization Parameters

baseline

  • Type: string
  • Mutability: One-time
  • Description: SQL baseline file path

Specifies SQL file to execute after database creation for initializing table structure, data, etc.

  • Path is relative to Ansible search path (usually files/ directory)
  • Only executes on first database creation
  • Re-executes when using state: recreate
- name: myapp
  baseline: myapp_init.sql   # will search files/myapp_init.sql

schemas

  • Type: (string | object)[]
  • Mutability: Incremental
  • Description: Schema definitions to create

Supports two formats:

schemas:
  # Simple format: schema name only
  - app
  - api

  # Full format: object definition
  - name: core               # schema name (required)
    owner: dbuser_app        # schema owner (optional)
  - name: old_schema
    state: absent            # delete schema

Schema owner: Use owner to specify schema owner, generates AUTHORIZATION clause:

- name: myapp
  owner: dbuser_myapp
  schemas:
    - name: app
      owner: dbuser_myapp    # schema owner same as database owner
    - name: audit
      owner: dbuser_audit    # schema owner is different user

Generated SQL:

CREATE SCHEMA IF NOT EXISTS "app" AUTHORIZATION "dbuser_myapp";
CREATE SCHEMA IF NOT EXISTS "audit" AUTHORIZATION "dbuser_audit";

Delete schema: Use state: absent to delete schema:

schemas:
  - { name: deprecated_schema, state: absent }

Generated SQL:

DROP SCHEMA IF EXISTS "deprecated_schema" CASCADE;

Note:

  • Create operations are incremental, uses IF NOT EXISTS
  • Delete operations use CASCADE, deletes all objects in schema

extensions

  • Type: object[]
  • Mutability: Incremental
  • Description: Extension definitions to install

Supports two formats:

extensions:
  # Simple format: extension name only
  - postgis
  - pg_trgm

  # Full format: object definition
  - name: vector             # extension name (required)
    schema: public           # install to specified schema (optional)
    version: '0.5.1'         # specify version (optional)
    state: absent            # set absent to uninstall extension (optional)

Uninstall extension: Use state: absent to uninstall:

extensions:
  - { name: pg_trgm, state: absent }  # uninstall pg_trgm

Uninstall executes DROP EXTENSION IF EXISTS "name" CASCADE. Note CASCADE deletes dependent objects.

parameters

  • Type: object
  • Mutability: Mutable
  • Description: Database-level config parameters

Set via ALTER DATABASE ... SET, params apply to all sessions connecting to this database.

- name: analytics
  parameters:
    work_mem: '256MB'
    maintenance_work_mem: '512MB'
    statement_timeout: '5min'
    search_path: 'analytics,public'

Reset parameter: Use special value DEFAULT (case-insensitive) to reset to PostgreSQL default:

- name: myapp
  parameters:
    work_mem: DEFAULT        # reset to default
    statement_timeout: '30s' # set new value

Generated SQL:

ALTER DATABASE "myapp" SET "work_mem" = DEFAULT;
ALTER DATABASE "myapp" SET "statement_timeout" = '30s';

Connection Pool Parameters

These params control database behavior in Pgbouncer connection pool.

pgbouncer

  • Type: bool
  • Mutability: Mutable
  • Default: true
  • Description: Add database to Pgbouncer connection pool
- name: internal_db
  pgbouncer: false           # not accessed via connection pool

pool_mode

  • Type: enum
  • Mutability: Mutable
  • Values: transaction, session, statement
  • Default: transaction
  • Description: Database-level pool mode
ModeDescriptionUse Case
transactionReturn connection after txnMost OLTP apps
sessionReturn connection after sessionApps needing session state
statementReturn connection after statementSimple stateless queries

pool_size

  • Type: int
  • Mutability: Mutable
  • Default: 64
  • Description: Database default pool size

pool_size_min

  • Type: int
  • Mutability: Mutable
  • Default: 0
  • Description: Minimum pool size, pre-warmed connections

pool_reserve

  • Type: int
  • Mutability: Mutable
  • Default: 32
  • Description: Reserve connections, extra burst connections available when default pool exhausted

pool_connlimit

  • Type: int
  • Mutability: Mutable
  • Default: 100
  • Description: Max connections accessing this database via pool

pool_auth_user

  • Type: string
  • Mutability: Mutable
  • Description: Auth query user

Requires pgbouncer_auth_query enabled. When specified, all connections to this database use this user to query passwords.


Monitoring Parameter

register_datasource

  • Type: bool
  • Mutability: Mutable
  • Default: true
  • Description: Register to Grafana datasource

Set to false to skip Grafana datasource registration, suitable for temporary databases not needing monitoring.


Template Inheritance

Many params inherit from template database if not explicitly specified. Default template is template1, whose encoding settings are determined by cluster init params:

Cluster ParameterDefaultDescription
pg_encodingUTF8Cluster default encoding
pg_localeCCluster default locale
pg_lc_collateCCluster default collation
pg_lc_ctypeCCluster default ctype

Newly created databases are forked from template1 by default. This template database is customized during PG_PROVISION phase: configured with extensions, schemas, and default privileges, so newly created databases also inherit these configs, unless you explicitly use another database as template.

For database management operations, see Database Management.

For database access privileges, see ACL: Database Privileges.

10.3.6 - HBA Rules

Detailed explanation of PostgreSQL and Pgbouncer Host-Based Authentication (HBA) rules configuration in Pigsty.

HBA (Host-Based Authentication) controls “who can connect to the database from where and how”. Pigsty manages HBA rules declaratively through pg_default_hba_rules and pg_hba_rules.


Overview

Pigsty renders the following config files during cluster init or HBA refresh:

Config FilePathDescription
PostgreSQL HBA/pg/data/pg_hba.confPostgreSQL server HBA rules
Pgbouncer HBA/etc/pgbouncer/pgb_hba.confConnection pool Pgbouncer HBA rules

HBA rules are controlled by these parameters:

ParameterLevelDescription
pg_default_hba_rulesGPostgreSQL global default HBA rules
pg_hba_rulesG/C/IPostgreSQL cluster/instance additional rules
pgb_default_hba_rulesGPgbouncer global default HBA rules
pgb_hba_rulesG/C/IPgbouncer cluster/instance additional rules

Rule features:

  • Role filtering: Rules support role field, auto-filter based on instance’s pg_role
  • Order sorting: Rules support order field, controls position in final config file
  • Two syntaxes: Supports alias form (simplified) and raw form (direct HBA text)

Parameter Reference

pg_default_hba_rules

PostgreSQL global default HBA rule list, usually defined in all.vars, provides base access control for all PostgreSQL clusters.

  • Type: rule[]
  • Level: Global (G)
  • Default: See below
pg_default_hba_rules:
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  ,order: 100}
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' ,order: 150}
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost',order: 200}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' ,order: 250}
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' ,order: 300}
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' ,order: 350}
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password',order: 400}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   ,order: 450}
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    ,order: 500}
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket',order: 550}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     ,order: 600}
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet',order: 650}

pg_hba_rules

PostgreSQL cluster/instance-level additional HBA rules, can be overridden at cluster or instance level, merged with default rules and sorted by order.

  • Type: rule[]
  • Level: Global/Cluster/Instance (G/C/I)
  • Default: []
pg_hba_rules:
  - {user: app_user, db: app_db, addr: intra, auth: pwd, title: 'app user access'}

pgb_default_hba_rules

Pgbouncer global default HBA rule list, usually defined in all.vars.

  • Type: rule[]
  • Level: Global (G)
  • Default: See below
pgb_default_hba_rules:
  - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident',order: 100}
  - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' ,order: 150}
  - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' ,order: 200}
  - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' ,order: 250}
  - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   ,order: 300}
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   ,order: 350}
  - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' ,order: 400}

pgb_hba_rules

Pgbouncer cluster/instance-level additional HBA rules.

  • Type: rule[]
  • Level: Global/Cluster/Instance (G/C/I)
  • Default: []

Note: Pgbouncer HBA does not support db: replication.


Rule Fields

Each HBA rule is a YAML dict supporting these fields:

FieldTypeRequiredDefaultDescription
userstringNoallUsername, supports all, variable placeholders, +rolename, etc.
dbstringNoallDatabase name, supports all, replication, specific db name
addrstringYes*-Address alias or CIDR, see Address Aliases
authstringNopwdAuth method alias, see Auth Methods
titlestringNo-Rule description/comment, rendered as comment in config file
rolestringNocommonInstance role filter, see Role Filtering
orderintNo1000Sort weight, lower numbers first, see Order Sorting
ruleslistYes*-Raw HBA text lines, mutually exclusive with addr

Either addr or rules must be specified. Use rules to write raw HBA format directly.


Address Aliases

Pigsty provides address aliases to simplify HBA rule writing:

AliasExpands ToDescription
localUnix socketLocal Unix socket connection
localhostUnix socket + 127.0.0.1/32 + ::1/128Loopback addresses
admin${admin_ip}/32Admin IP address
infraAll infra group node IPsInfrastructure node list
clusterAll current cluster member IPsAll instances in same cluster
intra / intranet10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16Intranet CIDR ranges
world / all0.0.0.0/0 + ::/0Any address (IPv4 + IPv6)
<CIDR>Direct usee.g., 192.168.1.0/24, 10.1.1.100/32

Intranet CIDRs can be customized via node_firewall_intranet:

node_firewall_intranet:
  - 10.0.0.0/8
  - 172.16.0.0/12
  - 192.168.0.0/16

Auth Methods

Pigsty provides auth method aliases for simplified config:

AliasActual MethodConnection TypeDescription
pwdscram-sha-256 or md5hostAuto-select based on pg_pwd_enc
sslscram-sha-256 or md5hostsslForce SSL + password
ssl-shascram-sha-256hostsslForce SSL + SCRAM-SHA-256
ssl-md5md5hostsslForce SSL + MD5
certcerthostsslClient certificate auth
trusttrusthostUnconditional trust (dangerous)
deny / rejectrejecthostReject connection
identidenthostOS user mapping (PostgreSQL)
peerpeerlocalOS user mapping (Pgbouncer/local)

pg_pwd_enc defaults to scram-sha-256, can be set to md5 for legacy client compatibility.


User Variables

HBA rules support these user placeholders, auto-replaced with actual usernames during rendering:

PlaceholderDefaultDescription
${dbsu}postgresDatabase superuser
${repl}replicatorReplication user
${monitor}dbuser_monitorMonitor user
${admin}dbuser_dbaAdmin user

Actual values controlled by corresponding params:

pg_dbsu: postgres
pg_replication_username: replicator
pg_monitor_username: dbuser_monitor
pg_admin_username: dbuser_dba

Role Filtering

The role field in HBA rules controls which instances the rule applies to:

RoleDescription
commonDefault, applies to all instances
primaryPrimary instance only
replicaReplica instance only
offlineOffline instance only (pg_role: offline or pg_offline_query: true)
standbyStandby instance
delayedDelayed replica instance

Role filtering matches based on instance’s pg_role variable. Non-matching rules are commented out (prefixed with #).

pg_hba_rules:
  # Only applies on primary
  - {user: writer, db: all, addr: intra, auth: pwd, role: primary, title: 'writer only on primary'}

  # Only applies on offline instances
  - {user: '+dbrole_offline', db: all, addr: '172.20.0.0/16', auth: ssl, role: offline, title: 'offline dedicated'}

Order Sorting

PostgreSQL HBA is first-match-wins, rule order is critical. Pigsty controls rule rendering order via the order field.

Order Interval Convention

IntervalUsage
0 - 99User high-priority rules (before all default rules)
100 - 650Default rule zone (spaced by 50 for easy insertion)
1000+User rule default (rules without order append to end)

Default Rule Order Assignment

PostgreSQL Default Rules:

OrderRule Description
100dbsu local ident
150dbsu replication local
200replicator localhost
250replicator intra replication
300replicator intra postgres
350monitor localhost
400monitor infra
450admin infra ssl
500admin world ssl
550dbrole_readonly localhost
600dbrole_readonly intra
650dbrole_offline intra

Pgbouncer Default Rules:

OrderRule Description
100dbsu local peer
150all localhost pwd
200monitor pgbouncer intra
250monitor world deny
300admin intra pwd
350admin world deny
400all intra pwd

Sorting Example

pg_hba_rules:
  # order: 0, before all default rules (blacklist)
  - {user: all, db: all, addr: '10.1.1.100/32', auth: deny, order: 0, title: 'blacklist bad ip'}

  # order: 120, between dbsu(100) and replicator(200)
  - {user: auditor, db: all, addr: local, auth: ident, order: 120, title: 'auditor access'}

  # order: 420, between monitor(400) and admin(450)
  - {user: exporter, db: all, addr: infra, auth: pwd, order: 420, title: 'prometheus exporter'}

  # no order, defaults to 1000, appends after all default rules
  - {user: app_user, db: app_db, addr: intra, auth: pwd, title: 'app user access'}

Syntax Examples

Alias Form

Using Pigsty simplified syntax:

pg_hba_rules:
  - title: allow grafana view access
    role: primary
    user: dbuser_view
    db: meta
    addr: infra
    auth: ssl

Rendered result:

# allow grafana view access [primary]
hostssl  meta               dbuser_view        10.10.10.10/32     scram-sha-256

Raw Form

Using PostgreSQL HBA syntax directly:

pg_hba_rules:
  - title: allow intranet password access
    role: common
    rules:
      - host all all 10.0.0.0/8 scram-sha-256
      - host all all 172.16.0.0/12 scram-sha-256
      - host all all 192.168.0.0/16 scram-sha-256

Rendered result:

# allow intranet password access [common]
host all all 10.0.0.0/8 scram-sha-256
host all all 172.16.0.0/12 scram-sha-256
host all all 192.168.0.0/16 scram-sha-256

Common Configuration Examples

1. Intranet Password Access to Business DBs

pg_hba_rules:
  - title: 'intra readwrite access'
    role: common
    user: '+dbrole_readwrite'
    db: all
    addr: intra
    auth: pwd

Effect: All business read-write roles can access any database from intranet using password.

2. Offline Instance Dedicated Network

pg_hba_rules:
  - title: 'offline replica dedicated network'
    role: offline
    user: '+dbrole_offline'
    db: all
    addr: 172.20.0.0/16
    auth: ssl-sha

Effect: Only instances with pg_role: offline or pg_offline_query: true enable this rule.

3. Blacklist IP

pg_hba_rules:
  - user: all
    db: all
    addr: '10.1.1.100/32'
    auth: deny
    order: 0
    title: 'block compromised host'

Effect: order: 0 ranks before all default rules (100+), matches and rejects first.

4. Whitelist Specific Application

pg_hba_rules:
  - title: 'allow app server access'
    user: app_user
    db: app_db
    addr: '192.168.1.10/32'
    auth: ssl
    order: 50

Effect: Specific app server uses SSL connection, high priority (50) ensures match before default rules.

5. Admin Forced Certificate Auth

pg_hba_rules:
  - title: 'admin cert access'
    role: common
    user: '${admin}'
    db: all
    addr: world
    auth: cert
    order: 10

Effect: Admin must carry client certificate to connect, order: 10 takes priority over default ssl rules (450/500).

6. Allow Internet Read-Only Access

pg_hba_rules:
  - title: 'readonly from internet'
    role: replica
    user: '+dbrole_readonly'
    db: all
    addr: world
    auth: ssl

Effect: Read-only users can connect to replicas from internet via SSL.

7. Pgbouncer Dedicated Rules

pgb_hba_rules:
  - title: 'app via pgbouncer'
    role: common
    user: '+dbrole_readwrite'
    db: all
    addr: world
    auth: ssl

Note: Pgbouncer HBA does not support db: replication.

8. Multi-Condition Combination

pg_hba_rules:
  # Dev env: trust local connections
  - {user: all, db: all, addr: local, auth: trust, title: 'dev trust local'}

  # Prod env: strict SSL
  - {user: '+dbrole_readwrite', db: all, addr: intra, auth: ssl-sha, title: 'prod ssl only'}

  # Monitor dedicated: from Prometheus nodes
  - {user: '${monitor}', db: all, addr: infra, auth: pwd, order: 380, title: 'prometheus access'}

9. Restrict Access by Database

pg_hba_rules:
  # Finance system: only specific network
  - {user: fin_user, db: finance_db, addr: '10.20.0.0/16', auth: ssl, title: 'finance restricted'}

  # HR system: only HR network
  - {user: hr_user, db: hr_db, addr: '10.30.0.0/16', auth: ssl, title: 'hr restricted'}

10. Complete Cluster Config Example

pg-prod:
  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: offline}
  vars:
    pg_cluster: pg-prod

    pg_hba_rules:
      # Blacklist: known malicious IP
      - {user: all, db: all, addr: '10.1.1.100/32', auth: deny, order: 0, title: 'blacklist'}

      # App server whitelist
      - {user: app_user, db: app_db, addr: '192.168.1.0/24', auth: ssl, order: 50, title: 'app servers'}

      # ETL tasks: offline instances only
      - {user: etl_user, db: all, addr: '172.20.0.0/16', auth: pwd, role: offline, title: 'etl tasks'}

      # Enhanced monitoring
      - {user: '${monitor}', db: all, addr: cluster, auth: pwd, order: 380, title: 'cluster monitor'}

    pgb_hba_rules:
      # App via connection pool
      - {user: '+dbrole_readwrite', db: all, addr: '192.168.1.0/24', auth: ssl, title: 'app via pgbouncer'}

Rendering Principle

Pigsty uses Jinja2 templates to render HBA config files:

  1. Merge rules: pg_default_hba_rules + pg_hba_rules
  2. Sort rules: Ascending by order field (rules without order append to end)
  3. Role filter: Filter based on instance pg_role, non-matching rules commented out
  4. Variable replace: ${dbsu} etc. replaced with actual usernames
  5. Address expand: intra, infra etc. expanded to actual IP/CIDRs
  6. Auth map: pwd, ssl etc. mapped to actual auth methods

Template locations:

  • PostgreSQL: roles/pgsql/templates/pg_hba.conf
  • Pgbouncer: roles/pgsql/templates/pgbouncer.hba

Important Notes

  1. Order sensitive: PostgreSQL HBA is first-match-wins, rule order matters
  2. Role matching: Ensure role field matches target instance’s pg_role
  3. Address validation: CIDR format must be correct, e.g., 10.0.0.0/8 not 10.0.0.0/255.0.0.0
  4. Pgbouncer limitation: Does not support db: replication
  5. Variable scope: User variables limited to four predefined (${dbsu}, ${repl}, ${monitor}, ${admin})
  6. SSL config: Ensure SSL is properly configured before using ssl, cert auth methods
  7. Test first: Recommend validating in test env before modifying HBA

Testing & Verification

Pigsty provides HBA order sorting test tools to verify config correctness before deployment:

Run Sorting Logic Test

# Run sorting logic test in pigsty directory
./files/test-hba-order.yml

This test verifies:

  • Rules sorted correctly by order field
  • Rules without order append to end
  • Same order values maintain original order (stable sort)
  • Backward compatibility (old configs need no changes)

Run Template Rendering Test

# Test HBA template rendering on target server
./files/test-hba-render.yml -l 10.10.10.10

This test renders HBA template on target server, verifying:

  • Template syntax correct
  • Rule order as expected
  • High-priority rules appear first

Verify Rendered Result

# View rendered PostgreSQL HBA
cat /pg/data/pg_hba.conf

# View rule titles order (verify order is effective)
grep '^#' /pg/data/pg_hba.conf | grep -v '^#=' | head -20

# Verify first rule is expected high-priority rule
head -30 /pg/data/pg_hba.conf

ParameterDescription
pg_pwd_encPassword encryption: scram-sha-256 (default) or md5
pg_dbsuDatabase superuser name
pg_replication_usernameReplication username
pg_monitor_usernameMonitor username
pg_admin_usernameAdmin username
node_firewall_intranetIntranet CIDR definition

10.3.7 - Access Control

Default role system and privilege model provided by Pigsty

Access control is determined by the combination of “role system + privilege templates + HBA”. This section focuses on how to declare roles and object privileges through configuration parameters.

Pigsty provides a streamlined ACL model, fully described by the following parameters:

  • pg_default_roles: System roles and system users.
  • pg_users: Business users and roles.
  • pg_default_privileges: Default privileges for objects created by administrators/owners.
  • pg_revoke_public, pg_default_schemas, pg_default_extensions: Control the default behavior of template1.

After understanding these parameters, you can write fully reproducible privilege configurations.


Default Role System (pg_default_roles)

By default, it includes 4 business roles + 4 system users:

NameTypeDescription
dbrole_readonlyNOLOGINShared by all business, has SELECT/USAGE
dbrole_readwriteNOLOGINInherits read-only role, with INSERT/UPDATE/DELETE
dbrole_adminNOLOGINInherits pg_monitor + read-write role, can create objects and triggers
dbrole_offlineNOLOGINRestricted read-only role, only allowed to access offline instances
postgresUserSystem superuser, same as pg_dbsu
replicatorUserUsed for streaming replication and backup, inherits monitoring and read-only privileges
dbuser_dbaUserPrimary admin account, also synced to pgbouncer
dbuser_monitorUserMonitoring account, has pg_monitor privilege, records slow SQL by default

These definitions are in pg_default_roles. They can theoretically be customized, but if you replace names, you must synchronize updates in HBA/ACL/script references.

Example: Add an additional dbrole_etl for offline tasks:

pg_default_roles:
  - { name: dbrole_etl, login: false, roles: [dbrole_offline], comment: 'etl read-only role' }
  - { name: dbrole_admin, login: false, roles: [pg_monitor, dbrole_readwrite, dbrole_etl] }

Effect: All users inheriting dbrole_admin automatically have dbrole_etl privileges, can access offline instances and execute ETL.


Default Users and Credential Parameters

System user usernames/passwords are controlled by the following parameters:

ParameterDefault ValuePurpose
pg_dbsupostgresDatabase/system superuser
pg_dbsu_passwordEmpty stringdbsu password (disabled by default)
pg_replication_usernamereplicatorReplication username
pg_replication_passwordDBUser.ReplicatorReplication user password
pg_admin_usernamedbuser_dbaAdmin username
pg_admin_passwordDBUser.DBAAdmin password
pg_monitor_usernamedbuser_monitorMonitoring user
pg_monitor_passwordDBUser.MonitorMonitoring user password

If you modify these parameters, please synchronize updates to the corresponding user definitions in pg_default_roles to avoid role attribute inconsistencies.


Business Roles and Authorization (pg_users)

Business users are declared through pg_users (see User Configuration for detailed fields), where the roles field controls the granted business roles.

Example: Create one read-only and one read-write user:

pg_users:
  - { name: app_reader,  password: DBUser.Reader,  roles: [dbrole_readonly],  pgbouncer: true }
  - { name: app_writer,  password: DBUser.Writer,  roles: [dbrole_readwrite], pgbouncer: true }

By inheriting dbrole_* to control access privileges, no need to GRANT for each database separately. Combined with pg_hba_rules, you can distinguish access sources.

For finer-grained ACL, you can use standard GRANT/REVOKE in baseline SQL or subsequent playbooks. Pigsty won’t prevent you from granting additional privileges.


Default Privilege Templates (pg_default_privileges)

pg_default_privileges will set DEFAULT PRIVILEGE on postgres, dbuser_dba, dbrole_admin (after business admin SET ROLE). The default template is as follows:

pg_default_privileges:
  - GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
  - GRANT SELECT     ON TABLES    TO dbrole_readonly
  - GRANT SELECT     ON SEQUENCES TO dbrole_readonly
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
  - GRANT USAGE      ON SCHEMAS   TO dbrole_offline
  - GRANT SELECT     ON TABLES    TO dbrole_offline
  - GRANT SELECT     ON SEQUENCES TO dbrole_offline
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
  - GRANT INSERT     ON TABLES    TO dbrole_readwrite
  - GRANT UPDATE     ON TABLES    TO dbrole_readwrite
  - GRANT DELETE     ON TABLES    TO dbrole_readwrite
  - GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
  - GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
  - GRANT TRUNCATE   ON TABLES    TO dbrole_admin
  - GRANT REFERENCES ON TABLES    TO dbrole_admin
  - GRANT TRIGGER    ON TABLES    TO dbrole_admin
  - GRANT CREATE     ON SCHEMAS   TO dbrole_admin

As long as objects are created by the above administrators, they will automatically carry the corresponding privileges without manual GRANT. If business needs a custom template, simply replace this array.

Additional notes:

  • pg_revoke_public defaults to true, meaning automatic revocation of PUBLIC’s CREATE privilege on databases and the public schema.
  • pg_default_schemas and pg_default_extensions control pre-created schemas/extensions in template1/postgres, typically used for monitoring objects (monitor schema, pg_stat_statements, etc.).

Common Configuration Scenarios

Provide Read-Only Account for Partners

pg_users:
  - name: partner_ro
    password: Partner.Read
    roles: [dbrole_readonly]
pg_hba_rules:
  - { user: partner_ro, db: analytics, addr: 203.0.113.0/24, auth: ssl }

Effect: Partner account only has default read-only privileges after login, and can only access the analytics database via TLS from the specified network segment.

Grant DDL Capability to Business Administrators

pg_users:
  - name: app_admin
    password: DBUser.AppAdmin
    roles: [dbrole_admin]

Business administrators can inherit the default DDL privilege template by SET ROLE dbrole_admin or logging in directly as app_admin.

Customize Default Privileges

pg_default_privileges:
  - GRANT INSERT,UPDATE,DELETE ON TABLES TO dbrole_admin
  - GRANT SELECT,UPDATE ON SEQUENCES TO dbrole_admin
  - GRANT SELECT ON TABLES TO reporting_group

After replacing the default template, all objects created by administrators will carry the new privilege definitions, avoiding per-object authorization.


Coordination with Other Components

  • HBA Rules: Use pg_hba_rules to bind roles with sources (e.g., only allow dbrole_offline to access offline instances).
  • Pgbouncer: Users with pgbouncer: true will be written to userlist.txt, and pool_mode/pool_connlimit can control connection pool-level quotas.
  • Grafana/Monitoring: dbuser_monitor’s privileges come from pg_default_roles. If you add a new monitoring user, remember to grant pg_monitor + access to the monitor schema.

Through these parameters, you can version the privilege system along with code, truly achieving “configuration as policy”.

10.4 - Service/Access

Split read and write operations, route traffic correctly, and reliably deliver PostgreSQL cluster capabilities.

Split read and write operations, route traffic correctly, and reliably deliver PostgreSQL cluster capabilities.

Service is an abstraction: it is the form in which database clusters provide capabilities externally, encapsulating the details of the underlying cluster.

Service is critical for stable access in production environments, showing its value during high availability cluster automatic failovers. Personal users typically don’t need to worry about this concept.


Personal User

The concept of “service” is for production environments. Personal users/single-machine clusters can skip the complexity and directly access the database using instance names/IP addresses.

For example, Pigsty’s default single-node pg-meta.meta database can be directly connected using three different users:

psql postgres://dbuser_dba:[email protected]/meta     # Direct connection with DBA superuser
psql postgres://dbuser_meta:[email protected]/meta   # Connect with default business admin user
psql postgres://dbuser_view:DBUser.View@pg-meta/meta       # Connect with default read-only user via instance domain name

Service Overview

In real-world production environments, we use primary-replica database clusters based on replication. Within the cluster, there is one and only one instance as the leader (primary) that can accept writes. Other instances (replicas) continuously fetch change logs from the cluster leader to stay synchronized. Additionally, replicas can handle read-only requests, significantly offloading the primary in read-heavy, write-light scenarios. Therefore, distinguishing between write requests and read-only requests to the cluster is a very common practice.

Moreover, for production environments with high-frequency short connections, we pool requests through connection pooling middleware (Pgbouncer) to reduce the overhead of connection and backend process creation. But for scenarios like ETL and change execution, we need to bypass the connection pool and directly access the database. At the same time, high-availability clusters may experience failover during failures, which causes a change in the cluster leader. Therefore, high-availability database solutions require write traffic to automatically adapt to cluster leader changes. These different access requirements (read-write separation, pooling vs. direct connection, automatic adaptation to failovers) ultimately abstract the concept of Service.

Typically, database clusters must provide this most basic service:

  • Read-write service (primary): Can read and write to the database

For production database clusters, at least these two services should be provided:

  • Read-write service (primary): Write data: Only carried by the primary.
  • Read-only service (replica): Read data: Can be carried by replicas, but can also be carried by the primary if no replicas are available

Additionally, depending on specific business scenarios, there might be other services, such as:

  • Default direct access service (default): Service that allows (admin) users to bypass the connection pool and directly access the database
  • Offline replica service (offline): Dedicated replica that doesn’t handle online read-only traffic, used for ETL and analytical queries
  • Synchronous replica service (standby): Read-only service with no replication delay, handled by synchronous standby/primary for read-only queries
  • Delayed replica service (delayed): Access older data from the same cluster from a certain time ago, handled by delayed replicas

Default Service

Pigsty provides four different services by default for each PostgreSQL database cluster. Here are the default services and their definitions:

ServicePortDescription
primary5433Production read-write, connect to primary pool (6432)
replica5434Production read-only, connect to replica pool (6432)
default5436Admin, ETL writes, direct access to primary (5432)
offline5438OLAP, ETL, personal users, interactive queries

Taking the default pg-meta cluster as an example, it provides four default services:

psql postgres://dbuser_meta:DBUser.Meta@pg-meta:5433/meta   # pg-meta-primary : production read-write via primary pgbouncer(6432)
psql postgres://dbuser_meta:DBUser.Meta@pg-meta:5434/meta   # pg-meta-replica : production read-only via replica pgbouncer(6432)
psql postgres://dbuser_dba:DBUser.DBA@pg-meta:5436/meta     # pg-meta-default : direct connection via primary postgres(5432)
psql postgres://dbuser_stats:DBUser.Stats@pg-meta:5438/meta # pg-meta-offline : direct connection via offline postgres(5432)

From the sample cluster architecture diagram, you can see how these four services work:

pigsty-ha.png

Note that the pg-meta domain name points to the cluster’s L2 VIP, which in turn points to the haproxy load balancer on the cluster primary, responsible for routing traffic to different instances. See Access Service for details.


Service Implementation

In Pigsty, services are implemented using haproxy on nodes, differentiated by different ports on the host node.

Haproxy is enabled by default on every node managed by Pigsty to expose services, and database nodes are no exception. Although nodes in the cluster have primary-replica distinctions from the database perspective, from the service perspective, all nodes are the same: This means even if you access a replica node, as long as you use the correct service port, you can still use the primary’s read-write service. This design seals the complexity: as long as you can access any instance on the PostgreSQL cluster, you can fully access all services.

This design is similar to the NodePort service in Kubernetes. Similarly, in Pigsty, every service includes these two core elements:

  1. Access endpoints exposed via NodePort (port number, from where to access?)
  2. Target instances chosen through Selectors (list of instances, who will handle it?)

The boundary of Pigsty’s service delivery stops at the cluster’s HAProxy. Users can access these load balancers in various ways. Please refer to Access Service.

All services are declared through configuration files. For instance, the default PostgreSQL service is defined by the pg_default_services parameter:

pg_default_services:
- { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
- { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
- { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
- { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}

You can also define additional services in pg_services. Both pg_default_services and pg_services are arrays of Service Definition objects.


Define Service

Pigsty allows you to define your own services:

  • pg_default_services: Services uniformly exposed by all PostgreSQL clusters, with four by default.
  • pg_services: Additional PostgreSQL services, can be defined at global or cluster level as needed.
  • haproxy_services: Directly customize HAProxy service content, can be used for other component access

For PostgreSQL clusters, you typically only need to focus on the first two. Each service definition will generate a new configuration file in the configuration directory of all related HAProxy instances: /etc/haproxy/<svcname>.cfg Here’s a custom service example standby: When you want to provide a read-only service with no replication delay, you can add this record in pg_services:

- name: standby                   # required, service name, the actual svc name will be prefixed with `pg_cluster`, e.g: pg-meta-standby
  port: 5435                      # required, service exposed port (work as kubernetes service node port mode)
  ip: "*"                         # optional, service bind ip address, `*` for all ip by default
  selector: "[]"                  # required, service member selector, use JMESPath to filter inventory
  backup: "[? pg_role == `primary`]"  # optional, backup server selector, these instances will only be used when default selector instances are all down
  dest: default                   # optional, destination port, default|postgres|pgbouncer|<port_number>, 'default' by default, which means use pg_default_service_dest value
  check: /sync                    # optional, health check url path, / by default, here using Patroni API: /sync, only sync standby and primary will return 200 healthy status
  maxconn: 5000                   # optional, max allowed front-end connection, default 5000
  balance: roundrobin             # optional, haproxy load balance algorithm (roundrobin by default, other options: leastconn)
  options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'

The service definition above will be translated to a haproxy config file /etc/haproxy/pg-test-standby.conf on the sample three-node pg-test:

#---------------------------------------------------------------------
# service: pg-test-standby @ 10.10.10.11:5435
#---------------------------------------------------------------------
# service instances 10.10.10.11, 10.10.10.13, 10.10.10.12
# service backups   10.10.10.11
listen pg-test-standby
    bind *:5435            # <--- Binds to port 5435 on all IP addresses
    mode tcp               # <--- Load balancer works on TCP protocol
    maxconn 5000           # <--- Max connections 5000, can be increased as needed
    balance roundrobin     # <--- Load balance algorithm is rr round-robin, can also use leastconn
    option httpchk         # <--- Enable HTTP health check
    option http-keep-alive # <--- Keep HTTP connections
    http-check send meth OPTIONS uri /sync   # <---- Using /sync here, Patroni health check API, only sync standby and primary will return 200 healthy status
    http-check expect status 200             # <---- Health check return code 200 means healthy
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers: All three instances of pg-test cluster are selected by selector: "[]", as there are no filtering conditions, they will all be backend servers for pg-test-replica service. But due to /sync health check, only primary and sync standby can actually serve requests.
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100 backup  # <----- Only primary satisfies condition pg_role == `primary`, selected by backup selector.
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100         #        Therefore acts as fallback instance: normally doesn't serve requests, only serves read-only requests after all other replicas are down, maximizing avoidance of read-write service being affected by read-only service
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100         #

Here, all three instances of the pg-test cluster are selected by selector: "[]" and rendered into the backend server list of the pg-test-replica service. But due to the /sync health check, the Patroni Rest API only returns HTTP 200 status code representing healthy on the primary and synchronous standby, so only the primary and sync standby can actually serve requests. Additionally, the primary satisfies the condition pg_role == primary and is selected by the backup selector, marked as a backup server, and will only be used when no other instances (i.e., sync standby) can satisfy the requirement.


Primary Service

The Primary service is probably the most critical service in production environments. It provides read-write capability to the database cluster on port 5433, with the service definition as follows:

- { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
  • The selector parameter selector: "[]" means all cluster members will be included in the Primary service
  • But only the primary can pass the health check (check: /primary), actually serving Primary service traffic.
  • The destination parameter dest: default means the Primary service destination is affected by the pg_default_service_dest parameter
  • The default value of dest is default which will be replaced with the value of pg_default_service_dest, defaulting to pgbouncer.
  • By default, the Primary service destination is the connection pool on the primary, i.e., the port specified by pgbouncer_port, defaulting to 6432

If the value of pg_default_service_dest is postgres, then the primary service destination will bypass the connection pool and directly use the PostgreSQL database port (pg_port, default value 5432), which is very useful for scenarios where you don’t want to use a connection pool.

Example: pg-test-primary haproxy configuration
listen pg-test-primary
    bind *:5433         # <--- primary service defaults to port 5433
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /primary # <--- primary service defaults to using Patroni RestAPI /primary health check
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100

Patroni’s high availability mechanism ensures that at most one instance’s /primary health check is true at any time, so the Primary service will always route traffic to the primary instance.

One benefit of using the Primary service instead of directly connecting to the database is that if the cluster experiences a split-brain situation (for example, killing the primary Patroni with kill -9 without watchdog), Haproxy can still avoid split-brain in this situation, because it only distributes traffic when Patroni is alive and returns primary status.


Replica Service

The Replica service is second only to the Primary service in importance in production environments. It provides read-only capability to the database cluster on port 5434, with the service definition as follows:

- { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
  • The selector parameter selector: "[]" means all cluster members will be included in the Replica service
  • All instances can pass the health check (check: /read-only), serving Replica service traffic.
  • Backup selector: [? pg_role == 'primary' || pg_role == 'offline' ] marks the primary and offline replicas as backup servers.
  • Only when all regular replicas are down will the Replica service be served by the primary or offline replicas.
  • The destination parameter dest: default means the Replica service destination is also affected by the pg_default_service_dest parameter
  • The default value of dest is default which will be replaced with the value of pg_default_service_dest, defaulting to pgbouncer, same as the Primary service
  • By default, the Replica service destination is the connection pool on replicas, i.e., the port specified by pgbouncer_port, defaulting to 6432
Example: pg-test-replica haproxy configuration
listen pg-test-replica
    bind *:5434
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /read-only
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100 backup
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100

The Replica service is very flexible: If there are living dedicated Replica instances, it will prioritize using these instances to serve read-only requests. Only when all replica instances are down will the primary serve as a fallback for read-only requests. For the common one-primary-one-replica two-node cluster: use the replica as long as it’s alive, use the primary only when the replica is down.

Additionally, unless all dedicated read-only instances are down, the Replica service will not use dedicated Offline instances, thus avoiding mixing online fast queries with offline slow queries and their mutual interference.


Default Service

The Default service provides service on port 5436, and it’s a variant of the Primary service.

The Default service always bypasses the connection pool and directly connects to PostgreSQL on the primary, which is useful for admin connections, ETL writes, CDC change data capture, etc.

- { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }

If pg_default_service_dest is changed to postgres, then the Default service is completely equivalent to the Primary service except for port and name. In this case, you can consider removing Default from default services.

Example: pg-test-default haproxy configuration
listen pg-test-default
    bind *:5436         # <--- Except for listening port/target port and service name, other configurations are the same as primary service
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /primary
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:5432 check port 8008 weight 100
    server pg-test-3 10.10.10.13:5432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:5432 check port 8008 weight 100

Offline Service

The Offline service provides service on port 5438, and it also bypasses the connection pool to directly access PostgreSQL database, typically used for slow queries/analytical queries/ETL reads/personal user interactive queries, with service definition as follows:

- { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}

The Offline service routes traffic directly to dedicated offline replicas, or regular read-only instances marked with pg_offline_query.

  • The selector parameter filters two types of instances from the cluster: offline replicas with pg_role = offline, or regular read-only instances marked with pg_offline_query = true
  • The main difference between dedicated offline replicas and marked regular replicas is: the former doesn’t serve Replica service requests by default, avoiding mixing fast and slow queries, while the latter does serve by default.
  • The backup selector parameter filters one type of instance from the cluster: regular replicas without the offline mark, which means if offline instances or marked regular replicas are down, other regular replicas can be used to serve Offline service.
  • Health check /replica only returns 200 for replicas, primary returns error, so Offline service will never distribute traffic to the primary instance, even if only the primary remains in the cluster.
  • At the same time, the primary instance is neither selected by the selector nor by the backup selector, so it will never serve Offline service. Therefore, Offline service can always avoid users accessing the primary, thus avoiding impact on the primary.
Example: pg-test-offline haproxy configuration
listen pg-test-offline
    bind *:5438
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /replica
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-3 10.10.10.13:5432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:5432 check port 8008 weight 100 backup

The Offline service provides restricted read-only service, typically used for two types of queries: interactive queries (personal users), slow queries and long transactions (analytics/ETL).

The Offline service requires extra maintenance care: When the cluster undergoes primary-replica switchover or automatic failover, the instance roles will change, but Haproxy configuration won’t automatically change. For clusters with multiple replicas, this is usually not a problem. However, for streamlined small clusters with one-primary-one-replica where the replica runs Offline queries, primary-replica switchover means the replica becomes primary (health check fails), and the original primary becomes replica (not in Offline backend list), so no instance can serve Offline service, requiring manual reload service to make changes effective.

If your business model is relatively simple, you can consider removing Default service and Offline service, using Primary service and Replica service to directly connect to the database.


Reload Service

When cluster membership changes, such as adding/removing replicas, switchover/failover, or adjusting relative weights, you need to reload service to make the changes take effect.

bin/pgsql-svc <cls> [ip...]         # reload service for lb cluster or lb instance
# ./pgsql.yml -t pg_service         # the actual ansible task to reload service

Access Service

The boundary of Pigsty’s service delivery stops at the cluster’s HAProxy. Users can access these load balancers in various ways.

The typical approach is to use DNS or VIP access, binding to all or any number of load balancers in the cluster.

pigsty-access.jpg

You can use different host & port combinations, which provide PostgreSQL services in different ways.

Host

TypeExampleDescription
Cluster Domain Namepg-testAccess via cluster domain name (resolved by dnsmasq @ infra nodes)
Cluster VIP Address10.10.10.3Access via L2 VIP address managed by vip-manager, bound to primary
Instance Hostnamepg-test-1Access via any instance hostname (resolved by dnsmasq @ infra nodes)
Instance IP Address10.10.10.11Access any instance IP address

Port

Pigsty uses different ports to distinguish pg services

PortServiceTypeDescription
5432postgresdatabaseDirect access to postgres server
6432pgbouncermiddlewareGo through connection pool middleware before postgres
5433primaryserviceAccess primary pgbouncer (or postgres)
5434replicaserviceAccess replica pgbouncer (or postgres)
5436defaultserviceAccess primary postgres
5438offlineserviceAccess offline postgres

Combinations

# Access via cluster domain
postgres://test@pg-test:5432/test # DNS -> L2 VIP -> primary direct connection
postgres://test@pg-test:6432/test # DNS -> L2 VIP -> primary connection pool -> primary
postgres://test@pg-test:5433/test # DNS -> L2 VIP -> HAProxy -> Primary Connection Pool -> Primary
postgres://test@pg-test:5434/test # DNS -> L2 VIP -> HAProxy -> Replica Connection Pool -> Replica
postgres://dbuser_dba@pg-test:5436/test # DNS -> L2 VIP -> HAProxy -> Primary direct connection (for Admin)
postgres://dbuser_stats@pg-test:5438/test # DNS -> L2 VIP -> HAProxy -> offline direct connection (for ETL/personal queries)

# Direct access via cluster VIP
postgres://[email protected]:5432/test # L2 VIP -> Primary direct access
postgres://[email protected]:6432/test # L2 VIP -> Primary Connection Pool -> Primary
postgres://[email protected]:5433/test # L2 VIP -> HAProxy -> Primary Connection Pool -> Primary
postgres://[email protected]:5434/test # L2 VIP -> HAProxy -> Replica Connection Pool -> Replica
postgres://[email protected]:5436/test # L2 VIP -> HAProxy -> Primary direct connection (for Admin)
postgres://[email protected]::5438/test # L2 VIP -> HAProxy -> offline direct connect (for ETL/personal queries)

# Specify any cluster instance name directly
postgres://test@pg-test-1:5432/test # DNS -> Database Instance Direct Connect (singleton access)
postgres://test@pg-test-1:6432/test # DNS -> connection pool -> database
postgres://test@pg-test-1:5433/test # DNS -> HAProxy -> connection pool -> database read/write
postgres://test@pg-test-1:5434/test # DNS -> HAProxy -> connection pool -> database read-only
postgres://dbuser_dba@pg-test-1:5436/test # DNS -> HAProxy -> database direct connect
postgres://dbuser_stats@pg-test-1:5438/test # DNS -> HAProxy -> database offline read/write

# Directly specify any cluster instance IP access
postgres://[email protected]:5432/test # Database instance direct connection (directly specify instance, no automatic traffic distribution)
postgres://[email protected]:6432/test # Connection Pool -> Database
postgres://[email protected]:5433/test # HAProxy -> connection pool -> database read/write
postgres://[email protected]:5434/test # HAProxy -> connection pool -> database read-only
postgres://[email protected]:5436/test # HAProxy -> Database Direct Connections
postgres://[email protected]:5438/test # HAProxy -> database offline read-write

# Smart client automatic read/write separation
postgres://[email protected]:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=primary
postgres://[email protected]:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=prefer-standby

Override Service

You can override the default service configuration in several ways. A common requirement is to have Primary service and Replica service bypass Pgbouncer connection pool and directly access PostgreSQL database.

To achieve this, you can change pg_default_service_dest to postgres, so all services with svc.dest='default' in the service definition will use postgres instead of the default pgbouncer as the target.

If you’ve already pointed Primary service to PostgreSQL, then the default service becomes redundant and can be removed.

If you don’t need to distinguish between personal interactive queries and analytics/ETL slow queries, you can consider removing the Offline service from the default service list pg_default_services.

If you don’t need read-only replicas to share online read-only traffic, you can also remove Replica service from the default service list.


Delegate Service

Pigsty exposes PostgreSQL services with haproxy on nodes. All haproxy instances in the cluster are configured with the same service definition.

However, you can delegate pg service to a specific node group (e.g., dedicated haproxy lb cluster) rather than haproxy on PostgreSQL cluster members.

To do so, you need to override the default service definition with pg_default_services and set pg_service_provider to the proxy group name.

For example, this configuration will expose pg cluster primary service on haproxy node group proxy with port 10013.

pg_service_provider: proxy       # use load balancer on group `proxy` with port 10013
pg_default_services:  [{ name: primary ,port: 10013 ,dest: postgres  ,check: /primary   ,selector: "[]" }]

It’s user’s responsibility to make sure each delegate service port is unique among the proxy cluster.

A dedicated load balancer cluster example is provided in the 43-node production environment simulation sandbox: prod.yml

10.5 - Access Control

Default role system and privilege model provided by Pigsty

Pigsty provides a battery-included access control model based on role system and privilege system.

Access control is crucial, yet many users struggle to implement it properly. Therefore, Pigsty provides a streamlined, battery-included access control model to provide a safety net for your cluster security.


Role System

Pigsty’s default role system includes four default roles and four default users:

Role NameAttributesMember ofDescription
dbrole_readonlyNOLOGINrole for global read-only access
dbrole_readwriteNOLOGINdbrole_readonlyrole for global read-write access
dbrole_adminNOLOGINpg_monitor,dbrole_readwriterole for admin/object creation
dbrole_offlineNOLOGINrole for restricted read-only access
postgresSUPERUSERsystem superuser
replicatorREPLICATIONpg_monitor,dbrole_readonlysystem replicator
dbuser_dbaSUPERUSERdbrole_adminpgsql admin user
dbuser_monitorpg_monitorpgsql monitor user

The detailed definitions of these roles and users are as follows:

pg_default_roles:                 # default roles and users in postgres cluster
  - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
  - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
  - { name: postgres     ,superuser: true  ,comment: system superuser }
  - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator }
  - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
  - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

Default Roles

There are four default roles in Pigsty:

  • Read-Only (dbrole_readonly): Role for global read-only access. If other business applications need read-only access to this database, they can use this role.
  • Read-Write (dbrole_readwrite): Role for global read-write access, the primary business production account should have database read-write privileges.
  • Admin (dbrole_admin): Role with DDL privileges, typically used for business administrators or scenarios requiring table creation in applications (such as various business software).
  • Offline (dbrole_offline): Restricted read-only access role (can only access offline instances, typically for personal users and ETL tool accounts).

Default roles are defined in pg_default_roles. Unless you really know what you’re doing, it’s recommended not to change the default role names.

- { name: dbrole_readonly  , login: false , comment: role for global read-only access  }                            # production read-only role
- { name: dbrole_offline ,   login: false , comment: role for restricted read-only access (offline instance) }      # restricted read-only role
- { name: dbrole_readwrite , login: false , roles: [dbrole_readonly], comment: role for global read-write access }  # production read-write role
- { name: dbrole_admin , login: false , roles: [pg_monitor, dbrole_readwrite] , comment: role for object creation } # production DDL change role

Default Users

Pigsty also has four default users (system users):

  • Superuser (postgres), the owner and creator of the cluster, same name as the OS dbsu.
  • Replication user (replicator), the system user used for primary-replica replication.
  • Monitor user (dbuser_monitor), a user used to monitor database and connection pool metrics.
  • Admin user (dbuser_dba), the admin user who performs daily operations and database changes.

The usernames/passwords for these 4 default users are defined through 4 pairs of dedicated parameters, referenced in many places:

Remember to change these passwords in production deployment! Do not use the default values!

pg_dbsu: postgres                             # database superuser name, better not to change this username.
pg_dbsu_password: ''                          # database superuser password, it's recommended to leave this empty! Disable dbsu password login.
pg_replication_username: replicator           # system replication username
pg_replication_password: DBUser.Replicator    # system replication password, must change this password!
pg_monitor_username: dbuser_monitor           # system monitor username
pg_monitor_password: DBUser.Monitor           # system monitor password, must change this password!
pg_admin_username: dbuser_dba                 # system admin username
pg_admin_password: DBUser.DBA                 # system admin password, must change this password!

If you modify the default user parameters, modify the corresponding role definitions in pg_default_roles:

- { name: postgres     ,superuser: true                                          ,comment: system superuser }
- { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly]   ,comment: system replicator }
- { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
- { name: dbuser_monitor   ,roles: [pg_monitor, dbrole_readonly] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

Privilege System

Pigsty has a battery-included privilege model that works with default roles.

  • All users have access to all schemas.
  • Read-Only users (dbrole_readonly) can read from all tables. (SELECT, EXECUTE)
  • Read-Write users (dbrole_readwrite) can write to all tables and run DML. (INSERT, UPDATE, DELETE).
  • Admin users (dbrole_admin) can create objects and run DDL (CREATE, USAGE, TRUNCATE, REFERENCES, TRIGGER).
  • Offline users (dbrole_offline) are similar to read-only users but with restricted access, only allowed to access offline instances (pg_role = 'offline' or pg_offline_query = true)
  • Objects created by admin users will have correct privileges.
  • Default privileges are configured on all databases, including template databases.
  • Database connect privileges are managed by database definitions.
  • The CREATE privilege on database and public schema is revoked from PUBLIC by default.

Object Privileges

Default privileges for newly created objects in the database are controlled by the parameter pg_default_privileges:

- GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
- GRANT SELECT     ON TABLES    TO dbrole_readonly
- GRANT SELECT     ON SEQUENCES TO dbrole_readonly
- GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
- GRANT USAGE      ON SCHEMAS   TO dbrole_offline
- GRANT SELECT     ON TABLES    TO dbrole_offline
- GRANT SELECT     ON SEQUENCES TO dbrole_offline
- GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
- GRANT INSERT     ON TABLES    TO dbrole_readwrite
- GRANT UPDATE     ON TABLES    TO dbrole_readwrite
- GRANT DELETE     ON TABLES    TO dbrole_readwrite
- GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
- GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
- GRANT TRUNCATE   ON TABLES    TO dbrole_admin
- GRANT REFERENCES ON TABLES    TO dbrole_admin
- GRANT TRIGGER    ON TABLES    TO dbrole_admin
- GRANT CREATE     ON SCHEMAS   TO dbrole_admin

Objects newly created by admin users will have the above privileges by default. Use \ddp+ to view these default privileges:

TypeAccess privileges
function=X
dbrole_readonly=X
dbrole_offline=X
dbrole_admin=X
schemadbrole_readonly=U
dbrole_offline=U
dbrole_admin=UC
sequencedbrole_readonly=r
dbrole_offline=r
dbrole_readwrite=wU
dbrole_admin=rwU
tabledbrole_readonly=r
dbrole_offline=r
dbrole_readwrite=awd
dbrole_admin=arwdDxt

Default Privileges

ALTER DEFAULT PRIVILEGES allows you to set the privileges that will be applied to objects created in the future. It does not affect privileges assigned to already-existing objects, nor objects created by non-admin users.

In Pigsty, default privileges are defined for three roles:

{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE {{ pg_dbsu }} {{ priv }};
{% endfor %}

{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE {{ pg_admin_username }} {{ priv }};
{% endfor %}

-- For other business administrators, they should execute SET ROLE dbrole_admin before running DDL to use the corresponding default privilege configuration.
{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE "dbrole_admin" {{ priv }};
{% endfor %}

These contents will be used by the PG cluster initialization template pg-init-template.sql, rendered and output to /pg/tmp/pg-init-template.sql during cluster initialization. This command will be executed on template1 and postgres databases, and newly created databases will inherit these default privilege configurations through template template1.

That is to say, to maintain correct object privileges, you must run DDL with admin users, which could be:

  1. {{ pg_dbsu }}, defaults to postgres
  2. {{ pg_admin_username }}, defaults to dbuser_dba
  3. Business admin users granted with dbrole_admin role (switch to dbrole_admin identity via SET ROLE)

It’s wise to use postgres as the global object owner. If you wish to create objects with business admin user, you must use SET ROLE dbrole_admin before running DDL to maintain correct privileges.

Of course, you can also explicitly grant default privileges to business admins in the database with ALTER DEFAULT PRIVILEGE FOR ROLE <some_biz_admin> XXX.


Database Privileges

In Pigsty, database-level privileges are covered in database definitions.

There are 3 database-level privileges: CONNECT, CREATE, TEMP, and a special ‘privilege’: OWNERSHIP.

- name: meta         # required, `name` is the only mandatory field in database definition
  owner: postgres    # optional, database owner, defaults to postgres
  allowconn: true    # optional, allow connection, true by default. false will completely disable connection to this database
  revokeconn: false  # optional, revoke public connection privilege. false by default, when set to true, CONNECT privilege will be revoked from users other than owner and admin
  • If owner parameter exists, it will be used as the database owner instead of the default {{ pg_dbsu }} (usually postgres)
  • If revokeconn is false, all users have the database’s CONNECT privilege, this is the default behavior.
  • If revokeconn is explicitly set to true:
    • The database’s CONNECT privilege will be revoked from PUBLIC: ordinary users cannot connect to this database
    • CONNECT privilege will be explicitly granted to {{ pg_replication_username }}, {{ pg_monitor_username }} and {{ pg_admin_username }}
    • CONNECT privilege will be granted to the database owner with GRANT OPTION, the database owner can then grant connection privileges to other users.
  • The revokeconn option can be used to isolate cross-database access within the same cluster. You can create different business users as owners for each database and set the revokeconn option for them.
Example: Database Isolation
pg-infra:
  hosts:
    10.10.10.40: { pg_seq: 1, pg_role: primary }
    10.10.10.41: { pg_seq: 2, pg_role: replica , pg_offline_query: true }
  vars:
    pg_cluster: pg-infra
    pg_users:
      - { name: dbuser_confluence, password: mc2iohos , pgbouncer: true, roles: [ dbrole_admin ] }
      - { name: dbuser_gitlab, password: sdf23g22sfdd , pgbouncer: true, roles: [ dbrole_readwrite ] }
      - { name: dbuser_jira, password: sdpijfsfdsfdfs , pgbouncer: true, roles: [ dbrole_admin ] }
    pg_databases:
      - { name: confluence , revokeconn: true, owner: dbuser_confluence , connlimit: 100 }
      - { name: gitlab , revokeconn: true, owner: dbuser_gitlab, connlimit: 100 }
      - { name: jira , revokeconn: true, owner: dbuser_jira , connlimit: 100 }

CREATE Privileges

For security considerations, Pigsty revokes the CREATE privilege on database from PUBLIC by default, and this has been the default behavior since PostgreSQL 15.

The database owner can always adjust CREATE privileges as needed based on actual requirements.

10.6 - Administration

Database administration and operation tasks

10.7 - Administration

Standard Operating Procedures (SOP) for database administration tasks

How to maintain existing PostgreSQL clusters with Pigsty?

This section provides standard operating procedures (SOP) for common PostgreSQL administration tasks:

  • SOP: Standard operating procedures for creating/removing clusters and instances, backup & restore, rolling upgrades, etc.
  • Failure: Common failure troubleshooting strategies and handling methods, such as disk exhaustion, connection exhaustion, XID wraparound, etc.
  • Drop: Emergency procedures for handling accidental data deletion, table drops, and database drops
  • Maintain: Maintenance tasks including regular inspections, post-failover cleanup, bloat management, VACUUM FREEZE, etc.
  • Tuning: Automatic optimization strategies and adjustment methods for memory, CPU, storage parameters, etc.

10.7.1 - Troubleshooting

Common failures and analysis troubleshooting approaches

This document lists potential failures in PostgreSQL and Pigsty, as well as SOPs for locating, handling, and analyzing issues.


Disk Space Exhausted

Disk space exhaustion is the most common type of failure.

Symptoms

When the disk space where the database resides is exhausted, PostgreSQL will not work normally and may exhibit the following symptoms: database logs repeatedly report “no space left on device” errors, new data cannot be written, and PostgreSQL may even trigger a PANIC and force shutdown.

Pigsty includes a NodeFsSpaceFull alert rule that triggers when filesystem available space is less than 10%. Use the monitoring system’s NODE Instance panel to review the FS metrics panel to locate the issue.

Diagnosis

You can also log into the database node and use df -h to view the usage of each mounted partition to determine which partition is full. For database nodes, focus on checking the following directories and their sizes to determine which category of files has filled up the space:

  • Data directory (/pg/data/base): Stores data files for tables and indexes; pay attention to heavy writes and temporary files
  • WAL directory (e.g., pg/data/pg_wal): Stores PG WAL; WAL accumulation/replication slot retention is a common cause of disk exhaustion.
  • Database log directory (e.g., pg/log): If PG logs are not rotated in time and large amounts of errors are written, they may also consume significant space.
  • Local backup directory (e.g., data/backups): When using pgBackRest or similar tools to save backups locally, this may also fill up the disk.

If the issue occurs on the Pigsty admin node or monitoring node, also consider:

  • Monitoring data: VictoriaMetrics time-series metrics and VictoriaLogs log storage both consume disk space; check retention policies.
  • Object storage data: Pigsty’s integrated MinIO object storage may be used for PG backup storage.

After identifying the directory consuming the most space, you can further use du -sh <directory> to drill down and find specific large files or subdirectories.

Resolution

Disk exhaustion is an emergency issue requiring immediate action to free up space and ensure the database continues to operate. When the data disk is not separated from the system disk, a full disk may prevent shell commands from executing. In this case, you can delete the /pg/dummy placeholder file to free up a small amount of emergency space so shell commands can work again. If the database has crashed due to pg_wal filling up, you need to restart the database service after clearing space and carefully check data integrity.


Transaction ID Wraparound

PostgreSQL cyclically uses 32-bit transaction IDs (XIDs), and when exhausted, a “transaction ID wraparound” failure occurs (XID Wraparound).

Symptoms

The typical sign in the first phase is when the age saturation in the PGSQL Persist - Age Usage panel enters the warning zone. Database logs begin to show messages like: WARNING: database "postgres" must be vacuumed within xxxxxxxx transactions.

If the problem continues to worsen, PostgreSQL enters protection mode: when remaining transaction IDs drop to about 1 million, the database switches to read-only mode; when reaching the limit of about 2.1 billion (2^31), it refuses any new transactions and forces the server to shut down to avoid data corruption.

Diagnosis

PostgreSQL and Pigsty enable automatic garbage collection (AutoVacuum) by default, so the occurrence of this type of failure usually has deeper root causes. Common causes include: very long transactions (SAGE), misconfigured Autovacuum, replication slot blockage, insufficient resources, storage engine/extension bugs, disk bad blocks.

First identify the database with the highest age, then use the Pigsty PGCAT Database - Tables panel to confirm the age distribution of tables. Also review the database error logs, which usually contain clues to locate the root cause.

Resolution

  1. Immediately freeze old transactions: If the database has not yet entered read-only protection mode, immediately execute a manual VACUUM FREEZE on the affected database. You can start by freezing the most severely aged tables one by one rather than doing the entire database at once to accelerate the effect. Connect to the database as a superuser and run VACUUM FREEZE table_name; on tables identified with the largest relfrozenxid, prioritizing tables with the highest XID age. This can quickly reclaim large amounts of transaction ID space.
  2. Single-user mode rescue: If the database is already refusing writes or has crashed for protection, you need to start the database in single-user mode to perform freeze operations. In single-user mode, run VACUUM FREEZE database_name; to freeze and clean the entire database. After completion, restart the database in multi-user mode. This can lift the wraparound lock and make the database writable again. Be very careful when operating in single-user mode and ensure sufficient transaction ID margin to complete the freeze.
  3. Standby node takeover: In some complex scenarios (e.g., when hardware issues prevent vacuum from completing), consider promoting a read-only standby node in the cluster to primary to obtain a relatively clean environment for handling the freeze. For example, if the primary cannot vacuum due to bad blocks, you can manually failover to promote the standby to the new primary, then perform emergency vacuum freeze on it. After ensuring the new primary has frozen old transactions, switch the load back.

Connection Exhaustion

PostgreSQL has a maximum connections configuration (max_connections). When client connections exceed this limit, new connection requests will be rejected. The typical symptom is that applications cannot connect to the database and report errors like FATAL: remaining connection slots are reserved for non-replication superuser connections or too many clients already. This indicates that regular connections are exhausted, leaving only slots reserved for superusers or replication.

Diagnosis

Connection exhaustion is usually caused by a large number of concurrent client requests. You can directly review the database’s current active sessions through PGCAT Instance / PGCAT Database / PGCAT Locks. Determine what types of queries are filling the system and proceed with further handling. Pay special attention to whether there are many connections in the “Idle in Transaction” state and long-running transactions (as well as slow queries).

Resolution

Kill queries: For situations where exhaustion has already blocked business operations, typically use pg_terminate_backend(pid) immediately for emergency pressure relief. For cases using connection pooling, you can adjust the connection pool size parameters and execute a reload to reduce the number of connections at the database level.

You can also modify the max_connections parameter to a larger value, but this parameter requires a database restart to take effect.


etcd Quota Exhausted

An exhausted etcd quota will cause the PG high availability control plane to fail and prevent configuration changes.

Diagnosis

Pigsty uses etcd as the distributed configuration store (DCS) when implementing high availability. etcd itself has a storage quota (default is about 2GB). When etcd storage usage reaches the quota limit, etcd will refuse write operations and report “etcdserver: mvcc: database space exceeded”. In this case, Patroni cannot write heartbeats or update configuration to etcd, causing cluster management functions to fail.

Resolution

Versions between Pigsty v2.0.0 and v2.5.1 are affected by this issue by default. Pigsty v2.6.0 added auto-compaction configuration for deployed etcd. If you only use it for PG high availability leases, this issue will no longer occur in regular use cases.


Defective Storage Engine

Currently, TimescaleDB’s experimental storage engine Hypercore has been proven to have defects, with cases of VACUUM being unable to reclaim leading to XID wraparound failures. Users using this feature should migrate to PostgreSQL native tables or TimescaleDB’s default engine promptly.

Detailed introduction: PG New Storage Engine Failure Case (Chinese)

10.7.2 - Database Management

Database management: create, modify, delete, rebuild databases, and clone databases using templates

In Pigsty, database management follows an IaC (Infrastructure as Code) approach—define in the configuration inventory, then execute playbooks.

When no baseline SQL is defined, executing the pgsql-db.yml playbook is idempotent. It adjusts the specified database in the specified cluster to match the target state in the configuration inventory.

Note that some parameters can only be specified at creation time. Modifying these parameters requires deleting and recreating the database (using state: recreate to rebuild).


Define Database

Business databases are defined in the cluster parameter pg_databases, which is an array of database definition objects. Databases in the array are created in definition order, so later-defined databases can use previously-defined databases as templates.

Here’s the database definition from the default cluster pg-meta in Pigsty’s demo environment:

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 ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: postgis, schema: public}, {name: timescaledb}]}
      - { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
      - { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
      - { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
      - { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
      - { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }
      - { name: noco     ,owner: dbuser_noco     ,revokeconn: true ,comment: nocodb database }

The only required field is name, which should be a valid and unique database name within the current PostgreSQL cluster—all other parameters have sensible defaults. For complete database definition parameter reference, see Database Configuration Reference.


Create Database

To create a new business database on an existing PostgreSQL cluster, add the database definition to all.children.<cls>.pg_databases, then execute:

bin/pgsql-db <cls> <dbname>    # Equivalent to: pgsql-db.yml -l <cls> -e dbname=<dbname>

Example: Create a business database named myapp

  1. Add the database definition to the configuration file:
pg-meta:
  vars:
    pg_databases:
      - name: myapp
        owner: dbuser_myapp
        schemas: [app]
        extensions:
          - { name: pg_trgm }
          - { name: btree_gin }
        comment: my application database
  1. Execute the create command:
bin/pgsql-db pg-meta myapp

Execution effects:

  • Creates database myapp on the primary
  • Sets database owner to dbuser_myapp
  • Creates schema app
  • Installs extensions pg_trgm and btree_gin
  • Configures default privileges (dbrole_readonly/readwrite/admin)
  • Adds database to Pgbouncer connection pool
  • Registers database as a Grafana data source

Modify Database

Modify database properties by updating the configuration and re-executing the playbook:

bin/pgsql-db <cls> <dbname>    # Idempotent operation, can be executed repeatedly

Modifiable Properties

PropertyDescriptionExample
ownerDatabase ownerowner: dbuser_new
tablespaceDefault tablespace (triggers data migration)tablespace: fast_ssd
is_templateMark as template databaseis_template: true
allowconnAllow connectionsallowconn: false
connlimitConnection limitconnlimit: 100
revokeconnRevoke PUBLIC CONNECT privilegerevokeconn: true
commentCommentcomment: new comment
parametersDatabase-level parametersSee examples below
schemasAdd/remove schemas (incremental)See Manage Schemas
extensionsAdd/remove extensions (incremental)See Manage Extensions
pgbouncerInclude in connection poolpgbouncer: false
pool_*Connection pool parametersSee Connection Pool Config

Non-modifiable Properties

The following properties cannot be modified after database creation—use state: recreate to rebuild the database:

  • template - Template database
  • encoding - Character encoding
  • locale / lc_collate / lc_ctype - Locale settings
  • locale_provider / icu_locale / icu_rules / builtin_locale - Locale provider settings
  • strategy - Clone strategy

Change Owner

- name: myapp
  owner: dbuser_new_owner     # Change to new owner
bin/pgsql-db pg-meta myapp

Executed SQL:

ALTER DATABASE "myapp" OWNER TO "dbuser_new_owner";
GRANT ALL PRIVILEGES ON DATABASE "myapp" TO "dbuser_new_owner";

Change Connection Limit

- name: myapp
  connlimit: 100              # Limit to max 100 connections

Executed SQL:

ALTER DATABASE "myapp" CONNECTION LIMIT 100;

Revoke Public Connection Privilege

- name: myapp
  owner: dbuser_myapp
  revokeconn: true            # Revoke PUBLIC CONNECT privilege

Executed SQL:

REVOKE CONNECT ON DATABASE "myapp" FROM PUBLIC;
GRANT CONNECT ON DATABASE "myapp" TO "replicator";
GRANT CONNECT ON DATABASE "myapp" TO "dbuser_monitor";
GRANT CONNECT ON DATABASE "myapp" TO "dbuser_dba" WITH GRANT OPTION;
GRANT CONNECT ON DATABASE "myapp" TO "dbuser_myapp" WITH GRANT OPTION;

To restore public connection privilege, set revokeconn: false:

- name: myapp
  revokeconn: false           # Restore PUBLIC CONNECT privilege

Executed SQL:

GRANT CONNECT ON DATABASE "myapp" TO PUBLIC;

Mark as Template Database

- name: app_template
  is_template: true           # Allow any user with CREATEDB privilege to clone

Executed SQL:

ALTER DATABASE "app_template" IS_TEMPLATE true;

Manage Parameters

Database-level parameters are configured via the parameters dictionary, generating ALTER DATABASE ... SET statements.

Set Parameters

- name: myapp
  parameters:
    work_mem: '256MB'
    maintenance_work_mem: '512MB'
    statement_timeout: '30s'
    search_path: 'app,public'

Executed SQL:

ALTER DATABASE "myapp" SET "work_mem" = '256MB';
ALTER DATABASE "myapp" SET "maintenance_work_mem" = '512MB';
ALTER DATABASE "myapp" SET "statement_timeout" = '30s';
ALTER DATABASE "myapp" SET "search_path" = 'app,public';

Reset Parameters to Default

Use the special value DEFAULT (case-insensitive) to reset parameters to PostgreSQL defaults:

- name: myapp
  parameters:
    work_mem: DEFAULT         # Reset to PostgreSQL default
    statement_timeout: DEFAULT

Executed SQL:

ALTER DATABASE "myapp" SET "work_mem" = DEFAULT;
ALTER DATABASE "myapp" SET "statement_timeout" = DEFAULT;

Common Database-Level Parameters

ParameterDescriptionExample Value
work_memQuery work memory'64MB'
maintenance_work_memMaintenance operation memory'256MB'
statement_timeoutStatement timeout'30s'
lock_timeoutLock wait timeout'10s'
idle_in_transaction_session_timeoutIdle transaction timeout'10min'
search_pathSchema search path'app,public'
default_tablespaceDefault tablespace'fast_ssd'
temp_tablespacesTemporary tablespaces'temp_ssd'
log_statementStatement logging level'ddl'

Manage Schemas

Schemas are configured via the schemas array, supporting create, assign owner, and delete operations.

Create Schemas

- name: myapp
  schemas:
    # Simple form: schema name only
    - app
    - api

    # Full form: specify owner
    - { name: core, owner: dbuser_myapp }

Executed SQL:

CREATE SCHEMA IF NOT EXISTS "app";
CREATE SCHEMA IF NOT EXISTS "api";
CREATE SCHEMA IF NOT EXISTS "core" AUTHORIZATION "dbuser_myapp";

Specify Schema Owner

Use the owner field to assign a schema owner—useful for multi-tenant or permission isolation scenarios:

- name: multi_tenant_db
  owner: dbuser_admin
  schemas:
    - { name: tenant_a, owner: dbuser_tenant_a }
    - { name: tenant_b, owner: dbuser_tenant_b }
    - { name: shared, owner: dbuser_admin }

Delete Schemas

Use state: absent to mark schemas for deletion:

- name: myapp
  schemas:
    - { name: deprecated_schema, state: absent }

Executed SQL:

DROP SCHEMA IF EXISTS "deprecated_schema" CASCADE;

Manage Extensions

Extensions are configured via the extensions array, supporting install and uninstall operations.

Install Extensions

- name: myapp
  extensions:
    # Simple form: extension name only
    - postgis
    - pg_trgm

    # Full form: specify schema and version
    - { name: vector, schema: public }
    - { name: pg_stat_statements, schema: monitor, version: '1.10' }

Executed SQL:

CREATE EXTENSION IF NOT EXISTS "postgis" CASCADE;
CREATE EXTENSION IF NOT EXISTS "pg_trgm" CASCADE;
CREATE EXTENSION IF NOT EXISTS "vector" WITH SCHEMA "public" CASCADE;
CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" WITH SCHEMA "monitor" VERSION '1.10' CASCADE;

Uninstall Extensions

Use state: absent to mark extensions for uninstall:

- name: myapp
  extensions:
    - { name: pg_trgm, state: absent }    # Uninstall extension
    - { name: postgis }                    # Keep extension

Executed SQL:

DROP EXTENSION IF EXISTS "pg_trgm" CASCADE;
CREATE EXTENSION IF NOT EXISTS "postgis" CASCADE;

Delete Database

To delete a database, set its state to absent and execute the playbook:

pg_databases:
  - name: olddb
    state: absent
bin/pgsql-db <cls> olddb

Delete operation will:

  1. If database is marked is_template: true, first execute ALTER DATABASE ... IS_TEMPLATE false
  2. Force drop database with DROP DATABASE ... WITH (FORCE) (PG13+)
  3. Terminate all active connections to the database
  4. Remove database from Pgbouncer connection pool
  5. Unregister from Grafana data sources

Protection mechanisms:

  • System databases postgres, template0, template1 cannot be deleted
  • Delete operations only execute on the primary—streaming replication syncs to replicas automatically

Rebuild Database

The recreate state rebuilds a database, equivalent to delete then create:

pg_databases:
  - name: testdb
    state: recreate
    owner: dbuser_test
    baseline: test_init.sql    # Execute initialization after rebuild
bin/pgsql-db <cls> testdb

Use cases:

  • Test environment reset
  • Clear development database
  • Modify immutable properties (encoding, locale, etc.)
  • Restore database to initial state

Difference from manual DROP + CREATE:

  • Single command, no need for two operations
  • Automatically preserves Pgbouncer and Grafana configuration
  • Automatically loads baseline initialization script after execution

Clone Database

You can use an existing database as a template to create a new database, enabling quick replication of database structures.

Basic Clone

pg_databases:
  # 1. First define the template database
  - name: app_template
    owner: dbuser_app
    schemas: [core, api]
    extensions: [postgis, pg_trgm]
    baseline: app_schema.sql

  # 2. Create business database using template
  - name: app_prod
    template: app_template
    owner: dbuser_app

Specify Clone Strategy (PG15+)

- name: app_staging
  template: app_template
  strategy: FILE_COPY        # Or WAL_LOG
  owner: dbuser_app
StrategyDescriptionUse Case
FILE_COPYDirect data file copyLarge templates, general scenarios
WAL_LOGCopy via WAL logsSmall templates, doesn’t block template connections

Use Custom Template Database

When using non-system templates (not template0/template1), Pigsty automatically terminates connections to the template database to allow cloning.

- name: new_db
  template: existing_db      # Use existing business database as template
  owner: dbuser_app

Mark as Template Database

By default, only superusers or database owners can use regular databases as templates. Using is_template: true allows any user with CREATEDB privilege to clone:

- name: shared_template
  is_template: true          # Allow any user with CREATEDB privilege to clone
  owner: dbuser_app

Use ICU Locale Provider

When using the icu locale provider, you must specify template: template0:

- name: myapp_icu
  template: template0        # Must use template0
  locale_provider: icu
  icu_locale: en-US
  encoding: UTF8

Connection Pool Config

By default, all business databases are added to the Pgbouncer connection pool.

Database-Level Connection Pool Parameters

- name: myapp
  pgbouncer: true              # Include in connection pool (default true)
  pool_mode: transaction       # Pool mode: transaction/session/statement
  pool_size: 64                # Default pool size
  pool_size_min: 0             # Minimum pool size
  pool_reserve: 32             # Reserved connections
  pool_connlimit: 100          # Maximum database connections
  pool_auth_user: dbuser_meta  # Auth query user

Generated Configuration

Configuration file located at /etc/pgbouncer/database.txt:

myapp                       = host=/var/run/postgresql pool_mode=transaction pool_size=64

Hide Databases

Some internal databases may not need connection pool access:

- name: internal_db
  pgbouncer: false           # Don't add to connection pool

Pool Mode Explanation

ModeDescriptionUse Case
transactionReturn connection after transaction ends (default)Most OLTP applications
sessionReturn connection after session endsApplications requiring session state
statementReturn connection after statement endsStateless queries

Locale Provider

PostgreSQL 15+ introduced the locale_provider parameter, supporting different locale implementations.

Use ICU Provider (PG15+)

- name: myapp_icu
  template: template0        # ICU must use template0
  locale_provider: icu
  icu_locale: en-US          # ICU locale rules
  encoding: UTF8

Use Builtin Provider (PG17+)

- name: myapp_builtin
  template: template0
  locale_provider: builtin
  builtin_locale: C.UTF-8    # Builtin locale rules
  encoding: UTF8

ICU Collation Rules (PG16+)

- name: myapp_custom_icu
  template: template0
  locale_provider: icu
  icu_locale: en-US
  icu_rules: '&V << w <<< W'  # Custom ICU collation rules

Provider Comparison

ProviderVersion RequirementFeatures
libc-Traditional, depends on OS
icuPG15+Cross-platform consistent, feature-rich
builtinPG17+Most efficient C/C.UTF-8 collation

Quick Reference

Common Commands

OperationCommand
Create databasebin/pgsql-db <cls> <dbname>
Modify databasebin/pgsql-db <cls> <dbname>
Delete databaseSet state: absent then run bin/pgsql-db <cls> <dbname>
Rebuild databaseSet state: recreate then run bin/pgsql-db <cls> <dbname>
List databasespsql -c '\l'
View connection pool databasescat /etc/pgbouncer/database.txt

Common Operation Examples

# Create basic database
- name: myapp
  owner: dbuser_myapp
  comment: my application database

# Create database with extensions
- name: geodata
  owner: dbuser_geo
  extensions: [postgis, postgis_topology]

# Private database with limited connections
- name: secure_db
  owner: dbuser_secure
  revokeconn: true
  connlimit: 10

# Set database-level parameters
- name: analytics
  owner: dbuser_analyst
  parameters:
    work_mem: '512MB'
    statement_timeout: '5min'

# Use ICU locale
- name: i18n_db
  template: template0
  locale_provider: icu
  icu_locale: zh-Hans
  encoding: UTF8

# Delete database
- name: old_db
  state: absent

# Rebuild database
- name: test_db
  state: recreate
  baseline: test_init.sql

Execution Flow

bin/pgsql-db executes these steps in order:

  1. Validate - Check dbname parameter and database definition
  2. Delete (if state=absent/recreate) - Execute DROP DATABASE
  3. Create (if state=create/recreate) - Execute CREATE DATABASE
  4. Configure - Execute ALTER DATABASE to set properties
  5. Initialize - Create schemas, install extensions, execute baseline
  6. Register - Update Pgbouncer and Grafana data sources

For database access permissions, refer to ACL: Database Privileges.

10.7.3 - HBA Management

PostgreSQL and Pgbouncer HBA rule management operations: refresh, reload, verify, and troubleshoot.

HBA rule changes require re-rendering configuration files and reloading services. This article covers HBA rule daily management operations.


Quick Reference

OperationCommand
Refresh cluster HBAbin/pgsql-hba <cls>
Refresh specific instancesbin/pgsql-hba <cls> <ip>...
Refresh PostgreSQL only./pgsql.yml -l <cls> -t pg_hba,pg_reload
Refresh Pgbouncer only./pgsql.yml -l <cls> -t pgbouncer_hba,pgbouncer_reload
View current HBApsql -c "TABLE pg_hba_file_rules"
Verify HBA configpsql -c "SELECT pg_reload_conf()"

Refresh HBA Rules

After modifying HBA rules in pigsty.yml, you need to re-render configuration files and reload services.

Using the Admin Script

The recommended approach is using the bin/pgsql-hba script to refresh PostgreSQL and Pgbouncer HBA in one step:

# Refresh entire cluster's HBA rules
bin/pgsql-hba pg-meta

# Refresh specific instances (multiple IPs separated by spaces)
bin/pgsql-hba pg-meta 10.10.10.10
bin/pgsql-hba pg-meta 10.10.10.11 10.10.10.12

# View script help
bin/pgsql-hba --help

The script internally executes:

./pgsql.yml -l <cluster> -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload

Using Ansible Playbook

Directly use the relevant tags from the pgsql.yml playbook:

# Refresh PostgreSQL HBA and reload
./pgsql.yml -l pg-meta -t pg_hba,pg_reload

# Refresh Pgbouncer HBA and reload
./pgsql.yml -l pg-meta -t pgbouncer_hba,pgbouncer_reload

# Refresh both
./pgsql.yml -l pg-meta -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload

# Use extra variables to force reload
./pgsql.yml -l pg-meta -e pg_reload=true -t pg_hba,pg_reload
TagDescription
pg_hbaRender PostgreSQL HBA configuration file
pg_reloadReload PostgreSQL config (requires pg_reload=true)
pgbouncer_hbaRender Pgbouncer HBA configuration file
pgbouncer_reloadReload Pgbouncer config

Configuration File Locations

HBA configuration files are rendered by Ansible:

ServiceConfig File PathTemplate File
PostgreSQL/pg/data/pg_hba.confroles/pgsql/templates/pg_hba.conf
Pgbouncer/etc/pgbouncer/pgb_hba.confroles/pgsql/templates/pgbouncer.hba

Warning: Don’t edit these files directly—they will be overwritten the next time a playbook runs. All changes should be made in pigsty.yml.


Verify HBA Rules

View Currently Active HBA Rules

# Use psql to view PostgreSQL HBA rules
psql -c "TABLE pg_hba_file_rules"

# Or view the config file directly
cat /pg/data/pg_hba.conf

# View Pgbouncer HBA rules
cat /etc/pgbouncer/pgb_hba.conf

Check HBA Configuration Syntax

# PostgreSQL config reload (validates syntax)
psql -c "SELECT pg_reload_conf()"

# If there are syntax errors, check the logs
tail -f /pg/log/postgresql-*.log

Test Connection Authentication

# Test connection for specific user from specific address
psql -h <host> -p 5432 -U <user> -d <database> -c "SELECT 1"

# See which HBA rule matches the connection
psql -c "SELECT * FROM pg_hba_file_rules WHERE database @> ARRAY['<dbname>']::text[]"

Common Management Scenarios

Add New HBA Rule

  1. Edit pigsty.yml, add rule to the cluster’s pg_hba_rules:
pg-meta:
  vars:
    pg_hba_rules:
      - {user: new_user, db: new_db, addr: '192.168.1.0/24', auth: pwd, title: 'new app access'}
  1. Execute refresh:
bin/pgsql-hba pg-meta

Emergency IP Block

When detecting a malicious IP, quickly add a blocklist rule:

  1. Add high-priority (order: 0) deny rule:
pg_hba_rules:
  - {user: all, db: all, addr: '10.1.1.100/32', auth: deny, order: 0, title: 'emergency block'}
  1. Refresh immediately:
bin/pgsql-hba pg-meta

Role-Based Rules

Configure different HBA rules for primary and replica:

pg_hba_rules:
  # Only primary allows write users
  - {user: writer, db: all, addr: intra, auth: pwd, role: primary, title: 'writer on primary'}

  # Replicas allow read-only users
  - {user: reader, db: all, addr: world, auth: ssl, role: replica, title: 'reader on replica'}

After refresh, rules are automatically enabled or disabled based on the instance’s pg_role.

Refresh HBA After Cluster Expansion

When new instances are added to the cluster, rules using addr: cluster need refresh to include new members:

# Add new instance
./pgsql.yml -l 10.10.10.14

# Refresh all instances' HBA (includes new member IPs)
bin/pgsql-hba pg-meta

Refresh HBA After Failover

After Patroni failover, instance pg_role may not match the configuration. If HBA rules use role filtering:

  1. Update role definitions in pigsty.yml
  2. Refresh HBA rules
# Refresh after updating roles in config file
bin/pgsql-hba pg-meta

Troubleshooting

Connection Rejected

Symptom: FATAL: no pg_hba.conf entry for host "x.x.x.x", user "xxx", database "xxx"

Troubleshooting steps:

  1. Check current HBA rules:
psql -c "TABLE pg_hba_file_rules"
  1. Confirm if client IP, username, database matches any rule

  2. Check rule order (first match wins)

  3. Add corresponding rule and refresh

Authentication Failed

Symptom: FATAL: password authentication failed for user "xxx"

Troubleshooting steps:

  1. Confirm password is correct
  2. Check password encryption method (pg_pwd_enc) compatibility with client
  3. Check if user exists: \du or SELECT * FROM pg_roles WHERE rolname = 'xxx'

HBA Rules Not Taking Effect

Troubleshooting steps:

  1. Confirm refresh command was executed
  2. Check if Ansible execution succeeded
  3. Confirm PostgreSQL reloaded:
psql -c "SELECT pg_reload_conf()"
  1. Check if config file was updated:
head -20 /pg/data/pg_hba.conf

Rule Order Issues

HBA uses first-match-wins logic. If rules aren’t working as expected:

  1. Check order values
  2. Use psql -c "TABLE pg_hba_file_rules" to view actual order
  3. Adjust order values or rule positions

While you can directly edit /pg/data/pg_hba.conf and reload, this is not recommended:

# Direct edit (not recommended)
vi /pg/data/pg_hba.conf

# Reload config
psql -c "SELECT pg_reload_conf()"
# Or
pg_ctl reload -D /pg/data
# Or
systemctl reload postgresql

Problem: Manual changes will be overwritten the next time an Ansible playbook runs.

Correct approach: Always modify in pigsty.yml, then run bin/pgsql-hba to refresh.


Pgbouncer HBA Management

Pgbouncer HBA management is similar to PostgreSQL, with some differences:

Configuration Differences

  • Config file: /etc/pgbouncer/pgb_hba.conf
  • Doesn’t support db: replication
  • Authentication method: local connections use peer instead of ident

Refresh Commands

# Refresh Pgbouncer HBA only
./pgsql.yml -l pg-meta -t pgbouncer_hba,pgbouncer_reload

# Or use unified script (refreshes both PostgreSQL and Pgbouncer)
bin/pgsql-hba pg-meta

View Pgbouncer HBA

cat /etc/pgbouncer/pgb_hba.conf

Best Practices

  1. Always manage in config files: Don’t directly edit pg_hba.conf—all changes through pigsty.yml
  2. Verify in test environment first: HBA changes can cause connection issues—verify in test environment first
  3. Use order to control priority: Blocklist rules use order: 0 to ensure priority matching
  4. Refresh promptly: Refresh HBA after adding/removing instances or failover
  5. Principle of least privilege: Only open necessary access—avoid addr: world + auth: trust
  6. Monitor authentication failures: Watch for authentication failures in pg_stat_activity
  7. Backup configuration: Backup pigsty.yml before important changes

Command Quick Reference

# Refresh HBA (recommended)
bin/pgsql-hba <cluster>

# View PostgreSQL HBA
psql -c "TABLE pg_hba_file_rules"
cat /pg/data/pg_hba.conf

# View Pgbouncer HBA
cat /etc/pgbouncer/pgb_hba.conf

# Reload PostgreSQL config
psql -c "SELECT pg_reload_conf()"

# Test connection
psql -h <host> -U <user> -d <db> -c "SELECT 1"

# View authentication failure logs
tail -f /pg/log/postgresql-*.log | grep -i auth

10.7.4 - SOP

Common PostgreSQL administration procedures in Pigsty for maintaining production database clusters.

This document organizes common PostgreSQL administration procedures in Pigsty for maintaining production database clusters.

Here are the standard operating procedures for common PostgreSQL administration tasks:


Cheatsheet

PGSQL playbooks and shortcuts:

bin/pgsql-add   <cls>                   # create pgsql cluster <cls>
bin/pgsql-user  <cls> <username>        # create pg user <username> on <cls>
bin/pgsql-db    <cls> <dbname>          # create pg database <dbname> on <cls>
bin/pgsql-svc   <cls> [...ip]           # reload pg service of cluster <cls>
bin/pgsql-hba   <cls> [...ip]           # reload postgres/pgbouncer HBA rules of cluster <cls>
bin/pgsql-add   <cls> [...ip]           # append replicas for cluster <cls>
bin/pgsql-rm    <cls> [...ip]           # remove replicas from cluster <cls>
bin/pgsql-rm    <cls>                   # remove pgsql cluster <cls>

Patroni admin command and shortcuts:

pg list        <cls>                    # print cluster info
pg edit-config <cls>                    # edit cluster config
pg reload      <cls> [ins]              # reload cluster config
pg restart     <cls> [ins]              # restart pgsql cluster
pg reinit      <cls> [ins]              # reinit cluster members
pg pause       <cls>                    # entering maintenance mode (no auto failover)
pg resume      <cls>                    # exiting maintenance mode
pg switchover  <cls>                    # switchover on cluster <cls> (primary is healthy)
pg failover    <cls>                    # failover on cluster <cls> (primary failed)

pgBackRest backup/restore command and shortcuts:

pb info                                 # print pgbackrest repo info
pg-backup                               # make a backup, incr, or full backup if necessary
pg-backup full                          # make a full backup
pg-backup diff                          # make a differential backup
pg-backup incr                          # make a incremental backup
pg-pitr -i                              # restore to most recent backup completion time (not common)
pg-pitr --time="2022-12-30 14:44:44+08" # restore to specific time point (e.g., in case of table/database drop)
pg-pitr --name="my-restore-point"       # restore to named restore point created by pg_create_restore_point
pg-pitr --lsn="0/7C82CB8" -X            # restore immediately before LSN
pg-pitr --xid="1234567" -X -P           # restore immediately before specific transaction ID, then promote to primary
pg-pitr --backup=latest                 # restore to latest backup set
pg-pitr --backup=20221108-105325        # restore to specific backup set, can be checked with pgbackrest info

Systemd components quick reference:

systemctl stop patroni                  # start stop restart reload
systemctl stop pgbouncer                # start stop restart reload
systemctl stop pg_exporter              # start stop restart reload
systemctl stop pgbouncer_exporter       # start stop restart reload
systemctl stop node_exporter            # start stop restart
systemctl stop haproxy                  # start stop restart reload
systemctl stop vip-manager              # start stop restart reload
systemctl stop postgres                 # only when patroni_mode == 'remove'

Create Cluster

To create a new Postgres cluster, first define it in the inventory, then initialize:

bin/node-add <cls>                # init nodes for cluster <cls>           # ./node.yml  -l <cls>
bin/pgsql-add <cls>               # init pgsql instances of cluster <cls>  # ./pgsql.yml -l <cls>

Note: PGSQL module requires managed nodes. Use bin/node-add to manage nodes first.

Example: Create Cluster

asciicast


Create User

To create a new business user on an existing Postgres cluster, add the user definition to all.children.<cls>.pg_users, then create it using:

bin/pgsql-user <cls> <username>   # ./pgsql-user.yml -l <cls> -e username=<username>
Example: Create Business User

asciicast


Delete User

To delete a user from an existing Postgres cluster, set the user’s state to absent in the definition, then execute:

bin/pgsql-user <cls> <username>   # ./pgsql-user.yml -l <cls> -e username=<username>

For example, to delete dbuser_test user:

pg_users:
  - name: dbuser_test
    state: absent

The deletion process will:

  1. Use the pg-drop-role script to safely delete the user
  2. Automatically disable user login and terminate active connections
  3. Automatically transfer database/tablespace ownership to postgres
  4. Automatically handle object ownership and permissions in all databases
  5. Revoke all role memberships
  6. Create an audit log for traceability
  7. Remove the user from the Pgbouncer user list (if previously added)
  8. Reload Pgbouncer configuration

Protected System Users:

The following system users cannot be deleted via state: absent and will be automatically skipped:

  • postgres (superuser)
  • replicator (or the user configured in pg_replication_username)
  • dbuser_dba (or the user configured in pg_admin_username)
  • dbuser_monitor (or the user configured in pg_monitor_username)
Example: pg-drop-role Script Usage
# Check user dependencies (read-only operation)
pg-drop-role dbuser_old --check

# Preview deletion operation (don't actually execute)
pg-drop-role dbuser_old --dry-run -v

# Delete user, transfer objects to postgres
pg-drop-role dbuser_old

# Delete user, transfer objects to specified user
pg-drop-role dbuser_old dbuser_new

# Force delete (terminate active connections)
pg-drop-role dbuser_old --force

Create Database

To create a new database on an existing Postgres cluster, add the database definition to all.children.<cls>.pg_databases, then create the database as follows:

bin/pgsql-db <cls> <dbname>       # ./pgsql-db.yml -l <cls> -e dbname=<dbname>

Note: If the database specifies a non-default owner, the owner user must already exist, otherwise you must Create User first.

Example: Create Business Database

asciicast


Reload Service

Services are access points exposed by PostgreSQL (reachable via PGURL), served by HAProxy on host nodes.

Use this task when cluster membership changes, for example: append/remove replicas, switchover/failover / exposing new services, or updating existing service configurations (e.g., LB weights)

To create new services or reload existing services on entire proxy cluster or specific instances:

bin/pgsql-svc <cls>               # pgsql.yml -l <cls> -t pg_service -e pg_reload=true
bin/pgsql-svc <cls> [ip...]       # pgsql.yml -l ip... -t pg_service -e pg_reload=true
Example: Reload PG Service to Remove an Instance

asciicast


Reload HBA

When your Postgres/Pgbouncer HBA rules change, you may need to reload HBA to apply the changes.

If you have any role-specific HBA rules, or IP address ranges referencing cluster member aliases, you may also need to reload HBA after switchover/cluster scaling.

To reload postgres and pgbouncer HBA rules on entire cluster or specific instances:

bin/pgsql-hba <cls>               # pgsql.yml -l <cls> -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload -e pg_reload=true
bin/pgsql-hba <cls> [ip...]       # pgsql.yml -l ip... -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload -e pg_reload=true
Example: Reload Cluster HBA Rules

asciicast


Config Cluster

To change configuration of an existing Postgres cluster, you need to issue control commands on the admin node using the admin user (the user who installed Pigsty, with nopass ssh/sudo):

Alternatively, on any node in the database cluster, using dbsu (default postgres), you can execute admin commands, but only for this cluster.

pg edit-config <cls>              # interactive config a cluster with patronictl

Change patroni parameters and postgresql.parameters, save and apply changes according to prompts.

Example: Non-Interactive Cluster Configuration

You can skip interactive mode and override postgres parameters using the -p option, for example:

pg edit-config -p log_min_duration_statement=1000 pg-test
pg edit-config --force -p shared_preload_libraries='timescaledb, pg_cron, pg_stat_statements, auto_explain'
Example: Change Cluster Config Using Patroni REST API

You can also use the Patroni REST API to change configuration non-interactively, for example:

$ curl -s 10.10.10.11:8008/config | jq .  # get current config
$ curl -u 'postgres:Patroni.API' \
        -d '{"postgresql":{"parameters": {"log_min_duration_statement":200}}}' \
        -s -X PATCH http://10.10.10.11:8008/config | jq .

Note: Patroni sensitive API access (e.g., restart) is restricted to requests from infra/admin nodes, with HTTP basic authentication (username/password) and optional HTTPS protection.

Example: Configure Cluster with patronictl

asciicast


Append Replica

To add a new replica to an existing PostgreSQL cluster, add its definition to the inventory all.children.<cls>.hosts, then:

bin/node-add <ip>                 # add node <ip> to Pigsty management
bin/pgsql-add <cls> <ip>          # init <ip> as new replica of cluster <cls>

This will add node <ip> to pigsty and initialize it as a replica of cluster <cls>.

Cluster services will be reloaded to accept the new member.

Example: Add Replica to pg-test

asciicast

For example, if you want to add pg-test-3 / 10.10.10.13 to existing cluster pg-test, first update the inventory:

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary } # existing member
    10.10.10.12: { pg_seq: 2, pg_role: replica } # existing member
    10.10.10.13: { pg_seq: 3, pg_role: replica } # <--- new member
  vars: { pg_cluster: pg-test }

Then apply the changes as follows:

bin/node-add          10.10.10.13   # add node to pigsty
bin/pgsql-add pg-test 10.10.10.13   # init new replica for cluster pg-test on 10.10.10.13

This is similar to cluster initialization but works on a single instance:

[ OK ] Initialize instance 10.10.10.11 in pgsql cluster 'pg-test':
[WARN]   Reminder: add nodes to pigsty first, then install module 'pgsql'
[HINT]     $ bin/node-add  10.10.10.11  # run this first except for infra nodes
[WARN]   Init instance from cluster:
[ OK ]     $ ./pgsql.yml -l '10.10.10.11,&pg-test'
[WARN]   Reload pg_service on existing instances:
[ OK ]     $ ./pgsql.yml -l 'pg-test,!10.10.10.11' -t pg_service

Remove Replica

To remove a replica from an existing PostgreSQL cluster:

bin/pgsql-rm <cls> <ip...>        # ./pgsql-rm.yml -l <ip>

This will remove instance <ip> from cluster <cls>. Cluster services will be reloaded to remove the instance from load balancers.

Example: Remove Replica from pg-test

asciicast

For example, if you want to remove pg-test-3 / 10.10.10.13 from existing cluster pg-test:

bin/pgsql-rm pg-test 10.10.10.13  # remove pgsql instance 10.10.10.13 from pg-test
bin/node-rm  10.10.10.13          # remove node from pigsty (optional)
vi pigsty.yml                     # remove instance definition from inventory
bin/pgsql-svc pg-test             # refresh pg_service on existing instances to remove from load balancer
[ OK ] Remove pgsql instance 10.10.10.13 from 'pg-test':
[WARN]   Remove instance from cluster:
[ OK ]     $ ./pgsql-rm.yml -l '10.10.10.13,&pg-test'

And remove the instance definition from inventory:

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 } # <--- remove this line after execution
  vars: { pg_cluster: pg-test }

Finally, you can reload PG service to remove the instance from load balancers:

bin/pgsql-svc pg-test             # reload service on pg-test

Remove Cluster

To remove an entire Postgres cluster, simply run:

bin/pgsql-rm <cls>                # ./pgsql-rm.yml -l <cls>
Example: Remove Cluster

asciicast

Example: Force Remove Cluster

Note: If pg_safeguard is configured for this cluster (or globally set to true), pgsql-rm.yml will abort to avoid accidental cluster removal.

You can explicitly override it with playbook command line parameters to force removal:

./pgsql-rm.yml -l pg-meta -e pg_safeguard=false    # force remove pg cluster pg-meta

Switchover

You can use the patroni command line tool to perform PostgreSQL cluster switchover.

pg switchover <cls>   # interactive mode, you can skip the wizard with the following parameter combination
pg switchover --leader pg-test-1 --candidate=pg-test-2 --scheduled=now --force pg-test
Example: pg-test Switchover

asciicast

$ pg switchover pg-test
Master [pg-test-1]:
Candidate ['pg-test-2', 'pg-test-3'] []: pg-test-2
When should the switchover take place (e.g. 2022-12-26T07:39 )  [now]: now
Current cluster topology
+ Cluster: pg-test (7181325041648035869) -----+----+-----------+-----------------+
| Member    | Host        | Role    | State   | TL | Lag in MB | Tags            |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-1 | 10.10.10.11 | Leader  | running |  1 |           | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-2 | 10.10.10.12 | Replica | running |  1 |         0 | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-3 | 10.10.10.13 | Replica | running |  1 |         0 | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+
Are you sure you want to switchover cluster pg-test, demoting current master pg-test-1? [y/N]: y
2022-12-26 06:39:58.02468 Successfully switched over to "pg-test-2"
+ Cluster: pg-test (7181325041648035869) -----+----+-----------+-----------------+
| Member    | Host        | Role    | State   | TL | Lag in MB | Tags            |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-1 | 10.10.10.11 | Replica | stopped |    |   unknown | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-2 | 10.10.10.12 | Leader  | running |  1 |           | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-3 | 10.10.10.13 | Replica | running |  1 |         0 | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+

To perform this via Patroni API (e.g., switch primary from instance 2 to instance 1 at a specified time):

curl -u 'postgres:Patroni.API' \
  -d '{"leader":"pg-test-2", "candidate": "pg-test-1","scheduled_at":"2022-12-26T14:47+08"}' \
  -s -X POST http://10.10.10.11:8008/switchover

After either switchover or failover, you need to refresh services and HBA rules after cluster membership changes. You should complete this promptly (e.g., within a few hours or a day) after the change:

bin/pgsql-svc <cls>
bin/pgsql-hba <cls>

Backup Cluster

To create backups using pgBackRest, run the following commands as local dbsu (default postgres):

pg-backup       # make a backup, incremental or full if necessary
pg-backup full  # make a full backup
pg-backup diff  # make a differential backup
pg-backup incr  # make an incremental backup
pb info         # print backup info (pgbackrest info)

See Backup & Restore for more information.

Example: Create Backup

asciicast

Example: Create Scheduled Backup Task

You can add crontab to node_crontab to specify your backup strategy.

# Full backup daily at 1 AM
- '00 01 * * * postgres /pg/bin/pg-backup full'

# Full backup on Monday at 1 AM, incremental backups on other weekdays
- '00 01 * * 1 postgres /pg/bin/pg-backup full'
- '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'

Restore Cluster

To restore a cluster to a previous point in time (PITR), run the Pigsty helper script pg-pitr as local dbsu user (default postgres):

pg-pitr -i                              # restore to most recent backup completion time (not common)
pg-pitr --time="2022-12-30 14:44:44+08" # restore to specific time point (e.g., in case of table/database drop)
pg-pitr --name="my-restore-point"       # restore to named restore point created by pg_create_restore_point
pg-pitr --lsn="0/7C82CB8" -X            # restore immediately before LSN
pg-pitr --xid="1234567" -X -P           # restore immediately before specific transaction ID, then promote cluster to primary
pg-pitr --backup=latest                 # restore to latest backup set
pg-pitr --backup=20221108-105325        # restore to specific backup set, can be listed with pgbackrest info

The command will output an operations manual, follow the instructions. See Backup & Restore - PITR for details.

Example: PITR Using Raw pgBackRest Commands
# Restore to latest available point (e.g., hardware failure)
pgbackrest --stanza=pg-meta restore

# PITR to specific time point (e.g., accidental table drop)
pgbackrest --stanza=pg-meta --type=time --target="2022-11-08 10:58:48" \
   --target-action=promote restore

# Restore specific backup point, then promote (or pause|shutdown)
pgbackrest --stanza=pg-meta --type=immediate --target-action=promote \
  --set=20221108-105325F_20221108-105938I restore

Adding Packages

To add new RPM packages, add them to repo_packages and repo_url_packages.

Use ./infra.yml -t repo_build subtask to rebuild local repo on Infra node. Then you can install these packages using ansible’s package module:

ansible pg-test -b -m package -a "name=pg_cron_15,topn_15,pg_stat_monitor_15*"  # install some packages with ansible
Example: Manually Update Packages in Local Repo
# Add upstream repo on infra/admin node, then manually download required packages
cd ~/pigsty; ./infra.yml -t repo_upstream,repo_cache # add upstream repo (internet)
cd /www/pigsty;  repotrack "some_new_package_name"   # download latest RPM packages

# Update local repo metadata
cd ~/pigsty; ./infra.yml -t repo_create              # recreate local repo
./node.yml -t node_repo                              # refresh YUM/APT cache on all nodes

# You can also manually refresh YUM/APT cache on nodes using Ansible
ansible all -b -a 'yum clean all'                    # clean node repo cache
ansible all -b -a 'yum makecache'                    # rebuild yum/apt cache from new repo
ansible all -b -a 'apt clean'                        # clean APT cache (Ubuntu/Debian)
ansible all -b -a 'apt update'                       # rebuild APT cache (Ubuntu/Debian)

For example, you can install or upgrade packages as follows:

ansible pg-test -b -m package -a "name=postgresql15* state=latest"

Install Extension

If you want to install extensions on a PostgreSQL cluster, add them to pg_extensions, then execute:

./pgsql.yml -t pg_extension     # install extensions

Some extensions need to be loaded in shared_preload_libraries to take effect. You can add them to pg_libs, or configure an existing cluster.

Finally, execute CREATE EXTENSION <extname>; on the cluster’s primary to complete extension installation.

Example: Install pg_cron Extension on pg-test Cluster
ansible pg-test -b -m package -a "name=pg_cron_15"          # install pg_cron package on all nodes
# Add pg_cron to shared_preload_libraries
pg edit-config --force -p shared_preload_libraries='timescaledb, pg_cron, pg_stat_statements, auto_explain'
pg restart --force pg-test                                  # restart cluster
psql -h pg-test -d postgres -c 'CREATE EXTENSION pg_cron;'  # install pg_cron on primary

For more details, see PGSQL Extension Installation.


Minor Upgrade

To perform minor version upgrade/downgrade, first add packages to the local repo: latest PG minor version RPM/DEB.

First perform rolling upgrade/downgrade on all replicas, then perform cluster switchover to upgrade/downgrade the primary.

ansible <cls> -b -a "yum upgrade/downgrade -y <pkg>"    # upgrade/downgrade packages
pg restart --force <cls>                                # restart cluster
Example: Downgrade PostgreSQL 15.2 to 15.1

Add 15.1 packages to repo and refresh nodes’ yum/apt cache:

cd ~/pigsty; ./infra.yml -t repo_upstream               # add upstream repo
cd /www/pigsty; repotrack postgresql15-*-15.1           # add 15.1 packages to yum repo
cd ~/pigsty; ./infra.yml -t repo_create                 # rebuild repo metadata
ansible pg-test -b -a 'yum clean all'                   # clean node repo cache
ansible pg-test -b -a 'yum makecache'                   # rebuild yum cache from new repo

# For Ubuntu/Debian users, use apt instead of yum
ansible pg-test -b -a 'apt clean'                       # clean node repo cache
ansible pg-test -b -a 'apt update'                      # rebuild apt cache from new repo

Execute downgrade and restart cluster:

ansible pg-test -b -a "yum downgrade -y postgresql15*"  # downgrade packages
pg restart --force pg-test                              # restart entire cluster to complete upgrade
Example: Upgrade PostgreSQL 15.1 Back to 15.2

This time we’ll do a rolling upgrade:

ansible pg-test -b -a "yum upgrade -y postgresql15*"    # upgrade packages (or apt upgrade)
ansible pg-test -b -a '/usr/pgsql/bin/pg_ctl --version' # check binary version is 15.2
pg restart --role replica --force pg-test               # restart replicas
pg switchover --leader pg-test-1 --candidate=pg-test-2 --scheduled=now --force pg-test    # switchover
pg restart --role primary --force pg-test               # restart primary

Major Upgrade

The easiest way to perform a major upgrade is to create a new cluster using the new version, then perform online migration through logical replication and blue-green deployment.

You can also perform in-place major upgrades. When using only the database kernel itself, this is not complicated - use PostgreSQL’s built-in pg_upgrade:

Suppose you want to upgrade PostgreSQL major version from 14 to 15. First add packages to the repo and ensure core extension plugins are installed with the same version numbers on both major versions.

./pgsql.yml -t pg_pkg -e pg_version=15                         # install pg 15 packages
sudo su - postgres; mkdir -p /data/postgres/pg-meta-15/data/   # prepare directory for 15
pg_upgrade -b /usr/pgsql-14/bin/ -B /usr/pgsql-15/bin/ -d /data/postgres/pg-meta-14/data/ -D /data/postgres/pg-meta-15/data/ -v -c # precheck
pg_upgrade -b /usr/pgsql-14/bin/ -B /usr/pgsql-15/bin/ -d /data/postgres/pg-meta-14/data/ -D /data/postgres/pg-meta-15/data/ --link -j8 -v -c
rm -rf /usr/pgsql; ln -s /usr/pgsql-15 /usr/pgsql;             # fix binary link
mv /data/postgres/pg-meta-14 /data/postgres/pg-meta-15         # rename data directory
rm -rf /pg; ln -s /data/postgres/pg-meta-15 /pg                # fix data directory link

10.7.5 - Cluster Management

Standard operation guide for creating/destroying PostgreSQL clusters and scaling existing clusters.

Create Cluster

To create a new Postgres cluster, first define it in the inventory, then initialize:

bin/node-add <cls>                # init nodes for cluster <cls>           # ./node.yml  -l <cls>
bin/pgsql-add <cls>               # init pgsql instances of cluster <cls>  # ./pgsql.yml -l <cls>

Note: PGSQL module requires managed nodes. Use bin/node-add to manage nodes first.

Example: Create Cluster

asciicast


Create User

To create a new business user on an existing Postgres cluster, add the user definition to all.children.<cls>.pg_users, then create it using:

bin/pgsql-user <cls> <username>   # ./pgsql-user.yml -l <cls> -e username=<username>
Example: Create Business User

asciicast


Create Database

To create a new database on an existing Postgres cluster, add the database definition to all.children.<cls>.pg_databases, then create the database as follows:

bin/pgsql-db <cls> <dbname>       # ./pgsql-db.yml -l <cls> -e dbname=<dbname>

Note: If the database specifies a non-default owner, the owner user must already exist, otherwise you must Create User first.

Example: Create Business Database

asciicast


Reload Service

Services are access points exposed by PostgreSQL (reachable via PGURL), served by HAProxy on host nodes.

Use this task when cluster membership changes, for example: append/remove replicas, switchover/failover / exposing new services, or updating existing service configurations (e.g., LB weights)

To create new services or reload existing services on entire proxy cluster or specific instances:

bin/pgsql-svc <cls>               # pgsql.yml -l <cls> -t pg_service -e pg_reload=true
bin/pgsql-svc <cls> [ip...]       # pgsql.yml -l ip... -t pg_service -e pg_reload=true
Example: Reload PG Service to Remove an Instance

asciicast


Reload HBA

When your Postgres/Pgbouncer HBA rules change, you may need to reload HBA to apply the changes.

If you have any role-specific HBA rules, or IP address ranges referencing cluster member aliases, you may also need to reload HBA after switchover/cluster scaling.

To reload postgres and pgbouncer HBA rules on entire cluster or specific instances:

bin/pgsql-hba <cls>               # pgsql.yml -l <cls> -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload -e pg_reload=true
bin/pgsql-hba <cls> [ip...]       # pgsql.yml -l ip... -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload -e pg_reload=true
Example: Reload Cluster HBA Rules

asciicast


Config Cluster

To change configuration of an existing Postgres cluster, you need to issue control commands on the admin node using the admin user (the user who installed Pigsty, with nopass ssh/sudo):

Alternatively, on any node in the database cluster, using dbsu (default postgres), you can execute admin commands, but only for this cluster.

pg edit-config <cls>              # interactive config a cluster with patronictl

Change patroni parameters and postgresql.parameters, save and apply changes according to prompts.

Example: Non-Interactive Cluster Configuration

You can skip interactive mode and override postgres parameters using the -p option, for example:

pg edit-config -p log_min_duration_statement=1000 pg-test
pg edit-config --force -p shared_preload_libraries='timescaledb, pg_cron, pg_stat_statements, auto_explain'
Example: Change Cluster Config Using Patroni REST API

You can also use the Patroni REST API to change configuration non-interactively, for example:

$ curl -s 10.10.10.11:8008/config | jq .  # get current config
$ curl -u 'postgres:Patroni.API' \
        -d '{"postgresql":{"parameters": {"log_min_duration_statement":200}}}' \
        -s -X PATCH http://10.10.10.11:8008/config | jq .

Note: Patroni sensitive API access (e.g., restart) is restricted to requests from infra/admin nodes, with HTTP basic authentication (username/password) and optional HTTPS protection.

Example: Configure Cluster with patronictl

asciicast


Append Replica

To add a new replica to an existing PostgreSQL cluster, add its definition to the inventory all.children.<cls>.hosts, then:

bin/node-add <ip>                 # add node <ip> to Pigsty management
bin/pgsql-add <cls> <ip>          # init <ip> as new replica of cluster <cls>

This will add node <ip> to pigsty and initialize it as a replica of cluster <cls>.

Cluster services will be reloaded to accept the new member.

Example: Add Replica to pg-test

asciicast

For example, if you want to add pg-test-3 / 10.10.10.13 to existing cluster pg-test, first update the inventory:

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary } # existing member
    10.10.10.12: { pg_seq: 2, pg_role: replica } # existing member
    10.10.10.13: { pg_seq: 3, pg_role: replica } # <--- new member
  vars: { pg_cluster: pg-test }

Then apply the changes as follows:

bin/node-add          10.10.10.13   # add node to pigsty
bin/pgsql-add pg-test 10.10.10.13   # init new replica for cluster pg-test on 10.10.10.13

This is similar to cluster initialization but works on a single instance:

[ OK ] Initialize instance 10.10.10.11 in pgsql cluster 'pg-test':
[WARN]   Reminder: add nodes to pigsty first, then install module 'pgsql'
[HINT]     $ bin/node-add  10.10.10.11  # run this first except for infra nodes
[WARN]   Init instance from cluster:
[ OK ]     $ ./pgsql.yml -l '10.10.10.11,&pg-test'
[WARN]   Reload pg_service on existing instances:
[ OK ]     $ ./pgsql.yml -l 'pg-test,!10.10.10.11' -t pg_service

Remove Replica

To remove a replica from an existing PostgreSQL cluster:

bin/pgsql-rm <cls> <ip...>        # ./pgsql-rm.yml -l <ip>

This will remove instance <ip> from cluster <cls>. Cluster services will be reloaded to remove the instance from load balancers.

Example: Remove Replica from pg-test

asciicast

For example, if you want to remove pg-test-3 / 10.10.10.13 from existing cluster pg-test:

bin/pgsql-rm pg-test 10.10.10.13  # remove pgsql instance 10.10.10.13 from pg-test
bin/node-rm  10.10.10.13          # remove node from pigsty (optional)
vi pigsty.yml                     # remove instance definition from inventory
bin/pgsql-svc pg-test             # refresh pg_service on existing instances to remove from load balancer
[ OK ] Remove pgsql instance 10.10.10.13 from 'pg-test':
[WARN]   Remove instance from cluster:
[ OK ]     $ ./pgsql-rm.yml -l '10.10.10.13,&pg-test'

And remove the instance definition from inventory:

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 } # <--- remove this line after execution
  vars: { pg_cluster: pg-test }

Finally, you can reload PG service to remove the instance from load balancers:

bin/pgsql-svc pg-test             # reload service on pg-test

Remove Cluster

To remove an entire Postgres cluster, simply run:

bin/pgsql-rm <cls>                # ./pgsql-rm.yml -l <cls>
Example: Remove Cluster

asciicast

Example: Force Remove Cluster

Note: If pg_safeguard is configured for this cluster (or globally set to true), pgsql-rm.yml will abort to avoid accidental cluster removal.

You can explicitly override it with playbook command line parameters to force removal:

./pgsql-rm.yml -l pg-meta -e pg_safeguard=false    # force remove pg cluster pg-meta

10.7.6 - User Management

Creating PostgreSQL users/roles, managing connection pool roles, refreshing expiration times, user password rotation

Creating Users

To create a new business user on an existing Postgres cluster, add the user definition to all.children.<cls>.pg_users, then create it using the following command:

bin/pgsql-user <cls> <username>   # ./pgsql-user.yml -l <cls> -e username=<username>

Example: Creating a business user

asciicast


Defining Users

Pigsty defines roles and users in database clusters through two configuration parameters:

  • pg_default_roles: Defines globally unified roles and users
  • pg_users: Defines business users and roles at the database cluster level

The former is used to define roles and users shared across the entire environment, while the latter defines business roles and users specific to individual clusters. Both have the same format, being arrays of user definition objects.

You can define multiple users/roles. They will be created sequentially first globally, then by cluster, and finally in array order, so later users can belong to previously defined roles.

Below is the business user definition in the default cluster pg-meta in the Pigsty demo environment:

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 }
      - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
      - {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database    }
      - {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database   }
      - {name: dbuser_kong     ,password: DBUser.Kong     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway    }
      - {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service       }
      - {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service     }
      - {name: dbuser_noco     ,password: DBUser.Noco     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for nocodb service      }

Each user/role definition is an object that may include the following fields, using the dbuser_meta user as an example:

- name: dbuser_meta               # Required, `name` is the only mandatory field in a user definition
  password: DBUser.Meta           # Optional, password, can be a scram-sha-256 hash string or plaintext
  login: true                     # Optional, can log in by default
  superuser: false                # Optional, default is false, is this a superuser?
  createdb: false                 # Optional, default is false, can create databases?
  createrole: false               # Optional, default is false, can create roles?
  inherit: true                   # Optional, by default, can this role use inherited permissions?
  replication: false              # Optional, default is false, can this role perform replication?
  bypassrls: false                # Optional, default is false, can this role bypass row-level security?
  pgbouncer: true                 # Optional, default is false, add this user to the pgbouncer user list? (production users using connection pooling should explicitly set to true)
  connlimit: -1                   # Optional, user connection limit, default -1 disables limit
  expire_in: 3650                 # Optional, expiration time for this role: calculated as created time + n days (higher priority than expire_at)
  expire_at: '2030-12-31'         # Optional, time point when this role expires, specify a specific date using YYYY-MM-DD format string (lower priority than expire_in)
  comment: pigsty admin user      # Optional, description and comment string for this user/role
  roles: [dbrole_admin]           # Optional, default roles are: dbrole_{admin,readonly,readwrite,offline}
  parameters: {}                  # Optional, configure role-level database parameters for this role using `ALTER ROLE SET`
  pool_mode: transaction          # Optional, pgbouncer pool mode defaulting to transaction, at user level
  pool_connlimit: -1              # Optional, maximum database connections at user level, default -1 disables limit
  search_path: public             # Optional, key-value configuration parameters according to postgresql documentation (e.g., use pigsty as default search_path)
  • The only required field is name, which should be a valid and unique username in the PostgreSQL cluster.
  • Roles don’t need a password, but for login-enabled business users, it’s usually necessary to specify a password.
  • password can be plaintext or a scram-sha-256 / md5 hash string; please avoid using plaintext passwords.
  • Users/roles are created sequentially in array order, so ensure role/group definitions come before members.
  • login, superuser, createdb, createrole, inherit, replication, bypassrls are boolean flags.
  • pgbouncer is disabled by default: to add business users to the pgbouncer user list, you should explicitly set it to true.

ACL System

Pigsty has a built-in, out-of-the-box access control / ACL system. You can easily use it by assigning the following four default roles to business users:

  • dbrole_readwrite: Role with global read-write access (production accounts primarily used by business should have database read-write permissions)
  • dbrole_readonly: Role with global read-only access (if other businesses want read-only access, they can use this role)
  • dbrole_admin: Role with DDL permissions (business administrators, scenarios requiring table creation in applications)
  • dbrole_offline: Role with restricted read-only access (can only access offline instances, typically for personal users)

If you want to redesign your own ACL system, consider customizing the following parameters and templates:


Creating Users

Users and roles defined in pg_default_roles and pg_users will be automatically created sequentially during the PROVISION phase of cluster initialization. If you want to create users on an existing cluster, you can use the bin/pgsql-user tool. Add the new user/role definition to all.children.<cls>.pg_users and create the database using the following method:

bin/pgsql-user <cls> <username>    # pgsql-user.yml -l <cls> -e username=<username>

Unlike databases, the user creation playbook is always idempotent. When the target user already exists, Pigsty will modify the target user’s attributes to conform to the configuration. So running it repeatedly on existing clusters typically won’t cause issues.


Modifying Users

The method for modifying PostgreSQL user attributes is the same as Creating Users.

First, adjust your user definition, modify the attributes that need adjustment, then execute the following command to apply:

bin/pgsql-user <cls> <username>    # pgsql-user.yml -l <cls> -e username=<username>

Note that modifying users does not delete users but modifies user attributes using the ALTER USER command; it also doesn’t revoke user permissions and groups, and uses the GRANT command to grant new roles.


Deleting Users

To delete a user, set its state to absent and execute the playbook:

pg_users:
  - name: dbuser_old
    state: absent
bin/pgsql-user <cls> dbuser_old

The deletion process will:

  1. Use the pg-drop-role script to safely delete the user
  2. Automatically disable user login and terminate active connections
  3. Automatically transfer database/tablespace ownership to postgres
  4. Automatically handle object ownership and permissions in all databases
  5. Revoke all role memberships
  6. Create an audit log for traceability
  7. Remove the user from the Pgbouncer user list (if previously added)
  8. Reload Pgbouncer configuration

Protected System Users:

The following system users cannot be deleted via state: absent and will be automatically skipped:

  • postgres (superuser)
  • replicator (or the user configured in pg_replication_username)
  • dbuser_dba (or the user configured in pg_admin_username)
  • dbuser_monitor (or the user configured in pg_monitor_username)

pg-drop-role Script

pg-drop-role is a safe user deletion script provided by Pigsty, located at /pg/bin/pg-drop-role.

Usage:

pg-drop-role <role_name> [successor_role] [options]

Common Options:

OptionDescription
--checkOnly check dependencies, don’t execute deletion
--dry-runShow SQL statements that would be executed, don’t actually execute
--forceForce terminate active connections before deletion
-v, --verboseShow verbose output
-h, --hostDatabase host
-p, --portDatabase port

Examples:

# Check user dependencies (read-only operation)
pg-drop-role dbuser_old --check

# Preview deletion operation (don't actually execute)
pg-drop-role dbuser_old --dry-run -v

# Delete user, transfer objects to postgres
pg-drop-role dbuser_old

# Delete user, transfer objects to specified user
pg-drop-role dbuser_old dbuser_new

# Force delete (terminate active connections)
pg-drop-role dbuser_old --force

Deletion Process:

  1. Pre-check - Verify connection, check if user exists, check if protected
  2. Create audit snapshot - Record all user dependencies
  3. Disable login - ALTER ROLE ... NOLOGIN
  4. Terminate connections - Terminate active connections when using --force
  5. Transfer shared objects - Transfer database, tablespace ownership
  6. Process all databases - Execute REASSIGN OWNED + DROP OWNED in each database
  7. Revoke memberships - Revoke all role memberships
  8. Drop role - Execute DROP ROLE

Pgbouncer Users

Pgbouncer is enabled by default and serves as connection pool middleware, with users managed by default.

Pigsty defaults to adding all users in pg_users that explicitly have the pgbouncer: true flag to the pgbouncer user list.

Users in the Pgbouncer connection pool are listed in /etc/pgbouncer/userlist.txt:

"postgres" ""
"dbuser_wiki" "SCRAM-SHA-256$4096:+77dyhrPeFDT/TptHs7/7Q==$KeatuohpKIYzHPCt/tqBu85vI11o9mar/by0hHYM2W8=:X9gig4JtjoS8Y/o1vQsIX/gY1Fns8ynTXkbWOjUfbRQ="
"dbuser_view" "SCRAM-SHA-256$4096:DFoZHU/DXsHL8MJ8regdEw==$gx9sUGgpVpdSM4o6A2R9PKAUkAsRPLhLoBDLBUYtKS0=:MujSgKe6rxcIUMv4GnyXJmV0YNbf39uFRZv724+X1FE="
"dbuser_monitor" "SCRAM-SHA-256$4096:fwU97ZMO/KR0ScHO5+UuBg==$CrNsmGrx1DkIGrtrD1Wjexb/aygzqQdirTO1oBZROPY=:L8+dJ+fqlMQh7y4PmVR/gbAOvYWOr+KINjeMZ8LlFww="
"dbuser_meta" "SCRAM-SHA-256$4096:leB2RQPcw1OIiRnPnOMUEg==$eyC+NIMKeoTxshJu314+BmbMFpCcspzI3UFZ1RYfNyU=:fJgXcykVPvOfro2MWNkl5q38oz21nSl1dTtM65uYR1Q="
"dbuser_kong" "SCRAM-SHA-256$4096:bK8sLXIieMwFDz67/0dqXQ==$P/tCRgyKx9MC9LH3ErnKsnlOqgNd/nn2RyvThyiK6e4=:CDM8QZNHBdPf97ztusgnE7olaKDNHBN0WeAbP/nzu5A="
"dbuser_grafana" "SCRAM-SHA-256$4096:HjLdGaGmeIAGdWyn2gDt/Q==$jgoyOB8ugoce+Wqjr0EwFf8NaIEMtiTuQTg1iEJs9BM=:ed4HUFqLyB4YpRr+y25FBT7KnlFDnan6JPVT9imxzA4="
"dbuser_gitea" "SCRAM-SHA-256$4096:l1DBGCc4dtircZ8O8Fbzkw==$tpmGwgLuWPDog8IEKdsaDGtiPAxD16z09slvu+rHE74=:pYuFOSDuWSofpD9OZhG7oWvyAR0PQjJBffgHZLpLHds="
"dbuser_dba" "SCRAM-SHA-256$4096:zH8niABU7xmtblVUo2QFew==$Zj7/pq+ICZx7fDcXikiN7GLqKKFA+X5NsvAX6CMshF0=:pqevR2WpizjRecPIQjMZOm+Ap+x0kgPL2Iv5zHZs0+g="
"dbuser_bytebase" "SCRAM-SHA-256$4096:OMoTM9Zf8QcCCMD0svK5gg==$kMchqbf4iLK1U67pVOfGrERa/fY818AwqfBPhsTShNQ=:6HqWteN+AadrUnrgC0byr5A72noqnPugItQjOLFw0Wk="

User-level connection pool parameters are maintained in a separate file: /etc/pgbouncer/useropts.txt, for example:

dbuser_dba                  = pool_mode=session max_user_connections=16
dbuser_monitor              = pool_mode=session max_user_connections=8

When you create a database, Pgbouncer’s database list definition file will be refreshed and take effect through online configuration reload, without affecting existing connections.

Pgbouncer runs with the same dbsu as PostgreSQL, defaulting to the postgres OS user. You can use the pgb alias to access pgbouncer management functions using dbsu.

Pigsty also provides a utility function pgb-route that can quickly switch pgbouncer database traffic to other nodes in the cluster for zero-downtime migration:

Connection pool user configuration files userlist.txt and useropts.txt will be automatically refreshed when you create users and take effect through online configuration reload, normally without affecting existing connections.

Note that the pgbouncer_auth_query parameter allows you to use dynamic queries to complete connection pool user authentication, which is a compromise solution when you don’t want to manage users in the connection pool.

10.7.7 - Parameter Tuning

Tuning Postgres Parameters

Pigsty provides four scenario-based parameter templates by default, which can be specified and used through the pg_conf parameter.

  • tiny.yml: Optimized for small nodes, VMs, and small demos (1-8 cores, 1-16GB)
  • oltp.yml: Optimized for OLTP workloads and latency-sensitive applications (4C8GB+) (default template)
  • olap.yml: Optimized for OLAP workloads and throughput (4C8G+)
  • crit.yml: Optimized for data consistency and critical applications (4C8G+)

Pigsty adopts different parameter optimization strategies for these four default scenarios, as shown below:


Memory Parameter Tuning

Pigsty automatically detects the system’s memory size and uses it as the basis for setting the maximum number of connections and memory-related parameters.

  • pg_max_conn: PostgreSQL maximum connections, auto will use recommended values for different scenarios
  • pg_shared_buffer_ratio: Shared buffer memory ratio, default is 0.25

By default, Pigsty uses 25% of memory as PostgreSQL shared buffers, with the remaining 75% as the operating system cache.

By default, if the user has not set a pg_max_conn maximum connections value, Pigsty will use defaults according to the following rules:

  • oltp: 500 (pgbouncer) / 1000 (postgres)
  • crit: 500 (pgbouncer) / 1000 (postgres)
  • tiny: 300
  • olap: 300

For OLTP and CRIT templates, if the service is not pointing to the pgbouncer connection pool but directly connects to the postgres database, the maximum connections will be doubled to 1000.

After determining the maximum connections, work_mem is calculated from shared memory size / maximum connections and limited to the range of 64MB ~ 1GB.

{% raw %}
{% if pg_max_conn != 'auto' and pg_max_conn|int >= 20 %}{% set pg_max_connections = pg_max_conn|int %}{% else %}{% if pg_default_service_dest|default('postgres') == 'pgbouncer' %}{% set pg_max_connections = 500 %}{% else %}{% set pg_max_connections = 1000 %}{% endif %}{% endif %}
{% set pg_max_prepared_transactions = pg_max_connections if 'citus' in pg_libs else 0 %}
{% set pg_max_locks_per_transaction = (2 * pg_max_connections)|int if 'citus' in pg_libs or 'timescaledb' in pg_libs else pg_max_connections %}
{% set pg_shared_buffers = (node_mem_mb|int * pg_shared_buffer_ratio|float) | round(0, 'ceil') | int %}
{% set pg_maintenance_mem = (pg_shared_buffers|int * 0.25)|round(0, 'ceil')|int %}
{% set pg_effective_cache_size = node_mem_mb|int - pg_shared_buffers|int  %}
{% set pg_workmem =  ([ ([ (pg_shared_buffers / pg_max_connections)|round(0,'floor')|int , 64 ])|max|int , 1024])|min|int %}
{% endraw %}

CPU Parameter Tuning

In PostgreSQL, there are 4 important parameters related to parallel queries. Pigsty automatically optimizes parameters based on the current system’s CPU cores. In all strategies, the total number of parallel processes (total budget) is usually set to CPU cores + 8, with a minimum of 16, to reserve enough background workers for logical replication and extensions. The OLAP and TINY templates vary slightly based on scenarios.

OLTPSetting LogicRange Limits
max_worker_processesmax(100% CPU + 8, 16)CPU cores + 4, minimum 12
max_parallel_workersmax(ceil(50% CPU), 2)1/2 CPU rounded up, minimum 2
max_parallel_maintenance_workersmax(ceil(33% CPU), 2)1/3 CPU rounded up, minimum 2
max_parallel_workers_per_gathermin(max(ceil(20% CPU), 2),8)1/5 CPU rounded down, minimum 2, max 8
OLAPSetting LogicRange Limits
max_worker_processesmax(100% CPU + 12, 20)CPU cores + 12, minimum 20
max_parallel_workersmax(ceil(80% CPU, 2))4/5 CPU rounded up, minimum 2
max_parallel_maintenance_workersmax(ceil(33% CPU), 2)1/3 CPU rounded up, minimum 2
max_parallel_workers_per_gathermax(floor(50% CPU), 2)1/2 CPU rounded up, minimum 2
CRITSetting LogicRange Limits
max_worker_processesmax(100% CPU + 8, 16)CPU cores + 8, minimum 16
max_parallel_workersmax(ceil(50% CPU), 2)1/2 CPU rounded up, minimum 2
max_parallel_maintenance_workersmax(ceil(33% CPU), 2)1/3 CPU rounded up, minimum 2
max_parallel_workers_per_gather0, enable as needed
TINYSetting LogicRange Limits
max_worker_processesmax(100% CPU + 4, 12)CPU cores + 4, minimum 12
max_parallel_workersmax(ceil(50% CPU) 1)50% CPU rounded down, minimum 1
max_parallel_maintenance_workersmax(ceil(33% CPU), 1)33% CPU rounded down, minimum 1
max_parallel_workers_per_gather0, enable as needed

Note that the CRIT and TINY templates disable parallel queries by setting max_parallel_workers_per_gather = 0. Users can enable parallel queries as needed by setting this parameter.

Both OLTP and CRIT templates additionally set the following parameters, doubling the parallel query cost to reduce the tendency to use parallel queries.

parallel_setup_cost: 2000           # double from 100 to increase parallel cost
parallel_tuple_cost: 0.2            # double from 0.1 to increase parallel cost
min_parallel_table_scan_size: 16MB  # double from 8MB to increase parallel cost
min_parallel_index_scan_size: 1024  # double from 512 to increase parallel cost

Note that adjustments to the max_worker_processes parameter only take effect after a restart. Additionally, when a replica’s configuration value for this parameter is higher than the primary’s, the replica will fail to start. This parameter must be adjusted through Patroni configuration management, which ensures consistent primary-replica configuration and prevents new replicas from failing to start during failover.


Storage Space Parameters

Pigsty automatically detects the total space of the disk where the /data/postgres main data directory is located and uses it as the basis for specifying the following parameters:

{% raw %}
min_wal_size: {{ ([pg_size_twentieth, 200])|min }}GB                  # 1/20 disk size, max 200GB
max_wal_size: {{ ([pg_size_twentieth * 4, 2000])|min }}GB             # 2/10 disk size, max 2000GB
max_slot_wal_keep_size: {{ ([pg_size_twentieth * 6, 3000])|min }}GB   # 3/10 disk size, max 3000GB
temp_file_limit: {{ ([pg_size_twentieth, 200])|min }}GB               # 1/20 of disk size, max 200GB
{% endraw %}
  • temp_file_limit defaults to 5% of disk space, capped at 200GB.
  • min_wal_size defaults to 5% of disk space, capped at 200GB.
  • max_wal_size defaults to 20% of disk space, capped at 2TB.
  • max_slot_wal_keep_size defaults to 30% of disk space, capped at 3TB.

As a special case, the OLAP template allows 20% for temp_file_limit, capped at 2TB.


Manual Parameter Tuning

In addition to using Pigsty’s automatically configured parameters, you can also manually tune PostgreSQL parameters.

Use the pg edit-config <cluster> command to interactively edit cluster configuration:

pg edit-config pg-meta

Or use the -p parameter to directly set parameters:

pg edit-config -p log_min_duration_statement=1000 pg-meta
pg edit-config --force -p shared_preload_libraries='timescaledb, pg_cron, pg_stat_statements, auto_explain' pg-meta

You can also use the Patroni REST API to modify configuration:

curl -u 'postgres:Patroni.API' \
    -d '{"postgresql":{"parameters": {"log_min_duration_statement":200}}}' \
    -s -X PATCH http://10.10.10.10:8008/config | jq .

10.7.8 - Accidental Deletion

Handling accidental data deletion, table deletion, and database deletion

Accidental Data Deletion

If it’s a small-scale DELETE misoperation, you can consider using the pg_surgery or pg_dirtyread extension for in-place surgical recovery.

-- Immediately disable Auto Vacuum on this table and abort Auto Vacuum worker processes for this table
ALTER TABLE public.some_table SET (autovacuum_enabled = off, toast.autovacuum_enabled = off);

CREATE EXTENSION pg_dirtyread;
SELECT * FROM pg_dirtyread('tablename') AS t(col1 type1, col2 type2, ...);

If the deleted data has already been reclaimed by VACUUM, then use the general accidental deletion recovery process.

Accidental Object Deletion

When DROP/DELETE type misoperations occur, typically decide on a recovery plan according to the following process:

  1. Confirm whether this data can be recovered from the business system or other data systems. If yes, recover directly from the business side.
  2. Confirm whether there is a delayed replica. If yes, advance the delayed replica to the time point before deletion and query the data for recovery.
  3. If the data has been confirmed deleted, confirm backup information and whether the backup range covers the deletion time point. If it does, start PITR.
  4. Confirm whether to perform in-place cluster PITR rollback, or start a new server for replay, or use a replica for replay, and execute the recovery strategy.

Accidental Cluster Deletion

If an entire database cluster is accidentally deleted through Pigsty management commands, for example, incorrectly executing the pgsql-rm.yml playbook or the bin/pgsql-rm command. Unless you have set the pg_rm_backup parameter to false, the backup will be deleted along with the database cluster.

Warning: In this situation, your data will be unrecoverable! Please think three times before proceeding!

Recommendation: For production environments, you can globally configure this parameter to false in the configuration manifest to preserve backups when removing clusters.

10.7.9 - Clone Replicas

How to clone databases, database instances, and database clusters?

PostgreSQL can already replicate data through physical replicas and logical replicas, but sometimes you may need to quickly clone a database, database instance, or entire database cluster. The cloned database can be written to, evolve independently, and not affect the original database. In Pigsty, there are several cloning methods:

  • Clone Database: Clone a new database within the same cluster
  • Clone Instance: Clone a new instance on the same PG node
  • Clone Cluster: Create a new database cluster using PITR mechanism and restore to any point in time of the specified cluster

Clone Database

You can copy a PostgreSQL database through the template mechanism, but no active connections to the template database are allowed during this period.

If you want to clone the postgres database, you must execute the following two statements at the same time. Ensure all connections to the postgres database are cleaned up before executing Clone:

SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'postgres';
CREATE DATABASE pgcopy TEMPLATE postgres STRATEGY FILE_COPY;

Instant Clone

If you are using PostgreSQL 18 or higher, Pigsty sets file_copy_method by default. This parameter allows you to clone a database in O(1) (~200ms) time complexity without copying data files.

However, you must explicitly use the FILE_COPY strategy to create the database. Since the STRATEGY parameter of CREATE DATABASE was introduced in PostgreSQL 15, the default value has been WAL_LOG. You need to explicitly specify FILE_COPY for instant cloning.

SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'postgres';
CREATE DATABASE pgcopy TEMPLATE postgres STRATEGY FILE_COPY;

For example, cloning a 30 GB database: normal clone (WAL_LOG) takes 18 seconds, while instant clone (FILE_COPY) only needs constant time of 200 milliseconds.

Since Pigsty v4.0, you can use strategy: FILE_COPY in the pg_databases parameter to achieve instant database cloning.

    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_version: 18
        pg_databases:

          - name: meta

          - name: meta_dev
            template: meta
            strategy: FILE_COPY         # <---- Introduced in PG 15, instant in PG18

After configuration, use the standard database creation SOP to create the database:

bin/pgsql-db pg-meta meta_dev

Limitations and Notes

This feature is only available on supported file systems (xfs, btrfs, zfs, apfs). If the file system doesn’t support it, PostgreSQL will fail with an error.

By default, mainstream OS distributions’ xfs have reflink=1 enabled by default, so you don’t need to worry about this in most cases.

If your PostgreSQL version is below 15, specifying strategy will have no effect.

Please don’t use the postgres database as a template database for cloning, as management connections typically connect to the postgres database, which prevents the cloning operation.

Use instant cloning with caution in extremely high concurrency/throughput production environments, as it requires clearing all connections to the template database within the cloning window (200ms), otherwise the clone will fail.

10.7.10 - Maintenance

Common system maintenance tasks

To ensure Pigsty and PostgreSQL clusters run healthily and stably, some routine maintenance work is required.


Regular Monitoring Review

Pigsty provides an out-of-the-box monitoring platform. We recommend you browse the monitoring dashboards once a day to keep track of system status. At a minimum, we recommend you review the monitoring at least once a week, paying attention to alert events that occur, which can help you avoid most failures and issues in advance.

Here is a list of pre-defined alert rules in Pigsty.


Failover Follow-up

Pigsty’s high availability architecture allows PostgreSQL clusters to automatically perform primary-replica switchovers, meaning operations and DBAs don’t need to intervene or respond immediately. However, users still need to perform the following follow-up work at an appropriate time (e.g., the next business day), including:

  • Investigate and confirm the cause of the failure to prevent recurrence
  • Restore the cluster’s original primary-replica topology as appropriate, or modify the configuration manifest to match the new primary-replica status.
  • Refresh load balancer configuration through bin/pgsql-svc to update service routing status
  • Refresh the cluster’s HBA rules through bin/pgsql-hba to avoid primary-replica-specific rule drift
  • If necessary, use bin/pgsql-rm to remove the failed server and expand with a new replica through bin/pgsql-add

Table Bloat Management

Long-running PostgreSQL will experience “table bloat” / “index bloat” phenomena, leading to system performance degradation.

Regularly using pg_repack to perform online rebuilding of tables and indexes helps maintain PostgreSQL’s good performance. Pigsty has already installed and enabled this extension by default in all databases, so you can use it directly.

You can use Pigsty’s PGCAT Database - Table Bloat panel to confirm table bloat and index bloat in the database. Select tables and indexes with high bloat rates (larger tables with bloat rates above 50%) and use pg_repack for online reorganization:

pg_repack dbname -t schema.table

Reorganization does not affect normal read and write operations, but the switching moment after reorganization completes requires an AccessExclusive lock on the table, blocking all access. Therefore, for high-throughput businesses, it’s recommended to perform this during off-peak periods or maintenance windows. For more details, please refer to: Managing Relation Bloat


VACUUM FREEZE

Freezing expired transaction IDs (VACUUM FREEZE) is an important PostgreSQL maintenance task used to prevent transaction ID (XID) exhaustion leading to downtime. Although PostgreSQL already provides an automatic vacuum (AutoVacuum) mechanism, for high-standard production environments, we still recommend combining both automatic and manual approaches, regularly executing database-wide VACUUM FREEZE to ensure XID safety.

You can manually execute VACUUM FREEZE on a database using the following commands:

-- Execute VACUUM FREEZE on the entire database
VACUUM FREEZE;

-- Execute VACUUM FREEZE on a specific table
VACUUM FREEZE schema.table_name;

Or set up a scheduled task through crontab, for example, execute every Sunday morning:

# Execute VACUUM FREEZE on all databases every Sunday at 3 AM
0 3 * * 0 postgres psql -c 'VACUUM FREEZE;' dbname

10.7.11 - Version Upgrade

How to upgrade (or downgrade) PostgreSQL minor version kernel, and how to perform major version upgrades

Minor Version Upgrade

To perform a minor version server upgrade/downgrade, you first need to add software to your local software repository: the latest PG minor version RPM/DEB.

First perform a rolling upgrade/downgrade on all replicas, then execute a cluster switchover to upgrade/downgrade the primary.

ansible <cls> -b -a "yum upgrade/downgrade -y <pkg>"    # Upgrade/downgrade packages
pg restart --force <cls>                                # Restart cluster

This time we’ll perform a rolling upgrade:

ansible pg-test -b -a "yum upgrade -y postgresql15*"    # Upgrade packages (or apt upgrade)
ansible pg-test -b -a '/usr/pgsql/bin/pg_ctl --version' # Check binary version is 15.2
pg restart --role replica --force pg-test               # Restart replicas
pg switchover --leader pg-test-1 --candidate=pg-test-2 --scheduled=now --force pg-test    # Switchover primary and replica
pg restart --role primary --force pg-test               # Restart primary

Minor Version Downgrade

Add 15.1 packages to the software repository and refresh the node’s yum/apt cache:

cd ~/pigsty; ./infra.yml -t repo_upstream               # Add upstream repository
cd /www/pigsty; repotrack postgresql15-*-15.1           # Add 15.1 packages to yum repository
cd ~/pigsty; ./infra.yml -t repo_create                 # Rebuild repository metadata
ansible pg-test -b -a 'yum clean all'                   # Clean node repository cache
ansible pg-test -b -a 'yum makecache'                   # Regenerate yum cache from new repository

# For Ubuntu/Debian users, use apt instead of yum
ansible pg-test -b -a 'apt clean'                       # Clean node repository cache
ansible pg-test -b -a 'apt update'                      # Regenerate apt cache from new repository

Execute downgrade and restart cluster:

ansible pg-test -b -a "yum downgrade -y postgresql15*"  # Downgrade packages
pg restart --force pg-test                              # Restart entire cluster to complete upgrade

Major Version Upgrade

The simplest way to perform a major version upgrade is to create a new cluster using the new version, then perform online migration through logical replication and blue-green deployment.

You can also perform an in-place major version upgrade. When you only use the database kernel itself, this is not complicated; use PostgreSQL’s built-in pg_upgrade:

Suppose you want to upgrade PostgreSQL major version from 14 to 15. You first need to add software to the repository and ensure that core extension plugins installed on both sides of the two major versions also have the same version numbers.

./pgsql.yml -t pg_pkg -e pg_version=15                         # Install pg 15 packages
sudo su - postgres; mkdir -p /data/postgres/pg-meta-15/data/   # Prepare directory for 15
pg_upgrade -b /usr/pgsql-14/bin/ -B /usr/pgsql-15/bin/ -d /data/postgres/pg-meta-14/data/ -D /data/postgres/pg-meta-15/data/ -v -c # Pre-check
pg_upgrade -b /usr/pgsql-14/bin/ -B /usr/pgsql-15/bin/ -d /data/postgres/pg-meta-14/data/ -D /data/postgres/pg-meta-15/data/ --link -j8 -v -c
rm -rf /usr/pgsql; ln -s /usr/pgsql-15 /usr/pgsql;             # Fix binary link
mv /data/postgres/pg-meta-14 /data/postgres/pg-meta-15         # Rename data directory
rm -rf /pg; ln -s /data/postgres/pg-meta-15 /pg                # Fix data directory link

10.8 - Backup & Restore

Point-in-Time Recovery (PITR) Backup and Restore

Pigsty uses pgBackRest to manage PostgreSQL backups, arguably the most powerful open-source backup tool in the ecosystem. It supports incremental/parallel backup and restore, encryption, MinIO/S3, and many other features. Pigsty configures backup functionality by default for each PGSQL cluster.

SectionContent
MechanismBackup scripts, cron jobs, pgbackrest, repository and management
PolicyBackup strategy, disk planning, recovery window tradeoffs
RepositoryConfiguring backup repositories: local, MinIO, S3
AdminCommon backup management commands
RestoreRestore to a specific point in time using playbooks
ExampleSandbox example: performing restore operations manually

Quick Start

  1. Backup Policy: Schedule base backups using Crontab
  2. WAL Archiving: Continuously record write activity
  3. Restore & Recovery: Recover from backups and WAL archives
node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ]
./pgsql-pitr.yml -e '{"pg_pitr": { "time": "2025-07-13 10:00:00+00" }}'

10.8.1 - Backup Policy

Design backup policies according to your needs
  • When: Backup schedule
  • Where: Backup repository
  • How: Backup method

When to Backup

The first question is when to backup your database - this is a tradeoff between backup frequency and recovery time. Since you need to replay WAL logs from the last backup to the recovery target point, the more frequent the backups, the less WAL logs need to be replayed, and the faster the recovery.

Daily Full Backup

For production databases, it’s recommended to start with the simplest daily full backup strategy. This is also Pigsty’s default backup strategy, implemented via crontab.

node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ]
pgbackrest_method: local          # Choose backup repository method: `local`, `minio`, or other custom repository
pgbackrest_repo:                  # pgbackrest repository configuration: https://pgbackrest.org/configuration.html#section-repository
  local:                          # Default pgbackrest repository using local POSIX filesystem
    path: /pg/backup              # Local backup directory, defaults to `/pg/backup`
    retention_full_type: count    # Retain full backups by count
    retention_full: 2             # Keep 2, up to 3 full backups when using local filesystem repository

When used with the default local local filesystem backup repository, this provides a 24~48 hour recovery window.

pitr-scope

Assuming your database size is 100GB and writes 10GB of data per day, the backup size is as follows:

pitr-space

This will consume 2~3 times the database size in space, plus 2 days of WAL logs. Therefore, in practice, you may need to prepare at least 3~5 times the database size for backup disk to use the default backup strategy.

Full + Incremental Backup

You can optimize backup space usage by adjusting these parameters.

If using MinIO / S3 as a centralized backup repository, you can use storage space beyond local disk limitations. In this case, consider using full + incremental backup with a 2-week retention policy:

node_crontab:  # Full backup at 1 AM on Monday, incremental backups on weekdays
  - '00 01 * * 1 postgres /pg/bin/pg-backup full'
  - '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'
pgbackrest_method: minio
pgbackrest_repo:                  # pgbackrest repository configuration: https://pgbackrest.org/configuration.html#section-repository
  minio:                          # Optional minio repository
    type: s3                      # minio is S3 compatible
    s3_endpoint: sss.pigsty       # minio endpoint domain, defaults to `sss.pigsty`
    s3_region: us-east-1          # minio region, defaults to us-east-1, meaningless for minio
    s3_bucket: pgsql              # minio bucket name, defaults to `pgsql`
    s3_key: pgbackrest            # minio user access key for pgbackrest
    s3_key_secret: S3User.Backup  # minio user secret for pgbackrest
    s3_uri_style: path            # minio uses path-style URIs instead of host-style
    path: /pgbackrest             # minio backup path, defaults to `/pgbackrest`
    storage_port: 9000            # minio port, defaults to 9000
    storage_ca_file: /etc/pki/ca.crt  # minio CA certificate path, defaults to `/etc/pki/ca.crt`
    block: y                      # Enable block-level incremental backup
    bundle: y                     # Bundle small files into a single file
    bundle_limit: 20MiB           # Bundle size limit, recommended 20MiB for object storage
    bundle_size: 128MiB           # Bundle target size, recommended 128MiB for object storage
    cipher_type: aes-256-cbc      # Enable AES encryption for remote backup repository
    cipher_pass: pgBackRest       # AES encryption password, defaults to 'pgBackRest'
    retention_full_type: time     # Retain full backups by time
    retention_full: 14            # Keep full backups from the last 14 days

When used with the built-in minio backup repository, this provides a guaranteed 1-week PITR recovery window.

pitr-scope2

Assuming your database size is 100GB and writes 10GB of data per day, the backup size is as follows:

pitr-space2


Backup Location

By default, Pigsty provides two default backup repository definitions: local and minio backup repositories.

  • local: Default option, uses local /pg/backup directory (symlink to pg_fs_backup: /data/backups)
  • minio: Uses SNSD single-node MinIO cluster (supported by Pigsty, but not enabled by default)
pgbackrest_method: local          # Choose backup repository method: `local`, `minio`, or other custom repository
pgbackrest_repo:                  # pgbackrest repository configuration: https://pgbackrest.org/configuration.html#section-repository
  local:                          # Default pgbackrest repository using local POSIX filesystem
    path: /pg/backup              # Local backup directory, defaults to `/pg/backup`
    retention_full_type: count    # Retain full backups by count
    retention_full: 2             # Keep 2, up to 3 full backups when using local filesystem repository
  minio:                          # Optional minio repository
    type: s3                      # minio is S3 compatible
    s3_endpoint: sss.pigsty       # minio endpoint domain, defaults to `sss.pigsty`
    s3_region: us-east-1          # minio region, defaults to us-east-1, meaningless for minio
    s3_bucket: pgsql              # minio bucket name, defaults to `pgsql`
    s3_key: pgbackrest            # minio user access key for pgbackrest
    s3_key_secret: S3User.Backup  # minio user secret for pgbackrest
    s3_uri_style: path            # minio uses path-style URIs instead of host-style
    path: /pgbackrest             # minio backup path, defaults to `/pgbackrest`
    storage_port: 9000            # minio port, defaults to 9000
    storage_ca_file: /etc/pki/ca.crt  # minio CA certificate path, defaults to `/etc/pki/ca.crt`
    block: y                      # Enable block-level incremental backup
    bundle: y                     # Bundle small files into a single file
    bundle_limit: 20MiB           # Bundle size limit, recommended 20MiB for object storage
    bundle_size: 128MiB           # Bundle target size, recommended 128MiB for object storage
    cipher_type: aes-256-cbc      # Enable AES encryption for remote backup repository
    cipher_pass: pgBackRest       # AES encryption password, defaults to 'pgBackRest'
    retention_full_type: time     # Retain full backups by time
    retention_full: 14            # Keep full backups from the last 14 days

10.8.2 - Backup Mechanism

Backup scripts, cron jobs, backup repository and infrastructure

Backups can be invoked via built-in scripts, scheduled using node crontab, managed by pgbackrest, and stored in backup repositories, which can be local disk filesystems or MinIO / S3, supporting different retention policies.


Scripts

You can create backups using the pg_dbsu user (defaults to postgres) to execute pgbackrest commands:

pgbackrest --stanza=pg-meta --type=full backup   # Create full backup for cluster pg-meta
$ pgbackrest --stanza=pg-meta --type=full backup
2025-07-15 01:36:57.007 P00   INFO: backup command begin 2.54.2: --annotation=pg_cluster=pg-meta ...
2025-07-15 01:36:57.030 P00   INFO: execute non-exclusive backup start: backup begins after the requested immediate checkpoint completes
2025-07-15 01:36:57.105 P00   INFO: backup start archive = 000000010000000000000006, lsn = 0/6000028
2025-07-15 01:36:58.540 P00   INFO: new backup label = 20250715-013657F
2025-07-15 01:36:58.588 P00   INFO: full backup size = 44.5MB, file total = 1437
2025-07-15 01:36:58.589 P00   INFO: backup command end: completed successfully (1584ms)
$ pgbackrest --stanza=pg-meta --type=diff backup
2025-07-15 01:37:24.952 P00   INFO: backup command begin 2.54.2: ...
2025-07-15 01:37:24.985 P00   INFO: last backup label = 20250715-013657F, version = 2.54.2
2025-07-15 01:37:26.337 P00   INFO: new backup label = 20250715-013657F_20250715-013724D
2025-07-15 01:37:26.381 P00   INFO: diff backup size = 424.3KB, file total = 1437
2025-07-15 01:37:26.381 P00   INFO: backup command end: completed successfully (1431ms)
$ pgbackrest --stanza=pg-meta --type=incr backup
2025-07-15 01:37:30.305 P00   INFO: backup command begin 2.54.2: ...
2025-07-15 01:37:30.337 P00   INFO: last backup label = 20250715-013657F_20250715-013724D, version = 2.54.2
2025-07-15 01:37:31.356 P00   INFO: new backup label = 20250715-013657F_20250715-013730I
2025-07-15 01:37:31.403 P00   INFO: incr backup size = 8.3KB, file total = 1437
2025-07-15 01:37:31.403 P00   INFO: backup command end: completed successfully (1099ms)
$ pgbackrest --stanza=pg-meta info
stanza: pg-meta
    status: ok
    cipher: aes-256-cbc

    db (current)
        wal archive min/max (17): 000000010000000000000001/00000001000000000000000A

        full backup: 20250715-013657F
            timestamp start/stop: 2025-07-15 01:36:57+00 / 2025-07-15 01:36:58+00
            wal start/stop: 000000010000000000000006 / 000000010000000000000006
            database size: 44.5MB, database backup size: 44.5MB
            repo1: backup size: 8.7MB

        diff backup: 20250715-013657F_20250715-013724D
            timestamp start/stop: 2025-07-15 01:37:24+00 / 2025-07-15 01:37:26+00
            database size: 44.5MB, database backup size: 424.3KB
            repo1: backup size: 94KB
            backup reference total: 1 full

        incr backup: 20250715-013657F_20250715-013730I
            timestamp start/stop: 2025-07-15 01:37:30+00 / 2025-07-15 01:37:31+00
            database size: 44.5MB, database backup size: 8.3KB
            repo1: backup size: 504B
            backup reference total: 1 full, 1 diff

Here the stanza is the database cluster name: pg_cluster, which is pg-meta in the default configuration.

Pigsty provides the pb alias and pg-backup wrapper script, which automatically fills in the current cluster name as the stanza:

function pb() {
    local stanza=$(grep -o '\[[^][]*]' /etc/pgbackrest/pgbackrest.conf | head -n1 | sed 's/.*\[\([^]]*\)].*/\1/')
    pgbackrest --stanza=$stanza $@
}
pb ...    # pgbackrest --stanza=pg-meta ...
pb info   # pgbackrest --stanza=pg-meta info
pb backup # pgbackrest --stanza=pg-meta backup
pg-backup full   # Perform full backup         = pgbackrest --stanza=pg-meta --type=full backup
pg-backup incr   # Perform incremental backup  = pgbackrest --stanza=pg-meta --type=incr backup
pg-backup diff   # Perform differential backup = pgbackrest --stanza=pg-meta --type=diff backup

Scheduled Backups

Pigsty uses Linux crontab to schedule backup tasks. You can use it to define backup policies.

For example, most single-node configuration templates have the following node_crontab for backups:

node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ]

You can design more complex backup strategies using crontab and the pg-backup script, for example:

node_crontab:  # Full backup at 1 AM on Monday, incremental backups on weekdays
  - '00 01 * * 1 postgres /pg/bin/pg-backup full'
  - '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'

To apply crontab changes, use node.yml to update crontab on all nodes:

./node.yml -t node_crontab -l pg-meta    # Apply crontab changes to pg-meta group

pgbackrest

Here are the configuration details for pgbackrest in Pigsty:

  • pgbackrest backup tool is enabled and configured by default (pgbackrest_enabled)
  • Installed in the pg_install task of the pgsql.yml playbook, defined in pg_packages
  • Configured in the pg_backup task of the pgsql.yml playbook, see Parameters: PG_BACKUP
  • Backup repository initialized in the pgbackrest_init task, which will fail if the repository already exists (error can be ignored)
  • Initial backup created in the pgbackrest_backup task, controlled by pgbackrest_init_backup

File Hierarchy

  • bin: /usr/bin/pgbackrest, from PGDG’s pgbackrest package, in group alias pgsql-common.
  • conf: /etc/pgbackrest, main configuration file is /etc/pgbackrest/pgbackrest.conf.
  • logs: /pg/log/pgbackrest/*, controlled by pgbackrest_log_dir
  • tmp: /pg/spool used as temporary spool directory for pgbackrest
  • data: /pg/backup used to store data (when using the default local filesystem backup repository)

Additionally, during PITR recovery, Pigsty creates a temporary /pg/conf/pitr.conf pgbackrest configuration file, and writes postgres recovery logs to the /pg/tmp/recovery.log file.

Monitoring

There is a pgbackrest_exporter service running on pgbackrest_exporter_port (9854) port for exporting pgbackrest metrics. You can customize it via pgbackrest_exporter_options, or set pgbackrest_exporter_enabled to false to disable it.

Initial Backup

When creating a postgres cluster, Pigsty automatically creates an initial backup. Since the new cluster is almost empty, this is a very small backup. It leaves a /etc/pgbackrest/initial.done marker file to avoid recreating the initial backup. If you don’t want an initial backup, set pgbackrest_init_backup to false.


Management

Enable Backup

If pgbackrest_enabled is set to true when the database cluster is created, backups will be automatically enabled.

If this value was false at creation time, you can enable the pgbackrest component with the following command:

./pgsql.yml -t pg_backup    # Run pgbackrest subtask

Remove Backup

When removing the primary instance (pg_role = primary), Pigsty will delete the pgbackrest backup stanza.

./pgsql-rm.yml
./pgsql-rm.yml -e pg_rm_backup=false   # Keep backups
./pgsql-rm.yml -t pg_backup            # Remove backups only

Use the pg_backup subtask to remove backups only, and the pg_rm_backup parameter (set to false) to preserve backups.

If your backup repository is locked (e.g., S3 / MinIO has locking options), this operation will fail.

List Backups

This command will list all backups in the pgbackrest repository (shared across all clusters)

pgbackrest info

Manual Backup

Pigsty provides a built-in script /pg/bin/pg-backup that wraps the pgbackrest backup command.

pg-backup        # Perform incremental backup
pg-backup full   # Perform full backup
pg-backup incr   # Perform incremental backup
pg-backup diff   # Perform differential backup

Base Backup

Pigsty provides an alternative backup script /pg/bin/pg-basebackup that does not depend on pgbackrest and directly provides a physical copy of the database cluster. The default backup directory is /pg/backup.

NAME
  pg-basebackup  -- make base backup from PostgreSQL instance

SYNOPSIS
  pg-basebackup -sdfeukr
  pg-basebackup --src postgres:/// --dst . --file backup.tar.lz4

DESCRIPTION
-s, --src, --url     Backup source URL, optional, defaults to "postgres:///", password should be provided in url, ENV, or .pgpass if required
-d, --dst, --dir     Location to store backup file, defaults to "/pg/backup"
-f, --file           Override default backup filename, "backup_${tag}_${date}.tar.lz4"
-r, --remove         Remove .lz4 files older than n minutes, defaults to 1200 (20 hours)
-t, --tag            Backup file tag, uses target cluster name or local IP address if not set, also used for default filename
-k, --key            Encryption key when --encrypt is specified, defaults to ${tag}
-u, --upload         Upload backup file to cloud storage (needs to be implemented by yourself)
-e, --encryption     Use OpenSSL RC4 encryption, uses tag as key if not specified
-h, --help           Print this help information
postgres@pg-meta-1:~$ pg-basebackup
[2025-07-13 06:16:05][INFO] ================================================================
[2025-07-13 06:16:05][INFO] [INIT] pg-basebackup begin, checking parameters
[2025-07-13 06:16:05][DEBUG] [INIT] filename  (-f)    :   backup_pg-meta_20250713.tar.lz4
[2025-07-13 06:16:05][DEBUG] [INIT] src       (-s)    :   postgres:///
[2025-07-13 06:16:05][DEBUG] [INIT] dst       (-d)    :   /pg/backup
[2025-07-13 06:16:05][INFO] [LOCK] lock acquired success on /tmp/backup.lock, pid=107417
[2025-07-13 06:16:05][INFO] [BKUP] backup begin, from postgres:/// to /pg/backup/backup_pg-meta_20250713.tar.lz4
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/7000028 on timeline 1
pg_basebackup: write-ahead log end point: 0/7000FD8
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed
[2025-07-13 06:16:06][INFO] [BKUP] backup complete!
[2025-07-13 06:16:06][INFO] [DONE] backup procedure complete!
[2025-07-13 06:16:06][INFO] ================================================================

The backup uses lz4 compression. You can decompress and extract the tarball with the following command:

mkdir -p /tmp/data   # Extract backup to this directory
cat /pg/backup/backup_pg-meta_20250713.tar.lz4 | unlz4 -d -c | tar -xC /tmp/data

Logical Backup

You can also perform logical backups using the pg_dump command.

Logical backups cannot be used for PITR (Point-in-Time Recovery), but are very useful for migrating data between different major versions or implementing flexible data export logic.

Bootstrap from Repository

Suppose you have an existing cluster pg-meta and want to clone it as pg-meta2:

You need to create a new pg-meta2 cluster branch and then run pitr on it.

10.8.3 - Backup Repository

PostgreSQL backup storage repository configuration

You can configure the backup storage location by specifying the pgbackrest_repo parameter. You can define multiple repositories here, and Pigsty will choose which one to use based on the value of pgbackrest_method.

Default Repositories

By default, Pigsty provides two default backup repository definitions: local and minio backup repositories.

  • local: Default option, uses local /pg/backup directory (symlink to pg_fs_backup: /data/backups)
  • minio: Uses SNSD single-node MinIO cluster (supported by Pigsty, but not enabled by default)
pgbackrest_method: local          # Choose backup repository method: `local`, `minio`, or other custom repository
pgbackrest_repo:                  # pgbackrest repository configuration: https://pgbackrest.org/configuration.html#section-repository
  local:                          # Default pgbackrest repository using local POSIX filesystem
    path: /pg/backup              # Local backup directory, defaults to `/pg/backup`
    retention_full_type: count    # Retain full backups by count
    retention_full: 2             # Keep 2, up to 3 full backups when using local filesystem repository
  minio:                          # Optional minio repository
    type: s3                      # minio is S3 compatible
    s3_endpoint: sss.pigsty       # minio endpoint domain, defaults to `sss.pigsty`
    s3_region: us-east-1          # minio region, defaults to us-east-1, meaningless for minio
    s3_bucket: pgsql              # minio bucket name, defaults to `pgsql`
    s3_key: pgbackrest            # minio user access key for pgbackrest
    s3_key_secret: S3User.Backup  # minio user secret for pgbackrest
    s3_uri_style: path            # minio uses path-style URIs instead of host-style
    path: /pgbackrest             # minio backup path, defaults to `/pgbackrest`
    storage_port: 9000            # minio port, defaults to 9000
    storage_ca_file: /etc/pki/ca.crt  # minio CA certificate path, defaults to `/etc/pki/ca.crt`
    block: y                      # Enable block-level incremental backup
    bundle: y                     # Bundle small files into a single file
    bundle_limit: 20MiB           # Bundle size limit, recommended 20MiB for object storage
    bundle_size: 128MiB           # Bundle target size, recommended 128MiB for object storage
    cipher_type: aes-256-cbc      # Enable AES encryption for remote backup repository
    cipher_pass: pgBackRest       # AES encryption password, defaults to 'pgBackRest'
    retention_full_type: time     # Retain full backups by time
    retention_full: 14            # Keep full backups from the last 14 days

Repository Retention Policy

If you backup daily but don’t delete old backups, the backup repository will grow indefinitely and exhaust disk space. You need to define a retention policy to keep only a limited number of backups.

The default backup policy is defined in the pgbackrest_repo parameter and can be adjusted as needed.

  • local: Keep the latest 2 full backups, allowing up to 3 during backup
  • minio: Keep all full backups from the last 14 days

Space Planning

Object storage provides almost unlimited storage capacity, so there’s no need to worry about disk space. You can use a hybrid full + differential backup strategy to optimize space usage.

For local disk backup repositories, Pigsty recommends using a policy that keeps the latest 2 full backups, meaning the disk will retain the two most recent full backups (there may be a third copy while running a new backup).

This guarantees at least a 24-hour recovery window. See Backup Policy for details.


Other Repository Options

You can also use other services as backup repositories, refer to the pgbackrest documentation for details:


Repository Versioning

You can even specify repo target time to get snapshots of object storage.

You can enable MinIO versioning by adding the versioning flag in minio_buckets:

minio_buckets:
  - { name: pgsql ,versioning: true }
  - { name: meta  ,versioning: true }
  - { name: data }

Repository Locking

Some object storage services (S3, MinIO, etc.) support locking functionality, which can prevent backups from being deleted, even by the DBA.

You can enable MinIO locking by adding the lock flag in minio_buckets:

minio_buckets:
  - { name: pgsql , lock: true }
  - { name: meta ,versioning: true  }
  - { name: data }

Using Object Storage

Object storage services provide almost unlimited storage capacity and provide remote disaster recovery capability for your system. If you don’t have an object storage service, Pigsty has built-in MinIO support.

MinIO

You can enable the MinIO backup repository by uncommenting the following settings. Note that pgbackrest only supports HTTPS / domain names, so you must run MinIO with domain names and HTTPS endpoints.

all:
  vars:
    pgbackrest_method: minio      # Use minio as default backup repository
  children:                       # Define a single-node minio SNSD cluster
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

S3

If you only have one node, a meaningful backup strategy would be to use cloud provider object storage services like AWS S3, Alibaba Cloud OSS, or Google Cloud, etc. To do this, you can define a new repository:

pgbackrest_method: s3             # Use 'pgbackrest_repo.s3' as backup repository
pgbackrest_repo:                  # pgbackrest repository configuration: https://pgbackrest.org/configuration.html#section-repository

  s3:                             # Alibaba Cloud OSS (S3 compatible) object storage service
    type: s3                      # oss is S3 compatible
    s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
    s3_region: oss-cn-beijing
    s3_bucket: <your_bucket_name>
    s3_key: <your_access_key>
    s3_key_secret: <your_secret_key>
    s3_uri_style: host
    path: /pgbackrest
    bundle: y                     # Bundle small files into a single file
    bundle_limit: 20MiB           # Bundle size limit, recommended 20MiB for object storage
    bundle_size: 128MiB           # Bundle target size, recommended 128MiB for object storage
    cipher_type: aes-256-cbc      # Enable AES encryption for remote backup repository
    cipher_pass: pgBackRest       # AES encryption password, defaults to 'pgBackRest'
    retention_full_type: time     # Retain full backups by time
    retention_full: 14            # Keep full backups from the last 14 days

  local:                          # Default pgbackrest repository using local POSIX filesystem
    path: /pg/backup              # Local backup directory, defaults to `/pg/backup`
    retention_full_type: count    # Retain full backups by count
    retention_full: 2             # Keep 2, up to 3 full backups when using local filesystem repository

Managing Backups

Enable Backup

If pgbackrest_enabled is set to true when the database cluster is created, backups will be automatically enabled.

If this value was false at creation time, you can enable the pgbackrest component with the following command:

./pgsql.yml -t pg_backup    # Run pgbackrest subtask

Remove Backup

When removing the primary instance (pg_role = primary), Pigsty will delete the pgbackrest backup stanza.

./pgsql-rm.yml
./pgsql-rm.yml -e pg_rm_backup=false   # Keep backups
./pgsql-rm.yml -t pg_backup            # Remove backups only

Use the pg_backup subtask to remove backups only, and the pg_rm_backup parameter (set to false) to preserve backups.

If your backup repository is locked (e.g., S3 / MinIO has locking options), this operation will fail.

List Backups

This command will list all backups in the pgbackrest repository (shared across all clusters)

pgbackrest info

Manual Backup

Pigsty provides a built-in script /pg/bin/pg-backup that wraps the pgbackrest backup command.

pg-backup        # Perform incremental backup
pg-backup full   # Perform full backup
pg-backup incr   # Perform incremental backup
pg-backup diff   # Perform differential backup

Base Backup

Pigsty provides an alternative backup script /pg/bin/pg-basebackup that does not depend on pgbackrest and directly provides a physical copy of the database cluster. The default backup directory is /pg/backup.

NAME
  pg-basebackup  -- make base backup from PostgreSQL instance

SYNOPSIS
  pg-basebackup -sdfeukr
  pg-basebackup --src postgres:/// --dst . --file backup.tar.lz4

DESCRIPTION
-s, --src, --url     Backup source URL, optional, defaults to "postgres:///", password should be provided in url, ENV, or .pgpass if required
-d, --dst, --dir     Location to store backup file, defaults to "/pg/backup"
-f, --file           Override default backup filename, "backup_${tag}_${date}.tar.lz4"
-r, --remove         Remove .lz4 files older than n minutes, defaults to 1200 (20 hours)
-t, --tag            Backup file tag, uses target cluster name or local IP address if not set, also used for default filename
-k, --key            Encryption key when --encrypt is specified, defaults to ${tag}
-u, --upload         Upload backup file to cloud storage (needs to be implemented by yourself)
-e, --encryption     Use OpenSSL RC4 encryption, uses tag as key if not specified
-h, --help           Print this help information
postgres@pg-meta-1:~$ pg-basebackup
[2025-07-13 06:16:05][INFO] ================================================================
[2025-07-13 06:16:05][INFO] [INIT] pg-basebackup begin, checking parameters
[2025-07-13 06:16:05][DEBUG] [INIT] filename  (-f)    :   backup_pg-meta_20250713.tar.lz4
[2025-07-13 06:16:05][DEBUG] [INIT] src       (-s)    :   postgres:///
[2025-07-13 06:16:05][DEBUG] [INIT] dst       (-d)    :   /pg/backup
[2025-07-13 06:16:05][INFO] [LOCK] lock acquired success on /tmp/backup.lock, pid=107417
[2025-07-13 06:16:05][INFO] [BKUP] backup begin, from postgres:/// to /pg/backup/backup_pg-meta_20250713.tar.lz4
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/7000028 on timeline 1
pg_basebackup: write-ahead log end point: 0/7000FD8
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed
[2025-07-13 06:16:06][INFO] [BKUP] backup complete!
[2025-07-13 06:16:06][INFO] [DONE] backup procedure complete!
[2025-07-13 06:16:06][INFO] ================================================================

The backup uses lz4 compression. You can decompress and extract the tarball with the following command:

mkdir -p /tmp/data   # Extract backup to this directory
cat /pg/backup/backup_pg-meta_20250713.tar.lz4 | unlz4 -d -c | tar -xC /tmp/data

Logical Backup

You can also perform logical backups using the pg_dump command.

Logical backups cannot be used for PITR (Point-in-Time Recovery), but are very useful for migrating data between different major versions or implementing flexible data export logic.

Bootstrap from Repository

Suppose you have an existing cluster pg-meta and want to clone it as pg-meta2:

You need to create a new pg-meta2 cluster branch and then run pitr on it.

10.8.4 - Admin Commands

Managing backup repositories and backups

Enable Backup

If pgbackrest_enabled is set to true when the database cluster is created, backups will be automatically enabled.

If this value was false at creation time, you can enable the pgbackrest component with the following command:

./pgsql.yml -t pg_backup    # Run pgbackrest subtask

Remove Backup

When removing the primary instance (pg_role = primary), Pigsty will delete the pgbackrest backup stanza.

./pgsql-rm.yml
./pgsql-rm.yml -e pg_rm_backup=false   # Keep backups
./pgsql-rm.yml -t pg_backup            # Remove backups only

Use the pg_backup subtask to remove backups only, and the pg_rm_backup parameter (set to false) to preserve backups.

If your backup repository is locked (e.g., S3 / MinIO has locking options), this operation will fail.


List Backups

This command will list all backups in the pgbackrest repository (shared across all clusters)

pgbackrest info

Manual Backup

Pigsty provides a built-in script /pg/bin/pg-backup that wraps the pgbackrest backup command.

pg-backup        # Perform incremental backup
pg-backup full   # Perform full backup
pg-backup incr   # Perform incremental backup
pg-backup diff   # Perform differential backup

Base Backup

Pigsty provides an alternative backup script /pg/bin/pg-basebackup that does not depend on pgbackrest and directly provides a physical copy of the database cluster. The default backup directory is /pg/backup.

NAME
  pg-basebackup  -- make base backup from PostgreSQL instance

SYNOPSIS
  pg-basebackup -sdfeukr
  pg-basebackup --src postgres:/// --dst . --file backup.tar.lz4

DESCRIPTION
-s, --src, --url     Backup source URL, optional, defaults to "postgres:///", password should be provided in url, ENV, or .pgpass if required
-d, --dst, --dir     Location to store backup file, defaults to "/pg/backup"
-f, --file           Override default backup filename, "backup_${tag}_${date}.tar.lz4"
-r, --remove         Remove .lz4 files older than n minutes, defaults to 1200 (20 hours)
-t, --tag            Backup file tag, uses target cluster name or local IP address if not set, also used for default filename
-k, --key            Encryption key when --encrypt is specified, defaults to ${tag}
-u, --upload         Upload backup file to cloud storage (needs to be implemented by yourself)
-e, --encryption     Use OpenSSL RC4 encryption, uses tag as key if not specified
-h, --help           Print this help information
postgres@pg-meta-1:~$ pg-basebackup
[2025-07-13 06:16:05][INFO] ================================================================
[2025-07-13 06:16:05][INFO] [INIT] pg-basebackup begin, checking parameters
[2025-07-13 06:16:05][DEBUG] [INIT] filename  (-f)    :   backup_pg-meta_20250713.tar.lz4
[2025-07-13 06:16:05][DEBUG] [INIT] src       (-s)    :   postgres:///
[2025-07-13 06:16:05][DEBUG] [INIT] dst       (-d)    :   /pg/backup
[2025-07-13 06:16:05][INFO] [LOCK] lock acquired success on /tmp/backup.lock, pid=107417
[2025-07-13 06:16:05][INFO] [BKUP] backup begin, from postgres:/// to /pg/backup/backup_pg-meta_20250713.tar.lz4
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/7000028 on timeline 1
pg_basebackup: write-ahead log end point: 0/7000FD8
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed
[2025-07-13 06:16:06][INFO] [BKUP] backup complete!
[2025-07-13 06:16:06][INFO] [DONE] backup procedure complete!
[2025-07-13 06:16:06][INFO] ================================================================

The backup uses lz4 compression. You can decompress and extract the tarball with the following command:

mkdir -p /tmp/data   # Extract backup to this directory
cat /pg/backup/backup_pg-meta_20250713.tar.lz4 | unlz4 -d -c | tar -xC /tmp/data

Logical Backup

You can also perform logical backups using the pg_dump command.

Logical backups cannot be used for PITR (Point-in-Time Recovery), but are very useful for migrating data between different major versions or implementing flexible data export logic.


Bootstrap from Repository

Suppose you have an existing cluster pg-meta and want to clone it as pg-meta2:

You need to create a new pg-meta2 cluster branch and then run pitr on it.

10.8.5 - Restore Operations

Restore PostgreSQL from backups

You can perform Point-in-Time Recovery (PITR) in Pigsty using pre-configured pgbackrest.

  • Manual Approach: Manually execute PITR using pg-pitr prompt scripts, more flexible but more complex.
  • Playbook Approach: Automatically execute PITR using pgsql-pitr.yml playbook, highly automated but less flexible and error-prone.

If you are very familiar with the configuration, you can use the fully automated playbook, otherwise manual step-by-step operation is recommended.


Quick Start

If you want to roll back the pg-meta cluster to a previous point in time, add the pg_pitr parameter:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta2
    pg_pitr: { time: '2025-07-13 10:00:00+00' }  # Recover from latest backup

Then run the pgsql-pitr.yml playbook, which will roll back the pg-meta cluster to the specified point in time.

./pgsql-pitr.yml -l pg-meta

Post-Recovery

The recovered cluster will have archive_mode disabled to prevent accidental WAL writes. If the recovered database state is normal, you can enable archive_mode and perform a full backup.

psql -c 'ALTER SYSTEM RESET archive_mode; SELECT pg_reload_conf();'
pg-backup full    # Perform new full backup

Recovery Target

You can specify different types of recovery targets in pg_pitr, but they are mutually exclusive:

  • time: To which point in time to recover?
  • name: Recover to a named restore point (created by pg_create_restore_point)
  • xid: Recover to a specific transaction ID (TXID/XID)
  • lsn: Recover to a specific LSN (Log Sequence Number) point

If any of the above parameters are specified, the recovery type will be set accordingly, otherwise it will be set to latest (end of WAL archive stream). The special immediate type can be used to instruct pgbackrest to minimize recovery time by stopping at the first consistent point.

Target Types

pg_pitr: { }  # Recover to latest state (end of WAL archive stream)
pg_pitr: { time: "2025-07-13 10:00:00+00" }
pg_pitr: { lsn: "0/4001C80" }
pg_pitr: { xid: "250000" }
pg_pitr: { name: "some_restore_point" }
pg_pitr: { type: "immediate" }

Recover by Time

The most commonly used target is a point in time; you can specify the time point to recover to:

./pgsql-pitr.yml -e '{"pg_pitr": { "time": "2025-07-13 10:00:00+00" }}'

Time should be in valid PostgreSQL TIMESTAMP format, YYYY-MM-DD HH:MM:SS+TZ is recommended.

Recover by Name

You can create named restore points using pg_create_restore_point:

SELECT pg_create_restore_point('shit_incoming');

Then use that named restore point in PITR:

./pgsql-pitr.yml -e '{"pg_pitr": { "name": "shit_incoming" }}'

Recover by XID

If you have a transaction that accidentally deleted some data, the best way to recover is to restore the database to the state before that transaction.

./pgsql-pitr.yml -e '{"pg_pitr": { "xid": "250000", exclusive: true }}'

You can find the exact transaction ID from monitoring dashboards or from the TXID field in CSVLOG.

Recover by LSN

PostgreSQL uses LSN (Log Sequence Number) to identify the location of WAL records. You can find it in many places, such as the PG LSN panel in Pigsty dashboards.

./pgsql-pitr.yml -e '{"pg_pitr": { "lsn": "0/4001C80", timeline: "1" }}'

To recover to an exact position in the WAL stream, you can also specify the timeline parameter (defaults to latest)


Recovery Source

  • cluster: From which cluster to recover? Defaults to current pg_cluster, you can use any other cluster in the same pgbackrest repository
  • repo: Override backup repository, uses same format as pgbackrest_repo
  • set: Defaults to latest backup set, but you can specify a specific pgbackrest backup by label

Pigsty will recover from the pgbackrest backup repository. If you use a centralized backup repository (like MinIO/S3), you can specify another “stanza” (another cluster’s backup directory) as the recovery source.

pg-meta2:
  hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta2
    pg_pitr: { cluster: pg-meta }  # Recover from pg-meta cluster backup

The above configuration will mark the PITR process to use the pg-meta stanza. You can also pass the pg_pitr parameter via CLI arguments:

./pgsql-pitr.yml -l pg-meta2 -e '{"pg_pitr": { "cluster": "pg-meta" }}'

You can also use these targets when PITR from another cluster:

./pgsql-pitr.yml -l pg-meta2 -e '{"pg_pitr": { "cluster": "pg-meta", "time": "2025-07-14 08:00:00+00" }}'

Step-by-Step Execution

This approach is semi-automatic, you will participate in the PITR process to make critical decisions.

For example, this configuration will restore the pg-meta cluster itself to the specified point in time:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta2
    pg_pitr: { time: '2025-07-13 10:00:00+00' }  # Recover from latest backup

Let’s execute step by step:

./pgsql-pitr.yml -l pg-meta -t down     # Pause patroni high availability
./pgsql-pitr.yml -l pg-meta -t pitr     # Run pitr process
./pgsql-pitr.yml -l pg-meta -t up       # Generate pgbackrest config and recovery script
# down                 : # Stop high availability and shutdown patroni and postgres
#   - pause            : # Pause patroni auto-failover
#   - stop             : # Stop patroni and postgres services
#     - stop_patroni   : # Stop patroni service
#     - stop_postgres  : # Stop postgres service
# pitr                 : # Perform PITR process
#   - config           : # Generate pgbackrest config and recovery script
#   - restore          : # Run pgbackrest restore command
#   - recovery         : # Start postgres and complete recovery
#   - verify           : # Verify recovered cluster control data
# up:                  : # Start postgres / patroni and restore high availability
#   - etcd             : # Clean etcd metadata before starting
#   - start            : # Start patroni and postgres services
#     - start_postgres : # Start postgres service
#     - start_patroni  : # Start patroni service
#   - resume           : # Resume patroni auto-failover

PITR Parameter Definition

The pg_pitr parameter has more options available:

pg_pitr:                           # Define PITR task
    cluster: "some_pg_cls_name"    # Source cluster name
    type: latest                   # Recovery target type: time, xid, name, lsn, immediate, latest
    time: "2025-01-01 10:00:00+00" # Recovery target: time, mutually exclusive with xid, name, lsn
    name: "some_restore_point"     # Recovery target: named restore point, mutually exclusive with time, xid, lsn
    xid:  "100000"                 # Recovery target: transaction ID, mutually exclusive with time, name, lsn
    lsn:  "0/3000000"              # Recovery target: log sequence number, mutually exclusive with time, name, xid
    timeline: latest               # Target timeline, can be integer, defaults to latest
    exclusive: false               # Whether to exclude target point, defaults to false
    action: pause                  # Post-recovery action: pause, promote, shutdown
    archive: false                 # Whether to keep archive settings? Defaults to false
    db_exclude: [ template0, template1 ]
    db_include: []
    link_map:
      pg_wal: '/data/wal'
      pg_xact: '/data/pg_xact'
    process: 4                     # Number of parallel recovery processes
    repo: {}                       # Recovery source repository
    data: /pg/data                 # Data recovery location
    port: 5432                     # Listening port for recovered instance

10.8.6 - Clone Database Cluster

How to use PITR to create a new PostgreSQL cluster and restore to a specified point in time?

Quick Start

  • Create an online replica of an existing cluster using Standby Cluster
  • Create a point-in-time snapshot of an existing cluster using PITR
  • Perform post-PITR cleanup to ensure the new cluster’s backup process works properly

You can use the PG PITR mechanism to clone an entire database cluster.

Reset a Cluster’s State

You can also consider creating a brand new empty cluster, then use PITR to reset it to a specific state of the pg-meta cluster.

Using this technique, you can clone any point-in-time (within backup retention period) state of the existing cluster pg-meta to a new cluster.

Using the Pigsty 4-node sandbox environment as an example, use the following command to reset the pg-test cluster to the latest state of the pg-meta cluster:

./pgsql-pitr.yml -l pg-test -e '{"pg_pitr": { "cluster": "pg-meta" }}'

Post-PITR Cleanup

When you restore a cluster using PITR, the new cluster’s PITR functionality is disabled. This is because if it also tries to generate backups and archive WAL, it could dirty the backup repository of the previous cluster.

Therefore, after confirming that the state of this PITR-restored new cluster meets expectations, you need to perform the following cleanup:

  • Upgrade the backup repository Stanza to accept new backups from different clusters (only when restoring from another cluster)
  • Enable archive_mode to allow the new cluster to archive WAL logs (requires cluster restart)
  • Perform a new full backup to ensure the new cluster’s data is included (optional, can also wait for crontab scheduled execution)
pb stanza-upgrade
psql -c 'ALTER SYSTEM RESET archive_mode;'
pg-backup full

Through these operations, your new cluster will have its own backup history starting from the first full backup. If you skip these steps, the new cluster’s backups will not work, and WAL archiving will not take effect, meaning you cannot perform any backup or PITR operations on the new cluster.

Consequences of Not Cleaning Up

Suppose you performed PITR recovery on the pg-test cluster using data from another cluster pg-meta, but did not perform cleanup.

Then at the next routine backup, you will see the following error:

postgres@pg-test-1:~$ pb backup
2025-12-27 10:20:29.336 P00   INFO: backup command begin...
2025-12-27 10:20:29.357 P00  ERROR: [051]: PostgreSQL version 18, system-id 7588470953413201282 do not match stanza version 18, system-id 7588470974940466058
                                    HINT: is this the correct stanza?

Clone a New Cluster

For example, suppose you have a cluster pg-meta, and now you want to clone a new cluster pg-meta2 from pg-meta.

You can consider using the Standby Cluster method to create a new cluster pg-meta2.

pgBackrest supports incremental backup/restore, so if you have already pulled pg-meta’s data through physical replication, the incremental PITR restore is usually very fast.

pb stop --force
pb stanza-delete --force
pb start
pb stanza-create

If you want to reset the pg-test cluster to the state of pg-meta cluster at 15:30 on December 26, 2025, you can use the following command:

./pgsql-pitr.yml -l pg-test -e '{"pg_pitr": { "cluster": "pg-meta", "time": "2025-12-27 17:50:00+08" ,archive: true }}'

Using this technique, you can not only clone the latest state of the pg-meta cluster, but also clone to any point in time.

10.8.7 - Instance Recovery

Clone instances and perform point-in-time recovery on the same machine

Pigsty provides two utility scripts for quickly cloning instances and performing point-in-time recovery on the same machine:

  • pg-fork: Quickly clone a new PostgreSQL instance on the same machine
  • pg-pitr: Manually perform point-in-time recovery using pgbackrest

These two scripts can be used together: first use pg-fork to clone the instance, then use pg-pitr to restore the cloned instance to a specified point in time.


pg-fork

pg-fork can quickly clone a new PostgreSQL instance on the same machine.

Quick Start

Execute the following command as the postgres user (dbsu) to create a new instance:

pg-fork 1                         # Clone from /pg/data to /pg/data1, port 15432
pg-fork 2 -d /pg/data1            # Clone from /pg/data1 to /pg/data2, port 25432
pg-fork 3 -D /tmp/test -P 5555    # Clone to custom directory and port

After cloning, start and access the new instance:

pg_ctl -D /pg/data1 start         # Start cloned instance
psql -p 15432                     # Connect to cloned instance

Command Syntax

pg-fork <FORK_ID> [options]

Required Parameters:

ParameterDescription
<FORK_ID>Clone instance number (1-9), determines default port and data directory

Optional Parameters:

ParameterDescriptionDefault
-d, --data <datadir>Source instance data directory/pg/data or $PG_DATA
-D, --dst <dst_dir>Target data directory/pg/data<FORK_ID>
-p, --port <port>Source instance port5432 or $PG_PORT
-P, --dst-port <port>Target instance port<FORK_ID>5432
-s, --skipSkip backup API, use cold copy mode-
-y, --yesSkip confirmation prompts-
-h, --helpShow help information-

How It Works

pg-fork supports two working modes:

Hot Backup Mode (default, source instance running):

  1. Call pg_backup_start() to start backup
  2. Use cp --reflink=auto to copy data directory
  3. Call pg_backup_stop() to end backup
  4. Modify configuration files to avoid conflicts with source instance

Cold Copy Mode (using -s parameter or source instance not running):

  1. Directly use cp --reflink=auto to copy data directory
  2. Modify configuration files

If you use XFS (with reflink enabled), Btrfs, or ZFS file systems, pg-fork will leverage Copy-on-Write features. The data directory copy completes in a few hundred milliseconds and takes almost no additional storage space.


pg-pitr

pg-pitr is a script for manually performing point-in-time recovery, based on pgbackrest.

Quick Start

pg-pitr -d                                  # Restore to latest state
pg-pitr -i                                  # Restore to backup completion time
pg-pitr -t "2025-01-01 12:00:00+08"         # Restore to specified time point
pg-pitr -n my-savepoint                     # Restore to named restore point
pg-pitr -l "0/7C82CB8"                      # Restore to specified LSN
pg-pitr -x 12345678 -X                      # Restore to before transaction
pg-pitr -b 20251225-120000F                 # Restore to specified backup set

Command Syntax

pg-pitr [options] [recovery_target]

Recovery Target (choose one):

ParameterDescription
-d, --defaultRestore to end of WAL archive stream (latest state)
-i, --immediateRestore to database consistency point (fastest recovery)
-t, --time <timestamp>Restore to specified time point
-n, --name <restore_point>Restore to named restore point
-l, --lsn <lsn>Restore to specified LSN
-x, --xid <xid>Restore to specified transaction ID
-b, --backup <label>Restore to specified backup set

Optional Parameters:

ParameterDescriptionDefault
-D, --data <path>Recovery target data directory/pg/data
-s, --stanza <name>pgbackrest stanza nameAuto-detect
-X, --exclusiveExclude target point (restore to before target)-
-P, --promoteAuto-promote after recovery (default pauses)-
-c, --checkDry run mode, only print commands-
-y, --yesSkip confirmation and countdown-

Post-Recovery Processing

After recovery completes, the instance will be in recovery paused state (unless -P parameter is used). You need to:

  1. Start instance: pg_ctl -D /pg/data start
  2. Verify data: Check if data meets expectations
  3. Promote instance: pg_ctl -D /pg/data promote
  4. Enable archiving: psql -c "ALTER SYSTEM SET archive_mode = on;"
  5. Restart instance: pg_ctl -D /pg/data restart
  6. Execute backup: pg-backup full

Combined Usage

pg-fork and pg-pitr can be combined for a safe PITR verification workflow:

# 1. Clone current instance
pg-fork 1 -y

# 2. Execute PITR on cloned instance (doesn't affect production)
pg-pitr -D /pg/data1 -t "2025-12-27 10:00:00+08"

# 3. Start cloned instance
pg_ctl -D /pg/data1 start

# 4. Verify recovery results
psql -p 15432 -c "SELECT count(*) FROM orders WHERE created_at < '2025-12-27 10:00:00';"

# 5. After confirmation, you can choose:
#    - Option A: Execute the same PITR on production instance
#    - Option B: Promote cloned instance as new production instance

# 6. Clean up test instance
pg_ctl -D /pg/data1 stop
rm -rf /pg/data1

Notes

Runtime Requirements

  • Must be executed as postgres user (or postgres group member)
  • pg-pitr requires stopping target instance’s PostgreSQL before execution
  • pg-fork hot backup mode requires source instance to be running

File System

  • XFS (with reflink enabled) or Btrfs file system recommended
  • Cloning on CoW file systems is almost instant and takes no extra space
  • Non-CoW file systems will perform full copy, taking longer

Port Planning

FORK_IDDefault PortDefault Data Directory
115432/pg/data1
225432/pg/data2
335432/pg/data3
995432/pg/data9

10.8.8 - Clone Database

How to clone an existing database within a PostgreSQL cluster using instant XFS cloning

Clone Database

You can copy a PostgreSQL database through the template mechanism, but no active connections to the template database are allowed during this period.

If you want to clone the postgres database, you must execute the following two statements at the same time. Ensure all connections to the postgres database are cleaned up before executing Clone:

SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'postgres';
CREATE DATABASE pgcopy TEMPLATE postgres STRATEGY FILE_COPY;

Instant Clone

If you are using PostgreSQL 18 or higher, Pigsty sets file_copy_method by default. This parameter allows you to clone a database in O(1) (~200ms) time complexity without copying data files.

However, you must explicitly use the FILE_COPY strategy to create the database. Since the STRATEGY parameter of CREATE DATABASE was introduced in PostgreSQL 15, the default value has been WAL_LOG. You need to explicitly specify FILE_COPY for instant cloning.

SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'meta';
CREATE DATABASE pgcopy TEMPLATE meta STRATEGY FILE_COPY;

For example, cloning a 30 GB database: normal clone (WAL_LOG) takes 18 seconds, while instant clone (FILE_COPY) only needs constant time of 200 milliseconds.

However, you still need to ensure no active connections to the template database during cloning, but this time can be very short, making it practical for production environments.

If you need a new database copy for testing or development, instant cloning is an excellent choice. It doesn’t introduce additional storage overhead because it uses the file system’s CoW (Copy on Write) mechanism.

Since Pigsty v4.0, you can use strategy: FILE_COPY in the pg_databases parameter to achieve instant database cloning.

    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_version: 18
        pg_databases:

          - name: meta

          - name: meta_dev
            template: meta
            strategy: FILE_COPY         # <---- Introduced in PG 15, instant in PG18
            #comment: "meta clone"      # <---- Database comment
            #pgbouncer: false           # <---- Not added to connection pool?
            #register_datasource: false # <---- Not added to Grafana datasource?

After configuration, use the standard database creation SOP to create the database:

bin/pgsql-db pg-meta meta_dev

Limitations and Notes

This feature is only available on supported file systems (xfs, btrfs, zfs, apfs). If the file system doesn’t support it, PostgreSQL will fail with an error.

By default, mainstream OS distributions’ xfs have reflink=1 enabled by default, so you don’t need to worry about this in most cases.

OpenZFS requires explicit configuration to support CoW, but due to prior data corruption incidents, it’s not recommended for production use.

If your PostgreSQL version is below 15, specifying strategy will have no effect.

Please don’t use the postgres database as a template database for cloning, as management connections typically connect to the postgres database, which prevents the cloning operation.

Use instant cloning with caution in extremely high concurrency/throughput production environments, as it requires clearing all connections to the template database within the cloning window (200ms), otherwise the clone will fail.

10.8.9 - Manual Recovery

Manually perform PITR following prompt scripts in sandbox environment

You can use the pgsql-pitr.yml playbook to perform PITR, but in some cases, you may want to manually execute PITR using pgbackrest primitives directly for fine-grained control. We will use a four-node sandbox cluster with MinIO backup repository to demonstrate the process.

pigsty-sandbox


Initialize Sandbox

Use vagrant or terraform to prepare a four-node sandbox environment, then:

curl https://repo.pigsty.io/get | bash; cd ~/pigsty/
./configure -c full
./install

Now operate as the admin user (or dbsu) on the admin node.


Check Backup

To check backup status, you need to switch to the postgres user and use the pb command:

sudo su - postgres    # Switch to dbsu: postgres user
pb info               # Print pgbackrest backup info

pb is an alias for pgbackrest that automatically retrieves the stanza name from pgbackrest configuration.

function pb() {
    local stanza=$(grep -o '\[[^][]*]' /etc/pgbackrest/pgbackrest.conf | head -n1 | sed 's/.*\[\([^]]*\)].*/\1/')
    pgbackrest --stanza=$stanza $@
}

You can see the initial backup information, which is a full backup:

root@pg-meta-1:~# pb info
stanza: pg-meta
    status: ok
    cipher: aes-256-cbc

    db (current)
        wal archive min/max (17): 000000010000000000000001/000000010000000000000007

        full backup: 20250713-022731F
            timestamp start/stop: 2025-07-13 02:27:31+00 / 2025-07-13 02:27:33+00
            wal start/stop: 000000010000000000000004 / 000000010000000000000004
            database size: 44MB, database backup size: 44MB
            repo1: backup size: 8.4MB

The backup completed at 2025-07-13 02:27:33+00, which is the earliest time you can restore to. Since WAL archiving is active, you can restore to any point in time after the backup, up to the end of WAL (i.e., now).


Generate Heartbeats

You can generate some heartbeats to simulate workload. /pg-bin/pg-heartbeat is for this purpose, it writes a heartbeat timestamp to the monitor.heartbeat table every second.

make rh     # Run heartbeat: ssh 10.10.10.10 'sudo -iu postgres /pg/bin/pg-heartbeat'
ssh 10.10.10.10 'sudo -iu postgres /pg/bin/pg-heartbeat'
   cls   |              ts               |    lsn     |  lsn_int  | txid | status  |       now       |  elapse
---------+-------------------------------+------------+-----------+------+---------+-----------------+----------
 pg-meta | 2025-07-13 03:01:20.318234+00 | 0/115BF5C0 | 291239360 | 4812 | leading | 03:01:20.318234 | 00:00:00

You can even add more workload to the cluster. Let’s use pgbench to generate some random writes:

make ri     # Initialize pgbench
make rw     # Run pgbench read-write workload
pgbench -is10 postgres://dbuser_meta:[email protected]:5433/meta
while true; do pgbench -nv -P1 -c4 --rate=64 -T10 postgres://dbuser_meta:[email protected]:5433/meta; done
while true; do pgbench -nv -P1 -c4 --rate=64 -T10 postgres://dbuser_meta:[email protected]:5433/meta; done
pgbench (17.5 (Homebrew), server 17.4 (Ubuntu 17.4-1.pgdg24.04+2))
progress: 1.0 s, 60.9 tps, lat 7.295 ms stddev 4.219, 0 failed, lag 1.818 ms
progress: 2.0 s, 69.1 tps, lat 6.296 ms stddev 1.983, 0 failed, lag 1.397 ms
...

PITR Manual

Now let’s choose a recovery point in time, such as 2025-07-13 03:03:03+00, which is a point after the initial backup (and heartbeat). To perform manual PITR, use the pg-pitr tool:

$ pg-pitr -t "2025-07-13 03:03:00+00"

It will generate instructions for performing the recovery, typically requiring four steps:

Perform time PITR on pg-meta
[1. Stop PostgreSQL] ===========================================
   1.1 Pause Patroni (if there are any replicas)
       $ pg pause <cls>  # Pause patroni auto-failover
   1.2 Shutdown Patroni
       $ pt-stop         # sudo systemctl stop patroni
   1.3 Shutdown Postgres
       $ pg-stop         # pg_ctl -D /pg/data stop -m fast

[2. Perform PITR] ===========================================
   2.1 Restore Backup
       $ pgbackrest --stanza=pg-meta --type=time --target='2025-07-13 03:03:00+00' restore
   2.2 Start PG to Replay WAL
       $ pg-start        # pg_ctl -D /pg/data start
   2.3 Validate and Promote
     - If database content is ok, promote it to finish recovery, otherwise goto 2.1
       $ pg-promote      # pg_ctl -D /pg/data promote
[3. Restore Primary] ===========================================
   3.1 Enable Archive Mode (Restart Required)
       $ psql -c 'ALTER SYSTEM SET archive_mode = on;'
   3.1 Restart Postgres to Apply Changes
       $ pg-restart      # pg_ctl -D /pg/data restart
   3.3 Restart Patroni
       $ pt-restart      # sudo systemctl restart patroni

[4. Restore Cluster] ===========================================
   4.1 Re-Init All [**REPLICAS**] (if any)
       - 4.1.1 option 1: restore replicas with same pgbackrest cmd (require central backup repo)
           $ pgbackrest --stanza=pg-meta --type=time --target='2025-07-13 03:03:00+00' restore
       - 4.1.2 option 2: nuke the replica data dir and restart patroni (may take long time to restore)
           $ rm -rf /pg/data/*; pt-restart
       - 4.1.3 option 3: reinit with patroni, which may fail if primary lsn < replica lsn
           $ pg reinit pg-meta
   4.2 Resume Patroni
       $ pg resume pg-meta
   4.3 Full Backup (optional)
       $ pg-backup full      # Recommended to perform new full backup after PITR

Single Node Example

Let’s start with the simple single-node pg-meta cluster as a simpler example.

Shutdown Database

pt-stop         # sudo systemctl stop patroni, shutdown patroni (and postgres)
# Optional, because postgres will be shutdown by patroni if patroni is not paused
$ pg_stop        # pg_ctl -D /pg/data stop -m fast, shutdown postgres

pg_ctl: PID file "/pg/data/postmaster.pid" does not exist
Is server running?

$ pg-ps           # Print postgres related processes

 UID         PID   PPID  C STIME TTY      STAT   TIME CMD
postgres  31048      1  0 02:27 ?        Ssl    0:19 /usr/sbin/pgbouncer /etc/pgbouncer/pgbouncer.ini
postgres  32026      1  0 02:28 ?        Ssl    0:03 /usr/bin/pg_exporter ...
postgres  35510  35480  0 03:01 pts/2    S+     0:00 /bin/bash /pg/bin/pg-heartbeat

Make sure local postgres is not running, then execute the recovery commands given in the manual:

Restore Backup

pgbackrest --stanza=pg-meta --type=time --target='2025-07-13 03:03:00+00' restore
postgres@pg-meta-1:~$ pgbackrest --stanza=pg-meta --type=time --target='2025-07-13 03:03:00+00' restore
2025-07-13 03:17:07.443 P00   INFO: restore command begin 2.54.2: ...
2025-07-13 03:17:07.470 P00   INFO: repo1: restore backup set 20250713-022731F, recovery will start at 2025-07-13 02:27:31
2025-07-13 03:17:07.471 P00   INFO: remove invalid files/links/paths from '/pg/data'
2025-07-13 03:17:08.523 P00   INFO: write updated /pg/data/postgresql.auto.conf
2025-07-13 03:17:08.527 P00   INFO: restore size = 44MB, file total = 1436
2025-07-13 03:17:08.527 P00   INFO: restore command end: completed successfully (1087ms)

Verify Data

We don’t want patroni HA to take over until we’re sure the data is correct, so start postgres manually:

pg-start
waiting for server to start....2025-07-13 03:19:33.133 UTC [39294] LOG:  redirecting log output to logging collector process
2025-07-13 03:19:33.133 UTC [39294] HINT:  Future log output will appear in directory "/pg/log/postgres".
 done
server started

Now you can check the data to see if it’s at the point in time you want. You can verify by checking the latest timestamp in business tables, or in this case, check via the heartbeat table.

postgres@pg-meta-1:~$ psql -c 'table monitor.heartbeat'
   id    |              ts               |    lsn    | txid
---------+-------------------------------+-----------+------
 pg-meta | 2025-07-13 03:02:59.214104+00 | 302005504 | 4912

The timestamp is just before our specified point in time! (2025-07-13 03:03:00+00). If this is not the point in time you want, you can repeat the recovery with a different time point. Since recovery is performed incrementally and in parallel, it’s very fast. You can retry until you find the correct point in time.

Promote Primary

The recovered postgres cluster is in recovery mode, so it will reject any write operations until promoted to primary. These recovery parameters are generated by pgBackRest in the configuration file.

postgres@pg-meta-1:~$ cat /pg/data/postgresql.auto.conf
# Do not edit this file or use ALTER SYSTEM manually!
# It is managed by Pigsty & Ansible automatically!

# Recovery settings generated by pgBackRest restore on 2025-07-13 03:17:08
archive_mode = 'off'
restore_command = 'pgbackrest --stanza=pg-meta archive-get %f "%p"'
recovery_target_time = '2025-07-13 03:03:00+00'

If the data is correct, you can promote it to primary, marking it as the new leader and ready to accept writes.

pg-promote
waiting for server to promote.... done
server promoted
psql -c 'SELECT pg_is_in_recovery()'   # 'f' means promoted to primary
 pg_is_in_recovery
-------------------
 f
(1 row)

Restore Cluster

Finally, not only do you need to restore data, but also restore cluster state, such as:

  • patroni takeover
  • archive mode
  • backup set
  • replicas

Patroni Takeover

Your postgres was started directly. To restore HA takeover, you need to start the patroni service:

pt-start   # sudo systemctl start patroni
pg resume pg-meta      # Resume patroni auto-failover (if previously paused)

Archive Mode

archive_mode is disabled during recovery by pgbackrest. If you want new leader writes to be archived to the backup repository, you also need to enable the archive_mode configuration.

psql -c 'show archive_mode'

 archive_mode
--------------
 off
psql -c 'ALTER SYSTEM RESET archive_mode;'
psql -c 'SELECT pg_reload_conf();'
psql -c 'show archive_mode'
# You can also directly edit postgresql.auto.conf and reload with pg_ctl
sed -i '/archive_mode/d' /pg/data/postgresql.auto.conf
pg_ctl -D /pg/data reload

Backup Set

It’s generally recommended to perform a new full backup after PITR, but this is optional.

Replicas

If your postgres cluster has replicas, you also need to perform PITR on each replica. Alternatively, a simpler approach is to remove the replica data directory and restart patroni, which will reinitialize the replica from the primary. We’ll cover this scenario in the next multi-node cluster example.


Multi-Node Example

Now let’s use the three-node pg-test cluster as a PITR example.

10.9 - Data Migration

How to migrate an existing PostgreSQL cluster to a new Pigsty-managed PostgreSQL cluster with minimal downtime?

Pigsty includes a built-in playbook pgsql-migration.yml that implements online database migration based on logical replication.

With pre-generated automation scripts, application downtime can be reduced to just a few seconds. However, note that logical replication requires PostgreSQL 10 or later to work.

Of course, if you have sufficient downtime budget, you can always use the pg_dump | psql approach for offline migration.


Defining Migration Tasks

To use Pigsty’s online migration playbook, you need to create a definition file that describes the migration task details.

Refer to the task definition file example: files/migration/pg-meta.yml.

This migration task will online migrate pg-meta.meta to pg-test.test, where the former is called the Source Cluster (SRC) and the latter is called the Destination Cluster (DST).

pg-meta-1	10.10.10.10  --> pg-test-1	10.10.10.11 (10.10.10.12,10.10.10.13)

Logical replication-based migration works on a per-database basis. You need to specify the database name to migrate, as well as the IP addresses of the source and destination cluster primary nodes and superuser connection information.

---
#-----------------------------------------------------------------
# PG_MIGRATION
#-----------------------------------------------------------------
context_dir: ~/migration  # Directory for migration manual & scripts
#-----------------------------------------------------------------
# SRC Cluster (Old Cluster)
#-----------------------------------------------------------------
src_cls: pg-meta      # Source cluster name                  <Required>
src_db: meta          # Source database name                 <Required>
src_ip: 10.10.10.10   # Source cluster primary IP            <Required>
#src_pg: ''            # If defined, use this as source dbsu pgurl instead of:
#                      # postgres://{{ pg_admin_username }}@{{ src_ip }}/{{ src_db }}
#                      # e.g.: 'postgres://dbuser_dba:[email protected]:5432/meta'
#sub_conn: ''          # If defined, use this as subscription connection string instead of:
#                      # host={{ src_ip }} dbname={{ src_db }} user={{ pg_replication_username }}'
#                      # e.g.: 'host=10.10.10.10 dbname=meta user=replicator password=DBUser.Replicator'
#-----------------------------------------------------------------
# DST Cluster (New Cluster)
#-----------------------------------------------------------------
dst_cls: pg-test      # Destination cluster name             <Required>
dst_db: test          # Destination database name            <Required>
dst_ip: 10.10.10.11   # Destination cluster primary IP       <Required>
#dst_pg: ''            # If defined, use this as destination dbsu pgurl instead of:
#                      # postgres://{{ pg_admin_username }}@{{ dst_ip }}/{{ dst_db }}
#                      # e.g.: 'postgres://dbuser_dba:[email protected]:5432/test'
#-----------------------------------------------------------------
# PGSQL
#-----------------------------------------------------------------
pg_dbsu: postgres
pg_replication_username: replicator
pg_replication_password: DBUser.Replicator
pg_admin_username: dbuser_dba
pg_admin_password: DBUser.DBA
pg_monitor_username: dbuser_monitor
pg_monitor_password: DBUser.Monitor
#-----------------------------------------------------------------
...

By default, the superuser connection strings on both source and destination sides are constructed using the global admin user and the respective primary IP addresses, but you can always override these defaults through the src_pg and dst_pg parameters. Similarly, you can override the subscription connection string default through the sub_conn parameter.


Generating Migration Plan

This playbook does not actively perform cluster migration, but it generates the operation manual and automation scripts needed for migration.

By default, you will find the migration context directory at ~/migration/pg-meta.meta. Follow the instructions in README.md and execute these scripts in sequence to complete the database migration!

# Activate migration context: enable related environment variables
. ~/migration/pg-meta.meta/activate

# These scripts check src cluster status and help generate new cluster definitions in pigsty
./check-user     # Check src users
./check-db       # Check src databases
./check-hba      # Check src hba rules
./check-repl     # Check src replication identity
./check-misc     # Check src special objects

# These scripts establish logical replication between existing src cluster and pigsty-managed dst cluster, data except sequences will sync in real-time
./copy-schema    # Copy schema to destination
./create-pub     # Create publication on src
./create-sub     # Create subscription on dst
./copy-progress  # Print logical replication progress
./copy-diff      # Quick compare src and dst differences by counting tables

# These scripts run during online migration, which stops src cluster and copies sequence numbers (logical replication doesn't replicate sequences!)
./copy-seq [n]   # Sync sequence numbers, if n is given, apply additional offset

# You must switch application traffic to the new cluster based on your access method (dns,vip,haproxy,pgbouncer,etc.)!
#./disable-src   # Restrict src cluster access to admin nodes and new cluster (your implementation)
#./re-routing    # Re-route application traffic from SRC to DST! (your implementation)

# Then cleanup to remove subscription and publication
./drop-sub       # Drop subscription on dst after migration
./drop-pub       # Drop publication on src after migration

Notes

If you’re worried about primary key conflicts when copying sequence numbers, you can advance all sequences forward by some distance when copying, for example +1000. You can use ./copy-seq with a parameter 1000 to achieve this.

You must implement your own ./re-routing script to route your application traffic from src to dst. Because we don’t know how your traffic is routed (e.g., dns, VIP, haproxy, or pgbouncer). Of course, you can also do this manually…

You can implement a ./disable-src script to restrict application access to the src cluster—this is optional: if you can ensure all application traffic is cleanly switched in ./re-routing, you don’t really need this step.

But if you have various access from unknown sources that can’t be cleanly sorted out, it’s better to use more thorough methods: change HBA rules and reload to implement (recommended), or simply stop the postgres, pgbouncer, or haproxy processes on the source primary.

10.10 - Tutorials

Step-by-step guides for common PostgreSQL tasks and scenarios.

This section provides step-by-step tutorials for common PostgreSQL tasks and scenarios.

10.10.1 - HA Drill: Handling 2-of-3 Node Failure

HA scenario response plan: When two of three nodes fail and auto-failover doesn’t work, how to recover from the emergency state?

If a classic 3-node HA deployment experiences simultaneous failure of two nodes (majority), the system typically cannot complete automatic failover and requires manual intervention.

First, assess the status of the other two servers. If they can be brought up quickly, prioritize recovering those two servers. Otherwise, enter the Emergency Recovery Procedure.

The Emergency Recovery Procedure assumes your admin node has failed and only a single regular database node survives. In this case, the fastest recovery process is:

  • Adjust HAProxy configuration to direct traffic to the primary.
  • Stop Patroni and manually promote the PostgreSQL replica to primary.

Adjust HAProxy Configuration

If you access the cluster bypassing HAProxy, you can skip this step. If you access the database cluster through HAProxy, you need to adjust the load balancer configuration to manually direct read/write traffic to the primary.

  • Edit the /etc/haproxy/<pg_cluster>-primary.cfg configuration file, where <pg_cluster> is your PostgreSQL cluster name, e.g., pg-meta.
  • Comment out the health check configuration options to stop health checks.
  • Comment out the other two failed machines in the server list, keeping only the current primary server.
listen pg-meta-primary
    bind *:5433
    mode tcp
    maxconn 5000
    balance roundrobin

    # Comment out the following four health check lines
    #option httpchk                               # <---- remove this
    #option http-keep-alive                       # <---- remove this
    #http-check send meth OPTIONS uri /primary    # <---- remove this
    #http-check expect status 200                 # <---- remove this

    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    server pg-meta-1 10.10.10.10:6432 check port 8008 weight 100

    # Comment out the other two failed machines
    #server pg-meta-2 10.10.10.11:6432 check port 8008 weight 100 <---- comment this
    #server pg-meta-3 10.10.10.12:6432 check port 8008 weight 100 <---- comment this

After adjusting the configuration, don’t rush to execute systemctl reload haproxy to reload. Wait until after promoting the primary, then execute together. The effect of this configuration is that HAProxy will no longer perform primary health checks (which by default use Patroni), but will directly direct write traffic to the current primary.


Manually Promote Replica

Log in to the target server, switch to the dbsu user, execute CHECKPOINT to flush to disk, stop Patroni, restart PostgreSQL, and execute Promote.

sudo su - postgres                     # Switch to database dbsu user
psql -c 'checkpoint; checkpoint;'      # Two Checkpoints to flush dirty pages, avoid long PG restart
sudo systemctl stop patroni            # Stop Patroni
pg-restart                             # Restart PostgreSQL
pg-promote                             # Promote PostgreSQL replica to primary
psql -c 'SELECT pg_is_in_recovery();'  # If result is f, it has been promoted to primary

If you adjusted the HAProxy configuration above, you can now execute systemctl reload haproxy to reload the HAProxy configuration and direct traffic to the new primary.

systemctl reload haproxy                # Reload HAProxy configuration to direct write traffic to current instance

Avoid Split Brain

After emergency recovery, the second priority is: Avoid Split Brain. Users should prevent the other two servers from coming back online and forming a split brain with the current primary, causing data inconsistency.

Simple approaches:

  • Power off/disconnect network the other two servers to ensure they don’t come online uncontrollably.
  • Adjust the database connection string used by applications to point directly to the surviving server’s primary.

Then decide the next steps based on the specific situation:

  • A: The two servers have temporary failures (e.g., network/power outage) and can be repaired in place to continue service.
  • B: The two failed servers have permanent failures (e.g., hardware damage) and will be removed and decommissioned.

Recovery After Temporary Failure

If the other two servers have temporary failures and can be repaired to continue service, follow these steps for repair and rebuild:

  • Handle one failed server at a time, prioritize the admin node / INFRA node.
  • Start the failed server and stop Patroni after startup.

After the ETCD cluster quorum is restored, it will resume work. Then start Patroni on the surviving server (current primary) to take over the existing PostgreSQL and regain cluster leadership. After Patroni starts, enter maintenance mode.

systemctl restart patroni
pg pause <pg_cluster>

On the other two instances, create the touch /pg/data/standby.signal marker file as the postgres user to mark them as replicas, then start Patroni:

systemctl restart patroni

After confirming Patroni cluster identity/roles are correct, exit maintenance mode:

pg resume <pg_cluster>

Recovery After Permanent Failure

After permanent failure, first recover the ~/pigsty directory on the admin node. The key files needed are pigsty.yml and files/pki/ca/ca.key.

If you cannot retrieve or don’t have backups of these two files, you can deploy a new Pigsty and migrate the existing cluster to the new deployment via Backup Cluster.

Please regularly backup the pigsty directory (e.g., using Git for version control). Learn from this and avoid such mistakes in the future.

Configuration Repair

You can use the surviving node as the new admin node, copy the ~/pigsty directory to the new admin node, then start adjusting the configuration. For example, replace the original default admin node 10.10.10.10 with the surviving node 10.10.10.12:

all:
  vars:
    admin_ip: 10.10.10.12               # Use new admin node address
    node_etc_hosts: [10.10.10.12 h.pigsty a.pigsty p.pigsty g.pigsty sss.pigsty]
    infra_portal: {}                    # Also modify other configs referencing old admin IP (10.10.10.10)

  children:

    infra:                              # Adjust Infra cluster
      hosts:
        # 10.10.10.10: { infra_seq: 1 } # Old Infra node
        10.10.10.12: { infra_seq: 3 }   # New Infra node

    etcd:                               # Adjust ETCD cluster
      hosts:
        #10.10.10.10: { etcd_seq: 1 }   # Comment out this failed node
        #10.10.10.11: { etcd_seq: 2 }   # Comment out this failed node
        10.10.10.12: { etcd_seq: 3 }    # Keep surviving node
      vars:
        etcd_cluster: etcd

    pg-meta:                            # Adjust PGSQL cluster configuration
      hosts:
        #10.10.10.10: { pg_seq: 1, pg_role: primary }
        #10.10.10.11: { pg_seq: 2, pg_role: replica }
        #10.10.10.12: { pg_seq: 3, pg_role: replica , pg_offline_query: true }
        10.10.10.12: { pg_seq: 3, pg_role: primary , pg_offline_query: true }
      vars:
        pg_cluster: pg-meta

ETCD Repair

Then execute the following command to reset ETCD to a single-node cluster:

./etcd.yml -e etcd_safeguard=false -e etcd_clean=true

Follow the instructions in ETCD Reload Configuration to adjust ETCD Endpoint references.

INFRA Repair

If the surviving node doesn’t have the INFRA module, configure and install a new INFRA module on the current node. Execute the following command to deploy the INFRA module to the surviving node:

./infra.yml -l 10.10.10.12

Repair monitoring on the current node:

./node.yml -t node_monitor

PGSQL Repair

./pgsql.yml -t pg_conf                            # Regenerate PG configuration files
systemctl reload patroni                          # Reload Patroni configuration on surviving node

After repairing each module, you can follow the standard expansion process to add new nodes to the cluster and restore cluster high availability.

10.10.2 - Bind a L2 VIP to PostgreSQL Primary with VIP-Manager

You can define an OPTIONAL L2 VIP on a PostgreSQL cluster, provided that all nodes in the cluster are in the same L2 network.

This VIP works on Master-Backup mode and always points to the node where the primary instance of the database cluster is located.

This VIP is managed by the VIP-Manager, which reads the Leader Key written by Patroni from DCS (etcd) to determine whether it is the master.


Enable VIP

Define pg_vip_enabled parameter as true in the cluster level to enable the VIP component on the cluster. You can also enable this configuration in the global configuration.

# pgsql 3 node ha cluster: pg-test
pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }   # primary instance, leader of cluster
    10.10.10.12: { pg_seq: 2, pg_role: replica }   # replica instance, follower of leader
    10.10.10.13: { pg_seq: 3, pg_role: replica, pg_offline_query: true } # replica with offline access
  vars:
    pg_cluster: pg-test           # define pgsql cluster name
    pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
    pg_databases: [{ name: test }]

    # Enable L2 VIP
    pg_vip_enabled: true
    pg_vip_address: 10.10.10.3/24
    pg_vip_interface: eth1

Beware that pg_vip_address must be a valid IP address with subnet and available in the current L2 network.

Beware that pg_vip_interface must be a valid network interface name and should be the same as the one using IPv4 address in the inventory.

If the network interface name is different among cluster members, users should explicitly specify the pg_vip_interface parameter for each instance, for example:

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary , pg_vip_interface: eth0  }
    10.10.10.12: { pg_seq: 2, pg_role: replica , pg_vip_interface: eth1  }
    10.10.10.13: { pg_seq: 3, pg_role: replica , pg_vip_interface: ens33 }
  vars:
    pg_cluster: pg-test           # define pgsql cluster name
    pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
    pg_databases: [{ name: test }]

    # Enable L2 VIP
    pg_vip_enabled: true
    pg_vip_address: 10.10.10.3/24
    #pg_vip_interface: eth1

To refresh the VIP configuration and restart the VIP-Manager, use the following command:

./pgsql.yml -t pg_vip

10.10.3 - Citus: Deploy HA Citus Cluster

How to deploy a Citus high-availability distributed cluster?

Citus is a PostgreSQL extension that transforms PostgreSQL into a distributed database, enabling horizontal scaling across multiple nodes to handle large amounts of data and queries.

Patroni v3.0+ provides native high-availability support for Citus, simplifying the setup of Citus clusters. Pigsty also provides native support for this.

Note: The current Citus version (12.1.6) supports PostgreSQL 16, 15, and 14, but not PostgreSQL 17 yet. There is no official ARM64 support. Pigsty extension repo provides Citus ARM64 packages, but use with caution on ARM architecture.


Citus Cluster

Pigsty natively supports Citus. See conf/citus.yml for reference.

Here we use the Pigsty 4-node sandbox to define a Citus cluster pg-citus, which includes a 2-node coordinator cluster pg-citus0 and two Worker clusters pg-citus1 and pg-citus2.

pg-citus:
  hosts:
    10.10.10.10: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.2/24 ,pg_seq: 1, pg_role: primary }
    10.10.10.11: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.2/24 ,pg_seq: 2, pg_role: replica }
    10.10.10.12: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.3/24 ,pg_seq: 1, pg_role: primary }
    10.10.10.13: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.4/24 ,pg_seq: 1, pg_role: primary }
  vars:
    pg_mode: citus                            # pgsql cluster mode: citus
    pg_version: 16                            # citus does not have pg16 available
    pg_shard: pg-citus                        # citus shard name: pg-citus
    pg_primary_db: citus                      # primary database used by citus
    pg_vip_enabled: true                      # enable vip for citus cluster
    pg_vip_interface: eth1                    # vip interface for all members
    pg_dbsu_password: DBUser.Postgres         # all dbsu password access for citus cluster
    pg_extensions: [ citus, postgis, pgvector, topn, pg_cron, hll ]  # install these extensions
    pg_libs: 'citus, pg_cron, pg_stat_statements' # citus will be added by patroni automatically
    pg_users: [{ name: dbuser_citus ,password: DBUser.Citus ,pgbouncer: true ,roles: [ dbrole_admin ]    }]
    pg_databases: [{ name: citus ,owner: dbuser_citus ,extensions: [ citus, vector, topn, pg_cron, hll ] }]
    pg_parameters:
      cron.database_name: citus
      citus.node_conninfo: 'sslmode=require sslrootcert=/pg/cert/ca.crt sslmode=verify-full'
    pg_hba_rules:
      - { user: 'all' ,db: all  ,addr: 127.0.0.1/32  ,auth: ssl   ,title: 'all user ssl access from localhost' }
      - { user: 'all' ,db: all  ,addr: intra         ,auth: ssl   ,title: 'all user ssl access from intranet'  }

Compared to standard PostgreSQL clusters, Citus cluster configuration has some special requirements. First, you need to ensure the Citus extension is downloaded, installed, loaded, and enabled, which involves the following four parameters:

  • repo_packages: Must include the citus extension, or you need to use a PostgreSQL offline package that includes Citus.
  • pg_extensions: Must include the citus extension, i.e., you must install the citus extension on each node.
  • pg_libs: Must include the citus extension at the first position, though Patroni now handles this automatically.
  • pg_databases: Define a primary database that must have the citus extension installed.

Second, you need to ensure the Citus cluster is configured correctly:

  • pg_mode: Must be set to citus to tell Patroni to use Citus mode.
  • pg_primary_db: Must specify the name of the primary database with citus extension, named citus here.
  • pg_shard: Must specify a unified name as the cluster name prefix for all horizontal shard PG clusters, pg-citus here.
  • pg_group: Must specify a shard number, integers starting from zero. 0 represents the coordinator cluster, others are Worker clusters.
  • pg_cluster: Must correspond to the combination of pg_shard and pg_group.
  • pg_dbsu_password: Must be set to a non-empty plaintext password, otherwise Citus will not work properly.
  • pg_parameters: Recommended to set citus.node_conninfo to enforce SSL access and require node-to-node client certificate verification.

After configuration, you can deploy the Citus cluster using pgsql.yml just like a regular PostgreSQL cluster.


Manage Citus Cluster

After defining the Citus cluster, deploy it using the pgsql.yml playbook:

./pgsql.yml -l pg-citus    # Deploy Citus cluster pg-citus

Using any member’s DBSU (postgres) user, you can list the Citus cluster status with patronictl (alias: pg):

$ pg list
+ Citus cluster: pg-citus ----------+---------+-----------+----+-----------+--------------------+
| Group | Member      | Host        | Role    | State     | TL | Lag in MB | Tags               |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
|     0 | pg-citus0-1 | 10.10.10.10 | Leader  | running   |  1 |           | clonefrom: true    |
|       |             |             |         |           |    |           | conf: tiny.yml     |
|       |             |             |         |           |    |           | spec: 20C.40G.125G |
|       |             |             |         |           |    |           | version: '16'      |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
|     1 | pg-citus1-1 | 10.10.10.11 | Leader  | running   |  1 |           | clonefrom: true    |
|       |             |             |         |           |    |           | conf: tiny.yml     |
|       |             |             |         |           |    |           | spec: 10C.20G.125G |
|       |             |             |         |           |    |           | version: '16'      |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
|     2 | pg-citus2-1 | 10.10.10.12 | Leader  | running   |  1 |           | clonefrom: true    |
|       |             |             |         |           |    |           | conf: tiny.yml     |
|       |             |             |         |           |    |           | spec: 10C.20G.125G |
|       |             |             |         |           |    |           | version: '16'      |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
|     2 | pg-citus2-2 | 10.10.10.13 | Replica | streaming |  1 |         0 | clonefrom: true    |
|       |             |             |         |           |    |           | conf: tiny.yml     |
|       |             |             |         |           |    |           | spec: 10C.20G.125G |
|       |             |             |         |           |    |           | version: '16'      |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+

You can treat each horizontal shard cluster as an independent PGSQL cluster and manage them with the pg (patronictl) command. Note that when using the pg command to manage Citus clusters, you need to use the --group parameter to specify the cluster shard number:

pg list pg-citus --group 0   # Use --group 0 to specify cluster shard number

Citus has a system table called pg_dist_node that records Citus cluster node information. Patroni automatically maintains this table.

PGURL=postgres://postgres:[email protected]/citus

psql $PGURL -c 'SELECT * FROM pg_dist_node;'       # View node information
 nodeid | groupid |  nodename   | nodeport | noderack | hasmetadata | isactive | noderole  | nodecluster | metadatasynced | shouldhaveshards
--------+---------+-------------+----------+----------+-------------+----------+-----------+-------------+----------------+------------------
      1 |       0 | 10.10.10.10 |     5432 | default  | t           | t        | primary   | default     | t              | f
      4 |       1 | 10.10.10.12 |     5432 | default  | t           | t        | primary   | default     | t              | t
      5 |       2 | 10.10.10.13 |     5432 | default  | t           | t        | primary   | default     | t              | t
      6 |       0 | 10.10.10.11 |     5432 | default  | t           | t        | secondary | default     | t              | f

You can also view user authentication information (superuser access only):

$ psql $PGURL -c 'SELECT * FROM pg_dist_authinfo;'   # View node auth info (superuser only)

Then you can use a regular business user (e.g., dbuser_citus with DDL privileges) to access the Citus cluster:

psql postgres://dbuser_citus:[email protected]/citus -c 'SELECT * FROM pg_dist_node;'

Using Citus Cluster

When using Citus clusters, we strongly recommend reading the Citus official documentation to understand its architecture and core concepts.

The key is understanding the five types of tables in Citus and their characteristics and use cases:

  • Distributed Table
  • Reference Table
  • Local Table
  • Local Management Table
  • Schema Table

On the coordinator node, you can create distributed tables and reference tables and query them from any data node. Since 11.2, any Citus database node can act as a coordinator.

We can use pgbench to create some tables and distribute the main table (pgbench_accounts) across nodes, then use other small tables as reference tables:

PGURL=postgres://dbuser_citus:[email protected]/citus
pgbench -i $PGURL

psql $PGURL <<-EOF
SELECT create_distributed_table('pgbench_accounts', 'aid'); SELECT truncate_local_data_after_distributing_table('public.pgbench_accounts');
SELECT create_reference_table('pgbench_branches')         ; SELECT truncate_local_data_after_distributing_table('public.pgbench_branches');
SELECT create_reference_table('pgbench_history')          ; SELECT truncate_local_data_after_distributing_table('public.pgbench_history');
SELECT create_reference_table('pgbench_tellers')          ; SELECT truncate_local_data_after_distributing_table('public.pgbench_tellers');
EOF

Run read/write tests:

pgbench -nv -P1 -c10 -T500 postgres://dbuser_citus:[email protected]/citus      # Direct connect to coordinator port 5432
pgbench -nv -P1 -c10 -T500 postgres://dbuser_citus:[email protected]:6432/citus # Through connection pool, reduce client connection pressure
pgbench -nv -P1 -c10 -T500 postgres://dbuser_citus:[email protected]/citus      # Any primary node can act as coordinator
pgbench --select-only -nv -P1 -c10 -T500 postgres://dbuser_citus:[email protected]/citus # Read-only queries

Production Deployment

For production use of Citus, you typically need to set up streaming replication physical replicas for the Coordinator and each Worker cluster.

For example, simu.yml defines a 10-node Citus cluster:

pg-citus: # citus group
  hosts:
    10.10.10.50: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.60/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.51: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.60/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.52: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.61/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.53: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.61/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.54: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.62/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.55: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.62/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.56: { pg_group: 3, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.63/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.57: { pg_group: 3, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.63/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.58: { pg_group: 4, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.64/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.59: { pg_group: 4, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.64/24 ,pg_seq: 1, pg_role: replica }
  vars:
    pg_mode: citus                            # pgsql cluster mode: citus
    pg_version: 16                            # citus does not have pg16 available
    pg_shard: pg-citus                        # citus shard name: pg-citus
    pg_primary_db: citus                      # primary database used by citus
    pg_vip_enabled: true                      # enable vip for citus cluster
    pg_vip_interface: eth1                    # vip interface for all members
    pg_dbsu_password: DBUser.Postgres         # enable dbsu password access for citus
    pg_extensions: [ citus, postgis, pgvector, topn, pg_cron, hll ]  # install these extensions
    pg_libs: 'citus, pg_cron, pg_stat_statements' # citus will be added by patroni automatically
    pg_users: [{ name: dbuser_citus ,password: DBUser.Citus ,pgbouncer: true ,roles: [ dbrole_admin ]    }]
    pg_databases: [{ name: citus ,owner: dbuser_citus ,extensions: [ citus, vector, topn, pg_cron, hll ] }]
    pg_parameters:
      cron.database_name: citus
      citus.node_conninfo: 'sslrootcert=/pg/cert/ca.crt sslmode=verify-full'
    pg_hba_rules:
      - { user: 'all' ,db: all  ,addr: 127.0.0.1/32  ,auth: ssl   ,title: 'all user ssl access from localhost' }
      - { user: 'all' ,db: all  ,addr: intra         ,auth: ssl   ,title: 'all user ssl access from intranet'  }

We will cover a series of advanced Citus topics in subsequent tutorials:

  • Read/write separation
  • Failure handling
  • Consistent backup and recovery
  • Advanced monitoring and diagnostics
  • Connection pooling

10.11 - Reference

Parameters and reference documentation

10.12 - Monitoring

Overview of Pigsty’s monitoring system architecture and how to monitor existing PostgreSQL instances

This document introduces Pigsty’s monitoring system architecture, including metrics, logs, and target management. It also covers how to monitor existing PG clusters and remote RDS services.


Monitoring Overview

Pigsty uses a modern observability stack for PostgreSQL monitoring:

  • Grafana for metrics visualization and PostgreSQL datasource
  • VictoriaMetrics for collecting metrics from PostgreSQL / Pgbouncer / Patroni / HAProxy / Node
  • VictoriaLogs for logging PostgreSQL / Pgbouncer / Patroni / pgBackRest and host component logs
  • Battery-included Grafana dashboards showcasing all aspects of PostgreSQL

Metrics

PostgreSQL monitoring metrics are fully defined by the pg_exporter configuration file: pg_exporter.yml They are further processed by Prometheus recording rules and alert rules: files/prometheus/rules/pgsql.yml.

Pigsty uses three identity labels: cls, ins, ip, which are attached to all metrics and logs. Additionally, metrics from Pgbouncer, host nodes (NODE), and load balancers are also used by Pigsty, with the same labels used whenever possible for correlation analysis.

{ cls: pg-meta, ins: pg-meta-1, ip: 10.10.10.10 }
{ cls: pg-meta, ins: pg-test-1, ip: 10.10.10.11 }
{ cls: pg-meta, ins: pg-test-2, ip: 10.10.10.12 }
{ cls: pg-meta, ins: pg-test-3, ip: 10.10.10.13 }

Logs

PostgreSQL-related logs are collected by Vector and sent to the VictoriaLogs log storage/query service on infra nodes.

Target Management

Prometheus monitoring targets are defined in static files under /etc/prometheus/targets/pgsql/, with each instance having a corresponding file. Taking pg-meta-1 as an example:

# pg-meta-1 [primary] @ 10.10.10.10
- labels: { cls: pg-meta, ins: pg-meta-1, ip: 10.10.10.10 }
  targets:
    - 10.10.10.10:9630    # <--- pg_exporter for PostgreSQL metrics
    - 10.10.10.10:9631    # <--- pg_exporter for pgbouncer metrics
    - 10.10.10.10:8008    # <--- patroni metrics (when API SSL is not enabled)

When the global flag patroni_ssl_enabled is set, patroni targets will be moved to a separate file /etc/prometheus/targets/patroni/<ins>.yml, as it uses the https scrape endpoint. When monitoring RDS instances, monitoring targets are placed separately in the /etc/prometheus/targets/pgrds/ directory and managed by cluster.

When removing a cluster using bin/pgsql-rm or pgsql-rm.yml, the Prometheus monitoring targets will be removed. You can also remove them manually or use subtasks from the playbook:

bin/pgmon-rm <cls|ins>    # Remove prometheus monitoring targets from all infra nodes

Remote RDS monitoring targets are placed in /etc/prometheus/targets/pgrds/<cls>.yml, created by the pgsql-monitor.yml playbook or bin/pgmon-add script.


Monitoring Modes

Pigsty provides three monitoring modes to suit different monitoring needs.

Item \ LevelL1L2L3
NameBasicManagedStandard
AbbrRDSMANAGEDFULL
ScenarioConnection string only, e.g., RDSExisting DB, nodes manageableInstances created by Pigsty
PGCAT Features✅ Fully Available✅ Fully Available✅ Fully Available
PGSQL Features✅ PG metrics only✅ PG & node metrics only✅ Full Features
Connection Pool Metrics❌ Not Available⚠️ Optional✅ Pre-installed
Load Balancer Metrics❌ Not Available⚠️ Optional✅ Pre-installed
PGLOG Features❌ Not Available⚠️ Optional✅ Pre-installed
PG Exporter⚠️ On infra nodes✅ On DB nodes✅ On DB nodes
Node Exporter❌ Not deployed✅ On DB nodes✅ On DB nodes
Intrusiveness✅ Non-intrusive⚠️ Install Exporter⚠️ Fully managed by Pigsty
Monitor Existing Instances✅ Supported✅ Supported❌ For Pigsty-managed only
Monitoring Users & ViewsManual setupManual setupAuto-created by Pigsty
Deployment Playbookbin/pgmon-add <cls>Partial pgsql.yml/node.ymlpgsql.yml
Required PermissionsConnectable PGURL from infraSSH & sudo on DB nodesSSH & sudo on DB nodes
Feature SummaryPGCAT + PGRDSMost featuresFull features

Databases fully managed by Pigsty are automatically monitored with the best support and typically require no configuration. For existing PostgreSQL clusters or RDS services, if the target DB nodes can be managed by Pigsty (ssh accessible, sudo available), you can consider managed deployment for a monitoring experience similar to native Pigsty. If you can only access the target database via PGURL (database connection string), such as remote RDS services, you can use basic mode to monitor the target database.


Monitor Existing Cluster

If the target DB nodes can be managed by Pigsty (ssh accessible and sudo available), you can use the pg_exporter task in the pgsql.yml playbook to deploy monitoring components (PG Exporter) on target nodes in the same way as standard deployments. You can also use the pgbouncer and pgbouncer_exporter tasks from that playbook to deploy connection pools and their monitoring on existing instance nodes. Additionally, you can use node_exporter, haproxy, and vector from node.yml to deploy host monitoring, load balancing, and log collection components, achieving an experience identical to native Pigsty database instances.

The definition method for existing clusters is exactly the same as for clusters managed by Pigsty. You selectively execute partial tasks from the pgsql.yml playbook instead of running the entire playbook.

./node.yml  -l <cls> -t node_repo,node_pkg           # Add YUM repos from INFRA nodes and install packages on host nodes
./node.yml  -l <cls> -t node_exporter,node_register  # Configure host monitoring and add to VictoriaMetrics
./node.yml  -l <cls> -t vector                       # Configure host log collection and send to VictoriaLogs
./pgsql.yml -l <cls> -t pg_exporter,pg_register      # Configure PostgreSQL monitoring and register with VictoriaMetrics/Grafana

Since the target database cluster already exists, you need to manually create monitoring users, schemas, and extensions on the target database cluster.


Monitor RDS

If you can only access the target database via PGURL (database connection string), you can configure according to the instructions here. In this mode, Pigsty deploys corresponding PG Exporters on INFRA nodes to scrape remote database metrics, as shown below:

------ infra ------
|                 |
|   prometheus    |            v---- pg-foo-1 ----v
|       ^         |  metrics   |         ^        |
|   pg_exporter <-|------------|----  postgres    |
|   (port: 20001) |            | 10.10.10.10:5432 |
|       ^         |            ^------------------^
|       ^         |                      ^
|       ^         |            v---- pg-foo-2 ----v
|       ^         |  metrics   |         ^        |
|   pg_exporter <-|------------|----  postgres    |
|   (port: 20002) |            | 10.10.10.11:5433 |
-------------------            ^------------------^

In this mode, the monitoring system will not have metrics from hosts, connection pools, load balancers, or high availability components, but the database itself and real-time status information from the data catalog are still available. Pigsty provides two dedicated monitoring dashboards focused on PostgreSQL metrics: PGRDS Cluster and PGRDS Instance, while overview and database-level monitoring reuses existing dashboards. Since Pigsty cannot manage your RDS, users need to configure monitoring objects on the target database in advance.

Here we use the sandbox environment as an example: suppose the pg-meta cluster is an RDS instance pg-foo-1 to be monitored, and the pg-test cluster is an RDS cluster pg-bar to be monitored:

  1. Create monitoring schemas, users, and permissions on the target. Refer to Monitor Setup for details

  2. Declare the cluster in the configuration inventory. For example, if we want to monitor “remote” pg-meta & pg-test clusters:

    infra:            # Infra cluster for proxies, monitoring, alerts, etc.
      hosts: { 10.10.10.10: { infra_seq: 1 } }
      vars:           # Install pg_exporter on group 'infra' for remote postgres RDS
        pg_exporters: # List all remote instances here, assign a unique unused local port for k
          20001: { pg_cluster: pg-foo, pg_seq: 1, pg_host: 10.10.10.10 , pg_databases: [{ name: meta }] } # Register meta database as Grafana datasource
    
          20002: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.11 , pg_port: 5432 } # Different connection string methods
          20003: { pg_cluster: pg-bar, pg_seq: 2, pg_host: 10.10.10.12 , pg_exporter_url: 'postgres://dbuser_monitor:[email protected]:5432/postgres?sslmode=disable'}
          20004: { pg_cluster: pg-bar, pg_seq: 3, pg_host: 10.10.10.13 , pg_monitor_username: dbuser_monitor, pg_monitor_password: DBUser.Monitor }
    

    Databases listed in the pg_databases field will be registered in Grafana as PostgreSQL datasources, providing data support for PGCAT monitoring dashboards. If you don’t want to use PGCAT and register databases in Grafana, simply set pg_databases to an empty array or leave it blank.

    pigsty-monitor.jpg

  3. Execute the add monitoring command: bin/pgmon-add <clsname>

    bin/pgmon-add pg-foo  # Bring pg-foo cluster into monitoring
    bin/pgmon-add pg-bar  # Bring pg-bar cluster into monitoring
    
  4. To remove remote cluster monitoring targets, use bin/pgmon-rm <clsname>

    bin/pgmon-rm pg-foo  # Remove pg-foo from Pigsty monitoring
    bin/pgmon-rm pg-bar  # Remove pg-bar from Pigsty monitoring
    

You can use more parameters to override default pg_exporter options. Here’s an example configuration for monitoring Aliyun RDS for PostgreSQL and PolarDB with Pigsty:

Example: Monitoring Aliyun RDS for PostgreSQL and PolarDB

For details, refer to: remote.yml

infra:            # Infra cluster for proxies, monitoring, alerts, etc.
  hosts: { 10.10.10.10: { infra_seq: 1 } }
  vars:
    pg_exporters:   # List all remote RDS PG instances to be monitored here

      20001:        # Assign a unique unused local port for local monitoring agent, this is a PolarDB primary
        pg_cluster: pg-polar                  # RDS cluster name (identity parameter, manually assigned name in monitoring system)
        pg_seq: 1                             # RDS instance number (identity parameter, manually assigned name in monitoring system)
        pg_host: pc-2ze379wb1d4irc18x.polardbpg.rds.aliyuncs.com # RDS host address
        pg_port: 1921                         # RDS port (from console connection info)
        pg_exporter_auto_discovery: true      # Disable new database auto-discovery feature
        pg_exporter_include_database: 'test'  # Only monitor databases in this list (comma-separated)
        pg_monitor_username: dbuser_monitor   # Monitoring username, overrides global config
        pg_monitor_password: DBUser_Monitor   # Monitoring password, overrides global config
        pg_databases: [{ name: test }]        # List of databases to enable PGCAT for, only name field needed, set register_datasource to false to not register

      20002:       # This is a PolarDB standby
        pg_cluster: pg-polar                  # RDS cluster name (identity parameter, manually assigned name in monitoring system)
        pg_seq: 2                             # RDS instance number (identity parameter, manually assigned name in monitoring system)
        pg_host: pe-2ze7tg620e317ufj4.polarpgmxs.rds.aliyuncs.com # RDS host address
        pg_port: 1521                         # RDS port (from console connection info)
        pg_exporter_auto_discovery: true      # Disable new database auto-discovery feature
        pg_exporter_include_database: 'test,postgres'  # Only monitor databases in this list (comma-separated)
        pg_monitor_username: dbuser_monitor   # Monitoring username
        pg_monitor_password: DBUser_Monitor   # Monitoring password
        pg_databases: [ { name: test } ]        # List of databases to enable PGCAT for, only name field needed, set register_datasource to false to not register

      20004: # This is a basic single-node RDS for PostgreSQL instance
        pg_cluster: pg-rds                    # RDS cluster name (identity parameter, manually assigned name in monitoring system)
        pg_seq: 1                             # RDS instance number (identity parameter, manually assigned name in monitoring system)
        pg_host: pgm-2zern3d323fe9ewk.pg.rds.aliyuncs.com  # RDS host address
        pg_port: 5432                         # RDS port (from console connection info)
        pg_exporter_auto_discovery: true      # Disable new database auto-discovery feature
        pg_exporter_include_database: 'rds'   # Only monitor databases in this list (comma-separated)
        pg_monitor_username: dbuser_monitor   # Monitoring username
        pg_monitor_password: DBUser_Monitor   # Monitoring password
        pg_databases: [ { name: rds } ]       # List of databases to enable PGCAT for, only name field needed, set register_datasource to false to not register

      20005: # This is a high-availability RDS for PostgreSQL cluster primary
        pg_cluster: pg-rdsha                  # RDS cluster name (identity parameter, manually assigned name in monitoring system)
        pg_seq: 1                             # RDS instance number (identity parameter, manually assigned name in monitoring system)
        pg_host: pgm-2ze3d35d27bq08wu.pg.rds.aliyuncs.com  # RDS host address
        pg_port: 5432                         # RDS port (from console connection info)
        pg_exporter_include_database: 'rds'   # Only monitor databases in this list (comma-separated)
        pg_databases: [ { name: rds }, {name : test} ]  # Include these two databases in PGCAT management, register as Grafana datasources

      20006: # This is a high-availability RDS for PostgreSQL cluster read-only instance (standby)
        pg_cluster: pg-rdsha                  # RDS cluster name (identity parameter, manually assigned name in monitoring system)
        pg_seq: 2                             # RDS instance number (identity parameter, manually assigned name in monitoring system)
        pg_host: pgr-2zexqxalk7d37edt.pg.rds.aliyuncs.com  # RDS host address
        pg_port: 5432                         # RDS port (from console connection info)
        pg_exporter_include_database: 'rds'   # Only monitor databases in this list (comma-separated)
        pg_databases: [ { name: rds }, {name : test} ]  # Include these two databases in PGCAT management, register as Grafana datasources

Monitor Setup

When you want to monitor existing instances, whether RDS or self-built PostgreSQL instances, you need to configure the target database so that Pigsty can access them.

To monitor an external existing PostgreSQL instance, you need a connection string that can access that instance/cluster. Any accessible connection string (business user, superuser) can be used, but we recommend using a dedicated monitoring user to avoid permission leaks.

  • Monitor User: The default username is dbuser_monitor, which should belong to the pg_monitor role group or have access to relevant views
  • Monitor Authentication: Default password authentication is used; ensure HBA policies allow the monitoring user to access databases from the admin node or DB node locally
  • Monitor Schema: Fixed schema name monitor is used for installing additional monitoring views and extension plugins; optional but recommended
  • Monitor Extension: Strongly recommended to enable the built-in monitoring extension pg_stat_statements
  • Monitor Views: Monitoring views are optional but can provide additional metric support

Monitor User

Using the default monitoring user dbuser_monitor as an example, create the following user on the target database cluster.

CREATE USER dbuser_monitor;                                       -- Create monitoring user
COMMENT ON ROLE dbuser_monitor IS 'system monitor user';          -- Comment on monitoring user
GRANT pg_monitor TO dbuser_monitor;                               -- Grant pg_monitor privilege to monitoring user, otherwise some metrics cannot be collected

ALTER USER dbuser_monitor PASSWORD 'DBUser.Monitor';              -- Modify monitoring user password as needed (strongly recommended! but keep consistent with Pigsty config)
ALTER USER dbuser_monitor SET log_min_duration_statement = 1000;  -- Recommended to avoid logs filling up with monitoring slow queries
ALTER USER dbuser_monitor SET search_path = monitor,public;       -- Recommended to ensure pg_stat_statements extension works properly

Please note that the monitoring user and password created here should be consistent with pg_monitor_username and pg_monitor_password.


Monitor Authentication

Configure the database pg_hba.conf file, adding the following rules to allow the monitoring user to access all databases from localhost and the admin machine using password authentication.

# allow local role monitor with password
local   all  dbuser_monitor                    md5
host    all  dbuser_monitor  127.0.0.1/32      md5
host    all  dbuser_monitor  <admin_machine_IP>/32 md5

If your RDS doesn’t support defining HBA, simply whitelist the internal IP address of the machine running Pigsty.


Monitor Schema

The monitoring schema is optional; even without it, the main functionality of Pigsty’s monitoring system can work properly, but we strongly recommend creating this schema.

CREATE SCHEMA IF NOT EXISTS monitor;               -- Create dedicated monitoring schema
GRANT USAGE ON SCHEMA monitor TO dbuser_monitor;   -- Allow monitoring user to use it

Monitor Extension

The monitoring extension is optional, but we strongly recommend enabling the pg_stat_statements extension, which provides important data about query performance.

Note: This extension must be listed in the database parameter shared_preload_libraries to take effect, and modifying that parameter requires a database restart.

CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" WITH SCHEMA "monitor";

Please note that you should install this extension in the default admin database postgres. Sometimes RDS doesn’t allow you to create a monitoring schema in the postgres database. In such cases, you can install the pg_stat_statements plugin in the default public schema, as long as you ensure the monitoring user’s search_path is configured as above so it can find the pg_stat_statements view.

CREATE EXTENSION IF NOT EXISTS "pg_stat_statements";
ALTER USER dbuser_monitor SET search_path = monitor,public; -- Recommended to ensure pg_stat_statements extension works properly

Monitor Views

Monitoring views provide several commonly used pre-processed results and encapsulate permissions for monitoring metrics that require high privileges (such as shared memory allocation), making them convenient for querying and use. Strongly recommended to create in all databases requiring monitoring.

Monitoring schema and monitoring view definitions
----------------------------------------------------------------------
-- Table bloat estimate : monitor.pg_table_bloat
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_table_bloat CASCADE;
CREATE OR REPLACE VIEW monitor.pg_table_bloat AS
SELECT CURRENT_CATALOG AS datname, nspname, relname , tblid , bs * tblpages AS size,
       CASE WHEN tblpages - est_tblpages_ff > 0 THEN (tblpages - est_tblpages_ff)/tblpages::FLOAT ELSE 0 END AS ratio
FROM (
         SELECT ceil( reltuples / ( (bs-page_hdr)*fillfactor/(tpl_size*100) ) ) + ceil( toasttuples / 4 ) AS est_tblpages_ff,
                tblpages, fillfactor, bs, tblid, nspname, relname, is_na
         FROM (
                  SELECT
                      ( 4 + tpl_hdr_size + tpl_data_size + (2 * ma)
                          - CASE WHEN tpl_hdr_size % ma = 0 THEN ma ELSE tpl_hdr_size % ma END
                          - CASE WHEN ceil(tpl_data_size)::INT % ma = 0 THEN ma ELSE ceil(tpl_data_size)::INT % ma END
                          ) AS tpl_size, (heappages + toastpages) AS tblpages, heappages,
                      toastpages, reltuples, toasttuples, bs, page_hdr, tblid, nspname, relname, fillfactor, is_na
                  FROM (
                           SELECT
                               tbl.oid AS tblid, ns.nspname , tbl.relname, tbl.reltuples,
                               tbl.relpages AS heappages, coalesce(toast.relpages, 0) AS toastpages,
                               coalesce(toast.reltuples, 0) AS toasttuples,
                               coalesce(substring(array_to_string(tbl.reloptions, ' ') FROM 'fillfactor=([0-9]+)')::smallint, 100) AS fillfactor,
                               current_setting('block_size')::numeric AS bs,
                               CASE WHEN version()~'mingw32' OR version()~'64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END AS ma,
                               24 AS page_hdr,
                               23 + CASE WHEN MAX(coalesce(s.null_frac,0)) > 0 THEN ( 7 + count(s.attname) ) / 8 ELSE 0::int END
                                   + CASE WHEN bool_or(att.attname = 'oid' and att.attnum < 0) THEN 4 ELSE 0 END AS tpl_hdr_size,
                               sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 0) ) AS tpl_data_size,
                               bool_or(att.atttypid = 'pg_catalog.name'::regtype)
                                   OR sum(CASE WHEN att.attnum > 0 THEN 1 ELSE 0 END) <> count(s.attname) AS is_na
                           FROM pg_attribute AS att
                                    JOIN pg_class AS tbl ON att.attrelid = tbl.oid
                                    JOIN pg_namespace AS ns ON ns.oid = tbl.relnamespace
                                    LEFT JOIN pg_stats AS s ON s.schemaname=ns.nspname AND s.tablename = tbl.relname AND s.inherited=false AND s.attname=att.attname
                                    LEFT JOIN pg_class AS toast ON tbl.reltoastrelid = toast.oid
                           WHERE NOT att.attisdropped AND tbl.relkind = 'r' AND nspname NOT IN ('pg_catalog','information_schema')
                           GROUP BY 1,2,3,4,5,6,7,8,9,10
                       ) AS s
              ) AS s2
     ) AS s3
WHERE NOT is_na;
COMMENT ON VIEW monitor.pg_table_bloat IS 'postgres table bloat estimate';

GRANT SELECT ON monitor.pg_table_bloat TO pg_monitor;

----------------------------------------------------------------------
-- Index bloat estimate : monitor.pg_index_bloat
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_index_bloat CASCADE;
CREATE OR REPLACE VIEW monitor.pg_index_bloat AS
SELECT CURRENT_CATALOG AS datname, nspname, idxname AS relname, tblid, idxid, relpages::BIGINT * bs AS size,
       COALESCE((relpages - ( reltuples * (6 + ma - (CASE WHEN index_tuple_hdr % ma = 0 THEN ma ELSE index_tuple_hdr % ma END)
                                               + nulldatawidth + ma - (CASE WHEN nulldatawidth % ma = 0 THEN ma ELSE nulldatawidth % ma END))
                                  / (bs - pagehdr)::FLOAT  + 1 )), 0) / relpages::FLOAT AS ratio
FROM (
         SELECT nspname,idxname,indrelid AS tblid,indexrelid AS idxid,
                reltuples,relpages,
                current_setting('block_size')::INTEGER                                                               AS bs,
                (CASE WHEN version() ~ 'mingw32' OR version() ~ '64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END)  AS ma,
                24                                                                                                   AS pagehdr,
                (CASE WHEN max(COALESCE(pg_stats.null_frac, 0)) = 0 THEN 2 ELSE 6 END)                               AS index_tuple_hdr,
                sum((1.0 - COALESCE(pg_stats.null_frac, 0.0)) *
                    COALESCE(pg_stats.avg_width, 1024))::INTEGER                                                     AS nulldatawidth
         FROM pg_attribute
                  JOIN (
             SELECT pg_namespace.nspname,
                    ic.relname                                                   AS idxname,
                    ic.reltuples,
                    ic.relpages,
                    pg_index.indrelid,
                    pg_index.indexrelid,
                    tc.relname                                                   AS tablename,
                    regexp_split_to_table(pg_index.indkey::TEXT, ' ') :: INTEGER AS attnum,
                    pg_index.indexrelid                                          AS index_oid
             FROM pg_index
                      JOIN pg_class ic ON pg_index.indexrelid = ic.oid
                      JOIN pg_class tc ON pg_index.indrelid = tc.oid
                      JOIN pg_namespace ON pg_namespace.oid = ic.relnamespace
                      JOIN pg_am ON ic.relam = pg_am.oid
             WHERE pg_am.amname = 'btree' AND ic.relpages > 0 AND nspname NOT IN ('pg_catalog', 'information_schema')
         ) ind_atts ON pg_attribute.attrelid = ind_atts.indexrelid AND pg_attribute.attnum = ind_atts.attnum
                  JOIN pg_stats ON pg_stats.schemaname = ind_atts.nspname
             AND ((pg_stats.tablename = ind_atts.tablename AND pg_stats.attname = pg_get_indexdef(pg_attribute.attrelid, pg_attribute.attnum, TRUE))
                 OR (pg_stats.tablename = ind_atts.idxname AND pg_stats.attname = pg_attribute.attname))
         WHERE pg_attribute.attnum > 0
         GROUP BY 1, 2, 3, 4, 5, 6
     ) est;
COMMENT ON VIEW monitor.pg_index_bloat IS 'postgres index bloat estimate (btree-only)';

GRANT SELECT ON monitor.pg_index_bloat TO pg_monitor;

----------------------------------------------------------------------
-- Relation Bloat : monitor.pg_bloat
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_bloat CASCADE;
CREATE OR REPLACE VIEW monitor.pg_bloat AS
SELECT coalesce(ib.datname, tb.datname)                                                   AS datname,
       coalesce(ib.nspname, tb.nspname)                                                   AS nspname,
       coalesce(ib.tblid, tb.tblid)                                                       AS tblid,
       coalesce(tb.nspname || '.' || tb.relname, ib.nspname || '.' || ib.tblid::RegClass) AS tblname,
       tb.size                                                                            AS tbl_size,
       CASE WHEN tb.ratio < 0 THEN 0 ELSE round(tb.ratio::NUMERIC, 6) END                 AS tbl_ratio,
       (tb.size * (CASE WHEN tb.ratio < 0 THEN 0 ELSE tb.ratio::NUMERIC END)) ::BIGINT    AS tbl_wasted,
       ib.idxid,
       ib.nspname || '.' || ib.relname                                                    AS idxname,
       ib.size                                                                            AS idx_size,
       CASE WHEN ib.ratio < 0 THEN 0 ELSE round(ib.ratio::NUMERIC, 5) END                 AS idx_ratio,
       (ib.size * (CASE WHEN ib.ratio < 0 THEN 0 ELSE ib.ratio::NUMERIC END)) ::BIGINT    AS idx_wasted
FROM monitor.pg_index_bloat ib
         FULL OUTER JOIN monitor.pg_table_bloat tb ON ib.tblid = tb.tblid;

COMMENT ON VIEW monitor.pg_bloat IS 'postgres relation bloat detail';
GRANT SELECT ON monitor.pg_bloat TO pg_monitor;

----------------------------------------------------------------------
-- monitor.pg_index_bloat_human
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_index_bloat_human CASCADE;
CREATE OR REPLACE VIEW monitor.pg_index_bloat_human AS
SELECT idxname                            AS name,
       tblname,
       idx_wasted                         AS wasted,
       pg_size_pretty(idx_size)           AS idx_size,
       round(100 * idx_ratio::NUMERIC, 2) AS idx_ratio,
       pg_size_pretty(idx_wasted)         AS idx_wasted,
       pg_size_pretty(tbl_size)           AS tbl_size,
       round(100 * tbl_ratio::NUMERIC, 2) AS tbl_ratio,
       pg_size_pretty(tbl_wasted)         AS tbl_wasted
FROM monitor.pg_bloat
WHERE idxname IS NOT NULL;
COMMENT ON VIEW monitor.pg_index_bloat_human IS 'postgres index bloat info in human-readable format';
GRANT SELECT ON monitor.pg_index_bloat_human TO pg_monitor;


----------------------------------------------------------------------
-- monitor.pg_table_bloat_human
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_table_bloat_human CASCADE;
CREATE OR REPLACE VIEW monitor.pg_table_bloat_human AS
SELECT tblname                                          AS name,
       idx_wasted + tbl_wasted                          AS wasted,
       pg_size_pretty(idx_wasted + tbl_wasted)          AS all_wasted,
       pg_size_pretty(tbl_wasted)                       AS tbl_wasted,
       pg_size_pretty(tbl_size)                         AS tbl_size,
       tbl_ratio,
       pg_size_pretty(idx_wasted)                       AS idx_wasted,
       pg_size_pretty(idx_size)                         AS idx_size,
       round(idx_wasted::NUMERIC * 100.0 / idx_size, 2) AS idx_ratio
FROM (SELECT datname,
             nspname,
             tblname,
             coalesce(max(tbl_wasted), 0)                         AS tbl_wasted,
             coalesce(max(tbl_size), 1)                           AS tbl_size,
             round(100 * coalesce(max(tbl_ratio), 0)::NUMERIC, 2) AS tbl_ratio,
             coalesce(sum(idx_wasted), 0)                         AS idx_wasted,
             coalesce(sum(idx_size), 1)                           AS idx_size
      FROM monitor.pg_bloat
      WHERE tblname IS NOT NULL
      GROUP BY 1, 2, 3
     ) d;
COMMENT ON VIEW monitor.pg_table_bloat_human IS 'postgres table bloat info in human-readable format';
GRANT SELECT ON monitor.pg_table_bloat_human TO pg_monitor;


----------------------------------------------------------------------
-- Activity Overview: monitor.pg_session
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_session CASCADE;
CREATE OR REPLACE VIEW monitor.pg_session AS
SELECT coalesce(datname, 'all') AS datname, numbackends, active, idle, ixact, max_duration, max_tx_duration, max_conn_duration
FROM (
         SELECT datname,
                count(*)                                         AS numbackends,
                count(*) FILTER ( WHERE state = 'active' )       AS active,
                count(*) FILTER ( WHERE state = 'idle' )         AS idle,
                count(*) FILTER ( WHERE state = 'idle in transaction'
                    OR state = 'idle in transaction (aborted)' ) AS ixact,
                max(extract(epoch from now() - state_change))
                FILTER ( WHERE state = 'active' )                AS max_duration,
                max(extract(epoch from now() - xact_start))      AS max_tx_duration,
                max(extract(epoch from now() - backend_start))   AS max_conn_duration
         FROM pg_stat_activity
         WHERE backend_type = 'client backend'
           AND pid <> pg_backend_pid()
         GROUP BY ROLLUP (1)
         ORDER BY 1 NULLS FIRST
     ) t;
COMMENT ON VIEW monitor.pg_session IS 'postgres activity group by session';
GRANT SELECT ON monitor.pg_session TO pg_monitor;


----------------------------------------------------------------------
-- Sequential Scan: monitor.pg_seq_scan
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_seq_scan CASCADE;
CREATE OR REPLACE VIEW monitor.pg_seq_scan AS
SELECT schemaname                                                        AS nspname,
       relname,
       seq_scan,
       seq_tup_read,
       seq_tup_read / seq_scan                                           AS seq_tup_avg,
       idx_scan,
       n_live_tup + n_dead_tup                                           AS tuples,
       round(n_live_tup * 100.0::NUMERIC / (n_live_tup + n_dead_tup), 2) AS live_ratio
FROM pg_stat_user_tables
WHERE seq_scan > 0
  and (n_live_tup + n_dead_tup) > 0
ORDER BY seq_scan DESC;
COMMENT ON VIEW monitor.pg_seq_scan IS 'table that have seq scan';
GRANT SELECT ON monitor.pg_seq_scan TO pg_monitor;
Function for viewing shared memory allocation (PG13 and above)
DROP FUNCTION IF EXISTS monitor.pg_shmem() CASCADE;
CREATE OR REPLACE FUNCTION monitor.pg_shmem() RETURNS SETOF
    pg_shmem_allocations AS $$ SELECT * FROM pg_shmem_allocations;$$ LANGUAGE SQL SECURITY DEFINER;
COMMENT ON FUNCTION monitor.pg_shmem() IS 'security wrapper for system view pg_shmem';
REVOKE ALL ON FUNCTION monitor.pg_shmem() FROM PUBLIC;
GRANT EXECUTE ON FUNCTION monitor.pg_shmem() TO pg_monitor;

10.12.1 - Monitoring Dashboards

Pigsty provides many out-of-the-box Grafana monitoring dashboards for PostgreSQL

Pigsty provides many out-of-the-box Grafana monitoring dashboards for PostgreSQL: Demo & Gallery.

There are 26 PostgreSQL-related monitoring dashboards in Pigsty, organized hierarchically into Overview, Cluster, Instance, and Database categories, and by data source into PGSQL, PGCAT, and PGLOG categories.

pigsty-dashboard.jpg


Overview

OverviewClusterInstanceDatabase
PGSQL OverviewPGSQL ClusterPGSQL InstancePGSQL Database
PGSQL AlertPGRDS ClusterPGRDS InstancePGCAT Database
PGSQL ShardPGSQL ActivityPGCAT InstancePGSQL Tables
PGSQL ReplicationPGSQL PersistPGSQL Table
PGSQL ServicePGSQL ProxyPGCAT Table
PGSQL DatabasesPGSQL PgbouncerPGSQL Query
PGSQL PatroniPGSQL SessionPGCAT Query
PGSQL PITRPGSQL XactsPGCAT Locks
PGSQL ExporterPGCAT Schema

Overview

  • pgsql-overview: Main dashboard for the PGSQL module
  • pgsql-alert: Global critical metrics and alert events for PGSQL
  • pgsql-shard: Overview of horizontally sharded PGSQL clusters, such as Citus / GPSQL clusters

Cluster

  • pgsql-cluster: Main dashboard for a PGSQL cluster
  • pgrds-cluster: RDS version of PGSQL Cluster, focused on all PostgreSQL-specific metrics
  • pgsql-activity: Focus on PGSQL cluster sessions/load/QPS/TPS/locks
  • pgsql-replication: Focus on PGSQL cluster replication, slots, and pub/sub
  • pgsql-service: Focus on PGSQL cluster services, proxies, routing, and load balancing
  • pgsql-databases: Focus on database CRUD, slow queries, and table statistics across all instances
  • pgsql-patroni: Focus on cluster high availability status and Patroni component status
  • pgsql-pitr: Focus on cluster PITR process context for point-in-time recovery assistance

Instance

  • pgsql-instance: Main dashboard for a single PGSQL instance
  • pgrds-instance: RDS version of PGSQL Instance, focused on all PostgreSQL-specific metrics
  • pgcat-instance: Instance information retrieved directly from the database catalog
  • pgsql-proxy: Detailed metrics for a single HAProxy load balancer
  • pgsql-pgbouncer: Metrics overview in a single Pgbouncer connection pool instance
  • pgsql-persist: Persistence metrics: WAL, XID, checkpoints, archiving, IO
  • pgsql-session: Session and active/idle time metrics in a single instance
  • pgsql-xacts: Metrics related to transactions, locks, TPS/QPS
  • pgsql-exporter: Self-monitoring metrics for Postgres and Pgbouncer monitoring components

Database

  • pgsql-database: Main dashboard for a single PGSQL database
  • pgcat-database: Database information retrieved directly from the database catalog
  • pgsql-tables: Table/index access metrics within a single database
  • pgsql-table: Details of a single table (QPS/RT/index/sequences…)
  • pgcat-table: Details of a single table retrieved directly from the database catalog (stats/bloat…)
  • pgsql-query: Details of a single query (QPS/RT)
  • pgcat-query: Details of a single query retrieved directly from the database catalog (SQL/stats)
  • pgcat-schema: Information about schemas retrieved directly from the database catalog (tables/indexes/sequences…)
  • pgcat-locks: Information about activities and lock waits retrieved directly from the database catalog

Overview

PGSQL Overview: Main dashboard for the PGSQL module

PGSQL Overview

pgsql-overview.jpg

PGSQL Alert: Global critical metrics overview and alert event listing for PGSQL

PGSQL Alert

pgsql-alert.jpg

PGSQL Shard: Shows horizontal metric comparisons within a PGSQL horizontally sharded cluster, such as CITUS / GPSQL clusters

PGSQL Shard

pgsql-shard.jpg


Cluster

PGSQL Cluster: Main dashboard for a PGSQL cluster

PGSQL Cluster

pgsql-cluster.jpg

PGRDS Cluster: RDS version of PGSQL Cluster, focused on all PostgreSQL-specific metrics

PGRDS Cluster

pgrds-cluster.jpg

PGSQL Service: Focus on PGSQL cluster services, proxies, routing, and load balancing

PGSQL Service

pgsql-service.jpg

PGSQL Activity: Focus on PGSQL cluster sessions/load/QPS/TPS/locks

PGSQL Activity

pgsql-activity.jpg

PGSQL Replication: Focus on PGSQL cluster replication, slots, and pub/sub

PGSQL Replication

pgsql-replication.jpg

PGSQL Databases: Focus on database CRUD, slow queries, and table statistics across all instances

PGSQL Databases

pgsql-databases.jpg

PGSQL Patroni: Focus on cluster high availability status and Patroni component status

PGSQL Patroni

pgsql-patroni.jpg

PGSQL PITR: Focus on cluster PITR process context for point-in-time recovery assistance

PGSQL PITR

pgsql-patroni.jpg


Instance

PGSQL Instance: Main dashboard for a single PGSQL instance

PGSQL Instance

pgsql-instance.jpg

PGRDS Instance: RDS version of PGSQL Instance, focused on all PostgreSQL-specific metrics

PGRDS Instance

pgrds-instance.jpg

PGSQL Proxy: Detailed metrics for a single HAProxy load balancer

PGSQL Proxy

pgsql-proxy.jpg

PGSQL Pgbouncer: Metrics overview in a single Pgbouncer connection pool instance

PGSQL Pgbouncer

pgsql-pgbouncer.jpg

PGSQL Persist: Persistence metrics: WAL, XID, checkpoints, archiving, IO

PGSQL Persist

pgsql-persist.jpg

PGSQL Xacts: Metrics related to transactions, locks, TPS/QPS

PGSQL Xacts

pgsql-xacts.jpg

PGSQL Session: Session and active/idle time metrics in a single instance

PGSQL Session

pgsql-session.jpg

PGSQL Exporter: Self-monitoring metrics for Postgres/Pgbouncer monitoring components

PGSQL Exporter

pgsql-exporter.jpg


Database

PGSQL Database: Main dashboard for a single PGSQL database

PGSQL Database

pgsql-database.jpg

PGSQL Tables: Table/index access metrics within a single database

PGSQL Tables

pgsql-tables.jpg

PGSQL Table: Details of a single table (QPS/RT/index/sequences…)

PGSQL Table

pgsql-table.jpg

PGSQL Query: Details of a single query (QPS/RT)

PGSQL Query

pgsql-query.jpg


PGCAT

PGCAT Instance: Instance information retrieved directly from the database catalog

PGCAT Instance

pgcat-instance.jpg

PGCAT Database: Database information retrieved directly from the database catalog

PGCAT Database

pgcat-database.jpg

PGCAT Schema: Information about schemas retrieved directly from the database catalog (tables/indexes/sequences…)

PGCAT Schema

pgcat-schema.jpg

PGCAT Table: Details of a single table retrieved directly from the database catalog (stats/bloat…)

PGCAT Table

pgcat-table.jpg

PGCAT Query: Details of a single query retrieved directly from the database catalog (SQL/stats)

PGCAT Query

pgcat-query.jpg

PGCAT Locks: Information about activities and lock waits retrieved directly from the database catalog

PGCAT Locks

pgcat-locks.jpg


PGLOG

PGLOG Overview: Overview of CSV log samples in Pigsty CMDB

PGLOG Overview

pglog-overview.jpg

PGLOG Session: Log details of a session in CSV log samples in Pigsty CMDB

PGLOG Session

pglog-session.jpg


For details, refer to pigsty/wiki/gallery.

PGSQL Overview

pgsql-overview.jpg

PGSQL Shard

pgsql-shard.jpg

PGSQL Cluster

pgsql-cluster.jpg

PGSQL Service

pgsql-service.jpg

PGSQL Activity

pgsql-activity.jpg

PGSQL Replication

pgsql-replication.jpg

PGSQL Databases

pgsql-databases.jpg

PGSQL Instance

pgsql-instance.jpg

PGSQL Proxy

pgsql-proxy.jpg

PGSQL Pgbouncer

pgsql-pgbouncer.jpg

PGSQL Session

pgsql-session.jpg

PGSQL Xacts

pgsql-xacts.jpg

PGSQL Persist

pgsql-persist.jpg

PGSQL Database

pgsql-database.jpg

PGSQL Tables

pgsql-tables.jpg

PGSQL Table

pgsql-table.jpg

PGSQL Query

pgsql-query.jpg

PGCAT Instance

pgcat-instance.jpg

PGCAT Database

pgcat-database.jpg

PGCAT Schema

pgcat-schema.jpg

PGCAT Table

pgcat-table.jpg

PGCAT Lock

pgcat-locks.jpg

PGCAT Query

pgcat-query.jpg

PGLOG Overview

pglog-overview.jpg

PGLOG Session

pglog-session.jpg

10.12.2 - Metrics List

Complete list and explanation of monitoring metrics provided by the Pigsty PGSQL module

The PGSQL module contains 638 types of available monitoring metrics.

Metric NameTypeLabelsDescription
ALERTSUnknowncategory, job, level, ins, severity, ip, alertname, alertstate, instance, clsN/A
ALERTS_FOR_STATEUnknowncategory, job, level, ins, severity, ip, alertname, instance, clsN/A
cls:pressure1Unknownjob, clsN/A
cls:pressure15Unknownjob, clsN/A
cls:pressure5Unknownjob, clsN/A
go_gc_duration_secondssummaryjob, ins, ip, instance, quantile, clsA summary of the pause duration of garbage collection cycles.
go_gc_duration_seconds_countUnknownjob, ins, ip, instance, clsN/A
go_gc_duration_seconds_sumUnknownjob, ins, ip, instance, clsN/A
go_goroutinesgaugejob, ins, ip, instance, clsNumber of goroutines that currently exist.
go_infogaugeversion, job, ins, ip, instance, clsInformation about the Go environment.
go_memstats_alloc_bytesgaugejob, ins, ip, instance, clsNumber of bytes allocated and still in use.
go_memstats_alloc_bytes_totalcounterjob, ins, ip, instance, clsTotal number of bytes allocated, even if freed.
go_memstats_buck_hash_sys_bytesgaugejob, ins, ip, instance, clsNumber of bytes used by the profiling bucket hash table.
go_memstats_frees_totalcounterjob, ins, ip, instance, clsTotal number of frees.
go_memstats_gc_sys_bytesgaugejob, ins, ip, instance, clsNumber of bytes used for garbage collection system metadata.
go_memstats_heap_alloc_bytesgaugejob, ins, ip, instance, clsNumber of heap bytes allocated and still in use.
go_memstats_heap_idle_bytesgaugejob, ins, ip, instance, clsNumber of heap bytes waiting to be used.
go_memstats_heap_inuse_bytesgaugejob, ins, ip, instance, clsNumber of heap bytes that are in use.
go_memstats_heap_objectsgaugejob, ins, ip, instance, clsNumber of allocated objects.
go_memstats_heap_released_bytesgaugejob, ins, ip, instance, clsNumber of heap bytes released to OS.
go_memstats_heap_sys_bytesgaugejob, ins, ip, instance, clsNumber of heap bytes obtained from system.
go_memstats_last_gc_time_secondsgaugejob, ins, ip, instance, clsNumber of seconds since 1970 of last garbage collection.
go_memstats_lookups_totalcounterjob, ins, ip, instance, clsTotal number of pointer lookups.
go_memstats_mallocs_totalcounterjob, ins, ip, instance, clsTotal number of mallocs.
go_memstats_mcache_inuse_bytesgaugejob, ins, ip, instance, clsNumber of bytes in use by mcache structures.
go_memstats_mcache_sys_bytesgaugejob, ins, ip, instance, clsNumber of bytes used for mcache structures obtained from system.
go_memstats_mspan_inuse_bytesgaugejob, ins, ip, instance, clsNumber of bytes in use by mspan structures.
go_memstats_mspan_sys_bytesgaugejob, ins, ip, instance, clsNumber of bytes used for mspan structures obtained from system.
go_memstats_next_gc_bytesgaugejob, ins, ip, instance, clsNumber of heap bytes when next garbage collection will take place.
go_memstats_other_sys_bytesgaugejob, ins, ip, instance, clsNumber of bytes used for other system allocations.
go_memstats_stack_inuse_bytesgaugejob, ins, ip, instance, clsNumber of bytes in use by the stack allocator.
go_memstats_stack_sys_bytesgaugejob, ins, ip, instance, clsNumber of bytes obtained from system for stack allocator.
go_memstats_sys_bytesgaugejob, ins, ip, instance, clsNumber of bytes obtained from system.
go_threadsgaugejob, ins, ip, instance, clsNumber of OS threads created.
ins:pressure1Unknownjob, ins, ip, clsN/A
ins:pressure15Unknownjob, ins, ip, clsN/A
ins:pressure5Unknownjob, ins, ip, clsN/A
patroni_cluster_unlockedgaugejob, ins, ip, instance, cls, scopeValue is 1 if the cluster is unlocked, 0 if locked.
patroni_dcs_last_seengaugejob, ins, ip, instance, cls, scopeEpoch timestamp when DCS was last contacted successfully by Patroni.
patroni_failsafe_mode_is_activegaugejob, ins, ip, instance, cls, scopeValue is 1 if failsafe mode is active, 0 if inactive.
patroni_is_pausedgaugejob, ins, ip, instance, cls, scopeValue is 1 if auto failover is disabled, 0 otherwise.
patroni_mastergaugejob, ins, ip, instance, cls, scopeValue is 1 if this node is the leader, 0 otherwise.
patroni_pending_restartgaugejob, ins, ip, instance, cls, scopeValue is 1 if the node needs a restart, 0 otherwise.
patroni_postgres_in_archive_recoverygaugejob, ins, ip, instance, cls, scopeValue is 1 if Postgres is replicating from archive, 0 otherwise.
patroni_postgres_runninggaugejob, ins, ip, instance, cls, scopeValue is 1 if Postgres is running, 0 otherwise.
patroni_postgres_server_versiongaugejob, ins, ip, instance, cls, scopeVersion of Postgres (if running), 0 otherwise.
patroni_postgres_streaminggaugejob, ins, ip, instance, cls, scopeValue is 1 if Postgres is streaming, 0 otherwise.
patroni_postgres_timelinecounterjob, ins, ip, instance, cls, scopePostgres timeline of this node (if running), 0 otherwise.
patroni_postmaster_start_timegaugejob, ins, ip, instance, cls, scopeEpoch seconds since Postgres started.
patroni_primarygaugejob, ins, ip, instance, cls, scopeValue is 1 if this node is the leader, 0 otherwise.
patroni_replicagaugejob, ins, ip, instance, cls, scopeValue is 1 if this node is a replica, 0 otherwise.
patroni_standby_leadergaugejob, ins, ip, instance, cls, scopeValue is 1 if this node is the standby_leader, 0 otherwise.
patroni_sync_standbygaugejob, ins, ip, instance, cls, scopeValue is 1 if this node is a sync standby replica, 0 otherwise.
patroni_upUnknownjob, ins, ip, instance, clsN/A
patroni_versiongaugejob, ins, ip, instance, cls, scopePatroni semver without periods.
patroni_xlog_locationcounterjob, ins, ip, instance, cls, scopeCurrent location of the Postgres transaction log, 0 if this node is not the leader.
patroni_xlog_pausedgaugejob, ins, ip, instance, cls, scopeValue is 1 if the Postgres xlog is paused, 0 otherwise.
patroni_xlog_received_locationcounterjob, ins, ip, instance, cls, scopeCurrent location of the received Postgres transaction log, 0 if this node is not a replica.
patroni_xlog_replayed_locationcounterjob, ins, ip, instance, cls, scopeCurrent location of the replayed Postgres transaction log, 0 if this node is not a replica.
patroni_xlog_replayed_timestampgaugejob, ins, ip, instance, cls, scopeCurrent timestamp of the replayed Postgres transaction log, 0 if null.
pg:cls:active_backendsUnknownjob, clsN/A
pg:cls:active_time_rate15mUnknownjob, clsN/A
pg:cls:active_time_rate1mUnknownjob, clsN/A
pg:cls:active_time_rate5mUnknownjob, clsN/A
pg:cls:ageUnknownjob, clsN/A
pg:cls:buf_alloc_rate1mUnknownjob, clsN/A
pg:cls:buf_clean_rate1mUnknownjob, clsN/A
pg:cls:buf_flush_backend_rate1mUnknownjob, clsN/A
pg:cls:buf_flush_checkpoint_rate1mUnknownjob, clsN/A
pg:cls:cpu_countUnknownjob, clsN/A
pg:cls:cpu_usageUnknownjob, clsN/A
pg:cls:cpu_usage_15mUnknownjob, clsN/A
pg:cls:cpu_usage_1mUnknownjob, clsN/A
pg:cls:cpu_usage_5mUnknownjob, clsN/A
pg:cls:db_sizeUnknownjob, clsN/A
pg:cls:file_sizeUnknownjob, clsN/A
pg:cls:ixact_backendsUnknownjob, clsN/A
pg:cls:ixact_time_rate1mUnknownjob, clsN/A
pg:cls:lag_bytesUnknownjob, clsN/A
pg:cls:lag_secondsUnknownjob, clsN/A
pg:cls:leaderUnknownjob, ins, ip, instance, clsN/A
pg:cls:load1Unknownjob, clsN/A
pg:cls:load15Unknownjob, clsN/A
pg:cls:load5Unknownjob, clsN/A
pg:cls:lock_countUnknownjob, clsN/A
pg:cls:locksUnknownjob, cls, modeN/A
pg:cls:log_sizeUnknownjob, clsN/A
pg:cls:lsn_rate1mUnknownjob, clsN/A
pg:cls:membersUnknownjob, ins, ip, clsN/A
pg:cls:num_backendsUnknownjob, clsN/A
pg:cls:partitionUnknownjob, clsN/A
pg:cls:receiverUnknownstate, slot_name, job, appname, ip, cls, sender_host, sender_portN/A
pg:cls:rlock_countUnknownjob, clsN/A
pg:cls:saturation1Unknownjob, clsN/A
pg:cls:saturation15Unknownjob, clsN/A
pg:cls:saturation5Unknownjob, clsN/A
pg:cls:senderUnknownpid, usename, address, job, ins, appname, ip, clsN/A
pg:cls:session_time_rate1mUnknownjob, clsN/A
pg:cls:sizeUnknownjob, clsN/A
pg:cls:slot_countUnknownjob, clsN/A
pg:cls:slot_retained_bytesUnknownjob, clsN/A
pg:cls:standby_countUnknownjob, clsN/A
pg:cls:sync_stateUnknownjob, clsN/A
pg:cls:timelineUnknownjob, clsN/A
pg:cls:tup_deleted_rate1mUnknownjob, clsN/A
pg:cls:tup_fetched_rate1mUnknownjob, clsN/A
pg:cls:tup_inserted_rate1mUnknownjob, clsN/A
pg:cls:tup_modified_rate1mUnknownjob, clsN/A
pg:cls:tup_returned_rate1mUnknownjob, clsN/A
pg:cls:wal_sizeUnknownjob, clsN/A
pg:cls:xact_commit_rate15mUnknownjob, clsN/A
pg:cls:xact_commit_rate1mUnknownjob, clsN/A
pg:cls:xact_commit_rate5mUnknownjob, clsN/A
pg:cls:xact_rollback_rate15mUnknownjob, clsN/A
pg:cls:xact_rollback_rate1mUnknownjob, clsN/A
pg:cls:xact_rollback_rate5mUnknownjob, clsN/A
pg:cls:xact_total_rate15mUnknownjob, clsN/A
pg:cls:xact_total_rate1mUnknownjob, clsN/A
pg:cls:xact_total_sigma15mUnknownjob, clsN/A
pg:cls:xlock_countUnknownjob, clsN/A
pg:db:active_backendsUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:active_time_rate15mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:active_time_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:active_time_rate5mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:ageUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:age_deriv1hUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:age_exhaustUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:blk_io_time_seconds_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:blk_read_time_seconds_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:blk_write_time_seconds_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:blks_access_1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:blks_hit_1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:blks_hit_ratio1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:blks_read_1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:conn_limitUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:conn_usageUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:db_sizeUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:ixact_backendsUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:ixact_time_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:lock_countUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:num_backendsUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:rlock_countUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:session_time_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:temp_bytes_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:temp_files_1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:tup_deleted_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:tup_fetched_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:tup_inserted_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:tup_modified_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:tup_returned_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:wlock_countUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:xact_commit_rate15mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:xact_commit_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:xact_commit_rate5mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:xact_rollback_rate15mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:xact_rollback_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:xact_rollback_rate5mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:xact_total_rate15mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:xact_total_rate1mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:xact_total_rate5mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:xact_total_sigma15mUnknowndatname, job, ins, ip, instance, clsN/A
pg:db:xlock_countUnknowndatname, job, ins, ip, instance, clsN/A
pg:env:active_backendsUnknownjobN/A
pg:env:active_time_rate15mUnknownjobN/A
pg:env:active_time_rate1mUnknownjobN/A
pg:env:active_time_rate5mUnknownjobN/A
pg:env:ageUnknownjobN/A
pg:env:cpu_countUnknownjobN/A
pg:env:cpu_usageUnknownjobN/A
pg:env:cpu_usage_15mUnknownjobN/A
pg:env:cpu_usage_1mUnknownjobN/A
pg:env:cpu_usage_5mUnknownjobN/A
pg:env:ixact_backendsUnknownjobN/A
pg:env:ixact_time_rate1mUnknownjobN/A
pg:env:lag_bytesUnknownjobN/A
pg:env:lag_secondsUnknownjobN/A
pg:env:lsn_rate1mUnknownjobN/A
pg:env:session_time_rate1mUnknownjobN/A
pg:env:tup_deleted_rate1mUnknownjobN/A
pg:env:tup_fetched_rate1mUnknownjobN/A
pg:env:tup_inserted_rate1mUnknownjobN/A
pg:env:tup_modified_rate1mUnknownjobN/A
pg:env:tup_returned_rate1mUnknownjobN/A
pg:env:xact_commit_rate15mUnknownjobN/A
pg:env:xact_commit_rate1mUnknownjobN/A
pg:env:xact_commit_rate5mUnknownjobN/A
pg:env:xact_rollback_rate15mUnknownjobN/A
pg:env:xact_rollback_rate1mUnknownjobN/A
pg:env:xact_rollback_rate5mUnknownjobN/A
pg:env:xact_total_rate15mUnknownjobN/A
pg:env:xact_total_rate1mUnknownjobN/A
pg:env:xact_total_sigma15mUnknownjobN/A
pg:ins:active_backendsUnknownjob, ins, ip, instance, clsN/A
pg:ins:active_time_rate15mUnknownjob, ins, ip, instance, clsN/A
pg:ins:active_time_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:active_time_rate5mUnknownjob, ins, ip, instance, clsN/A
pg:ins:ageUnknownjob, ins, ip, instance, clsN/A
pg:ins:blks_hit_ratio1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:buf_alloc_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:buf_clean_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:buf_flush_backend_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:buf_flush_checkpoint_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:ckpt_1hUnknownjob, ins, ip, instance, clsN/A
pg:ins:ckpt_req_1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:ckpt_timed_1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:conn_limitUnknownjob, ins, ip, instance, clsN/A
pg:ins:conn_usageUnknownjob, ins, ip, instance, clsN/A
pg:ins:cpu_countUnknownjob, ins, ip, instance, clsN/A
pg:ins:cpu_usageUnknownjob, ins, ip, instance, clsN/A
pg:ins:cpu_usage_15mUnknownjob, ins, ip, instance, clsN/A
pg:ins:cpu_usage_1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:cpu_usage_5mUnknownjob, ins, ip, instance, clsN/A
pg:ins:db_sizeUnknownjob, ins, ip, instance, clsN/A
pg:ins:file_sizeUnknownjob, ins, ip, instance, clsN/A
pg:ins:fs_sizeUnknownjob, ins, ip, instance, clsN/A
pg:ins:is_leaderUnknownjob, ins, ip, instance, clsN/A
pg:ins:ixact_backendsUnknownjob, ins, ip, instance, clsN/A
pg:ins:ixact_time_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:lag_bytesUnknownjob, ins, ip, instance, clsN/A
pg:ins:lag_secondsUnknownjob, ins, ip, instance, clsN/A
pg:ins:load1Unknownjob, ins, ip, instance, clsN/A
pg:ins:load15Unknownjob, ins, ip, instance, clsN/A
pg:ins:load5Unknownjob, ins, ip, instance, clsN/A
pg:ins:lock_countUnknownjob, ins, ip, instance, clsN/A
pg:ins:locksUnknownjob, ins, ip, mode, instance, clsN/A
pg:ins:log_sizeUnknownjob, ins, ip, instance, clsN/A
pg:ins:lsn_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:mem_sizeUnknownjob, ins, ip, instance, clsN/A
pg:ins:num_backendsUnknownjob, ins, ip, instance, clsN/A
pg:ins:rlock_countUnknownjob, ins, ip, instance, clsN/A
pg:ins:saturation1Unknownjob, ins, ip, clsN/A
pg:ins:saturation15Unknownjob, ins, ip, clsN/A
pg:ins:saturation5Unknownjob, ins, ip, clsN/A
pg:ins:session_time_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:slot_retained_bytesUnknownjob, ins, ip, instance, clsN/A
pg:ins:space_usageUnknownjob, ins, ip, instance, clsN/A
pg:ins:statusUnknownjob, ins, ip, instance, clsN/A
pg:ins:sync_stateUnknownjob, ins, instance, clsN/A
pg:ins:target_countUnknownjob, cls, insN/A
pg:ins:timelineUnknownjob, ins, ip, instance, clsN/A
pg:ins:tup_deleted_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:tup_fetched_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:tup_inserted_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:tup_modified_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:tup_returned_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:wal_sizeUnknownjob, ins, ip, instance, clsN/A
pg:ins:wlock_countUnknownjob, ins, ip, instance, clsN/A
pg:ins:xact_commit_rate15mUnknownjob, ins, ip, instance, clsN/A
pg:ins:xact_commit_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:xact_commit_rate5mUnknownjob, ins, ip, instance, clsN/A
pg:ins:xact_rollback_rate15mUnknownjob, ins, ip, instance, clsN/A
pg:ins:xact_rollback_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:xact_rollback_rate5mUnknownjob, ins, ip, instance, clsN/A
pg:ins:xact_total_rate15mUnknownjob, ins, ip, instance, clsN/A
pg:ins:xact_total_rate1mUnknownjob, ins, ip, instance, clsN/A
pg:ins:xact_total_rate5mUnknownjob, ins, ip, instance, clsN/A
pg:ins:xact_total_sigma15mUnknownjob, ins, ip, instance, clsN/A
pg:ins:xlock_countUnknownjob, ins, ip, instance, clsN/A
pg:query:call_rate1mUnknowndatname, query, job, ins, ip, instance, clsN/A
pg:query:rt_1mUnknowndatname, query, job, ins, ip, instance, clsN/A
pg:table:scan_rate1mUnknowndatname, relname, job, ins, ip, instance, clsN/A
pg_activity_countgaugedatname, state, job, ins, ip, instance, clsCount of connection among (datname,state)
pg_activity_max_conn_durationgaugedatname, state, job, ins, ip, instance, clsMax backend session duration since state change among (datname, state)
pg_activity_max_durationgaugedatname, state, job, ins, ip, instance, clsMax duration since last state change among (datname, state)
pg_activity_max_tx_durationgaugedatname, state, job, ins, ip, instance, clsMax transaction duration since state change among (datname, state)
pg_archiver_failed_countcounterjob, ins, ip, instance, clsNumber of failed attempts for archiving WAL files
pg_archiver_finish_countcounterjob, ins, ip, instance, clsNumber of WAL files that have been successfully archived
pg_archiver_last_failed_timecounterjob, ins, ip, instance, clsTime of the last failed archival operation
pg_archiver_last_finish_timecounterjob, ins, ip, instance, clsTime of the last successful archive operation
pg_archiver_reset_timegaugejob, ins, ip, instance, clsTime at which archive statistics were last reset
pg_backend_countgaugetype, job, ins, ip, instance, clsDatabase backend process count by backend_type
pg_bgwriter_buffers_alloccounterjob, ins, ip, instance, clsNumber of buffers allocated
pg_bgwriter_buffers_backendcounterjob, ins, ip, instance, clsNumber of buffers written directly by a backend
pg_bgwriter_buffers_backend_fsynccounterjob, ins, ip, instance, clsNumber of times a backend had to execute its own fsync call
pg_bgwriter_buffers_checkpointcounterjob, ins, ip, instance, clsNumber of buffers written during checkpoints
pg_bgwriter_buffers_cleancounterjob, ins, ip, instance, clsNumber of buffers written by the background writer
pg_bgwriter_checkpoint_sync_timecounterjob, ins, ip, instance, clsTotal amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds
pg_bgwriter_checkpoint_write_timecounterjob, ins, ip, instance, clsTotal amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds
pg_bgwriter_checkpoints_reqcounterjob, ins, ip, instance, clsNumber of requested checkpoints that have been performed
pg_bgwriter_checkpoints_timedcounterjob, ins, ip, instance, clsNumber of scheduled checkpoints that have been performed
pg_bgwriter_maxwritten_cleancounterjob, ins, ip, instance, clsNumber of times the background writer stopped a cleaning scan because it had written too many buffers
pg_bgwriter_reset_timecounterjob, ins, ip, instance, clsTime at which bgwriter statistics were last reset
pg_boot_timegaugejob, ins, ip, instance, clsunix timestamp when postmaster boot
pg_checkpoint_checkpoint_lsncounterjob, ins, ip, instance, clsLatest checkpoint location
pg_checkpoint_elapsegaugejob, ins, ip, instance, clsSeconds elapsed since latest checkpoint in seconds
pg_checkpoint_full_page_writesgaugejob, ins, ip, instance, clsLatest checkpoint’s full_page_writes enabled
pg_checkpoint_newest_commit_ts_xidcounterjob, ins, ip, instance, clsLatest checkpoint’s newestCommitTsXid
pg_checkpoint_next_multi_offsetcounterjob, ins, ip, instance, clsLatest checkpoint’s NextMultiOffset
pg_checkpoint_next_multixact_idcounterjob, ins, ip, instance, clsLatest checkpoint’s NextMultiXactId
pg_checkpoint_next_oidcounterjob, ins, ip, instance, clsLatest checkpoint’s NextOID
pg_checkpoint_next_xidcounterjob, ins, ip, instance, clsLatest checkpoint’s NextXID xid
pg_checkpoint_next_xid_epochcounterjob, ins, ip, instance, clsLatest checkpoint’s NextXID epoch
pg_checkpoint_oldest_active_xidcounterjob, ins, ip, instance, clsLatest checkpoint’s oldestActiveXID
pg_checkpoint_oldest_commit_ts_xidcounterjob, ins, ip, instance, clsLatest checkpoint’s oldestCommitTsXid
pg_checkpoint_oldest_multi_dbidgaugejob, ins, ip, instance, clsLatest checkpoint’s oldestMulti’s DB OID
pg_checkpoint_oldest_multi_xidcounterjob, ins, ip, instance, clsLatest checkpoint’s oldestMultiXid
pg_checkpoint_oldest_xidcounterjob, ins, ip, instance, clsLatest checkpoint’s oldestXID
pg_checkpoint_oldest_xid_dbidgaugejob, ins, ip, instance, clsLatest checkpoint’s oldestXID’s DB OID
pg_checkpoint_prev_tlicounterjob, ins, ip, instance, clsLatest checkpoint’s PrevTimeLineID
pg_checkpoint_redo_lsncounterjob, ins, ip, instance, clsLatest checkpoint’s REDO location
pg_checkpoint_timecounterjob, ins, ip, instance, clsTime of latest checkpoint
pg_checkpoint_tlicounterjob, ins, ip, instance, clsLatest checkpoint’s TimeLineID
pg_conf_reload_timegaugejob, ins, ip, instance, clsseconds since last configuration reload
pg_db_active_timecounterdatname, job, ins, ip, instance, clsTime spent executing SQL statements in this database, in seconds
pg_db_agegaugedatname, job, ins, ip, instance, clsAge of database calculated from datfrozenxid
pg_db_allow_conngaugedatname, job, ins, ip, instance, clsIf false(0) then no one can connect to this database.
pg_db_blk_read_timecounterdatname, job, ins, ip, instance, clsTime spent reading data file blocks by backends in this database, in seconds
pg_db_blk_write_timecounterdatname, job, ins, ip, instance, clsTime spent writing data file blocks by backends in this database, in seconds
pg_db_blks_accesscounterdatname, job, ins, ip, instance, clsNumber of times disk blocks that accessed read+hit
pg_db_blks_hitcounterdatname, job, ins, ip, instance, clsNumber of times disk blocks were found already in the buffer cache
pg_db_blks_readcounterdatname, job, ins, ip, instance, clsNumber of disk blocks read in this database
pg_db_cks_fail_timegaugedatname, job, ins, ip, instance, clsTime at which the last data page checksum failure was detected in this database
pg_db_cks_failscounterdatname, job, ins, ip, instance, clsNumber of data page checksum failures detected in this database, -1 for not enabled
pg_db_confl_confl_bufferpincounterdatname, job, ins, ip, instance, clsNumber of queries in this database that have been canceled due to pinned buffers
pg_db_confl_confl_deadlockcounterdatname, job, ins, ip, instance, clsNumber of queries in this database that have been canceled due to deadlocks
pg_db_confl_confl_lockcounterdatname, job, ins, ip, instance, clsNumber of queries in this database that have been canceled due to lock timeouts
pg_db_confl_confl_snapshotcounterdatname, job, ins, ip, instance, clsNumber of queries in this database that have been canceled due to old snapshots
pg_db_confl_confl_tablespacecounterdatname, job, ins, ip, instance, clsNumber of queries in this database that have been canceled due to dropped tablespaces
pg_db_conflictscounterdatname, job, ins, ip, instance, clsNumber of queries canceled due to conflicts with recovery in this database
pg_db_conn_limitgaugedatname, job, ins, ip, instance, clsSets maximum number of concurrent connections that can be made to this database. -1 means no limit.
pg_db_datidgaugedatname, job, ins, ip, instance, clsOID of the database
pg_db_deadlockscounterdatname, job, ins, ip, instance, clsNumber of deadlocks detected in this database
pg_db_frozen_xidgaugedatname, job, ins, ip, instance, clsAll transaction IDs before this one have been frozened
pg_db_is_templategaugedatname, job, ins, ip, instance, clsIf true(1), then this database can be cloned by any user with CREATEDB privileges
pg_db_ixact_timecounterdatname, job, ins, ip, instance, clsTime spent idling while in a transaction in this database, in seconds
pg_db_numbackendsgaugedatname, job, ins, ip, instance, clsNumber of backends currently connected to this database
pg_db_reset_timecounterdatname, job, ins, ip, instance, clsTime at which database statistics were last reset
pg_db_session_timecounterdatname, job, ins, ip, instance, clsTime spent by database sessions in this database, in seconds
pg_db_sessionscounterdatname, job, ins, ip, instance, clsTotal number of sessions established to this database
pg_db_sessions_abandonedcounterdatname, job, ins, ip, instance, clsNumber of database sessions to this database that were terminated because connection to the client was lost
pg_db_sessions_fatalcounterdatname, job, ins, ip, instance, clsNumber of database sessions to this database that were terminated by fatal errors
pg_db_sessions_killedcounterdatname, job, ins, ip, instance, clsNumber of database sessions to this database that were terminated by operator intervention
pg_db_temp_bytescounterdatname, job, ins, ip, instance, clsTotal amount of data written to temporary files by queries in this database.
pg_db_temp_filescounterdatname, job, ins, ip, instance, clsNumber of temporary files created by queries in this database
pg_db_tup_deletedcounterdatname, job, ins, ip, instance, clsNumber of rows deleted by queries in this database
pg_db_tup_fetchedcounterdatname, job, ins, ip, instance, clsNumber of rows fetched by queries in this database
pg_db_tup_insertedcounterdatname, job, ins, ip, instance, clsNumber of rows inserted by queries in this database
pg_db_tup_modifiedcounterdatname, job, ins, ip, instance, clsNumber of rows modified by queries in this database
pg_db_tup_returnedcounterdatname, job, ins, ip, instance, clsNumber of rows returned by queries in this database
pg_db_tup_updatedcounterdatname, job, ins, ip, instance, clsNumber of rows updated by queries in this database
pg_db_xact_commitcounterdatname, job, ins, ip, instance, clsNumber of transactions in this database that have been committed
pg_db_xact_rollbackcounterdatname, job, ins, ip, instance, clsNumber of transactions in this database that have been rolled back
pg_db_xact_totalcounterdatname, job, ins, ip, instance, clsNumber of transactions in this database
pg_downstream_countgaugestate, job, ins, ip, instance, clsCount of corresponding state
pg_exporter_agent_upUnknownjob, ins, ip, instance, clsN/A
pg_exporter_last_scrape_timegaugejob, ins, ip, instance, clsseconds exporter spending on scrapping
pg_exporter_query_cache_ttlgaugedatname, query, job, ins, ip, instance, clstimes to live of query cache
pg_exporter_query_scrape_durationgaugedatname, query, job, ins, ip, instance, clsseconds query spending on scrapping
pg_exporter_query_scrape_error_countgaugedatname, query, job, ins, ip, instance, clstimes the query failed
pg_exporter_query_scrape_hit_countgaugedatname, query, job, ins, ip, instance, clsnumbers been scrapped from this query
pg_exporter_query_scrape_metric_countgaugedatname, query, job, ins, ip, instance, clsnumbers of metrics been scrapped from this query
pg_exporter_query_scrape_total_countgaugedatname, query, job, ins, ip, instance, clstimes exporter server was scraped for metrics
pg_exporter_scrape_durationgaugejob, ins, ip, instance, clsseconds exporter spending on scrapping
pg_exporter_scrape_error_countcounterjob, ins, ip, instance, clstimes exporter was scraped for metrics and failed
pg_exporter_scrape_total_countcounterjob, ins, ip, instance, clstimes exporter was scraped for metrics
pg_exporter_server_scrape_durationgaugedatname, job, ins, ip, instance, clsseconds exporter server spending on scrapping
pg_exporter_server_scrape_error_countUnknowndatname, job, ins, ip, instance, clsN/A
pg_exporter_server_scrape_total_countgaugedatname, job, ins, ip, instance, clstimes exporter server was scraped for metrics
pg_exporter_server_scrape_total_secondsgaugedatname, job, ins, ip, instance, clsseconds exporter server spending on scrapping
pg_exporter_upgaugejob, ins, ip, instance, clsalways be 1 if your could retrieve metrics
pg_exporter_uptimegaugejob, ins, ip, instance, clsseconds since exporter primary server inited
pg_flush_lsncounterjob, ins, ip, instance, clsprimary only, location of current wal syncing
pg_func_callscounterdatname, funcname, job, ins, ip, instance, clsNumber of times this function has been called
pg_func_self_timecounterdatname, funcname, job, ins, ip, instance, clsTotal time spent in this function itself, not including other functions called by it, in ms
pg_func_total_timecounterdatname, funcname, job, ins, ip, instance, clsTotal time spent in this function and all other functions called by it, in ms
pg_in_recoverygaugejob, ins, ip, instance, clsserver is in recovery mode? 1 for yes 0 for no
pg_index_idx_blks_hitcounterdatname, relname, job, ins, relid, ip, instance, cls, idxnameNumber of buffer hits in this index
pg_index_idx_blks_readcounterdatname, relname, job, ins, relid, ip, instance, cls, idxnameNumber of disk blocks read from this index
pg_index_idx_scancounterdatname, relname, job, ins, relid, ip, instance, cls, idxnameNumber of index scans initiated on this index
pg_index_idx_tup_fetchcounterdatname, relname, job, ins, relid, ip, instance, cls, idxnameNumber of live table rows fetched by simple index scans using this index
pg_index_idx_tup_readcounterdatname, relname, job, ins, relid, ip, instance, cls, idxnameNumber of index entries returned by scans on this index
pg_index_relpagesgaugedatname, relname, job, ins, relid, ip, instance, cls, idxnameSize of the on-disk representation of this index in pages
pg_index_reltuplesgaugedatname, relname, job, ins, relid, ip, instance, cls, idxnameEstimate relation tuples
pg_insert_lsncounterjob, ins, ip, instance, clsprimary only, location of current wal inserting
pg_io_evictionscountertype, job, ins, object, ip, context, instance, clsNumber of times a block has been written out from a shared or local buffer
pg_io_extend_timecountertype, job, ins, object, ip, context, instance, clsTime spent in extend operations in seconds
pg_io_extendscountertype, job, ins, object, ip, context, instance, clsNumber of relation extend operations, each of the size specified in op_bytes.
pg_io_fsync_timecountertype, job, ins, object, ip, context, instance, clsTime spent in fsync operations in seconds
pg_io_fsyncscountertype, job, ins, object, ip, context, instance, clsNumber of fsync calls. These are only tracked in context normal
pg_io_hitscountertype, job, ins, object, ip, context, instance, clsThe number of times a desired block was found in a shared buffer.
pg_io_op_bytesgaugetype, job, ins, object, ip, context, instance, clsThe number of bytes per unit of I/O read, written, or extended. 8192 by default
pg_io_read_timecountertype, job, ins, object, ip, context, instance, clsTime spent in read operations in seconds
pg_io_readscountertype, job, ins, object, ip, context, instance, clsNumber of read operations, each of the size specified in op_bytes.
pg_io_reset_timegaugetype, job, ins, object, ip, context, instance, clsTimestamp at which these statistics were last reset
pg_io_reusescountertype, job, ins, object, ip, context, instance, clsThe number of times an existing buffer in reused
pg_io_write_timecountertype, job, ins, object, ip, context, instance, clsTime spent in write operations in seconds
pg_io_writeback_timecountertype, job, ins, object, ip, context, instance, clsTime spent in writeback operations in seconds
pg_io_writebackscountertype, job, ins, object, ip, context, instance, clsNumber of units of size op_bytes which the process requested the kernel write out to permanent storage.
pg_io_writescountertype, job, ins, object, ip, context, instance, clsNumber of write operations, each of the size specified in op_bytes.
pg_is_in_recoverygaugejob, ins, ip, instance, cls1 if in recovery mode
pg_is_wal_replay_pausedgaugejob, ins, ip, instance, cls1 if wal play paused
pg_laggaugejob, ins, ip, instance, clsreplica only, replication lag in seconds
pg_last_replay_timegaugejob, ins, ip, instance, clstime when last transaction been replayed
pg_lock_countgaugedatname, job, ins, ip, mode, instance, clsNumber of locks of corresponding mode and database
pg_lsncounterjob, ins, ip, instance, clslog sequence number, current write location
pg_meta_infogaugecls, extensions, version, job, ins, primary_conninfo, conf_path, hba_path, ip, cluster_id, instance, listen_port, wal_level, ver_num, cluster_name, data_dirconstant 1
pg_query_callscounterdatname, query, job, ins, ip, instance, clsNumber of times the statement was executed
pg_query_exec_timecounterdatname, query, job, ins, ip, instance, clsTotal time spent executing the statement, in seconds
pg_query_io_timecounterdatname, query, job, ins, ip, instance, clsTotal time the statement spent reading and writing blocks, in seconds
pg_query_rowscounterdatname, query, job, ins, ip, instance, clsTotal number of rows retrieved or affected by the statement
pg_query_sblk_dirtiedcounterdatname, query, job, ins, ip, instance, clsTotal number of shared blocks dirtied by the statement
pg_query_sblk_hitcounterdatname, query, job, ins, ip, instance, clsTotal number of shared block cache hits by the statement
pg_query_sblk_readcounterdatname, query, job, ins, ip, instance, clsTotal number of shared blocks read by the statement
pg_query_sblk_writtencounterdatname, query, job, ins, ip, instance, clsTotal number of shared blocks written by the statement
pg_query_wal_bytescounterdatname, query, job, ins, ip, instance, clsTotal amount of WAL bytes generated by the statement
pg_receive_lsncounterjob, ins, ip, instance, clsreplica only, location of wal synced to disk
pg_recovery_backup_end_lsncounterjob, ins, ip, instance, clsBackup end location
pg_recovery_backup_start_lsncounterjob, ins, ip, instance, clsBackup start location
pg_recovery_min_lsncounterjob, ins, ip, instance, clsMinimum recovery ending location
pg_recovery_min_timelinecounterjob, ins, ip, instance, clsMin recovery ending loc’s timeline
pg_recovery_prefetch_block_distancegaugejob, ins, ip, instance, clsHow many blocks ahead the prefetcher is looking
pg_recovery_prefetch_hitcounterjob, ins, ip, instance, clsNumber of blocks not prefetched because they were already in the buffer pool
pg_recovery_prefetch_io_depthgaugejob, ins, ip, instance, clsHow many prefetches have been initiated but are not yet known to have completed
pg_recovery_prefetch_prefetchcounterjob, ins, ip, instance, clsNumber of blocks prefetched because they were not in the buffer pool
pg_recovery_prefetch_reset_timecounterjob, ins, ip, instance, clsTime at which these recovery prefetch statistics were last reset
pg_recovery_prefetch_skip_fpwgaugejob, ins, ip, instance, clsNumber of blocks not prefetched because a full page image was included in the WAL
pg_recovery_prefetch_skip_initcounterjob, ins, ip, instance, clsNumber of blocks not prefetched because they would be zero-initialized
pg_recovery_prefetch_skip_newcounterjob, ins, ip, instance, clsNumber of blocks not prefetched because they didn’t exist yet
pg_recovery_prefetch_skip_repcounterjob, ins, ip, instance, clsNumber of blocks not prefetched because they were already recently prefetched
pg_recovery_prefetch_wal_distancegaugejob, ins, ip, instance, clsHow many bytes ahead the prefetcher is looking
pg_recovery_require_recordgaugejob, ins, ip, instance, clsEnd-of-backup record required
pg_recv_flush_lsncounterstate, slot_name, job, ins, ip, instance, cls, sender_host, sender_portLast write-ahead log location already received and flushed to disk
pg_recv_flush_tlicounterstate, slot_name, job, ins, ip, instance, cls, sender_host, sender_portTimeline number of last write-ahead log location received and flushed to disk
pg_recv_init_lsncounterstate, slot_name, job, ins, ip, instance, cls, sender_host, sender_portFirst write-ahead log location used when WAL receiver is started
pg_recv_init_tlicounterstate, slot_name, job, ins, ip, instance, cls, sender_host, sender_portFirst timeline number used when WAL receiver is started
pg_recv_msg_recv_timegaugestate, slot_name, job, ins, ip, instance, cls, sender_host, sender_portReceipt time of last message received from origin WAL sender
pg_recv_msg_send_timegaugestate, slot_name, job, ins, ip, instance, cls, sender_host, sender_portSend time of last message received from origin WAL sender
pg_recv_pidgaugestate, slot_name, job, ins, ip, instance, cls, sender_host, sender_portProcess ID of the WAL receiver process
pg_recv_reported_lsncounterstate, slot_name, job, ins, ip, instance, cls, sender_host, sender_portLast write-ahead log location reported to origin WAL sender
pg_recv_reported_timegaugestate, slot_name, job, ins, ip, instance, cls, sender_host, sender_portTime of last write-ahead log location reported to origin WAL sender
pg_recv_timegaugestate, slot_name, job, ins, ip, instance, cls, sender_host, sender_portTime of current snapshot
pg_recv_write_lsncounterstate, slot_name, job, ins, ip, instance, cls, sender_host, sender_portLast write-ahead log location already received and written to disk, but not flushed.
pg_relkind_countgaugedatname, job, ins, ip, instance, cls, relkindNumber of relations of corresponding relkind
pg_repl_backend_xmincounterpid, usename, address, job, ins, appname, ip, instance, clsThis standby’s xmin horizon reported by hot_standby_feedback.
pg_repl_client_portgaugepid, usename, address, job, ins, appname, ip, instance, clsTCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used
pg_repl_flush_diffgaugepid, usename, address, job, ins, appname, ip, instance, clsLast log position flushed to disk by this standby server diff with current lsn
pg_repl_flush_laggaugepid, usename, address, job, ins, appname, ip, instance, clsTime elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it
pg_repl_flush_lsncounterpid, usename, address, job, ins, appname, ip, instance, clsLast write-ahead log location flushed to disk by this standby server
pg_repl_launch_timecounterpid, usename, address, job, ins, appname, ip, instance, clsTime when this process was started, i.e., when the client connected to this WAL sender
pg_repl_lsncounterpid, usename, address, job, ins, appname, ip, instance, clsCurrent log position on this server
pg_repl_replay_diffgaugepid, usename, address, job, ins, appname, ip, instance, clsLast log position replayed into the database on this standby server diff with current lsn
pg_repl_replay_laggaugepid, usename, address, job, ins, appname, ip, instance, clsTime elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it
pg_repl_replay_lsncounterpid, usename, address, job, ins, appname, ip, instance, clsLast write-ahead log location replayed into the database on this standby server
pg_repl_reply_timegaugepid, usename, address, job, ins, appname, ip, instance, clsSend time of last reply message received from standby server
pg_repl_sent_diffgaugepid, usename, address, job, ins, appname, ip, instance, clsLast log position sent to this standby server diff with current lsn
pg_repl_sent_lsncounterpid, usename, address, job, ins, appname, ip, instance, clsLast write-ahead log location sent on this connection
pg_repl_stategaugepid, usename, address, job, ins, appname, ip, instance, clsCurrent WAL sender encoded state 0-4 for streaming startup catchup backup stopping
pg_repl_sync_prioritygaugepid, usename, address, job, ins, appname, ip, instance, clsPriority of this standby server for being chosen as the synchronous standby
pg_repl_sync_stategaugepid, usename, address, job, ins, appname, ip, instance, clsEncoded synchronous state of this standby server, 0-3 for async potential sync quorum
pg_repl_timecounterpid, usename, address, job, ins, appname, ip, instance, clsCurrent timestamp in unix epoch
pg_repl_write_diffgaugepid, usename, address, job, ins, appname, ip, instance, clsLast log position written to disk by this standby server diff with current lsn
pg_repl_write_laggaugepid, usename, address, job, ins, appname, ip, instance, clsTime elapsed between flushing recent WAL locally and receiving notification that this standby server has written it
pg_repl_write_lsncounterpid, usename, address, job, ins, appname, ip, instance, clsLast write-ahead log location written to disk by this standby server
pg_replay_lsncounterjob, ins, ip, instance, clsreplica only, location of wal applied
pg_seq_blks_hitcounterdatname, job, ins, ip, instance, cls, seqnameNumber of buffer hits in this sequence
pg_seq_blks_readcounterdatname, job, ins, ip, instance, cls, seqnameNumber of disk blocks read from this sequence
pg_seq_last_valuecounterdatname, job, ins, ip, instance, cls, seqnameThe last sequence value written to disk
pg_setting_block_sizegaugejob, ins, ip, instance, clspg page block size, 8192 by default
pg_setting_data_checksumsgaugejob, ins, ip, instance, clswhether data checksum is enabled, 1 enabled 0 disabled
pg_setting_max_connectionsgaugejob, ins, ip, instance, clsnumber of concurrent connections to the database server
pg_setting_max_locks_per_transactiongaugejob, ins, ip, instance, clsno more than this many distinct objects can be locked at any one time
pg_setting_max_prepared_transactionsgaugejob, ins, ip, instance, clsmaximum number of transactions that can be in the prepared state simultaneously
pg_setting_max_replication_slotsgaugejob, ins, ip, instance, clsmaximum number of replication slots
pg_setting_max_wal_sendersgaugejob, ins, ip, instance, clsmaximum number of concurrent connections from standby servers
pg_setting_max_worker_processesgaugejob, ins, ip, instance, clsmaximum number of background processes that the system can support
pg_setting_wal_log_hintsgaugejob, ins, ip, instance, clswhether wal_log_hints is enabled, 1 enabled 0 disabled
pg_size_bytesgaugedatname, job, ins, ip, instance, clsFile size in bytes
pg_slot_activegaugeslot_name, job, ins, ip, instance, clsTrue(1) if this slot is currently actively being used
pg_slot_catalog_xmincounterslot_name, job, ins, ip, instance, clsThe oldest transaction affecting the system catalogs that this slot needs the database to retain.
pg_slot_confirm_lsncounterslot_name, job, ins, ip, instance, clsThe address (LSN) up to which the logical slot’s consumer has confirmed receiving data.
pg_slot_reset_timecounterslot_name, job, ins, ip, instance, clsWhen statistics were last reset
pg_slot_restart_lsncounterslot_name, job, ins, ip, instance, clsThe address (LSN) of oldest WAL which still might be required by the consumer of this slot
pg_slot_retained_bytesgaugeslot_name, job, ins, ip, instance, clsSize of bytes that retained for this slot
pg_slot_safe_wal_sizegaugeslot_name, job, ins, ip, instance, clsbytes that can be written to WAL which will not make slot into lost
pg_slot_spill_bytescounterslot_name, job, ins, ip, instance, clsBytes that spilled to disk due to logical decode mem exceeding
pg_slot_spill_countcounterslot_name, job, ins, ip, instance, clsXacts that spilled to disk due to logical decode mem exceeding (a xact can be spilled multiple times)
pg_slot_spill_txnscounterslot_name, job, ins, ip, instance, clsXacts that spilled to disk due to logical decode mem exceeding (subtrans included)
pg_slot_stream_bytescounterslot_name, job, ins, ip, instance, clsBytes that streamed to decoding output plugin after mem exceed
pg_slot_stream_countcounterslot_name, job, ins, ip, instance, clsXacts that streamed to decoding output plugin after mem exceed (a xact can be streamed multiple times)
pg_slot_stream_txnscounterslot_name, job, ins, ip, instance, clsXacts that streamed to decoding output plugin after mem exceed
pg_slot_temporarygaugeslot_name, job, ins, ip, instance, clsTrue(1) if this is a temporary replication slot.
pg_slot_total_bytescounterslot_name, job, ins, ip, instance, clsNumber of decoded bytes sent to the decoding output plugin for this slot
pg_slot_total_txnscounterslot_name, job, ins, ip, instance, clsNumber of decoded xacts sent to the decoding output plugin for this slot
pg_slot_wal_statusgaugeslot_name, job, ins, ip, instance, clsWAL reserve status 0-3 means reserved,extended,unreserved,lost, -1 means other
pg_slot_xmincounterslot_name, job, ins, ip, instance, clsThe oldest transaction that this slot needs the database to retain.
pg_slru_blks_existscounterjob, ins, ip, instance, clsNumber of blocks checked for existence for this SLRU
pg_slru_blks_hitcounterjob, ins, ip, instance, clsNumber of times disk blocks were found already in the SLRU, so that a read was not necessary
pg_slru_blks_readcounterjob, ins, ip, instance, clsNumber of disk blocks read for this SLRU
pg_slru_blks_writtencounterjob, ins, ip, instance, clsNumber of disk blocks written for this SLRU
pg_slru_blks_zeroedcounterjob, ins, ip, instance, clsNumber of blocks zeroed during initializations
pg_slru_flushescounterjob, ins, ip, instance, clsNumber of flushes of dirty data for this SLRU
pg_slru_reset_timecounterjob, ins, ip, instance, clsTime at which these statistics were last reset
pg_slru_truncatescounterjob, ins, ip, instance, clsNumber of truncates for this SLRU
pg_ssl_disabledgaugejob, ins, ip, instance, clsNumber of client connection that does not use ssl
pg_ssl_enabledgaugejob, ins, ip, instance, clsNumber of client connection that use ssl
pg_sync_standby_enabledgaugejob, ins, ip, names, instance, clsSynchronous commit enabled, 1 if enabled, 0 if disabled
pg_table_agegaugedatname, relname, job, ins, ip, instance, clsAge of this table in vacuum cycles
pg_table_analyze_countcounterdatname, relname, job, ins, ip, instance, clsNumber of times this table has been manually analyzed
pg_table_autoanalyze_countcounterdatname, relname, job, ins, ip, instance, clsNumber of times this table has been analyzed by the autovacuum daemon
pg_table_autovacuum_countcounterdatname, relname, job, ins, ip, instance, clsNumber of times this table has been vacuumed by the autovacuum daemon
pg_table_frozenxidcounterdatname, relname, job, ins, ip, instance, clsAll txid before this have been frozen on this table
pg_table_heap_blks_hitcounterdatname, relname, job, ins, ip, instance, clsNumber of buffer hits in this table
pg_table_heap_blks_readcounterdatname, relname, job, ins, ip, instance, clsNumber of disk blocks read from this table
pg_table_idx_blks_hitcounterdatname, relname, job, ins, ip, instance, clsNumber of buffer hits in all indexes on this table
pg_table_idx_blks_readcounterdatname, relname, job, ins, ip, instance, clsNumber of disk blocks read from all indexes on this table
pg_table_idx_scancounterdatname, relname, job, ins, ip, instance, clsNumber of index scans initiated on this table
pg_table_idx_tup_fetchcounterdatname, relname, job, ins, ip, instance, clsNumber of live rows fetched by index scans
pg_table_kindgaugedatname, relname, job, ins, ip, instance, clsRelation kind r/table/114
pg_table_n_dead_tupgaugedatname, relname, job, ins, ip, instance, clsEstimated number of dead rows
pg_table_n_ins_since_vacuumgaugedatname, relname, job, ins, ip, instance, clsEstimated number of rows inserted since this table was last vacuumed
pg_table_n_live_tupgaugedatname, relname, job, ins, ip, instance, clsEstimated number of live rows
pg_table_n_mod_since_analyzegaugedatname, relname, job, ins, ip, instance, clsEstimated number of rows modified since this table was last analyzed
pg_table_n_tup_delcounterdatname, relname, job, ins, ip, instance, clsNumber of rows deleted
pg_table_n_tup_hot_updcounterdatname, relname, job, ins, ip, instance, clsNumber of rows HOT updated (i.e with no separate index update required)
pg_table_n_tup_inscounterdatname, relname, job, ins, ip, instance, clsNumber of rows inserted
pg_table_n_tup_modcounterdatname, relname, job, ins, ip, instance, clsNumber of rows modified (insert + update + delete)
pg_table_n_tup_newpage_updcounterdatname, relname, job, ins, ip, instance, clsNumber of rows updated where the successor version goes onto a new heap page
pg_table_n_tup_updcounterdatname, relname, job, ins, ip, instance, clsNumber of rows updated (includes HOT updated rows)
pg_table_ncolsgaugedatname, relname, job, ins, ip, instance, clsNumber of columns in the table
pg_table_pagesgaugedatname, relname, job, ins, ip, instance, clsSize of the on-disk representation of this table in pages
pg_table_relidgaugedatname, relname, job, ins, ip, instance, clsRelation oid of this table
pg_table_seq_scancounterdatname, relname, job, ins, ip, instance, clsNumber of sequential scans initiated on this table
pg_table_seq_tup_readcounterdatname, relname, job, ins, ip, instance, clsNumber of live rows fetched by sequential scans
pg_table_size_bytesgaugedatname, relname, job, ins, ip, instance, clsTotal bytes of this table (including toast, index, toast index)
pg_table_size_indexsizegaugedatname, relname, job, ins, ip, instance, clsBytes of all related indexes of this table
pg_table_size_relsizegaugedatname, relname, job, ins, ip, instance, clsBytes of this table itself (main, vm, fsm)
pg_table_size_toastsizegaugedatname, relname, job, ins, ip, instance, clsBytes of toast tables of this table
pg_table_tbl_scancounterdatname, relname, job, ins, ip, instance, clsNumber of scans initiated on this table
pg_table_tup_readcounterdatname, relname, job, ins, ip, instance, clsNumber of live rows fetched by scans
pg_table_tuplescounterdatname, relname, job, ins, ip, instance, clsAll txid before this have been frozen on this table
pg_table_vacuum_countcounterdatname, relname, job, ins, ip, instance, clsNumber of times this table has been manually vacuumed (not counting VACUUM FULL)
pg_timestampgaugejob, ins, ip, instance, clsdatabase current timestamp
pg_upgaugejob, ins, ip, instance, clslast scrape was able to connect to the server: 1 for yes, 0 for no
pg_uptimegaugejob, ins, ip, instance, clsseconds since postmaster start
pg_versiongaugejob, ins, ip, instance, clsserver version number
pg_wait_countgaugedatname, job, ins, event, ip, instance, clsCount of WaitEvent on target database
pg_wal_buffers_fullcounterjob, ins, ip, instance, clsNumber of times WAL data was written to disk because WAL buffers became full
pg_wal_bytescounterjob, ins, ip, instance, clsTotal amount of WAL generated in bytes
pg_wal_fpicounterjob, ins, ip, instance, clsTotal number of WAL full page images generated
pg_wal_recordscounterjob, ins, ip, instance, clsTotal number of WAL records generated
pg_wal_reset_timecounterjob, ins, ip, instance, clsWhen statistics were last reset
pg_wal_synccounterjob, ins, ip, instance, clsNumber of times WAL files were synced to disk via issue_xlog_fsync request
pg_wal_sync_timecounterjob, ins, ip, instance, clsTotal amount of time spent syncing WAL files to disk via issue_xlog_fsync request, in seconds
pg_wal_writecounterjob, ins, ip, instance, clsNumber of times WAL buffers were written out to disk via XLogWrite request.
pg_wal_write_timecounterjob, ins, ip, instance, clsTotal amount of time spent writing WAL buffers to disk via XLogWrite request in seconds
pg_write_lsncounterjob, ins, ip, instance, clsprimary only, location of current wal writing
pg_xact_xmaxcounterjob, ins, ip, instance, clsFirst as-yet-unassigned txid. txid >= this are invisible.
pg_xact_xmincounterjob, ins, ip, instance, clsEarliest txid that is still active
pg_xact_xnumgaugejob, ins, ip, instance, clsCurrent active transaction count
pgbouncer:cls:load1Unknownjob, clsN/A
pgbouncer:cls:load15Unknownjob, clsN/A
pgbouncer:cls:load5Unknownjob, clsN/A
pgbouncer:db:conn_usageUnknowndatname, job, ins, ip, instance, host, cls, real_datname, portN/A
pgbouncer:db:conn_usage_reserveUnknowndatname, job, ins, ip, instance, host, cls, real_datname, portN/A
pgbouncer:db:pool_current_connUnknowndatname, job, ins, ip, instance, host, cls, real_datname, portN/A
pgbouncer:db:pool_disabledUnknowndatname, job, ins, ip, instance, host, cls, real_datname, portN/A
pgbouncer:db:pool_max_connUnknowndatname, job, ins, ip, instance, host, cls, real_datname, portN/A
pgbouncer:db:pool_pausedUnknowndatname, job, ins, ip, instance, host, cls, real_datname, portN/A
pgbouncer:db:pool_reserve_sizeUnknowndatname, job, ins, ip, instance, host, cls, real_datname, portN/A
pgbouncer:db:pool_sizeUnknowndatname, job, ins, ip, instance, host, cls, real_datname, portN/A
pgbouncer:ins:free_clientsUnknownjob, ins, ip, instance, clsN/A
pgbouncer:ins:free_serversUnknownjob, ins, ip, instance, clsN/A
pgbouncer:ins:load1Unknownjob, ins, ip, instance, clsN/A
pgbouncer:ins:load15Unknownjob, ins, ip, instance, clsN/A
pgbouncer:ins:load5Unknownjob, ins, ip, instance, clsN/A
pgbouncer:ins:login_clientsUnknownjob, ins, ip, instance, clsN/A
pgbouncer:ins:pool_databasesUnknownjob, ins, ip, instance, clsN/A
pgbouncer:ins:pool_usersUnknownjob, ins, ip, instance, clsN/A
pgbouncer:ins:poolsUnknownjob, ins, ip, instance, clsN/A
pgbouncer:ins:used_clientsUnknownjob, ins, ip, instance, clsN/A
pgbouncer_database_current_connectionsgaugedatname, job, ins, ip, instance, host, cls, real_datname, portCurrent number of connections for this database
pgbouncer_database_disabledgaugedatname, job, ins, ip, instance, host, cls, real_datname, portTrue(1) if this database is currently disabled, else 0
pgbouncer_database_max_connectionsgaugedatname, job, ins, ip, instance, host, cls, real_datname, portMaximum number of allowed connections for this database
pgbouncer_database_min_pool_sizegaugedatname, job, ins, ip, instance, host, cls, real_datname, portMinimum number of server connections
pgbouncer_database_pausedgaugedatname, job, ins, ip, instance, host, cls, real_datname, portTrue(1) if this database is currently paused, else 0
pgbouncer_database_pool_sizegaugedatname, job, ins, ip, instance, host, cls, real_datname, portMaximum number of server connections
pgbouncer_database_reserve_poolgaugedatname, job, ins, ip, instance, host, cls, real_datname, portMaximum number of additional connections for this database
pgbouncer_exporter_agent_upUnknownjob, ins, ip, instance, clsN/A
pgbouncer_exporter_last_scrape_timegaugejob, ins, ip, instance, clsseconds exporter spending on scrapping
pgbouncer_exporter_query_cache_ttlgaugedatname, query, job, ins, ip, instance, clstimes to live of query cache
pgbouncer_exporter_query_scrape_durationgaugedatname, query, job, ins, ip, instance, clsseconds query spending on scrapping
pgbouncer_exporter_query_scrape_error_countgaugedatname, query, job, ins, ip, instance, clstimes the query failed
pgbouncer_exporter_query_scrape_hit_countgaugedatname, query, job, ins, ip, instance, clsnumbers been scrapped from this query
pgbouncer_exporter_query_scrape_metric_countgaugedatname, query, job, ins, ip, instance, clsnumbers of metrics been scrapped from this query
pgbouncer_exporter_query_scrape_total_countgaugedatname, query, job, ins, ip, instance, clstimes exporter server was scraped for metrics
pgbouncer_exporter_scrape_durationgaugejob, ins, ip, instance, clsseconds exporter spending on scrapping
pgbouncer_exporter_scrape_error_countcounterjob, ins, ip, instance, clstimes exporter was scraped for metrics and failed
pgbouncer_exporter_scrape_total_countcounterjob, ins, ip, instance, clstimes exporter was scraped for metrics
pgbouncer_exporter_server_scrape_durationgaugedatname, job, ins, ip, instance, clsseconds exporter server spending on scrapping
pgbouncer_exporter_server_scrape_total_countgaugedatname, job, ins, ip, instance, clstimes exporter server was scraped for metrics
pgbouncer_exporter_server_scrape_total_secondsgaugedatname, job, ins, ip, instance, clsseconds exporter server spending on scrapping
pgbouncer_exporter_upgaugejob, ins, ip, instance, clsalways be 1 if your could retrieve metrics
pgbouncer_exporter_uptimegaugejob, ins, ip, instance, clsseconds since exporter primary server inited
pgbouncer_in_recoverygaugejob, ins, ip, instance, clsserver is in recovery mode? 1 for yes 0 for no
pgbouncer_list_itemsgaugejob, ins, ip, instance, list, clsNumber of corresponding pgbouncer object
pgbouncer_pool_active_cancel_clientsgaugedatname, job, ins, ip, instance, user, cls, pool_modeClient connections that have forwarded query cancellations to the server and are waiting for the server response.
pgbouncer_pool_active_cancel_serversgaugedatname, job, ins, ip, instance, user, cls, pool_modeServer connections that are currently forwarding a cancel request
pgbouncer_pool_active_clientsgaugedatname, job, ins, ip, instance, user, cls, pool_modeClient connections that are linked to server connection and can process queries
pgbouncer_pool_active_serversgaugedatname, job, ins, ip, instance, user, cls, pool_modeServer connections that are linked to a client
pgbouncer_pool_cancel_clientsgaugedatname, job, ins, ip, instance, user, cls, pool_modeClient connections that have not forwarded query cancellations to the server yet.
pgbouncer_pool_cancel_serversgaugedatname, job, ins, ip, instance, user, cls, pool_modecancel requests have completed that were sent to cancel a query on this server
pgbouncer_pool_idle_serversgaugedatname, job, ins, ip, instance, user, cls, pool_modeServer connections that are unused and immediately usable for client queries
pgbouncer_pool_login_serversgaugedatname, job, ins, ip, instance, user, cls, pool_modeServer connections currently in the process of logging in
pgbouncer_pool_maxwaitgaugedatname, job, ins, ip, instance, user, cls, pool_modeHow long the first(oldest) client in the queue has waited, in seconds, key metric
pgbouncer_pool_maxwait_usgaugedatname, job, ins, ip, instance, user, cls, pool_modeMicrosecond part of the maximum waiting time.
pgbouncer_pool_tested_serversgaugedatname, job, ins, ip, instance, user, cls, pool_modeServer connections that are currently running reset or check query
pgbouncer_pool_used_serversgaugedatname, job, ins, ip, instance, user, cls, pool_modeServer connections that have been idle for more than server_check_delay (means have to run check query)
pgbouncer_pool_waiting_clientsgaugedatname, job, ins, ip, instance, user, cls, pool_modeClient connections that have sent queries but have not yet got a server connection
pgbouncer_stat_avg_query_countgaugedatname, job, ins, ip, instance, clsAverage queries per second in last stat period
pgbouncer_stat_avg_query_timegaugedatname, job, ins, ip, instance, clsAverage query duration, in seconds
pgbouncer_stat_avg_recvgaugedatname, job, ins, ip, instance, clsAverage received (from clients) bytes per second
pgbouncer_stat_avg_sentgaugedatname, job, ins, ip, instance, clsAverage sent (to clients) bytes per second
pgbouncer_stat_avg_wait_timegaugedatname, job, ins, ip, instance, clsTime spent by clients waiting for a server, in seconds (average per second).
pgbouncer_stat_avg_xact_countgaugedatname, job, ins, ip, instance, clsAverage transactions per second in last stat period
pgbouncer_stat_avg_xact_timegaugedatname, job, ins, ip, instance, clsAverage transaction duration, in seconds
pgbouncer_stat_total_query_countgaugedatname, job, ins, ip, instance, clsTotal number of SQL queries pooled by pgbouncer
pgbouncer_stat_total_query_timecounterdatname, job, ins, ip, instance, clsTotal number of seconds spent when executing queries
pgbouncer_stat_total_receivedcounterdatname, job, ins, ip, instance, clsTotal volume in bytes of network traffic received by pgbouncer
pgbouncer_stat_total_sentcounterdatname, job, ins, ip, instance, clsTotal volume in bytes of network traffic sent by pgbouncer
pgbouncer_stat_total_wait_timecounterdatname, job, ins, ip, instance, clsTime spent by clients waiting for a server, in seconds
pgbouncer_stat_total_xact_countgaugedatname, job, ins, ip, instance, clsTotal number of SQL transactions pooled by pgbouncer
pgbouncer_stat_total_xact_timecounterdatname, job, ins, ip, instance, clsTotal number of seconds spent when in a transaction
pgbouncer_upgaugejob, ins, ip, instance, clslast scrape was able to connect to the server: 1 for yes, 0 for no
pgbouncer_versiongaugejob, ins, ip, instance, clsserver version number
process_cpu_seconds_totalcounterjob, ins, ip, instance, clsTotal user and system CPU time spent in seconds.
process_max_fdsgaugejob, ins, ip, instance, clsMaximum number of open file descriptors.
process_open_fdsgaugejob, ins, ip, instance, clsNumber of open file descriptors.
process_resident_memory_bytesgaugejob, ins, ip, instance, clsResident memory size in bytes.
process_start_time_secondsgaugejob, ins, ip, instance, clsStart time of the process since unix epoch in seconds.
process_virtual_memory_bytesgaugejob, ins, ip, instance, clsVirtual memory size in bytes.
process_virtual_memory_max_bytesgaugejob, ins, ip, instance, clsMaximum amount of virtual memory available in bytes.
promhttp_metric_handler_requests_in_flightgaugejob, ins, ip, instance, clsCurrent number of scrapes being served.
promhttp_metric_handler_requests_totalcountercode, job, ins, ip, instance, clsTotal number of scrapes by HTTP status code.
scrape_duration_secondsUnknownjob, ins, ip, instance, clsN/A
scrape_samples_post_metric_relabelingUnknownjob, ins, ip, instance, clsN/A
scrape_samples_scrapedUnknownjob, ins, ip, instance, clsN/A
scrape_series_addedUnknownjob, ins, ip, instance, clsN/A
upUnknownjob, ins, ip, instance, clsN/A

10.13 - Parameters

Customize PostgreSQL clusters with 120 parameters in the PGSQL module

The PGSQL module needs to be installed on nodes managed by Pigsty (i.e., nodes that have the NODE module configured), and also requires an available ETCD cluster in your deployment to store cluster metadata.

Installing the PGSQL module on a single node will create a standalone PGSQL server/instance, i.e., a primary instance. Installing on additional nodes will create read replicas, which can serve as standby instances and handle read-only requests. You can also create offline instances for ETL/OLAP/interactive queries, use sync standby and quorum commit to improve data consistency, or even set up standby clusters and delayed clusters to quickly respond to data loss caused by human errors and software defects.

You can define multiple PGSQL clusters and further organize them into a horizontal sharding cluster: Pigsty natively supports Citus cluster groups, allowing you to upgrade your standard PGSQL cluster in-place to a distributed database cluster.

Pigsty v4.0 uses PostgreSQL 18 by default and introduces new parameters such as pg_io_method and pgbackrest_exporter.


SectionDescription
PG_IDPostgreSQL cluster and instance identity parameters
PG_BUSINESSBusiness users, databases, services and access control rule definition
PG_INSTALLPostgreSQL installation: version, paths, packages
PG_BOOTSTRAPPostgreSQL cluster initialization: Patroni high availability
PG_PROVISIONPostgreSQL cluster template provisioning: roles, privileges, extensions
PG_BACKUPpgBackRest backup and recovery configuration
PG_ACCESSService exposure, connection pooling, VIP, DNS client access config
PG_MONITORPostgreSQL monitoring exporter configuration
PG_REMOVEPostgreSQL instance cleanup and uninstall configuration

Parameter Overview


PG_ID parameters are used to define PostgreSQL cluster and instance identity, including cluster name, instance sequence number, role, shard, and other core identity parameters.

ParameterTypeLevelDescription
pg_modeenumCpgsql cluster mode: pgsql,citus,mssql,mysql,polar,ivory,oracle,gpsql
pg_clusterstringCpgsql cluster name, REQUIRED identity parameter
pg_seqintIpgsql instance seq number, REQUIRED identity parameter
pg_roleenumIpgsql instance role, REQUIRED, could be primary, replica, offline
pg_instancesdictIdefine multiple pg instances on node in {port:ins_vars} format
pg_upstreamipIrepl upstream ip addr for standby cluster or cascade replica
pg_shardstringCpgsql shard name, REQUIRED identity for sharding clusters like citus
pg_groupintCpgsql shard index, REQUIRED identity for sharding clusters like citus
gp_roleenumCgreenplum role of this cluster, could be master or segment
pg_exportersdictCadditional pg_exporters to monitor remote postgres instances
pg_offline_queryboolIset to true to mark this replica as offline instance for offline queries

PG_BUSINESS parameters are used to define business users, databases, services and access control rules, as well as default system user credentials.

ParameterTypeLevelDescription
pg_usersuser[]Cpostgres business users
pg_databasesdatabase[]Cpostgres business databases
pg_servicesservice[]Cpostgres business services
pg_hba_ruleshba[]Cbusiness hba rules for postgres
pgb_hba_ruleshba[]Cbusiness hba rules for pgbouncer
pg_replication_usernameusernameGpostgres replication username, replicator by default
pg_replication_passwordpasswordGpostgres replication password, DBUser.Replicator by default
pg_admin_usernameusernameGpostgres admin username, dbuser_dba by default
pg_admin_passwordpasswordGpostgres admin password in plain text, DBUser.DBA by default
pg_monitor_usernameusernameGpostgres monitor username, dbuser_monitor by default
pg_monitor_passwordpasswordGpostgres monitor password, DBUser.Monitor by default
pg_dbsu_passwordpasswordG/Cdbsu password, empty string disables it by default, best not set

PG_INSTALL parameters are used to configure PostgreSQL installation options, including version, paths, packages, and extensions.

ParameterTypeLevelDescription
pg_dbsuusernameCos dbsu name, postgres by default, better not change it
pg_dbsu_uidintCos dbsu uid and gid, 26 for default postgres user and group
pg_dbsu_sudoenumCdbsu sudo privilege, none,limit,all,nopass. limit by default
pg_dbsu_homepathCpostgresql home directory, /var/lib/pgsql by default
pg_dbsu_ssh_exchangeboolCexchange postgres dbsu ssh key among same pgsql cluster
pg_versionenumCpostgres major version to be installed, 18 by default
pg_bin_dirpathCpostgres binary dir, /usr/pgsql/bin by default
pg_log_dirpathCpostgres log dir, /pg/log/postgres by default
pg_packagesstring[]Cpg packages to be installed, ${pg_version} will be replaced
pg_extensionsstring[]Cpg extensions to be installed, ${pg_version} will be replaced

PG_BOOTSTRAP parameters are used to configure PostgreSQL cluster initialization, including Patroni high availability, data directory, storage, networking, encoding, and other core settings.

ParameterTypeLevelDescription
pg_datapathCpostgres data directory, /pg/data by default
pg_fs_mainpathCmountpoint/path for pg main data, /data/postgres by default
pg_fs_backuppathCmountpoint/path for pg backup data, /data/backups by default
pg_storage_typeenumCstorage type for pg main data, SSD,HDD. SSD by default
pg_dummy_filesizesizeCsize of /pg/dummy, hold 64MB disk space for emergency use
pg_listenip(s)C/Ipostgres/pgbouncer listen addr, comma separated list, 0.0.0.0
pg_portportCpostgres listen port, 5432 by default
pg_localhostpathCpostgres unix socket dir for localhost connection
pg_namespacepathCtop level key namespace in etcd, used by patroni & vip
patroni_enabledboolCif disabled, no postgres cluster will be created during init
patroni_modeenumCpatroni working mode: default,pause,remove
patroni_portportCpatroni listen port, 8008 by default
patroni_log_dirpathCpatroni log dir, /pg/log/patroni by default
patroni_ssl_enabledboolGsecure patroni RestAPI communications with SSL?
patroni_watchdog_modeenumCpatroni watchdog mode: automatic,required,off. off by default
patroni_usernameusernameCpatroni restapi username, postgres by default
patroni_passwordpasswordCpatroni restapi password, Patroni.API by default
pg_primary_dbstringCprimary database name, used by citus,etc. postgres by default
pg_parametersdictCextra parameters in postgresql.auto.conf
pg_filespath[]Cextra files to be copied to PGDATA (e.g. license files)
pg_confenumCconfig template: oltp,olap,crit,tiny. oltp.yml by default
pg_max_connintCpostgres max connections, auto will use recommended value
pg_shared_buffer_ratiofloatCpostgres shared buffer memory ratio, 0.25 by default, 0.1~0.4
pg_rtointCrecovery time objective in seconds, 30s by default
pg_rpointCrecovery point objective in bytes, 1MiB by default
pg_libsstringCpreloaded libraries, pg_stat_statements,auto_explain by default
pg_delayintervalIWAL replay apply delay for standby cluster, for delayed replica
pg_checksumboolCenable data checksum for postgres cluster?
pg_pwd_encenumCpassword encryption algorithm: fixed to scram-sha-256
pg_encodingenumCdatabase cluster encoding, UTF8 by default
pg_localeenumCdatabase cluster locale, C by default
pg_lc_collateenumCdatabase cluster collate, C by default
pg_lc_ctypeenumCdatabase character type, C by default
pg_io_methodenumCPostgreSQL IO method: auto, sync, worker, io_uring
pg_etcd_passwordpasswordCetcd password for this PostgreSQL cluster, cluster name by default
pgsodium_keystringCpgsodium encryption master key, 64 hex digits, sha256(pg_cluster)
pgsodium_getkey_scriptpathCpgsodium getkey script path, uses template pgsodium_getkey

PG_PROVISION parameters are used to configure PostgreSQL cluster template provisioning, including default roles, privileges, schemas, extensions, and HBA rules.

ParameterTypeLevelDescription
pg_provisionboolCprovision postgres cluster content after bootstrap?
pg_initstringG/Cinit script for cluster template, pg-init by default
pg_default_rolesrole[]G/Cdefault predefined roles and system users in postgres
pg_default_privilegesstring[]G/Cdefault privileges when created by admin user
pg_default_schemasstring[]G/Cdefault schemas to be created
pg_default_extensionsextension[]G/Cdefault extensions to be created
pg_reloadboolAreload postgres config after hba changes?
pg_default_hba_ruleshba[]G/Cpostgres default host-based auth rules, global default HBA
pgb_default_hba_ruleshba[]G/Cpgbouncer default host-based auth rules, global default HBA

PG_BACKUP parameters are used to configure pgBackRest backup and recovery, including repository type, paths, and retention policies.

ParameterTypeLevelDescription
pgbackrest_enabledboolCenable pgbackrest on pgsql host?
pgbackrest_cleanboolCremove previous pg backup data during init?
pgbackrest_log_dirpathCpgbackrest log dir, /pg/log/pgbackrest by default
pgbackrest_methodenumCpgbackrest repo method: local,minio,etc…
pgbackrest_init_backupboolCperform full backup after init? true by default
pgbackrest_repodictG/Cpgbackrest repo definition

PG_ACCESS parameters are used to configure service exposure, connection pooling, VIP, DNS, and other client access options.

ParameterTypeLevelDescription
pgbouncer_enabledboolCif disabled, pgbouncer will not be configured
pgbouncer_portportCpgbouncer listen port, 6432 by default
pgbouncer_log_dirpathCpgbouncer log dir, /pg/log/pgbouncer by default
pgbouncer_auth_queryboolCuse AuthQuery to get unlisted business users from postgres?
pgbouncer_poolmodeenumCpool mode: transaction,session,statement. transaction by default
pgbouncer_sslmodeenumCpgbouncer client ssl mode, disabled by default
pgbouncer_ignore_paramstring[]Cpgbouncer ignore startup parameters list
pg_weightintIrelative load balancing weight in service, 0-255, 100 by default
pg_service_providerstringG/Cdedicated haproxy node group name, or use local haproxy
pg_default_service_destenumG/Cdefault service dest if svc.dest=‘default’: postgres or pgbouncer
pg_default_servicesservice[]G/Cpostgres default service definition list, shared globally
pg_vip_enabledboolCenable L2 VIP for pgsql primary? disabled by default
pg_vip_addresscidr4Cvip address in <ipv4>/<mask> format, required if vip enabled
pg_vip_interfacestringC/Ivip network interface to bindg, eth0 by default
pg_dns_suffixstringCpgsql dns suffix, empty by default
pg_dns_targetenumCPG DNS resolves to: auto, primary, vip, none, or specific IP

PG_MONITOR parameters are used to configure PostgreSQL monitoring exporters, including pg_exporter, pgbouncer_exporter, and pgbackrest_exporter.

ParameterTypeLevelDescription
pg_exporter_enabledboolCenable pg_exporter on pgsql host?
pg_exporter_configstringCpg_exporter config file/template name
pg_exporter_cache_ttlsstringCpg_exporter collector ttl stages, ‘1,10,60,300’ by default
pg_exporter_portportCpg_exporter listen port, 9630 by default
pg_exporter_paramsstringCextra URL parameters for pg_exporter dsn
pg_exporter_urlpgurlCoverwrite auto-generated postgres DSN connection string
pg_exporter_auto_discoveryboolCenable auto database discovery for monitoring? enabled
pg_exporter_exclude_databasestringCexcluded database list when auto-discovery, comma separated
pg_exporter_include_databasestringConly monitor these databases when auto-discovery enabled
pg_exporter_connect_timeoutintCpg_exporter connect timeout in ms, 200 by default
pg_exporter_optionsargCextra command line options for pg_exporter
pgbouncer_exporter_enabledboolCenable pgbouncer_exporter on pgsql host?
pgbouncer_exporter_portportCpgbouncer_exporter listen port, 9631 by default
pgbouncer_exporter_urlpgurlCoverwrite auto-generated pgbouncer dsn connection string
pgbouncer_exporter_optionsargCextra command line options for pgbouncer_exporter
pgbackrest_exporter_enabledboolCenable pgbackrest_exporter on pgsql host?
pgbackrest_exporter_portportCpgbackrest_exporter listen port, 9854 by default
pgbackrest_exporter_optionsargCextra command line options for pgbackrest_exporter

PG_REMOVE parameters are used to configure PostgreSQL instance cleanup and uninstall behavior, including data directory, backup, and package removal control.

ParameterTypeLevelDescription
pg_rm_databoolG/C/Aremove postgres data directory when removing instance?
pg_rm_backupboolG/C/Aremove pgbackrest backup when removing primary?
pg_rm_pkgboolG/C/Auninstall related packages when removing pgsql instance?
pg_safeguardboolG/C/Aprevent accidental pgsql cleanup operations? false

PG_ID

Here are commonly used parameters for identifying entities in the PGSQL module: clusters, instances, services, etc…

# pg_cluster:           #CLUSTER  # pgsql cluster name, required identity parameter
# pg_seq: 0             #INSTANCE # pgsql instance seq number, required identity parameter
# pg_role: replica      #INSTANCE # pgsql role, required, could be primary,replica,offline
# pg_instances: {}      #INSTANCE # define multiple pg instances on node in `{port:ins_vars}` format
# pg_upstream:          #INSTANCE # repl upstream ip addr for standby cluster or cascade replica
# pg_shard:             #CLUSTER  # pgsql shard name, optional identity for sharding clusters
# pg_group: 0           #CLUSTER  # pgsql shard index number, optional identity for sharding clusters
# gp_role: master       #CLUSTER  # greenplum role of this cluster, could be master or segment
pg_offline_query: false #INSTANCE # set to true to enable offline query on this instance

You must explicitly specify these identity parameters, they have no default values:

NameTypeLevelDescription
pg_clusterstringCPG cluster name
pg_seqnumberIPG instance ID
pg_roleenumIPG instance role
pg_shardstringCShard name
pg_groupnumberCShard index
  • pg_cluster: Identifies the cluster name, configured at cluster level.
  • pg_role: Configured at instance level, identifies the role of the instance. Only primary role is treated specially. If not specified, defaults to replica role, with special delayed and offline roles.
  • pg_seq: Used to identify instances within a cluster, typically an integer starting from 0 or 1, once assigned it doesn’t change.
  • {{ pg_cluster }}-{{ pg_seq }} uniquely identifies an instance, i.e., pg_instance.
  • {{ pg_cluster }}-{{ pg_role }} identifies services within the cluster, i.e., pg_service.
  • pg_shard and pg_group are used for horizontal sharding clusters, only for citus, greenplum, and matrixdb.

pg_cluster, pg_role, pg_seq are core identity parameters, required for any Postgres cluster and must be explicitly specified. Here is an example:

pg-test:
  hosts:
    10.10.10.11: {pg_seq: 1, pg_role: replica}
    10.10.10.12: {pg_seq: 2, pg_role: primary}
    10.10.10.13: {pg_seq: 3, pg_role: replica}
  vars:
    pg_cluster: pg-test

All other parameters can be inherited from global or default configuration, but identity parameters must be explicitly specified and manually assigned.

pg_mode

Parameter Name: pg_mode, Type: enum, Level: C

PostgreSQL cluster mode, default value is pgsql, i.e., standard PostgreSQL cluster.

Available mode options include:

  • pgsql: Standard PostgreSQL cluster
  • citus: Citus distributed database cluster
  • mssql: Babelfish MSSQL wire protocol compatible kernel
  • mysql: OpenHalo/HaloDB MySQL wire protocol compatible kernel
  • ivory: IvorySQL Oracle compatible kernel
  • polar: PolarDB for PostgreSQL kernel
  • oracle: PolarDB for Oracle kernel
  • gpsql: Greenplum parallel database cluster (monitoring)

If pg_mode is set to citus or gpsql, two additional required identity parameters pg_shard and pg_group are needed to define the horizontal sharding cluster identity.

In both cases, each PostgreSQL cluster is part of a larger business unit.

pg_cluster

Parameter Name: pg_cluster, Type: string, Level: C

PostgreSQL cluster name, required identity parameter, no default value.

The cluster name is used as the namespace for resources.

Cluster naming must follow a specific pattern: [a-z][a-z0-9-]*, i.e., only numbers and lowercase letters, not starting with a number, to meet different identifier constraints.

pg_seq

Parameter Name: pg_seq, Type: int, Level: I

PostgreSQL instance sequence number, required identity parameter, no default value.

The sequence number of this instance, uniquely assigned within its cluster, typically using natural numbers starting from 0 or 1, usually not recycled or reused.

pg_role

Parameter Name: pg_role, Type: enum, Level: I

PostgreSQL instance role, required identity parameter, no default value. Values can be: primary, replica, offline

The role of a PGSQL instance can be: primary, replica, standby, or offline.

  • primary: Primary instance, there is one and only one in a cluster.
  • replica: Replica for serving online read-only traffic, may have slight replication delay under high load (10ms~100ms, 100KB).
  • offline: Offline replica for handling offline read-only traffic, such as analytics/ETL/personal queries.

pg_instances

Parameter Name: pg_instances, Type: dict, Level: I

Define multiple PostgreSQL instances on a single host using {port:ins_vars} format.

This parameter is reserved for multi-instance deployment on a single node. Pigsty has not yet implemented this feature and strongly recommends dedicated node deployment.

pg_upstream

Parameter Name: pg_upstream, Type: ip, Level: I

Upstream instance IP address for standby cluster or cascade replica.

Setting pg_upstream on the primary instance of a cluster indicates this cluster is a standby cluster, and this instance will act as a standby leader, receiving and applying changes from the upstream cluster.

Setting pg_upstream on a non-primary instance specifies a specific instance as the upstream for physical replication. If different from the primary instance IP address, this instance becomes a cascade replica. It is the user’s responsibility to ensure the upstream IP address is another instance in the same cluster.

pg_shard

Parameter Name: pg_shard, Type: string, Level: C

PostgreSQL horizontal shard name, required identity parameter for sharding clusters (e.g., citus clusters).

When multiple standard PostgreSQL clusters serve the same business together in a horizontal sharding manner, Pigsty marks this group of clusters as a horizontal sharding cluster.

pg_shard is the shard group name. It is typically a prefix of pg_cluster.

For example, if we have a shard group pg-citus with 4 clusters, their identity parameters would be:

cls pg_shard: pg-citus
cls pg_group = 0:   pg-citus0
cls pg_group = 1:   pg-citus1
cls pg_group = 2:   pg-citus2
cls pg_group = 3:   pg-citus3

pg_group

Parameter Name: pg_group, Type: int, Level: C

PostgreSQL horizontal sharding cluster shard index number, required identity parameter for sharding clusters (e.g., citus clusters).

This parameter is used in conjunction with pg_shard, typically using non-negative integers as index numbers.

gp_role

Parameter Name: gp_role, Type: enum, Level: C

Greenplum/Matrixdb role of the PostgreSQL cluster, can be master or segment.

  • master: Marks the postgres cluster as a greenplum master instance (coordinator node), this is the default value.
  • segment: Marks the postgres cluster as a greenplum segment cluster (data node).

This parameter is only used for Greenplum/MatrixDB databases (pg_mode is gpsql) and has no meaning for regular PostgreSQL clusters.

pg_exporters

Parameter Name: pg_exporters, Type: dict, Level: C

Additional exporter definitions for monitoring remote PostgreSQL instances, default value: {}

If you want to monitor remote PostgreSQL instances, define them in the pg_exporters parameter on the cluster where the monitoring system resides (Infra node), and use the pgsql-monitor.yml playbook to complete the deployment.

pg_exporters: # list all remote instances here, alloc a unique unused local port as k
    20001: { pg_cluster: pg-foo, pg_seq: 1, pg_host: 10.10.10.10 }
    20004: { pg_cluster: pg-foo, pg_seq: 2, pg_host: 10.10.10.11 }
    20002: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.12 }
    20003: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.13 }

pg_offline_query

Parameter Name: pg_offline_query, Type: bool, Level: I

Set to true to enable offline queries on this instance, default is false.

When this parameter is enabled on a PostgreSQL instance, users belonging to the dbrole_offline group can directly connect to this PostgreSQL instance to execute offline queries (slow queries, interactive queries, ETL/analytics queries).

Instances with this flag have an effect similar to setting pg_role = offline for the instance, with the only difference being that offline instances by default do not serve replica service requests and exist as dedicated offline/analytics replica instances.

If you don’t have spare instances available for this purpose, you can select a regular replica and enable this parameter at the instance level to handle offline queries when needed.


PG_BUSINESS

Customize cluster templates: users, databases, services, and permission rules.

Users should pay close attention to this section of parameters, as this is where business declares its required database objects.

Default database users and their credentials. It is strongly recommended to change these user passwords in production environments.

# postgres business object definition, overwrite in group vars
pg_users: []                      # postgres business users
pg_databases: []                  # postgres business databases
pg_services: []                   # postgres business services
pg_hba_rules: []                  # business hba rules for postgres
pgb_hba_rules: []                 # business hba rules for pgbouncer
# global credentials, overwrite in global vars
pg_dbsu_password: ''              # dbsu password, empty string means no dbsu password by default
pg_replication_username: replicator
pg_replication_password: DBUser.Replicator
pg_admin_username: dbuser_dba
pg_admin_password: DBUser.DBA
pg_monitor_username: dbuser_monitor
pg_monitor_password: DBUser.Monitor

pg_users

Parameter Name: pg_users, Type: user[], Level: C

PostgreSQL business user list, needs to be defined at the PG cluster level. Default value: [] empty list.

Each array element is a user/role definition, for example:

- name: dbuser_meta               # required, `name` is the only required field for user definition
  password: DBUser.Meta           # optional, password, can be scram-sha-256 hash string or plaintext
  login: true                     # optional, can login by default
  superuser: false                # optional, default false, is superuser?
  createdb: false                 # optional, default false, can create database?
  createrole: false               # optional, default false, can create role?
  inherit: true                   # optional, by default, can this role use inherited privileges?
  replication: false              # optional, default false, can this role do replication?
  bypassrls: false                # optional, default false, can this role bypass row-level security?
  pgbouncer: true                 # optional, default false, add this user to pgbouncer user list? (production users using connection pool should explicitly set to true)
  connlimit: -1                   # optional, user connection limit, default -1 disables limit
  expire_in: 3650                 # optional, this role expires: calculated from creation + n days (higher priority than expire_at)
  expire_at: '2030-12-31'         # optional, when this role expires, use YYYY-MM-DD format string to specify a specific date (lower priority than expire_in)
  comment: pigsty admin user      # optional, description and comment string for this user/role
  roles: [dbrole_admin]           # optional, default roles are: dbrole_{admin,readonly,readwrite,offline}
  parameters: {}                  # optional, use `ALTER ROLE SET` for this role, configure role-level database parameters
  pool_mode: transaction          # optional, pgbouncer pool mode at user level, default transaction
  pool_connlimit: -1              # optional, user-level max database connections, default -1 disables limit
  search_path: public             # optional, key-value config parameter per postgresql docs (e.g., use pigsty as default search_path)

pg_databases

Parameter Name: pg_databases, Type: database[], Level: C

PostgreSQL business database list, needs to be defined at the PG cluster level. Default value: [] empty list.

Each array element is a business database definition, for example:

- name: meta                      # required, `name` is the only required field for database definition
  baseline: cmdb.sql              # optional, database sql baseline file path (relative path in ansible search path, e.g., files/)
  pgbouncer: true                 # optional, add this database to pgbouncer database list? default true
  schemas: [pigsty]               # optional, additional schemas to create, array of schema name strings
  extensions:                     # optional, additional extensions to install: array of extension objects
    - { name: postgis , schema: public }  # can specify which schema to install extension into, or not (if not specified, installs to first schema in search_path)
    - { name: timescaledb }               # some extensions create and use fixed schemas, so no need to specify schema
  comment: pigsty meta database   # optional, description and comment for the database
  owner: postgres                 # optional, database owner, default is postgres
  template: template1             # optional, template to use, default is template1, target must be a template database
  encoding: UTF8                  # optional, database encoding, default UTF8 (must match template database)
  locale: C                       # optional, database locale setting, default C (must match template database)
  lc_collate: C                   # optional, database collate rule, default C (must match template database), no reason to change
  lc_ctype: C                     # optional, database ctype character set, default C (must match template database)
  tablespace: pg_default          # optional, default tablespace, default is 'pg_default'
  allowconn: true                 # optional, allow connections, default true. Explicitly set false to completely forbid connections
  revokeconn: false               # optional, revoke public connect privileges. default false, when true, CONNECT privilege revoked from users other than owner and admin
  register_datasource: true       # optional, register this database to grafana datasource? default true, explicitly false skips registration
  connlimit: -1                   # optional, database connection limit, default -1 means no limit, positive integer limits connections
  pool_auth_user: dbuser_meta     # optional, all connections to this pgbouncer database will authenticate using this user (useful when pgbouncer_auth_query enabled)
  pool_mode: transaction          # optional, database-level pgbouncer pooling mode, default transaction
  pool_size: 64                   # optional, database-level pgbouncer default pool size, default 64
  pool_size_reserve: 32           # optional, database-level pgbouncer pool reserve, default 32, max additional burst connections when default pool insufficient
  pool_size_min: 0                # optional, database-level pgbouncer pool minimum size, default 0
  pool_max_db_conn: 100           # optional, database-level max database connections, default 100

In each database definition object, only name is a required field, all other fields are optional.

pg_services

Parameter Name: pg_services, Type: service[], Level: C

PostgreSQL service list, needs to be defined at the PG cluster level. Default value: [], empty list.

Used to define additional services at the database cluster level. Each object in the array defines a service. A complete service definition example:

- name: standby                   # required, service name, final svc name will use `pg_cluster` as prefix, e.g., pg-meta-standby
  port: 5435                      # required, exposed service port (as kubernetes service node port mode)
  ip: "*"                         # optional, IP address to bind service, default is all IP addresses
  selector: "[]"                  # required, service member selector, use JMESPath to filter inventory
  backup: "[? pg_role == `primary`]"  # optional, service member selector (backup), service is handled by these instances when default selector instances are all down
  dest: default                   # optional, target port, default|postgres|pgbouncer|<port_number>, default is 'default', Default means use pg_default_service_dest value to decide
  check: /sync                    # optional, health check URL path, default is /, here uses Patroni API: /sync, only sync standby and primary return 200 health status
  maxconn: 5000                   # optional, max frontend connections allowed, default 5000
  balance: roundrobin             # optional, haproxy load balancing algorithm (default roundrobin, other option: leastconn)
  options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'

Note that this parameter is used to add additional services at the cluster level. If you want to globally define services that all PostgreSQL databases should provide, use the pg_default_services parameter.

pg_hba_rules

Parameter Name: pg_hba_rules, Type: hba[], Level: C

Client IP whitelist/blacklist rules for database cluster/instance. Default: [] empty list.

Array of objects, each object represents a rule. HBA rule object definition:

- title: allow intranet password access
  role: common
  rules:
    - host   all  all  10.0.0.0/8      md5
    - host   all  all  172.16.0.0/12   md5
    - host   all  all  192.168.0.0/16  md5
  • title: Rule title name, rendered as comment in HBA file.
  • rules: Rule array, each element is a standard HBA rule string.
  • role: Rule application scope, which instance roles will enable this rule?
    • common: Applies to all instances
    • primary, replica, offline: Only applies to instances with specific pg_role.
    • Special case: role: 'offline' rules apply to instances with pg_role : offline, and also to instances with pg_offline_query flag.

In addition to the native HBA rule definition above, Pigsty also provides a more convenient alias form:

- addr: 'intra'    # world|intra|infra|admin|local|localhost|cluster|<cidr>
  auth: 'pwd'      # trust|pwd|ssl|cert|deny|<official auth method>
  user: 'all'      # all|${dbsu}|${repl}|${admin}|${monitor}|<user>|<group>
  db: 'all'        # all|replication|....
  rules: []        # raw hba string precedence over above all
  title: allow intranet password access

pg_default_hba_rules is similar to this parameter, but it’s used to define global HBA rules, while this parameter is typically used to customize HBA rules for specific clusters/instances.

pgb_hba_rules

Parameter Name: pgb_hba_rules, Type: hba[], Level: C

Pgbouncer business HBA rules, default value: [], empty array.

This parameter is similar to pg_hba_rules, both are arrays of hba rule objects, the difference is that this parameter is for Pgbouncer.

pgb_default_hba_rules is similar to this parameter, but it’s used to define global connection pool HBA rules, while this parameter is typically used to customize HBA rules for specific connection pool clusters/instances.

pg_replication_username

Parameter Name: pg_replication_username, Type: username, Level: G

PostgreSQL physical replication username, default is replicator, not recommended to change this parameter.

pg_replication_password

Parameter Name: pg_replication_password, Type: password, Level: G

PostgreSQL physical replication user password, default value: DBUser.Replicator.

Warning: Please change this password in production environments!

pg_admin_username

Parameter Name: pg_admin_username, Type: username, Level: G

PostgreSQL / Pgbouncer admin name, default: dbuser_dba.

This is the globally used database administrator with database Superuser privileges and connection pool traffic management permissions. Please control its usage scope.

pg_admin_password

Parameter Name: pg_admin_password, Type: password, Level: G

PostgreSQL / Pgbouncer admin password, default: DBUser.DBA.

Warning: Please change this password in production environments!

pg_monitor_username

Parameter Name: pg_monitor_username, Type: username, Level: G

PostgreSQL/Pgbouncer monitor username, default: dbuser_monitor.

This is a database/connection pool user for monitoring, not recommended to change this username.

However, if your existing database uses a different monitor user, you can use this parameter to specify the monitor username when defining monitoring targets.

pg_monitor_password

Parameter Name: pg_monitor_password, Type: password, Level: G

Password used by PostgreSQL/Pgbouncer monitor user, default: DBUser.Monitor.

Try to avoid using characters like @:/ that can be confused with URL delimiters in passwords to reduce unnecessary trouble.

Warning: Please change this password in production environments!

pg_dbsu_password

Parameter Name: pg_dbsu_password, Type: password, Level: G/C

PostgreSQL pg_dbsu superuser password, default is empty string, meaning no password is set.

We don’t recommend configuring password login for dbsu as it increases the attack surface. The exception is: pg_mode = citus, in which case you need to configure a password for each shard cluster’s dbsu to allow connections within the shard cluster.


PG_INSTALL

This section is responsible for installing PostgreSQL and its extensions. If you want to install different major versions and extension plugins, just modify pg_version and pg_extensions. Note that not all extensions are available for all major versions.

pg_dbsu: postgres                 # os dbsu name, default is postgres, better not change it
pg_dbsu_uid: 26                   # os dbsu uid and gid, default is 26, for default postgres user and group
pg_dbsu_sudo: limit               # dbsu sudo privilege, none,limit,all,nopass. default is limit
pg_dbsu_home: /var/lib/pgsql      # postgresql home directory, default is `/var/lib/pgsql`
pg_dbsu_ssh_exchange: true        # exchange postgres dbsu ssh key among same pgsql cluster
pg_version: 18                    # postgres major version to be installed, default is 18
pg_bin_dir: /usr/pgsql/bin        # postgres binary dir, default is `/usr/pgsql/bin`
pg_log_dir: /pg/log/postgres      # postgres log dir, default is `/pg/log/postgres`
pg_packages:                      # pg packages to be installed, alias can be used
  - pgsql-main pgsql-common
pg_extensions: []                 # pg extensions to be installed, alias can be used

pg_dbsu

Parameter Name: pg_dbsu, Type: username, Level: C

OS dbsu username used by PostgreSQL, default is postgres, changing this username is not recommended.

However, in certain situations, you may need a username different from postgres, for example, when installing and configuring Greenplum / MatrixDB, you need to use gpadmin / mxadmin as the corresponding OS superuser.

pg_dbsu_uid

Parameter Name: pg_dbsu_uid, Type: int, Level: C

OS database superuser uid and gid, 26 is the default postgres user UID/GID from PGDG RPM.

For Debian/Ubuntu systems, there is no default value, and user 26 is often taken. Therefore, when Pigsty detects the installation environment is Debian-based and uid is 26, it will automatically use the replacement pg_dbsu_uid = 543.

pg_dbsu_sudo

Parameter Name: pg_dbsu_sudo, Type: enum, Level: C

Database superuser sudo privilege, can be none, limit, all, or nopass. Default is limit

  • none: No sudo privilege

  • limit: Limited sudo privilege for executing systemctl commands for database-related components (default option).

  • all: Full sudo privilege, requires password.

  • nopass: Full sudo privilege without password (not recommended).

  • Default value is limit, only allows executing sudo systemctl <start|stop|reload> <postgres|patroni|pgbouncer|...>.

pg_dbsu_home

Parameter Name: pg_dbsu_home, Type: path, Level: C

PostgreSQL home directory, default is /var/lib/pgsql, consistent with official pgdg RPM.

pg_dbsu_ssh_exchange

Parameter Name: pg_dbsu_ssh_exchange, Type: bool, Level: C

Whether to exchange OS dbsu ssh keys within the same PostgreSQL cluster?

Default is true, meaning database superusers in the same cluster can ssh to each other.

pg_version

Parameter Name: pg_version, Type: enum, Level: C

PostgreSQL major version to install, default is 18.

Note that PostgreSQL physical streaming replication cannot cross major versions, so it’s best not to configure this at the instance level.

You can use parameters in pg_packages and pg_extensions to install different packages and extensions for specific PG major versions.

pg_bin_dir

Parameter Name: pg_bin_dir, Type: path, Level: C

PostgreSQL binary directory, default is /usr/pgsql/bin.

The default value is a symlink manually created during installation, pointing to the specific installed Postgres version directory.

For example /usr/pgsql -> /usr/pgsql-15. On Ubuntu/Debian it points to /usr/lib/postgresql/15/bin.

For more details, see PGSQL File Structure.

pg_log_dir

Parameter Name: pg_log_dir, Type: path, Level: C

PostgreSQL log directory, default: /pg/log/postgres. The Vector log agent uses this variable to collect PostgreSQL logs.

Note that if the log directory pg_log_dir is prefixed with the data directory pg_data, it won’t be explicitly created (created automatically during data directory initialization).

pg_packages

Parameter Name: pg_packages, Type: string[], Level: C

PostgreSQL packages to install (RPM/DEB), this is an array of package names where elements can be space or comma-separated package aliases.

Pigsty v4 converges the default value to two aliases:

pg_packages:
  - pgsql-main pgsql-common
  • pgsql-main: Maps to PostgreSQL kernel, client, PL languages, and core extensions like pg_repack, wal2json, pgvector on the current platform.
  • pgsql-common: Maps to companion components required for running the database, such as Patroni, Pgbouncer, pgBackRest, pg_exporter, vip-manager, and other daemons.

Alias definitions can be found in pg_package_map under roles/node_id/vars/. Pigsty first resolves aliases based on OS and architecture, then replaces $v/${pg_version} with the actual major version pg_version, and finally installs the real packages. This shields package name differences between distributions.

If additional packages are needed (e.g., specific FDW or extensions), you can append aliases or real package names directly to pg_packages. But remember to keep pgsql-main pgsql-common, otherwise core components will be missing.

pg_extensions

Parameter Name: pg_extensions, Type: string[], Level: G/C

PostgreSQL extension packages to install (RPM/DEB), this is an array of extension package names or aliases.

Starting from v4, the default value is an empty list []. Pigsty no longer forces installation of large extensions, users can choose as needed to avoid extra disk and dependency usage.

To install extensions, fill in like this:

pg_extensions:
  - postgis timescaledb pgvector
  - pgsql-fdw     # use alias to install common FDWs at once

pg_package_map provides many aliases to shield package name differences between distributions. Here are available extension combinations for EL9 platform for reference (pick as needed):

pg_extensions: # extensions to be installed on this cluster
  - timescaledb periods temporal_tables emaj table_version pg_cron pg_later pg_background pg_timetable
  - postgis pgrouting pointcloud pg_h3 q3c ogr_fdw geoip #pg_geohash #mobilitydb
  - pgvector pgvectorscale pg_vectorize pg_similarity pg_tiktoken pgml #smlar
  - pg_search pg_bigm zhparser hunspell
  - hydra pg_analytics pg_lakehouse pg_duckdb duckdb_fdw pg_fkpart pg_partman plproxy #pg_strom citus
  - pg_hint_plan age hll rum pg_graphql pg_jsonschema jsquery index_advisor hypopg imgsmlr pg_ivm pgmq pgq #rdkit
  - pg_tle plv8 pllua plprql pldebugger plpgsql_check plprofiler plsh #pljava plr pgtap faker dbt2
  - prefix semver pgunit md5hash asn1oid roaringbitmap pgfaceting pgsphere pg_country pg_currency pgmp numeral pg_rational pguint ip4r timestamp9 chkpass #pg_uri #pgemailaddr #acl #debversion #pg_rrule
  - topn pg_gzip pg_http pg_net pg_html5_email_address pgsql_tweaks pg_extra_time pg_timeit count_distinct extra_window_functions first_last_agg tdigest aggs_for_arrays pg_arraymath pg_idkit pg_uuidv7 permuteseq pg_hashids
  - sequential_uuids pg_math pg_random pg_base36 pg_base62 floatvec pg_financial pgjwt pg_hashlib shacrypt cryptint pg_ecdsa pgpcre icu_ext envvar url_encode #pg_zstd #aggs_for_vecs #quantile #lower_quantile #pgqr #pg_protobuf
  - pg_repack pg_squeeze pg_dirtyread pgfincore pgdd ddlx pg_prioritize pg_checksums pg_readonly safeupdate pg_permissions pgautofailover pg_catcheck preprepare pgcozy pg_orphaned pg_crash pg_cheat_funcs pg_savior table_log pg_fio #pgpool pgagent
  - pg_profile pg_show_plans pg_stat_kcache pg_stat_monitor pg_qualstats pg_store_plans pg_track_settings pg_wait_sampling system_stats pg_meta pgnodemx pg_sqlog bgw_replstatus pgmeminfo toastinfo pagevis powa pg_top #pg_statviz #pgexporter_ext #pg_mon
  - passwordcheck supautils pgsodium pg_vault anonymizer pg_tde pgsmcrypto pgaudit pgauditlogtofile pg_auth_mon credcheck pgcryptokey pg_jobmon logerrors login_hook set_user pg_snakeoil pgextwlist pg_auditor noset #sslutils
  - wrappers multicorn odbc_fdw mysql_fdw tds_fdw sqlite_fdw pgbouncer_fdw mongo_fdw redis_fdw pg_redis_pubsub kafka_fdw hdfs_fdw firebird_fdw aws_s3 log_fdw #oracle_fdw #db2_fdw #jdbc_fdw
  - orafce pgtt session_variable pg_statement_rollback pg_dbms_metadata pg_dbms_lock pgmemcache #pg_dbms_job #wiltondb
  - pglogical pgl_ddl_deploy pg_failover_slots wal2json wal2mongo decoderbufs decoder_raw mimeo pgcopydb pgloader pg_fact_loader pg_bulkload pg_comparator pgimportdoc pgexportdoc #repmgr #slony
  - gis-stack rag-stack fdw-stack fts-stack etl-stack feat-stack olap-stack supa-stack stat-stack json-stack

For complete list, see: roles/node_id/vars


PG_BOOTSTRAP

Bootstrap PostgreSQL cluster with Patroni and set up 1:1 corresponding Pgbouncer connection pool.

It also initializes the database cluster with default roles, users, privileges, schemas, and extensions defined in PG_PROVISION.

pg_data: /pg/data                 # postgres data directory, `/pg/data` by default
pg_fs_main: /data/postgres        # postgres main data directory, `/data/postgres` by default
pg_fs_backup: /data/backups       # postgres backup data directory, `/data/backups` by default
pg_storage_type: SSD              # storage type for pg main data, SSD,HDD, SSD by default
pg_dummy_filesize: 64MiB          # size of `/pg/dummy`, hold 64MB disk space for emergency use
pg_listen: '0.0.0.0'              # postgres/pgbouncer listen addresses, comma separated list
pg_port: 5432                     # postgres listen port, 5432 by default
pg_localhost: /var/run/postgresql # postgres unix socket dir for localhost connection
patroni_enabled: true             # if disabled, no postgres cluster will be created during init
patroni_mode: default             # patroni working mode: default,pause,remove
pg_namespace: /pg                 # top level key namespace in etcd, used by patroni & vip
patroni_port: 8008                # patroni listen port, 8008 by default
patroni_log_dir: /pg/log/patroni  # patroni log dir, `/pg/log/patroni` by default
patroni_ssl_enabled: false        # secure patroni RestAPI communications with SSL?
patroni_watchdog_mode: off        # patroni watchdog mode: automatic,required,off. off by default
patroni_username: postgres        # patroni restapi username, `postgres` by default
patroni_password: Patroni.API     # patroni restapi password, `Patroni.API` by default
pg_etcd_password: ''              # etcd password for this pg cluster, '' to use pg_cluster
pg_primary_db: postgres           # primary database name, used by citus,etc... ,postgres by default
pg_parameters: {}                 # extra parameters in postgresql.auto.conf
pg_files: []                      # extra files to be copied to postgres data directory (e.g. license)
pg_conf: oltp.yml                 # config template: oltp,olap,crit,tiny. `oltp.yml` by default
pg_max_conn: auto                 # postgres max connections, `auto` will use recommended value
pg_shared_buffer_ratio: 0.25      # postgres shared buffers ratio, 0.25 by default, 0.1~0.4
pg_io_method: worker              # io method for postgres, auto,fsync,worker,io_uring, worker by default
pg_rto: 30                        # recovery time objective in seconds,  `30s` by default
pg_rpo: 1048576                   # recovery point objective in bytes, `1MiB` at most by default
pg_libs: 'pg_stat_statements, auto_explain'  # preloaded libraries, `pg_stat_statements,auto_explain` by default
pg_delay: 0                       # replication apply delay for standby cluster leader
pg_checksum: true                 # enable data checksum for postgres cluster?
pg_pwd_enc: scram-sha-256         # passwords encryption algorithm: fixed to scram-sha-256
pg_encoding: UTF8                 # database cluster encoding, `UTF8` by default
pg_locale: C                      # database cluster local, `C` by default
pg_lc_collate: C                  # database cluster collate, `C` by default
pg_lc_ctype: C                    # database character type, `C` by default
#pgsodium_key: ""                 # pgsodium key, 64 hex digit, default to sha256(pg_cluster)
#pgsodium_getkey_script: ""       # pgsodium getkey script path, pgsodium_getkey by default

pg_data

Parameter Name: pg_data, Type: path, Level: C

Postgres data directory, default is /pg/data.

This is a symlink to the underlying actual data directory, used in multiple places, please don’t modify it. See PGSQL File Structure for details.

pg_fs_main

Parameter Name: pg_fs_main, Type: path, Level: C

Mount point/file system path for PostgreSQL main data disk, default is /data/postgres.

Default value: /data/postgres, which will be used directly as the parent directory of PostgreSQL main data directory.

NVME SSD is recommended for PostgreSQL main data storage. Pigsty is optimized for SSD storage by default, but also supports HDD.

You can change pg_storage_type to HDD for HDD storage optimization.

pg_fs_backup

Parameter Name: pg_fs_backup, Type: path, Level: C

Mount point/file system path for PostgreSQL backup data disk, default is /data/backups.

If you’re using the default pgbackrest_method = local, it’s recommended to use a separate disk for backup storage.

The backup disk should be large enough to hold all backups, at least sufficient for 3 base backups + 2 days of WAL archives. Usually capacity isn’t a big issue since you can use cheap large HDDs as backup disks.

It’s recommended to use a separate disk for backup storage, otherwise Pigsty will fall back to the main data disk and consume main data disk capacity and IO.

pg_storage_type

Parameter Name: pg_storage_type, Type: enum, Level: C

Type of PostgreSQL data storage media: SSD or HDD, default is SSD.

Default value: SSD, which affects some tuning parameters like random_page_cost and effective_io_concurrency.

pg_dummy_filesize

Parameter Name: pg_dummy_filesize, Type: size, Level: C

Size of /pg/dummy, default is 64MiB, 64MB disk space for emergency use.

When disk is full, deleting the placeholder file can free some space for emergency use. Recommend at least 8GiB for production.

pg_listen

Parameter Name: pg_listen, Type: ip, Level: C

PostgreSQL / Pgbouncer listen address, default is 0.0.0.0 (all ipv4 addresses).

You can use placeholders in this variable, for example: '${ip},${lo}' or '${ip},${vip},${lo}':

  • ${ip}: Translates to inventory_hostname, which is the primary internal IP address defined in the inventory.
  • ${vip}: If pg_vip_enabled is enabled, will use the host part of pg_vip_address.
  • ${lo}: Will be replaced with 127.0.0.1

For production environments with high security requirements, it’s recommended to restrict listen IP addresses.

pg_port

Parameter Name: pg_port, Type: port, Level: C

Port that PostgreSQL server listens on, default is 5432.

pg_localhost

Parameter Name: pg_localhost, Type: path, Level: C

Unix socket directory for localhost PostgreSQL connection, default is /var/run/postgresql.

Unix socket directory for PostgreSQL and Pgbouncer local connections. pg_exporter and patroni will preferentially use Unix sockets to access PostgreSQL.

pg_namespace

Parameter Name: pg_namespace, Type: path, Level: C

Top-level namespace used in etcd, used by patroni and vip-manager, default is: /pg, not recommended to change.

patroni_enabled

Parameter Name: patroni_enabled, Type: bool, Level: C

Enable Patroni? Default is: true.

If disabled, no Postgres cluster will be created during initialization. Pigsty will skip the task of starting patroni, which can be used when trying to add some components to existing postgres instances.

patroni_mode

Parameter Name: patroni_mode, Type: enum, Level: C

Patroni working mode: default, pause, remove. Default: default.

  • default: Normal use of Patroni to bootstrap PostgreSQL cluster
  • pause: Similar to default, but enters maintenance mode after bootstrap
  • remove: Use Patroni to initialize cluster, then remove Patroni and use raw PostgreSQL.

patroni_port

Parameter Name: patroni_port, Type: port, Level: C

Patroni listen port, default is 8008, not recommended to change.

Patroni API server listens on this port for health checks and API requests.

patroni_log_dir

Parameter Name: patroni_log_dir, Type: path, Level: C

Patroni log directory, default is /pg/log/patroni, collected by Vector log agent.

patroni_ssl_enabled

Parameter Name: patroni_ssl_enabled, Type: bool, Level: G

Secure patroni RestAPI communications with SSL? Default is false.

This parameter is a global flag that can only be set before deployment. Because if SSL is enabled for patroni, you will have to use HTTPS instead of HTTP for health checks, fetching metrics, and calling APIs.

patroni_watchdog_mode

Parameter Name: patroni_watchdog_mode, Type: string, Level: C

Patroni watchdog mode: automatic, required, off, default is off.

In case of primary failure, Patroni can use watchdog to force shutdown old primary node to avoid split-brain.

  • off: Don’t use watchdog. No fencing at all (default behavior)
  • automatic: Enable watchdog if kernel has softdog module enabled and watchdog belongs to dbsu.
  • required: Force enable watchdog, refuse to start Patroni/PostgreSQL if softdog unavailable.

Default is off. You should not enable watchdog on Infra nodes. Critical systems where data consistency takes priority over availability, especially business clusters involving money, can consider enabling this option.

Note that if all your access traffic uses HAproxy health check service access, there is normally no split-brain risk.

patroni_username

Parameter Name: patroni_username, Type: username, Level: C

Patroni REST API username, default is postgres, used with patroni_password.

Patroni’s dangerous REST APIs (like restarting cluster) are protected by additional username/password. See Configure Cluster and Patroni RESTAPI for details.

patroni_password

Parameter Name: patroni_password, Type: password, Level: C

Patroni REST API password, default is Patroni.API.

Warning: Must change this parameter in production environments!

pg_primary_db

Parameter Name: pg_primary_db, Type: string, Level: C

Specify the primary database name in the cluster, used for citus and other business databases, default is postgres.

For example, when using Patroni to manage HA Citus clusters, you must choose a “primary database”.

Additionally, the database name specified here will be displayed in the printed connection string after PGSQL module installation is complete.

pg_parameters

Parameter Name: pg_parameters, Type: dict, Level: G/C/I

Used to specify and manage configuration parameters in postgresql.auto.conf.

After all cluster instances are initialized, the pg_param task will write the key/value pairs from this dictionary sequentially to /pg/data/postgresql.auto.conf.

Note: Do not manually modify this configuration file, or modify cluster configuration parameters via ALTER SYSTEM, changes will be overwritten on the next configuration sync.

This variable has higher priority than cluster configuration in Patroni / DCS (i.e., higher priority than cluster configuration edited by Patroni edit-config), so it can typically be used to override cluster default parameters at instance level.

When your cluster members have different specifications (not recommended!), you can use this parameter for fine-grained configuration management of each instance.

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary , pg_parameters: { shared_buffers: '5GB' } }
    10.10.10.12: { pg_seq: 2, pg_role: replica , pg_parameters: { shared_buffers: '4GB' } }
    10.10.10.13: { pg_seq: 3, pg_role: replica , pg_parameters: { shared_buffers: '3GB' } }

Note that some important cluster parameters (with requirements on primary/replica parameter values) are managed directly by Patroni via command line arguments, have highest priority, and cannot be overridden this way. For these parameters, you must use Patroni edit-config for management and configuration.

PostgreSQL parameters that must be consistent on primary and replicas (inconsistency will cause replica to fail to start!):

  • wal_level
  • max_connections
  • max_locks_per_transaction
  • max_worker_processes
  • max_prepared_transactions
  • track_commit_timestamp

Parameters that should preferably be consistent on primary and replicas (considering possibility of failover):

  • listen_addresses
  • port
  • cluster_name
  • hot_standby
  • wal_log_hints
  • max_wal_senders
  • max_replication_slots
  • wal_keep_segments
  • wal_keep_size

You can set non-existent parameters (e.g., GUCs from extensions, thus configuring “not yet existing” parameters that ALTER SYSTEM cannot modify), but modifying existing configuration to illegal values may cause PostgreSQL to fail to start, configure with caution!

pg_files

Parameter Name: pg_files, Type: path[], Level: C

Used to specify a list of files to be copied to the PGDATA directory, default is empty array: []

Files specified in this parameter will be copied to the {{ pg_data }} directory, mainly used to distribute license files required by special commercial PostgreSQL kernels.

Currently only PolarDB (Oracle compatible) kernel requires license files. For example, you can place the license.lic file in the files/ directory and specify in pg_files:

pg_files: [ license.lic ]

pg_conf

Parameter Name: pg_conf, Type: enum, Level: C

Configuration template: {oltp,olap,crit,tiny}.yml, default is oltp.yml.

  • tiny.yml: Optimized for small nodes, VMs, small demos (1-8 cores, 1-16GB)
  • oltp.yml: Optimized for OLTP workloads and latency-sensitive applications (4C8GB+) (default template)
  • olap.yml: Optimized for OLAP workloads and throughput (4C8G+)
  • crit.yml: Optimized for data consistency and critical applications (4C8G+)

Default is oltp.yml, but the configure script will set this to tiny.yml when current node is a small node.

You can have your own templates, just place them under templates/<mode>.yml and set this value to the template name to use.

pg_max_conn

Parameter Name: pg_max_conn, Type: int, Level: C

PostgreSQL server max connections. You can choose a value between 50 and 5000, or use auto for recommended value.

Default is auto, which sets max connections based on pg_conf and pg_default_service_dest.

  • tiny: 100
  • olap: 200
  • oltp: 200 (pgbouncer) / 1000 (postgres)
    • pg_default_service_dest = pgbouncer : 200
    • pg_default_service_dest = postgres : 1000
  • crit: 200 (pgbouncer) / 1000 (postgres)
    • pg_default_service_dest = pgbouncer : 200
    • pg_default_service_dest = postgres : 1000

Not recommended to set this value above 5000, otherwise you’ll need to manually increase haproxy service connection limits.

Pgbouncer’s transaction pool can mitigate excessive OLTP connection issues, so setting a large connection count is not recommended by default.

For OLAP scenarios, change pg_default_service_dest to postgres to bypass connection pooling.

pg_shared_buffer_ratio

Parameter Name: pg_shared_buffer_ratio, Type: float, Level: C

Postgres shared buffer memory ratio, default is 0.25, normal range is 0.1~0.4.

Default: 0.25, meaning 25% of node memory will be used as PostgreSQL’s shared buffer. If you want to enable huge pages for PostgreSQL, this value should be appropriately smaller than node_hugepage_ratio.

Setting this value above 0.4 (40%) is usually not a good idea, but may be useful in extreme cases.

Note that shared buffers are only part of PostgreSQL’s shared memory. To calculate total shared memory, use show shared_memory_size_in_huge_pages;.

pg_rto

Parameter Name: pg_rto, Type: int, Level: C

Recovery Time Objective (RTO) in seconds. This is used to calculate Patroni’s TTL value, default is 30 seconds.

If the primary instance is missing for this long, a new leader election will be triggered. This value is not the lower the better, it involves trade-offs:

Reducing this value can reduce unavailable time (unable to write) during cluster failover, but makes the cluster more sensitive to short-term network jitter, thus increasing the chance of false positives triggering failover.

You need to configure this value based on network conditions and business constraints, making a trade-off between failure probability and failure impact. Default is 30s, which affects the following Patroni parameters:

# TTL for acquiring leader lease (in seconds). Think of it as the time before starting automatic failover. Default: 30
ttl: {{ pg_rto }}

# Seconds the loop will sleep. Default: 10, this is patroni check loop interval
loop_wait: {{ (pg_rto / 3)|round(0, 'ceil')|int }}

# Timeout for DCS and PostgreSQL operation retries (in seconds). DCS or network issues shorter than this won't cause Patroni to demote leader. Default: 10
retry_timeout: {{ (pg_rto / 3)|round(0, 'ceil')|int }}

# Time (in seconds) allowed for primary to recover from failure before triggering failover, max RTO: 2x loop_wait + primary_start_timeout
primary_start_timeout: {{ (pg_rto / 3)|round(0, 'ceil')|int }}

pg_rpo

Parameter Name: pg_rpo, Type: int, Level: C

Recovery Point Objective (RPO) in bytes, default: 1048576.

Default is 1MiB, meaning up to 1MiB of data loss can be tolerated during failover.

When the primary goes down and all replicas are lagging, you must make a difficult choice, trade-off between availability and consistency:

  • Promote a replica to become new primary and restore service ASAP, but at the cost of acceptable data loss (e.g., less than 1MB).
  • Wait for primary to come back online (may never happen), or manual intervention to avoid any data loss.

You can use the crit.yml conf template to ensure no data loss during failover, but this sacrifices some performance.

pg_libs

Parameter Name: pg_libs, Type: string, Level: C

Preloaded dynamic shared libraries, default is pg_stat_statements,auto_explain, two PostgreSQL built-in extensions that are strongly recommended to enable.

For existing clusters, you can directly configure cluster shared_preload_libraries parameter and apply.

If you want to use TimescaleDB or Citus extensions, you need to add timescaledb or citus to this list. timescaledb and citus should be placed at the front of this list, for example:

citus,timescaledb,pg_stat_statements,auto_explain

Other extensions requiring dynamic loading can also be added to this list, such as pg_cron, pgml, etc. Typically citus and timescaledb have highest priority and should be added to the front of the list.

pg_delay

Parameter Name: pg_delay, Type: interval, Level: I

Delayed standby replication delay, default: 0.

If this value is set to a positive value, the standby cluster leader will be delayed by this time before applying WAL changes. Setting to 1h means data in this cluster will always lag the original cluster by one hour.

See Delayed Standby Cluster for details.

pg_checksum

Parameter Name: pg_checksum, Type: bool, Level: C

Enable data checksum for PostgreSQL cluster? Default is true, enabled.

This parameter can only be set before PGSQL deployment (but you can enable it manually later).

Data checksums help detect disk corruption and hardware failures. This feature is enabled by default since Pigsty v3.5 to ensure data integrity.

pg_pwd_enc

Parameter Name: pg_pwd_enc, Type: enum, Level: C

Password encryption algorithm, fixed to scram-sha-256 since Pigsty v4.

All new users will use SCRAM credentials. md5 has been deprecated. For compatibility with old clients, upgrade to SCRAM in business connection pools or client drivers.

pg_encoding

Parameter Name: pg_encoding, Type: enum, Level: C

Database cluster encoding, default is UTF8.

Using other non-UTF8 encodings is not recommended.

pg_locale

Parameter Name: pg_locale, Type: enum, Level: C

Database cluster locale, default is C.

This parameter controls the database’s default Locale setting, affecting collation, character classification, and other behaviors. Using C or POSIX provides best performance and predictable sorting behavior.

If you need specific language localization support, you can set it to the corresponding Locale, such as en_US.UTF-8 or zh_CN.UTF-8. Note that Locale settings affect index sort order, so they cannot be changed after cluster initialization.

pg_lc_collate

Parameter Name: pg_lc_collate, Type: enum, Level: C

Database cluster collation, default is C.

Unless you know what you’re doing, modifying cluster-level collation settings is not recommended.

pg_lc_ctype

Parameter Name: pg_lc_ctype, Type: enum, Level: C

Database character set CTYPE, default is C.

Starting from Pigsty v3.5, to be consistent with pg_lc_collate, the default value changed to C.

pg_io_method

Parameter Name: pg_io_method, Type: enum, Level: C

PostgreSQL IO method, default is worker. Available options include:

  • auto: Automatically select based on operating system, uses io_uring on Debian-based systems or EL 10+, otherwise uses worker
  • sync: Use traditional synchronous IO method
  • worker: Use background worker processes to handle IO (default option)
  • io_uring: Use Linux’s io_uring asynchronous IO interface

This parameter only applies to PostgreSQL 17 and above, controlling PostgreSQL’s data block layer IO strategy.

  • In PostgreSQL 17, io_uring can provide higher IO performance, but requires operating system kernel support (Linux 5.1+) and the liburing library installed.
  • In PostgreSQL 18, the default IO method changed from sync to worker, using background worker processes for asynchronous IO without additional dependencies.
  • If you’re using Debian 12/Ubuntu 22+ or EL 10+ systems and want optimal IO performance, consider setting this to io_uring.

Note that setting this value on systems that don’t support io_uring may cause PostgreSQL startup to fail, so auto or worker are safer choices.

pg_etcd_password

Parameter Name: pg_etcd_password, Type: password, Level: C

The password used by this PostgreSQL cluster in etcd, default is empty string ''.

If set to empty string, the pg_cluster parameter value will be used as the password (for Citus clusters, the pg_shard parameter value is used).

This password is used for authentication when Patroni connects to etcd and when vip-manager accesses etcd.

pgsodium_key

Parameter Name: pgsodium_key, Type: string, Level: C

The encryption master key for the pgsodium extension, consisting of 64 hexadecimal digits.

This parameter is not set by default. If not specified, Pigsty will automatically generate a deterministic key using the value of sha256(pg_cluster).

pgsodium is a PostgreSQL extension based on libsodium that provides encryption functions and transparent column encryption capabilities. If you need to use pgsodium’s encryption features, it’s recommended to explicitly specify a secure random key and keep it safe.

Example command to generate a random key:

openssl rand -hex 32   # Generate 64-digit hexadecimal key

pgsodium_getkey_script

Parameter Name: pgsodium_getkey_script, Type: path, Level: C

Path to the pgsodium key retrieval script, default uses the pgsodium_getkey script from Pigsty templates.

This script is used to retrieve pgsodium’s master key when PostgreSQL starts. The default script reads the key from environment variables or configuration files.

If you have custom key management requirements (such as using HashiCorp Vault, AWS KMS, etc.), you can provide a custom script path.

PG_PROVISION

If PG_BOOTSTRAP is about creating a new cluster, then PG_PROVISION is about creating default objects in the cluster, including:

pg_provision: true                # provision postgres cluster after bootstrap
pg_init: pg-init                  # init script for cluster template, default is `pg-init`
pg_default_roles:                 # default roles and users in postgres cluster
  - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
  - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
  - { name: postgres     ,superuser: true  ,comment: system superuser }
  - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator }
  - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
  - { name: dbuser_monitor ,roles: [pg_monitor, dbrole_readonly] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }
pg_default_privileges:            # default privileges when admin user creates objects
  - GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
  - GRANT SELECT     ON TABLES    TO dbrole_readonly
  - GRANT SELECT     ON SEQUENCES TO dbrole_readonly
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
  - GRANT USAGE      ON SCHEMAS   TO dbrole_offline
  - GRANT SELECT     ON TABLES    TO dbrole_offline
  - GRANT SELECT     ON SEQUENCES TO dbrole_offline
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
  - GRANT INSERT     ON TABLES    TO dbrole_readwrite
  - GRANT UPDATE     ON TABLES    TO dbrole_readwrite
  - GRANT DELETE     ON TABLES    TO dbrole_readwrite
  - GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
  - GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
  - GRANT TRUNCATE   ON TABLES    TO dbrole_admin
  - GRANT REFERENCES ON TABLES    TO dbrole_admin
  - GRANT TRIGGER    ON TABLES    TO dbrole_admin
  - GRANT CREATE     ON SCHEMAS   TO dbrole_admin
pg_default_schemas: [ monitor ]   # default schemas
pg_default_extensions:            # default extensions
  - { name: pg_stat_statements ,schema: monitor }
  - { name: pgstattuple        ,schema: monitor }
  - { name: pg_buffercache     ,schema: monitor }
  - { name: pageinspect        ,schema: monitor }
  - { name: pg_prewarm         ,schema: monitor }
  - { name: pg_visibility      ,schema: monitor }
  - { name: pg_freespacemap    ,schema: monitor }
  - { name: postgres_fdw       ,schema: public  }
  - { name: file_fdw           ,schema: public  }
  - { name: btree_gist         ,schema: public  }
  - { name: btree_gin          ,schema: public  }
  - { name: pg_trgm            ,schema: public  }
  - { name: intagg             ,schema: public  }
  - { name: intarray           ,schema: public  }
  - { name: pg_repack }
pg_reload: true                   # reload config after HBA changes?
pg_default_hba_rules:             # postgres default HBA rules, ordered by `order`
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  ,order: 100}
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' ,order: 150}
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost',order: 200}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' ,order: 250}
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' ,order: 300}
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' ,order: 350}
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password',order: 400}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   ,order: 450}
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    ,order: 500}
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket',order: 550}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     ,order: 600}
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet',order: 650}
pgb_default_hba_rules:            # pgbouncer default HBA rules, ordered by `order`
  - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident',order: 100}
  - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' ,order: 150}
  - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' ,order: 200}
  - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' ,order: 250}
  - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   ,order: 300}
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   ,order: 350}
  - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' ,order: 400}

pg_provision

Parameter Name: pg_provision, Type: bool, Level: C

Complete the PostgreSQL cluster provisioning work defined in this section after the cluster is bootstrapped. Default value is true.

If disabled, the PostgreSQL cluster will not be provisioned. For some special “PostgreSQL” clusters, such as Greenplum, you can disable this option to skip the provisioning phase.

pg_init

Parameter Name: pg_init, Type: string, Level: G/C

Location of the shell script for initializing database templates, default is pg-init. This script is copied to /pg/bin/pg-init and then executed.

This script is located at roles/pgsql/templates/pg-init

You can add your own logic to this script, or provide a new script in the templates/ directory and set pg_init to the new script name. When using a custom script, please preserve the existing initialization logic.

pg_default_roles

Parameter Name: pg_default_roles, Type: role[], Level: G/C

Default roles and users in Postgres cluster.

Pigsty has a built-in role system. Please check PGSQL Access Control: Role System for details.

pg_default_roles:                 # default roles and users in postgres cluster
  - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
  - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly]               ,comment: role for global read-write access }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite]  ,comment: role for object creation }
  - { name: postgres     ,superuser: true                                          ,comment: system superuser }
  - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly]   ,comment: system replicator }
  - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
  - { name: dbuser_monitor   ,roles: [pg_monitor, dbrole_readonly] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

pg_default_privileges

Parameter Name: pg_default_privileges, Type: string[], Level: G/C

Default privileges (DEFAULT PRIVILEGE) settings in each database:

pg_default_privileges:            # default privileges when admin user creates objects
  - GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
  - GRANT SELECT     ON TABLES    TO dbrole_readonly
  - GRANT SELECT     ON SEQUENCES TO dbrole_readonly
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
  - GRANT USAGE      ON SCHEMAS   TO dbrole_offline
  - GRANT SELECT     ON TABLES    TO dbrole_offline
  - GRANT SELECT     ON SEQUENCES TO dbrole_offline
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
  - GRANT INSERT     ON TABLES    TO dbrole_readwrite
  - GRANT UPDATE     ON TABLES    TO dbrole_readwrite
  - GRANT DELETE     ON TABLES    TO dbrole_readwrite
  - GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
  - GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
  - GRANT TRUNCATE   ON TABLES    TO dbrole_admin
  - GRANT REFERENCES ON TABLES    TO dbrole_admin
  - GRANT TRIGGER    ON TABLES    TO dbrole_admin
  - GRANT CREATE     ON SCHEMAS   TO dbrole_admin

Pigsty provides corresponding default privilege settings based on the default role system. Please check PGSQL Access Control: Privileges for details.

pg_default_schemas

Parameter Name: pg_default_schemas, Type: string[], Level: G/C

Default schemas to create, default value is: [ monitor ]. This will create a monitor schema on all databases for placing various monitoring extensions, tables, views, and functions.

pg_default_extensions

Parameter Name: pg_default_extensions, Type: extension[], Level: G/C

List of extensions to be created and enabled by default in all databases, default value:

pg_default_extensions: # default extensions to be created
  - { name: pg_stat_statements ,schema: monitor }
  - { name: pgstattuple        ,schema: monitor }
  - { name: pg_buffercache     ,schema: monitor }
  - { name: pageinspect        ,schema: monitor }
  - { name: pg_prewarm         ,schema: monitor }
  - { name: pg_visibility      ,schema: monitor }
  - { name: pg_freespacemap    ,schema: monitor }
  - { name: postgres_fdw       ,schema: public  }
  - { name: file_fdw           ,schema: public  }
  - { name: btree_gist         ,schema: public  }
  - { name: btree_gin          ,schema: public  }
  - { name: pg_trgm            ,schema: public  }
  - { name: intagg             ,schema: public  }
  - { name: intarray           ,schema: public  }
  - { name: pg_repack }

The only third-party extension is pg_repack, which is important for database maintenance. All other extensions are built-in PostgreSQL Contrib extensions.

Monitoring-related extensions are installed in the monitor schema by default, which is created by pg_default_schemas.

pg_reload

Parameter Name: pg_reload, Type: bool, Level: A

Reload PostgreSQL after HBA changes, default value is true.

Set it to false to disable automatic configuration reload when you want to check before applying HBA changes.

pg_default_hba_rules

Parameter Name: pg_default_hba_rules, Type: hba[], Level: G/C

PostgreSQL host-based authentication rules, global default rules definition. Default value is:

pg_default_hba_rules:             # postgres default host-based authentication rules, ordered by `order`
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  ,order: 100}
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' ,order: 150}
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost',order: 200}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' ,order: 250}
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' ,order: 300}
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' ,order: 350}
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password',order: 400}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   ,order: 450}
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    ,order: 500}
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket',order: 550}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     ,order: 600}
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet',order: 650}

The default value provides a fair security level for common scenarios. Please check PGSQL Authentication for details.

This parameter is an array of HBA rule objects, identical in format to pg_hba_rules. It’s recommended to configure unified pg_default_hba_rules globally, and use pg_hba_rules for additional customization on specific clusters. Rules from both parameters are applied sequentially, with the latter having higher priority.

pgb_default_hba_rules

Parameter Name: pgb_default_hba_rules, Type: hba[], Level: G/C

Pgbouncer default host-based authentication rules, array of HBA rule objects.

Default value provides a fair security level for common scenarios. Check PGSQL Authentication for details.

pgb_default_hba_rules:            # pgbouncer default host-based authentication rules, ordered by `order`
  - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident',order: 100}
  - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' ,order: 150}
  - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' ,order: 200}
  - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' ,order: 250}
  - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   ,order: 300}
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   ,order: 350}
  - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' ,order: 400}

The default Pgbouncer HBA rules are simple:

  1. Allow login from localhost with password
  2. Allow login from intranet with password

Users can customize according to their own needs.

This parameter is identical in format to pgb_hba_rules. It’s recommended to configure unified pgb_default_hba_rules globally, and use pgb_hba_rules for additional customization on specific clusters. Rules from both parameters are applied sequentially, with the latter having higher priority.


PG_BACKUP

This section defines variables for pgBackRest, which is used for PGSQL Point-in-Time Recovery (PITR).

Check PGSQL Backup & PITR for detailed information.

pgbackrest_enabled: true          # enable pgBackRest on pgsql host?
pgbackrest_clean: true            # remove pg backup data during init?
pgbackrest_log_dir: /pg/log/pgbackrest # pgbackrest log dir, default is `/pg/log/pgbackrest`
pgbackrest_method: local          # pgbackrest repo method: local, minio, [user defined...]
pgbackrest_init_backup: true      # perform a full backup immediately after pgbackrest init?
pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
  local:                          # default pgbackrest repo with local posix filesystem
    path: /pg/backup              # local backup directory, default is `/pg/backup`
    retention_full_type: count    # retain full backup by count
    retention_full: 2             # keep at most 3 full backups when using local filesystem repo, at least 2
  minio:                          # optional minio repo for pgbackrest
    type: s3                      # minio is s3-compatible, so use s3
    s3_endpoint: sss.pigsty       # minio endpoint domain, default is `sss.pigsty`
    s3_region: us-east-1          # minio region, default is us-east-1, not effective for minio
    s3_bucket: pgsql              # minio bucket name, default is `pgsql`
    s3_key: pgbackrest            # minio user access key for pgbackrest
    s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
    s3_uri_style: path            # use path style uri for minio, instead of host style
    path: /pgbackrest             # minio backup path, default is `/pgbackrest`
    storage_port: 9000            # minio port, default is 9000
    storage_ca_file: /etc/pki/ca.crt  # minio ca file path, default is `/etc/pki/ca.crt`
    block: y                      # enable block-level incremental backup (pgBackRest 2.46+)
    bundle: y                     # bundle small files into one file
    bundle_limit: 20MiB           # object storage file bundling threshold, default 20MiB
    bundle_size: 128MiB           # object storage file bundling target size, default 128MiB
    cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
    cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
    retention_full_type: time     # retain full backup by time on minio repo
    retention_full: 14            # keep full backups from the past 14 days

pgbackrest_enabled

Parameter Name: pgbackrest_enabled, Type: bool, Level: C

Enable pgBackRest on PGSQL nodes? Default value is: true

When using local filesystem backup repository (local), only the cluster primary will actually enable pgbackrest. Other instances will only initialize an empty repository.

pgbackrest_clean

Parameter Name: pgbackrest_clean, Type: bool, Level: C

Remove PostgreSQL backup data during initialization? Default value is true.

pgbackrest_log_dir

Parameter Name: pgbackrest_log_dir, Type: path, Level: C

pgBackRest log directory, default is /pg/log/pgbackrest. The Vector log agent references this parameter for log collection.

pgbackrest_method

Parameter Name: pgbackrest_method, Type: enum, Level: C

pgBackRest repository method: default options are local, minio, or other user-defined methods, default is local.

This parameter determines which repository to use for pgBackRest. All available repository methods are defined in pgbackrest_repo.

Pigsty uses the local backup repository by default, which creates a backup repository in the /pg/backup directory on the primary instance. The underlying storage path is specified by pg_fs_backup.

pgbackrest_init_backup

Parameter Name: pgbackrest_init_backup, Type: bool, Level: C

Perform a full backup immediately after pgBackRest initialization completes? Default is true.

This operation is only executed on cluster primary and non-cascading replicas (no pg_upstream defined). Enabling this parameter ensures you have a base backup immediately after cluster initialization for recovery when needed.

pgbackrest_repo

Parameter Name: pgbackrest_repo, Type: dict, Level: G/C

pgBackRest repository documentation: https://pgbackrest.org/configuration.html#section-repository

Default value includes two repository methods: local and minio, defined as follows:

pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
  local:                          # default pgbackrest repo with local posix filesystem
    path: /pg/backup              # local backup directory, default is `/pg/backup`
    retention_full_type: count    # retain full backup by count
    retention_full: 2             # keep at most 3 full backups when using local filesystem repo, at least 2
  minio:                          # optional minio repo for pgbackrest
    type: s3                      # minio is s3-compatible, so use s3
    s3_endpoint: sss.pigsty       # minio endpoint domain, default is `sss.pigsty`
    s3_region: us-east-1          # minio region, default is us-east-1, not effective for minio
    s3_bucket: pgsql              # minio bucket name, default is `pgsql`
    s3_key: pgbackrest            # minio user access key for pgbackrest
    s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
    s3_uri_style: path            # use path style uri for minio, instead of host style
    path: /pgbackrest             # minio backup path, default is `/pgbackrest`
    storage_port: 9000            # minio port, default is 9000
    storage_ca_file: /etc/pki/ca.crt  # minio ca file path, default is `/etc/pki/ca.crt`
    block: y                      # enable block-level incremental backup (pgBackRest 2.46+)
    bundle: y                     # bundle small files into one file
    bundle_limit: 20MiB           # object storage file bundling threshold, default 20MiB
    bundle_size: 128MiB           # object storage file bundling target size, default 128MiB
    cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
    cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
    retention_full_type: time     # retain full backup by time on minio repo
    retention_full: 14            # keep full backups from the past 14 days

You can define new backup repositories, such as using AWS S3, GCP, or other cloud providers’ S3-compatible storage services.

Block Incremental Backup: Starting from pgBackRest 2.46, the block: y option enables block-level incremental backup. This means during incremental backups, pgBackRest only backs up changed data blocks instead of entire changed files, significantly reducing backup data volume and backup time. This feature is particularly useful for large databases, and it’s recommended to enable this option on object storage repositories.


PG_ACCESS

This section handles database access paths, including:

  • Deploy Pgbouncer connection pooler on each PGSQL node and set default behavior
  • Publish service ports through local or dedicated haproxy nodes
  • Bind optional L2 VIP and register DNS records
pgbouncer_enabled: true           # if disabled, pgbouncer will not be launched on pgsql host
pgbouncer_port: 6432              # pgbouncer listen port, 6432 by default
pgbouncer_log_dir: /pg/log/pgbouncer  # pgbouncer log dir, `/pg/log/pgbouncer` by default
pgbouncer_auth_query: false       # query postgres to retrieve unlisted business users?
pgbouncer_poolmode: transaction   # pooling mode: transaction,session,statement, transaction by default
pgbouncer_sslmode: disable        # pgbouncer client ssl mode, disable by default
pgbouncer_ignore_param: [ extra_float_digits, application_name, TimeZone, DateStyle, IntervalStyle, search_path ]
pg_weight: 100          #INSTANCE # relative load balance weight in service, 100 by default, 0-255
pg_service_provider: ''           # dedicate haproxy node group name, or empty string for local nodes by default
pg_default_service_dest: pgbouncer # default service destination if svc.dest='default'
pg_default_services:              # postgres default service definitions
  - { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
  - { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
  - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
  - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}
pg_vip_enabled: false             # enable a l2 vip for pgsql primary? false by default
pg_vip_address: 127.0.0.1/24      # vip address in `<ipv4>/<mask>` format, require if vip is enabled
pg_vip_interface: eth0            # vip network interface to listen, eth0 by default
pg_dns_suffix: ''                 # pgsql dns suffix, '' by default
pg_dns_target: auto               # auto, primary, vip, none, or ad hoc ip

pgbouncer_enabled

Parameter Name: pgbouncer_enabled, Type: bool, Level: C

Default value is true. If disabled, the Pgbouncer connection pooler will not be configured on PGSQL nodes.

pgbouncer_port

Parameter Name: pgbouncer_port, Type: port, Level: C

Pgbouncer listen port, default is 6432.

pgbouncer_log_dir

Parameter Name: pgbouncer_log_dir, Type: path, Level: C

Pgbouncer log directory, default is /pg/log/pgbouncer. The Vector log agent collects Pgbouncer logs based on this parameter.

pgbouncer_auth_query

Parameter Name: pgbouncer_auth_query, Type: bool, Level: C

Allow Pgbouncer to query PostgreSQL to allow users not explicitly listed to access PostgreSQL through the connection pool? Default value is false.

If enabled, pgbouncer users will authenticate against the postgres database using SELECT username, password FROM monitor.pgbouncer_auth($1). Otherwise, only business users with pgbouncer: true are allowed to connect to the Pgbouncer connection pool.

pgbouncer_poolmode

Parameter Name: pgbouncer_poolmode, Type: enum, Level: C

Pgbouncer connection pool pooling mode: transaction, session, statement, default is transaction.

  • session: Session-level pooling with best feature compatibility.
  • transaction: Transaction-level pooling with better performance (many small connections), may break some session-level features like NOTIFY/LISTEN, etc.
  • statements: Statement-level pooling for simple read-only queries.

If your application has feature compatibility issues, consider changing this parameter to session.

pgbouncer_sslmode

Parameter Name: pgbouncer_sslmode, Type: enum, Level: C

Pgbouncer client SSL mode, default is disable.

Note that enabling SSL may have a significant performance impact on your pgbouncer.

  • disable: Ignore if client requests TLS (default)
  • allow: Use TLS if client requests it. Use plain TCP if not. Does not verify client certificate.
  • prefer: Same as allow.
  • require: Client must use TLS. Reject client connection if not. Does not verify client certificate.
  • verify-ca: Client must use TLS with a valid client certificate.
  • verify-full: Same as verify-ca.

pgbouncer_ignore_param

Parameter Name: pgbouncer_ignore_param, Type: string[], Level: C

List of startup parameters ignored by PgBouncer, default value is:

[ extra_float_digits, application_name, TimeZone, DateStyle, IntervalStyle, search_path ]

These parameters are configured in the ignore_startup_parameters option in the PgBouncer configuration file. When clients set these parameters during connection, PgBouncer will not create new connections due to parameter mismatch in the connection pool.

This allows different clients to use the same connection pool even if they set different values for these parameters. This parameter was added in Pigsty v3.5.


pg_weight

Parameter Name: pg_weight, Type: int, Level: I

Relative load balancing weight in service, default is 100, range 0-255.

Default value: 100. You must define it in instance variables and reload service for it to take effect.

pg_service_provider

Parameter Name: pg_service_provider, Type: string, Level: G/C

Dedicated haproxy node group name, or empty string for local nodes by default.

If specified, PostgreSQL services will be registered to the dedicated haproxy node group instead of the current PGSQL cluster nodes.

Remember to allocate unique ports for each service on the dedicated haproxy nodes!

For example, if we define the following parameters on a 3-node pg-test cluster:

pg_service_provider: infra       # use load balancer on group `infra`
pg_default_services:             # alloc port 10001 and 10002 for pg-test primary/replica service
  - { name: primary ,port: 10001 ,dest: postgres  ,check: /primary   ,selector: "[]" }
  - { name: replica ,port: 10002 ,dest: postgres  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }

pg_default_service_dest

Parameter Name: pg_default_service_dest, Type: enum, Level: G/C

When defining a service, if svc.dest='default', this parameter will be used as the default value.

Default value: pgbouncer, meaning the 5433 primary service and 5434 replica service will route traffic to pgbouncer by default.

If you don’t want to use pgbouncer, set it to postgres. Traffic will be routed directly to postgres.

pg_default_services

Parameter Name: pg_default_services, Type: service[], Level: G/C

Postgres default service definitions.

Default value is four default service definitions, as described in PGSQL Service.

pg_default_services:               # postgres default service definitions
  - { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
  - { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
  - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
  - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}

pg_vip_enabled

Parameter Name: pg_vip_enabled, Type: bool, Level: C

Enable L2 VIP for PGSQL cluster? Default value is false, meaning no L2 VIP will be created.

When L2 VIP is enabled, a VIP will be bound to the cluster primary instance node, managed by vip-manager based on data in etcd.

L2 VIP can only be used within the same L2 network, which may impose additional constraints on your network topology.

pg_vip_address

Parameter Name: pg_vip_address, Type: cidr4, Level: C

VIP address in <ipv4>/<mask> format is required if VIP is enabled.

Default value: 127.0.0.1/24. This value consists of two parts: ipv4 and mask, separated by /.

pg_vip_interface

Parameter Name: pg_vip_interface, Type: string, Level: C/I

VIP network interface to listen, eth0 by default.

It should be your node’s primary network interface name, i.e., the IP address used in your inventory.

If your nodes have multiple network interfaces with different names, you can override it in instance variables:

pg-test:
    hosts:
        10.10.10.11: {pg_seq: 1, pg_role: replica ,pg_vip_interface: eth0 }
        10.10.10.12: {pg_seq: 2, pg_role: primary ,pg_vip_interface: eth1 }
        10.10.10.13: {pg_seq: 3, pg_role: replica ,pg_vip_interface: eth2 }
    vars:
      pg_vip_enabled: true          # enable L2 VIP for this cluster, binds to primary by default
      pg_vip_address: 10.10.10.3/24 # L2 network CIDR: 10.10.10.0/24, vip address: 10.10.10.3
      # pg_vip_interface: eth1      # if your nodes have a unified interface, you can define it here

pg_dns_suffix

Parameter Name: pg_dns_suffix, Type: string, Level: C

PostgreSQL DNS name suffix, default is empty string.

By default, the PostgreSQL cluster name is registered as a DNS domain in dnsmasq on Infra nodes for external resolution.

You can specify a domain suffix with this parameter, which will use {{ pg_cluster }}{{ pg_dns_suffix }} as the cluster DNS name.

For example, if you set pg_dns_suffix to .db.vip.company.tld, the pg-test cluster DNS name will be pg-test.db.vip.company.tld.

pg_dns_target

Parameter Name: pg_dns_target, Type: enum, Level: C

Could be: auto, primary, vip, none, or an ad hoc IP address, which will be the target IP address of cluster DNS record.

Default value: auto, which will bind to pg_vip_address if pg_vip_enabled, or fallback to cluster primary instance IP address.

  • vip: bind to pg_vip_address
  • primary: resolve to cluster primary instance IP address
  • auto: resolve to pg_vip_address if pg_vip_enabled, or fallback to cluster primary instance IP address
  • none: do not bind to any IP address
  • <ipv4>: bind to the given IP address

PG_MONITOR

The PG_MONITOR group parameters are used to monitor the status of PostgreSQL databases, Pgbouncer connection pools, and pgBackRest backup systems.

This parameter group defines three Exporter configurations: pg_exporter for monitoring PostgreSQL, pgbouncer_exporter for monitoring connection pools, and pgbackrest_exporter for monitoring backup status.

pg_exporter_enabled: true              # enable pg_exporter on pgsql host?
pg_exporter_config: pg_exporter.yml    # pg_exporter config file name
pg_exporter_cache_ttls: '1,10,60,300'  # pg_exporter collector ttl stages (seconds), default is '1,10,60,300'
pg_exporter_port: 9630                 # pg_exporter listen port, default is 9630
pg_exporter_params: 'sslmode=disable'  # extra url parameters for pg_exporter dsn
pg_exporter_url: ''                    # if specified, will override auto-generated pg dsn
pg_exporter_auto_discovery: true       # enable auto database discovery? enabled by default
pg_exporter_exclude_database: 'template0,template1,postgres' # csv list of databases not monitored during auto-discovery
pg_exporter_include_database: ''       # csv list of databases monitored during auto-discovery
pg_exporter_connect_timeout: 200       # pg_exporter connection timeout (ms), default is 200
pg_exporter_options: ''                # extra options to override pg_exporter
pgbouncer_exporter_enabled: true       # enable pgbouncer_exporter on pgsql host?
pgbouncer_exporter_port: 9631          # pgbouncer_exporter listen port, default is 9631
pgbouncer_exporter_url: ''             # if specified, will override auto-generated pgbouncer dsn
pgbouncer_exporter_options: ''         # extra options to override pgbouncer_exporter
pgbackrest_exporter_enabled: true      # enable pgbackrest_exporter on pgsql host?
pgbackrest_exporter_port: 9854         # pgbackrest_exporter listen port, default is 9854
pgbackrest_exporter_options: ''        # extra options to override pgbackrest_exporter

pg_exporter_enabled

Parameter Name: pg_exporter_enabled, Type: bool, Level: C

Enable pg_exporter on PGSQL nodes? Default value is: true.

PG Exporter is used to monitor PostgreSQL database instances. Set to false if you don’t want to install pg_exporter.

pg_exporter_config

Parameter Name: pg_exporter_config, Type: string, Level: C

pg_exporter configuration file name, both PG Exporter and PGBouncer Exporter will use this configuration file. Default value: pg_exporter.yml.

If you want to use a custom configuration file, you can define it here. Your custom configuration file should be placed in files/<name>.yml.

For example, when you want to monitor a remote PolarDB database instance, you can use the sample configuration: files/polar_exporter.yml.

pg_exporter_cache_ttls

Parameter Name: pg_exporter_cache_ttls, Type: string, Level: C

pg_exporter collector TTL stages (seconds), default is ‘1,10,60,300’.

Default value: 1,10,60,300, which will use different TTL values for different metric collectors: 1s, 10s, 60s, 300s.

PG Exporter has a built-in caching mechanism to avoid the improper impact of multiple Prometheus scrapes on the database. All metric collectors are divided into four categories by TTL:

ttl_fast: "{{ pg_exporter_cache_ttls.split(',')[0]|int }}"         # critical queries
ttl_norm: "{{ pg_exporter_cache_ttls.split(',')[1]|int }}"         # common queries
ttl_slow: "{{ pg_exporter_cache_ttls.split(',')[2]|int }}"         # slow queries (e.g table size)
ttl_slowest: "{{ pg_exporter_cache_ttls.split(',')[3]|int }}"      # ver slow queries (e.g bloat)

For example, with default configuration, liveness metrics are cached for at most 1s, most common metrics are cached for 10s (should match the monitoring scrape interval victoria_scrape_interval). A few slow-changing queries have 60s TTL, and very few high-overhead monitoring queries have 300s TTL.

pg_exporter_port

Parameter Name: pg_exporter_port, Type: port, Level: C

pg_exporter listen port, default value is: 9630

pg_exporter_params

Parameter Name: pg_exporter_params, Type: string, Level: C

Extra URL path parameters in the DSN used by pg_exporter.

Default value: sslmode=disable, which disables SSL for monitoring connections (since local unix sockets are used by default).

pg_exporter_url

Parameter Name: pg_exporter_url, Type: pgurl, Level: C

If specified, will override the auto-generated PostgreSQL DSN and use the specified DSN to connect to PostgreSQL. Default value is empty string.

If not specified, PG Exporter will use the following connection string to access PostgreSQL by default:

postgres://{{ pg_monitor_username }}:{{ pg_monitor_password }}@{{ pg_host }}:{{ pg_port }}/postgres{% if pg_exporter_params != '' %}?{{ pg_exporter_params }}{% endif %}

Use this parameter when you want to monitor a remote PostgreSQL instance, or need to use different monitoring user/password or configuration options.

pg_exporter_auto_discovery

Parameter Name: pg_exporter_auto_discovery, Type: bool, Level: C

Enable auto database discovery? Enabled by default: true.

By default, PG Exporter connects to the database specified in the DSN (default is the admin database postgres) to collect global metrics. If you want to collect metrics from all business databases, enable this option. PG Exporter will automatically discover all databases in the target PostgreSQL instance and collect database-level monitoring metrics from these databases.

pg_exporter_exclude_database

Parameter Name: pg_exporter_exclude_database, Type: string, Level: C

If database auto-discovery is enabled (enabled by default), databases in this parameter’s list will not be monitored. Default value is: template0,template1,postgres, meaning the admin database postgres and template databases are excluded from auto-monitoring.

As an exception, the database specified in the DSN is not affected by this parameter. For example, if PG Exporter connects to the postgres database, it will be monitored even if postgres is in this list.

pg_exporter_include_database

Parameter Name: pg_exporter_include_database, Type: string, Level: C

If database auto-discovery is enabled (enabled by default), only databases in this parameter’s list will be monitored. Default value is empty string, meaning this feature is not enabled.

The parameter format is a comma-separated list of database names, e.g., db1,db2,db3.

This parameter has higher priority than pg_exporter_exclude_database, acting as a whitelist mode. Use this parameter if you only want to monitor specific databases.

pg_exporter_connect_timeout

Parameter Name: pg_exporter_connect_timeout, Type: int, Level: C

pg_exporter connection timeout (milliseconds), default is 200 (in milliseconds).

How long will PG Exporter wait when trying to connect to a PostgreSQL database? Beyond this time, PG Exporter will give up the connection and report an error.

The default value of 200ms is sufficient for most scenarios (e.g., same availability zone monitoring), but if your monitored remote PostgreSQL is on another continent, you may need to increase this value to avoid connection timeouts.

pg_exporter_options

Parameter Name: pg_exporter_options, Type: arg, Level: C

Command line arguments passed to PG Exporter, default value is: "" empty string.

When using empty string, the default command arguments will be used:

{% if pg_exporter_port != '' %}
PG_EXPORTER_OPTS='--web.listen-address=:{{ pg_exporter_port }} {{ pg_exporter_options }}'
{% else %}
PG_EXPORTER_OPTS='--web.listen-address=:{{ pg_exporter_port }} --log.level=info'
{% endif %}

Note: Do not override the pg_exporter_port port configuration in this parameter.

pgbouncer_exporter_enabled

Parameter Name: pgbouncer_exporter_enabled, Type: bool, Level: C

Enable pgbouncer_exporter on PGSQL nodes? Default value is: true.

pgbouncer_exporter_port

Parameter Name: pgbouncer_exporter_port, Type: port, Level: C

pgbouncer_exporter listen port, default value is: 9631

pgbouncer_exporter_url

Parameter Name: pgbouncer_exporter_url, Type: pgurl, Level: C

If specified, will override the auto-generated pgbouncer DSN and use the specified DSN to connect to pgbouncer. Default value is empty string.

If not specified, Pgbouncer Exporter will use the following connection string to access Pgbouncer by default:

postgres://{{ pg_monitor_username }}:{{ pg_monitor_password }}@:{{ pgbouncer_port }}/pgbouncer?host={{ pg_localhost }}&sslmode=disable

Use this parameter when you want to monitor a remote Pgbouncer instance, or need to use different monitoring user/password or configuration options.

pgbouncer_exporter_options

Parameter Name: pgbouncer_exporter_options, Type: arg, Level: C

Command line arguments passed to Pgbouncer Exporter, default value is: "" empty string.

When using empty string, the default command arguments will be used:

{% if pgbouncer_exporter_options != '' %}
PG_EXPORTER_OPTS='--web.listen-address=:{{ pgbouncer_exporter_port }} {{ pgbouncer_exporter_options }}'
{% else %}
PG_EXPORTER_OPTS='--web.listen-address=:{{ pgbouncer_exporter_port }} --log.level=info'
{% endif %}

Note: Do not override the pgbouncer_exporter_port port configuration in this parameter.

pgbackrest_exporter_enabled

Parameter Name: pgbackrest_exporter_enabled, Type: bool, Level: C

Enable pgbackrest_exporter on PGSQL nodes? Default value is: true.

pgbackrest_exporter is used to monitor the status of the pgBackRest backup system, including key metrics such as backup size, time, type, and duration.

pgbackrest_exporter_port

Parameter Name: pgbackrest_exporter_port, Type: port, Level: C

pgbackrest_exporter listen port, default value is: 9854.

This port needs to be referenced in the Prometheus service discovery configuration to scrape backup-related monitoring metrics.

pgbackrest_exporter_options

Parameter Name: pgbackrest_exporter_options, Type: arg, Level: C

Command line arguments passed to pgbackrest_exporter, default value is: "" empty string.

When using empty string, the default command argument configuration will be used. You can specify additional parameter options here to adjust the exporter’s behavior.


PG_REMOVE

pgsql-rm.yml invokes the pg_remove role to safely remove PostgreSQL instances. This section’s parameters control cleanup behavior to avoid accidental deletion.

pg_rm_data: true                  # remove postgres data during remove? true by default
pg_rm_backup: true                # remove pgbackrest backup during primary remove? true by default
pg_rm_pkg: true                   # uninstall postgres packages during remove? true by default
pg_safeguard: false               # stop pg_remove running if pg_safeguard is enabled, false by default

pg_rm_data

Parameter Name: pg_rm_data, Type: bool, Level: G/C/A

Whether to clean up pg_data and symlinks when removing PGSQL instances, default is true.

This switch affects both pgsql-rm.yml and other scenarios that trigger pg_remove. Set to false to preserve the data directory for manual inspection or remounting.

pg_rm_backup

Parameter Name: pg_rm_backup, Type: bool, Level: G/C/A

Whether to also clean up the pgBackRest repository and configuration when removing the primary, default is true.

This parameter only applies to primary instances with pg_role=primary: pg_remove will first stop pgBackRest, delete the current cluster’s stanza, and remove data in pg_fs_backup when pgbackrest_method == 'local'. Standby clusters or upstream backups are not affected.

pg_rm_pkg

Parameter Name: pg_rm_pkg, Type: bool, Level: G/C/A

Whether to uninstall all packages installed by pg_packages when cleaning up PGSQL instances, default is true.

If you only want to temporarily stop and preserve binaries, set it to false. Otherwise, pg_remove will call the system package manager to completely uninstall PostgreSQL-related components.

pg_safeguard

Parameter Name: pg_safeguard, Type: bool, Level: G/C/A

Accidental deletion protection, default is false. When explicitly set to true, pg_remove will immediately terminate with a prompt, and will only continue after using -e pg_safeguard=false or disabling it in variables.

It’s recommended to enable this switch before batch cleanup in production environments, verify the commands and target nodes are correct, then disable it to avoid accidental deletion of instances.

10.14 - Playbook

How to manage PostgreSQL clusters with Ansible playbooks

Pigsty provides a series of playbooks for cluster provisioning, scaling, user/database management, monitoring, backup & recovery, and migration.

PlaybookFunction
pgsql.ymlInitialize PostgreSQL cluster or add new replicas
pgsql-rm.ymlRemove PostgreSQL cluster or specific instances
pgsql-user.ymlAdd new business user to existing PostgreSQL cluster
pgsql-db.ymlAdd new business database to existing PostgreSQL cluster
pgsql-monitor.ymlMonitor remote PostgreSQL instances
pgsql-migration.ymlGenerate migration manual and scripts for existing PostgreSQL
pgsql-pitr.ymlPerform Point-In-Time Recovery (PITR)

Safeguard

Be extra cautious when using PGSQL playbooks. Misuse of pgsql.yml and pgsql-rm.yml can lead to accidental database deletion!

  • Always add the -l parameter to limit the execution scope, and ensure you’re executing the right tasks on the right targets.
  • Limiting scope to a single cluster is recommended. Running pgsql.yml without parameters in production is a high-risk operation—think twice before proceeding.

To prevent accidental deletion, Pigsty’s PGSQL module provides a safeguard mechanism controlled by the pg_safeguard parameter. When pg_safeguard is set to true, the pgsql-rm.yml playbook will abort immediately, protecting your database cluster.

# Will abort execution, protecting data
./pgsql-rm.yml -l pg-test

# Force override the safeguard via command line parameter
./pgsql-rm.yml -l pg-test -e pg_safeguard=false

In addition to pg_safeguard, pgsql-rm.yml provides finer-grained control parameters:

ParameterDefaultDescription
pg_safeguardfalseSafeguard switch; when true, playbook aborts
pg_rm_datatrueWhether to remove PostgreSQL data directory
pg_rm_backuptrueWhether to remove pgBackRest backup data (only when removing primary)
pg_rm_pkgfalseWhether to uninstall PostgreSQL packages

These parameters allow precise control over removal behavior:

# Remove cluster but keep data directory (only stop services)
./pgsql-rm.yml -l pg-test -e pg_rm_data=false

# Remove cluster but keep backup data
./pgsql-rm.yml -l pg-test -e pg_rm_backup=false

# Remove cluster and uninstall packages
./pgsql-rm.yml -l pg-test -e pg_rm_pkg=true

pgsql.yml

The pgsql.yml playbook is used to initialize PostgreSQL clusters or add new replicas.

Here’s a demo of initializing a PostgreSQL cluster in the sandbox environment:

asciicast

Basic Usage

./pgsql.yml -l pg-meta            # Initialize cluster pg-meta
./pgsql.yml -l 10.10.10.13        # Initialize/add instance 10.10.10.13
./pgsql.yml -l pg-test -t pg_service  # Refresh services for cluster pg-test
./pgsql.yml -l pg-test -t pg_hba,pgbouncer_hba,pgbouncer_reload -e pg_reload=true  # Reload HBA rules

Wrapper Scripts

Pigsty provides convenient wrapper scripts to simplify common operations:

bin/pgsql-add pg-meta             # Initialize pgsql cluster pg-meta
bin/pgsql-add 10.10.10.10         # Initialize pgsql instance 10.10.10.10
bin/pgsql-add pg-test 10.10.10.13 # Add 10.10.10.13 to cluster pg-test (auto refresh services)
bin/pgsql-svc pg-test             # Refresh haproxy services for pg-test (use after membership changes)
bin/pgsql-hba pg-test             # Reload pg/pgb HBA rules for pg-test

Subtasks

This playbook contains the following subtasks:

# pg_install              : install postgres packages & extensions
#   - pg_dbsu             : setup postgres superuser
#     - pg_dbsu_create    : create dbsu user
#     - pg_dbsu_sudo      : configure dbsu sudo privileges
#     - pg_ssh            : exchange dbsu SSH keys
#   - pg_pkg              : install postgres packages
#     - pg_pre            : pre-installation tasks
#     - pg_ext            : install postgres extension packages
#     - pg_post           : post-installation tasks
#   - pg_link             : link pgsql version bin to /usr/pgsql
#   - pg_path             : add pgsql bin to system path
#   - pg_dir              : create postgres directories and setup FHS
#   - pg_bin              : sync /pg/bin scripts
#   - pg_alias            : configure pgsql/psql aliases
#   - pg_dummy            : create dummy placeholder file
#
# pg_bootstrap            : bootstrap postgres cluster
#   - pg_config           : generate postgres config
#     - pg_conf           : generate patroni config
#     - pg_key            : generate pgsodium key
#   - pg_cert             : issue certificates for postgres
#     - pg_cert_private   : check pg private key existence
#     - pg_cert_issue     : sign pg server certificate
#     - pg_cert_copy      : copy key & certs to pg node
#   - pg_launch           : launch patroni primary & replicas
#     - pg_watchdog       : grant watchdog permission to postgres
#     - pg_primary        : launch patroni/postgres primary
#     - pg_init           : init pg cluster with roles/templates
#     - pg_pass           : write .pgpass file to pg home
#     - pg_replica        : launch patroni/postgres replicas
#     - pg_hba            : generate pg HBA rules
#     - patroni_reload    : reload patroni config
#     - pg_patroni        : pause or remove patroni if necessary
#
# pg_provision            : provision postgres business users & databases
#   - pg_user             : provision postgres business users
#     - pg_user_config    : render create user SQL
#     - pg_user_create    : create user on postgres
#   - pg_db               : provision postgres business databases
#     - pg_db_drop        : drop database on postgres (state=absent/recreate)
#     - pg_db_config      : render create database SQL
#     - pg_db_create      : create database on postgres
#
# pg_backup               : init postgres PITR backup
#   - pgbackrest          : setup pgbackrest for backup
#     - pgbackrest_config : generate pgbackrest config
#     - pgbackrest_init   : init pgbackrest repo
#     - pgbackrest_backup : make initial backup after bootstrap
#
# pg_access               : init postgres service access layer
#   - pgbouncer           : deploy pgbouncer connection pooler
#     - pgbouncer_dir     : create pgbouncer directories
#     - pgbouncer_config  : generate pgbouncer config
#       - pgbouncer_hba   : generate pgbouncer HBA config
#       - pgbouncer_user  : generate pgbouncer userlist
#     - pgbouncer_launch  : launch pgbouncer service
#     - pgbouncer_reload  : reload pgbouncer config
#   - pg_vip              : bind VIP to primary with vip-manager
#     - pg_vip_config     : generate vip-manager config
#     - pg_vip_launch     : launch vip-manager to bind VIP
#   - pg_dns              : register DNS name to infra dnsmasq
#     - pg_dns_ins        : register pg instance name
#     - pg_dns_cls        : register pg cluster name
#   - pg_service          : expose pgsql service with haproxy
#     - pg_service_config : generate local haproxy config for pg services
#     - pg_service_reload : expose postgres services with haproxy
#
# pg_monitor              : setup pgsql monitoring and register to infra
#   - pg_exporter         : configure and launch pg_exporter
#   - pgbouncer_exporter  : configure and launch pgbouncer_exporter
#   - pgbackrest_exporter : configure and launch pgbackrest_exporter
#   - pg_register         : register pgsql to monitoring/logging/datasource
#     - add_metrics       : register pg as VictoriaMetrics monitoring target
#     - add_logs          : register pg as Vector log source
#     - add_ds            : register pg database as Grafana datasource

Related Administration Tasks

Notes

  • When running this playbook on a single replica, ensure the cluster primary is already initialized!
  • After scaling out, you need to Reload Service and Reload HBA. The wrapper script bin/pgsql-add handles these tasks automatically.

When scaling a cluster, if Patroni takes too long to bring up a replica, the Ansible playbook may abort due to timeout:

  • Typical error message: wait for postgres/patroni replica task runs for a long time before aborting
  • However, the replica creation process continues. For scenarios where replica creation takes more than a day, see FAQ: Replica creation failed.

pgsql-rm.yml

The pgsql-rm.yml playbook is used to remove PostgreSQL clusters or specific instances.

Here’s a demo of removing a PostgreSQL cluster in the sandbox environment:

asciicast

Basic Usage

./pgsql-rm.yml -l pg-test          # Remove cluster pg-test
./pgsql-rm.yml -l 10.10.10.13      # Remove instance 10.10.10.13

Command Line Arguments

This playbook supports the following command line arguments:

./pgsql-rm.yml -l pg-test          # Remove cluster pg-test
    -e pg_safeguard=false          # Safeguard switch, disabled by default; override when enabled
    -e pg_rm_data=true             # Whether to remove PostgreSQL data directory, default: remove
    -e pg_rm_backup=true           # Whether to remove pgBackRest backup (primary only), default: remove
    -e pg_rm_pkg=false             # Whether to uninstall PostgreSQL packages, default: keep

Wrapper Scripts

bin/pgsql-rm pg-meta               # Remove pgsql cluster pg-meta
bin/pgsql-rm pg-test 10.10.10.13   # Remove instance 10.10.10.13 from cluster pg-test

Subtasks

This playbook contains the following subtasks:

# pg_safeguard           : abort if pg_safeguard is enabled
#
# pg_monitor             : remove registration from monitoring system
#   - pg_deregister      : remove pg monitoring targets from infra
#     - rm_metrics       : remove monitoring targets from prometheus
#     - rm_ds            : remove datasource from grafana
#     - rm_logs          : remove log targets from vector
#   - pg_exporter        : remove pg_exporter
#   - pgbouncer_exporter : remove pgbouncer_exporter
#   - pgbackrest_exporter: remove pgbackrest_exporter
#
# pg_access              : remove pg service access layer
#   - dns                : remove pg DNS records
#   - vip                : remove vip-manager
#   - pg_service         : remove pg service from haproxy
#   - pgbouncer          : remove pgbouncer connection middleware
#
# postgres               : remove postgres instances
#   - pg_replica         : remove all replicas
#   - pg_primary         : remove primary
#   - pg_meta            : remove metadata from etcd
#
# pg_backup              : remove backup repo (disable with pg_rm_backup=false)
# pg_data                : remove postgres data (disable with pg_rm_data=false)
# pg_pkg                 : uninstall pg packages (enable with pg_rm_pkg=true)
#   - pg_ext             : uninstall postgres extensions alone

Related Administration Tasks

Notes

  • Do not run this playbook on a primary that still has replicas—otherwise, remaining replicas will trigger automatic failover. Always remove all replicas first, then remove the primary. This is not a concern when removing the entire cluster at once.
  • Refresh cluster services after removing instances. When you remove a replica from a cluster, it remains in the load balancer configuration file. Since health checks will fail, the removed instance won’t affect cluster services. However, you should Reload Service at an appropriate time to ensure consistency between the production environment and configuration inventory.

pgsql-user.yml

The pgsql-user.yml playbook is used to add new business users to existing PostgreSQL clusters.

Basic Usage

./pgsql-user.yml -l pg-meta -e username=dbuser_meta

Wrapper Scripts

bin/pgsql-user pg-meta dbuser_meta  # Create user dbuser_meta on cluster pg-meta

Workflow

  1. Define user in the config inventory: all.children.<pg_cluster>.vars.pg_users[i]
  2. Execute playbook specifying cluster and username: pgsql-user.yml -l <pg_cluster> -e username=<name>

The playbook will:

  1. Generate user creation SQL at /pg/tmp/pg-user-{{ user.name }}.sql
  2. Execute user creation/update SQL on the cluster primary
  3. Update /etc/pgbouncer/userlist.txt and useropts.txt
  4. Reload pgbouncer to apply configuration

User Definition Example

pg_users:
  - name: dbuser_meta               # Required, username is the only mandatory field
    password: DBUser.Meta           # Optional, can be scram-sha-256 hash or plaintext
    login: true                     # Optional, can login, default: true
    superuser: false                # Optional, is superuser, default: false
    createdb: false                 # Optional, can create database, default: false
    createrole: false               # Optional, can create role, default: false
    inherit: true                   # Optional, inherit privileges, default: true
    replication: false              # Optional, can replicate, default: false
    bypassrls: false                # Optional, bypass RLS, default: false
    pgbouncer: true                 # Optional, add to pgbouncer userlist, default: false
    connlimit: -1                   # Optional, connection limit, -1 means unlimited
    expire_in: 3650                 # Optional, expire in N days (overrides expire_at)
    expire_at: '2030-12-31'         # Optional, specify expiration date
    comment: pigsty admin user      # Optional, user comment
    roles: [dbrole_admin]           # Optional, roles to grant
    parameters: {}                  # Optional, role-level parameters
    pool_mode: transaction          # Optional, pgbouncer user-level pool mode
    pool_connlimit: -1              # Optional, user-level max connections

For details, see: Admin SOP: Create User


pgsql-db.yml

The pgsql-db.yml playbook is used to add new business databases to existing PostgreSQL clusters.

Basic Usage

./pgsql-db.yml -l pg-meta -e dbname=meta

Wrapper Scripts

bin/pgsql-db pg-meta meta  # Create database meta on cluster pg-meta

Workflow

  1. Define database in the config inventory: all.children.<pg_cluster>.vars.pg_databases[i]
  2. Execute playbook specifying cluster and database name: pgsql-db.yml -l <pg_cluster> -e dbname=<name>

The playbook will:

  1. Generate database creation SQL at /pg/tmp/pg-db-{{ database.name }}.sql
  2. Execute database creation/update SQL on the cluster primary
  3. If db.register_datasource is true, register database as Grafana datasource
  4. Update /etc/pgbouncer/database.txt and reload pgbouncer

Database Definition Example

pg_databases:
  - name: meta                      # Required, database name is the only mandatory field
    baseline: cmdb.sql              # Optional, database initialization SQL file path
    pgbouncer: true                 # Optional, add to pgbouncer, default: true
    schemas: [pigsty]               # Optional, additional schemas to create
    extensions:                     # Optional, extensions to install
      - { name: postgis, schema: public }
      - { name: timescaledb }
    comment: pigsty meta database   # Optional, database comment
    owner: postgres                 # Optional, database owner
    template: template1             # Optional, template database
    encoding: UTF8                  # Optional, character encoding
    locale: C                       # Optional, locale setting
    tablespace: pg_default          # Optional, default tablespace
    allowconn: true                 # Optional, allow connections
    revokeconn: false               # Optional, revoke public connect privilege
    register_datasource: true       # Optional, register as Grafana datasource
    connlimit: -1                   # Optional, connection limit
    pool_mode: transaction          # Optional, pgbouncer pool mode
    pool_size: 64                   # Optional, pgbouncer pool size
    pool_size_reserve: 32           # Optional, pgbouncer reserve pool size

For details, see: Admin SOP: Create Database


pgsql-monitor.yml

The pgsql-monitor.yml playbook is used to bring remote PostgreSQL instances into Pigsty’s monitoring system.

Basic Usage

./pgsql-monitor.yml -e clsname=pg-foo  # Monitor remote cluster pg-foo

Wrapper Scripts

bin/pgmon-add pg-foo              # Monitor a remote pgsql cluster pg-foo
bin/pgmon-add pg-foo pg-bar       # Monitor multiple clusters simultaneously

Configuration

First, define pg_exporters in the infra group variables:

infra:
  hosts:
    10.10.10.10:
      pg_exporters:  # List all remote instances, assign unique unused local ports
        20001: { pg_cluster: pg-foo, pg_seq: 1, pg_host: 10.10.10.10 }
        20002: { pg_cluster: pg-foo, pg_seq: 2, pg_host: 10.10.10.11 }

Architecture Diagram

     ------ infra ------
     |                 |
     |   prometheus    |            v---- pg-foo-1 ----v
     |       ^         |  metrics   |         ^        |
     |   pg_exporter <-|------------|----  postgres    |
     |   (port: 20001) |            | 10.10.10.10:5432 |
     |       ^         |            ^------------------^
     |       ^         |                      ^
     |       ^         |            v---- pg-foo-2 ----v
     |       ^         |  metrics   |         ^        |
     |   pg_exporter <-|------------|----  postgres    |
     |   (port: 20002) |            | 10.10.10.11:5433 |
     -------------------            ^------------------^

Configurable Parameters

pg_exporter_config: pg_exporter.yml    # pg_exporter config file name
pg_exporter_cache_ttls: '1,10,60,300'  # pg_exporter collector TTL stages
pg_exporter_port: 9630                 # pg_exporter listen port
pg_exporter_params: 'sslmode=disable'  # DSN extra URL parameters
pg_exporter_url: ''                    # Directly override auto-generated DSN
pg_exporter_auto_discovery: true       # Enable auto database discovery
pg_exporter_exclude_database: 'template0,template1,postgres'  # Databases to exclude
pg_exporter_include_database: ''       # Databases to include only
pg_exporter_connect_timeout: 200       # Connection timeout (milliseconds)
pg_monitor_username: dbuser_monitor    # Monitor username
pg_monitor_password: DBUser.Monitor    # Monitor password

Remote Database Setup

Remote PostgreSQL instances need a monitoring user:

CREATE USER dbuser_monitor;
COMMENT ON ROLE dbuser_monitor IS 'system monitor user';
ALTER USER dbuser_monitor PASSWORD 'DBUser.Monitor';
GRANT pg_monitor TO dbuser_monitor;
CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" WITH SCHEMA "monitor";

Limitations

  • Only postgres metrics available
  • node, pgbouncer, patroni, haproxy metrics not available

For details, see: Admin SOP: Monitor RDS


pgsql-migration.yml

The pgsql-migration.yml playbook generates migration manuals and scripts for zero-downtime logical replication-based migration of existing PostgreSQL clusters.

Basic Usage

./pgsql-migration.yml -e@files/migration/pg-meta.yml

Workflow

  1. Define migration task configuration file (e.g., files/migration/pg-meta.yml)
  2. Execute playbook to generate migration manual and scripts
  3. Follow the manual to execute scripts step by step for migration

Migration Task Definition Example

# files/migration/pg-meta.yml
context_dir: ~/migration           # Migration manual and scripts output directory
src_cls: pg-meta                   # Source cluster name (required)
src_db: meta                       # Source database name (required)
src_ip: 10.10.10.10                # Source cluster primary IP (required)
dst_cls: pg-test                   # Target cluster name (required)
dst_db: test                       # Target database name (required)
dst_ip: 10.10.10.11                # Target cluster primary IP (required)

# Optional parameters
pg_dbsu: postgres
pg_replication_username: replicator
pg_replication_password: DBUser.Replicator
pg_admin_username: dbuser_dba
pg_admin_password: DBUser.DBA
pg_monitor_username: dbuser_monitor
pg_monitor_password: DBUser.Monitor

For details, see: Admin SOP: Migrate Cluster


pgsql-pitr.yml

The pgsql-pitr.yml playbook performs PostgreSQL Point-In-Time Recovery (PITR).

Basic Usage

# Recover to latest state (end of WAL archive stream)
./pgsql-pitr.yml -l pg-meta -e '{"pg_pitr": {}}'

# Recover to specific point in time
./pgsql-pitr.yml -l pg-meta -e '{"pg_pitr": {"time": "2025-07-13 10:00:00+00"}}'

# Recover to specific LSN
./pgsql-pitr.yml -l pg-meta -e '{"pg_pitr": {"lsn": "0/4001C80"}}'

# Recover to specific transaction ID
./pgsql-pitr.yml -l pg-meta -e '{"pg_pitr": {"xid": "250000"}}'

# Recover to named restore point
./pgsql-pitr.yml -l pg-meta -e '{"pg_pitr": {"name": "some_restore_point"}}'

# Recover from another cluster's backup
./pgsql-pitr.yml -l pg-test -e '{"pg_pitr": {"cluster": "pg-meta"}}'

PITR Task Parameters

pg_pitr:                           # Define PITR task
  cluster: "pg-meta"               # Source cluster name (for restoring from another cluster's backup)
  type: latest                     # Recovery target type: time, xid, name, lsn, immediate, latest
  time: "2025-01-01 10:00:00+00"   # Recovery target: point in time
  name: "some_restore_point"       # Recovery target: named restore point
  xid: "100000"                    # Recovery target: transaction ID
  lsn: "0/3000000"                 # Recovery target: log sequence number
  set: latest                      # Backup set to restore from, default: latest
  timeline: latest                 # Target timeline, can be integer, default: latest
  exclusive: false                 # Exclude target point, default: false
  action: pause                    # Post-recovery action: pause, promote, shutdown
  archive: false                   # Keep archive settings, default: false
  backup: false                    # Backup existing data to /pg/data-backup before restore? default: false
  db_include: []                   # Include only these databases
  db_exclude: []                   # Exclude these databases
  link_map: {}                     # Tablespace link mapping
  process: 4                       # Parallel recovery processes
  repo: {}                         # Recovery source repo configuration
  data: /pg/data                   # Recovery data directory
  port: 5432                       # Recovery instance listen port

Subtasks

This playbook contains the following subtasks:

# down                 : stop HA and shutdown patroni and postgres
#   - pause            : pause patroni auto failover
#   - stop             : stop patroni and postgres services
#     - stop_patroni   : stop patroni service
#     - stop_postgres  : stop postgres service
#
# pitr                 : execute PITR recovery process
#   - config           : generate pgbackrest config and recovery script
#   - backup           : perform optional backup to original data
#   - restore          : run pgbackrest restore command
#   - recovery         : start postgres and complete recovery
#   - verify           : verify recovered cluster control data
#
# up                   : start postgres/patroni and restore HA
#   - etcd             : clean etcd metadata before startup
#   - start            : start patroni and postgres services
#     - start_postgres : start postgres service
#     - start_patroni  : start patroni service
#   - resume           : resume patroni auto failover

Recovery Target Types

TypeDescriptionExample
latestRecover to end of WAL archive stream (latest state){"pg_pitr": {}}
timeRecover to specific point in time{"pg_pitr": {"time": "2025-07-13 10:00:00"}}
xidRecover to specific transaction ID{"pg_pitr": {"xid": "250000"}}
nameRecover to named restore point{"pg_pitr": {"name": "before_ddl"}}
lsnRecover to specific LSN{"pg_pitr": {"lsn": "0/4001C80"}}
immediateStop immediately after reaching consistent state{"pg_pitr": {"type": "immediate"}}

For details, see: Backup & Recovery Tutorial

10.15 - Extensions

Harness the synergistic power of PostgreSQL extensions

Pigsty provides 440+ extensions, covering 16 major categories including time-series, geospatial, vector, full-text search, analytics, and feature enhancements, ready to use out-of-the-box.

Using extensions in Pigsty involves four core steps: Download, Install, Config/Load, and Create.

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_databases:
      - name: meta
        extensions: [ postgis, timescaledb, vector ]   # Create: Create extensions in database
    pg_libs: 'timescaledb, pg_stat_statements, auto_explain' # Config: Preload extension libraries
    pg_extensions: [ postgis, timescaledb, pgvector ]  # Install: Install extension packages

10.15.1 - Quick Start

Four-step process overview for using extensions

Using extensions in Pigsty requires four steps: Download, Install, Config, and Create.

  1. Download: Download extension packages to the local repository (Pigsty has already downloaded mainstream extensions by default)
  2. Install: Install extension packages on cluster nodes
  3. Config: Some extensions need to be preloaded or configured with parameters
  4. Create: Execute CREATE EXTENSION in the database to create the extension

Declarative Configuration

Declare extensions in the Pigsty configuration manifest, and they will be automatically installed and created during cluster initialization:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_databases:
      - name: meta
        extensions: [ postgis, timescaledb, vector ]   # Create extensions in database
    pg_libs: 'timescaledb, pg_stat_statements, auto_explain' # Preload extension libraries
    pg_extensions: [ postgis, timescaledb, pgvector ]  # Install extension packages

After executing ./pgsql.yml to initialize the cluster, the three extensions postgis, timescaledb, and vector will be available in the meta database.


Imperative Operations

For existing clusters, you can add extensions using command-line methods:

# 1. Install extension packages
./pgsql.yml -l pg-meta -t pg_extension -e '{"pg_extensions":["pgvector"]}'

# 2. Preload extension (if needed, requires restart after modification)
pg edit-config pg-meta --force -p shared_preload_libraries='timescaledb, pg_stat_statements, auto_explain'

# 3. Create extension in database
psql -d meta -c 'CREATE EXTENSION vector;'

You can also use the pig package manager to install directly:

pig install pgvector        # Install extension package
pig extension create vector  # Create extension in database

Process Quick Reference

StepParameter/CommandDescription
Downloadrepo_extra_packagesSpecify extension packages to download to local repository
Installpg_extensionsSpecify extension packages to install on cluster
Configpg_libsPreload extensions to shared_preload_libraries
Createpg_databases.extensionsAutomatically execute CREATE EXTENSION in database

For detailed instructions, please refer to each subsection: Download, Install, Config, Create

10.15.2 - Introduction

Core concepts of PostgreSQL extensions and the Pigsty extension ecosystem

Extensions are the soul of PostgreSQL. Pigsty includes 440+ pre-compiled, out-of-the-box extension plugins, fully unleashing PostgreSQL’s potential.


What are Extensions

PostgreSQL extensions are a modular mechanism that allows enhancing database functionality without modifying the core code. An extension typically consists of three parts:

  • Control file (.control): Required, contains extension metadata
  • SQL scripts (.sql): Optional, defines functions, types, operators, and other database objects
  • Dynamic library (.so): Optional, provides high-performance functionality implemented in C

Extensions can add to PostgreSQL: new data types, index methods, functions and operators, foreign data access, procedural languages, performance monitoring, security auditing, and more.


Core Extensions

Among the extensions included in Pigsty, the following are most representative:

ExtensionDescription
PostGISGeospatial data types and indexes, de facto GIS standard
TimescaleDBTime-series database with continuous aggregates, columnar storage, auto-compression
PGVectorVector data type with HNSW/IVFFlat indexes, essential for AI applications
CitusDistributed database with horizontal sharding capabilities
pg_duckdbEmbedded DuckDB analytical engine for OLAP acceleration
ParadeDBElasticSearch-level full-text search capabilities
Apache AGEGraph database supporting OpenCypher query language
pg_graphqlNative GraphQL query support

Most extensions can coexist and even be combined, creating synergistic effects far greater than the sum of their parts.


Extension Categories

Pigsty organizes extensions into 16 categories:

CategoryAliasDescriptionTypical Extensions
Time-seriestimeTime-series data processingtimescaledb, pg_cron, periods
GeospatialgisGeospatial datapostgis, h3, pgrouting
VectorragVector retrieval and AIpgvector, vchord, pg_vectorize
SearchftsFull-text searchpgroonga, zhparser, pg_bigm
AnalyticsolapOLAP and analyticspg_duckdb, pg_mooncake, citus
FeaturefeatFeature enhancementsage, pg_graphql, hll, rum
LanguagelangProcedural languagesplpython3u, pljava, plv8
TypetypeData typeshstore, ltree, ip4r
UtilityutilUtility toolshttp, pg_net, pgjwt
FunctionfuncFunction librariespg_uuidv7, topn, tdigest
AdminadminOperations managementpg_repack, pg_squeeze, pgagent
StatstatMonitoring statisticspg_stat_statements, pg_qualstats, auto_explain
SecuritysecSecurity auditingpgaudit, pgsodium, pg_tde
FDWfdwForeign data accesspostgres_fdw, mysql_fdw, oracle_fdw
CompatibilitysimDatabase compatibilityorafce, babelfish
ETLetlData synchronizationpglogical, wal2json, decoderbufs

You can batch install an entire category of extensions using category aliases, for example: pg_extensions: [ pgsql-gis, pgsql-rag ].


Predefined Extension Stacks

Pigsty provides several predefined extension stacks for convenient scenario-based selection:

StackIncluded Extensions
gis-stackpostgis, pgrouting, pointcloud, h3, q3c, ogr_fdw
rag-stackpgvector, vchord, pgvectorscale, pg_similarity, pg_tiktoken
fts-stackpgroonga, pg_bigm, zhparser, hunspell
olap-stackpg_duckdb, pg_mooncake, timescaledb, pg_partman, plproxy
feat-stackage, hll, rum, pg_graphql, pg_jsonschema, jsquery
stat-stackpg_show_plans, pg_stat_kcache, pg_qualstats, pg_wait_sampling
supa-stackpg_graphql, pg_jsonschema, wrappers, pgvector, pgsodium, vault

Simply use these names in pg_extensions to install the entire stack.


Extension Resources

10.15.3 - Packages

Extension package aliases and category naming conventions

Pigsty uses a package alias mechanism to simplify extension installation and management.


Package Alias Mechanism

Managing extensions involves multiple layers of name mapping:

LayerExample pgvectorExample postgis
Extension Namevectorpostgis, postgis_topology, …
Package Aliaspgvectorpostgis
RPM Package Namepgvector_18postgis36_18*
DEB Package Namepostgresql-18-pgvectorpostgresql-18-postgis-3*

Pigsty provides a package alias abstraction layer, so users don’t need to worry about specific RPM/DEB package names:

pg_extensions: [ pgvector, postgis, timescaledb ]  # Use package aliases

Pigsty automatically translates to the correct package names based on the operating system and PostgreSQL version.

Note: When using CREATE EXTENSION, you use the extension name (e.g., vector), not the package alias (pgvector).


Category Aliases

All extensions are organized into 16 categories, which can be batch installed using category aliases:

# Use generic category aliases (auto-adapt to current PG version)
pg_extensions: [ pgsql-gis, pgsql-rag, pgsql-fts ]

# Or use version-specific category aliases
pg_extensions: [ pg18-gis, pg18-rag, pg18-fts ]

Except for the olap category, all category extensions can be installed simultaneously. Within the olap category, there are conflicts: pg_duckdb and pg_mooncake are mutually exclusive.


Category List

CategoryDescriptionTypical Extensions
timeTime-seriestimescaledb, pg_cron, periods
gisGeospatialpostgis, h3, pgrouting
ragVector/RAGpgvector, pgml, vchord
ftsFull-text Searchpg_trgm, zhparser, pgroonga
olapAnalyticscitus, pg_duckdb, pg_analytics
featFeatureage, pg_graphql, rum
langLanguageplpython3u, pljava, plv8
typeData Typehstore, ltree, citext
utilUtilityhttp, pg_net, pgjwt
funcFunctionpgcrypto, uuid-ossp, pg_uuidv7
adminAdminpg_repack, pgagent, pg_squeeze
statStatisticspg_stat_statements, pg_qualstats, auto_explain
secSecuritypgaudit, pgcrypto, pgsodium
fdwForeign Data Wrapperpostgres_fdw, mysql_fdw, oracle_fdw
simCompatibilityorafce, babelfishpg_tds
etlData/ETLpglogical, wal2json, decoderbufs

Browse Extension Catalog

You can browse detailed information about all available extensions on the Pigsty Extension Catalog website, including:

  • Extension name, description, version
  • Supported PostgreSQL versions
  • Supported OS distributions
  • Installation methods, preloading requirements
  • License, source repository

10.15.4 - Download

Download extension packages from software repositories to local

Before installing extensions, ensure that extension packages are downloaded to the local repository or available from upstream.


Default Behavior

Pigsty automatically downloads mainstream extensions available for the default PostgreSQL version to the local software repository during installation.

Benefits of using a local repository:

  • Accelerated installation, avoiding repeated downloads
  • Reduced network traffic consumption
  • Improved delivery reliability
  • Ensured version consistency

Download New Extensions

To download additional extensions, add them to repo_extra_packages and rebuild the repository:

all:
  vars:
    repo_extra_packages: [ pgvector, postgis, timescaledb, pg_duckdb ]
# Re-download packages to local repository
./infra.yml -t repo_build

# Refresh package source cache on all nodes
./node.yml -t node_repo

Using Upstream Repositories

You can also install directly from internet upstream repositories without pre-downloading:

# Add upstream software sources on nodes
./node.yml -t node_repo -e node_repo_modules=node,pgsql

This approach is suitable for:

  • Quick testing of latest versions
  • Installing rare extensions
  • Environments with good network conditions

But may face:

  • Network instability affecting installation
  • Version inconsistency risks

Extension Sources

Extension packages come from two main sources:

RepositoryDescription
PGDGPostgreSQL official repository, providing core extensions
PigstyPigsty supplementary repository, providing additional extensions

The Pigsty repository only includes extensions not present in the PGDG repository. Once an extension enters the PGDG repository, the Pigsty repository will remove it or keep it consistent.

Repository URLs:

For detailed repository configuration, see Extension Repository.

10.15.5 - Install

Install extension packages on cluster nodes

Pigsty uses the operating system’s package manager (yum/apt) to install extension packages.


Two parameters are used to specify extensions to install:

ParameterPurposeDefault Behavior
pg_packagesGlobal common packagesEnsure present (no upgrade)
pg_extensionsCluster-specific extensionsInstall latest version

pg_packages is typically used to specify base components needed by all clusters (PostgreSQL kernel, Patroni, pgBouncer, etc.) and essential extensions.

pg_extensions is used to specify extensions needed by specific clusters.

pg_packages:                           # Global base packages
  - pgsql-main pgsql-common
pg_extensions:                         # Cluster extensions
  - postgis timescaledb pgvector

Install During Cluster Initialization

Declare extensions in cluster configuration, and they will be automatically installed during initialization:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_extensions: [ postgis, timescaledb, pgvector, pg_duckdb ]

When executing ./pgsql.yml to initialize the cluster, extensions will be automatically installed.


Install Extensions on Existing Cluster

For initialized clusters, there are multiple ways to install extensions:

Using Pigsty Playbook

# Install using playbook after modifying configuration
./pgsql.yml -l pg-meta -t pg_extension

# Or specify extensions directly on command line
./pgsql.yml -l pg-meta -t pg_extension -e '{"pg_extensions":["pg_duckdb"]}'

Using pig Package Manager

# Install extension using pig
pig install pg_duckdb

# Batch install
ansible pg-meta -b -a 'pig install pg_duckdb pgvector'

Using Package Manager Directly

# EL systems
sudo yum install -y pg_duckdb_18*

# Debian/Ubuntu systems
sudo apt install -y postgresql-18-pg-duckdb

Using Package Aliases

Pigsty supports using standardized package aliases, automatically translating to package names for the corresponding PG version:

pg_extensions:
  - pgvector           # Auto-translates to pgvector_18* (EL) or postgresql-18-pgvector (Debian)
  - postgis            # Auto-translates to postgis36_18* (EL) or postgresql-18-postgis-3* (Debian)
  - pgsql-gis          # Category alias, installs entire GIS category of extensions

You can also use raw package names directly:

pg_extensions:
  - pgvector_18*                    # EL system raw package name
  - postgresql-18-pgvector          # Debian system raw package name

For package alias definitions, see:


Verify Installation

After installation, verify in the database:

-- Check installed extensions
SELECT * FROM pg_available_extensions WHERE name = 'vector';

-- Check if extension files exist
\dx

10.15.6 - Config

Preload extension libraries and configure extension parameters

Some extensions require preloading dynamic libraries or configuring parameters before use. This section describes how to configure extensions.


Preload Extensions

Most extensions can be enabled directly with CREATE EXTENSION after installation, but some extensions using PostgreSQL’s Hook mechanism require preloading.

Preloading is specified via the shared_preload_libraries parameter and requires a database restart to take effect.

Extensions Requiring Preload

Common extensions that require preloading:

ExtensionDescription
timescaledbTime-series database extension, must be placed first
citusDistributed database extension, must be placed first
pg_stat_statementsSQL statement statistics, enabled by default in Pigsty
auto_explainAutomatically log slow query execution plans, enabled by default in Pigsty
pg_cronScheduled task scheduling
pg_netAsynchronous HTTP requests
pg_tleTrusted language extensions
pgauditAudit logging
pg_stat_kcacheKernel statistics
pg_squeezeOnline table space reclamation
pgmlPostgresML machine learning

For the complete list, see the Extension Catalog (marked with LOAD).

Preload Order

The loading order of extensions in shared_preload_libraries is important:

  • timescaledb and citus must be placed first
  • If using both, citus should come before timescaledb
  • Statistics extensions should come after pg_stat_statements to use the same query_id
pg_libs: 'citus, timescaledb, pg_stat_statements, auto_explain'

Configure During Cluster Initialization

When creating a new cluster, use the pg_libs parameter to specify preloaded extensions:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_libs: 'timescaledb, pg_stat_statements, auto_explain'
    pg_extensions: [ timescaledb, postgis, pgvector ]

The value of pg_libs will be written to shared_preload_libraries during cluster initialization.

Default Value

The default value of pg_libs is pg_stat_statements, auto_explain. These two Contrib extensions provide basic observability:

  • pg_stat_statements: Track execution statistics of all SQL statements
  • auto_explain: Automatically log execution plans for slow queries

Modify Configuration on Existing Cluster

For initialized clusters, use patronictl to modify shared_preload_libraries:

# Add timescaledb to preload libraries
pg edit-config pg-meta --force -p shared_preload_libraries='timescaledb, pg_stat_statements, auto_explain'

# Restart cluster to apply configuration
pg restart pg-meta

You can also directly modify postgresql.conf or use ALTER SYSTEM:

ALTER SYSTEM SET shared_preload_libraries = 'timescaledb, pg_stat_statements, auto_explain';

A PostgreSQL service restart is required after modification.


Extension Parameter Configuration

Many extensions have configurable parameters that can be set in the following locations:

During Cluster Initialization

Use the pg_parameters parameter to specify:

pg-meta:
  vars:
    pg_cluster: pg-meta
    pg_libs: 'pg_cron, pg_stat_statements, auto_explain'
    pg_parameters:
      cron.database_name: postgres           # Database used by pg_cron
      pg_stat_statements.track: all          # Track all statements
      auto_explain.log_min_duration: 1000    # Log queries exceeding 1 second

Runtime Modification

Use ALTER SYSTEM or patronictl:

-- Modify parameter
ALTER SYSTEM SET pg_stat_statements.track = 'all';

-- Reload configuration
SELECT pg_reload_conf();
# Modify using patronictl
pg edit-config pg-meta --force -p 'pg_stat_statements.track=all'

Important Notes

  1. Preload errors prevent startup: If an extension in shared_preload_libraries doesn’t exist or fails to load, PostgreSQL will not start. Ensure extensions are properly installed before adding to preload.

  2. Modification requires restart: Changes to shared_preload_libraries require restarting the PostgreSQL service to take effect.

  3. Partial functionality available: Some extensions can be partially used without preloading, but full functionality requires preloading.

  4. View current configuration: Use the following command to view current preload libraries:

SHOW shared_preload_libraries;

10.15.7 - Create

Create and enable extensions in databases

After installing extension packages, you need to execute CREATE EXTENSION in the database to use extension features.


View Available Extensions

After installing extension packages, you can view available extensions:

-- View all available extensions
SELECT * FROM pg_available_extensions;

-- View specific extension
SELECT * FROM pg_available_extensions WHERE name = 'vector';

-- View enabled extensions
SELECT * FROM pg_extension;

Create Extensions

Use CREATE EXTENSION to enable extensions in the database:

-- Create extension
CREATE EXTENSION vector;

-- Create extension in specific schema
CREATE EXTENSION postgis SCHEMA public;

-- Automatically install dependent extensions
CREATE EXTENSION postgis_topology CASCADE;

-- Create if not exists
CREATE EXTENSION IF NOT EXISTS vector;

Note: CREATE EXTENSION uses the extension name (e.g., vector), not the package alias (pgvector).


Create During Cluster Initialization

Declare extensions in pg_databases, and they will be automatically created during cluster initialization:

pg-meta:
  vars:
    pg_cluster: pg-meta
    pg_databases:
      - name: meta
        extensions:
          - { name: vector }                         # Use default schema
          - { name: postgis, schema: public }        # Specify schema
          - { name: pg_stat_statements, schema: monitor }

Pigsty will automatically execute CREATE EXTENSION after database creation.


Extensions Requiring Preload

Some extensions must be added to shared_preload_libraries and restarted before creation:

pg-meta:
  vars:
    pg_cluster: pg-meta
    pg_libs: 'timescaledb, pg_stat_statements, auto_explain'
    pg_databases:
      - name: meta
        extensions:
          - { name: timescaledb }  # Requires preload

If you try to create without preloading, you will receive an error message.

Common extensions requiring preload: timescaledb, citus, pg_cron, pg_net, pgaudit, etc. See Configure Extensions.


Extension Dependencies

Some extensions depend on other extensions and need to be created in order:

-- postgis_topology depends on postgis
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;

-- Or use CASCADE to automatically install dependencies
CREATE EXTENSION postgis_topology CASCADE;

Extensions Not Requiring Creation

A few extensions don’t provide SQL interfaces and don’t need CREATE EXTENSION:

ExtensionDescription
wal2jsonLogical decoding plugin, used directly in replication slots
decoderbufsLogical decoding plugin
decoder_rawLogical decoding plugin

These extensions can be used immediately after installation, for example:

-- Create logical replication slot using wal2json
SELECT * FROM pg_create_logical_replication_slot('test_slot', 'wal2json');

View Extension Information

-- View extension details
\dx+ vector

-- View objects contained in extension
SELECT * FROM pg_extension_config_dump('vector');

-- View extension version
SELECT extversion FROM pg_extension WHERE extname = 'vector';

10.15.8 - Update

Upgrade PostgreSQL extension versions

Extension updates involve two levels: package updates (operating system level) and extension object updates (database level).


Update Packages

Use package managers to update extension packages:

# EL systems
sudo yum update pgvector_18*

# Debian/Ubuntu systems
sudo apt update && sudo apt upgrade postgresql-18-pgvector

Batch update using Pigsty:

# Update extension packages for specified cluster
./pgsql.yml -l pg-meta -t pg_extension -e '{"pg_extensions":["pgvector"]}'

# Using pig package manager
pig update pgvector

Update Extension Objects

After package updates, extension objects in the database may need to be synchronized.

View Updatable Extensions

-- View installed extensions and their versions
SELECT name, default_version, installed_version
FROM pg_available_extensions
WHERE installed_version IS NOT NULL;

-- View upgradable extensions
SELECT name, installed_version, default_version
FROM pg_available_extensions
WHERE installed_version IS NOT NULL
  AND installed_version <> default_version;

Execute Extension Update

-- Update to latest version
ALTER EXTENSION pgvector UPDATE;

-- Update to specific version
ALTER EXTENSION pgvector UPDATE TO '0.8.0';

View Update Paths

-- View available upgrade paths for extension
SELECT * FROM pg_extension_update_paths('pgvector');

Important Notes

  1. Backup first: Backup the database before updating extensions, especially for extensions involving data type changes.

  2. Check compatibility: Some extension major version upgrades may be incompatible. Consult the extension’s upgrade documentation.

  3. Preloaded extensions: If updating a preloaded extension (like timescaledb), a database restart may be required after the update.

  4. Dependencies: If other extensions depend on the updated extension, update them in dependency order.

  5. Replication environments: In master-slave replication environments, test updates on slaves first, then update the master after confirmation.


Common Issues

Update Failure

If ALTER EXTENSION UPDATE fails, it may be because:

  • No available upgrade path
  • Extension is in use
  • Insufficient permissions
-- View extension dependencies
SELECT * FROM pg_depend WHERE refobjid = (SELECT oid FROM pg_extension WHERE extname = 'pgvector');

Rollback Update

PostgreSQL extensions typically don’t support direct rollback. To rollback:

  1. Restore from backup
  2. Or: Uninstall new version extension, install old version package, recreate extension

10.15.9 - Remove

Uninstall PostgreSQL extensions

Removing extensions involves two levels: dropping extension objects (database level) and uninstalling packages (operating system level).


Drop Extension Objects

Use DROP EXTENSION to remove extensions from the database:

-- Drop extension
DROP EXTENSION pgvector;

-- If there are dependent objects, cascade delete is required
DROP EXTENSION pgvector CASCADE;

Warning: CASCADE will drop all objects that depend on this extension (tables, functions, views, etc.). Use with caution.

Check Extension Dependencies

It’s recommended to check dependencies before dropping:

-- View objects that depend on an extension
SELECT
    classid::regclass,
    objid,
    deptype
FROM pg_depend
WHERE refobjid = (SELECT oid FROM pg_extension WHERE extname = 'pgvector');

-- View tables using extension types
SELECT
    c.relname AS table_name,
    a.attname AS column_name,
    t.typname AS type_name
FROM pg_attribute a
JOIN pg_class c ON a.attrelid = c.oid
JOIN pg_type t ON a.atttypid = t.oid
WHERE t.typname = 'vector';

Remove Preload

If the extension is in shared_preload_libraries, it must be removed from the preload list after dropping:

# Modify shared_preload_libraries, remove extension
pg edit-config pg-meta --force -p shared_preload_libraries='pg_stat_statements, auto_explain'

# Restart to apply configuration
pg restart pg-meta

Uninstall Packages

After dropping the extension from the database, you can optionally uninstall the package:

# EL systems
sudo yum remove pgvector_18*

# Debian/Ubuntu systems
sudo apt remove postgresql-18-pgvector

# Using pig package manager
pig remove pgvector

Typically keeping the package doesn’t cause issues. Only uninstall when you need to free disk space or resolve conflicts.


Important Notes

  1. Data loss risk: Using CASCADE will drop dependent objects, potentially causing data loss.

  2. Application compatibility: Ensure applications no longer use the extension’s functionality before dropping.

  3. Preload order: If dropping a preloaded extension, be sure to also remove it from shared_preload_libraries, otherwise the database may fail to start.

  4. Master-slave environments: In replication environments, DROP EXTENSION automatically replicates to slaves.


Operation Sequence

Complete extension removal workflow:

# 1. Check dependencies
psql -d mydb -c "SELECT * FROM pg_depend WHERE refobjid = (SELECT oid FROM pg_extension WHERE extname = 'pgvector');"

# 2. Drop extension from database
psql -d mydb -c "DROP EXTENSION pgvector;"

# 3. If it's a preloaded extension, remove from shared_preload_libraries
pg edit-config pg-meta --force -p shared_preload_libraries='pg_stat_statements, auto_explain'

# 4. Restart database (if preload configuration was modified)
pg restart pg-meta

# 5. Optional: Uninstall package
sudo yum remove pgvector_18*

10.15.10 - Default Extensions

PostgreSQL extensions installed by default in Pigsty

Pigsty installs and enables some core extensions by default when initializing PostgreSQL clusters.


Default Installed Extensions

Extensions installed by default via pg_packages:

ExtensionDescription
pg_repackHandle table bloat online, important maintenance tool
wal2jsonLogical decoding outputs JSON format changes, commonly used in CDC scenarios

Extensions optionally installed via pg_extensions (commented by default):

ExtensionDescription
postgisGeospatial database extension
timescaledbTime-series database extension
pgvectorVector data type and indexes

Default Enabled Extensions

Extensions enabled by default in all databases via pg_default_extensions:

ExtensionSchemaDescription
pg_stat_statementsmonitorSQL statement execution statistics
pgstattuplemonitorTuple-level statistics
pg_buffercachemonitorBuffer cache inspection
pageinspectmonitorPage-level inspection
pg_prewarmmonitorRelation prewarming
pg_visibilitymonitorVisibility map inspection
pg_freespacemapmonitorFree space map inspection
postgres_fdwpublicPostgreSQL foreign data wrapper
file_fdwpublicFile foreign data wrapper
btree_gistpublicB-tree GiST operator classes
btree_ginpublicB-tree GIN operator classes
pg_trgmpublicTrigram matching
intaggpublicInteger aggregator
intarraypublicInteger array functions
pg_repack-Online table reorganization

These extensions provide basic monitoring, operations, and feature enhancement capabilities.


Default Preloaded Extensions

Extensions preloaded by default into shared_preload_libraries via pg_libs:

ExtensionDescription
pg_stat_statementsTrack execution statistics of all SQL statements
auto_explainAutomatically log execution plans for slow queries

These two extensions provide basic observability and are strongly recommended to keep.


Customize Default Extensions

You can customize default installed and enabled extensions by modifying configuration parameters:

all:
  vars:
    # Modify default extension packages
    pg_packages:
      - pgsql-main pgsql-common
      - pg_repack_$v* wal2json_$v*

    # Modify default installed extensions
    pg_extensions: [ postgis, timescaledb, pgvector ]

    # Modify default preloaded extensions
    pg_libs: 'timescaledb, pg_stat_statements, auto_explain'

    # Modify default enabled extensions
    pg_default_extensions:
      - { name: pg_stat_statements, schema: monitor }
      - { name: pg_repack }
      # ... add more

For detailed extension usage, please refer to:

10.15.11 - Repository

Pigsty extension software repository configuration

Pigsty provides supplementary extension repositories, offering additional extension packages on top of the PGDG official repository.


YUM Repository

Applicable to EL 7/8/9/10 and compatible systems (RHEL, Rocky, AlmaLinux, CentOS, etc.).

Add Repository

# Add GPG public key
curl -fsSL https://repo.pigsty.io/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

# Add repository configuration
curl -fsSL https://repo.pigsty.io/yum/repo | sudo tee /etc/yum.repos.d/pigsty.repo >/dev/null

# Refresh cache
sudo yum makecache

China Mainland Mirror

curl -fsSL https://repo.pigsty.cc/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null
curl -fsSL https://repo.pigsty.cc/yum/repo | sudo tee /etc/yum.repos.d/pigsty.repo >/dev/null

Repository URLs


APT Repository

Applicable to Debian 11/12/13 and Ubuntu 22.04/24.04 and compatible systems.

Add Repository

# Add GPG public key
curl -fsSL https://repo.pigsty.io/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

# Get distribution codename and add repository
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/infra generic main
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/pgsql ${distro_codename} main
EOF

# Refresh cache
sudo apt update

China Mainland Mirror

curl -fsSL https://repo.pigsty.cc/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.cc/apt/infra generic main
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.cc/apt/pgsql/${distro_codename} ${distro_codename} main
EOF

Repository URLs


GPG Signature

All packages are signed with GPG:

  • Fingerprint: 9592A7BC7A682E7333376E09E7935D8DB9BD8B20
  • Short ID: B9BD8B20

Repository Policy

The Pigsty repository follows these principles:

  1. Supplementary: Only includes extensions not present in the PGDG repository
  2. Consistency: Once an extension enters the PGDG repository, the Pigsty repository will remove it or keep it consistent
  3. Compatibility: Supports multiple major versions of PostgreSQL 13-18
  4. Multi-platform: Supports x86_64 and aarch64 architectures

10.16 - Kernel Forks

How to use other PostgreSQL kernel forks in Pigsty? Such as Citus, Babelfish, IvorySQL, PolarDB, etc.

In Pigsty, you can replace the “native PG kernel” with different “flavors” of PostgreSQL forks to achieve special features and effects.

Pigsty supports various PostgreSQL kernels and compatible forks, enabling you to simulate different database systems while leveraging PostgreSQL’s ecosystem. Each kernel provides unique capabilities and compatibility layers.

KernelKey FeatureDescription
PostgreSQLOriginal FlavorVanilla PostgreSQL with 440 extensions
CitusHorizontal ScalingDistributed PostgreSQL via native extension
WiltonDBSQL Server CompatibleSQL Server wire-protocol compatibility
IvorySQLOracle CompatibleOracle syntax and PL/SQL compatibility
OpenHaloMySQL CompatibleMySQL wire-protocol compatibility
PerconaTransparent EncryptionPercona Distribution with pg_tde
FerretDBMongoDB MigrationMongoDB wire-protocol compatibility
OrioleDBOLTP OptimizationZheap, No bloat, S3 Storage
PolarDBAurora-style RACRAC, China domestic compliance
SupabaseBackend as a ServiceBaaS based on PostgreSQL, Firebase alternative
CloudberryMPP DW & AnalyticsMassively parallel processing data warehouse

10.16.1 - PostgreSQL

Vanilla PostgreSQL kernel with 440 extensions

PostgreSQL is the world’s most advanced and popular open-source database.

Pigsty supports PostgreSQL 13 ~ 18 and provides 440 PG extensions.


Quick Start

Install Pigsty using the pgsql configuration template.

./configure -c pgsql     # Use postgres kernel
./deploy.yml             # Set up everything with pigsty

Most configuration templates use PostgreSQL kernel by default, for example:

  • meta : Default, postgres with core extensions (vector, postgis, timescale)
  • rich : postgres with all extensions installed
  • slim : postgres only, no monitoring infrastructure
  • full : 4-node sandbox for HA demonstration
  • pgsql : minimal postgres kernel configuration example

Configuration

Vanilla PostgreSQL kernel requires no special adjustments:

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 }
      - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
    pg_databases:
      - { name: meta, baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ vector ]}
    pg_hba_rules:
      - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
    node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # Full backup at 1 AM daily
    pg_packages: [ pgsql-main, pgsql-common ]   # pg kernel and common utilities
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

Version Selection

To use a different PostgreSQL major version, you can configure it using the -v parameter:

./configure -c pgsql            # Default is postgresql 18, no need to specify explicitly
./configure -c pgsql -v 17      # Use postgresql 17
./configure -c pgsql -v 16      # Use postgresql 16
./configure -c pgsql -v 15      # Use postgresql 15
./configure -c pgsql -v 14      # Use postgresql 14
./configure -c pgsql -v 13      # Use postgresql 13

If a PostgreSQL cluster is already installed, you need to uninstall it before installing a new version:

./pgsql-rm.yml # -l pg-meta

Extension Ecosystem

Pigsty provides a rich extension ecosystem for PostgreSQL, including:

  • Time-series: timescaledb, pg_cron, periods
  • Geospatial: postgis, h3, pgrouting
  • Vector: pgvector, pgml, vchord
  • Search: pg_trgm, zhparser, pgroonga
  • Analytics: citus, pg_duckdb, pg_analytics
  • Features: age, pg_graphql, rum
  • Languages: plpython3u, pljava, plv8
  • Types: hstore, ltree, citext
  • Utilities: http, pg_net, pgjwt
  • Functions: pgcrypto, uuid-ossp, pg_uuidv7
  • Administration: pg_repack, pgagent, pg_squeeze
  • Statistics: pg_stat_statements, pg_qualstats, auto_explain
  • Security: pgaudit, pgcrypto, pgsodium
  • Foreign: postgres_fdw, mysql_fdw, oracle_fdw
  • Compatibility: orafce, babelfishpg_tds
  • Data: pglogical, wal2json, decoderbufs

For details, please refer to Extension Catalog.

10.16.2 - Supabase

How to self-host Supabase with Pigsty, deploy an open-source Firebase alternative with a complete backend stack in one click.

Supabase — Build in a weekend, Scale to millions

Supabase is an open-source Firebase alternative that wraps PostgreSQL and provides authentication, out-of-the-box APIs, edge functions, real-time subscriptions, object storage, and vector embedding capabilities. This is a low-code all-in-one backend platform that lets you skip most backend development work, requiring only database design and frontend knowledge to quickly ship products!

Supabase’s motto is: “Build in a weekend, Scale to millions”. Indeed, Supabase is extremely cost-effective at small to micro scales (4c8g), like a cyber bodhisattva. — But when you really scale to millions of users — you should seriously consider self-hosting Supabase — whether for functionality, performance, or cost considerations.

Pigsty provides you with a complete one-click self-hosting solution for Supabase. Self-hosted Supabase enjoys full PostgreSQL monitoring, IaC, PITR, and high availability, and compared to Supabase cloud services, it provides up to 440 out-of-the-box PostgreSQL extensions and can more fully utilize the performance and cost advantages of modern hardware.

For the complete self-hosting tutorial, please refer to: Supabase Self-Hosting Manual


Quick Start

Pigsty’s default supa.yml configuration template defines a single-node Supabase.

First, use Pigsty’s standard installation process to install the MinIO and PostgreSQL instances required for Supabase:

 curl -fsSL https://repo.pigsty.io/get | bash
./bootstrap          # environment check, install dependencies
./configure -c supa  # Important: please modify passwords and other key information in the configuration file!
./deploy.yml         # install Pigsty, deploy PGSQL and MINIO!

Before deploying Supabase, please modify the Supabase parameters in the pigsty.yml configuration file according to your actual situation (mainly passwords!)

Then, run supabase.yml to complete the remaining work and deploy Supabase containers

./supabase.yml       # install Docker and deploy stateless Supabase components!

For users in China, please configure appropriate Docker mirror sites or proxy servers to bypass GFW to pull DockerHub images. For professional subscriptions, we provide the ability to offline install Pigsty and Supabase without internet access.

Pigsty exposes web services through Nginx on the admin node/INFRA node by default. You can add DNS resolution for supa.pigsty pointing to this node locally, then access https://supa.pigsty through a browser to enter the Supabase Studio management interface.

Default username and password: supabase / pigsty


Architecture Overview

Pigsty uses the Docker Compose template provided by Supabase as a blueprint, extracting the stateless components to be handled by Docker Compose. The stateful database and object storage containers are replaced with external PostgreSQL clusters and MinIO services managed by Pigsty.

Supabase: Self-Hosting with Docker

After transformation, Supabase itself is stateless, so you can run, stop, or even run multiple stateless Supabase containers simultaneously on the same PGSQL/MINIO for scaling.

Pigsty uses a single-node PostgreSQL instance on the local machine as Supabase’s core backend database by default. For serious production deployments, we recommend using Pigsty to deploy a PG high-availability cluster with at least three nodes. Or at least use external object storage as a PITR backup repository for failover.

Pigsty uses the SNSD MinIO service on the local machine as file storage by default. For serious production environment deployments, you can use external S3-compatible object storage services, or use other multi-node multi-drive MinIO clusters independently deployed by Pigsty.


Configuration Details

When self-hosting Supabase, the directory app/supabase containing resources required for Docker Compose will be copied entirely to the target node (default supabase group) at /opt/supabase, and deployed in the background using docker compose up -d.

All configuration parameters are defined in the .env file and docker-compose.yml template. But you usually don’t need to modify these two templates directly. You can specify parameters in .env in supa_config, and these configurations will automatically override or append to the final /opt/supabase/.env core configuration file.

The most critical parameters here are jwt_secret, and the corresponding anon_key and service_role_key. For serious production use, please be sure to refer to the instructions and tools in the Supabase Self-Hosting Manual for settings. If you want to provide services using a domain name, you can specify your domain name in site_url, api_external_url, and supabase_public_url.

Pigsty uses local MinIO by default. If you want to use S3 or MinIO as file storage, you need to configure parameters such as s3_bucket, s3_endpoint, s3_access_key, s3_secret_key.

Generally speaking, you also need to use an external SMTP service to send emails. Email services are not recommended for self-hosting, please consider using mature third-party services such as Mailchimp, Aliyun Mail Push, etc.

For users in mainland China, we recommend you configure docker_registry_mirrors mirror sites, or use proxy_env to specify available proxy servers to bypass GFW, otherwise pulling images from DockerHub may fail or be extremely slow!

# launch supabase stateless part with docker compose:
# ./supabase.yml
supabase:
  hosts:
    10.10.10.10: { supa_seq: 1 }  # instance id
  vars:
    supa_cluster: supa            # cluster name
    docker_enabled: true          # enable docker

    # use these to pull docker images via proxy and mirror registries
    #docker_registry_mirrors: ['https://docker.xxxxx.io']
    #proxy_env:   # add [OPTIONAL] proxy env to /etc/docker/daemon.json configuration file
    #  no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
    #  #all_proxy: http://user:pass@host:port

    # these configuration entries will OVERWRITE or APPEND to /opt/supabase/.env file (src template: app/supabase/.env)
    # check https://github.com/pgsty/pigsty/blob/main/app/supabase/.env for default values
    supa_config:

      # IMPORTANT: CHANGE JWT_SECRET AND REGENERATE CREDENTIAL ACCORDING!!!!!!!!!!!
      # https://supabase.com/docs/guides/self-hosting/docker#securing-your-services
      jwt_secret: your-super-secret-jwt-token-with-at-least-32-characters-long
      anon_key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
      service_role_key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
      dashboard_username: supabase
      dashboard_password: pigsty

      # postgres connection string (use the correct ip and port)
      postgres_host: 10.10.10.10
      postgres_port: 5436             # access via the 'default' service, which always route to the primary postgres
      postgres_db: postgres
      postgres_password: DBUser.Supa  # password for supabase_admin and multiple supabase users

      # expose supabase via domain name
      site_url: http://supa.pigsty
      api_external_url: http://supa.pigsty
      supabase_public_url: http://supa.pigsty

      # if using s3/minio as file storage
      s3_bucket: supa
      s3_endpoint: https://sss.pigsty:9000
      s3_access_key: supabase
      s3_secret_key: S3User.Supabase
      s3_force_path_style: true
      s3_protocol: https
      s3_region: stub
      minio_domain_ip: 10.10.10.10  # sss.pigsty domain name will resolve to this ip statically

      # if using SMTP (optional)
      #smtp_admin_email: [email protected]
      #smtp_host: supabase-mail
      #smtp_port: 2500
      #smtp_user: fake_mail_user
      #smtp_pass: fake_mail_password
      #smtp_sender_name: fake_sender
      #enable_anonymous_users: false



10.16.3 - Percona

Percona Postgres distribution with TDE transparent encryption support

Percona Postgres is a patched Postgres kernel with pg_tde (Transparent Data Encryption) extension.

It’s compatible with PostgreSQL 18.1 and available on all Pigsty-supported platforms.


Quick Start

Use Pigsty’s standard installation process with the pgtde configuration template.

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty;
./configure -c pgtde     # Use percona postgres kernel
./deploy.yml             # Set up everything with pigsty

Configuration

The following parameters need to be adjusted to deploy a Percona cluster:

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: pgsql admin user }
      - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
    pg_databases:
      - name: meta
        baseline: cmdb.sql
        comment: pigsty tde database
        schemas: [pigsty]
        extensions: [ vector, postgis, pg_tde ,pgaudit, { name: pg_stat_monitor, schema: monitor } ]
    pg_hba_rules:
      - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
    node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # Full backup at 1 AM daily

    # Percona PostgreSQL TDE specific settings
    pg_packages: [ percona-main, pgsql-common ]  # Install percona postgres packages
    pg_libs: 'pg_tde, pgaudit, pg_stat_statements, pg_stat_monitor, auto_explain'

Extensions

Percona provides 80 available extensions, including pg_tde, pgvector, postgis, pgaudit, set_user, pg_stat_monitor, and other useful third-party extensions.

ExtensionVersionDescription
pg_tde2.1Percona transparent data encryption access method
vector0.8.1Vector data type and ivfflat and hnsw access methods
postgis3.5.4PostGIS geometry and geography types and functions
pgaudit18.0Provides auditing functionality
pg_stat_monitor2.3PostgreSQL query performance monitoring tool
set_user4.2.0Similar to SET ROLE but with additional logging
pg_repack1.5.3Reorganize tables in PostgreSQL databases with minimal locks
hstore1.8Data type for storing sets of (key, value) pairs
ltree1.3Data type for hierarchical tree-like structures
pg_trgm1.6Text similarity measurement and index searching based on trigrams

For the complete list of 80 extensions, please refer to the Percona Postgres official documentation.


Key Features

  • Transparent Data Encryption: Provides data-at-rest encryption using the pg_tde extension
  • PostgreSQL 18 Compatible: Based on the latest PostgreSQL 18 version
  • Enterprise Extensions: Includes enterprise-grade features like pgaudit, pg_stat_monitor
  • Complete Ecosystem: Supports popular extensions like pgvector, PostGIS

Note: Currently in stable stage - thoroughly evaluate before production use.

10.16.4 - OpenHalo

MySQL compatible Postgres 14 fork

OpenHalo is an open-source PostgreSQL kernel that provides MySQL wire protocol compatibility.

OpenHalo is based on PostgreSQL 14.10 kernel version and provides wire protocol compatibility with MySQL 5.7.32-log / 8.0 versions.

Pigsty provides deployment support for OpenHalo on all supported Linux platforms.


Quick Start

Use Pigsty’s standard installation process with the mysql configuration template.

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty;
./configure -c mysql    # Use MySQL (openHalo) configuration template
./deploy.yml            # Install, for production deployment please modify passwords in pigsty.yml first

For production deployment, ensure you modify the password parameters in the pigsty.yml configuration file before running the install playbook.


Configuration

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 }
      - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
    pg_databases:
      - {name: postgres, extensions: [aux_mysql]} # mysql compatible database
      - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty]}
    pg_hba_rules:
      - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
    node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # Full backup at 1 AM daily

    # OpenHalo specific settings
    pg_mode: mysql                    # HaloDB's MySQL compatibility mode
    pg_version: 14                    # Current HaloDB compatible PG major version 14
    pg_packages: [ openhalodb, pgsql-common ]  # Install openhalodb instead of postgresql kernel

Usage

When accessing MySQL, the actual connection uses the postgres database. Please note that the concept of “database” in MySQL actually corresponds to “Schema” in PostgreSQL. Therefore, use mysql actually uses the mysql Schema within the postgres database.

The username and password for MySQL are the same as in PostgreSQL. You can manage users and permissions using standard PostgreSQL methods.

Client Access

OpenHalo provides MySQL wire protocol compatibility, listening on port 3306 by default, allowing MySQL clients and drivers to connect directly.

Pigsty’s conf/mysql configuration installs the mysql client tool by default.

You can access MySQL using the following command:

mysql -h 127.0.0.1 -u dbuser_dba

Currently, OpenHalo officially ensures Navicat can properly access this MySQL port, but Intellij IDEA’s DataGrip access will cause errors.


Modification Notes

The OpenHalo kernel installed by Pigsty is based on the HaloTech-Co-Ltd/openHalo kernel with minor modifications:

  • Changed the default database name from halo0root back to postgres
  • Removed the 1.0. prefix from the default version number, restoring it to 14.10
  • Modified the default configuration file to enable MySQL compatibility and listen on port 3306 by default

Please note that Pigsty does not provide any warranty for using the OpenHalo kernel. Any issues or requirements encountered when using this kernel should be addressed with the original vendor.

Warning: Currently experimental - thoroughly evaluate before production use.

10.16.5 - OrioleDB

Next-generation OLTP engine for PostgreSQL

OrioleDB is a PostgreSQL storage engine extension that claims to provide 4x OLTP performance, no xid wraparound and table bloat issues, and “cloud-native” (data stored in S3) capabilities.

OrioleDB’s latest version is based on a patched PostgreSQL 17.0 and an additional extension

You can run OrioleDB as an RDS using Pigsty. It’s compatible with PG 17 and available on all supported Linux platforms. The latest version is beta12, based on PG 17_11 patch.


Quick Start

Follow Pigsty’s standard installation process using the oriole configuration template.

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty;
./configure -c oriole    # Use OrioleDB configuration template
./deploy.yml             # Install Pigsty with OrioleDB

For production deployment, ensure you modify the password parameters in the pigsty.yml configuration before running the install playbook.


Configuration

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 }
      - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
    pg_databases:
      - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty], extensions: [orioledb]}
    pg_hba_rules:
      - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
    node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # Full backup at 1 AM daily

    # OrioleDB specific settings
    pg_mode: oriole                                         # oriole compatibility mode
    pg_packages: [ orioledb, pgsql-common ]                 # Install OrioleDB kernel
    pg_libs: 'orioledb, pg_stat_statements, auto_explain'   # Load OrioleDB extension

Usage

To use OrioleDB, you need to install the orioledb_17 and oriolepg_17 packages (currently only RPM versions are available).

Initialize TPC-B-like tables with pgbench using 100 warehouses:

pgbench -is 100 meta
pgbench -nv -P1 -c10 -S -T1000 meta
pgbench -nv -P1 -c50 -S -T1000 meta
pgbench -nv -P1 -c10    -T1000 meta
pgbench -nv -P1 -c50    -T1000 meta

Next, you can rebuild these tables using the orioledb storage engine and observe the performance difference:

-- Create OrioleDB tables
CREATE TABLE pgbench_accounts_o (LIKE pgbench_accounts INCLUDING ALL) USING orioledb;
CREATE TABLE pgbench_branches_o (LIKE pgbench_branches INCLUDING ALL) USING orioledb;
CREATE TABLE pgbench_history_o (LIKE pgbench_history INCLUDING ALL) USING orioledb;
CREATE TABLE pgbench_tellers_o (LIKE pgbench_tellers INCLUDING ALL) USING orioledb;

-- Copy data from regular tables to OrioleDB tables
INSERT INTO pgbench_accounts_o SELECT * FROM pgbench_accounts;
INSERT INTO pgbench_branches_o SELECT * FROM pgbench_branches;
INSERT INTO pgbench_history_o SELECT  * FROM pgbench_history;
INSERT INTO pgbench_tellers_o SELECT * FROM pgbench_tellers;

-- Drop original tables and rename OrioleDB tables
DROP TABLE pgbench_accounts, pgbench_branches, pgbench_history, pgbench_tellers;
ALTER TABLE pgbench_accounts_o RENAME TO pgbench_accounts;
ALTER TABLE pgbench_branches_o RENAME TO pgbench_branches;
ALTER TABLE pgbench_history_o RENAME TO pgbench_history;
ALTER TABLE pgbench_tellers_o RENAME TO pgbench_tellers;

Key Features

  • No XID Wraparound: Eliminates transaction ID wraparound maintenance
  • No Table Bloat: Advanced storage management prevents table bloat
  • Cloud Storage: Native support for S3-compatible object storage
  • OLTP Optimized: Designed for transactional workloads
  • Improved Performance: Better space utilization and query performance

Note: Currently in Beta stage - thoroughly evaluate before production use.

10.16.6 - Citus

Deploy native high-availability Citus horizontally sharded clusters with Pigsty, seamlessly scaling PostgreSQL across multiple shards and accelerating OLTP/OLAP queries.

Pigsty natively supports Citus. This is a distributed horizontal scaling extension based on the native PostgreSQL kernel.


Installation

Citus is a PostgreSQL extension plugin that can be installed and enabled on a native PostgreSQL cluster following the standard plugin installation process.

./pgsql.yml -t pg_extension -e '{"pg_extensions":["citus"]}'

Configuration

To define a citus cluster, you need to specify the following parameters:

  • pg_mode must be set to citus instead of the default pgsql
  • You must define the shard name pg_shard and shard number pg_group on each shard cluster
  • You must define pg_primary_db to specify the database managed by Patroni
  • If you want to use postgres from pg_dbsu instead of the default pg_admin_username to execute admin commands, then pg_dbsu_password must be set to a non-empty plaintext password

Additionally, you need extra hba rules to allow SSL access from localhost and other data nodes.

You can define each Citus cluster as a separate group, like standard PostgreSQL clusters, as shown in conf/dbms/citus.yml:

all:
  children:
    pg-citus0: # citus shard 0
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus0 , pg_group: 0 }
    pg-citus1: # citus shard 1
      hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus1 , pg_group: 1 }
    pg-citus2: # citus shard 2
      hosts: { 10.10.10.12: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus2 , pg_group: 2 }
    pg-citus3: # citus shard 3
      hosts:
        10.10.10.13: { pg_seq: 1, pg_role: primary }
        10.10.10.14: { pg_seq: 2, pg_role: replica }
      vars: { pg_cluster: pg-citus3 , pg_group: 3 }
  vars:                               # Global parameters for all Citus clusters
    pg_mode: citus                    # pgsql cluster mode must be set to: citus
    pg_shard: pg-citus                # citus horizontal shard name: pg-citus
    pg_primary_db: meta               # citus database name: meta
    pg_dbsu_password: DBUser.Postgres # If using dbsu, you need to configure a password for it
    pg_users: [ { name: dbuser_meta ,password: DBUser.Meta ,pgbouncer: true ,roles: [ dbrole_admin ] } ]
    pg_databases: [ { name: meta ,extensions: [ { name: citus }, { name: postgis }, { name: timescaledb } ] } ]
    pg_hba_rules:
      - { user: 'all' ,db: all  ,addr: 127.0.0.1/32 ,auth: ssl ,title: 'all user ssl access from localhost' }
      - { user: 'all' ,db: all  ,addr: intra        ,auth: ssl ,title: 'all user ssl access from intranet'  }

You can also specify identity parameters for all Citus cluster members within a single group, as shown in prod.yml:

#==========================================================#
# pg-citus: 10 node citus cluster (5 x primary-replica pair)
#==========================================================#
pg-citus: # citus group
  hosts:
    10.10.10.50: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.60/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.51: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.60/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.52: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.61/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.53: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.61/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.54: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.62/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.55: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.62/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.56: { pg_group: 3, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.63/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.57: { pg_group: 3, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.63/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.58: { pg_group: 4, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.64/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.59: { pg_group: 4, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.64/24 ,pg_seq: 1, pg_role: replica }
  vars:
    pg_mode: citus                    # pgsql cluster mode: citus
    pg_shard: pg-citus                # citus shard name: pg-citus
    pg_primary_db: test               # primary database used by citus
    pg_dbsu_password: DBUser.Postgres # all dbsu password access for citus cluster
    pg_vip_enabled: true
    pg_vip_interface: eth1
    pg_extensions: [ 'citus postgis timescaledb pgvector' ]
    pg_libs: 'citus, timescaledb, pg_stat_statements, auto_explain' # citus will be added by patroni automatically
    pg_users: [ { name: test ,password: test ,pgbouncer: true ,roles: [ dbrole_admin ] } ]
    pg_databases: [ { name: test ,owner: test ,extensions: [ { name: citus }, { name: postgis } ] } ]
    pg_hba_rules:
      - { user: 'all' ,db: all  ,addr: 10.10.10.0/24 ,auth: trust ,title: 'trust citus cluster members'        }
      - { user: 'all' ,db: all  ,addr: 127.0.0.1/32  ,auth: ssl   ,title: 'all user ssl access from localhost' }
      - { user: 'all' ,db: all  ,addr: intra         ,auth: ssl   ,title: 'all user ssl access from intranet'  }

Usage

You can access any node just like accessing a regular cluster:

pgbench -i postgres://test:test@pg-citus0/test
pgbench -nv -P1 -T1000 -c 2 postgres://test:test@pg-citus0/test

By default, changes you make to one Shard only occur on that cluster and are not synchronized to other Shards.

If you want to distribute writes across all Shards, you can use the API functions provided by Citus to mark tables as:

  • Distributed tables (automatic partitioning, requires specifying partition key)
  • Reference tables (full replication: does not require specifying partition key)

Starting from Citus 11.2, any Citus database node can play the role of coordinator, meaning any primary node can write:

psql -h pg-citus0 -d test -c "SELECT create_distributed_table('pgbench_accounts', 'aid'); SELECT truncate_local_data_after_distributing_table('public.pgbench_accounts');"
psql -h pg-citus0 -d test -c "SELECT create_reference_table('pgbench_branches')         ; SELECT truncate_local_data_after_distributing_table('public.pgbench_branches');"
psql -h pg-citus0 -d test -c "SELECT create_reference_table('pgbench_history')          ; SELECT truncate_local_data_after_distributing_table('public.pgbench_history');"
psql -h pg-citus0 -d test -c "SELECT create_reference_table('pgbench_tellers')          ; SELECT truncate_local_data_after_distributing_table('public.pgbench_tellers');"

After distributing the tables, you can also access them on other nodes:

psql -h pg-citus1 -d test -c '\dt+'

For example, a full table scan will show that the execution plan has become a distributed plan:

vagrant@meta-1:~$ psql -h pg-citus3 -d test -c 'explain select * from pgbench_accounts'
                                               QUERY PLAN
---------------------------------------------------------------------------------------------------------
 Custom Scan (Citus Adaptive)  (cost=0.00..0.00 rows=100000 width=352)
   Task Count: 32
   Tasks Shown: One of 32
   ->  Task
         Node: host=10.10.10.52 port=5432 dbname=test
         ->  Seq Scan on pgbench_accounts_102008 pgbench_accounts  (cost=0.00..81.66 rows=3066 width=97)
(6 rows)

You can initiate writes from several different primary nodes:

pgbench -nv -P1 -T1000 -c 2 postgres://test:test@pg-citus1/test
pgbench -nv -P1 -T1000 -c 2 postgres://test:test@pg-citus2/test
pgbench -nv -P1 -T1000 -c 2 postgres://test:test@pg-citus3/test
pgbench -nv -P1 -T1000 -c 2 postgres://test:test@pg-citus4/test

When a node fails, the native high availability support provided by Patroni will promote the standby node and automatically take over.

test=# select * from  pg_dist_node;
 nodeid | groupid |  nodename   | nodeport | noderack | hasmetadata | isactive | noderole | nodecluster | metadatasynced | shouldhaveshards
--------+---------+-------------+----------+----------+-------------+----------+----------+-------------+----------------+------------------
      1 |       0 | 10.10.10.51 |     5432 | default  | t           | t        | primary  | default     | t              | f
      2 |       2 | 10.10.10.54 |     5432 | default  | t           | t        | primary  | default     | t              | t
      5 |       1 | 10.10.10.52 |     5432 | default  | t           | t        | primary  | default     | t              | t
      3 |       4 | 10.10.10.58 |     5432 | default  | t           | t        | primary  | default     | t              | t
      4 |       3 | 10.10.10.56 |     5432 | default  | t           | t        | primary  | default     | t              | t

10.16.7 - Babelfish

Create Microsoft SQL Server compatible PostgreSQL clusters using WiltonDB and Babelfish! (Wire protocol level compatibility)

Babelfish is an MSSQL (Microsoft SQL Server) compatibility solution based on PostgreSQL, open-sourced by AWS.


Overview

Pigsty allows users to create Microsoft SQL Server compatible PostgreSQL clusters using Babelfish and WiltonDB!

  • Babelfish: An MSSQL (Microsoft SQL Server) compatibility extension plugin open-sourced by AWS
  • WiltonDB: A PostgreSQL kernel distribution focusing on integrating Babelfish

Babelfish is a PostgreSQL extension, but it only works on a slightly modified PostgreSQL kernel fork. WiltonDB provides compiled fork kernel binaries and extension binary packages on EL/Ubuntu systems.

Pigsty can replace the native PostgreSQL kernel with WiltonDB, providing an out-of-the-box MSSQL compatible cluster. Using and managing an MSSQL cluster is no different from a standard PostgreSQL 15 cluster. You can use all the features provided by Pigsty, such as high availability, backup, monitoring, etc.

WiltonDB comes with several extension plugins including Babelfish, but cannot use native PostgreSQL extension plugins.

After the MSSQL compatible cluster starts, in addition to listening on the PostgreSQL default port, it also listens on the MSSQL default port 1433, providing MSSQL services via the TDS Wire Protocol on this port. You can connect to the MSSQL service provided by Pigsty using any MSSQL client, such as SQL Server Management Studio, or using the sqlcmd command-line tool.


Installation

WiltonDB conflicts with the native PostgreSQL kernel. Only one kernel can be installed on a node. Use the following command to install the WiltonDB kernel online.

./node.yml -t node_install -e '{"node_repo_modules":"local,mssql","node_packages":["wiltondb"]}'

Please note that WiltonDB is only available on EL and Ubuntu systems. Debian support is not currently provided.

The Pigsty Professional Edition provides offline installation packages for WiltonDB, which can be installed from local software sources.


Configuration

When installing and deploying the MSSQL module, please pay special attention to the following:

  • WiltonDB is available on EL (7/8/9) and Ubuntu (20.04/22.04), but not available on Debian systems.
  • WiltonDB is currently compiled based on PostgreSQL 15, so you need to specify pg_version: 15.
  • On EL systems, the wiltondb binary is installed by default in the /usr/bin/ directory, while on Ubuntu systems it is installed in the /usr/lib/postgresql/15/bin/ directory, which is different from the official PostgreSQL binary placement.
  • In WiltonDB compatibility mode, the HBA password authentication rule needs to use md5 instead of scram-sha-256. Therefore, you need to override Pigsty’s default HBA rule set and insert the md5 authentication rule required by SQL Server before the dbrole_readonly wildcard authentication rule.
  • WiltonDB can only be enabled for one primary database, and you should designate a user as the Babelfish superuser, allowing Babelfish to create databases and users. The default is mssql and dbuser_mssql. If you change this, please also modify the user in files/mssql.sql.
  • The WiltonDB TDS wire protocol compatibility plugin babelfishpg_tds needs to be enabled in shared_preload_libraries.
  • After enabling the WiltonDB extension, it listens on the MSSQL default port 1433. You can override Pigsty’s default service definitions to point the primary and replica services to port 1433 instead of 5432 / 6432.

The following parameters need to be configured for the MSSQL database cluster:

#----------------------------------#
# PGSQL & MSSQL (Babelfish & Wilton)
#----------------------------------#
# PG Installation
node_repo_modules: local,node,mssql # add mssql and os upstream repos
pg_mode: mssql                      # Microsoft SQL Server Compatible Mode
pg_libs: 'babelfishpg_tds, pg_stat_statements, auto_explain' # add timescaledb to shared_preload_libraries
pg_version: 15                      # The current WiltonDB major version is 15
pg_packages:
  - wiltondb                        # install forked version of postgresql with babelfishpg support
  - patroni pgbouncer pgbackrest pg_exporter pgbadger vip-manager
pg_extensions: []                   # do not install any vanilla postgresql extensions

# PG Provision
pg_default_hba_rules:               # overwrite default HBA rules for babelfish cluster
- {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  }
- {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' }
- {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost'}
- {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' }
- {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' }
- {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' }
- {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password'}
- {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   }
- {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    }
- {user: dbuser_mssql ,db: mssql       ,addr: intra     ,auth: md5   ,title: 'allow mssql dbsu intranet access'     } # <--- use md5 auth method for mssql user
- {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket'}
- {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     }
- {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet'}
pg_default_services:                # route primary & replica service to mssql port 1433
- { name: primary ,port: 5433 ,dest: 1433  ,check: /primary   ,selector: "[]" }
- { name: replica ,port: 5434 ,dest: 1433  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
- { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
- { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}

You can define MSSQL business databases and business users:

#----------------------------------#
# pgsql (singleton on current node)
#----------------------------------#
# this is an example single-node postgres cluster with postgis & timescaledb installed, with one biz database & two biz users
pg-meta:
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary } # <---- primary instance with read-write capability
  vars:
    pg_cluster: pg-test
    pg_users:                           # create MSSQL superuser
      - {name: dbuser_mssql ,password: DBUser.MSSQL ,superuser: true, pgbouncer: true ,roles: [dbrole_admin], comment: superuser & owner for babelfish  }
    pg_primary_db: mssql                # use `mssql` as the primary sql server database
    pg_databases:
      - name: mssql
        baseline: mssql.sql             # init babelfish database & user
        extensions:
          - { name: uuid-ossp          }
          - { name: babelfishpg_common }
          - { name: babelfishpg_tsql   }
          - { name: babelfishpg_tds    }
          - { name: babelfishpg_money  }
          - { name: pg_hint_plan       }
          - { name: system_stats       }
          - { name: tds_fdw            }
        owner: dbuser_mssql
        parameters: { 'babelfishpg_tsql.migration_mode' : 'multi-db' }
        comment: babelfish cluster, a MSSQL compatible pg cluster

Access

You can use any SQL Server compatible client tool to access this database cluster.

Microsoft provides sqlcmd as the official command-line tool.

In addition, they also provide a Go version command-line tool go-sqlcmd.

Install go-sqlcmd:

curl -LO https://github.com/microsoft/go-sqlcmd/releases/download/v1.4.0/sqlcmd-v1.4.0-linux-amd64.tar.bz2
tar xjvf sqlcmd-v1.4.0-linux-amd64.tar.bz2
sudo mv sqlcmd* /usr/bin/

Quick start with go-sqlcmd:

$ sqlcmd -S 10.10.10.10,1433 -U dbuser_mssql -P DBUser.MSSQL
1> select @@version
2> go
version
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Babelfish for PostgreSQL with SQL Server Compatibility - 12.0.2000.8
Oct 22 2023 17:48:32
Copyright (c) Amazon Web Services
PostgreSQL 15.4 (EL 1:15.4.wiltondb3.3_2-2.el8) on x86_64-redhat-linux-gnu (Babelfish 3.3.0)

(1 row affected)

Using the service mechanism provided by Pigsty, you can use ports 5433 / 5434 to always connect to port 1433 on the primary/replica.

# Access port 5433 on any cluster member, pointing to port 1433 MSSQL port on the primary
sqlcmd -S 10.10.10.11,5433 -U dbuser_mssql -P DBUser.MSSQL

# Access port 5434 on any cluster member, pointing to port 1433 MSSQL port on any readable replica
sqlcmd -S 10.10.10.11,5434 -U dbuser_mssql -P DBUser.MSSQL

Extensions

Most of the PGSQL module’s extension plugins (non-pure SQL class) cannot be directly used on the WiltonDB kernel of the MSSQL module and need to be recompiled.

Currently, WiltonDB comes with the following extension plugins. In addition to PostgreSQL Contrib extensions and the four BabelfishPG core extensions, it also provides three third-party extensions: pg_hint_plan, tds_fdw, and system_stats.

Extension NameVersionDescription
dblink1.2connect to other PostgreSQL databases from within a database
adminpack2.1administrative functions for PostgreSQL
dict_int1.0text search dictionary template for integers
intagg1.1integer aggregator and enumerator (obsolete)
dict_xsyn1.0text search dictionary template for extended synonym processing
amcheck1.3functions for verifying relation integrity
autoinc1.0functions for autoincrementing fields
bloom1.0bloom access method - signature file based index
fuzzystrmatch1.1determine similarities and distance between strings
intarray1.5functions, operators, and index support for 1-D arrays of integers
btree_gin1.3support for indexing common datatypes in GIN
btree_gist1.7support for indexing common datatypes in GiST
hstore1.8data type for storing sets of (key, value) pairs
hstore_plperl1.0transform between hstore and plperl
isn1.2data types for international product numbering standards
hstore_plperlu1.0transform between hstore and plperlu
jsonb_plperl1.0transform between jsonb and plperl
citext1.6data type for case-insensitive character strings
jsonb_plperlu1.0transform between jsonb and plperlu
jsonb_plpython3u1.0transform between jsonb and plpython3u
cube1.5data type for multidimensional cubes
hstore_plpython3u1.0transform between hstore and plpython3u
earthdistance1.1calculate great-circle distances on the surface of the Earth
lo1.1Large Object maintenance
file_fdw1.0foreign-data wrapper for flat file access
insert_username1.0functions for tracking who changed a table
ltree1.2data type for hierarchical tree-like structures
ltree_plpython3u1.0transform between ltree and plpython3u
pg_walinspect1.0functions to inspect contents of PostgreSQL Write-Ahead Log
moddatetime1.0functions for tracking last modification time
old_snapshot1.0utilities in support of old_snapshot_threshold
pgcrypto1.3cryptographic functions
pgrowlocks1.2show row-level locking information
pageinspect1.11inspect the contents of database pages at a low level
pg_surgery1.0extension to perform surgery on a damaged relation
seg1.4data type for representing line segments or floating-point intervals
pgstattuple1.5show tuple-level statistics
pg_buffercache1.3examine the shared buffer cache
pg_freespacemap1.2examine the free space map (FSM)
postgres_fdw1.1foreign-data wrapper for remote PostgreSQL servers
pg_prewarm1.2prewarm relation data
tcn1.0Triggered change notifications
pg_trgm1.6text similarity measurement and index searching based on trigrams
xml21.1XPath querying and XSLT
refint1.0functions for implementing referential integrity (obsolete)
pg_visibility1.2examine the visibility map (VM) and page-level visibility info
pg_stat_statements1.10track planning and execution statistics of all SQL statements executed
sslinfo1.2information about SSL certificates
tablefunc1.0functions that manipulate whole tables, including crosstab
tsm_system_rows1.0TABLESAMPLE method which accepts number of rows as a limit
tsm_system_time1.0TABLESAMPLE method which accepts time in milliseconds as a limit
unaccent1.1text search dictionary that removes accents
uuid-ossp1.1generate universally unique identifiers (UUIDs)
plpgsql1.0PL/pgSQL procedural language
babelfishpg_money1.1.0babelfishpg_money
system_stats2.0EnterpriseDB system statistics for PostgreSQL
tds_fdw2.0.3Foreign data wrapper for querying a TDS database (Sybase or Microsoft SQL Server)
babelfishpg_common3.3.3Transact SQL Datatype Support
babelfishpg_tds1.0.0TDS protocol extension
pg_hint_plan1.5.1
babelfishpg_tsql3.3.1Transact SQL compatibility
  • The Pigsty Professional Edition provides offline installation capabilities for MSSQL compatible modules
  • Pigsty Professional Edition provides optional MSSQL compatible kernel extension porting and customization services, which can port extensions available in the PGSQL module to MSSQL clusters.

10.16.8 - IvorySQL

Use HighGo’s open-source IvorySQL kernel to achieve Oracle syntax/PLSQL compatibility based on PostgreSQL clusters.

IvorySQL is an open-source PostgreSQL kernel fork that aims to provide “Oracle compatibility” based on PG.


Overview

The IvorySQL kernel is supported in the Pigsty open-source version. Your server needs internet access to download relevant packages directly from IvorySQL’s official repository.

Please note that adding IvorySQL directly to Pigsty’s default software repository will affect the installation of the native PostgreSQL kernel. Pigsty Professional Edition provides offline installation solutions including the IvorySQL kernel.

The current latest version of IvorySQL is 5.0, corresponding to PostgreSQL version 18. Please note that IvorySQL is currently only available on EL8/EL9.

The last IvorySQL version supporting EL7 was 3.3, corresponding to PostgreSQL 16.3; the last version based on PostgreSQL 17 is IvorySQL 4.4


Installation

If your environment has internet access, you can add the IvorySQL repository directly to the node using the following method, then execute the PGSQL playbook for installation:

./node.yml -t node_repo -e '{"node_repo_modules":"local,node,pgsql,ivory"}'

Configuration

The following parameters need to be configured for IvorySQL database clusters:

#----------------------------------#
# Ivory SQL Configuration
#----------------------------------#
node_repo_modules: local,node,pgsql,ivory  # add ivorysql upstream repo
pg_mode: ivory                    # IvorySQL Oracle Compatible Mode
pg_packages: [ 'ivorysql patroni pgbouncer pgbackrest pg_exporter pgbadger vip-manager' ]
pg_libs: 'liboracle_parser, pg_stat_statements, auto_explain'
pg_extensions: [ ]                # do not install any vanilla postgresql extensions

When using Oracle compatibility mode, you need to dynamically load the liboracle_parser extension plugin.


Client Access

IvorySQL is equivalent to PostgreSQL 16, and any client tool compatible with the PostgreSQL wire protocol can access IvorySQL clusters.


Extension List

Most of the PGSQL module’s extensions (non-pure SQL types) cannot be used directly on the IvorySQL kernel. If you need to use them, please recompile and install from source for the new kernel.

Currently, the IvorySQL kernel comes with the following 101 extension plugins.

(The extension table remains unchanged as it’s already in English)

Please note that Pigsty does not assume any warranty responsibility for using the IvorySQL kernel. Any issues or requirements encountered when using this kernel should be addressed with the original vendor.

10.16.9 - PolarDB PG

Using Alibaba Cloud’s open-source PolarDB for PostgreSQL kernel to provide domestic innovation qualification support, with Oracle RAC-like user experience.

Overview

Pigsty allows you to create PostgreSQL clusters with “domestic innovation qualification” credentials using PolarDB!

PolarDB for PostgreSQL is essentially equivalent to PostgreSQL 15. Any client tool compatible with the PostgreSQL wire protocol can access PolarDB clusters.

Pigsty’s PGSQL repository provides PolarDB PG open-source installation packages for EL7 / EL8, but they are not downloaded to the local software repository during Pigsty installation.

If you need offline installation support for PolarDB PG, please consider our professional subscription service


Installation

If your environment has internet access, you can add the Pigsty PGSQL and dependency repositories to the node using the following method:

node_repo_modules: local,node,pgsql

Then in pg_packages, replace the native postgresql package with polardb.


Configuration

The following parameters need special configuration for PolarDB database clusters:

#----------------------------------#
# PGSQL & PolarDB
#----------------------------------#
pg_version: 15
pg_packages: [ 'polardb patroni pgbouncer pgbackrest pg_exporter pgbadger vip-manager' ]
pg_extensions: [ ]                # do not install any vanilla postgresql extensions
pg_mode: polar                    # PolarDB Compatible Mode
pg_default_roles:                 # default roles and users in postgres cluster
  - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
  - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
  - { name: postgres     ,superuser: true  ,comment: system superuser }
  - { name: replicator   ,superuser: true  ,replication: true ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator } # <- superuser is required for replication
  - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
  - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

Note particularly that PolarDB PG requires the replicator replication user to be a Superuser, unlike native PG.


Extension List

Most PGSQL module extension plugins (non-pure SQL types) cannot be used directly on the PolarDB kernel. If needed, please recompile and install from source for the new kernel.

Currently, the PolarDB kernel comes with the following 61 extension plugins. Apart from Contrib extensions, the additional extensions provided include:

  • polar_csn 1.0 : polar_csn
  • polar_monitor 1.2 : examine the polardb information
  • polar_monitor_preload 1.1 : examine the polardb information
  • polar_parameter_check 1.0 : kernel extension for parameter validation
  • polar_px 1.0 : Parallel Execution extension
  • polar_stat_env 1.0 : env stat functions for PolarDB
  • polar_stat_sql 1.3 : Kernel statistics gathering, and sql plan nodes information gathering
  • polar_tde_utils 1.0 : Internal extension for TDE
  • polar_vfs 1.0 : polar_vfs
  • polar_worker 1.0 : polar_worker
  • timetravel 1.0 : functions for implementing time travel
  • vector 0.5.1 : vector data type and ivfflat and hnsw access methods
  • smlar 1.0 : compute similary of any one-dimensional arrays

Complete list of available PolarDB plugins:

nameversioncomment
hstore_plpython2u1.0transform between hstore and plpython2u
dict_int1.0text search dictionary template for integers
adminpack2.0administrative functions for PostgreSQL
hstore_plpython3u1.0transform between hstore and plpython3u
amcheck1.1functions for verifying relation integrity
hstore_plpythonu1.0transform between hstore and plpythonu
autoinc1.0functions for autoincrementing fields
insert_username1.0functions for tracking who changed a table
bloom1.0bloom access method - signature file based index
file_fdw1.0foreign-data wrapper for flat file access
dblink1.2connect to other PostgreSQL databases from within a database
btree_gin1.3support for indexing common datatypes in GIN
fuzzystrmatch1.1determine similarities and distance between strings
lo1.1Large Object maintenance
intagg1.1integer aggregator and enumerator (obsolete)
btree_gist1.5support for indexing common datatypes in GiST
hstore1.5data type for storing sets of (key, value) pairs
intarray1.2functions, operators, and index support for 1-D arrays of integers
citext1.5data type for case-insensitive character strings
cube1.4data type for multidimensional cubes
hstore_plperl1.0transform between hstore and plperl
isn1.2data types for international product numbering standards
jsonb_plperl1.0transform between jsonb and plperl
dict_xsyn1.0text search dictionary template for extended synonym processing
hstore_plperlu1.0transform between hstore and plperlu
earthdistance1.1calculate great-circle distances on the surface of the Earth
pg_prewarm1.2prewarm relation data
jsonb_plperlu1.0transform between jsonb and plperlu
pg_stat_statements1.6track execution statistics of all SQL statements executed
jsonb_plpython2u1.0transform between jsonb and plpython2u
jsonb_plpython3u1.0transform between jsonb and plpython3u
jsonb_plpythonu1.0transform between jsonb and plpythonu
pg_trgm1.4text similarity measurement and index searching based on trigrams
pgstattuple1.5show tuple-level statistics
ltree1.1data type for hierarchical tree-like structures
ltree_plpython2u1.0transform between ltree and plpython2u
pg_visibility1.2examine the visibility map (VM) and page-level visibility info
ltree_plpython3u1.0transform between ltree and plpython3u
ltree_plpythonu1.0transform between ltree and plpythonu
seg1.3data type for representing line segments or floating-point intervals
moddatetime1.0functions for tracking last modification time
pgcrypto1.3cryptographic functions
pgrowlocks1.2show row-level locking information
pageinspect1.7inspect the contents of database pages at a low level
pg_buffercache1.3examine the shared buffer cache
pg_freespacemap1.2examine the free space map (FSM)
tcn1.0Triggered change notifications
plperl1.0PL/Perl procedural language
uuid-ossp1.1generate universally unique identifiers (UUIDs)
plperlu1.0PL/PerlU untrusted procedural language
refint1.0functions for implementing referential integrity (obsolete)
xml21.1XPath querying and XSLT
plpgsql1.0PL/pgSQL procedural language
plpython3u1.0PL/Python3U untrusted procedural language
pltcl1.0PL/Tcl procedural language
pltclu1.0PL/TclU untrusted procedural language
polar_csn1.0polar_csn
sslinfo1.2information about SSL certificates
polar_monitor1.2examine the polardb information
polar_monitor_preload1.1examine the polardb information
polar_parameter_check1.0kernel extension for parameter validation
polar_px1.0Parallel Execution extension
tablefunc1.0functions that manipulate whole tables, including crosstab
polar_stat_env1.0env stat functions for PolarDB
smlar1.0compute similary of any one-dimensional arrays
timetravel1.0functions for implementing time travel
tsm_system_rows1.0TABLESAMPLE method which accepts number of rows as a limit
polar_stat_sql1.3Kernel statistics gathering, and sql plan nodes information gathering
tsm_system_time1.0TABLESAMPLE method which accepts time in milliseconds as a limit
polar_tde_utils1.0Internal extension for TDE
polar_vfs1.0polar_vfs
polar_worker1.0polar_worker
unaccent1.1text search dictionary that removes accents
postgres_fdw1.0foreign-data wrapper for remote PostgreSQL servers
  • Pigsty Professional Edition provides PolarDB offline installation support, extension plugin compilation support, and monitoring and management support specifically adapted for PolarDB clusters.
  • Pigsty collaborates with the Alibaba Cloud kernel team and can provide paid kernel backup support services.

10.16.10 - PolarDB Oracle

Using Alibaba Cloud’s commercial PolarDB for Oracle kernel (closed source, PG14, only available in special enterprise edition customization)

Pigsty allows you to create PolarDB for Oracle clusters with “domestic innovation qualification” credentials using PolarDB!

According to the Security and Reliability Evaluation Results Announcement (No. 1, 2023), Appendix 3, Centralized Database. PolarDB v2.0 is an autonomous, controllable, secure, and reliable domestic innovation database.

PolarDB for Oracle is an Oracle-compatible version developed based on PolarDB for PostgreSQL. Both share the same kernel, distinguished by the --compatibility-mode parameter.

We collaborate with the Alibaba Cloud kernel team to provide a complete database solution based on PolarDB v2.0 kernel and Pigsty v3.0 RDS. Please contact sales for inquiries, or purchase on Alibaba Cloud Marketplace.

The PolarDB for Oracle kernel is currently only available on EL systems.


Extensions

Currently, the PolarDB 2.0 (Oracle compatible) kernel comes with the following 188 extension plugins:

namedefault_versioncomment
cube1.5data type for multidimensional cubes
ip4r2.4NULL
adminpack2.1administrative functions for PostgreSQL
dict_xsyn1.0text search dictionary template for extended synonym processing
amcheck1.4functions for verifying relation integrity
autoinc1.0functions for autoincrementing fields
hstore1.8data type for storing sets of (key, value) pairs
bloom1.0bloom access method - signature file based index
earthdistance1.1calculate great-circle distances on the surface of the Earth
hstore_plperl1.0transform between hstore and plperl
bool_plperl1.0transform between bool and plperl
file_fdw1.0foreign-data wrapper for flat file access
bool_plperlu1.0transform between bool and plperlu
fuzzystrmatch1.1determine similarities and distance between strings
hstore_plperlu1.0transform between hstore and plperlu
btree_gin1.3support for indexing common datatypes in GIN
hstore_plpython2u1.0transform between hstore and plpython2u
btree_gist1.6support for indexing common datatypes in GiST
hll2.17type for storing hyperloglog data
hstore_plpython3u1.0transform between hstore and plpython3u
citext1.6data type for case-insensitive character strings
hstore_plpythonu1.0transform between hstore and plpythonu
hypopg1.3.1Hypothetical indexes for PostgreSQL
insert_username1.0functions for tracking who changed a table
dblink1.2connect to other PostgreSQL databases from within a database
decoderbufs0.1.0Logical decoding plugin that delivers WAL stream changes using a Protocol Buffer format
intagg1.1integer aggregator and enumerator (obsolete)
dict_int1.0text search dictionary template for integers
intarray1.5functions, operators, and index support for 1-D arrays of integers
isn1.2data types for international product numbering standards
jsonb_plperl1.0transform between jsonb and plperl
jsonb_plperlu1.0transform between jsonb and plperlu
jsonb_plpython2u1.0transform between jsonb and plpython2u
jsonb_plpython3u1.0transform between jsonb and plpython3u
jsonb_plpythonu1.0transform between jsonb and plpythonu
lo1.1Large Object maintenance
log_fdw1.0foreign-data wrapper for csvlog
ltree1.2data type for hierarchical tree-like structures
ltree_plpython2u1.0transform between ltree and plpython2u
ltree_plpython3u1.0transform between ltree and plpython3u
ltree_plpythonu1.0transform between ltree and plpythonu
moddatetime1.0functions for tracking last modification time
old_snapshot1.0utilities in support of old_snapshot_threshold
oracle_fdw1.2foreign data wrapper for Oracle access
oss_fdw1.1foreign-data wrapper for OSS access
pageinspect2.1inspect the contents of database pages at a low level
pase0.0.1ant ai similarity search
pg_bigm1.2text similarity measurement and index searching based on bigrams
pg_freespacemap1.2examine the free space map (FSM)
pg_hint_plan1.4controls execution plan with hinting phrases in comment of special form
pg_buffercache1.5examine the shared buffer cache
pg_prewarm1.2prewarm relation data
pg_repack1.4.8-1Reorganize tables in PostgreSQL databases with minimal locks
pg_sphere1.0spherical objects with useful functions, operators and index support
pg_cron1.5Job scheduler for PostgreSQL
pg_jieba1.1.0a parser for full-text search of Chinese
pg_stat_kcache2.2.1Kernel statistics gathering
pg_stat_statements1.9track planning and execution statistics of all SQL statements executed
pg_surgery1.0extension to perform surgery on a damaged relation
pg_trgm1.6text similarity measurement and index searching based on trigrams
pg_visibility1.2examine the visibility map (VM) and page-level visibility info
pg_wait_sampling1.1sampling based statistics of wait events
pgaudit1.6.2provides auditing functionality
pgcrypto1.3cryptographic functions
pgrowlocks1.2show row-level locking information
pgstattuple1.5show tuple-level statistics
pgtap1.2.0Unit testing for PostgreSQL
pldbgapi1.1server-side support for debugging PL/pgSQL functions
plperl1.0PL/Perl procedural language
plperlu1.0PL/PerlU untrusted procedural language
plpgsql1.0PL/pgSQL procedural language
plpython2u1.0PL/Python2U untrusted procedural language
plpythonu1.0PL/PythonU untrusted procedural language
plsql1.0Oracle compatible PL/SQL procedural language
pltcl1.0PL/Tcl procedural language
pltclu1.0PL/TclU untrusted procedural language
polar_bfile1.0The BFILE data type enables access to binary file LOBs that are stored in file systems outside Database
polar_bpe1.0polar_bpe
polar_builtin_cast1.1Internal extension for builtin casts
polar_builtin_funcs2.0implement polar builtin functions
polar_builtin_type1.5polar_builtin_type for PolarDB
polar_builtin_view1.5polar_builtin_view
polar_catalog1.2polardb pg extend catalog
polar_channel1.0polar_channel
polar_constraint1.0polar_constraint
polar_csn1.0polar_csn
polar_dba_views1.0polar_dba_views
polar_dbms_alert1.2implement polar_dbms_alert - supports asynchronous notification of database events.
polar_dbms_application_info1.0implement polar_dbms_application_info - record names of executing modules or transactions in the database.
polar_dbms_pipe1.1implements polar_dbms_pipe - package lets two or more sessions in the same instance communicate.
polar_dbms_aq1.2implement dbms_aq - provides an interface to Advanced Queuing.
polar_dbms_lob1.3implement dbms_lob - provides subprograms to operate on BLOBs, CLOBs, and NCLOBs.
polar_dbms_output1.2implement polar_dbms_output - enables you to send messages from stored procedures.
polar_dbms_lock1.0implement polar_dbms_lock - provides an interface to Oracle Lock Management services.
polar_dbms_aqadm1.3polar_dbms_aqadm - procedures to manage Advanced Queuing configuration and administration information.
polar_dbms_assert1.0implement polar_dbms_assert - provide an interface to validate properties of the input value.
polar_dbms_metadata1.0implement polar_dbms_metadata - provides a way for you to retrieve metadata from the database dictionary.
polar_dbms_random1.0implement polar_dbms_random - a built-in random number generator, not intended for cryptography
polar_dbms_crypto1.1implement dbms_crypto - provides an interface to encrypt and decrypt stored data.
polar_dbms_redact1.0implement polar_dbms_redact - provides an interface to mask data from queries by an application.
polar_dbms_debug1.1server-side support for debugging PL/SQL functions
polar_dbms_job1.0polar_dbms_job
polar_dbms_mview1.1implement polar_dbms_mview - enables to refresh materialized views.
polar_dbms_job_preload1.0polar_dbms_job_preload
polar_dbms_obfuscation_toolkit1.1implement polar_dbms_obfuscation_toolkit - enables an application to get data md5.
polar_dbms_rls1.1implement polar_dbms_rls - a fine-grained access control administrative built-in package
polar_multi_toast_utils1.0polar_multi_toast_utils
polar_dbms_session1.2implement polar_dbms_session - support to set preferences and security levels.
polar_odciconst1.0implement ODCIConst - Provide some built-in constants in Oracle.
polar_dbms_sql1.2implement polar_dbms_sql - provides an interface to execute dynamic SQL.
polar_osfs_toolkit1.0osfs library tools and functions extension
polar_dbms_stats14.0stabilize plans by fixing statistics
polar_monitor1.5monitor functions for PolarDB
polar_osfs_utils1.0osfs library utils extension
polar_dbms_utility1.3implement polar_dbms_utility - provides various utility subprograms.
polar_parameter_check1.0kernel extension for parameter validation
polar_dbms_xmldom1.0implement dbms_xmldom and dbms_xmlparser - support standard DOM interface and xml parser object
polar_parameter_manager1.1Extension to select parameters for manger.
polar_faults1.0.0simulate some database faults for end user or testing system.
polar_monitor_preload1.1examine the polardb information
polar_proxy_utils1.0Extension to provide operations about proxy.
polar_feature_utils1.2PolarDB feature utilization
polar_global_awr1.0PolarDB Global AWR Report
polar_publication1.0support polardb pg logical replication
polar_global_cache1.0polar_global_cache
polar_px1.0Parallel Execution extension
polar_serverless1.0polar serverless extension
polar_resource_manager1.0a background process that forcibly frees user session process memory
polar_sys_context1.1implement polar_sys_context - returns the value of parameter associated with the context namespace at the current instant.
polar_gpc1.3polar_gpc
polar_tde_utils1.0Internal extension for TDE
polar_gtt1.1polar_gtt
polar_utl_encode1.2implement polar_utl_encode - provides functions that encode RAW data into a standard encoded format
polar_htap1.1extension for PolarDB HTAP
polar_htap_db1.0extension for PolarDB HTAP database level operation
polar_io_stat1.0polar io stat in multi dimension
polar_utl_file1.0implement utl_file - support PL/SQL programs can read and write operating system text files
polar_ivm1.0polar_ivm
polar_sql_mapping1.2Record error sqls and mapping them to correct one
polar_stat_sql1.0Kernel statistics gathering, and sql plan nodes information gathering
tds_fdw2.0.2Foreign data wrapper for querying a TDS database (Sybase or Microsoft SQL Server)
xml21.1XPath querying and XSLT
polar_upgrade_catalogs1.1Upgrade catalogs for old version instance
polar_utl_i18n1.1polar_utl_i18n
polar_utl_raw1.0implement utl_raw - provides SQL functions for manipulating RAW datatypes.
timescaledb2.9.2Enables scalable inserts and complex queries for time-series data
polar_vfs1.0polar virtual file system for different storage
polar_worker1.0polar_worker
postgres_fdw1.1foreign-data wrapper for remote PostgreSQL servers
refint1.0functions for implementing referential integrity (obsolete)
roaringbitmap0.5support for Roaring Bitmaps
tsm_system_time1.0TABLESAMPLE method which accepts time in milliseconds as a limit
vector0.5.0vector data type and ivfflat and hnsw access methods
rum1.3RUM index access method
unaccent1.1text search dictionary that removes accents
seg1.4data type for representing line segments or floating-point intervals
sequential_uuids1.0.2generator of sequential UUIDs
uuid-ossp1.1generate universally unique identifiers (UUIDs)
smlar1.0compute similary of any one-dimensional arrays
varbitx1.1varbit functions pack
sslinfo1.2information about SSL certificates
tablefunc1.0functions that manipulate whole tables, including crosstab
tcn1.0Triggered change notifications
zhparser1.0a parser for full-text search of Chinese
address_standardizer3.3.2Ganos PostGIS address standardizer
address_standardizer_data_us3.3.2Ganos PostGIS address standardizer data us
ganos_fdw6.0Ganos Spatial FDW extension for POLARDB
ganos_geometry6.0Ganos geometry lite extension for POLARDB
ganos_geometry_pyramid6.0Ganos Geometry Pyramid extension for POLARDB
ganos_geometry_sfcgal6.0Ganos geometry lite sfcgal extension for POLARDB
ganos_geomgrid6.0Ganos geometry grid extension for POLARDB
ganos_importer6.0Ganos Spatial importer extension for POLARDB
ganos_networking6.0Ganos networking
ganos_pointcloud6.0Ganos pointcloud extension For POLARDB
ganos_pointcloud_geometry6.0Ganos_pointcloud LIDAR data and ganos_geometry data for POLARDB
ganos_raster6.0Ganos raster extension for POLARDB
ganos_scene6.0Ganos scene extension for POLARDB
ganos_sfmesh6.0Ganos surface mesh extension for POLARDB
ganos_spatialref6.0Ganos spatial reference extension for POLARDB
ganos_trajectory6.0Ganos trajectory extension for POLARDB
ganos_vomesh6.0Ganos volumn mesh extension for POLARDB
postgis_tiger_geocoder3.3.2Ganos PostGIS tiger geocoder
postgis_topology3.3.2Ganos PostGIS topology

10.16.11 - PostgresML

How to deploy PostgresML with Pigsty: ML, training, inference, Embedding, RAG inside DB.

PostgresML is a PostgreSQL extension that supports the latest large language models (LLM), vector operations, classical machine learning, and traditional Postgres application workloads.

PostgresML (pgml) is a PostgreSQL extension written in Rust. You can run standalone Docker images, but this documentation is not a docker-compose template introduction, for reference only.

PostgresML officially supports Ubuntu 22.04, but we also maintain RPM versions for EL 8/9, if you don’t need CUDA and NVIDIA-related features.

You need internet access on database nodes to download Python dependencies from PyPI and models from HuggingFace.


Configuration

PostgresML is an extension written in Rust, officially supporting Ubuntu. Pigsty maintains RPM versions of PostgresML on EL8 and EL9.

Creating a New Cluster

PostgresML 2.7.9 is available for PostgreSQL 15, supporting Ubuntu 22.04 (official), Debian 12, and EL 8/9 (maintained by Pigsty). To enable pgml, you first need to install the extension:

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 }
      - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
    pg_databases:
      - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: postgis, schema: public}, {name: timescaledb}]}
    pg_hba_rules:
      - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
    pg_libs: 'pgml, pg_stat_statements, auto_explain'
    pg_extensions: [ 'pgml_15 pgvector_15 wal2json_15 repack_15' ]  # ubuntu
    #pg_extensions: [ 'postgresql-pgml-15 postgresql-15-pgvector postgresql-15-wal2json postgresql-15-repack' ]  # ubuntu

On EL 8/9, the extension name is pgml_15, corresponding to the Ubuntu/Debian name postgresql-pgml-15. You also need to add pgml to pg_libs.

Enabling on an Existing Cluster

To enable pgml on an existing cluster, you can install it using Ansible’s package module:

ansible pg-meta -m package -b -a 'name=pgml_15'
# ansible el8,el9 -m package -b -a 'name=pgml_15'           # EL 8/9
# ansible u22 -m package -b -a 'name=postgresql-pgml-15'    # Ubuntu 22.04 jammy

Python Dependencies

You also need to install PostgresML’s Python dependencies on cluster nodes. Official tutorial: Installation Guide

Install Python and PIP

Ensure python3, pip, and venv are installed:

# Ubuntu 22.04 (python3.10), need to install pip and venv using apt
sudo apt install -y python3 python3-pip python3-venv

For EL 8 / EL9 and compatible distributions, you can use python3.11:

# EL 8/9, can upgrade the default pip and virtualenv
sudo yum install -y python3.11 python3.11-pip       # install latest python3.11
python3.11 -m pip install --upgrade pip virtualenv  # use python3.11 on EL8 / EL9
Using PyPI Mirrors

For users in mainland China, we recommend using Tsinghua University’s PyPI mirror.

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple    # set global mirror (recommended)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package        # use for single installation

Install Dependencies

Create a Python virtual environment and use pip to install dependencies from requirements.txt and requirements-xformers.txt.

If you’re using EL 8/9, replace python3 with python3.11 in the following commands.

su - postgres;                          # create virtual environment as database superuser
mkdir -p /data/pgml; cd /data/pgml;     # create virtual environment directory
python3    -m venv /data/pgml           # create virtual environment directory (Ubuntu 22.04)
source /data/pgml/bin/activate          # activate virtual environment

# write Python dependencies and install with pip
cat > /data/pgml/requirments.txt <<EOF
accelerate==0.22.0
auto-gptq==0.4.2
bitsandbytes==0.41.1
catboost==1.2
ctransformers==0.2.27
datasets==2.14.5
deepspeed==0.10.3
huggingface-hub==0.17.1
InstructorEmbedding==1.0.1
lightgbm==4.1.0
orjson==3.9.7
pandas==2.1.0
rich==13.5.2
rouge==1.0.1
sacrebleu==2.3.1
sacremoses==0.0.53
scikit-learn==1.3.0
sentencepiece==0.1.99
sentence-transformers==2.2.2
tokenizers==0.13.3
torch==2.0.1
torchaudio==2.0.2
torchvision==0.15.2
tqdm==4.66.1
transformers==4.33.1
xgboost==2.0.0
langchain==0.0.287
einops==0.6.1
pynvml==11.5.0
EOF

# install dependencies using pip in the virtual environment
python3 -m pip install -r /data/pgml/requirments.txt
python3 -m pip install xformers==0.0.21 --no-dependencies

# additionally, 3 Python packages need to be installed globally using sudo!
sudo python3 -m pip install xgboost lightgbm scikit-learn

Enable PostgresML

After installing the pgml extension and Python dependencies on all cluster nodes, you can enable pgml on the PostgreSQL cluster.

Use the patronictl command to configure the cluster, add pgml to shared_preload_libraries, and specify your virtual environment directory in pgml.venv:

shared_preload_libraries: pgml, timescaledb, pg_stat_statements, auto_explain
pgml.venv: '/data/pgml'

Then restart the database cluster and create the extension using SQL commands:

CREATE EXTENSION vector;        -- also recommend installing pgvector!
CREATE EXTENSION pgml;          -- create PostgresML in the current database
SELECT pgml.version();          -- print PostgresML version information

If everything is normal, you should see output similar to the following:

# create extension pgml;
INFO:  Python version: 3.11.2 (main, Oct  5 2023, 16:06:03) [GCC 8.5.0 20210514 (Red Hat 8.5.0-18)]
INFO:  Scikit-learn 1.3.0, XGBoost 2.0.0, LightGBM 4.1.0, NumPy 1.26.1
CREATE EXTENSION

# SELECT pgml.version(); -- print PostgresML version information
 version
---------
 2.7.8

Done! For more details, please refer to the official PostgresML documentation: https://postgresml.org/docs/guides/use-cases/

10.16.12 - Greenplum

Deploy/Monitor Greenplum clusters with Pigsty, build Massively Parallel Processing (MPP) PostgreSQL data warehouse clusters!

Pigsty supports deploying Greenplum clusters and its derivative distribution YMatrixDB, and provides the capability to integrate existing Greenplum deployments into Pigsty monitoring.


Overview

Greenplum / YMatrix cluster deployment capabilities are only available in the professional/enterprise editions and are not currently open source.


Installation

Pigsty provides installation packages for Greenplum 6 (@el7) and Greenplum 7 (@el8). Open source users can install and configure them manually.

# EL 7 Only (Greenplum6)
./node.yml -t node_install  -e '{"node_repo_modules":"pgsql","node_packages":["open-source-greenplum-db-6"]}'

# EL 8 Only (Greenplum7)
./node.yml -t node_install  -e '{"node_repo_modules":"pgsql","node_packages":["open-source-greenplum-db-7"]}'

Configuration

To define a Greenplum cluster, you need to use pg_mode = gpsql and additional identity parameters pg_shard and gp_role.

#================================================================#
#                        GPSQL Clusters                          #
#================================================================#

#----------------------------------#
# cluster: mx-mdw (gp master)
#----------------------------------#
mx-mdw:
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary , nodename: mx-mdw-1 }
  vars:
    gp_role: master          # this cluster is used as greenplum master
    pg_shard: mx             # pgsql sharding name & gpsql deployment name
    pg_cluster: mx-mdw       # this master cluster name is mx-mdw
    pg_databases:
      - { name: matrixmgr , extensions: [ { name: matrixdbts } ] }
      - { name: meta }
    pg_users:
      - { name: meta , password: DBUser.Meta , pgbouncer: true }
      - { name: dbuser_monitor , password: DBUser.Monitor , roles: [ dbrole_readonly ], superuser: true }

    pgbouncer_enabled: true                # enable pgbouncer for greenplum master
    pgbouncer_exporter_enabled: false      # enable pgbouncer_exporter for greenplum master
    pg_exporter_params: 'host=127.0.0.1&sslmode=disable'  # use 127.0.0.1 as local monitor host

#----------------------------------#
# cluster: mx-sdw (gp master)
#----------------------------------#
mx-sdw:
  hosts:
    10.10.10.11:
      nodename: mx-sdw-1        # greenplum segment node
      pg_instances:             # greenplum segment instances
        6000: { pg_cluster: mx-seg1, pg_seq: 1, pg_role: primary , pg_exporter_port: 9633 }
        6001: { pg_cluster: mx-seg2, pg_seq: 2, pg_role: replica , pg_exporter_port: 9634 }
    10.10.10.12:
      nodename: mx-sdw-2
      pg_instances:
        6000: { pg_cluster: mx-seg2, pg_seq: 1, pg_role: primary , pg_exporter_port: 9633  }
        6001: { pg_cluster: mx-seg3, pg_seq: 2, pg_role: replica , pg_exporter_port: 9634  }
    10.10.10.13:
      nodename: mx-sdw-3
      pg_instances:
        6000: { pg_cluster: mx-seg3, pg_seq: 1, pg_role: primary , pg_exporter_port: 9633 }
        6001: { pg_cluster: mx-seg1, pg_seq: 2, pg_role: replica , pg_exporter_port: 9634 }
  vars:
    gp_role: segment               # these are nodes for gp segments
    pg_shard: mx                   # pgsql sharding name & gpsql deployment name
    pg_cluster: mx-sdw             # these segment clusters name is mx-sdw
    pg_preflight_skip: true        # skip preflight check (since pg_seq & pg_role & pg_cluster not exists)
    pg_exporter_config: pg_exporter_basic.yml                             # use basic config to avoid segment server crash
    pg_exporter_params: 'options=-c%20gp_role%3Dutility&sslmode=disable'  # use gp_role = utility to connect to segments

Additionally, PG Exporter requires extra connection parameters to connect to Greenplum Segment instances for metric collection.

10.16.13 - Cloudberry

Deploy/Monitor Cloudberry clusters with Pigsty, an MPP data warehouse cluster forked from Greenplum!

Installation

Pigsty provides installation packages for Greenplum 6 (@el7) and Greenplum 7 (@el8). Open source users can install and configure them manually.

# EL 7 Only (Greenplum6)
./node.yml -t node_install  -e '{"node_repo_modules":"pgsql","node_packages":["cloudberrydb"]}'

# EL 8 Only (Greenplum7)
./node.yml -t node_install  -e '{"node_repo_modules":"pgsql","node_packages":["cloudberrydb"]}'

10.16.14 - Neon

Use Neon’s open-source Serverless PostgreSQL kernel to build flexible, scale-to-zero, forkable PG services.

Neon adopts a storage and compute separation architecture, providing seamless autoscaling, scale to zero, and unique database branching capabilities.

Neon official website: https://neon.tech/

The compiled binaries of Neon are excessively large and are currently not available to open-source users. It is currently in the pilot stage. If you have requirements, please contact Pigsty sales.

10.17 - FAQ

Frequently asked questions about PostgreSQL

Why can’t my current user use the pg admin alias?

Starting from Pigsty v4.0, permissions to manage global Patroni / PostgreSQL clusters using the pg admin alias have been tightened to the admin group (admin) on admin nodes.

The admin user (dba) created by the node.yml playbook has this permission by default. If your current user wants this permission, you need to explicitly add them to the admin group:

sudo usermod -aG admin <username>

PGSQL Init Fails: Fail to wait for postgres/patroni primary

There are multiple possible causes for this error. You need to check Ansible, Systemd / Patroni / PostgreSQL logs to find the real cause.

  • Possibility 1: Cluster config error - find and fix the incorrect config items.
  • Possibility 2: A cluster with the same name exists, or the previous same-named cluster primary was improperly removed.
  • Possibility 3: Residual garbage metadata from a same-named cluster in DCS - decommissioning wasn’t completed properly. Use etcdctl del --prefix /pg/<cls> to manually delete residual data (be careful).
  • Possibility 4: Your PostgreSQL or node-related RPM pkgs were not successfully installed.
  • Possibility 5: Your Watchdog kernel module was not properly enabled/loaded.
  • Possibility 6: The locale you specified during database init doesn’t exist (e.g., used en_US.UTF8 but English language pack or Locale support wasn’t installed).
  • If you encounter other causes, please submit an Issue or ask the community for help.

PGSQL Init Fails: Fail to wait for postgres/patroni replica

There are several possible causes:

Immediate failure: Usually due to config errors, network issues, corrupted DCS metadata, etc. You must check /pg/log to find the actual cause.

Failure after a while: This might be due to source instance data corruption. See PGSQL FAQ: How to create a replica when data is corrupted?

Timeout after a long time: If the wait for postgres replica task takes 30 minutes or longer and fails due to timeout, this is common for large clusters (e.g., 1TB+, may take hours to create a replica).

In this case, the underlying replica creation process is still ongoing. You can use pg list <cls> to check cluster status and wait for the replica to catch up with the primary. Then use the following command to continue with remaining tasks and complete the full replica init:

./pgsql.yml -t pg_hba,pg_reload,pg_backup,pgbouncer,pg_vip,pg_dns,pg_service,pg_exporter,pg_register -l <problematic_replica>

PGSQL Init Fails: ABORT due to pg_safeguard enabled

This means the PostgreSQL instance being cleaned has the deletion safeguard enabled. Disable pg_safeguard to remove the Postgres instance.

If the deletion safeguard pg_safeguard is enabled, you cannot remove running PGSQL instances using bin/pgsql-rm or the pgsql-rm.yml playbook.

To disable pg_safeguard, you can set pg_safeguard to false in the config inventory, or use the command param -e pg_safeguard=false when executing the playbook.

./pgsql-rm.yml -e pg_safeguard=false -l <cls_to_remove>    # Force override pg_safeguard

How to Enable HugePages for PostgreSQL?

Use node_hugepage_count and node_hugepage_ratio or /pg/bin/pg-tune-hugepage

If you plan to enable HugePages, consider using node_hugepage_count and node_hugepage_ratio, and apply with ./node.yml -t node_tune.

HugePages have pros and cons for databases. The advantage is that memory is managed exclusively, eliminating concerns about being reallocated and reducing database OOM risk. The disadvantage is that it may negatively impact performance in certain scenarios.

Before PostgreSQL starts, you need to allocate enough huge pages. The wasted portion can be reclaimed using the pg-tune-hugepage script, but this script is only available for PostgreSQL 15+.

If your PostgreSQL is already running, you can enable huge pages using the following method (PG15+ only):

sync; echo 3 > /proc/sys/vm/drop_caches   # Flush disk, release system cache (be prepared for database perf impact)
sudo /pg/bin/pg-tune-hugepage             # Write nr_hugepages to /etc/sysctl.d/hugepage.conf
pg restart <cls>                          # Restart postgres to use hugepage

How to Ensure No Data Loss During Failover?

Use the crit.yml param template, set pg_rpo to 0, or config the cluster for sync commit mode.

Consider using Sync Standby and Quorum Commit to ensure zero data loss during failover.

For more details, see the intro in Security Considerations - Availability.


How to Rescue When Disk is Full?

If the disk is full and even Shell commands cannot execute, rm -rf /pg/dummy can release some emergency space.

By default, pg_dummy_filesize is set to 64MB. In prod envs, it’s recommended to increase it to 8GB or larger.

It will be placed at /pg/dummy path on the PGSQL main data disk. You can delete this file to free up some emergency space: at least it will allow you to run some shell scripts on that node to further reclaim other space.


How to Create a Replica When Cluster Data is Corrupted?

Pigsty sets the clonefrom: true tag in the patroni config of all instances, marking the instance as available for creating replicas.

If an instance has corrupted data files causing errors when creating new replicas, you can set clonefrom: false to avoid pulling data from the corrupted instance. Here’s how:

$ vi /pg/bin/patroni.yml

tags:
  nofailover: false
  clonefrom: true      # ----------> change to false
  noloadbalance: false
  nosync: false
  version:  '15'
  spec: '4C.8G.50G'
  conf: 'oltp.yml'

$ systemctl reload patroni    # Reload Patroni config

What is the Perf Overhead of PostgreSQL Monitoring?

A regular PostgreSQL instance scrape takes about 200ms. The scrape interval defaults to 10 seconds, which is almost negligible for a prod multi-core database instance.

Note that Pigsty enables in-database object monitoring by default, so if your database has hundreds of thousands of table/index objects, scraping may increase to several seconds.

You can modify Prometheus’s scrape frequency. Please ensure: the scrape cycle should be significantly longer than the duration of a single scrape.


How to Monitor an Existing PostgreSQL Instance?

Detailed monitoring config instructions are provided in PGSQL Monitor.


How to Manually Remove PostgreSQL Monitoring Targets?

./pgsql-rm.yml -t rm_metrics -l <cls>     # Remove all instances of cluster 'cls' from victoria
bin/pgmon-rm <ins>     # Remove a single instance 'ins' monitoring object from Victoria, especially suitable for removing added external instances

10.18 - Misc

Miscellaneous Topics

10.18.1 - Service / Access

Separate read and write operations, route traffic correctly, and deliver PostgreSQL cluster capabilities reliably.

Separate read and write operations, route traffic correctly, and deliver PostgreSQL cluster capabilities reliably.

Service is an abstraction: it is the form in which database clusters provide capabilities to the outside world and encapsulates the details of the underlying cluster.

Services are critical for stable access in production environments and show their value when high availability clusters automatically fail over. Single-node users typically don’t need to worry about this concept.


Single-Node Users

The concept of “service” is for production environments. Personal users/single-node clusters can simply access the database directly using instance name/IP address.

For example, Pigsty’s default single-node pg-meta.meta database can be connected directly using three different users:

psql postgres://dbuser_dba:[email protected]/meta     # Connect directly with DBA superuser
psql postgres://dbuser_meta:[email protected]/meta   # Connect with default business admin user
psql postgres://dbuser_view:DBUser.View@pg-meta/meta       # Connect with default read-only user via instance domain name

Service Overview

In real-world production environments, we use replication-based primary-replica database clusters. In a cluster, there is one and only one instance as the leader (primary) that can accept writes. Other instances (replicas) continuously fetch change logs from the cluster leader and stay consistent with it. At the same time, replicas can also handle read-only requests, significantly reducing the load on the primary in read-heavy scenarios. Therefore, separating write requests and read-only requests to the cluster is a very common practice.

In addition, for production environments with high-frequency short connections, we also pool requests through a connection pool middleware (Pgbouncer) to reduce the overhead of creating connections and backend processes. But for scenarios such as ETL and change execution, we need to bypass the connection pool and access the database directly. At the same time, high-availability clusters will experience failover when failures occur, and failover will cause changes to the cluster’s leader. Therefore, high-availability database solutions require that write traffic can automatically adapt to changes in the cluster’s leader. These different access requirements (read-write separation, pooling and direct connection, automatic failover adaptation) ultimately abstract the concept of Service.

Typically, database clusters must provide this most basic service:

  • Read-Write Service (primary): Can read and write to the database

For production database clusters, at least these two services should be provided:

  • Read-Write Service (primary): Write data: can only be carried by the primary.
  • Read-Only Service (replica): Read data: can be carried by replicas, or by the primary if there are no replicas

In addition, depending on specific business scenarios, there may be other services, such as:

  • Default Direct Service (default): Allows (admin) users to access the database directly, bypassing the connection pool
  • Offline Replica Service (offline): Dedicated replicas that do not handle online read-only traffic, used for ETL and analytical queries
  • Standby Replica Service (standby): Read-only service without replication lag, handled by sync standby/primary for read-only queries
  • Delayed Replica Service (delayed): Access old data from the same cluster at a previous point in time, handled by delayed replica

Default Services

Pigsty provides four different services by default for each PostgreSQL database cluster. Here are the default services and their definitions:

ServicePortDescription
primary5433Production read-write, connects to primary connection pool (6432)
replica5434Production read-only, connects to replica connection pool (6432)
default5436Admin, ETL writes, direct access to primary (5432)
offline5438OLAP, ETL, personal users, interactive queries

Taking the default pg-meta cluster as an example, it provides four default services:

psql postgres://dbuser_meta:DBUser.Meta@pg-meta:5433/meta   # pg-meta-primary : production read-write via primary pgbouncer(6432)
psql postgres://dbuser_meta:DBUser.Meta@pg-meta:5434/meta   # pg-meta-replica : production read-only via replica pgbouncer(6432)
psql postgres://dbuser_dba:DBUser.DBA@pg-meta:5436/meta     # pg-meta-default : direct connection via primary postgres(5432)
psql postgres://dbuser_stats:DBUser.Stats@pg-meta:5438/meta # pg-meta-offline : direct connection via offline postgres(5432)

You can see how these four services work from the sample cluster architecture diagram:

pigsty-ha.png

Note that the pg-meta domain name points to the cluster’s L2 VIP, which in turn points to the haproxy load balancer on the cluster primary, which routes traffic to different instances. See Accessing Services for details.


Service Implementation

In Pigsty, services are implemented using haproxy on nodes, differentiated by different ports on host nodes.

Haproxy is enabled by default on each node managed by Pigsty to expose services, and database nodes are no exception. Although nodes in a cluster have primary-replica distinctions from the database perspective, from the service perspective, each node is the same: This means that even if you access a replica node, as long as you use the correct service port, you can still use the primary’s read-write service. This design can hide complexity: so as long as you can access any instance on a PostgreSQL cluster, you can completely access all services.

This design is similar to NodePort services in Kubernetes. Similarly, in Pigsty, each service includes the following two core elements:

  1. Access endpoints exposed through NodePort (port number, where to access?)
  2. Target instances selected through Selectors (instance list, who carries the load?)

Pigsty’s service delivery boundary stops at the cluster’s HAProxy, and users can access these load balancers in various ways. See Accessing Services.

All services are declared through configuration files. For example, the PostgreSQL default services are defined by the pg_default_services parameter:

pg_default_services:
- { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
- { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
- { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
- { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}

You can also define additional services in pg_services. Both pg_default_services and pg_services are arrays of service definition objects.


Defining Services

Pigsty allows you to define your own services:

  • pg_default_services: Services uniformly exposed by all PostgreSQL clusters, four by default.
  • pg_services: Additional PostgreSQL services, can be defined at global or cluster level as needed.
  • haproxy_services: Directly customize HAProxy service content, can be used for accessing other components

For PostgreSQL clusters, you typically only need to focus on the first two. Each service definition generates a new configuration file in the configuration directory of all related HAProxy instances: /etc/haproxy/<svcname>.cfg Here’s a custom service example standby: when you want to provide a read-only service without replication lag, you can add this record to pg_services:

- name: standby                   # Required, service name, final svc name uses `pg_cluster` as prefix, e.g.: pg-meta-standby
  port: 5435                      # Required, exposed service port (as kubernetes service node port mode)
  ip: "*"                         # Optional, IP address the service binds to, all IP addresses by default
  selector: "[]"                  # Required, service member selector, uses JMESPath to filter configuration manifest
  backup: "[? pg_role == `primary`]"  # Optional, service member selector (backup), instances selected here only carry the service when all default selector instances are down
  dest: default                   # Optional, target port, default|postgres|pgbouncer|<port_number>, defaults to 'default', Default means using pg_default_service_dest value to ultimately decide
  check: /sync                    # Optional, health check URL path, defaults to /, here uses Patroni API: /sync, only sync standby and primary return 200 healthy status code
  maxconn: 5000                   # Optional, maximum number of allowed frontend connections, defaults to 5000
  balance: roundrobin             # Optional, haproxy load balancing algorithm (defaults to roundrobin, other options: leastconn)
  options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'

The above service definition will be converted to haproxy configuration file /etc/haproxy/pg-test-standby.conf on the sample three-node pg-test:

#---------------------------------------------------------------------
# service: pg-test-standby @ 10.10.10.11:5435
#---------------------------------------------------------------------
# service instances 10.10.10.11, 10.10.10.13, 10.10.10.12
# service backups   10.10.10.11
listen pg-test-standby
    bind *:5435            # <--- Binds port 5435 on all IP addresses
    mode tcp               # <--- Load balancer works on TCP protocol
    maxconn 5000           # <--- Maximum connections 5000, can be increased as needed
    balance roundrobin     # <--- Load balancing algorithm is rr round-robin, can also use leastconn
    option httpchk         # <--- Enable HTTP health check
    option http-keep-alive # <--- Keep HTTP connection
    http-check send meth OPTIONS uri /sync   # <---- Here uses /sync, Patroni health check API, only sync standby and primary return 200 healthy status code
    http-check expect status 200             # <---- Health check return code 200 means normal
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers: # All three instances of pg-test cluster are selected by selector: "[]", since there are no filter conditions, they all become backend servers for pg-test-replica service. But due to /sync health check, only primary and sync standby can actually handle requests
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100 backup  # <----- Only primary satisfies condition pg_role == `primary`, selected by backup selector
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100         #        Therefore serves as service fallback instance: normally doesn't handle requests, only handles read-only requests when all other replicas fail, thus maximally avoiding read-write service being affected by read-only service
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100         #

Here, all three instances of the pg-test cluster are selected by selector: "[]", rendered into the backend server list of the pg-test-replica service. But due to the /sync health check, Patroni Rest API only returns healthy HTTP 200 status code on the primary and sync standby, so only the primary and sync standby can actually handle requests. Additionally, the primary satisfies the condition pg_role == primary, is selected by the backup selector, and is marked as a backup server, only used when no other instances (i.e., sync standby) can meet the demand.


Primary Service

The Primary service is perhaps the most critical service in production environments. It provides read-write capability to the database cluster on port 5433. The service definition is as follows:

- { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
  • The selector parameter selector: "[]" means all cluster members will be included in the Primary service
  • But only the primary can pass the health check (check: /primary) and actually carry Primary service traffic.
  • The destination parameter dest: default means the Primary service destination is affected by the pg_default_service_dest parameter
  • The default value default of dest will be replaced by the value of pg_default_service_dest, which defaults to pgbouncer.
  • By default, the Primary service destination is the connection pool on the primary, which is the port specified by pgbouncer_port, defaulting to 6432

If the value of pg_default_service_dest is postgres, then the primary service destination will bypass the connection pool and use the PostgreSQL database port directly (pg_port, default 5432). This parameter is very useful for scenarios that don’t want to use a connection pool.

Example: haproxy configuration for pg-test-primary
listen pg-test-primary
    bind *:5433         # <--- primary service defaults to port 5433
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /primary # <--- primary service defaults to Patroni RestAPI /primary health check
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100

Patroni’s high availability mechanism ensures that at most one instance’s /primary health check is true at any time, so the Primary service will always route traffic to the primary instance.

One benefit of using the Primary service instead of direct database connection is that if the cluster has a split-brain situation for some reason (e.g., kill -9 killing the primary Patroni without watchdog), Haproxy can still avoid split-brain in this case, because it will only distribute traffic when Patroni is alive and returns primary status.


Replica Service

The Replica service is second only to the Primary service in importance in production environments. It provides read-only capability to the database cluster on port 5434. The service definition is as follows:

- { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
  • The selector parameter selector: "[]" means all cluster members will be included in the Replica service
  • All instances can pass the health check (check: /read-only) and carry Replica service traffic.
  • Backup selector: [? pg_role == 'primary' || pg_role == 'offline' ] marks the primary and offline replicas as backup servers.
  • Only when all normal replicas are down will the Replica service be carried by the primary or offline replicas.
  • The destination parameter dest: default means the Replica service destination is also affected by the pg_default_service_dest parameter
  • The default value default of dest will be replaced by the value of pg_default_service_dest, which defaults to pgbouncer, same as the Primary service
  • By default, the Replica service destination is the connection pool on the replicas, which is the port specified by pgbouncer_port, defaulting to 6432
Example: haproxy configuration for pg-test-replica
listen pg-test-replica
    bind *:5434
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /read-only
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100 backup
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100

The Replica service is very flexible: if there are surviving dedicated Replica instances, it will prioritize using these instances to handle read-only requests. Only when all replica instances are down will the primary handle read-only requests. For the common one-primary-one-replica two-node cluster, this means: use the replica as long as it’s alive, use the primary when the replica is down.

Additionally, unless all dedicated read-only instances are down, the Replica service will not use dedicated Offline instances, thus avoiding mixing online fast queries and offline slow queries together, interfering with each other.


Default Service

The Default service provides services on port 5436. It is a variant of the Primary service.

The Default service always bypasses the connection pool and connects directly to PostgreSQL on the primary. This is useful for admin connections, ETL writes, CDC data change capture, etc.

- { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }

If pg_default_service_dest is changed to postgres, then the Default service is completely equivalent to the Primary service except for port and name. In this case, you can consider removing Default from default services.

Example: haproxy configuration for pg-test-default
listen pg-test-default
    bind *:5436         # <--- Except for listening port/target port and service name, other configurations are exactly the same as primary service
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /primary
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:5432 check port 8008 weight 100
    server pg-test-3 10.10.10.13:5432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:5432 check port 8008 weight 100

Offline Service

The Offline service provides services on port 5438. It also bypasses the connection pool to directly access the PostgreSQL database, typically used for slow queries/analytical queries/ETL reads/personal user interactive queries. Its service definition is as follows:

- { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}

The Offline service routes traffic directly to dedicated offline replicas, or normal read-only instances with the pg_offline_query flag.

  • The selector parameter filters two types of instances from the cluster: offline replicas with pg_role = offline, or normal read-only instances with pg_offline_query = true
  • The main difference between dedicated offline replicas and flagged normal replicas is: the former does not handle Replica service requests by default, avoiding mixing fast and slow requests together, while the latter does by default.
  • The backup selector parameter filters one type of instance from the cluster: normal replicas without offline flag. This means if offline instances or flagged normal replicas fail, other normal replicas can be used to carry the Offline service.
  • The health check /replica only returns 200 for replicas, the primary returns an error, so the Offline service will never distribute traffic to the primary instance, even if only this primary is left in the cluster.
  • At the same time, the primary instance is neither selected by the selector nor by the backup selector, so it will never carry the Offline service. Therefore, the Offline service can always avoid user access to the primary, thus avoiding impact on the primary.
Example: haproxy configuration for pg-test-offline
listen pg-test-offline
    bind *:5438
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /replica
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-3 10.10.10.13:5432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:5432 check port 8008 weight 100 backup

The Offline service provides limited read-only service, typically used for two types of queries: interactive queries (personal users), slow queries and long transactions (analytics/ETL).

The Offline service requires extra maintenance care: when the cluster experiences primary-replica switchover or automatic failover, the cluster’s instance roles change, but Haproxy’s configuration does not automatically change. For clusters with multiple replicas, this is usually not a problem. However, for simplified small clusters with one primary and one replica running Offline queries, primary-replica switchover means the replica becomes the primary (health check fails), and the original primary becomes a replica (not in the Offline backend list), so no instance can carry the Offline service. Therefore, you need to manually reload services to make the changes effective.

If your business model is relatively simple, you can consider removing the Default service and Offline service, and use the Primary service and Replica service to connect directly to the database.


Reload Services

When cluster members change, such as adding/removing replicas, primary-replica switchover, or adjusting relative weights, you need to reload services to make the changes effective.

bin/pgsql-svc <cls> [ip...]         # Reload services for lb cluster or lb instance
# ./pgsql.yml -t pg_service         # Actual ansible task for reloading services

Accessing Services

Pigsty’s service delivery boundary stops at the cluster’s HAProxy. Users can access these load balancers in various ways.

The typical approach is to use DNS or VIP access, binding them to all or any number of load balancers in the cluster.

pigsty-access.jpg

You can use different host & port combinations, which provide PostgreSQL services in different ways.

Host

TypeExampleDescription
Cluster Domainpg-testAccess via cluster domain name (resolved by dnsmasq @ infra node)
Cluster VIP Address10.10.10.3Access via L2 VIP address managed by vip-manager, bound to primary node
Instance Hostnamepg-test-1Access via any instance hostname (resolved by dnsmasq @ infra node)
Instance IP Address10.10.10.11Access any instance’s IP address

Port

Pigsty uses different ports to distinguish pg services

PortServiceTypeDescription
5432postgresDatabaseDirect access to postgres server
6432pgbouncerMiddlewareAccess postgres via connection pool middleware
5433primaryServiceAccess primary pgbouncer (or postgres)
5434replicaServiceAccess replica pgbouncer (or postgres)
5436defaultServiceAccess primary postgres
5438offlineServiceAccess offline postgres

Combinations

# Access via cluster domain name
postgres://test@pg-test:5432/test # DNS -> L2 VIP -> Primary direct connection
postgres://test@pg-test:6432/test # DNS -> L2 VIP -> Primary connection pool -> Primary
postgres://test@pg-test:5433/test # DNS -> L2 VIP -> HAProxy -> Primary connection pool -> Primary
postgres://test@pg-test:5434/test # DNS -> L2 VIP -> HAProxy -> Replica connection pool -> Replica
postgres://dbuser_dba@pg-test:5436/test # DNS -> L2 VIP -> HAProxy -> Primary direct connection (for admin)
postgres://dbuser_stats@pg-test:5438/test # DNS -> L2 VIP -> HAProxy -> Offline direct connection (for ETL/personal queries)

# Direct access via cluster VIP
postgres://[email protected]:5432/test # L2 VIP -> Primary direct access
postgres://[email protected]:6432/test # L2 VIP -> Primary connection pool -> Primary
postgres://[email protected]:5433/test # L2 VIP -> HAProxy -> Primary connection pool -> Primary
postgres://[email protected]:5434/test # L2 VIP -> HAProxy -> Replica connection pool -> Replica
postgres://[email protected]:5436/test # L2 VIP -> HAProxy -> Primary direct connection (for admin)
postgres://[email protected]::5438/test # L2 VIP -> HAProxy -> Offline direct connection (for ETL/personal queries)

# Specify any cluster instance name directly
postgres://test@pg-test-1:5432/test # DNS -> Database instance direct connection (single instance access)
postgres://test@pg-test-1:6432/test # DNS -> Connection pool -> Database
postgres://test@pg-test-1:5433/test # DNS -> HAProxy -> Connection pool -> Database read/write
postgres://test@pg-test-1:5434/test # DNS -> HAProxy -> Connection pool -> Database read-only
postgres://dbuser_dba@pg-test-1:5436/test # DNS -> HAProxy -> Database direct connection
postgres://dbuser_stats@pg-test-1:5438/test # DNS -> HAProxy -> Database offline read/write

# Specify any cluster instance IP directly
postgres://[email protected]:5432/test # Database instance direct connection (direct instance specification, no automatic traffic distribution)
postgres://[email protected]:6432/test # Connection pool -> Database
postgres://[email protected]:5433/test # HAProxy -> Connection pool -> Database read/write
postgres://[email protected]:5434/test # HAProxy -> Connection pool -> Database read-only
postgres://[email protected]:5436/test # HAProxy -> Database direct connection
postgres://[email protected]:5438/test # HAProxy -> Database offline read-write

# Smart client: automatic read-write separation
postgres://[email protected]:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=primary
postgres://[email protected]:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=prefer-standby

Overriding Services

You can override default service configuration in multiple ways. A common requirement is to have Primary service and Replica service bypass the Pgbouncer connection pool and access the PostgreSQL database directly.

To achieve this, you can change pg_default_service_dest to postgres, so all services with svc.dest='default' in their service definitions will use postgres instead of the default pgbouncer as the target.

If you have already pointed Primary service to PostgreSQL, then default service becomes redundant and can be considered for removal.

If you don’t need to distinguish between personal interactive queries and analytical/ETL slow queries, you can consider removing Offline service from the default service list pg_default_services.

If you don’t need read-only replicas to share online read-only traffic, you can also remove Replica service from the default service list.


Delegating Services

Pigsty exposes PostgreSQL services through haproxy on nodes. All haproxy instances in the entire cluster are configured with the same service definitions.

However, you can delegate pg services to specific node groups (e.g., dedicated haproxy load balancer cluster) instead of haproxy on PostgreSQL cluster members.

To do this, you need to override the default service definitions using pg_default_services and set pg_service_provider to the proxy group name.

For example, this configuration will expose the pg cluster’s primary service on the proxy haproxy node group on port 10013.

pg_service_provider: proxy       # Use load balancer from `proxy` group on port 10013
pg_default_services:  [{ name: primary ,port: 10013 ,dest: postgres  ,check: /primary   ,selector: "[]" }]

Users need to ensure that the port for each delegated service is unique in the proxy cluster.

An example of using a dedicated load balancer cluster is provided in the 43-node production environment simulation sandbox: prod.yml

10.18.2 - User / Role

Users/roles refer to logical objects within a database cluster created using the SQL commands CREATE USER/ROLE.

In this context, users refer to logical objects within a database cluster created using the SQL commands CREATE USER/ROLE.

In PostgreSQL, users belong directly to the database cluster rather than to a specific database. Therefore, when creating business databases and business users, you should follow the principle of “users first, then databases.”


Defining Users

Pigsty defines roles and users in database clusters through two configuration parameters:

  • pg_default_roles: Defines globally unified roles and users
  • pg_users: Defines business users and roles at the database cluster level

The former defines roles and users shared across the entire environment, while the latter defines business roles and users specific to individual clusters. Both have the same format and are arrays of user definition objects.

You can define multiple users/roles, and they will be created sequentially—first global, then cluster-level, and finally in array order—so later users can belong to roles defined earlier.

Here is the business user definition for the default cluster pg-meta in the Pigsty demo environment:

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 }
      - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
      - {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database    }
      - {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database   }
      - {name: dbuser_kong     ,password: DBUser.Kong     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway    }
      - {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service       }
      - {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service     }
      - {name: dbuser_noco     ,password: DBUser.Noco     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for nocodb service      }

Each user/role definition is an object that may include the following fields. Using dbuser_meta as an example:

- name: dbuser_meta               # Required, `name` is the only mandatory field in user definition
  password: DBUser.Meta           # Optional, password can be scram-sha-256 hash string or plaintext
  login: true                     # Optional, can login by default
  superuser: false                # Optional, default is false, is this a superuser?
  createdb: false                 # Optional, default is false, can create databases?
  createrole: false               # Optional, default is false, can create roles?
  inherit: true                   # Optional, by default this role can use inherited privileges?
  replication: false              # Optional, default is false, can this role perform replication?
  bypassrls: false                # Optional, default is false, can this role bypass row-level security?
  pgbouncer: true                 # Optional, default is false, add this user to pgbouncer user list? (production users using connection pool should explicitly set to true)
  connlimit: -1                   # Optional, user connection limit, default -1 disables limit
  expire_in: 3650                 # Optional, this role expires: calculated from creation + n days (higher priority than expire_at)
  expire_at: '2030-12-31'         # Optional, when this role expires, use YYYY-MM-DD format string to specify a date (lower priority than expire_in)
  comment: pigsty admin user      # Optional, description and comment string for this user/role
  roles: [dbrole_admin]           # Optional, default roles are: dbrole_{admin,readonly,readwrite,offline}
  parameters: {}                  # Optional, use `ALTER ROLE SET` to configure role-level database parameters for this role
  pool_mode: transaction          # Optional, pgbouncer pool mode defaulting to transaction, user level
  pool_connlimit: -1              # Optional, user-level maximum database connections, default -1 disables limit
  search_path: public             # Optional, key-value configuration parameters per postgresql documentation (e.g., use pigsty as default search_path)
  • The only required field is name, which should be a valid and unique username in the PostgreSQL cluster.
  • Roles don’t need a password, but for loginable business users, a password is usually required.
  • password can be plaintext or scram-sha-256 / md5 hash string; please avoid using plaintext passwords.
  • Users/roles are created one by one in array order, so ensure roles/groups are defined before their members.
  • login, superuser, createdb, createrole, inherit, replication, bypassrls are boolean flags.
  • pgbouncer is disabled by default: to add business users to the pgbouncer user list, you should explicitly set it to true.

ACL System

Pigsty has a built-in, out-of-the-box access control / ACL system. You can easily use it by simply assigning the following four default roles to business users:

  • dbrole_readwrite: Role with global read-write access (production accounts primarily used by business should have database read-write privileges)
  • dbrole_readonly: Role with global read-only access (if other businesses need read-only access, use this role)
  • dbrole_admin: Role with DDL privileges (business administrators, scenarios requiring table creation in applications)
  • dbrole_offline: Restricted read-only access role (can only access offline instances, typically for individual users)

If you want to redesign your own ACL system, consider customizing the following parameters and templates:


Creating Users

Users and roles defined in pg_default_roles and pg_users are automatically created one by one during the cluster initialization PROVISION phase. If you want to create users on an existing cluster, you can use the bin/pgsql-user tool. Add the new user/role definition to all.children.<cls>.pg_users and use the following method to create the user:

bin/pgsql-user <cls> <username>    # pgsql-user.yml -l <cls> -e username=<username>

Unlike databases, the user creation playbook is always idempotent. When the target user already exists, Pigsty will modify the target user’s attributes to match the configuration. So running it repeatedly on existing clusters is usually not a problem.


Modifying Users

The method for modifying PostgreSQL user attributes is the same as Creating Users.

First, adjust your user definition, modify the attributes that need adjustment, then execute the following command to apply:

bin/pgsql-user <cls> <username>    # pgsql-user.yml -l <cls> -e username=<username>

Note that modifying users will not delete users, but modify user attributes through the ALTER USER command; it also won’t revoke user privileges and groups, and will use the GRANT command to grant new roles.


Pgbouncer Users

Pgbouncer is enabled by default and serves as a connection pool middleware, with its users managed by default.

Pigsty adds all users in pg_users that explicitly have the pgbouncer: true flag to the pgbouncer user list.

Users in the Pgbouncer connection pool are listed in /etc/pgbouncer/userlist.txt:

"postgres" ""
"dbuser_wiki" "SCRAM-SHA-256$4096:+77dyhrPeFDT/TptHs7/7Q==$KeatuohpKIYzHPCt/tqBu85vI11o9mar/by0hHYM2W8=:X9gig4JtjoS8Y/o1vQsIX/gY1Fns8ynTXkbWOjUfbRQ="
"dbuser_view" "SCRAM-SHA-256$4096:DFoZHU/DXsHL8MJ8regdEw==$gx9sUGgpVpdSM4o6A2R9PKAUkAsRPLhLoBDLBUYtKS0=:MujSgKe6rxcIUMv4GnyXJmV0YNbf39uFRZv724+X1FE="
"dbuser_monitor" "SCRAM-SHA-256$4096:fwU97ZMO/KR0ScHO5+UuBg==$CrNsmGrx1DkIGrtrD1Wjexb/aygzqQdirTO1oBZROPY=:L8+dJ+fqlMQh7y4PmVR/gbAOvYWOr+KINjeMZ8LlFww="
"dbuser_meta" "SCRAM-SHA-256$4096:leB2RQPcw1OIiRnPnOMUEg==$eyC+NIMKeoTxshJu314+BmbMFpCcspzI3UFZ1RYfNyU=:fJgXcykVPvOfro2MWNkl5q38oz21nSl1dTtM65uYR1Q="
"dbuser_kong" "SCRAM-SHA-256$4096:bK8sLXIieMwFDz67/0dqXQ==$P/tCRgyKx9MC9LH3ErnKsnlOqgNd/nn2RyvThyiK6e4=:CDM8QZNHBdPf97ztusgnE7olaKDNHBN0WeAbP/nzu5A="
"dbuser_grafana" "SCRAM-SHA-256$4096:HjLdGaGmeIAGdWyn2gDt/Q==$jgoyOB8ugoce+Wqjr0EwFf8NaIEMtiTuQTg1iEJs9BM=:ed4HUFqLyB4YpRr+y25FBT7KnlFDnan6JPVT9imxzA4="
"dbuser_gitea" "SCRAM-SHA-256$4096:l1DBGCc4dtircZ8O8Fbzkw==$tpmGwgLuWPDog8IEKdsaDGtiPAxD16z09slvu+rHE74=:pYuFOSDuWSofpD9OZhG7oWvyAR0PQjJBffgHZLpLHds="
"dbuser_dba" "SCRAM-SHA-256$4096:zH8niABU7xmtblVUo2QFew==$Zj7/pq+ICZx7fDcXikiN7GLqkKFA+X5NsvAX6CMshF0=:pqevR2WpizjRecPIQjMZOm+Ap+x0kgPL2Iv5zHZs0+g="
"dbuser_bytebase" "SCRAM-SHA-256$4096:OMoTM9Zf8QcCCMD0svK5gg==$kMchqbf4iLK1U67pVOfGrERa/fY818AwqfBPhsTShNQ=:6HqWteN+AadrUnrgC0byr5A72noqnPugItQjOLFw0Wk="

User-level connection pool parameters are maintained in a separate file: /etc/pgbouncer/useropts.txt, for example:

dbuser_dba                  = pool_mode=session max_user_connections=16
dbuser_monitor              = pool_mode=session max_user_connections=8

When you create a database, the Pgbouncer database list definition file will be refreshed and take effect through online configuration reload, without affecting existing connections.

Pgbouncer runs with the same dbsu as PostgreSQL, which defaults to the postgres operating system user. You can use the pgb alias to access pgbouncer management functions using the dbsu.

Pigsty also provides a utility function pgb-route that can quickly switch pgbouncer database traffic to other nodes in the cluster, useful for zero-downtime migration:

The connection pool user configuration files userlist.txt and useropts.txt are automatically refreshed when you create users, and take effect through online configuration reload, normally without affecting existing connections.

Note that the pgbouncer_auth_query parameter allows you to use dynamic queries to complete connection pool user authentication—this is a compromise when you don’t want to manage users in the connection pool.

10.18.3 - Database

Database refers to the logical object created using the SQL command CREATE DATABASE within a database cluster.

In this context, Database refers to the logical object created using the SQL command CREATE DATABASE within a database cluster.

A PostgreSQL server can serve multiple databases simultaneously. In Pigsty, you can define the required databases in the cluster configuration.

Pigsty will modify and customize the default template database template1, creating default schemas, installing default extensions, and configuring default privileges. Newly created databases will inherit these settings from template1 by default.

By default, all business databases will be added to the Pgbouncer connection pool in a 1:1 manner; pg_exporter will use an auto-discovery mechanism to find all business databases and monitor objects within them.


Define Database

Business databases are defined in the database cluster parameter pg_databases, which is an array of database definition objects. Databases in the array are created sequentially according to the definition order, so later defined databases can use previously defined databases as templates.

Below is the database definition for the default pg-meta cluster in the Pigsty demo environment:

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 ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: postgis, schema: public}, {name: timescaledb}]}
      - { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
      - { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
      - { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
      - { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
      - { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }
      - { name: noco     ,owner: dbuser_noco     ,revokeconn: true ,comment: nocodb database }

Each database definition is an object that may include the following fields, using the meta database as an example:

- name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
  baseline: cmdb.sql              # optional, database sql baseline path (relative path among ansible search path, e.g. files/)
  pgbouncer: true                 # optional, add this database to pgbouncer database list? true by default
  schemas: [pigsty]               # optional, additional schemas to be created, array of schema names
  extensions:                     # optional, additional extensions to be installed: array of extension objects
    - { name: postgis , schema: public }  # can specify which schema to install the extension in, or leave it unspecified (will install in the first schema of search_path)
    - { name: timescaledb }               # for example, some extensions create and use fixed schemas, so no schema specification is needed.
  comment: pigsty meta database   # optional, comment string for this database
  owner: postgres                 # optional, database owner, postgres by default
  template: template1             # optional, which template to use, template1 by default, target must be a template database
  encoding: UTF8                  # optional, database encoding, UTF8 by default (MUST same as template database)
  locale: C                       # optional, database locale, C by default (MUST same as template database)
  lc_collate: C                   # optional, database collate, C by default (MUST same as template database), no reason not to recommend changing.
  lc_ctype: C                     # optional, database ctype, C by default (MUST same as template database)
  tablespace: pg_default          # optional, default tablespace, 'pg_default' by default
  allowconn: true                 # optional, allow connection, true by default. false will disable connect at all
  revokeconn: false               # optional, revoke public connection privilege. false by default, when set to true, CONNECT privilege will be revoked from users other than owner and admin
  register_datasource: true       # optional, register this database to grafana datasources? true by default, explicitly set to false to skip registration
  connlimit: -1                   # optional, database connection limit, default -1 disable limit, set to positive integer will limit connections
  pool_auth_user: dbuser_meta     # optional, all connections to this pgbouncer database will be authenticated using this user (only useful when pgbouncer_auth_query is enabled)
  pool_mode: transaction          # optional, pgbouncer pool mode at database level, default transaction
  pool_size: 64                   # optional, pgbouncer pool size at database level, default 64
  pool_size_reserve: 32           # optional, pgbouncer pool size reserve at database level, default 32, when default pool is insufficient, can request at most this many burst connections
  pool_size_min: 0                # optional, pgbouncer pool size min at database level, default 0
  pool_max_db_conn: 100           # optional, max database connections at database level, default 100

The only required field is name, which should be a valid and unique database name in the current PostgreSQL cluster, other parameters have reasonable defaults.

  • name: Database name, required.
  • baseline: SQL file path (Ansible search path, usually in files), used to initialize database content.
  • owner: Database owner, default is postgres
  • template: Template used when creating the database, default is template1
  • encoding: Database default character encoding, default is UTF8, default is consistent with the instance. It is recommended not to configure and modify.
  • locale: Database default locale, default is C, it is recommended not to configure, keep consistent with the instance.
  • lc_collate: Database default locale string collation, default is same as instance setting, it is recommended not to modify, must be consistent with template database. It is strongly recommended not to configure, or configure to C.
  • lc_ctype: Database default LOCALE, default is same as instance setting, it is recommended not to modify or set, must be consistent with template database. It is recommended to configure to C or en_US.UTF8.
  • allowconn: Whether to allow connection to the database, default is true, not recommended to modify.
  • revokeconn: Whether to revoke connection privilege to the database? Default is false. If true, PUBLIC CONNECT privilege on the database will be revoked. Only default users (dbsu|monitor|admin|replicator|owner) can connect. In addition, admin|owner will have GRANT OPTION, can grant connection privileges to other users.
  • tablespace: Tablespace associated with the database, default is pg_default.
  • connlimit: Database connection limit, default is -1, meaning no limit.
  • extensions: Object array, each object defines an extension in the database, and the schema in which it is installed.
  • parameters: KV object, each KV defines a parameter that needs to be modified for the database through ALTER DATABASE.
  • pgbouncer: Boolean option, whether to add this database to Pgbouncer. All databases will be added to Pgbouncer list unless explicitly specified as pgbouncer: false.
  • comment: Database comment information.
  • pool_auth_user: When pgbouncer_auth_query is enabled, all connections to this pgbouncer database will use the user specified here to execute authentication queries. You need to use a user with access to the pg_shadow table.
  • pool_mode: Database level pgbouncer pool mode, default is transaction, i.e., transaction pooling. If left empty, will use pgbouncer_poolmode parameter as default value.
  • pool_size: Database level pgbouncer default pool size, default is 64
  • pool_size_reserve: Database level pgbouncer pool size reserve, default is 32, when default pool is insufficient, can request at most this many burst connections.
  • pool_size_min: Database level pgbouncer pool size min, default is 0
  • pool_max_db_conn: Database level pgbouncer connection pool max database connections, default is 100

Newly created databases are forked from the template1 database by default. This template database will be customized during the PG_PROVISION phase: configured with extensions, schemas, and default privileges, so newly created databases will also inherit these configurations unless you explicitly use another database as a template.

For database access privileges, refer to ACL: Database Privilege section.


Create Database

Databases defined in pg_databases will be automatically created during cluster initialization. If you wish to create database on an existing cluster, you can use the bin/pgsql-db wrapper script. Add new database definition to all.children.<cls>.pg_databases, and create that database with the following command:

bin/pgsql-db <cls> <dbname>    # pgsql-db.yml -l <cls> -e dbname=<dbname>

Here are some considerations when creating a new database:

The create database playbook is idempotent by default, however when you use baseline scripts, it may not be: in this case, it’s usually not recommended to re-run this on existing databases unless you’re sure the provided baseline SQL is also idempotent.

We don’t recommend manually creating new databases, especially when you’re using the default pgbouncer connection pool: unless you’re willing to manually maintain the Pgbouncer database list and keep it consistent with PostgreSQL. When creating new databases using the pgsql-db tool or pgsql-db.yml playbook, this database will also be added to the Pgbouncer Database list.

If your database definition has a non-trivial owner (default is dbsu postgres), make sure the owner user exists before creating the database. Best practice is always to create users before creating databases.


Pgbouncer Database

Pigsty will configure and enable a Pgbouncer connection pool for PostgreSQL instances in a 1:1 manner by default, communicating via /var/run/postgresql Unix Socket.

Connection pools can optimize short connection performance, reduce concurrency contention, avoid overwhelming the database with too many connections, and provide additional flexibility during database migration.

Pigsty adds all databases in pg_databases to pgbouncer’s database list by default. You can disable pgbouncer connection pool support for a specific database by explicitly setting pgbouncer: false in the database definition.

The Pgbouncer database list is defined in /etc/pgbouncer/database.txt, and connection pool parameters from the database definition are reflected here:

meta                        = host=/var/run/postgresql mode=session
grafana                     = host=/var/run/postgresql mode=transaction
bytebase                    = host=/var/run/postgresql auth_user=dbuser_meta
kong                        = host=/var/run/postgresql pool_size=32 reserve_pool=64
gitea                       = host=/var/run/postgresql min_pool_size=10
wiki                        = host=/var/run/postgresql
noco                        = host=/var/run/postgresql
mongo                       = host=/var/run/postgresql

When you create databases, the Pgbouncer database list definition file will be refreshed and take effect through online configuration reload, normally without affecting existing connections.

Pgbouncer runs with the same dbsu as PostgreSQL, defaulting to the postgres os user. You can use the pgb alias to access pgbouncer management functions using dbsu.

Pigsty also provides a utility function pgb-route, which can quickly switch pgbouncer database traffic to other nodes in the cluster for zero-downtime migration:

# route pgbouncer traffic to another cluster member
function pgb-route(){
  local ip=${1-'\/var\/run\/postgresql'}
  sed -ie "s/host=[^[:space:]]\+/host=${ip}/g" /etc/pgbouncer/pgbouncer.ini
  cat /etc/pgbouncer/pgbouncer.ini
}

10.18.4 - Authentication / HBA

Detailed explanation of Host-Based Authentication (HBA) in Pigsty.

Detailed explanation of Host-Based Authentication (HBA) in Pigsty.

Authentication is the foundation of Access Control and the Privilege System. PostgreSQL has multiple authentication methods.

Here we mainly introduce HBA: Host Based Authentication. HBA rules define which users can access which databases from which locations and in which ways.


Client Authentication

To connect to a PostgreSQL database, users must first be authenticated (password is used by default).

You can provide the password in the connection string (not secure), or pass it using the PGPASSWORD environment variable or .pgpass file. Refer to the psql documentation and PostgreSQL Connection Strings for more details.

psql 'host=<host> port=<port> dbname=<dbname> user=<username> password=<password>'
psql postgres://<username>:<password>@<host>:<port>/<dbname>
PGPASSWORD=<password>; psql -U <username> -h <host> -p <port> -d <dbname>

For example, to connect to Pigsty’s default meta database, you can use the following connection strings:

psql 'host=10.10.10.10 port=5432 dbname=meta user=dbuser_dba password=DBUser.DBA'
psql postgres://dbuser_dba:[email protected]:5432/meta
PGPASSWORD=DBUser.DBA; psql -U dbuser_dba -h 10.10.10.10 -p 5432 -d meta

By default, Pigsty enables server-side SSL encryption but does not verify client SSL certificates. To connect using client SSL certificates, you can provide client parameters using the PGSSLCERT and PGSSLKEY environment variables or sslkey and sslcert parameters.

psql 'postgres://dbuser_dba:[email protected]:5432/meta?sslkey=/path/to/dbuser_dba.key&sslcert=/path/to/dbuser_dba.crt'

Client certificates (CN = username) can be signed using the local CA with the cert.yml playbook.


Defining HBA

In Pigsty, there are four parameters related to HBA rules:

These are all arrays of HBA rule objects. Each HBA rule is an object in one of the following two forms:

1. Raw Form

The raw form of HBA is almost identical to the PostgreSQL pg_hba.conf format:

- title: allow intranet password access
  role: common
  rules:
    - host   all  all  10.0.0.0/8      md5
    - host   all  all  172.16.0.0/12   md5
    - host   all  all  192.168.0.0/16  md5

In this form, the rules field is an array of strings, where each line is a raw HBA rule. The title field is rendered as a comment explaining what the rules below do.

The role field specifies which instance roles the rule applies to. When an instance’s pg_role matches the role, the HBA rule will be added to that instance’s HBA.

  • HBA rules with role: common will be added to all instances.
  • HBA rules with role: primary will only be added to primary instances.
  • HBA rules with role: replica will only be added to replica instances.
  • HBA rules with role: offline will be added to offline instances (pg_role = offline or pg_offline_query = true)

2. Alias Form

The alias form allows you to maintain HBA rules in a simpler, clearer, and more convenient way: it replaces the rules field with addr, auth, user, and db fields. The title and role fields still apply.

- addr: 'intra'    # world|intra|infra|admin|local|localhost|cluster|<cidr>
  auth: 'pwd'      # trust|pwd|ssl|cert|deny|<official auth method>
  user: 'all'      # all|${dbsu}|${repl}|${admin}|${monitor}|<user>|<group>
  db: 'all'        # all|replication|....
  rules: []        # raw hba string precedence over above all
  title: allow intranet password access
  • addr: where - Which IP address ranges are affected by this rule?
    • world: All IP addresses
    • intra: All intranet IP address ranges: '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'
    • infra: IP addresses of Infra nodes
    • admin: IP addresses of admin_ip management nodes
    • local: Local Unix Socket
    • localhost: Local Unix Socket and TCP 127.0.0.1/32 loopback address
    • cluster: IP addresses of all members in the same PostgreSQL cluster
    • <cidr>: A specific CIDR address block or IP address
  • auth: how - What authentication method does this rule specify?
    • deny: Deny access
    • trust: Trust directly, no authentication required
    • pwd: Password authentication, uses md5 or scram-sha-256 authentication based on the pg_pwd_enc parameter
    • sha/scram-sha-256: Force use of scram-sha-256 password authentication.
    • md5: md5 password authentication, but can also be compatible with scram-sha-256 authentication, not recommended.
    • ssl: On top of password authentication pwd, require SSL to be enabled
    • ssl-md5: On top of password authentication md5, require SSL to be enabled
    • ssl-sha: On top of password authentication sha, require SSL to be enabled
    • os/ident: Use ident authentication with the operating system user identity
    • peer: Use peer authentication method, similar to os ident
    • cert: Use client SSL certificate-based authentication, certificate CN is the username
  • user: who: Which users are affected by this rule?
  • db: which: Which databases are affected by this rule?
    • all: All databases
    • replication: Allow replication connections (not specifying a specific database)
    • A specific database

3. Definition Location

Typically, global HBA is defined in all.vars. If you want to modify the global default HBA rules, you can copy one from the full.yml template to all.vars and modify it.

Cluster-specific HBA rules are defined in the database cluster-level configuration:

Here are some examples of cluster HBA rule definitions:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_hba_rules:
      - { user: dbuser_view ,db: all    ,addr: infra        ,auth: pwd  ,title: 'Allow dbuser_view password access to all databases from infrastructure nodes'}
      - { user: all         ,db: all    ,addr: 100.0.0.0/8  ,auth: pwd  ,title: 'Allow all users password access to all databases from K8S network'          }
      - { user: '${admin}'  ,db: world  ,addr: 0.0.0.0/0    ,auth: cert ,title: 'Allow admin user to login from anywhere with client certificate'       }

Reloading HBA

HBA is a static rule configuration file that needs to be reloaded to take effect after modification. The default HBA rule set typically doesn’t need to be reloaded because it doesn’t involve Role or cluster members.

If your HBA design uses specific instance role restrictions or cluster member restrictions, then when cluster instance members change (add/remove/failover), some HBA rules’ effective conditions/scope change, and you typically also need to reload HBA to reflect the latest changes.

To reload postgres/pgbouncer hba rules:

bin/pgsql-hba <cls>                 # Reload hba rules for cluster `<cls>`
bin/pgsql-hba <cls> ip1 ip2...      # Reload hba rules for specific instances

The underlying Ansible playbook commands actually executed are:

./pgsql.yml -l <cls> -e pg_reload=true -t pg_hba,pg_reload
./pgsql.yml -l <cls> -e pg_reload=true -t pgbouncer_hba,pgbouncer_reload

Default HBA

Pigsty has a default set of HBA rules that are secure enough for most scenarios. These rules use the alias form, so they are basically self-explanatory.

pg_default_hba_rules:             # postgres global default HBA rules 
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  }
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' }
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost'}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' }
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' }
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' }
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password'}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'   }
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket'}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     }
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet'}
pgb_default_hba_rules:            # pgbouncer global default HBA rules 
  - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident'}
  - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' }
  - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' }
  - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' }
  - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   }
  - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' }
Example: Rendered pg_hba.conf
#==============================================================#
# File      :   pg_hba.conf
# Desc      :   Postgres HBA Rules for pg-meta-1 [primary]
# Time      :   2023-01-11 15:19
# Host      :   pg-meta-1 @ 10.10.10.10:5432
# Path      :   /pg/data/pg_hba.conf
# Note      :   ANSIBLE MANAGED, DO NOT CHANGE!
# Author    :   Ruohang Feng ([email protected])
# License   :   AGPLv3
#==============================================================#

# addr alias
# local     : /var/run/postgresql
# admin     : 10.10.10.10
# infra     : 10.10.10.10
# intra     : 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16

# user alias
# dbsu    :  postgres
# repl    :  replicator
# monitor :  dbuser_monitor
# admin   :  dbuser_dba

# dbsu access via local os user ident [default]
local    all                postgres                              ident

# dbsu replication from local os ident [default]
local    replication        postgres                              ident

# replicator replication from localhost [default]
local    replication        replicator                            scram-sha-256
host     replication        replicator         127.0.0.1/32       scram-sha-256

# replicator replication from intranet [default]
host     replication        replicator         10.0.0.0/8         scram-sha-256
host     replication        replicator         172.16.0.0/12      scram-sha-256
host     replication        replicator         192.168.0.0/16     scram-sha-256

# replicator postgres db from intranet [default]
host     postgres           replicator         10.0.0.0/8         scram-sha-256
host     postgres           replicator         172.16.0.0/12      scram-sha-256
host     postgres           replicator         192.168.0.0/16     scram-sha-256

# monitor from localhost with password [default]
local    all                dbuser_monitor                        scram-sha-256
host     all                dbuser_monitor     127.0.0.1/32       scram-sha-256

# monitor from infra host with password [default]
host     all                dbuser_monitor     10.10.10.10/32     scram-sha-256

# admin @ infra nodes with pwd & ssl [default]
hostssl  all                dbuser_dba         10.10.10.10/32     scram-sha-256

# admin @ everywhere with ssl & pwd [default]
hostssl  all                dbuser_dba         0.0.0.0/0          scram-sha-256

# pgbouncer read/write via local socket [default]
local    all                +dbrole_readonly                      scram-sha-256
host     all                +dbrole_readonly   127.0.0.1/32       scram-sha-256

# read/write biz user via password [default]
host     all                +dbrole_readonly   10.0.0.0/8         scram-sha-256
host     all                +dbrole_readonly   172.16.0.0/12      scram-sha-256
host     all                +dbrole_readonly   192.168.0.0/16     scram-sha-256

# allow etl offline tasks from intranet [default]
host     all                +dbrole_offline    10.0.0.0/8         scram-sha-256
host     all                +dbrole_offline    172.16.0.0/12      scram-sha-256
host     all                +dbrole_offline    192.168.0.0/16     scram-sha-256

# allow application database intranet access [common] [DISABLED]
#host    kong            dbuser_kong         10.0.0.0/8          md5
#host    bytebase        dbuser_bytebase     10.0.0.0/8          md5
#host    grafana         dbuser_grafana      10.0.0.0/8          md5
Example: Rendered pgb_hba.conf
#==============================================================#
# File      :   pgb_hba.conf
# Desc      :   Pgbouncer HBA Rules for pg-meta-1 [primary]
# Time      :   2023-01-11 15:28
# Host      :   pg-meta-1 @ 10.10.10.10:5432
# Path      :   /etc/pgbouncer/pgb_hba.conf
# Note      :   ANSIBLE MANAGED, DO NOT CHANGE!
# Author    :   Ruohang Feng ([email protected])
# License   :   AGPLv3
#==============================================================#

# PGBOUNCER HBA RULES FOR pg-meta-1 @ 10.10.10.10:6432
# ansible managed: 2023-01-11 14:30:58

# addr alias
# local     : /var/run/postgresql
# admin     : 10.10.10.10
# infra     : 10.10.10.10
# intra     : 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16

# user alias
# dbsu    :  postgres
# repl    :  replicator
# monitor :  dbuser_monitor
# admin   :  dbuser_dba

# dbsu local admin access with os ident [default]
local    pgbouncer          postgres                              peer

# allow all user local access with pwd [default]
local    all                all                                   scram-sha-256
host     all                all                127.0.0.1/32       scram-sha-256

# monitor access via intranet with pwd [default]
host     pgbouncer          dbuser_monitor     10.0.0.0/8         scram-sha-256
host     pgbouncer          dbuser_monitor     172.16.0.0/12      scram-sha-256
host     pgbouncer          dbuser_monitor     192.168.0.0/16     scram-sha-256

# reject all other monitor access addr [default]
host     all                dbuser_monitor     0.0.0.0/0          reject

# admin access via intranet with pwd [default]
host     all                dbuser_dba         10.0.0.0/8         scram-sha-256
host     all                dbuser_dba         172.16.0.0/12      scram-sha-256
host     all                dbuser_dba         192.168.0.0/16     scram-sha-256

# reject all other admin access addr [default]
host     all                dbuser_dba         0.0.0.0/0          reject

# allow all user intra access with pwd [default]
host     all                all                10.0.0.0/8         scram-sha-256
host     all                all                172.16.0.0/12      scram-sha-256
host     all                all                192.168.0.0/16     scram-sha-256

Security Hardening

For scenarios requiring higher security, we provide a security hardening configuration template security.yml, which uses the following default HBA rule set:

pg_default_hba_rules:             # postgres host-based auth rules by default
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  }
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' }
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: ssl   ,title: 'replicator replication from localhost'}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: ssl   ,title: 'replicator replication from intranet' }
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: ssl   ,title: 'replicator postgres db from intranet' }
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' }
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: ssl   ,title: 'monitor from infra host with password'}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: cert  ,title: 'admin @ everywhere with ssl & cert'   }
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: ssl   ,title: 'pgbouncer read/write via local socket'}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: ssl   ,title: 'read/write biz user via password'     }
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: ssl   ,title: 'allow etl offline tasks from intranet'}
pgb_default_hba_rules:            # pgbouncer host-based authentication rules
  - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident'}
  - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' }
  - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: ssl   ,title: 'monitor access via intranet with pwd' }
  - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' }
  - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: ssl   ,title: 'admin access via intranet with pwd'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   }
  - {user: 'all'        ,db: all         ,addr: intra     ,auth: ssl   ,title: 'allow all user intra access with pwd' }

For more information, refer to the Security Hardening section.

10.18.5 - Access Control

Default role system and privilege model provided by Pigsty

Pigsty provides a battery-included access control model based on a role system and privilege system.

Access control is important, but many users don’t do it well. Therefore, Pigsty provides a simplified, ready-to-use access control model to provide a security baseline for your cluster.


Role System

Pigsty’s default role system includes four default roles and four default users:

Role NameAttributesMember ofDescription
dbrole_readonlyNOLOGINrole for global read-only access
dbrole_readwriteNOLOGINdbrole_readonlyrole for global read-write access
dbrole_adminNOLOGINpg_monitor,dbrole_readwriterole for object creation
dbrole_offlineNOLOGINrole for restricted read-only access
postgresSUPERUSERsystem superuser
replicatorREPLICATIONpg_monitor,dbrole_readonlysystem replicator
dbuser_dbaSUPERUSERdbrole_adminpgsql admin user
dbuser_monitorpg_monitorpgsql monitor user

The detailed definitions of these roles and users are as follows:

pg_default_roles:                 # default roles and users in postgres cluster
  - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
  - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
  - { name: postgres     ,superuser: true  ,comment: system superuser }
  - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator }
  - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
  - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

Default Roles

There are four default roles in Pigsty:

  • Business Read-Only (dbrole_readonly): Role for global read-only access. If other businesses need read-only access to this database, they can use this role.
  • Business Read-Write (dbrole_readwrite): Role for global read-write access. Production accounts used by primary business should have database read-write privileges.
  • Business Admin (dbrole_admin): Role with DDL permissions, typically used for business administrators or scenarios requiring table creation in applications (such as various business software).
  • Offline Read-Only (dbrole_offline): Restricted read-only access role (can only access offline instances, typically for personal users and ETL tool accounts).

Default roles are defined in pg_default_roles. Unless you really know what you’re doing, it’s recommended not to change the default role names.

- { name: dbrole_readonly  , login: false , comment: role for global read-only access  }                            # production read-only role
- { name: dbrole_offline ,   login: false , comment: role for restricted read-only access (offline instance) }      # restricted-read-only role
- { name: dbrole_readwrite , login: false , roles: [dbrole_readonly], comment: role for global read-write access }  # production read-write role
- { name: dbrole_admin , login: false , roles: [pg_monitor, dbrole_readwrite] , comment: role for object creation } # production DDL change role

Default Users

Pigsty also has four default users (system users):

  • Superuser (postgres), the owner and creator of the cluster, same as the OS dbsu.
  • Replication user (replicator), the system user used for primary-replica replication.
  • Monitor user (dbuser_monitor), a user used to monitor database and connection pool metrics.
  • Admin user (dbuser_dba), the admin user who performs daily operations and database changes.

These four default users’ username/password are defined with four pairs of dedicated parameters, referenced in many places:

Remember to change these passwords in production deployment! Don’t use default values!

pg_dbsu: postgres                             # database superuser name, it's recommended not to modify this username.
pg_dbsu_password: ''                          # database superuser password, it's recommended to leave this empty! Prohibit dbsu password login.
pg_replication_username: replicator           # system replication username
pg_replication_password: DBUser.Replicator    # system replication password, be sure to modify this password!
pg_monitor_username: dbuser_monitor           # system monitor username
pg_monitor_password: DBUser.Monitor           # system monitor password, be sure to modify this password!
pg_admin_username: dbuser_dba                 # system admin username
pg_admin_password: DBUser.DBA                 # system admin password, be sure to modify this password!

If you modify the default user parameters, update the corresponding role definition in pg_default_roles:

- { name: postgres     ,superuser: true                                          ,comment: system superuser }
- { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly]   ,comment: system replicator }
- { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
- { name: dbuser_monitor   ,roles: [pg_monitor, dbrole_readonly] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

Privilege System

Pigsty has a battery-included privilege model that works with default roles.

  • All users have access to all schemas.
  • Read-Only users (dbrole_readonly) can read from all tables. (SELECT, EXECUTE)
  • Read-Write users (dbrole_readwrite) can write to all tables and run DML. (INSERT, UPDATE, DELETE).
  • Admin users (dbrole_admin) can create objects and run DDL (CREATE, USAGE, TRUNCATE, REFERENCES, TRIGGER).
  • Offline users (dbrole_offline) are like Read-Only users, but with limited access, only allowed to access offline instances (pg_role = 'offline' or pg_offline_query = true)
  • Objects created by admin users will have correct privileges.
  • Default privileges are installed on all databases, including template databases.
  • Database connect privilege is covered by database definition.
  • CREATE privileges of database & public schema are revoked from PUBLIC by default.

Object Privilege

Default object privileges for newly created objects in the database are controlled by the pg_default_privileges parameter:

- GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
- GRANT SELECT     ON TABLES    TO dbrole_readonly
- GRANT SELECT     ON SEQUENCES TO dbrole_readonly
- GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
- GRANT USAGE      ON SCHEMAS   TO dbrole_offline
- GRANT SELECT     ON TABLES    TO dbrole_offline
- GRANT SELECT     ON SEQUENCES TO dbrole_offline
- GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
- GRANT INSERT     ON TABLES    TO dbrole_readwrite
- GRANT UPDATE     ON TABLES    TO dbrole_readwrite
- GRANT DELETE     ON TABLES    TO dbrole_readwrite
- GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
- GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
- GRANT TRUNCATE   ON TABLES    TO dbrole_admin
- GRANT REFERENCES ON TABLES    TO dbrole_admin
- GRANT TRIGGER    ON TABLES    TO dbrole_admin
- GRANT CREATE     ON SCHEMAS   TO dbrole_admin

Newly created objects by admin users will have these privileges by default. Use \ddp+ to view these default privileges:

TypeAccess privileges
function=X
dbrole_readonly=X
dbrole_offline=X
dbrole_admin=X
schemadbrole_readonly=U
dbrole_offline=U
dbrole_admin=UC
sequencedbrole_readonly=r
dbrole_offline=r
dbrole_readwrite=wU
dbrole_admin=rwU
tabledbrole_readonly=r
dbrole_offline=r
dbrole_readwrite=awd
dbrole_admin=arwdDxt

Default Privilege

ALTER DEFAULT PRIVILEGES allows you to set the privileges that will be applied to objects created in the future. It does not affect privileges assigned to already-existing objects, nor does it affect objects created by non-admin users.

In Pigsty, default privileges are defined for three roles:

{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE {{ pg_dbsu }} {{ priv }};
{% endfor %}

{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE {{ pg_admin_username }} {{ priv }};
{% endfor %}

-- for additional business admin, they should SET ROLE dbrole_admin before executing DDL to use the corresponding default privilege configuration.
{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE "dbrole_admin" {{ priv }};
{% endfor %}

This content will be used by the PG cluster initialization template pg-init-template.sql, rendered during cluster initialization and output to /pg/tmp/pg-init-template.sql. These commands will be executed on template1 and postgres databases, and newly created databases will inherit these default privilege configurations from template1.

That is to say, to maintain correct object privileges, you must execute DDL with admin users, which could be:

  1. {{ pg_dbsu }}, postgres by default
  2. {{ pg_admin_username }}, dbuser_dba by default
  3. Business admin users granted with dbrole_admin role (by switching to dbrole_admin identity using SET ROLE)

It’s wise to use postgres as the global object owner. If you wish to create objects as business admin user, you MUST USE SET ROLE dbrole_admin before running that DDL to maintain the correct privileges.

You can also explicitly grant default privileges to business admin users in the database through ALTER DEFAULT PRIVILEGE FOR ROLE <some_biz_admin> XXX.


Database Privilege

In Pigsty, database-level privileges are covered in the database definition.

There are three database level privileges: CONNECT, CREATE, TEMP, and a special ‘privilege’: OWNERSHIP.

- name: meta         # required, `name` is the only mandatory field of a database definition
  owner: postgres    # optional, specify a database owner, postgres by default
  allowconn: true    # optional, allow connection, true by default. false will disable connect at all
  revokeconn: false  # optional, revoke public connection privilege. false by default. when set to true, CONNECT privilege will be revoked from users other than owner and admin
  • If owner exists, it will be used as the database owner instead of default {{ pg_dbsu }} (which is usually postgres)
  • If revokeconn is false, all users have the CONNECT privilege of the database, this is the default behavior.
  • If revokeconn is explicitly set to true:
    • CONNECT privilege of the database will be revoked from PUBLIC: regular users cannot connect to this database
    • CONNECT privilege will be explicitly granted to {{ pg_replication_username }}, {{ pg_monitor_username }} and {{ pg_admin_username }}
    • CONNECT privilege will be granted to the database owner with GRANT OPTION, the database owner can then grant connection privileges to other users.
  • revokeconn flag can be used for database access isolation. You can create different business users as owners for each database and set the revokeconn option for them.
Example: Database Isolation
pg-infra:
  hosts:
    10.10.10.40: { pg_seq: 1, pg_role: primary }
    10.10.10.41: { pg_seq: 2, pg_role: replica , pg_offline_query: true }
  vars:
    pg_cluster: pg-infra
    pg_users:
      - { name: dbuser_confluence, password: mc2iohos , pgbouncer: true, roles: [ dbrole_admin ] }
      - { name: dbuser_gitlab, password: sdf23g22sfdd , pgbouncer: true, roles: [ dbrole_readwrite ] }
      - { name: dbuser_jira, password: sdpijfsfdsfdfs , pgbouncer: true, roles: [ dbrole_admin ] }
    pg_databases:
      - { name: confluence , revokeconn: true, owner: dbuser_confluence , connlimit: 100 }
      - { name: gitlab , revokeconn: true, owner: dbuser_gitlab, connlimit: 100 }
      - { name: jira , revokeconn: true, owner: dbuser_jira , connlimit: 100 }

CREATE Privilege

For security reasons, Pigsty revokes the CREATE privilege on databases from PUBLIC by default, which is also the default behavior since PostgreSQL 15.

The database owner has the full ability to adjust CREATE privileges as they see fit.

11 - Module: INFRA

Optional standalone infrastructure that provides NTP, DNS, observability and other foundational services for PostgreSQL.

Configuration | Administration | Playbooks | Monitoring | Parameters


Overview

Every Pigsty deployment includes a set of infrastructure components that provide services for managed nodes and database clusters:

ComponentPortDomainDescription
Nginx80/443i.pigstyWeb service portal, local repo, and unified entry point
Grafana3000g.pigstyVisualization platform for monitoring dashboards and data apps
VictoriaMetrics8428p.pigstyTime-series database with VMUI, compatible with Prometheus API
VictoriaLogs9428-Centralized log database, receives structured logs from Vector
VictoriaTraces10428-Tracing and event storage for slow SQL / request tracing
VMAlert8880-Alert rule evaluator, triggers alerts based on VictoriaMetrics metrics
AlertManager9059a.pigstyAlert aggregation and dispatch, receives notifications from VMAlert
BlackboxExporter9115-ICMP/TCP/HTTP blackbox probing
DNSMASQ53-DNS server for internal domain resolution
Chronyd123-NTP time server
PostgreSQL5432-CMDB and default database
Ansible--Runs playbooks, orchestrates all infrastructure

In Pigsty, the PGSQL module uses some services on INFRA nodes, specifically:

  • Database cluster/host node domains depend on DNSMASQ on INFRA nodes for resolution.
  • Installing software on database nodes uses the local yum/apt repo hosted by Nginx on INFRA nodes.
  • Database cluster/node monitoring metrics are scraped and stored by VictoriaMetrics on INFRA nodes, accessible via VMUI / PromQL.
  • Database and node runtime logs are collected by Vector and pushed to VictoriaLogs on INFRA, searchable in Grafana.
  • VMAlert evaluates alert rules based on metrics in VictoriaMetrics and forwards events to Alertmanager.
  • Users initiate management of database nodes from Infra/Admin nodes using Ansible or other tools:
    • Execute cluster creation, scaling, instance/cluster recycling
    • Create business users, databases, modify services, HBA changes;
    • Execute log collection, garbage cleanup, backup, inspections, etc.
  • Database nodes sync time from the NTP server on INFRA/ADMIN nodes by default
  • If no dedicated cluster exists, the HA component Patroni uses etcd on INFRA nodes as the HA DCS.
  • If no dedicated cluster exists, the backup component pgbackrest uses MinIO on INFRA nodes as an optional centralized backup repository.

Nginx

Nginx is the access entry point for all WebUI services in Pigsty, using port 80 on the admin node by default.

Many infrastructure components with WebUI are exposed through Nginx, such as Grafana, VictoriaMetrics (VMUI), AlertManager, and HAProxy traffic management pages. Additionally, static file resources like yum/apt repos are served through Nginx.

Nginx routes access requests to corresponding upstream components based on domain names according to infra_portal configuration. If you use other domains or public domains, you can modify them here:

infra_portal:  # domain names and upstream servers
  home         : { domain: i.pigsty }
  grafana      : { domain: g.pigsty ,endpoint: "${admin_ip}:3000" , websocket: true }
  prometheus   : { domain: p.pigsty ,endpoint: "${admin_ip}:8428" }   # VMUI
  alertmanager : { domain: a.pigsty ,endpoint: "${admin_ip}:9059" }
  blackbox     : { endpoint: "${admin_ip}:9115" }
  vmalert      : { endpoint: "${admin_ip}:8880" }
  #logs         : { domain: logs.pigsty ,endpoint: "${admin_ip}:9428" }
  #minio        : { domain: sss.pigsty  ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

Pigsty strongly recommends using domain names to access Pigsty UI systems rather than direct IP+port access, for these reasons:

  • Using domains makes it easy to enable HTTPS traffic encryption, consolidate access to Nginx, audit all requests, and conveniently integrate authentication mechanisms.
  • Some components only listen on 127.0.0.1 by default, so they can only be accessed through Nginx proxy.
  • Domain names are easier to remember and provide additional configuration flexibility.

If you don’t have available internet domains or local DNS resolution, you can add local static resolution records in /etc/hosts (MacOS/Linux) or C:\Windows\System32\drivers\etc\hosts (Windows).

Nginx configuration parameters are at: Configuration: INFRA - NGINX


Local Software Repository

Pigsty creates a local software repository during installation to accelerate subsequent software installation.

This repository is served by Nginx, located by default at /www/pigsty, accessible via http://i.pigsty/pigsty.

Pigsty’s offline package is the entire software repository directory (yum/apt) compressed. When Pigsty tries to build a local repo, if it finds the local repo directory /www/pigsty already exists with the /www/pigsty/repo_complete marker file, it considers the local repo already built and skips downloading software from upstream, eliminating internet dependency.

The repo definition file is at /www/pigsty.repo, accessible by default via http://${admin_ip}/pigsty.repo

curl -L http://i.pigsty/pigsty.repo -o /etc/yum.repos.d/pigsty.repo

You can also use the file local repo directly without Nginx:

[pigsty-local]
name=Pigsty local $releasever - $basearch
baseurl=file:///www/pigsty/
enabled=1
gpgcheck=0

Local repository configuration parameters are at: Configuration: INFRA - REPO


Victoria Observability Suite

Pigsty v4.0 uses the VictoriaMetrics family to replace Prometheus/Loki, providing unified monitoring, logging, and tracing capabilities:

  • VictoriaMetrics listens on port 8428 by default, accessible via http://p.pigsty or https://i.pigsty/vmetrics/ for VMUI, compatible with Prometheus API.
  • VMAlert evaluates alert rules in /infra/rules/*.yml, listens on port 8880, and sends alert events to Alertmanager.
  • VictoriaLogs listens on port 9428, supports the https://i.pigsty/vlogs/ query interface. All nodes run Vector by default, pushing structured system logs, PostgreSQL logs, etc. to VictoriaLogs.
  • VictoriaTraces listens on port 10428 for slow SQL / Trace collection, Grafana accesses it as a Jaeger datasource.
  • Alertmanager listens on port 9059, accessible via http://a.pigsty or https://i.pigsty/alertmgr/ for managing alert notifications. After configuring SMTP, Webhook, etc., it can push messages.
  • Blackbox Exporter listens on port 9115 by default for Ping/TCP/HTTP probing, accessible via https://i.pigsty/blackbox/.

For more information, see: Configuration: INFRA - VICTORIA and Configuration: INFRA - PROMETHEUS.


Grafana

Grafana is the core of Pigsty’s WebUI, listening on port 3000 by default, accessible directly via IP:3000 or domain http://g.pigsty.

Pigsty comes with preconfigured datasources for VictoriaMetrics / Logs / Traces (vmetrics-*, vlogs-*, vtraces-*), and numerous dashboards with URL-based navigation for quick problem location.

Grafana can also be used as a general low-code visualization platform, so Pigsty installs plugins like ECharts and victoriametrics-datasource by default for building monitoring dashboards or inspection reports.

Grafana configuration parameters are at: Configuration: INFRA - GRAFANA.


Ansible

Pigsty installs Ansible on the meta node by default. Ansible is a popular operations tool with declarative configuration style and idempotent playbook design that greatly reduces system maintenance complexity.


DNSMASQ

DNSMASQ provides DNS resolution services within the environment. Domain names from other modules are registered with the DNSMASQ service on INFRA nodes.

DNS records are placed by default in the /etc/hosts.d/ directory on all INFRA nodes.

DNSMASQ configuration parameters are at: Configuration: INFRA - DNS


Chronyd

NTP service synchronizes time across all nodes in the environment (optional)

NTP configuration parameters are at: Configuration: NODES - NTP


Configuration

To install the INFRA module on a node, first add it to the infra group in the config inventory and assign an instance number infra_seq

# Configure single INFRA node
infra: { hosts: { 10.10.10.10: { infra_seq: 1 } }}

# Configure two INFRA nodes
infra:
  hosts:
    10.10.10.10: { infra_seq: 1 }
    10.10.10.11: { infra_seq: 2 }

Then use the infra.yml playbook to initialize the INFRA module on the nodes.


Administration

Here are some administration tasks related to the INFRA module:


Install/Uninstall Infra Module

./infra.yml     # Install INFRA module on infra group
./infra-rm.yml  # Uninstall INFRA module from infra group

Manage Local Software Repository

You can use the following playbook subtasks to manage the local yum repo on Infra nodes:

./infra.yml -t repo              # Create local repo from internet or offline package

./infra.yml -t repo_dir          # Create local repo directory
./infra.yml -t repo_check        # Check if local repo already exists
./infra.yml -t repo_prepare      # If exists, use existing local repo
./infra.yml -t repo_build        # If not exists, build local repo from upstream
./infra.yml     -t repo_upstream     # Handle upstream repo files in /etc/yum.repos.d
./infra.yml     -t repo_remove       # If repo_remove == true, delete existing repo files
./infra.yml     -t repo_add          # Add upstream repo files to /etc/yum.repos.d (or /etc/apt/sources.list.d)
./infra.yml     -t repo_url_pkg      # Download packages from internet defined by repo_url_packages
./infra.yml     -t repo_cache        # Create upstream repo metadata cache with yum makecache / apt update
./infra.yml     -t repo_boot_pkg     # Install bootstrap packages like createrepo_c, yum-utils... (or dpkg-)
./infra.yml     -t repo_pkg          # Download packages & dependencies from upstream repos
./infra.yml     -t repo_create       # Create local repo with createrepo_c & modifyrepo_c
./infra.yml     -t repo_use          # Add newly built repo to /etc/yum.repos.d | /etc/apt/sources.list.d
./infra.yml -t repo_nginx        # If no nginx serving, start nginx as web server

The most commonly used commands are:

./infra.yml     -t repo_upstream     # Add upstream repos defined in repo_upstream to INFRA nodes
./infra.yml     -t repo_pkg          # Download packages and dependencies from upstream repos
./infra.yml     -t repo_create       # Create/update local yum repo with createrepo_c & modifyrepo_c

Manage Infrastructure Components

You can use the following playbook subtasks to manage various infrastructure components on Infra nodes:

./infra.yml -t infra           # Configure infrastructure
./infra.yml -t infra_env       # Configure environment variables on admin node: env_dir, env_pg, env_var
./infra.yml -t infra_pkg       # Install software packages required by INFRA: infra_pkg_yum, infra_pkg_pip
./infra.yml -t infra_user      # Setup infra OS user group
./infra.yml -t infra_cert      # Issue certificates for infra components
./infra.yml -t dns             # Configure DNSMasq: dns_config, dns_record, dns_launch
./infra.yml -t nginx           # Configure Nginx: nginx_config, nginx_cert, nginx_static, nginx_launch, nginx_exporter
./infra.yml -t victoria        # Configure VictoriaMetrics/Logs/Traces: vmetrics|vlogs|vtraces|vmalert
./infra.yml -t alertmanager    # Configure AlertManager: alertmanager_config, alertmanager_launch
./infra.yml -t blackbox        # Configure Blackbox Exporter: blackbox_launch
./infra.yml -t grafana         # Configure Grafana: grafana_clean, grafana_config, grafana_plugin, grafana_launch, grafana_provision
./infra.yml -t infra_register  # Register infra components to VictoriaMetrics / Grafana

Other commonly used tasks include:

./infra.yml -t nginx_index                        # Re-render Nginx homepage content
./infra.yml -t nginx_config,nginx_reload          # Re-render Nginx portal config, expose new upstream services
./infra.yml -t vmetrics_config,vmetrics_launch    # Regenerate VictoriaMetrics main config and restart service
./infra.yml -t vlogs_config,vlogs_launch          # Re-render VictoriaLogs config
./infra.yml -t vmetrics_clean                     # Clean VictoriaMetrics storage data directory
./infra.yml -t grafana_plugin                     # Download Grafana plugins from internet

Playbooks

Pigsty provides three playbooks related to the INFRA module:

  • infra.yml: Initialize pigsty infrastructure on infra nodes
  • infra-rm.yml: Remove infrastructure components from infra nodes
  • deploy.yml: Complete one-time Pigsty installation on all nodes

infra.yml

The INFRA module playbook infra.yml initializes pigsty infrastructure on INFRA nodes

Executing this playbook completes the following tasks

  • Configure meta node directories and environment variables
  • Download and build a local software repository to accelerate subsequent installation. (If using offline package, skip download phase)
  • Add the current meta node as a regular node under Pigsty management
  • Deploy infrastructure components including VictoriaMetrics/Logs/Traces, VMAlert, Grafana, Alertmanager, Blackbox Exporter, etc.

This playbook executes on INFRA nodes by default

  • Pigsty uses the current node executing this playbook as Pigsty’s INFRA node and ADMIN node by default.
  • During configuration, Pigsty marks the current node as Infra/Admin node and replaces the placeholder IP 10.10.10.10 in config templates with the current node’s primary IP address.
  • Besides initiating management and hosting infrastructure, this node is no different from a regular managed node.
  • In single-node installation, ETCD is also installed on this node to provide DCS service

Notes about this playbook

  • This is an idempotent playbook; repeated execution will wipe infrastructure components on meta nodes.
  • To preserve historical monitoring data, first set vmetrics_clean, vlogs_clean, vtraces_clean to false.
  • When offline repo /www/pigsty/repo_complete exists, this playbook skips downloading software from internet. Full execution takes about 5-8 minutes depending on machine configuration.
  • Downloading directly from upstream internet sources without offline package may take 10-20 minutes depending on your network conditions.

asciicast


infra-rm.yml

The INFRA module playbook infra-rm.yml removes pigsty infrastructure from INFRA nodes

Common subtasks include:

./infra-rm.yml               # Remove INFRA module
./infra-rm.yml -t service    # Stop infrastructure services on INFRA
./infra-rm.yml -t data       # Remove remaining data on INFRA
./infra-rm.yml -t package    # Uninstall software packages installed on INFRA

deploy.yml

The INFRA module playbook deploy.yml performs a complete one-time Pigsty installation on all nodes

This playbook is described in more detail in Playbook: One-Time Installation.


Monitoring

Pigsty Home: Pigsty monitoring system homepage

Pigsty Home Dashboard

pigsty.jpg

INFRA Overview: Pigsty infrastructure self-monitoring overview

INFRA Overview Dashboard

infra-overview.jpg

Nginx Instance: Nginx metrics and logs

Nginx Overview Dashboard

nginx-overview.jpg

Grafana Instance: Grafana metrics and logs

Grafana Overview Dashboard

grafana-overview.jpg

VictoriaMetrics Instance: VictoriaMetrics scraping, querying, and storage metrics

VMAlert Instance: Alert rule evaluation and queue status

Alertmanager Instance: Alert aggregation, notification pipelines, and Silences

VictoriaLogs Instance: Log ingestion rate, query load, and index hits

VictoriaTraces Instance: Trace/KV storage and Jaeger interface

Logs Instance: Node log search based on Vector + VictoriaLogs

Logs Instance Dashboard

logs-instance.jpg

CMDB Overview: CMDB visualization

CMDB Overview Dashboard

cmdb-overview.jpg

ETCD Overview: etcd metrics and logs

ETCD Overview Dashboard

etcd-overview.jpg


Parameters

The INFRA module has the following 10 parameter groups.

  • META: Pigsty metadata
  • CA: Self-signed PKI/CA infrastructure
  • INFRA_ID: Infrastructure portal, Nginx domains
  • REPO: Local software repository
  • INFRA_PACKAGE: Infrastructure software packages
  • NGINX: Nginx web server
  • DNS: DNSMASQ domain server
  • VICTORIA: VictoriaMetrics / Logs / Traces suite
  • PROMETHEUS: Alertmanager and Blackbox Exporter
  • GRAFANA: Grafana observability suite
Parameter Overview

For the latest default values, types, and hierarchy, please refer to the Parameter Reference to stay consistent with the Pigsty version.

11.1 - Architecture

INFRA module architecture, functional components, and responsibilities in Pigsty.

Architecture Overview

Standard Pigsty deployment includes an INFRA module that provides services for managed nodes and database clusters:

  • Nginx: Web server providing local repo services; reverse proxy consolidates Grafana, VMUI, Alertmanager web UI access.
  • Grafana: Visualization platform for monitoring metrics, logs, and tracing—hosts monitoring dashboards, inspection reports, and custom data apps.
  • VictoriaMetrics Suite: Unified observability platform.
    • VictoriaMetrics: Scrapes all monitoring metrics, Prometheus API-compatible, provides query interface via VMUI.
    • VMAlert: Evaluates alert rules, pushes events to Alertmanager.
    • VictoriaLogs: Centralized log collection and storage. All nodes run Vector by default, pushing system and database logs here.
    • VictoriaTraces: Collects slow SQL, service traces, and other trace data.
    • AlertManager: Aggregates alert events, dispatches notifications (email, Webhook, etc.).
    • BlackboxExporter: Probes IP/VIP/URL reachability via ICMP/TCP/HTTP.
  • DNSMASQ: Provides DNS resolution for internal domain names.
  • Chronyd: NTP time sync service ensuring consistent time across all nodes.
  • PostgreSQL: CMDB and default database.
  • Ansible: Runs playbooks, orchestrates all infrastructure.

pigsty-arch

INFRA module is optional for PG HA. For example, Slim Install mode doesn’t install INFRA.

However, INFRA provides supporting services needed for prod-grade HA PG clusters, strongly recommended for full Pigsty DBaaS experience.

If you have existing infra (Nginx, local repo, monitoring, DNS, NTP), you can disable INFRA module and configure Pigsty to use existing infrastructure instead.


Nginx

Nginx = Pigsty web UI entry point—HTTP/HTTPS on ports 80/443 by default.

Web UIs with infrastructure components exposed via Nginx: Grafana, VictoriaMetrics (VMUI), AlertManager, and HAProxy traffic console. Local yum/apt repo static files also served via Nginx.

Nginx routes based on infra_portal configuration—domain-based proxy to upstream components. Customize for other or public domains:

infra_portal:  # domain names and upstream servers
  home         : { domain: i.pigsty }
  grafana      : { domain: g.pigsty ,endpoint: "${admin_ip}:3000" , websocket: true }
  prometheus   : { domain: p.pigsty ,endpoint: "${admin_ip}:8428" }   # VMUI
  alertmanager : { domain: a.pigsty ,endpoint: "${admin_ip}:9059" }
  blackbox     : { endpoint: "${admin_ip}:9115" }
  vmalert      : { endpoint: "${admin_ip}:8880" }
  #logs         : { domain: logs.pigsty ,endpoint: "${admin_ip}:9428" }
  #minio        : { domain: sss.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
  #pgadmin      : { domain: adm.pigsty ,endpoint: "127.0.0.1:8885" }
  #pgweb        : { domain: cli.pigsty ,endpoint: "127.0.0.1:8886" }
  #bytebase     : { domain: ddl.pigsty ,endpoint: "127.0.0.1:8887" }
  #jupyter      : { domain: lab.pigsty ,endpoint: "127.0.0.1:8888"   ,websocket: true }
  #gitea        : { domain: git.pigsty ,endpoint: "127.0.0.1:8889" }
  #wiki         : { domain: wiki.pigsty ,endpoint: "127.0.0.1:9002" }
  #noco         : { domain: noco.pigsty ,endpoint: "127.0.0.1:9003" }
  #supa         : { domain: supa.pigsty ,endpoint: "10.2.82.163:8000" ,websocket: true }
  #odoo         : { domain: odoo.pigsty ,endpoint: "127.0.0.1:8069"   ,websocket: true }
  #mm           : { domain: mm.pigsty ,endpoint: "10.2.82.163:8065" ,websocket: true }
  web.io:
    domain: en.pigsty
    path: "/www/web.io"
    certbot: pigsty.doc
    enforce_https: true
    config: |
      # rewrite /zh/ to /
      location /zh/ {
                rewrite ^/zh/(.*)$ /$1 permanent;
      }
  web.cc:
    domain: pigsty.cc
    path: "/www/web.cc"
    domains: [ zh.pigsty.cc ]
    certbot: pigsty.doc
    config: |
      # rewrite /zh/ to /
      location /zh/ {
                rewrite ^/zh/(.*)$ /$1 permanent;
      }
  repo:
    domain: pro.pigsty
    path: "/www/repo"
    index: true
    certbot: pigsty.doc

Pigsty strongly recommends domain access over IP+port:

  • Enables HTTPS encryption, consolidates to Nginx, audits all requests, integrates auth.
  • Some components only listen on 127.0.0.1—only accessible via Nginx proxy.
  • Domains easier to remember, extra flexibility.

If no internet domain or local DNS resolution, add local static records in /etc/hosts (MacOS/Linux) or C:\Windows\System32\drivers\etc\hosts (Windows).

Nginx config: Configuration: INFRA - NGINX.


Local Software Repository

Pigsty creates local repo during install on INFRA nodes to accelerate subsequent software installation.

Repo served by Nginx, default location /www/pigsty, accessible via http://i.pigsty/pigsty.

Pigsty’s offline package = entire built repo directory (yum/apt) compressed. When building local repo, if /www/pigsty exists with /www/pigsty/repo_complete marker, considers repo already built—skips upstream downloads, eliminating internet dependency.

Repo definition file: /www/pigsty.repo, accessible via http://${admin_ip}/pigsty.repo.

curl -L http://i.pigsty/pigsty.repo -o /etc/yum.repos.d/pigsty.repo

Or use file local repo without Nginx:

[pigsty-local]
name=Pigsty local $releasever - $basearch
baseurl=file:///www/pigsty/
enabled=1
gpgcheck=0

Local repo config: Configuration: INFRA - REPO.


Victoria Observability Suite

Pigsty v4.0 uses VictoriaMetrics family—unified monitoring, logging, tracing:

  • VictoriaMetrics: Default port 8428, accessible via http://p.pigsty or https://i.pigsty/vmetrics/, Prometheus API-compatible.
  • VMAlert: Evaluates alert rules in /infra/rules/*.yml, port 8880, sends events to Alertmanager.
  • VictoriaLogs: Default port 9428, supports log search via https://i.pigsty/vlogs/. All nodes run Vector by default, pushing structured system logs, PG logs here.
  • VictoriaTraces: Port 10428 for slow SQL / Trace collection. Grafana accesses as Jaeger datasource.
  • AlertManager: Port 9059, accessible via http://a.pigsty or https://i.pigsty/alertmgr/ for managing alert notifications. Configure SMTP, Webhook, etc. to push messages.
  • Blackbox Exporter: Default port 9115 for Ping/TCP/HTTP probing, accessible via https://i.pigsty/blackbox/.

More: Configuration: INFRA - VICTORIA and Configuration: INFRA - PROMETHEUS.


Grafana

Grafana = Pigsty web UI core, default port 3000, accessible via IP:3000 or domain http://g.pigsty.

Pigsty includes preconfigured datasources for VictoriaMetrics / Logs / Traces (vmetrics-*, vlogs-*, vtraces-*), plus numerous dashboards with URL navigation for quick problem location.

Grafana = low-code visualization platform. Pigsty installs plugins (ECharts, victoriametrics-datasource) by default for building monitoring dashboards/inspection reports.

Grafana config: Configuration: INFRA - GRAFANA.


Ansible

Pigsty installs Ansible on meta node by default. Ansible = popular ops tool with declarative config style and idempotent playbook design—reduces system maintenance complexity.


DNSMASQ

DNSMASQ provides DNS resolution for internal Pigsty domain names. Other modules’ domain names register with DNSMASQ service on INFRA nodes.

DNS records: default location /etc/hosts.d/ on all INFRA nodes.

DNSMASQ config: Configuration: INFRA - DNS.


Chronyd

NTP service syncs time across all nodes in environment (optional).

NTP config: Configuration: NODE - NTP.

ComponentPortDefault DomainDescription
Nginx80/443i.pigstyWeb portal, local repo, unified entry
Grafana3000g.pigstyVisualization platform, monitoring dashboards
VictoriaMetrics8428p.pigstyTSDB, VMUI, Prometheus-compatible
VictoriaLogs9428-Centralized log DB, Vector pushes logs
VictoriaTraces10428-Tracing / slow SQL, Jaeger interface
VMAlert8880-Alert rule evaluator
AlertManager9059a.pigstyAlert aggregation, notifications
BlackboxExporter9115-ICMP/TCP/HTTP probes
DNSMASQ53-DNS server
Chronyd123-NTP time server

11.2 - Configuration

How to configure INFRA nodes? Customize Nginx, local repo, DNS, NTP, monitoring components.

Configuration Guide

INFRA = primarily monitoring infrastructure, optional for PostgreSQL databases.

Unless manually configured to depend on DNS/NTP services on INFRA nodes, INFRA module failures typically don’t affect PG cluster operations.

Single INFRA node suffices for most scenarios. Prod env recommends 2-3 INFRA nodes for HA.

For better resource utilization, ETCD module (required by PG HA) can share nodes with INFRA module.

Using more than 3 INFRA nodes provides little additional benefit, but more ETCD nodes (e.g., 5) can improve DCS availability.


Configuration Examples

Add node IPs to infra group in config inventory, assign INFRA instance number infra_seq.

Default single INFRA node config:

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } }}

By default, 10.10.10.10 placeholder replaced with current node’s primary IP during config.

Use infra.yml playbook to init INFRA module on nodes.

More Nodes

Two INFRA nodes config:

all:
  children:
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
        10.10.10.11: { infra_seq: 2 }

Three INFRA nodes config (with params):

all:
  children:
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
        10.10.10.11: { infra_seq: 2, repo_enabled: false }
        10.10.10.12: { infra_seq: 3, repo_enabled: false }
      vars:
        grafana_clean: false
        vmetrics_clean: false
        vlogs_clean: false
        vtraces_clean: false

INFRA High Availability

Most INFRA module components = “stateless/identical state”. For HA, focus on “load balancing”.

HA achievable via Keepalived L2 VIP or HAProxy L4 load balancing. L2 VIP recommended for L2-reachable networks.

Config example:

infra:
  hosts:
    10.10.10.10: { infra_seq: 1 }
    10.10.10.11: { infra_seq: 2 }
    10.10.10.12: { infra_seq: 3 }
  vars:
    vip_enabled: true
    vip_vrid: 128
    vip_address: 10.10.10.8
    vip_interface: eth1

    infra_portal:
      home         : { domain: i.pigsty }
      grafana      : { domain: g.pigsty ,endpoint: "10.10.10.8:3000" , websocket: true }
      prometheus   : { domain: p.pigsty ,endpoint: "10.10.10.8:8428" }
      alertmanager : { domain: a.pigsty ,endpoint: "10.10.10.8:9059" }
      blackbox     : { endpoint: "10.10.10.8:9115" }
      vmalert      : { endpoint: "10.10.10.8:8880" }

Set VIP-related params and modify service endpoints in infra_portal.


Nginx Configuration

See Nginx Parameter Config and Tutorial: Nginx.


Local Repo Configuration

See Repo Parameter Config.


DNS Configuration

See DNS Parameter Config and Tutorial: DNS.


NTP Configuration

See NTP Parameter Config.

11.3 - Parameters

INFRA module provides 10 sections with 70+ configurable parameters

The INFRA module is responsible for deploying Pigsty’s infrastructure components: local software repository, Nginx, DNSMasq, VictoriaMetrics, VictoriaLogs, Grafana, Alertmanager, Blackbox Exporter, and other monitoring and alerting infrastructure.

Pigsty v4.0 uses VictoriaMetrics to replace Prometheus and VictoriaLogs to replace Loki, providing a superior observability solution.

SectionDescription
METAPigsty metadata: version, admin IP, region, language, proxy
CASelf-signed CA certificate management
INFRA_IDInfrastructure node identity and service portal
REPOLocal software repository configuration
INFRA_PACKAGEInfrastructure node package installation
NGINXNginx web server and reverse proxy configuration
DNSDNSMasq DNS server configuration
VICTORIAVictoriaMetrics/Logs/Traces observability stack
PROMETHEUSAlertmanager and Blackbox Exporter
GRAFANAGrafana visualization platform configuration

Parameter Overview

META parameters define Pigsty metadata, including version string, admin node IP, repository mirror region, default language, and proxy settings.

ParameterTypeLevelDescription
versionstringGPigsty version string
admin_ipipGAdmin node IP address
regionenumGUpstream mirror region: default,china,europe
languageenumGDefault language: en or zh
proxy_envdictGGlobal proxy environment variables

CA parameters configure Pigsty’s self-signed CA certificate management, including CA creation, CA name, and certificate validity.

ParameterTypeLevelDescription
ca_createboolGCreate CA if not exists? Default true
ca_cnstringGCA CN name, fixed as pigsty-ca
cert_validityintervalGCertificate validity, default 20 years

INFRA_ID parameters define infrastructure node identity, including node sequence number, service portal configuration, and data directory.

ParameterTypeLevelDescription
infra_seqintIInfrastructure node sequence, REQUIRED
infra_portaldictGInfrastructure services exposed via Nginx portal
infra_datapathGInfrastructure data directory, default /data/infra

REPO parameters configure the local software repository, including repository enable switch, directory paths, upstream source definitions, and packages to download.

ParameterTypeLevelDescription
repo_enabledboolG/ICreate local repo on this infra node?
repo_homepathGRepo home directory, default /www
repo_namestringGRepo name, default pigsty
repo_endpointurlGRepo access endpoint: domain or ip:port
repo_removeboolG/ARemove existing upstream repo definitions?
repo_modulesstringG/AEnabled upstream repo modules, comma separated
repo_upstreamupstream[]GUpstream repo definitions
repo_packagesstring[]GPackages to download from upstream
repo_extra_packagesstring[]G/C/IExtra packages to download
repo_url_packagesstring[]GExtra packages downloaded via URL

INFRA_PACKAGE parameters define packages to install on infrastructure nodes, including RPM/DEB packages and PIP packages.

ParameterTypeLevelDescription
infra_packagesstring[]GPackages to install on infra nodes
infra_packages_pipstringGPip packages to install on infra nodes

NGINX parameters configure Nginx web server and reverse proxy, including enable switch, ports, SSL mode, certificates, and basic authentication.

ParameterTypeLevelDescription
nginx_enabledboolG/IEnable Nginx on this infra node?
nginx_cleanboolG/AClean existing Nginx config during init?
nginx_exporter_enabledboolG/IEnable nginx_exporter on this infra node?
nginx_exporter_portportGnginx_exporter listen port, default 9113
nginx_sslmodeenumGNginx SSL mode: disable,enable,enforce
nginx_cert_validitydurationGNginx self-signed cert validity, default 397d
nginx_homepathGNginx content dir, default /www, symlink to nginx_data
nginx_datapathGNginx actual data dir, default /data/nginx
nginx_usersdictGNginx basic auth users: username-password dict
nginx_portportGNginx listen port, default 80
nginx_ssl_portportGNginx SSL listen port, default 443
certbot_signboolG/ASign cert with certbot?
certbot_emailstringG/ACertbot notification email address
certbot_optionsstringG/ACertbot extra command line options

DNS parameters configure DNSMasq DNS server, including enable switch, listen port, and dynamic DNS records.

ParameterTypeLevelDescription
dns_enabledboolG/ISetup dnsmasq on this infra node?
dns_portportGDNS server listen port, default 53
dns_recordsstring[]GDynamic DNS records resolved by dnsmasq

VICTORIA parameters configure the VictoriaMetrics/Logs/Traces observability stack, including enable switches, ports, and data retention policies.

ParameterTypeLevelDescription
vmetrics_enabledboolG/IEnable VictoriaMetrics on this infra node?
vmetrics_cleanboolG/AClean VictoriaMetrics data during init?
vmetrics_portportGVictoriaMetrics listen port, default 8428
vmetrics_scrape_intervalintervalGGlobal scrape interval, default 10s
vmetrics_scrape_timeoutintervalGGlobal scrape timeout, default 8s
vmetrics_optionsargGVictoriaMetrics extra CLI options
vlogs_enabledboolG/IEnable VictoriaLogs on this infra node?
vlogs_cleanboolG/AClean VictoriaLogs data during init?
vlogs_portportGVictoriaLogs listen port, default 9428
vlogs_optionsargGVictoriaLogs extra CLI options
vtraces_enabledboolG/IEnable VictoriaTraces on this infra node?
vtraces_cleanboolG/AClean VictoriaTraces data during init?
vtraces_portportGVictoriaTraces listen port, default 10428
vtraces_optionsargGVictoriaTraces extra CLI options
vmalert_enabledboolG/IEnable VMAlert on this infra node?
vmalert_portportGVMAlert listen port, default 8880
vmalert_optionsargGVMAlert extra CLI options

PROMETHEUS parameters configure Alertmanager and Blackbox Exporter, providing alert management and network probing capabilities.

ParameterTypeLevelDescription
blackbox_enabledboolG/ISetup blackbox_exporter on this infra node?
blackbox_portportGblackbox_exporter listen port, default 9115
blackbox_optionsargGblackbox_exporter extra CLI options
alertmanager_enabledboolG/ISetup alertmanager on this infra node?
alertmanager_portportGAlertManager listen port, default 9059
alertmanager_optionsargGalertmanager extra CLI options
exporter_metrics_pathpathGExporter metrics path, default /metrics

GRAFANA parameters configure the Grafana visualization platform, including enable switch, port, admin credentials, and data source configuration.

ParameterTypeLevelDescription
grafana_enabledboolG/IEnable Grafana on this infra node?
grafana_portportGGrafana listen port, default 3000
grafana_cleanboolG/AClean Grafana data during init?
grafana_admin_usernameusernameGGrafana admin username, default admin
grafana_admin_passwordpasswordGGrafana admin password, default pigsty
grafana_auth_proxyboolGEnable Grafana auth proxy?
grafana_pgurlurlGExternal PostgreSQL URL for Grafana persistence
grafana_view_passwordpasswordGGrafana metadb PG datasource password

META

This section defines Pigsty deployment metadata: version string, admin node IP address, repository mirror region, default language, and HTTP(S) proxy for downloading packages.

version: v4.0.0                   # pigsty version string
admin_ip: 10.10.10.10             # admin node ip address
region: default                   # upstream mirror region: default,china,europe
language: en                      # default language: en or zh
proxy_env:                        # global proxy env when downloading packages
  no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
  # http_proxy:  # set your proxy here: e.g http://user:[email protected]
  # https_proxy: # set your proxy here: e.g http://user:[email protected]
  # all_proxy:   # set your proxy here: e.g http://user:[email protected]

version

name: version, type: string, level: G

Pigsty version string, default value is the current version: v4.0.0.

Pigsty uses this version string internally for feature control and content rendering. Do not modify this parameter arbitrarily.

Pigsty uses semantic versioning, and the version string typically starts with the character v, e.g., v4.0.0.

admin_ip

name: admin_ip, type: ip, level: G

Admin node IP address, default is the placeholder IP address: 10.10.10.10

The node specified by this parameter will be treated as the admin node, typically pointing to the first node where Pigsty is installed, i.e., the control node.

The default value 10.10.10.10 is a placeholder that will be replaced with the actual admin node IP address during configure.

Many parameters reference this parameter, such as:

In these parameters, the string ${admin_ip} will be replaced with the actual value of admin_ip. Using this mechanism, you can specify different admin nodes for different nodes.

region

name: region, type: enum, level: G

Upstream mirror region, available options: default, china, europe, default is default

If a region other than default is set, and there’s a corresponding entry in repo_upstream with a matching baseurl, it will be used instead of the default baseurl.

For example, if your region is set to china, Pigsty will attempt to use Chinese mirror sites to accelerate downloads. If an upstream repository doesn’t have a corresponding China region mirror, the default upstream mirror site will be used instead. Additionally, URLs defined in repo_url_packages will be replaced from repo.pigsty.io to repo.pigsty.cc to use domestic mirrors.

language

name: language, type: enum, level: G

Default language setting, options are en (English) or zh (Chinese), default is en.

This parameter affects the language preference of some Pigsty-generated configurations and content, such as the initial language setting of Grafana dashboards.

If you are a Chinese user, it is recommended to set this parameter to zh for a better Chinese support experience.

proxy_env

name: proxy_env, type: dict, level: G

Global proxy environment variables used when downloading packages, default value specifies no_proxy, which is the list of addresses that should not use a proxy:

proxy_env:
  no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.aliyuncs.com,mirrors.tuna.tsinghua.edu.cn,mirrors.zju.edu.cn"
  #http_proxy: 'http://username:[email protected]'
  #https_proxy: 'http://username:[email protected]'
  #all_proxy: 'http://username:[email protected]'

When installing from the Internet in mainland China, certain packages may be blocked. You can use a proxy to solve this problem.

Note that if the Docker module is used, the proxy server configuration here will also be written to the Docker Daemon configuration file.

Note that if the -x parameter is specified during ./configure, the proxy configuration information in the current environment will be automatically filled into the generated pigsty.yaml file.


CA

Pigsty uses self-signed CA certificates to support advanced security features such as HTTPS access, PostgreSQL SSL connections, etc.

ca_create: true                   # create CA if not exists? default true
ca_cn: pigsty-ca                  # CA CN name, fixed as pigsty-ca
cert_validity: 7300d              # certificate validity, default 20 years

ca_create

name: ca_create, type: bool, level: G

Create CA if not exists? Default value is true.

When set to true, if the CA public-private key pair does not exist in the files/pki/ca directory, Pigsty will automatically create a new CA.

If you already have a CA public-private key pair, you can copy them to the files/pki/ca directory:

  • files/pki/ca/ca.crt: CA public key certificate
  • files/pki/ca/ca.key: CA private key file

Pigsty will use the existing CA key pair instead of creating a new one. If the CA does not exist and this parameter is set to false, an error will occur.

Be sure to retain and backup the newly generated CA private key file during deployment, as it is crucial for issuing new certificates later.

Note: Pigsty v3.x used the ca_method parameter (with values create/recreate/copy), v4.0 simplifies this to the boolean ca_create.

ca_cn

name: ca_cn, type: string, level: G

CA CN (Common Name), fixed as pigsty-ca, not recommended to modify.

You can use the following command to view the Pigsty CA certificate details on a node:

openssl x509 -text -in /etc/pki/ca.crt

cert_validity

name: cert_validity, type: interval, level: G

Certificate validity period for issued certificates, default is 20 years, sufficient for most scenarios. Default value: 7300d

This parameter affects the validity of all certificates issued by the Pigsty CA, including:

  • PostgreSQL server certificates
  • Patroni API certificates
  • etcd server/client certificates
  • Other internal service certificates

Note: The validity of HTTPS certificates used by Nginx is controlled separately by nginx_cert_validity, because modern browsers have stricter requirements for website certificate validity (maximum 397 days).


INFRA_ID

Infrastructure identity and portal definition.

#infra_seq: 1                     # infra node sequence, REQUIRED identity parameter
infra_portal:                     # infrastructure services exposed via Nginx portal
  home : { domain: i.pigsty }     # default home server definition
infra_data: /data/infra           # infrastructure default data directory

infra_seq

name: infra_seq, type: int, level: I

Infrastructure node sequence number, REQUIRED identity parameter that must be explicitly specified on infrastructure nodes, so no default value is provided.

This parameter is used to uniquely identify each node in multi-infrastructure node deployments, typically using positive integers starting from 1.

Example configuration:

infra:
  hosts:
    10.10.10.10: { infra_seq: 1 }
    10.10.10.11: { infra_seq: 2 }

infra_portal

name: infra_portal, type: dict, level: G

Infrastructure services exposed via Nginx portal. The v4.0 default value is very concise:

infra_portal:
  home : { domain: i.pigsty }     # default home server definition

Pigsty will automatically configure the corresponding reverse proxies based on the actually enabled components. Users typically only need to define the home domain name.

Each record consists of a Key and a Value dictionary, where name is the key representing the component name, and the value is an object that can configure the following parameters:

  • name: REQUIRED, specifies the name of the Nginx server
    • Default record: home is a fixed name, please do not modify it.
    • Used as part of the Nginx configuration file name, corresponding to: /etc/nginx/conf.d/<name>.conf
    • Nginx servers without a domain field will not generate configuration files but will be used as references.
  • domain: OPTIONAL, when the service needs to be exposed via Nginx, this is a REQUIRED field specifying the domain name to use
    • In Pigsty self-signed Nginx HTTPS certificates, the domain will be added to the SAN field of the Nginx SSL certificate
    • Pigsty web page cross-references will use the default domain name here
  • endpoint: Usually used as an alternative to path, specifies the upstream server address. Setting endpoint indicates this is a reverse proxy server
    • ${admin_ip} can be used as a placeholder in the configuration and will be dynamically replaced with admin_ip during deployment
    • Default reverse proxy servers use endpoint.conf as the configuration template
    • Reverse proxy servers can also configure websocket and schema parameters
  • path: Usually used as an alternative to endpoint, specifies the local file server path. Setting path indicates this is a local web server
    • Local web servers use path.conf as the configuration template
    • Local web servers can also configure the index parameter to enable file index pages
  • certbot: Certbot certificate name; if configured, Certbot will be used to apply for certificates
    • If multiple servers specify the same certbot, Pigsty will merge certificate applications; the final certificate name will be this certbot value
  • cert: Certificate file path; if configured, will override the default certificate path
  • key: Certificate key file path; if configured, will override the default certificate key path
  • websocket: Whether to enable WebSocket support
    • Only reverse proxy servers can configure this parameter; if enabled, upstream WebSocket connections will be allowed
  • schema: Protocol used by the upstream server; if configured, will override the default protocol
    • Default is http; if configured as https, it will force HTTPS connections to the upstream server
  • index: Whether to enable file index pages
    • Only local web servers can configure this parameter; if enabled, autoindex configuration will be enabled to automatically generate directory index pages
  • log: Nginx log file path
    • If specified, access logs will be written to this file; otherwise, the default log file will be used based on server type
    • Reverse proxy servers use /var/log/nginx/<name>.log as the default log file path
    • Local web servers use the default Access log
  • conf: Nginx configuration file path
    • Explicitly specifies the configuration template file to use, located in roles/infra/templates/nginx or templates/nginx directory
    • If this parameter is not specified, the default configuration template will be used
  • config: Nginx configuration code block
    • Configuration text directly injected into the Nginx Server configuration block
  • enforce_https: Redirect HTTP to HTTPS
    • Global configuration can be specified via nginx_sslmode: enforce
    • This configuration does not affect the default home server, which will always listen on both ports 80 and 443 to ensure compatibility

infra_data

name: infra_data, type: path, level: G

Infrastructure data directory, default value is /data/infra.

This directory is used to store data files for infrastructure components, including:

  • VictoriaMetrics time series database data
  • VictoriaLogs log data
  • VictoriaTraces trace data
  • Other infrastructure component persistent data

It is recommended to place this directory on a separate data disk for easier management and expansion.


REPO

This section is about local software repository configuration. Pigsty enables a local software repository (APT/YUM) on infrastructure nodes by default.

During initialization, Pigsty downloads all packages and their dependencies (specified by repo_packages) from the Internet upstream repository (specified by repo_upstream) to {{ nginx_home }} / {{ repo_name }} (default /www/pigsty). The total size of all software and dependencies is approximately 1GB.

When creating the local repository, if it already exists (determined by the presence of a marker file named repo_complete in the repository directory), Pigsty will consider the repository already built, skip the software download phase, and directly use the built repository.

If some packages download too slowly, you can set a download proxy using the proxy_env configuration to complete the initial download, or directly download the pre-packaged offline package, which is essentially a local software repository built on the same operating system.

repo_enabled: true                # create local repo on this infra node?
repo_home: /www                   # repo home directory, default /www
repo_name: pigsty                 # repo name, default pigsty
repo_endpoint: http://${admin_ip}:80 # repo access endpoint
repo_remove: true                 # remove existing upstream repo definitions
repo_modules: infra,node,pgsql    # enabled upstream repo modules
#repo_upstream: []                # upstream repo definitions (inherited from OS variables)
#repo_packages: []                # packages to download (inherited from OS variables)
#repo_extra_packages: []          # extra packages to download
repo_url_packages: []             # extra packages downloaded via URL

repo_enabled

name: repo_enabled, type: bool, level: G/I

Create a local software repository on this infrastructure node? Default is true, meaning all Infra nodes will set up a local software repository.

If you have multiple infrastructure nodes, you can keep only 1-2 nodes as software repositories; other nodes can set this parameter to false to avoid duplicate software download builds.

repo_home

name: repo_home, type: path, level: G

Local software repository home directory, defaults to Nginx’s root directory: /www.

This directory is actually a symlink pointing to nginx_data. It’s not recommended to modify this directory. If modified, it should be consistent with nginx_home.

repo_name

name: repo_name, type: string, level: G

Local repository name, default is pigsty. Changing this repository name is not recommended.

The final repository path is {{ repo_home }}/{{ repo_name }}, defaulting to /www/pigsty.

repo_endpoint

name: repo_endpoint, type: url, level: G

Endpoint used by other nodes to access this repository, default value: http://${admin_ip}:80.

Pigsty starts Nginx on infrastructure nodes at ports 80/443 by default, providing local software repository (static files) service.

If you modify nginx_port or nginx_ssl_port, or use a different infrastructure node from the control node, adjust this parameter accordingly.

If you use a domain name, you can add resolution in node_default_etc_hosts, node_etc_hosts, or dns_records.

repo_remove

name: repo_remove, type: bool, level: G/A

Remove existing upstream repository definitions when building the local repository? Default value: true.

When this parameter is enabled, all existing repository files in /etc/yum.repos.d will be moved and backed up to /etc/yum.repos.d/backup. On Debian systems, /etc/apt/sources.list and /etc/apt/sources.list.d are removed and backed up to /etc/apt/backup.

Since existing OS sources have uncontrollable content, using Pigsty-validated upstream software sources can improve the success rate and speed of downloading packages from the Internet.

In certain situations (e.g., your OS is some EL/Deb compatible variant that uses private sources for many packages), you may need to keep existing upstream repository definitions. In such cases, set this parameter to false.

repo_modules

name: repo_modules, type: string, level: G/A

Which upstream repository modules will be added to the local software source, default value: infra,node,pgsql

When Pigsty attempts to add upstream repositories, it filters entries in repo_upstream based on this parameter’s value. Only entries whose module field matches this parameter’s value will be added to the local software source.

Modules are comma-separated. Available module lists can be found in the repo_upstream definitions; common modules include:

  • local: Local Pigsty repository
  • infra: Infrastructure packages (Nginx, Docker, etc.)
  • node: OS base packages
  • pgsql: PostgreSQL-related packages
  • extra: Extra PostgreSQL extensions
  • docker: Docker-related
  • redis: Redis-related
  • mongo: MongoDB-related
  • mysql: MySQL-related
  • etc…

repo_upstream

name: repo_upstream, type: upstream[], level: G

Where to download upstream packages when building the local repository? This parameter has no default value. If not explicitly specified by the user in the configuration file, it will be loaded from the repo_upstream_default variable defined in roles/node_id/vars based on the current node’s OS family.

Pigsty provides complete upstream repository definitions for different OS versions (EL8/9/10, Debian 11/12/13, Ubuntu 22/24), including:

  • OS base repositories (BaseOS, AppStream, EPEL, etc.)
  • PostgreSQL official PGDG repository
  • Pigsty extension repository
  • Various third-party software repositories (Docker, Nginx, Grafana, etc.)

Each upstream repository definition contains the following fields:

- name: pigsty-pgsql              # repository name
  description: 'Pigsty PGSQL'     # repository description
  module: pgsql                   # module it belongs to
  releases: [8,9,10]              # supported OS versions
  arch: [x86_64, aarch64]         # supported CPU architectures
  baseurl:                        # repository URL, configured by region
    default: 'https://repo.pigsty.io/yum/pgsql/el$releasever.$basearch'
    china: 'https://repo.pigsty.cc/yum/pgsql/el$releasever.$basearch'

Users typically don’t need to modify this parameter unless they have special repository requirements. For detailed repository definitions, refer to the configuration files for corresponding operating systems in the roles/node_id/vars/ directory.

repo_packages

name: repo_packages, type: string[], level: G

String array type, where each line is a space-separated list of software packages, specifying packages (and their dependencies) to download using repotrack or apt download.

This parameter has no default value, meaning its default state is undefined. If not explicitly defined, Pigsty will load the default from the repo_packages_default variable defined in roles/node_id/vars:

[ node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-utility, extra-modules ]

Each element in this parameter will be translated according to the package_map in the above files, based on the specific OS distro major version. For example, on EL systems it translates to:

node-bootstrap:          "ansible python3 python3-pip python3-virtualenv python3-requests python3-jmespath python3-cryptography dnf-utils modulemd-tools createrepo_c sshpass"
infra-package:           "nginx dnsmasq etcd haproxy vip-manager node_exporter keepalived_exporter pg_exporter pgbackrest_exporter redis_exporter redis minio mcli pig"
infra-addons:            "grafana grafana-plugins grafana-victoriametrics-ds grafana-victorialogs-ds victoria-metrics victoria-logs victoria-traces vlogscli vmutils vector alertmanager"

As a convention, repo_packages typically includes packages unrelated to the PostgreSQL major version (such as Infra, Node, and PGDG Common parts), while PostgreSQL major version-related packages (kernel, extensions) are usually specified in repo_extra_packages to facilitate switching PG major versions.

repo_extra_packages

name: repo_extra_packages, type: string[], level: G/C/I

Used to specify additional packages to download without modifying repo_packages (typically PG major version-related packages), default value is an empty list.

If not explicitly defined, Pigsty will load the default from the repo_extra_packages_default variable defined in roles/node_id/vars:

[ pgsql-main ]

Elements in this parameter undergo package name translation, where $v will be replaced with pg_version, i.e., the current PG major version (default 18).

The pgsql-main here translates on EL systems to:

postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit pg_repack_$v* wal2json_$v* pgvector_$v*

Users can typically specify PostgreSQL major version-related packages here without affecting the other PG version-independent packages defined in repo_packages.

repo_url_packages

name: repo_url_packages, type: object[] | string[], level: G

Packages downloaded directly from the Internet using URLs, default is an empty array: []

You can use URL strings directly as array elements in this parameter, or use object structures to explicitly specify URLs and filenames.

Note that this parameter is affected by the region variable. If you’re in mainland China, Pigsty will automatically replace URLs, changing repo.pigsty.io to repo.pigsty.cc.


INFRA_PACKAGE

These packages are installed only on INFRA nodes, including regular RPM/DEB packages and PIP packages.

infra_packages

name: infra_packages, type: string[], level: G

String array type, where each line is a space-separated list of software packages, specifying packages to install on Infra nodes.

This parameter has no default value, meaning its default state is undefined. If not explicitly specified by the user in the configuration file, Pigsty will load the default from the infra_packages_default variable defined in roles/node_id/vars based on the current node’s OS family.

v4.0 default value (EL operating systems):

infra_packages_default:
  - grafana,grafana-plugins,grafana-victorialogs-ds,grafana-victoriametrics-ds,victoria-metrics,victoria-logs,victoria-traces,vmutils,vlogscli,alertmanager
  - node_exporter,blackbox_exporter,nginx_exporter,pg_exporter,pev2,nginx,dnsmasq,ansible,etcd,python3-requests,redis,mcli,restic,certbot,python3-certbot-nginx

Default value (Debian/Ubuntu):

infra_packages_default:
  - grafana,grafana-plugins,grafana-victorialogs-ds,grafana-victoriametrics-ds,victoria-metrics,victoria-logs,victoria-traces,vmutils,vlogscli,alertmanager
  - node-exporter,blackbox-exporter,nginx-exporter,pg-exporter,pev2,nginx,dnsmasq,ansible,etcd,python3-requests,redis,mcli,restic,certbot,python3-certbot-nginx

Note: v4.0 uses the VictoriaMetrics suite to replace Prometheus and Loki, so the package list differs significantly from v3.x.

infra_packages_pip

name: infra_packages_pip, type: string, level: G

Additional packages to install using pip on Infra nodes, package names separated by commas. Default value is an empty string, meaning no additional python packages are installed.

Example:

infra_packages_pip: 'requests,boto3,awscli'

NGINX

Pigsty proxies all web service access through Nginx: Home Page, Grafana, VictoriaMetrics, etc., as well as other optional tools like PGWeb, Jupyter Lab, Pgadmin, Bytebase, and static resources and reports like pev, schemaspy, and pgbadger.

Most importantly, Nginx also serves as the web server for the local software repository (Yum/Apt), used to store and distribute Pigsty packages.

nginx_enabled: true               # enable Nginx on this infra node?
nginx_clean: false                # clean existing Nginx config during init?
nginx_exporter_enabled: true      # enable nginx_exporter?
nginx_exporter_port: 9113         # nginx_exporter listen port
nginx_sslmode: enable             # SSL mode: disable,enable,enforce
nginx_cert_validity: 397d         # self-signed cert validity
nginx_home: /www                  # Nginx content directory (symlink)
nginx_data: /data/nginx           # Nginx actual data directory
nginx_users: {}                   # basic auth users dictionary
nginx_port: 80                    # HTTP port
nginx_ssl_port: 443               # HTTPS port
certbot_sign: false               # sign cert with certbot?
certbot_email: [email protected]     # certbot email
certbot_options: ''               # certbot extra options

nginx_enabled

name: nginx_enabled, type: bool, level: G/I

Enable Nginx on this Infra node? Default value: true.

Nginx is a core component of Pigsty infrastructure, responsible for:

  • Providing local software repository service
  • Reverse proxying Grafana, VictoriaMetrics, and other web services
  • Hosting static files and reports

nginx_clean

name: nginx_clean, type: bool, level: G/A

Clean existing Nginx configuration during initialization? Default value: false.

When set to true, all existing configuration files under /etc/nginx/conf.d/ will be deleted during Nginx initialization, ensuring a clean start.

If you’re deploying for the first time or want to completely rebuild Nginx configuration, you can set this parameter to true.

nginx_exporter_enabled

name: nginx_exporter_enabled, type: bool, level: G/I

Enable nginx_exporter on this infrastructure node? Default value: true.

If this option is disabled, the /nginx health check stub will also be disabled. Consider disabling this when your Nginx version doesn’t support this feature.

nginx_exporter_port

name: nginx_exporter_port, type: port, level: G

nginx_exporter listen port, default value is 9113.

nginx_exporter is used to collect Nginx operational metrics for VictoriaMetrics to scrape and monitor.

nginx_sslmode

name: nginx_sslmode, type: enum, level: G

Nginx SSL operating mode. Three options: disable, enable, enforce, default value is enable, meaning SSL is enabled but not enforced.

  • disable: Only listen on the port specified by nginx_port to serve HTTP requests.
  • enable: Also listen on the port specified by nginx_ssl_port to serve HTTPS requests.
  • enforce: All links will be rendered to use https:// by default
    • Also redirect port 80 to port 443 for non-default servers in infra_portal

nginx_cert_validity

name: nginx_cert_validity, type: duration, level: G

Nginx self-signed certificate validity, default value is 397d (approximately 13 months).

Modern browsers require website certificate validity to be at most 397 days, hence this default value. Setting a longer validity is not recommended, as browsers may refuse to trust such certificates.

nginx_home

name: nginx_home, type: path, level: G

Nginx server static content directory, default: /www

This is a symlink that actually points to the nginx_data directory. This directory contains static resources and software repository files.

It’s best not to modify this parameter arbitrarily. If modified, it should be consistent with the repo_home parameter.

nginx_data

name: nginx_data, type: path, level: G

Nginx actual data directory, default is /data/nginx.

This is the actual storage location for Nginx static files; nginx_home is a symlink pointing to this directory.

It’s recommended to place this directory on a data disk for easier management of large package files.

nginx_users

name: nginx_users, type: dict, level: G

Nginx Basic Authentication user dictionary, default is an empty dictionary {}.

Format is { username: password } key-value pairs, for example:

nginx_users:
  admin: pigsty
  viewer: readonly

These users can be used to protect certain Nginx endpoints that require authentication.

nginx_port

name: nginx_port, type: port, level: G

Nginx default listening port (serving HTTP), default is port 80. It’s best not to modify this parameter.

When your server’s port 80 is occupied, you can consider using another port, but you need to also modify repo_endpoint and keep node_repo_local_urls consistent with the port used here.

nginx_ssl_port

name: nginx_ssl_port, type: port, level: G

Nginx SSL default listening port, default is 443. It’s best not to modify this parameter.

certbot_sign

name: certbot_sign, type: bool, level: G/A

Use certbot to sign Nginx certificates during installation? Default value is false.

When set to true, Pigsty will use certbot to automatically apply for free SSL certificates from Let’s Encrypt during the execution of infra.yml and install.yml playbooks (in the nginx role).

For domains defined in infra_portal, if a certbot parameter is defined, Pigsty will use certbot to apply for a certificate for that domain. The certificate name will be the value of the certbot parameter. If multiple servers/domains specify the same certbot parameter, Pigsty will merge and apply for certificates for these domains, using the certbot parameter value as the certificate name.

Enabling this option requires:

  • The current node can be accessed through a public domain name, and DNS resolution is correctly pointed to the current node’s public IP
  • The current node can access the Let’s Encrypt API interface

This option is disabled by default. You can manually execute the make cert command after installation, which actually calls the rendered /etc/nginx/sign-cert script to update or apply for certificates using certbot.

certbot_email

name: certbot_email, type: string, level: G/A

Email address for receiving certificate expiration reminder emails, default value is [email protected].

When certbot_sign is set to true, it’s recommended to provide this parameter. Let’s Encrypt will send reminder emails to this address when certificates are about to expire.

certbot_options

name: certbot_options, type: string, level: G/A

Additional configuration parameters passed to certbot, default value is an empty string.

You can pass additional command-line options to certbot through this parameter, for example --dry-run, which makes certbot perform a preview and test without actually applying for certificates.


DNS

Pigsty enables DNSMASQ service on Infra nodes by default to resolve auxiliary domain names such as i.pigsty, m.pigsty, api.pigsty, etc., and optionally sss.pigsty for MinIO.

Resolution records are stored in the /etc/hosts.d/default file on Infra nodes. To use this DNS server, you must add nameserver <ip> to /etc/resolv.conf. The node_dns_servers parameter handles this.

dns_enabled: true                 # setup dnsmasq on this infra node?
dns_port: 53                      # DNS server listen port
dns_records:                      # dynamic DNS records
  - "${admin_ip} i.pigsty"
  - "${admin_ip} m.pigsty supa.pigsty api.pigsty adm.pigsty cli.pigsty ddl.pigsty"

dns_enabled

name: dns_enabled, type: bool, level: G/I

Enable DNSMASQ service on this Infra node? Default value: true.

If you don’t want to use the default DNS server (e.g., you already have an external DNS server, or your provider doesn’t allow you to use a DNS server), you can set this value to false to disable it, and use node_default_etc_hosts and node_etc_hosts static resolution records instead.

dns_port

name: dns_port, type: port, level: G

DNSMASQ default listening port, default is 53. It’s not recommended to modify the default DNS service port.

dns_records

name: dns_records, type: string[], level: G

Dynamic DNS records resolved by dnsmasq, generally used to resolve auxiliary domain names to the admin node. These records are written to the /etc/hosts.d/default file on infrastructure nodes.

v4.0 default value:

dns_records:
  - "${admin_ip} i.pigsty"
  - "${admin_ip} m.pigsty supa.pigsty api.pigsty adm.pigsty cli.pigsty ddl.pigsty"

The ${admin_ip} placeholder is used here and will be replaced with the actual admin_ip value during deployment.

Common domain name purposes:

  • i.pigsty: Pigsty home page
  • m.pigsty: VictoriaMetrics Web UI
  • api.pigsty: API service
  • adm.pigsty: Admin service
  • Others customized based on actual deployment needs

VICTORIA

Pigsty v4.0 uses the VictoriaMetrics suite to replace Prometheus and Loki, providing a superior observability solution:

  • VictoriaMetrics: Replaces Prometheus as the time series database for storing monitoring metrics
  • VictoriaLogs: Replaces Loki as the log aggregation storage
  • VictoriaTraces: Distributed trace storage
  • VMAlert: Replaces Prometheus Alerting for alert rule evaluation
vmetrics_enabled: true            # enable VictoriaMetrics?
vmetrics_clean: false             # clean data during init?
vmetrics_port: 8428               # listen port
vmetrics_scrape_interval: 10s     # global scrape interval
vmetrics_scrape_timeout: 8s       # global scrape timeout
vmetrics_options: >-
  -retentionPeriod=15d
  -promscrape.fileSDCheckInterval=5s
vlogs_enabled: true               # enable VictoriaLogs?
vlogs_clean: false                # clean data during init?
vlogs_port: 9428                  # listen port
vlogs_options: >-
  -retentionPeriod=15d
  -retention.maxDiskSpaceUsageBytes=50GiB
  -insert.maxLineSizeBytes=1MB
  -search.maxQueryDuration=120s
vtraces_enabled: true             # enable VictoriaTraces?
vtraces_clean: false              # clean data during init?
vtraces_port: 10428               # listen port
vtraces_options: >-
  -retentionPeriod=15d
  -retention.maxDiskSpaceUsageBytes=50GiB
vmalert_enabled: true             # enable VMAlert?
vmalert_port: 8880                # listen port
vmalert_options: ''               # extra CLI options

vmetrics_enabled

name: vmetrics_enabled, type: bool, level: G/I

Enable VictoriaMetrics on this Infra node? Default value is true.

VictoriaMetrics is the core monitoring component in Pigsty v4.0, replacing Prometheus as the time series database, responsible for:

  • Scraping monitoring metrics from various exporters
  • Storing time series data
  • Providing PromQL-compatible query interface
  • Supporting Grafana data sources

vmetrics_clean

name: vmetrics_clean, type: bool, level: G/A

Clean existing VictoriaMetrics data during initialization? Default value is false.

When set to true, existing time series data will be deleted during initialization. Use this option carefully unless you’re sure you want to rebuild monitoring data.

vmetrics_port

name: vmetrics_port, type: port, level: G

VictoriaMetrics listen port, default value is 8428.

This port is used for:

  • HTTP API access
  • Web UI access
  • Prometheus-compatible remote write/read
  • Grafana data source connections

vmetrics_scrape_interval

name: vmetrics_scrape_interval, type: interval, level: G

VictoriaMetrics global metrics scrape interval, default value is 10s.

In production environments, 10-30 seconds is a suitable scrape interval. If you need finer monitoring data granularity, you can adjust this parameter, but it will increase storage and CPU overhead.

vmetrics_scrape_timeout

name: vmetrics_scrape_timeout, type: interval, level: G

VictoriaMetrics global scrape timeout, default is 8s.

Setting a scrape timeout can effectively prevent avalanches caused by monitoring system queries. The principle is that this parameter must be less than and close to vmetrics_scrape_interval to ensure each scrape duration doesn’t exceed the scrape interval.

vmetrics_options

name: vmetrics_options, type: arg, level: G

VictoriaMetrics extra command line options, default value:

vmetrics_options: >-
  -retentionPeriod=15d
  -promscrape.fileSDCheckInterval=5s

Common parameter descriptions:

  • -retentionPeriod=15d: Data retention period, default 15 days
  • -promscrape.fileSDCheckInterval=5s: File service discovery refresh interval

You can add other VictoriaMetrics-supported parameters as needed.

vlogs_enabled

name: vlogs_enabled, type: bool, level: G/I

Enable VictoriaLogs on this Infra node? Default value is true.

VictoriaLogs replaces Loki as the log aggregation storage, responsible for:

  • Receiving log data from Vector
  • Storing and indexing logs
  • Providing log query interface
  • Supporting Grafana VictoriaLogs data source

vlogs_clean

name: vlogs_clean, type: bool, level: G/A

Clean existing VictoriaLogs data during initialization? Default value is false.

vlogs_port

name: vlogs_port, type: port, level: G

VictoriaLogs listen port, default value is 9428.

vlogs_options

name: vlogs_options, type: arg, level: G

VictoriaLogs extra command line options, default value:

vlogs_options: >-
  -retentionPeriod=15d
  -retention.maxDiskSpaceUsageBytes=50GiB
  -insert.maxLineSizeBytes=1MB
  -search.maxQueryDuration=120s

Common parameter descriptions:

  • -retentionPeriod=15d: Log retention period, default 15 days
  • -retention.maxDiskSpaceUsageBytes=50GiB: Maximum disk usage
  • -insert.maxLineSizeBytes=1MB: Maximum single log line size
  • -search.maxQueryDuration=120s: Maximum query execution time

vtraces_enabled

name: vtraces_enabled, type: bool, level: G/I

Enable VictoriaTraces on this Infra node? Default value is true.

VictoriaTraces is used for distributed trace data storage and query, supporting Jaeger, Zipkin, and other trace protocols.

vtraces_clean

name: vtraces_clean, type: bool, level: G/A

Clean existing VictoriaTraces data during initialization? Default value is false.

vtraces_port

name: vtraces_port, type: port, level: G

VictoriaTraces listen port, default value is 10428.

vtraces_options

name: vtraces_options, type: arg, level: G

VictoriaTraces extra command line options, default value:

vtraces_options: >-
  -retentionPeriod=15d
  -retention.maxDiskSpaceUsageBytes=50GiB

vmalert_enabled

name: vmalert_enabled, type: bool, level: G/I

Enable VMAlert on this Infra node? Default value is true.

VMAlert is responsible for alert rule evaluation, replacing Prometheus Alerting functionality, working with Alertmanager.

vmalert_port

name: vmalert_port, type: port, level: G

VMAlert listen port, default value is 8880.

vmalert_options

name: vmalert_options, type: arg, level: G

VMAlert extra command line options, default value is an empty string.


PROMETHEUS

This section now primarily contains Blackbox Exporter and Alertmanager configuration.

Note: Pigsty v4.0 uses VictoriaMetrics to replace Prometheus. The original prometheus_* and pushgateway_* parameters have been moved to the VICTORIA section.

blackbox_enabled: true            # enable blackbox_exporter?
blackbox_port: 9115               # blackbox_exporter listen port
blackbox_options: ''              # extra CLI options
alertmanager_enabled: true        # enable alertmanager?
alertmanager_port: 9059           # alertmanager listen port
alertmanager_options: ''          # extra CLI options
exporter_metrics_path: /metrics   # exporter metrics path

blackbox_enabled

name: blackbox_enabled, type: bool, level: G/I

Enable BlackboxExporter on this Infra node? Default value is true.

BlackboxExporter sends ICMP packets to node IP addresses, VIP addresses, and PostgreSQL VIP addresses to test network connectivity. It can also perform HTTP, TCP, DNS, and other probes.

blackbox_port

name: blackbox_port, type: port, level: G

Blackbox Exporter listen port, default value is 9115.

blackbox_options

name: blackbox_options, type: arg, level: G

BlackboxExporter extra command line options, default value: empty string.

alertmanager_enabled

name: alertmanager_enabled, type: bool, level: G/I

Enable AlertManager on this Infra node? Default value is true.

AlertManager is responsible for receiving alert notifications from VMAlert and performing alert grouping, inhibition, silencing, routing, and other processing.

alertmanager_port

name: alertmanager_port, type: port, level: G

AlertManager listen port, default value is 9059.

If you modify this port, ensure you update the alertmanager entry’s endpoint configuration in infra_portal accordingly (if defined).

alertmanager_options

name: alertmanager_options, type: arg, level: G

AlertManager extra command line options, default value: empty string.

exporter_metrics_path

name: exporter_metrics_path, type: path, level: G

HTTP endpoint path where monitoring exporters expose metrics, default: /metrics. Not recommended to modify this parameter.

This parameter defines the standard path for all exporters to expose monitoring metrics.


GRAFANA

Pigsty uses Grafana as the monitoring system frontend. It can also serve as a data analysis and visualization platform, or for low-code data application development and data application prototyping.

grafana_enabled: true             # enable Grafana?
grafana_port: 3000                # Grafana listen port
grafana_clean: false              # clean data during init?
grafana_admin_username: admin     # admin username
grafana_admin_password: pigsty    # admin password
grafana_auth_proxy: false         # enable auth proxy?
grafana_pgurl: ''                 # external PostgreSQL URL
grafana_view_password: DBUser.Viewer  # PG datasource password

grafana_enabled

name: grafana_enabled, type: bool, level: G/I

Enable Grafana on Infra node? Default value: true, meaning all infrastructure nodes will install and enable Grafana by default.

grafana_port

name: grafana_port, type: port, level: G

Grafana listen port, default value is 3000.

If you need to access Grafana directly (not through Nginx reverse proxy), you can use this port.

grafana_clean

name: grafana_clean, type: bool, level: G/A

Clean Grafana data files during initialization? Default: false.

This operation removes /var/lib/grafana/grafana.db, ensuring a fresh Grafana installation.

If you want to preserve existing Grafana configuration (such as dashboards, users, data sources, etc.), set this parameter to false.

grafana_admin_username

name: grafana_admin_username, type: username, level: G

Grafana admin username, default is admin.

grafana_admin_password

name: grafana_admin_password, type: password, level: G

Grafana admin password, default is pigsty.

IMPORTANT: Be sure to change this password parameter before deploying to production!

grafana_auth_proxy

name: grafana_auth_proxy, type: bool, level: G

Enable Grafana auth proxy? Default is false.

When enabled, Grafana will trust user identity information passed by the reverse proxy (Nginx), enabling single sign-on (SSO) functionality.

This is typically used for integration with external identity authentication systems.

grafana_pgurl

name: grafana_pgurl, type: url, level: G

External PostgreSQL database URL for Grafana persistence storage. Default is an empty string.

If specified, Grafana will use this PostgreSQL database instead of the default SQLite database to store its configuration data.

Format example: postgres://grafana:password@pg-meta:5432/grafana?sslmode=disable

This is useful for scenarios requiring Grafana high availability deployment or data persistence.

grafana_view_password

name: grafana_view_password, type: password, level: G

Read-only user password used by Grafana metadb PG data source, default is DBUser.Viewer.

This password is used for Grafana to connect to the PostgreSQL CMDB data source to query metadata in read-only mode.

11.4 - Playbook

How to use built-in Ansible playbooks to manage the INFRA module, with a quick reference for common commands.

Pigsty provides four playbooks related to the INFRA module:

  • deploy.yml: Deploy all components on all nodes in one pass
  • infra.yml: Initialize Pigsty infrastructure on infra nodes
  • infra-rm.yml: Remove infrastructure components from infra nodes
  • install.yml: Perform a complete one-time installation of Pigsty on all nodes

deploy.yml

Deploy all components on all nodes in one pass, resolving INFRA/NODE circular dependency issues.

This playbook interleaves subtasks from infra.yml and node.yml, completing deployment of all components in the following order:

  1. id: Generate node and PostgreSQL identities
  2. ca: Create self-signed CA on localhost
  3. repo: Create local software repository on infra nodes
  4. node-init: Initialize nodes, HAProxy, and Docker
  5. infra: Initialize Nginx, DNS, VictoriaMetrics, Grafana, etc.
  6. node-monitor: Initialize node-exporter, vector
  7. etcd: Initialize etcd (required for PostgreSQL HA)
  8. minio: Initialize MinIO (optional)
  9. pgsql: Initialize PostgreSQL clusters
  10. pgsql-monitor: Initialize PostgreSQL monitoring

This playbook is equivalent to executing the following four playbooks sequentially:

./infra.yml -l infra    # Deploy infrastructure on infra group
./node.yml              # Initialize all nodes
./etcd.yml              # Initialize etcd cluster
./pgsql.yml             # Initialize PostgreSQL clusters

infra.yml

Initialize the infrastructure module on Infra nodes defined in the infra group of your configuration file.

This playbook performs the following tasks:

  • Configures directories and environment variables on Infra nodes
  • Downloads and creates a local software repository to accelerate subsequent installations
  • Incorporates the current Infra node as a common node managed by Pigsty
  • Deploys infrastructure components (VictoriaMetrics/Logs/Traces, VMAlert, Grafana, Alertmanager, Blackbox Exporter, etc.)

Playbook notes:

  • This is an idempotent playbook - repeated execution will overwrite infrastructure components on Infra nodes
  • To preserve historical monitoring data, set vmetrics_clean, vlogs_clean, vtraces_clean to false beforehand
  • Unless grafana_clean is set to false, Grafana dashboards and configuration changes will be lost
  • When the local software repository /www/pigsty/repo_complete exists, this playbook skips downloading software from the internet
  • Complete execution takes approximately 1-3 minutes, depending on machine configuration and network conditions

Available Tasks

# ca: create self-signed CA on localhost files/pki
#   - ca_dir        : create CA directory
#   - ca_private    : generate ca private key: files/pki/ca/ca.key
#   - ca_cert       : signing ca cert: files/pki/ca/ca.crt
#
# id: generate node identity
#
# repo: bootstrap a local yum repo from internet or offline packages
#   - repo_dir      : create repo directory
#   - repo_check    : check repo exists
#   - repo_prepare  : use existing repo if exists
#   - repo_build    : build repo from upstream if not exists
#     - repo_upstream    : handle upstream repo files in /etc/yum.repos.d
#       - repo_remove    : remove existing repo file if repo_remove == true
#       - repo_add       : add upstream repo files to /etc/yum.repos.d
#     - repo_url_pkg     : download packages from internet defined by repo_url_packages
#     - repo_cache       : make upstream yum cache with yum makecache
#     - repo_boot_pkg    : install bootstrap pkg such as createrepo_c,yum-utils,...
#     - repo_pkg         : download packages & dependencies from upstream repo
#     - repo_create      : create a local yum repo with createrepo_c & modifyrepo_c
#     - repo_use         : add newly built repo into /etc/yum.repos.d
#   - repo_nginx    : launch a nginx for repo if no nginx is serving
#
# node/haproxy/docker/monitor: setup infra node as a common node
#   - node_name, node_hosts, node_resolv, node_firewall, node_ca, node_repo, node_pkg
#   - node_feature, node_kernel, node_tune, node_sysctl, node_profile, node_ulimit
#   - node_data, node_admin, node_timezone, node_ntp, node_crontab, node_vip
#   - haproxy_install, haproxy_config, haproxy_launch, haproxy_reload
#   - docker_install, docker_admin, docker_config, docker_launch, docker_image
#   - haproxy_register, node_exporter, node_register, vector
#
# infra: setup infra components
#   - infra_env      : env_dir, env_pg, env_pgadmin, env_var
#   - infra_pkg      : infra_pkg_yum, infra_pkg_pip
#   - infra_user     : setup infra os user group
#   - infra_cert     : issue cert for infra components
#   - dns            : dns_config, dns_record, dns_launch
#   - nginx          : nginx_config, nginx_cert, nginx_static, nginx_launch, nginx_certbot, nginx_reload, nginx_exporter
#   - victoria       : vmetrics_config, vmetrics_launch, vlogs_config, vlogs_launch, vtraces_config, vtraces_launch, vmalert_config, vmalert_launch
#   - alertmanager   : alertmanager_config, alertmanager_launch
#   - blackbox       : blackbox_config, blackbox_launch
#   - grafana        : grafana_clean, grafana_config, grafana_launch, grafana_provision
#   - infra_register : register infra components to victoria

infra-rm.yml

Remove Pigsty infrastructure from Infra nodes defined in the infra group of your configuration file.

Common subtasks include:

./infra-rm.yml               # Remove the INFRA module
./infra-rm.yml -t service    # Stop infrastructure services on INFRA
./infra-rm.yml -t data       # Remove retained data on INFRA
./infra-rm.yml -t package    # Uninstall packages installed on INFRA

install.yml

Perform a complete one-time installation of Pigsty on all nodes.

This playbook is described in more detail in Playbook: One-Pass Installation.

11.5 - Monitoring

How to perform self-monitoring of infrastructure in Pigsty?

This document describes monitoring dashboards and alert rules for the INFRA module in Pigsty.


Dashboards

Pigsty provides the following monitoring dashboards for the Infra module:

DashboardDescription
Pigsty HomePigsty monitoring system homepage
INFRA OverviewPigsty infrastructure self-monitoring overview
Nginx InstanceNginx metrics and logs
Grafana InstanceGrafana metrics and logs
VictoriaMetrics InstanceVictoriaMetrics scraping/query status
VMAlert InstanceAlert rule execution status
Alertmanager InstanceAlert aggregation and notifications
VictoriaLogs InstanceLog ingestion, querying, and indexing
Logs InstanceView log information on a single node
VictoriaTraces InstanceTrace storage and querying
Inventory CMDBCMDB visualization
ETCD Overviewetcd cluster monitoring

Alert Rules

Pigsty provides the following two alert rules for the INFRA module:

Alert RuleDescription
InfraDownInfrastructure component is down
AgentDownMonitoring agent is down

You can modify or add new infrastructure alert rules in files/victoria/rules/infra.yml.

Alert Rule Configuration

################################################################
#                Infrastructure Alert Rules                    #
################################################################
- name: infra-alert
  rules:

    #==============================================================#
    #                       Infra Aliveness                        #
    #==============================================================#
    # infra components (victoria,grafana) down for 1m triggers a P1 alert
    - alert: InfraDown
      expr: infra_up < 1
      for: 1m
      labels: { level: 0, severity: CRIT, category: infra }
      annotations:
        summary: "CRIT InfraDown {{ $labels.type }}@{{ $labels.instance }}"
        description: |
          infra_up[type={{ $labels.type }}, instance={{ $labels.instance }}] = {{ $value  | printf "%.2f" }} < 1

    #==============================================================#
    #                       Agent Aliveness                        #
    #==============================================================#

    # agent aliveness are determined directly by exporter aliveness
    # including: node_exporter, pg_exporter, pgbouncer_exporter, haproxy_exporter
    - alert: AgentDown
      expr: agent_up < 1
      for: 1m
      labels: { level: 0, severity: CRIT, category: infra }
      annotations:
        summary: 'CRIT AgentDown {{ $labels.ins }}@{{ $labels.instance }}'
        description: |
          agent_up[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value  | printf "%.2f" }} < 1

11.6 - Metrics

Complete list of monitoring metrics provided by the Pigsty INFRA module

Note: Pigsty v4.0 has replaced Prometheus/Loki with VictoriaMetrics/Logs/Traces. The following metric list is still based on v3.x generation, for reference when troubleshooting older versions only. To get the latest metrics, query directly in https://p.pigsty (VMUI) or Grafana. Future versions will regenerate metric reference sheets consistent with the Victoria suite.

INFRA Metrics

The INFRA module has 964 available metrics.

Metric NameTypeLabelsDescription
alertmanager_alertsgaugeins, instance, ip, job, cls, stateHow many alerts by state.
alertmanager_alerts_invalid_totalcounterversion, ins, instance, ip, job, clsThe total number of received alerts that were invalid.
alertmanager_alerts_received_totalcounterversion, ins, instance, ip, status, job, clsThe total number of received alerts.
alertmanager_build_infogaugerevision, version, ins, instance, ip, tags, goarch, goversion, job, cls, branch, goosA metric with a constant ‘1’ value labeled by version, revision, branch, goversion from which alertmanager was built, and the goos and goarch for the build.
alertmanager_cluster_alive_messages_totalcounterins, instance, ip, peer, job, clsTotal number of received alive messages.
alertmanager_cluster_enabledgaugeins, instance, ip, job, clsIndicates whether the clustering is enabled or not.
alertmanager_cluster_failed_peersgaugeins, instance, ip, job, clsNumber indicating the current number of failed peers in the cluster.
alertmanager_cluster_health_scoregaugeins, instance, ip, job, clsHealth score of the cluster. Lower values are better and zero means ’totally healthy’.
alertmanager_cluster_membersgaugeins, instance, ip, job, clsNumber indicating current number of members in cluster.
alertmanager_cluster_messages_pruned_totalcounterins, instance, ip, job, clsTotal number of cluster messages pruned.
alertmanager_cluster_messages_queuedgaugeins, instance, ip, job, clsNumber of cluster messages which are queued.
alertmanager_cluster_messages_received_size_totalcounterins, instance, ip, msg_type, job, clsTotal size of cluster messages received.
alertmanager_cluster_messages_received_totalcounterins, instance, ip, msg_type, job, clsTotal number of cluster messages received.
alertmanager_cluster_messages_sent_size_totalcounterins, instance, ip, msg_type, job, clsTotal size of cluster messages sent.
alertmanager_cluster_messages_sent_totalcounterins, instance, ip, msg_type, job, clsTotal number of cluster messages sent.
alertmanager_cluster_peer_infogaugeins, instance, ip, peer, job, clsA metric with a constant ‘1’ value labeled by peer name.
alertmanager_cluster_peers_joined_totalcounterins, instance, ip, job, clsA counter of the number of peers that have joined.
alertmanager_cluster_peers_left_totalcounterins, instance, ip, job, clsA counter of the number of peers that have left.
alertmanager_cluster_peers_update_totalcounterins, instance, ip, job, clsA counter of the number of peers that have updated metadata.
alertmanager_cluster_reconnections_failed_totalcounterins, instance, ip, job, clsA counter of the number of failed cluster peer reconnection attempts.
alertmanager_cluster_reconnections_totalcounterins, instance, ip, job, clsA counter of the number of cluster peer reconnections.
alertmanager_cluster_refresh_join_failed_totalcounterins, instance, ip, job, clsA counter of the number of failed cluster peer joined attempts via refresh.
alertmanager_cluster_refresh_join_totalcounterins, instance, ip, job, clsA counter of the number of cluster peer joined via refresh.
alertmanager_config_hashgaugeins, instance, ip, job, clsHash of the currently loaded alertmanager configuration.
alertmanager_config_last_reload_success_timestamp_secondsgaugeins, instance, ip, job, clsTimestamp of the last successful configuration reload.
alertmanager_config_last_reload_successfulgaugeins, instance, ip, job, clsWhether the last configuration reload attempt was successful.
alertmanager_dispatcher_aggregation_groupsgaugeins, instance, ip, job, clsNumber of active aggregation groups
alertmanager_dispatcher_alert_processing_duration_seconds_countUnknownins, instance, ip, job, clsN/A
alertmanager_dispatcher_alert_processing_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
alertmanager_http_concurrency_limit_exceeded_totalcounterins, instance, method, ip, job, clsTotal number of times an HTTP request failed because the concurrency limit was reached.
alertmanager_http_request_duration_seconds_bucketUnknownins, instance, method, ip, le, job, cls, handlerN/A
alertmanager_http_request_duration_seconds_countUnknownins, instance, method, ip, job, cls, handlerN/A
alertmanager_http_request_duration_seconds_sumUnknownins, instance, method, ip, job, cls, handlerN/A
alertmanager_http_requests_in_flightgaugeins, instance, method, ip, job, clsCurrent number of HTTP requests being processed.
alertmanager_http_response_size_bytes_bucketUnknownins, instance, method, ip, le, job, cls, handlerN/A
alertmanager_http_response_size_bytes_countUnknownins, instance, method, ip, job, cls, handlerN/A
alertmanager_http_response_size_bytes_sumUnknownins, instance, method, ip, job, cls, handlerN/A
alertmanager_integrationsgaugeins, instance, ip, job, clsNumber of configured integrations.
alertmanager_marked_alertsgaugeins, instance, ip, job, cls, stateHow many alerts by state are currently marked in the Alertmanager regardless of their expiry.
alertmanager_nflog_gc_duration_seconds_countUnknownins, instance, ip, job, clsN/A
alertmanager_nflog_gc_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
alertmanager_nflog_gossip_messages_propagated_totalcounterins, instance, ip, job, clsNumber of received gossip messages that have been further gossiped.
alertmanager_nflog_maintenance_errors_totalcounterins, instance, ip, job, clsHow many maintenances were executed for the notification log that failed.
alertmanager_nflog_maintenance_totalcounterins, instance, ip, job, clsHow many maintenances were executed for the notification log.
alertmanager_nflog_queries_totalcounterins, instance, ip, job, clsNumber of notification log queries were received.
alertmanager_nflog_query_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
alertmanager_nflog_query_duration_seconds_countUnknownins, instance, ip, job, clsN/A
alertmanager_nflog_query_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
alertmanager_nflog_query_errors_totalcounterins, instance, ip, job, clsNumber notification log received queries that failed.
alertmanager_nflog_snapshot_duration_seconds_countUnknownins, instance, ip, job, clsN/A
alertmanager_nflog_snapshot_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
alertmanager_nflog_snapshot_size_bytesgaugeins, instance, ip, job, clsSize of the last notification log snapshot in bytes.
alertmanager_notification_latency_seconds_bucketUnknownintegration, ins, instance, ip, le, job, clsN/A
alertmanager_notification_latency_seconds_countUnknownintegration, ins, instance, ip, job, clsN/A
alertmanager_notification_latency_seconds_sumUnknownintegration, ins, instance, ip, job, clsN/A
alertmanager_notification_requests_failed_totalcounterintegration, ins, instance, ip, job, clsThe total number of failed notification requests.
alertmanager_notification_requests_totalcounterintegration, ins, instance, ip, job, clsThe total number of attempted notification requests.
alertmanager_notifications_failed_totalcounterintegration, ins, instance, ip, reason, job, clsThe total number of failed notifications.
alertmanager_notifications_totalcounterintegration, ins, instance, ip, job, clsThe total number of attempted notifications.
alertmanager_oversize_gossip_message_duration_seconds_bucketUnknownins, instance, ip, le, key, job, clsN/A
alertmanager_oversize_gossip_message_duration_seconds_countUnknownins, instance, ip, key, job, clsN/A
alertmanager_oversize_gossip_message_duration_seconds_sumUnknownins, instance, ip, key, job, clsN/A
alertmanager_oversized_gossip_message_dropped_totalcounterins, instance, ip, key, job, clsNumber of oversized gossip messages that were dropped due to a full message queue.
alertmanager_oversized_gossip_message_failure_totalcounterins, instance, ip, key, job, clsNumber of oversized gossip message sends that failed.
alertmanager_oversized_gossip_message_sent_totalcounterins, instance, ip, key, job, clsNumber of oversized gossip message sent.
alertmanager_peer_positiongaugeins, instance, ip, job, clsPosition the Alertmanager instance believes it’s in. The position determines a peer’s behavior in the cluster.
alertmanager_receiversgaugeins, instance, ip, job, clsNumber of configured receivers.
alertmanager_silencesgaugeins, instance, ip, job, cls, stateHow many silences by state.
alertmanager_silences_gc_duration_seconds_countUnknownins, instance, ip, job, clsN/A
alertmanager_silences_gc_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
alertmanager_silences_gossip_messages_propagated_totalcounterins, instance, ip, job, clsNumber of received gossip messages that have been further gossiped.
alertmanager_silences_maintenance_errors_totalcounterins, instance, ip, job, clsHow many maintenances were executed for silences that failed.
alertmanager_silences_maintenance_totalcounterins, instance, ip, job, clsHow many maintenances were executed for silences.
alertmanager_silences_queries_totalcounterins, instance, ip, job, clsHow many silence queries were received.
alertmanager_silences_query_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
alertmanager_silences_query_duration_seconds_countUnknownins, instance, ip, job, clsN/A
alertmanager_silences_query_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
alertmanager_silences_query_errors_totalcounterins, instance, ip, job, clsHow many silence received queries did not succeed.
alertmanager_silences_snapshot_duration_seconds_countUnknownins, instance, ip, job, clsN/A
alertmanager_silences_snapshot_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
alertmanager_silences_snapshot_size_bytesgaugeins, instance, ip, job, clsSize of the last silence snapshot in bytes.
blackbox_exporter_build_infogaugerevision, version, ins, instance, ip, tags, goarch, goversion, job, cls, branch, goosA metric with a constant ‘1’ value labeled by version, revision, branch, goversion from which blackbox_exporter was built, and the goos and goarch for the build.
blackbox_exporter_config_last_reload_success_timestamp_secondsgaugeins, instance, ip, job, clsTimestamp of the last successful configuration reload.
blackbox_exporter_config_last_reload_successfulgaugeins, instance, ip, job, clsBlackbox exporter config loaded successfully.
blackbox_module_unknown_totalcounterins, instance, ip, job, clsCount of unknown modules requested by probes
cortex_distributor_ingester_clientsgaugeins, instance, ip, job, clsThe current number of ingester clients.
cortex_dns_failures_totalUnknownins, instance, ip, job, clsN/A
cortex_dns_lookups_totalUnknownins, instance, ip, job, clsN/A
cortex_frontend_query_range_duration_seconds_bucketUnknownins, instance, method, ip, le, job, cls, status_codeN/A
cortex_frontend_query_range_duration_seconds_countUnknownins, instance, method, ip, job, cls, status_codeN/A
cortex_frontend_query_range_duration_seconds_sumUnknownins, instance, method, ip, job, cls, status_codeN/A
cortex_ingester_flush_queue_lengthgaugeins, instance, ip, job, clsThe total number of series pending in the flush queue.
cortex_kv_request_duration_seconds_bucketUnknownins, instance, role, ip, le, kv_name, type, operation, job, cls, status_codeN/A
cortex_kv_request_duration_seconds_countUnknownins, instance, role, ip, kv_name, type, operation, job, cls, status_codeN/A
cortex_kv_request_duration_seconds_sumUnknownins, instance, role, ip, kv_name, type, operation, job, cls, status_codeN/A
cortex_member_consul_heartbeats_totalUnknownins, instance, ip, job, clsN/A
cortex_prometheus_notifications_alertmanagers_discoveredgaugeins, instance, ip, user, job, clsThe number of alertmanagers discovered and active.
cortex_prometheus_notifications_dropped_totalUnknownins, instance, ip, user, job, clsN/A
cortex_prometheus_notifications_queue_capacitygaugeins, instance, ip, user, job, clsThe capacity of the alert notifications queue.
cortex_prometheus_notifications_queue_lengthgaugeins, instance, ip, user, job, clsThe number of alert notifications in the queue.
cortex_prometheus_rule_evaluation_duration_secondssummaryins, instance, ip, user, job, cls, quantileThe duration for a rule to execute.
cortex_prometheus_rule_evaluation_duration_seconds_countUnknownins, instance, ip, user, job, clsN/A
cortex_prometheus_rule_evaluation_duration_seconds_sumUnknownins, instance, ip, user, job, clsN/A
cortex_prometheus_rule_group_duration_secondssummaryins, instance, ip, user, job, cls, quantileThe duration of rule group evaluations.
cortex_prometheus_rule_group_duration_seconds_countUnknownins, instance, ip, user, job, clsN/A
cortex_prometheus_rule_group_duration_seconds_sumUnknownins, instance, ip, user, job, clsN/A
cortex_query_frontend_connected_schedulersgaugeins, instance, ip, job, clsNumber of schedulers this frontend is connected to.
cortex_query_frontend_queries_in_progressgaugeins, instance, ip, job, clsNumber of queries in progress handled by this frontend.
cortex_query_frontend_retries_bucketUnknownins, instance, ip, le, job, clsN/A
cortex_query_frontend_retries_countUnknownins, instance, ip, job, clsN/A
cortex_query_frontend_retries_sumUnknownins, instance, ip, job, clsN/A
cortex_query_scheduler_connected_frontend_clientsgaugeins, instance, ip, job, clsNumber of query-frontend worker clients currently connected to the query-scheduler.
cortex_query_scheduler_connected_querier_clientsgaugeins, instance, ip, job, clsNumber of querier worker clients currently connected to the query-scheduler.
cortex_query_scheduler_inflight_requestssummaryins, instance, ip, job, cls, quantileNumber of inflight requests (either queued or processing) sampled at a regular interval. Quantile buckets keep track of inflight requests over the last 60s.
cortex_query_scheduler_inflight_requests_countUnknownins, instance, ip, job, clsN/A
cortex_query_scheduler_inflight_requests_sumUnknownins, instance, ip, job, clsN/A
cortex_query_scheduler_queue_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
cortex_query_scheduler_queue_duration_seconds_countUnknownins, instance, ip, job, clsN/A
cortex_query_scheduler_queue_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
cortex_query_scheduler_queue_lengthUnknownins, instance, ip, user, job, clsN/A
cortex_query_scheduler_runninggaugeins, instance, ip, job, clsValue will be 1 if the scheduler is in the ReplicationSet and actively receiving/processing requests
cortex_ring_member_heartbeats_totalUnknownins, instance, ip, job, clsN/A
cortex_ring_member_tokens_ownedgaugeins, instance, ip, job, clsThe number of tokens owned in the ring.
cortex_ring_member_tokens_to_owngaugeins, instance, ip, job, clsThe number of tokens to own in the ring.
cortex_ring_membersgaugeins, instance, ip, job, cls, stateNumber of members in the ring
cortex_ring_oldest_member_timestampgaugeins, instance, ip, job, cls, stateTimestamp of the oldest member in the ring.
cortex_ring_tokens_totalgaugeins, instance, ip, job, clsNumber of tokens in the ring
cortex_ruler_clientsgaugeins, instance, ip, job, clsThe current number of ruler clients in the pool.
cortex_ruler_config_last_reload_successfulgaugeins, instance, ip, user, job, clsBoolean set to 1 whenever the last configuration reload attempt was successful.
cortex_ruler_config_last_reload_successful_secondsgaugeins, instance, ip, user, job, clsTimestamp of the last successful configuration reload.
cortex_ruler_config_updates_totalUnknownins, instance, ip, user, job, clsN/A
cortex_ruler_managers_totalgaugeins, instance, ip, job, clsTotal number of managers registered and running in the ruler
cortex_ruler_ring_check_errors_totalUnknownins, instance, ip, job, clsN/A
cortex_ruler_sync_rules_totalUnknownins, instance, ip, reason, job, clsN/A
deprecated_flags_inuse_totalUnknownins, instance, ip, job, clsN/A
go_cgo_go_to_c_calls_calls_totalUnknownins, instance, ip, job, clsN/A
go_cpu_classes_gc_mark_assist_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
go_cpu_classes_gc_mark_dedicated_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
go_cpu_classes_gc_mark_idle_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
go_cpu_classes_gc_pause_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
go_cpu_classes_gc_total_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
go_cpu_classes_idle_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
go_cpu_classes_scavenge_assist_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
go_cpu_classes_scavenge_background_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
go_cpu_classes_scavenge_total_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
go_cpu_classes_total_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
go_cpu_classes_user_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
go_gc_cycles_automatic_gc_cycles_totalUnknownins, instance, ip, job, clsN/A
go_gc_cycles_forced_gc_cycles_totalUnknownins, instance, ip, job, clsN/A
go_gc_cycles_total_gc_cycles_totalUnknownins, instance, ip, job, clsN/A
go_gc_duration_secondssummaryins, instance, ip, job, cls, quantileA summary of the pause duration of garbage collection cycles.
go_gc_duration_seconds_countUnknownins, instance, ip, job, clsN/A
go_gc_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
go_gc_gogc_percentgaugeins, instance, ip, job, clsHeap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function.
go_gc_gomemlimit_bytesgaugeins, instance, ip, job, clsGo runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function.
go_gc_heap_allocs_by_size_bytes_bucketUnknownins, instance, ip, le, job, clsN/A
go_gc_heap_allocs_by_size_bytes_countUnknownins, instance, ip, job, clsN/A
go_gc_heap_allocs_by_size_bytes_sumUnknownins, instance, ip, job, clsN/A
go_gc_heap_allocs_bytes_totalUnknownins, instance, ip, job, clsN/A
go_gc_heap_allocs_objects_totalUnknownins, instance, ip, job, clsN/A
go_gc_heap_frees_by_size_bytes_bucketUnknownins, instance, ip, le, job, clsN/A
go_gc_heap_frees_by_size_bytes_countUnknownins, instance, ip, job, clsN/A
go_gc_heap_frees_by_size_bytes_sumUnknownins, instance, ip, job, clsN/A
go_gc_heap_frees_bytes_totalUnknownins, instance, ip, job, clsN/A
go_gc_heap_frees_objects_totalUnknownins, instance, ip, job, clsN/A
go_gc_heap_goal_bytesgaugeins, instance, ip, job, clsHeap size target for the end of the GC cycle.
go_gc_heap_live_bytesgaugeins, instance, ip, job, clsHeap memory occupied by live objects that were marked by the previous GC.
go_gc_heap_objects_objectsgaugeins, instance, ip, job, clsNumber of objects, live or unswept, occupying heap memory.
go_gc_heap_tiny_allocs_objects_totalUnknownins, instance, ip, job, clsN/A
go_gc_limiter_last_enabled_gc_cyclegaugeins, instance, ip, job, clsGC cycle the last time the GC CPU limiter was enabled. This metric is useful for diagnosing the root cause of an out-of-memory error, because the limiter trades memory for CPU time when the GC’s CPU time gets too high. This is most likely to occur with use of SetMemoryLimit. The first GC cycle is cycle 1, so a value of 0 indicates that it was never enabled.
go_gc_pauses_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
go_gc_pauses_seconds_countUnknownins, instance, ip, job, clsN/A
go_gc_pauses_seconds_sumUnknownins, instance, ip, job, clsN/A
go_gc_scan_globals_bytesgaugeins, instance, ip, job, clsThe total amount of global variable space that is scannable.
go_gc_scan_heap_bytesgaugeins, instance, ip, job, clsThe total amount of heap space that is scannable.
go_gc_scan_stack_bytesgaugeins, instance, ip, job, clsThe number of bytes of stack that were scanned last GC cycle.
go_gc_scan_total_bytesgaugeins, instance, ip, job, clsThe total amount space that is scannable. Sum of all metrics in /gc/scan.
go_gc_stack_starting_size_bytesgaugeins, instance, ip, job, clsThe stack size of new goroutines.
go_godebug_non_default_behavior_execerrdot_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_gocachehash_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_gocachetest_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_gocacheverify_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_http2client_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_http2server_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_installgoroot_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_jstmpllitinterp_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_multipartmaxheaders_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_multipartmaxparts_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_multipathtcp_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_panicnil_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_randautoseed_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_tarinsecurepath_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_tlsmaxrsasize_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_x509sha1_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_x509usefallbackroots_events_totalUnknownins, instance, ip, job, clsN/A
go_godebug_non_default_behavior_zipinsecurepath_events_totalUnknownins, instance, ip, job, clsN/A
go_goroutinesgaugeins, instance, ip, job, clsNumber of goroutines that currently exist.
go_infogaugeversion, ins, instance, ip, job, clsInformation about the Go environment.
go_memory_classes_heap_free_bytesgaugeins, instance, ip, job, clsMemory that is completely free and eligible to be returned to the underlying system, but has not been. This metric is the runtime’s estimate of free address space that is backed by physical memory.
go_memory_classes_heap_objects_bytesgaugeins, instance, ip, job, clsMemory occupied by live objects and dead objects that have not yet been marked free by the garbage collector.
go_memory_classes_heap_released_bytesgaugeins, instance, ip, job, clsMemory that is completely free and has been returned to the underlying system. This metric is the runtime’s estimate of free address space that is still mapped into the process, but is not backed by physical memory.
go_memory_classes_heap_stacks_bytesgaugeins, instance, ip, job, clsMemory allocated from the heap that is reserved for stack space, whether or not it is currently in-use. Currently, this represents all stack memory for goroutines. It also includes all OS thread stacks in non-cgo programs. Note that stacks may be allocated differently in the future, and this may change.
go_memory_classes_heap_unused_bytesgaugeins, instance, ip, job, clsMemory that is reserved for heap objects but is not currently used to hold heap objects.
go_memory_classes_metadata_mcache_free_bytesgaugeins, instance, ip, job, clsMemory that is reserved for runtime mcache structures, but not in-use.
go_memory_classes_metadata_mcache_inuse_bytesgaugeins, instance, ip, job, clsMemory that is occupied by runtime mcache structures that are currently being used.
go_memory_classes_metadata_mspan_free_bytesgaugeins, instance, ip, job, clsMemory that is reserved for runtime mspan structures, but not in-use.
go_memory_classes_metadata_mspan_inuse_bytesgaugeins, instance, ip, job, clsMemory that is occupied by runtime mspan structures that are currently being used.
go_memory_classes_metadata_other_bytesgaugeins, instance, ip, job, clsMemory that is reserved for or used to hold runtime metadata.
go_memory_classes_os_stacks_bytesgaugeins, instance, ip, job, clsStack memory allocated by the underlying operating system. In non-cgo programs this metric is currently zero. This may change in the future.In cgo programs this metric includes OS thread stacks allocated directly from the OS. Currently, this only accounts for one stack in c-shared and c-archive build modes, and other sources of stacks from the OS are not measured. This too may change in the future.
go_memory_classes_other_bytesgaugeins, instance, ip, job, clsMemory used by execution trace buffers, structures for debugging the runtime, finalizer and profiler specials, and more.
go_memory_classes_profiling_buckets_bytesgaugeins, instance, ip, job, clsMemory that is used by the stack trace hash map used for profiling.
go_memory_classes_total_bytesgaugeins, instance, ip, job, clsAll memory mapped by the Go runtime into the current process as read-write. Note that this does not include memory mapped by code called via cgo or via the syscall package. Sum of all metrics in /memory/classes.
go_memstats_alloc_bytescounterins, instance, ip, job, clsTotal number of bytes allocated, even if freed.
go_memstats_alloc_bytes_totalcounterins, instance, ip, job, clsTotal number of bytes allocated, even if freed.
go_memstats_buck_hash_sys_bytesgaugeins, instance, ip, job, clsNumber of bytes used by the profiling bucket hash table.
go_memstats_frees_totalcounterins, instance, ip, job, clsTotal number of frees.
go_memstats_gc_sys_bytesgaugeins, instance, ip, job, clsNumber of bytes used for garbage collection system metadata.
go_memstats_heap_alloc_bytesgaugeins, instance, ip, job, clsNumber of heap bytes allocated and still in use.
go_memstats_heap_idle_bytesgaugeins, instance, ip, job, clsNumber of heap bytes waiting to be used.
go_memstats_heap_inuse_bytesgaugeins, instance, ip, job, clsNumber of heap bytes that are in use.
go_memstats_heap_objectsgaugeins, instance, ip, job, clsNumber of allocated objects.
go_memstats_heap_released_bytesgaugeins, instance, ip, job, clsNumber of heap bytes released to OS.
go_memstats_heap_sys_bytesgaugeins, instance, ip, job, clsNumber of heap bytes obtained from system.
go_memstats_last_gc_time_secondsgaugeins, instance, ip, job, clsNumber of seconds since 1970 of last garbage collection.
go_memstats_lookups_totalcounterins, instance, ip, job, clsTotal number of pointer lookups.
go_memstats_mallocs_totalcounterins, instance, ip, job, clsTotal number of mallocs.
go_memstats_mcache_inuse_bytesgaugeins, instance, ip, job, clsNumber of bytes in use by mcache structures.
go_memstats_mcache_sys_bytesgaugeins, instance, ip, job, clsNumber of bytes used for mcache structures obtained from system.
go_memstats_mspan_inuse_bytesgaugeins, instance, ip, job, clsNumber of bytes in use by mspan structures.
go_memstats_mspan_sys_bytesgaugeins, instance, ip, job, clsNumber of bytes used for mspan structures obtained from system.
go_memstats_next_gc_bytesgaugeins, instance, ip, job, clsNumber of heap bytes when next garbage collection will take place.
go_memstats_other_sys_bytesgaugeins, instance, ip, job, clsNumber of bytes used for other system allocations.
go_memstats_stack_inuse_bytesgaugeins, instance, ip, job, clsNumber of bytes in use by the stack allocator.
go_memstats_stack_sys_bytesgaugeins, instance, ip, job, clsNumber of bytes obtained from system for stack allocator.
go_memstats_sys_bytesgaugeins, instance, ip, job, clsNumber of bytes obtained from system.
go_sched_gomaxprocs_threadsgaugeins, instance, ip, job, clsThe current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously.
go_sched_goroutines_goroutinesgaugeins, instance, ip, job, clsCount of live goroutines.
go_sched_latencies_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
go_sched_latencies_seconds_countUnknownins, instance, ip, job, clsN/A
go_sched_latencies_seconds_sumUnknownins, instance, ip, job, clsN/A
go_sql_stats_connections_blocked_secondsunknownins, instance, db_name, ip, job, clsThe total time blocked waiting for a new connection.
go_sql_stats_connections_closed_max_idleunknownins, instance, db_name, ip, job, clsThe total number of connections closed due to SetMaxIdleConns.
go_sql_stats_connections_closed_max_idle_timeunknownins, instance, db_name, ip, job, clsThe total number of connections closed due to SetConnMaxIdleTime.
go_sql_stats_connections_closed_max_lifetimeunknownins, instance, db_name, ip, job, clsThe total number of connections closed due to SetConnMaxLifetime.
go_sql_stats_connections_idlegaugeins, instance, db_name, ip, job, clsThe number of idle connections.
go_sql_stats_connections_in_usegaugeins, instance, db_name, ip, job, clsThe number of connections currently in use.
go_sql_stats_connections_max_opengaugeins, instance, db_name, ip, job, clsMaximum number of open connections to the database.
go_sql_stats_connections_opengaugeins, instance, db_name, ip, job, clsThe number of established connections both in use and idle.
go_sql_stats_connections_waited_forunknownins, instance, db_name, ip, job, clsThe total number of connections waited for.
go_sync_mutex_wait_total_seconds_totalUnknownins, instance, ip, job, clsN/A
go_threadsgaugeins, instance, ip, job, clsNumber of OS threads created.
grafana_access_evaluation_countunknownins, instance, ip, job, clsnumber of evaluation calls
grafana_access_evaluation_duration_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_access_evaluation_duration_countUnknownins, instance, ip, job, clsN/A
grafana_access_evaluation_duration_sumUnknownins, instance, ip, job, clsN/A
grafana_access_permissions_duration_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_access_permissions_duration_countUnknownins, instance, ip, job, clsN/A
grafana_access_permissions_duration_sumUnknownins, instance, ip, job, clsN/A
grafana_aggregator_discovery_aggregation_count_totalUnknownins, instance, ip, job, clsN/A
grafana_alerting_active_alertsgaugeins, instance, ip, job, clsamount of active alerts
grafana_alerting_active_configurationsgaugeins, instance, ip, job, clsThe number of active Alertmanager configurations.
grafana_alerting_alertmanager_config_matchgaugeins, instance, ip, job, clsThe total number of match
grafana_alerting_alertmanager_config_match_regaugeins, instance, ip, job, clsThe total number of matchRE
grafana_alerting_alertmanager_config_matchersgaugeins, instance, ip, job, clsThe total number of matchers
grafana_alerting_alertmanager_config_object_matchersgaugeins, instance, ip, job, clsThe total number of object_matchers
grafana_alerting_discovered_configurationsgaugeins, instance, ip, job, clsThe number of organizations we’ve discovered that require an Alertmanager configuration.
grafana_alerting_dispatcher_aggregation_groupsgaugeins, instance, ip, job, clsNumber of active aggregation groups
grafana_alerting_dispatcher_alert_processing_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_dispatcher_alert_processing_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_execution_time_millisecondssummaryins, instance, ip, job, cls, quantilesummary of alert execution duration
grafana_alerting_execution_time_milliseconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_execution_time_milliseconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_nflog_gc_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_nflog_gc_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_nflog_gossip_messages_propagated_totalUnknownins, instance, ip, job, clsN/A
grafana_alerting_nflog_queries_totalUnknownins, instance, ip, job, clsN/A
grafana_alerting_nflog_query_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_alerting_nflog_query_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_nflog_query_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_nflog_query_errors_totalUnknownins, instance, ip, job, clsN/A
grafana_alerting_nflog_snapshot_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_nflog_snapshot_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_nflog_snapshot_size_bytesgaugeins, instance, ip, job, clsSize of the last notification log snapshot in bytes.
grafana_alerting_notification_latency_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_alerting_notification_latency_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_notification_latency_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_schedule_alert_rulesgaugeins, instance, ip, job, clsThe number of alert rules that could be considered for evaluation at the next tick.
grafana_alerting_schedule_alert_rules_hashgaugeins, instance, ip, job, clsA hash of the alert rules that could be considered for evaluation at the next tick.
grafana_alerting_schedule_periodic_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_alerting_schedule_periodic_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_schedule_periodic_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_schedule_query_alert_rules_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_alerting_schedule_query_alert_rules_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_schedule_query_alert_rules_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_scheduler_behind_secondsgaugeins, instance, ip, job, clsThe total number of seconds the scheduler is behind.
grafana_alerting_silences_gc_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_silences_gc_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_silences_gossip_messages_propagated_totalUnknownins, instance, ip, job, clsN/A
grafana_alerting_silences_queries_totalUnknownins, instance, ip, job, clsN/A
grafana_alerting_silences_query_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_alerting_silences_query_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_silences_query_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_silences_query_errors_totalUnknownins, instance, ip, job, clsN/A
grafana_alerting_silences_snapshot_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_silences_snapshot_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_silences_snapshot_size_bytesgaugeins, instance, ip, job, clsSize of the last silence snapshot in bytes.
grafana_alerting_state_calculation_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_alerting_state_calculation_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_alerting_state_calculation_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_alerting_state_history_writes_bytes_totalUnknownins, instance, ip, job, clsN/A
grafana_alerting_ticker_interval_secondsgaugeins, instance, ip, job, clsInterval at which the ticker is meant to tick.
grafana_alerting_ticker_last_consumed_tick_timestamp_secondsgaugeins, instance, ip, job, clsTimestamp of the last consumed tick in seconds.
grafana_alerting_ticker_next_tick_timestamp_secondsgaugeins, instance, ip, job, clsTimestamp of the next tick in seconds before it is consumed.
grafana_api_admin_user_created_totalUnknownins, instance, ip, job, clsN/A
grafana_api_dashboard_get_millisecondssummaryins, instance, ip, job, cls, quantilesummary for dashboard get duration
grafana_api_dashboard_get_milliseconds_countUnknownins, instance, ip, job, clsN/A
grafana_api_dashboard_get_milliseconds_sumUnknownins, instance, ip, job, clsN/A
grafana_api_dashboard_save_millisecondssummaryins, instance, ip, job, cls, quantilesummary for dashboard save duration
grafana_api_dashboard_save_milliseconds_countUnknownins, instance, ip, job, clsN/A
grafana_api_dashboard_save_milliseconds_sumUnknownins, instance, ip, job, clsN/A
grafana_api_dashboard_search_millisecondssummaryins, instance, ip, job, cls, quantilesummary for dashboard search duration
grafana_api_dashboard_search_milliseconds_countUnknownins, instance, ip, job, clsN/A
grafana_api_dashboard_search_milliseconds_sumUnknownins, instance, ip, job, clsN/A
grafana_api_dashboard_snapshot_create_totalUnknownins, instance, ip, job, clsN/A
grafana_api_dashboard_snapshot_external_totalUnknownins, instance, ip, job, clsN/A
grafana_api_dashboard_snapshot_get_totalUnknownins, instance, ip, job, clsN/A
grafana_api_dataproxy_request_all_millisecondssummaryins, instance, ip, job, cls, quantilesummary for dataproxy request duration
grafana_api_dataproxy_request_all_milliseconds_countUnknownins, instance, ip, job, clsN/A
grafana_api_dataproxy_request_all_milliseconds_sumUnknownins, instance, ip, job, clsN/A
grafana_api_login_oauth_totalUnknownins, instance, ip, job, clsN/A
grafana_api_login_post_totalUnknownins, instance, ip, job, clsN/A
grafana_api_login_saml_totalUnknownins, instance, ip, job, clsN/A
grafana_api_models_dashboard_insert_totalUnknownins, instance, ip, job, clsN/A
grafana_api_org_create_totalUnknownins, instance, ip, job, clsN/A
grafana_api_response_status_totalUnknownins, instance, ip, job, cls, codeN/A
grafana_api_user_signup_completed_totalUnknownins, instance, ip, job, clsN/A
grafana_api_user_signup_invite_totalUnknownins, instance, ip, job, clsN/A
grafana_api_user_signup_started_totalUnknownins, instance, ip, job, clsN/A
grafana_apiserver_audit_event_totalUnknownins, instance, ip, job, clsN/A
grafana_apiserver_audit_requests_rejected_totalUnknownins, instance, ip, job, clsN/A
grafana_apiserver_client_certificate_expiration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_apiserver_client_certificate_expiration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_apiserver_client_certificate_expiration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_apiserver_envelope_encryption_dek_cache_fill_percentgaugeins, instance, ip, job, cls[ALPHA] Percent of the cache slots currently occupied by cached DEKs.
grafana_apiserver_flowcontrol_seat_fair_fracgaugeins, instance, ip, job, cls[ALPHA] Fair fraction of server’s concurrency to allocate to each priority level that can use it
grafana_apiserver_storage_data_key_generation_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_apiserver_storage_data_key_generation_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_apiserver_storage_data_key_generation_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_apiserver_storage_data_key_generation_failures_totalUnknownins, instance, ip, job, clsN/A
grafana_apiserver_storage_envelope_transformation_cache_misses_totalUnknownins, instance, ip, job, clsN/A
grafana_apiserver_tls_handshake_errors_totalUnknownins, instance, ip, job, clsN/A
grafana_apiserver_webhooks_x509_insecure_sha1_totalUnknownins, instance, ip, job, clsN/A
grafana_apiserver_webhooks_x509_missing_san_totalUnknownins, instance, ip, job, clsN/A
grafana_authn_authn_failed_authentication_totalUnknownins, instance, ip, job, clsN/A
grafana_authn_authn_successful_authentication_totalUnknownins, instance, ip, client, job, clsN/A
grafana_authn_authn_successful_login_totalUnknownins, instance, ip, client, job, clsN/A
grafana_aws_cloudwatch_get_metric_data_totalUnknownins, instance, ip, job, clsN/A
grafana_aws_cloudwatch_get_metric_statistics_totalUnknownins, instance, ip, job, clsN/A
grafana_aws_cloudwatch_list_metrics_totalUnknownins, instance, ip, job, clsN/A
grafana_build_infogaugerevision, version, ins, instance, edition, ip, goversion, job, cls, branchA metric with a constant ‘1’ value labeled by version, revision, branch, and goversion from which Grafana was built
grafana_build_timestampgaugerevision, version, ins, instance, edition, ip, goversion, job, cls, branchA metric exposing when the binary was built in epoch
grafana_cardinality_enforcement_unexpected_categorizations_totalUnknownins, instance, ip, job, clsN/A
grafana_database_conn_idlegaugeins, instance, ip, job, clsThe number of idle connections
grafana_database_conn_in_usegaugeins, instance, ip, job, clsThe number of connections currently in use
grafana_database_conn_max_idle_closed_secondsunknownins, instance, ip, job, clsThe total number of connections closed due to SetConnMaxIdleTime
grafana_database_conn_max_idle_closed_totalUnknownins, instance, ip, job, clsN/A
grafana_database_conn_max_lifetime_closed_totalUnknownins, instance, ip, job, clsN/A
grafana_database_conn_max_opengaugeins, instance, ip, job, clsMaximum number of open connections to the database
grafana_database_conn_opengaugeins, instance, ip, job, clsThe number of established connections both in use and idle
grafana_database_conn_wait_count_totalUnknownins, instance, ip, job, clsN/A
grafana_database_conn_wait_duration_secondsunknownins, instance, ip, job, clsThe total time blocked waiting for a new connection
grafana_datasource_request_duration_seconds_bucketUnknowndatasource, ins, instance, method, ip, le, datasource_type, job, cls, codeN/A
grafana_datasource_request_duration_seconds_countUnknowndatasource, ins, instance, method, ip, datasource_type, job, cls, codeN/A
grafana_datasource_request_duration_seconds_sumUnknowndatasource, ins, instance, method, ip, datasource_type, job, cls, codeN/A
grafana_datasource_request_in_flightgaugedatasource, ins, instance, ip, datasource_type, job, clsA gauge of outgoing data source requests currently being sent by Grafana
grafana_datasource_request_totalUnknowndatasource, ins, instance, method, ip, datasource_type, job, cls, codeN/A
grafana_datasource_response_size_bytes_bucketUnknowndatasource, ins, instance, ip, le, datasource_type, job, clsN/A
grafana_datasource_response_size_bytes_countUnknowndatasource, ins, instance, ip, datasource_type, job, clsN/A
grafana_datasource_response_size_bytes_sumUnknowndatasource, ins, instance, ip, datasource_type, job, clsN/A
grafana_db_datasource_query_by_id_totalUnknownins, instance, ip, job, clsN/A
grafana_disabled_metrics_totalUnknownins, instance, ip, job, clsN/A
grafana_emails_sent_failedunknownins, instance, ip, job, clsNumber of emails Grafana failed to send
grafana_emails_sent_totalUnknownins, instance, ip, job, clsN/A
grafana_encryption_cache_reads_totalUnknownins, instance, method, ip, hit, job, clsN/A
grafana_encryption_ops_totalUnknownins, instance, ip, success, operation, job, clsN/A
grafana_environment_infogaugeversion, ins, instance, ip, job, cls, commitA metric with a constant ‘1’ value labeled by environment information about the running instance.
grafana_feature_toggles_infogaugeins, instance, ip, job, clsinfo metric that exposes what feature toggles are enabled or not
grafana_frontend_boot_css_time_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_frontend_boot_css_time_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_frontend_boot_css_time_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_frontend_boot_first_contentful_paint_time_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_frontend_boot_first_contentful_paint_time_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_frontend_boot_first_contentful_paint_time_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_frontend_boot_first_paint_time_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_frontend_boot_first_paint_time_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_frontend_boot_first_paint_time_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_frontend_boot_js_done_time_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_frontend_boot_js_done_time_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_frontend_boot_js_done_time_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_frontend_boot_load_time_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_frontend_boot_load_time_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_frontend_boot_load_time_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_frontend_plugins_preload_ms_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_frontend_plugins_preload_ms_countUnknownins, instance, ip, job, clsN/A
grafana_frontend_plugins_preload_ms_sumUnknownins, instance, ip, job, clsN/A
grafana_hidden_metrics_totalUnknownins, instance, ip, job, clsN/A
grafana_http_request_duration_seconds_bucketUnknownins, instance, method, ip, le, job, cls, status_code, handlerN/A
grafana_http_request_duration_seconds_countUnknownins, instance, method, ip, job, cls, status_code, handlerN/A
grafana_http_request_duration_seconds_sumUnknownins, instance, method, ip, job, cls, status_code, handlerN/A
grafana_http_request_in_flightgaugeins, instance, ip, job, clsA gauge of requests currently being served by Grafana.
grafana_idforwarding_idforwarding_failed_token_signing_totalUnknownins, instance, ip, job, clsN/A
grafana_idforwarding_idforwarding_token_signing_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_idforwarding_idforwarding_token_signing_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_idforwarding_idforwarding_token_signing_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_idforwarding_idforwarding_token_signing_from_cache_totalUnknownins, instance, ip, job, clsN/A
grafana_idforwarding_idforwarding_token_signing_totalUnknownins, instance, ip, job, clsN/A
grafana_instance_start_totalUnknownins, instance, ip, job, clsN/A
grafana_ldap_users_sync_execution_timesummaryins, instance, ip, job, cls, quantilesummary for LDAP users sync execution duration
grafana_ldap_users_sync_execution_time_countUnknownins, instance, ip, job, clsN/A
grafana_ldap_users_sync_execution_time_sumUnknownins, instance, ip, job, clsN/A
grafana_live_client_command_duration_secondssummaryins, instance, method, ip, job, cls, quantileClient command duration summary.
grafana_live_client_command_duration_seconds_countUnknownins, instance, method, ip, job, clsN/A
grafana_live_client_command_duration_seconds_sumUnknownins, instance, method, ip, job, clsN/A
grafana_live_client_num_reply_errorsunknownins, instance, method, ip, job, cls, codeNumber of errors in replies sent to clients.
grafana_live_client_num_server_disconnectsunknownins, instance, ip, job, cls, codeNumber of server initiated disconnects.
grafana_live_client_recoverunknownins, instance, ip, recovered, job, clsCount of recover operations.
grafana_live_node_action_countunknownaction, ins, instance, ip, job, clsNumber of node actions called.
grafana_live_node_buildgaugeversion, ins, instance, ip, job, clsNode build info.
grafana_live_node_messages_received_countunknownins, instance, ip, type, job, clsNumber of messages received.
grafana_live_node_messages_sent_countunknownins, instance, ip, type, job, clsNumber of messages sent.
grafana_live_node_num_channelsgaugeins, instance, ip, job, clsNumber of channels with one or more subscribers.
grafana_live_node_num_clientsgaugeins, instance, ip, job, clsNumber of clients connected.
grafana_live_node_num_nodesgaugeins, instance, ip, job, clsNumber of nodes in cluster.
grafana_live_node_num_subscriptionsgaugeins, instance, ip, job, clsNumber of subscriptions.
grafana_live_node_num_usersgaugeins, instance, ip, job, clsNumber of unique users connected.
grafana_live_transport_connect_countunknownins, instance, ip, transport, job, clsNumber of connections to specific transport.
grafana_live_transport_messages_sentunknownins, instance, ip, transport, job, clsNumber of messages sent over specific transport.
grafana_loki_plugin_parse_response_duration_seconds_bucketUnknownendpoint, ins, instance, ip, le, status, job, clsN/A
grafana_loki_plugin_parse_response_duration_seconds_countUnknownendpoint, ins, instance, ip, status, job, clsN/A
grafana_loki_plugin_parse_response_duration_seconds_sumUnknownendpoint, ins, instance, ip, status, job, clsN/A
grafana_page_response_status_totalUnknownins, instance, ip, job, cls, codeN/A
grafana_plugin_build_infogaugeversion, signature_status, ins, instance, plugin_type, ip, plugin_id, job, clsA metric with a constant ‘1’ value labeled by pluginId, pluginType and version from which Grafana plugin was built
grafana_plugin_request_duration_milliseconds_bucketUnknownendpoint, ins, instance, target, ip, le, plugin_id, job, clsN/A
grafana_plugin_request_duration_milliseconds_countUnknownendpoint, ins, instance, target, ip, plugin_id, job, clsN/A
grafana_plugin_request_duration_milliseconds_sumUnknownendpoint, ins, instance, target, ip, plugin_id, job, clsN/A
grafana_plugin_request_duration_seconds_bucketUnknownendpoint, ins, instance, target, ip, le, status, plugin_id, source, job, clsN/A
grafana_plugin_request_duration_seconds_countUnknownendpoint, ins, instance, target, ip, status, plugin_id, source, job, clsN/A
grafana_plugin_request_duration_seconds_sumUnknownendpoint, ins, instance, target, ip, status, plugin_id, source, job, clsN/A
grafana_plugin_request_size_bytes_bucketUnknownendpoint, ins, instance, target, ip, le, plugin_id, source, job, clsN/A
grafana_plugin_request_size_bytes_countUnknownendpoint, ins, instance, target, ip, plugin_id, source, job, clsN/A
grafana_plugin_request_size_bytes_sumUnknownendpoint, ins, instance, target, ip, plugin_id, source, job, clsN/A
grafana_plugin_request_totalUnknownendpoint, ins, instance, target, ip, status, plugin_id, job, clsN/A
grafana_process_cpu_seconds_totalUnknownins, instance, ip, job, clsN/A
grafana_process_max_fdsgaugeins, instance, ip, job, clsMaximum number of open file descriptors.
grafana_process_open_fdsgaugeins, instance, ip, job, clsNumber of open file descriptors.
grafana_process_resident_memory_bytesgaugeins, instance, ip, job, clsResident memory size in bytes.
grafana_process_start_time_secondsgaugeins, instance, ip, job, clsStart time of the process since unix epoch in seconds.
grafana_process_virtual_memory_bytesgaugeins, instance, ip, job, clsVirtual memory size in bytes.
grafana_process_virtual_memory_max_bytesgaugeins, instance, ip, job, clsMaximum amount of virtual memory available in bytes.
grafana_prometheus_plugin_backend_request_countunknownendpoint, ins, instance, ip, status, errorSource, job, clsThe total amount of prometheus backend plugin requests
grafana_proxy_response_status_totalUnknownins, instance, ip, job, cls, codeN/A
grafana_public_dashboard_request_countunknownins, instance, ip, job, clscounter for public dashboards requests
grafana_registered_metrics_totalUnknownins, instance, ip, stability_level, deprecated_version, job, clsN/A
grafana_rendering_queue_sizegaugeins, instance, ip, job, clssize of rendering queue
grafana_search_dashboard_search_failures_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_search_dashboard_search_failures_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_search_dashboard_search_failures_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_search_dashboard_search_successes_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
grafana_search_dashboard_search_successes_duration_seconds_countUnknownins, instance, ip, job, clsN/A
grafana_search_dashboard_search_successes_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
grafana_stat_active_usersgaugeins, instance, ip, job, clsnumber of active users
grafana_stat_total_orgsgaugeins, instance, ip, job, clstotal amount of orgs
grafana_stat_total_playlistsgaugeins, instance, ip, job, clstotal amount of playlists
grafana_stat_total_service_account_tokensgaugeins, instance, ip, job, clstotal amount of service account tokens
grafana_stat_total_service_accountsgaugeins, instance, ip, job, clstotal amount of service accounts
grafana_stat_total_service_accounts_role_nonegaugeins, instance, ip, job, clstotal amount of service accounts with no role
grafana_stat_total_teamsgaugeins, instance, ip, job, clstotal amount of teams
grafana_stat_total_usersgaugeins, instance, ip, job, clstotal amount of users
grafana_stat_totals_active_adminsgaugeins, instance, ip, job, clstotal amount of active admins
grafana_stat_totals_active_editorsgaugeins, instance, ip, job, clstotal amount of active editors
grafana_stat_totals_active_viewersgaugeins, instance, ip, job, clstotal amount of active viewers
grafana_stat_totals_adminsgaugeins, instance, ip, job, clstotal amount of admins
grafana_stat_totals_alert_rulesgaugeins, instance, ip, job, clstotal amount of alert rules in the database
grafana_stat_totals_annotationsgaugeins, instance, ip, job, clstotal amount of annotations in the database
grafana_stat_totals_correlationsgaugeins, instance, ip, job, clstotal amount of correlations
grafana_stat_totals_dashboardgaugeins, instance, ip, job, clstotal amount of dashboards
grafana_stat_totals_dashboard_versionsgaugeins, instance, ip, job, clstotal amount of dashboard versions in the database
grafana_stat_totals_data_keysgaugeins, instance, ip, job, cls, activetotal amount of data keys in the database
grafana_stat_totals_datasourcegaugeins, instance, ip, plugin_id, job, clstotal number of defined datasources, labeled by pluginId
grafana_stat_totals_editorsgaugeins, instance, ip, job, clstotal amount of editors
grafana_stat_totals_foldergaugeins, instance, ip, job, clstotal amount of folders
grafana_stat_totals_library_panelsgaugeins, instance, ip, job, clstotal amount of library panels in the database
grafana_stat_totals_library_variablesgaugeins, instance, ip, job, clstotal amount of library variables in the database
grafana_stat_totals_public_dashboardgaugeins, instance, ip, job, clstotal amount of public dashboards
grafana_stat_totals_rule_groupsgaugeins, instance, ip, job, clstotal amount of alert rule groups in the database
grafana_stat_totals_viewersgaugeins, instance, ip, job, clstotal amount of viewers
infra_upUnknownins, instance, ip, job, clsN/A
jaeger_tracer_baggage_restrictions_updates_totalUnknownresult, ins, instance, ip, job, clsN/A
jaeger_tracer_baggage_truncations_totalUnknownins, instance, ip, job, clsN/A
jaeger_tracer_baggage_updates_totalUnknownresult, ins, instance, ip, job, clsN/A
jaeger_tracer_finished_spans_totalUnknownins, instance, ip, sampled, job, clsN/A
jaeger_tracer_reporter_queue_lengthgaugeins, instance, ip, job, clsCurrent number of spans in the reporter queue
jaeger_tracer_reporter_spans_totalUnknownresult, ins, instance, ip, job, clsN/A
jaeger_tracer_sampler_queries_totalUnknownresult, ins, instance, ip, job, clsN/A
jaeger_tracer_sampler_updates_totalUnknownresult, ins, instance, ip, job, clsN/A
jaeger_tracer_span_context_decoding_errors_totalUnknownins, instance, ip, job, clsN/A
jaeger_tracer_started_spans_totalUnknownins, instance, ip, sampled, job, clsN/A
jaeger_tracer_throttled_debug_spans_totalUnknownins, instance, ip, job, clsN/A
jaeger_tracer_throttler_updates_totalUnknownresult, ins, instance, ip, job, clsN/A
jaeger_tracer_traces_totalUnknownins, instance, ip, sampled, job, cls, stateN/A
kv_request_duration_seconds_bucketUnknownins, instance, role, ip, le, kv_name, type, operation, job, cls, status_codeN/A
kv_request_duration_seconds_countUnknownins, instance, role, ip, kv_name, type, operation, job, cls, status_codeN/A
kv_request_duration_seconds_sumUnknownins, instance, role, ip, kv_name, type, operation, job, cls, status_codeN/A
legacy_grafana_alerting_ticker_interval_secondsgaugeins, instance, ip, job, clsInterval at which the ticker is meant to tick.
legacy_grafana_alerting_ticker_last_consumed_tick_timestamp_secondsgaugeins, instance, ip, job, clsTimestamp of the last consumed tick in seconds.
legacy_grafana_alerting_ticker_next_tick_timestamp_secondsgaugeins, instance, ip, job, clsTimestamp of the next tick in seconds before it is consumed.
logql_query_duration_seconds_bucketUnknownins, instance, query_type, ip, le, job, clsN/A
logql_query_duration_seconds_countUnknownins, instance, query_type, ip, job, clsN/A
logql_query_duration_seconds_sumUnknownins, instance, query_type, ip, job, clsN/A
loki_azure_blob_egress_bytes_totalUnknownins, instance, ip, job, clsN/A
loki_boltdb_shipper_apply_retention_last_successful_run_timestamp_secondsgaugeins, instance, ip, job, clsUnix timestamp of the last successful retention run
loki_boltdb_shipper_compact_tables_operation_duration_secondsgaugeins, instance, ip, job, clsTime (in seconds) spent in compacting all the tables
loki_boltdb_shipper_compact_tables_operation_last_successful_run_timestamp_secondsgaugeins, instance, ip, job, clsUnix timestamp of the last successful compaction run
loki_boltdb_shipper_compact_tables_operation_totalUnknownins, instance, ip, status, job, clsN/A
loki_boltdb_shipper_compactor_runninggaugeins, instance, ip, job, clsValue will be 1 if compactor is currently running on this instance
loki_boltdb_shipper_open_existing_file_failures_totalUnknownins, instance, ip, component, job, clsN/A
loki_boltdb_shipper_query_time_table_download_duration_secondsunknownins, instance, ip, component, job, cls, tableTime (in seconds) spent in downloading of files per table at query time
loki_boltdb_shipper_request_duration_seconds_bucketUnknownins, instance, ip, le, component, operation, job, cls, status_codeN/A
loki_boltdb_shipper_request_duration_seconds_countUnknownins, instance, ip, component, operation, job, cls, status_codeN/A
loki_boltdb_shipper_request_duration_seconds_sumUnknownins, instance, ip, component, operation, job, cls, status_codeN/A
loki_boltdb_shipper_tables_download_operation_duration_secondsgaugeins, instance, ip, component, job, clsTime (in seconds) spent in downloading updated files for all the tables
loki_boltdb_shipper_tables_sync_operation_totalUnknownins, instance, ip, status, component, job, clsN/A
loki_boltdb_shipper_tables_upload_operation_totalUnknownins, instance, ip, status, component, job, clsN/A
loki_build_infogaugerevision, version, ins, instance, ip, tags, goarch, goversion, job, cls, branch, goosA metric with a constant ‘1’ value labeled by version, revision, branch, goversion from which loki was built, and the goos and goarch for the build.
loki_bytes_per_line_bucketUnknownins, instance, ip, le, job, clsN/A
loki_bytes_per_line_countUnknownins, instance, ip, job, clsN/A
loki_bytes_per_line_sumUnknownins, instance, ip, job, clsN/A
loki_cache_corrupt_chunks_totalUnknownins, instance, ip, job, clsN/A
loki_cache_fetched_keysunknownins, instance, ip, job, clsTotal count of keys requested from cache.
loki_cache_hitsunknownins, instance, ip, job, clsTotal count of keys found in cache.
loki_cache_request_duration_seconds_bucketUnknownins, instance, method, ip, le, job, cls, status_codeN/A
loki_cache_request_duration_seconds_countUnknownins, instance, method, ip, job, cls, status_codeN/A
loki_cache_request_duration_seconds_sumUnknownins, instance, method, ip, job, cls, status_codeN/A
loki_cache_value_size_bytes_bucketUnknownins, instance, method, ip, le, job, clsN/A
loki_cache_value_size_bytes_countUnknownins, instance, method, ip, job, clsN/A
loki_cache_value_size_bytes_sumUnknownins, instance, method, ip, job, clsN/A
loki_chunk_fetcher_cache_dequeued_totalUnknownins, instance, ip, job, clsN/A
loki_chunk_fetcher_cache_enqueued_totalUnknownins, instance, ip, job, clsN/A
loki_chunk_fetcher_cache_skipped_buffer_full_totalUnknownins, instance, ip, job, clsN/A
loki_chunk_fetcher_fetched_size_bytes_bucketUnknownins, instance, ip, le, source, job, clsN/A
loki_chunk_fetcher_fetched_size_bytes_countUnknownins, instance, ip, source, job, clsN/A
loki_chunk_fetcher_fetched_size_bytes_sumUnknownins, instance, ip, source, job, clsN/A
loki_chunk_store_chunks_per_query_bucketUnknownins, instance, ip, le, job, clsN/A
loki_chunk_store_chunks_per_query_countUnknownins, instance, ip, job, clsN/A
loki_chunk_store_chunks_per_query_sumUnknownins, instance, ip, job, clsN/A
loki_chunk_store_deduped_bytes_totalUnknownins, instance, ip, job, clsN/A
loki_chunk_store_deduped_chunks_totalUnknownins, instance, ip, job, clsN/A
loki_chunk_store_fetched_chunk_bytes_totalUnknownins, instance, ip, user, job, clsN/A
loki_chunk_store_fetched_chunks_totalUnknownins, instance, ip, user, job, clsN/A
loki_chunk_store_index_entries_per_chunk_bucketUnknownins, instance, ip, le, job, clsN/A
loki_chunk_store_index_entries_per_chunk_countUnknownins, instance, ip, job, clsN/A
loki_chunk_store_index_entries_per_chunk_sumUnknownins, instance, ip, job, clsN/A
loki_chunk_store_index_lookups_per_query_bucketUnknownins, instance, ip, le, job, clsN/A
loki_chunk_store_index_lookups_per_query_countUnknownins, instance, ip, job, clsN/A
loki_chunk_store_index_lookups_per_query_sumUnknownins, instance, ip, job, clsN/A
loki_chunk_store_series_post_intersection_per_query_bucketUnknownins, instance, ip, le, job, clsN/A
loki_chunk_store_series_post_intersection_per_query_countUnknownins, instance, ip, job, clsN/A
loki_chunk_store_series_post_intersection_per_query_sumUnknownins, instance, ip, job, clsN/A
loki_chunk_store_series_pre_intersection_per_query_bucketUnknownins, instance, ip, le, job, clsN/A
loki_chunk_store_series_pre_intersection_per_query_countUnknownins, instance, ip, job, clsN/A
loki_chunk_store_series_pre_intersection_per_query_sumUnknownins, instance, ip, job, clsN/A
loki_chunk_store_stored_chunk_bytes_totalUnknownins, instance, ip, user, job, clsN/A
loki_chunk_store_stored_chunks_totalUnknownins, instance, ip, user, job, clsN/A
loki_consul_request_duration_seconds_bucketUnknownins, instance, ip, le, kv_name, operation, job, cls, status_codeN/A
loki_consul_request_duration_seconds_countUnknownins, instance, ip, kv_name, operation, job, cls, status_codeN/A
loki_consul_request_duration_seconds_sumUnknownins, instance, ip, kv_name, operation, job, cls, status_codeN/A
loki_delete_request_lookups_failed_totalUnknownins, instance, ip, job, clsN/A
loki_delete_request_lookups_totalUnknownins, instance, ip, job, clsN/A
loki_discarded_bytes_totalUnknownins, instance, ip, reason, job, cls, tenantN/A
loki_discarded_samples_totalUnknownins, instance, ip, reason, job, cls, tenantN/A
loki_distributor_bytes_received_totalUnknownins, instance, retention_hours, ip, job, cls, tenantN/A
loki_distributor_ingester_appends_totalUnknownins, instance, ip, ingester, job, clsN/A
loki_distributor_lines_received_totalUnknownins, instance, ip, job, cls, tenantN/A
loki_distributor_replication_factorgaugeins, instance, ip, job, clsThe configured replication factor.
loki_distributor_structured_metadata_bytes_received_totalUnknownins, instance, retention_hours, ip, job, cls, tenantN/A
loki_experimental_features_in_use_totalUnknownins, instance, ip, job, clsN/A
loki_index_chunk_refs_totalUnknownins, instance, ip, status, job, clsN/A
loki_index_request_duration_seconds_bucketUnknownins, instance, ip, le, component, operation, job, cls, status_codeN/A
loki_index_request_duration_seconds_countUnknownins, instance, ip, component, operation, job, cls, status_codeN/A
loki_index_request_duration_seconds_sumUnknownins, instance, ip, component, operation, job, cls, status_codeN/A
loki_inflight_requestsgaugeins, instance, method, ip, route, job, clsCurrent number of inflight requests.
loki_ingester_autoforget_unhealthy_ingesters_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_blocks_per_chunk_bucketUnknownins, instance, ip, le, job, clsN/A
loki_ingester_blocks_per_chunk_countUnknownins, instance, ip, job, clsN/A
loki_ingester_blocks_per_chunk_sumUnknownins, instance, ip, job, clsN/A
loki_ingester_checkpoint_creations_failed_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_checkpoint_creations_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_checkpoint_deletions_failed_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_checkpoint_deletions_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_checkpoint_duration_secondssummaryins, instance, ip, job, cls, quantileTime taken to create a checkpoint.
loki_ingester_checkpoint_duration_seconds_countUnknownins, instance, ip, job, clsN/A
loki_ingester_checkpoint_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
loki_ingester_checkpoint_logged_bytes_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_age_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
loki_ingester_chunk_age_seconds_countUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_age_seconds_sumUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_bounds_hours_bucketUnknownins, instance, ip, le, job, clsN/A
loki_ingester_chunk_bounds_hours_countUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_bounds_hours_sumUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_compression_ratio_bucketUnknownins, instance, ip, le, job, clsN/A
loki_ingester_chunk_compression_ratio_countUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_compression_ratio_sumUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_encode_time_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
loki_ingester_chunk_encode_time_seconds_countUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_encode_time_seconds_sumUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_entries_bucketUnknownins, instance, ip, le, job, clsN/A
loki_ingester_chunk_entries_countUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_entries_sumUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_size_bytes_bucketUnknownins, instance, ip, le, job, clsN/A
loki_ingester_chunk_size_bytes_countUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_size_bytes_sumUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_stored_bytes_totalUnknownins, instance, ip, job, cls, tenantN/A
loki_ingester_chunk_utilization_bucketUnknownins, instance, ip, le, job, clsN/A
loki_ingester_chunk_utilization_countUnknownins, instance, ip, job, clsN/A
loki_ingester_chunk_utilization_sumUnknownins, instance, ip, job, clsN/A
loki_ingester_chunks_created_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_chunks_flushed_totalUnknownins, instance, ip, reason, job, clsN/A
loki_ingester_chunks_stored_totalUnknownins, instance, ip, job, cls, tenantN/A
loki_ingester_client_request_duration_seconds_bucketUnknownins, instance, ip, le, operation, job, cls, status_codeN/A
loki_ingester_client_request_duration_seconds_countUnknownins, instance, ip, operation, job, cls, status_codeN/A
loki_ingester_client_request_duration_seconds_sumUnknownins, instance, ip, operation, job, cls, status_codeN/A
loki_ingester_limiter_enabledgaugeins, instance, ip, job, clsWhether the ingester’s limiter is enabled
loki_ingester_memory_chunksgaugeins, instance, ip, job, clsThe total number of chunks in memory.
loki_ingester_memory_streamsgaugeins, instance, ip, job, cls, tenantThe total number of streams in memory per tenant.
loki_ingester_memory_streams_labels_bytesgaugeins, instance, ip, job, clsTotal bytes of labels of the streams in memory.
loki_ingester_received_chunksunknownins, instance, ip, job, clsThe total number of chunks received by this ingester whilst joining.
loki_ingester_samples_per_chunk_bucketUnknownins, instance, ip, le, job, clsN/A
loki_ingester_samples_per_chunk_countUnknownins, instance, ip, job, clsN/A
loki_ingester_samples_per_chunk_sumUnknownins, instance, ip, job, clsN/A
loki_ingester_sent_chunksunknownins, instance, ip, job, clsThe total number of chunks sent by this ingester whilst leaving.
loki_ingester_shutdown_markergaugeins, instance, ip, job, cls1 if prepare shutdown has been called, 0 otherwise
loki_ingester_streams_created_totalUnknownins, instance, ip, job, cls, tenantN/A
loki_ingester_streams_removed_totalUnknownins, instance, ip, job, cls, tenantN/A
loki_ingester_wal_bytes_in_usegaugeins, instance, ip, job, clsTotal number of bytes in use by the WAL recovery process.
loki_ingester_wal_disk_full_failures_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_wal_duplicate_entries_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_wal_logged_bytes_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_wal_records_logged_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_wal_recovered_bytes_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_wal_recovered_chunks_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_wal_recovered_entries_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_wal_recovered_streams_totalUnknownins, instance, ip, job, clsN/A
loki_ingester_wal_replay_activegaugeins, instance, ip, job, clsWhether the WAL is replaying
loki_ingester_wal_replay_duration_secondsgaugeins, instance, ip, job, clsTime taken to replay the checkpoint and the WAL.
loki_ingester_wal_replay_flushinggaugeins, instance, ip, job, clsWhether the wal replay is in a flushing phase due to backpressure
loki_internal_log_messages_totalUnknownins, instance, ip, level, job, clsN/A
loki_kv_request_duration_seconds_bucketUnknownins, instance, role, ip, le, kv_name, type, operation, job, cls, status_codeN/A
loki_kv_request_duration_seconds_countUnknownins, instance, role, ip, kv_name, type, operation, job, cls, status_codeN/A
loki_kv_request_duration_seconds_sumUnknownins, instance, role, ip, kv_name, type, operation, job, cls, status_codeN/A
loki_log_flushes_bucketUnknownins, instance, ip, le, job, clsN/A
loki_log_flushes_countUnknownins, instance, ip, job, clsN/A
loki_log_flushes_sumUnknownins, instance, ip, job, clsN/A
loki_log_messages_totalUnknownins, instance, ip, level, job, clsN/A
loki_logql_querystats_bytes_processed_per_seconds_bucketUnknownins, instance, range, ip, le, sharded, type, job, cls, status_code, latency_typeN/A
loki_logql_querystats_bytes_processed_per_seconds_countUnknownins, instance, range, ip, sharded, type, job, cls, status_code, latency_typeN/A
loki_logql_querystats_bytes_processed_per_seconds_sumUnknownins, instance, range, ip, sharded, type, job, cls, status_code, latency_typeN/A
loki_logql_querystats_chunk_download_latency_seconds_bucketUnknownins, instance, range, ip, le, type, job, cls, status_codeN/A
loki_logql_querystats_chunk_download_latency_seconds_countUnknownins, instance, range, ip, type, job, cls, status_codeN/A
loki_logql_querystats_chunk_download_latency_seconds_sumUnknownins, instance, range, ip, type, job, cls, status_codeN/A
loki_logql_querystats_downloaded_chunk_totalUnknownins, instance, range, ip, type, job, cls, status_codeN/A
loki_logql_querystats_duplicates_totalUnknownins, instance, ip, job, clsN/A
loki_logql_querystats_ingester_sent_lines_totalUnknownins, instance, ip, job, clsN/A
loki_logql_querystats_latency_seconds_bucketUnknownins, instance, range, ip, le, type, job, cls, status_codeN/A
loki_logql_querystats_latency_seconds_countUnknownins, instance, range, ip, type, job, cls, status_codeN/A
loki_logql_querystats_latency_seconds_sumUnknownins, instance, range, ip, type, job, cls, status_codeN/A
loki_panic_totalUnknownins, instance, ip, job, clsN/A
loki_querier_index_cache_corruptions_totalUnknownins, instance, ip, job, clsN/A
loki_querier_index_cache_encode_errors_totalUnknownins, instance, ip, job, clsN/A
loki_querier_index_cache_gets_totalUnknownins, instance, ip, job, clsN/A
loki_querier_index_cache_hits_totalUnknownins, instance, ip, job, clsN/A
loki_querier_index_cache_puts_totalUnknownins, instance, ip, job, clsN/A
loki_querier_query_frontend_clientsgaugeins, instance, ip, job, clsThe current number of clients connected to query-frontend.
loki_querier_query_frontend_request_duration_seconds_bucketUnknownins, instance, ip, le, operation, job, cls, status_codeN/A
loki_querier_query_frontend_request_duration_seconds_countUnknownins, instance, ip, operation, job, cls, status_codeN/A
loki_querier_query_frontend_request_duration_seconds_sumUnknownins, instance, ip, operation, job, cls, status_codeN/A
loki_querier_tail_activegaugeins, instance, ip, job, clsNumber of active tailers
loki_querier_tail_active_streamsgaugeins, instance, ip, job, clsNumber of active streams being tailed
loki_querier_tail_bytes_totalUnknownins, instance, ip, job, clsN/A
loki_querier_worker_concurrencygaugeins, instance, ip, job, clsNumber of concurrent querier workers
loki_querier_worker_inflight_queriesgaugeins, instance, ip, job, clsNumber of queries being processed by the querier workers
loki_query_frontend_log_result_cache_hit_totalUnknownins, instance, ip, job, clsN/A
loki_query_frontend_log_result_cache_miss_totalUnknownins, instance, ip, job, clsN/A
loki_query_frontend_partitions_bucketUnknownins, instance, ip, le, job, clsN/A
loki_query_frontend_partitions_countUnknownins, instance, ip, job, clsN/A
loki_query_frontend_partitions_sumUnknownins, instance, ip, job, clsN/A
loki_query_frontend_shard_factor_bucketUnknownins, instance, ip, le, mapper, job, clsN/A
loki_query_frontend_shard_factor_countUnknownins, instance, ip, mapper, job, clsN/A
loki_query_frontend_shard_factor_sumUnknownins, instance, ip, mapper, job, clsN/A
loki_query_scheduler_enqueue_countUnknownins, instance, ip, level, user, job, clsN/A
loki_rate_store_expired_streams_totalUnknownins, instance, ip, job, clsN/A
loki_rate_store_max_stream_rate_bytesgaugeins, instance, ip, job, clsThe maximum stream rate for any stream reported by ingesters during a sync operation. Sharded Streams are combined.
loki_rate_store_max_stream_shardsgaugeins, instance, ip, job, clsThe number of shards for a single stream reported by ingesters during a sync operation.
loki_rate_store_max_unique_stream_rate_bytesgaugeins, instance, ip, job, clsThe maximum stream rate for any stream reported by ingesters during a sync operation. Sharded Streams are considered separate.
loki_rate_store_stream_rate_bytes_bucketUnknownins, instance, ip, le, job, clsN/A
loki_rate_store_stream_rate_bytes_countUnknownins, instance, ip, job, clsN/A
loki_rate_store_stream_rate_bytes_sumUnknownins, instance, ip, job, clsN/A
loki_rate_store_stream_shards_bucketUnknownins, instance, ip, le, job, clsN/A
loki_rate_store_stream_shards_countUnknownins, instance, ip, job, clsN/A
loki_rate_store_stream_shards_sumUnknownins, instance, ip, job, clsN/A
loki_rate_store_streamsgaugeins, instance, ip, job, clsThe number of unique streams reported by all ingesters. Sharded streams are combined
loki_request_duration_seconds_bucketUnknownins, instance, method, ip, le, ws, route, job, cls, status_codeN/A
loki_request_duration_seconds_countUnknownins, instance, method, ip, ws, route, job, cls, status_codeN/A
loki_request_duration_seconds_sumUnknownins, instance, method, ip, ws, route, job, cls, status_codeN/A
loki_request_message_bytes_bucketUnknownins, instance, method, ip, le, route, job, clsN/A
loki_request_message_bytes_countUnknownins, instance, method, ip, route, job, clsN/A
loki_request_message_bytes_sumUnknownins, instance, method, ip, route, job, clsN/A
loki_response_message_bytes_bucketUnknownins, instance, method, ip, le, route, job, clsN/A
loki_response_message_bytes_countUnknownins, instance, method, ip, route, job, clsN/A
loki_response_message_bytes_sumUnknownins, instance, method, ip, route, job, clsN/A
loki_results_cache_version_comparisons_totalUnknownins, instance, ip, job, clsN/A
loki_store_chunks_downloaded_totalUnknownins, instance, ip, status, job, clsN/A
loki_store_chunks_per_batch_bucketUnknownins, instance, ip, le, status, job, clsN/A
loki_store_chunks_per_batch_countUnknownins, instance, ip, status, job, clsN/A
loki_store_chunks_per_batch_sumUnknownins, instance, ip, status, job, clsN/A
loki_store_series_totalUnknownins, instance, ip, status, job, clsN/A
loki_stream_sharding_countunknownins, instance, ip, job, clsTotal number of times the distributor has sharded streams
loki_tcp_connectionsgaugeins, instance, ip, protocol, job, clsCurrent number of accepted TCP connections.
loki_tcp_connections_limitgaugeins, instance, ip, protocol, job, clsThe max number of TCP connections that can be accepted (0 means no limit).
net_conntrack_dialer_conn_attempted_totalcounterins, instance, ip, dialer_name, job, clsTotal number of connections attempted by the given dialer a given name.
net_conntrack_dialer_conn_closed_totalcounterins, instance, ip, dialer_name, job, clsTotal number of connections closed which originated from the dialer of a given name.
net_conntrack_dialer_conn_established_totalcounterins, instance, ip, dialer_name, job, clsTotal number of connections successfully established by the given dialer a given name.
net_conntrack_dialer_conn_failed_totalcounterins, instance, ip, dialer_name, reason, job, clsTotal number of connections failed to dial by the dialer a given name.
net_conntrack_listener_conn_accepted_totalcounterins, instance, ip, listener_name, job, clsTotal number of connections opened to the listener of a given name.
net_conntrack_listener_conn_closed_totalcounterins, instance, ip, listener_name, job, clsTotal number of connections closed that were made to the listener of a given name.
nginx_connections_acceptedcounterins, instance, ip, job, clsAccepted client connections
nginx_connections_activegaugeins, instance, ip, job, clsActive client connections
nginx_connections_handledcounterins, instance, ip, job, clsHandled client connections
nginx_connections_readinggaugeins, instance, ip, job, clsConnections where NGINX is reading the request header
nginx_connections_waitinggaugeins, instance, ip, job, clsIdle client connections
nginx_connections_writinggaugeins, instance, ip, job, clsConnections where NGINX is writing the response back to the client
nginx_exporter_build_infogaugerevision, version, ins, instance, ip, tags, goarch, goversion, job, cls, branch, goosA metric with a constant ‘1’ value labeled by version, revision, branch, goversion from which nginx_exporter was built, and the goos and goarch for the build.
nginx_http_requests_totalcounterins, instance, ip, job, clsTotal http requests
nginx_upgaugeins, instance, ip, job, clsStatus of the last metric scrape
plugins_active_instancesgaugeins, instance, ip, job, clsThe number of active plugin instances
plugins_datasource_instances_totalUnknownins, instance, ip, job, clsN/A
process_cpu_seconds_totalcounterins, instance, ip, job, clsTotal user and system CPU time spent in seconds.
process_max_fdsgaugeins, instance, ip, job, clsMaximum number of open file descriptors.
process_open_fdsgaugeins, instance, ip, job, clsNumber of open file descriptors.
process_resident_memory_bytesgaugeins, instance, ip, job, clsResident memory size in bytes.
process_start_time_secondsgaugeins, instance, ip, job, clsStart time of the process since unix epoch in seconds.
process_virtual_memory_bytesgaugeins, instance, ip, job, clsVirtual memory size in bytes.
process_virtual_memory_max_bytesgaugeins, instance, ip, job, clsMaximum amount of virtual memory available in bytes.
prometheus_api_remote_read_queriesgaugeins, instance, ip, job, clsThe current number of remote read queries being executed or waiting.
prometheus_build_infogaugerevision, version, ins, instance, ip, tags, goarch, goversion, job, cls, branch, goosA metric with a constant ‘1’ value labeled by version, revision, branch, goversion from which prometheus was built, and the goos and goarch for the build.
prometheus_config_last_reload_success_timestamp_secondsgaugeins, instance, ip, job, clsTimestamp of the last successful configuration reload.
prometheus_config_last_reload_successfulgaugeins, instance, ip, job, clsWhether the last configuration reload attempt was successful.
prometheus_engine_queriesgaugeins, instance, ip, job, clsThe current number of queries being executed or waiting.
prometheus_engine_queries_concurrent_maxgaugeins, instance, ip, job, clsThe max number of concurrent queries.
prometheus_engine_query_duration_secondssummaryins, instance, ip, job, cls, quantile, sliceQuery timings
prometheus_engine_query_duration_seconds_countUnknownins, instance, ip, job, cls, sliceN/A
prometheus_engine_query_duration_seconds_sumUnknownins, instance, ip, job, cls, sliceN/A
prometheus_engine_query_log_enabledgaugeins, instance, ip, job, clsState of the query log.
prometheus_engine_query_log_failures_totalcounterins, instance, ip, job, clsThe number of query log failures.
prometheus_engine_query_samples_totalcounterins, instance, ip, job, clsThe total number of samples loaded by all queries.
prometheus_http_request_duration_seconds_bucketUnknownins, instance, ip, le, job, cls, handlerN/A
prometheus_http_request_duration_seconds_countUnknownins, instance, ip, job, cls, handlerN/A
prometheus_http_request_duration_seconds_sumUnknownins, instance, ip, job, cls, handlerN/A
prometheus_http_requests_totalcounterins, instance, ip, job, cls, code, handlerCounter of HTTP requests.
prometheus_http_response_size_bytes_bucketUnknownins, instance, ip, le, job, cls, handlerN/A
prometheus_http_response_size_bytes_countUnknownins, instance, ip, job, cls, handlerN/A
prometheus_http_response_size_bytes_sumUnknownins, instance, ip, job, cls, handlerN/A
prometheus_notifications_alertmanagers_discoveredgaugeins, instance, ip, job, clsThe number of alertmanagers discovered and active.
prometheus_notifications_dropped_totalcounterins, instance, ip, job, clsTotal number of alerts dropped due to errors when sending to Alertmanager.
prometheus_notifications_errors_totalcounterins, instance, ip, alertmanager, job, clsTotal number of errors sending alert notifications.
prometheus_notifications_latency_secondssummaryins, instance, ip, alertmanager, job, cls, quantileLatency quantiles for sending alert notifications.
prometheus_notifications_latency_seconds_countUnknownins, instance, ip, alertmanager, job, clsN/A
prometheus_notifications_latency_seconds_sumUnknownins, instance, ip, alertmanager, job, clsN/A
prometheus_notifications_queue_capacitygaugeins, instance, ip, job, clsThe capacity of the alert notifications queue.
prometheus_notifications_queue_lengthgaugeins, instance, ip, job, clsThe number of alert notifications in the queue.
prometheus_notifications_sent_totalcounterins, instance, ip, alertmanager, job, clsTotal number of alerts sent.
prometheus_readygaugeins, instance, ip, job, clsWhether Prometheus startup was fully completed and the server is ready for normal operation.
prometheus_remote_storage_exemplars_in_totalcounterins, instance, ip, job, clsExemplars in to remote storage, compare to exemplars out for queue managers.
prometheus_remote_storage_highest_timestamp_in_secondsgaugeins, instance, ip, job, clsHighest timestamp that has come into the remote storage via the Appender interface, in seconds since epoch.
prometheus_remote_storage_histograms_in_totalcounterins, instance, ip, job, clsHistogramSamples in to remote storage, compare to histograms out for queue managers.
prometheus_remote_storage_samples_in_totalcounterins, instance, ip, job, clsSamples in to remote storage, compare to samples out for queue managers.
prometheus_remote_storage_string_interner_zero_reference_releases_totalcounterins, instance, ip, job, clsThe number of times release has been called for strings that are not interned.
prometheus_rule_evaluation_duration_secondssummaryins, instance, ip, job, cls, quantileThe duration for a rule to execute.
prometheus_rule_evaluation_duration_seconds_countUnknownins, instance, ip, job, clsN/A
prometheus_rule_evaluation_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
prometheus_rule_evaluation_failures_totalcounterins, instance, ip, job, cls, rule_groupThe total number of rule evaluation failures.
prometheus_rule_evaluations_totalcounterins, instance, ip, job, cls, rule_groupThe total number of rule evaluations.
prometheus_rule_group_duration_secondssummaryins, instance, ip, job, cls, quantileThe duration of rule group evaluations.
prometheus_rule_group_duration_seconds_countUnknownins, instance, ip, job, clsN/A
prometheus_rule_group_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
prometheus_rule_group_interval_secondsgaugeins, instance, ip, job, cls, rule_groupThe interval of a rule group.
prometheus_rule_group_iterations_missed_totalcounterins, instance, ip, job, cls, rule_groupThe total number of rule group evaluations missed due to slow rule group evaluation.
prometheus_rule_group_iterations_totalcounterins, instance, ip, job, cls, rule_groupThe total number of scheduled rule group evaluations, whether executed or missed.
prometheus_rule_group_last_duration_secondsgaugeins, instance, ip, job, cls, rule_groupThe duration of the last rule group evaluation.
prometheus_rule_group_last_evaluation_samplesgaugeins, instance, ip, job, cls, rule_groupThe number of samples returned during the last rule group evaluation.
prometheus_rule_group_last_evaluation_timestamp_secondsgaugeins, instance, ip, job, cls, rule_groupThe timestamp of the last rule group evaluation in seconds.
prometheus_rule_group_rulesgaugeins, instance, ip, job, cls, rule_groupThe number of rules.
prometheus_sd_azure_cache_hit_totalcounterins, instance, ip, job, clsNumber of cache hit during refresh.
prometheus_sd_azure_failures_totalcounterins, instance, ip, job, clsNumber of Azure service discovery refresh failures.
prometheus_sd_consul_rpc_duration_secondssummaryendpoint, ins, instance, ip, job, cls, call, quantileThe duration of a Consul RPC call in seconds.
prometheus_sd_consul_rpc_duration_seconds_countUnknownendpoint, ins, instance, ip, job, cls, callN/A
prometheus_sd_consul_rpc_duration_seconds_sumUnknownendpoint, ins, instance, ip, job, cls, callN/A
prometheus_sd_consul_rpc_failures_totalcounterins, instance, ip, job, clsThe number of Consul RPC call failures.
prometheus_sd_discovered_targetsgaugeins, instance, ip, config, job, clsCurrent number of discovered targets.
prometheus_sd_dns_lookup_failures_totalcounterins, instance, ip, job, clsThe number of DNS-SD lookup failures.
prometheus_sd_dns_lookups_totalcounterins, instance, ip, job, clsThe number of DNS-SD lookups.
prometheus_sd_failed_configsgaugeins, instance, ip, job, clsCurrent number of service discovery configurations that failed to load.
prometheus_sd_file_mtime_secondsgaugeins, instance, ip, filename, job, clsTimestamp (mtime) of files read by FileSD. Timestamp is set at read time.
prometheus_sd_file_read_errors_totalcounterins, instance, ip, job, clsThe number of File-SD read errors.
prometheus_sd_file_scan_duration_secondssummaryins, instance, ip, job, cls, quantileThe duration of the File-SD scan in seconds.
prometheus_sd_file_scan_duration_seconds_countUnknownins, instance, ip, job, clsN/A
prometheus_sd_file_scan_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
prometheus_sd_file_watcher_errors_totalcounterins, instance, ip, job, clsThe number of File-SD errors caused by filesystem watch failures.
prometheus_sd_http_failures_totalcounterins, instance, ip, job, clsNumber of HTTP service discovery refresh failures.
prometheus_sd_kubernetes_events_totalcounterevent, ins, instance, role, ip, job, clsThe number of Kubernetes events handled.
prometheus_sd_kuma_fetch_duration_secondssummaryins, instance, ip, job, cls, quantileThe duration of a Kuma MADS fetch call.
prometheus_sd_kuma_fetch_duration_seconds_countUnknownins, instance, ip, job, clsN/A
prometheus_sd_kuma_fetch_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
prometheus_sd_kuma_fetch_failures_totalcounterins, instance, ip, job, clsThe number of Kuma MADS fetch call failures.
prometheus_sd_kuma_fetch_skipped_updates_totalcounterins, instance, ip, job, clsThe number of Kuma MADS fetch calls that result in no updates to the targets.
prometheus_sd_linode_failures_totalcounterins, instance, ip, job, clsNumber of Linode service discovery refresh failures.
prometheus_sd_nomad_failures_totalcounterins, instance, ip, job, clsNumber of nomad service discovery refresh failures.
prometheus_sd_received_updates_totalcounterins, instance, ip, job, clsTotal number of update events received from the SD providers.
prometheus_sd_updates_totalcounterins, instance, ip, job, clsTotal number of update events sent to the SD consumers.
prometheus_target_interval_length_secondssummaryins, instance, interval, ip, job, cls, quantileActual intervals between scrapes.
prometheus_target_interval_length_seconds_countUnknownins, instance, interval, ip, job, clsN/A
prometheus_target_interval_length_seconds_sumUnknownins, instance, interval, ip, job, clsN/A
prometheus_target_metadata_cache_bytesgaugeins, instance, ip, scrape_job, job, clsThe number of bytes that are currently used for storing metric metadata in the cache
prometheus_target_metadata_cache_entriesgaugeins, instance, ip, scrape_job, job, clsTotal number of metric metadata entries in the cache
prometheus_target_scrape_pool_exceeded_label_limits_totalcounterins, instance, ip, job, clsTotal number of times scrape pools hit the label limits, during sync or config reload.
prometheus_target_scrape_pool_exceeded_target_limit_totalcounterins, instance, ip, job, clsTotal number of times scrape pools hit the target limit, during sync or config reload.
prometheus_target_scrape_pool_reloads_failed_totalcounterins, instance, ip, job, clsTotal number of failed scrape pool reloads.
prometheus_target_scrape_pool_reloads_totalcounterins, instance, ip, job, clsTotal number of scrape pool reloads.
prometheus_target_scrape_pool_sync_totalcounterins, instance, ip, scrape_job, job, clsTotal number of syncs that were executed on a scrape pool.
prometheus_target_scrape_pool_target_limitgaugeins, instance, ip, scrape_job, job, clsMaximum number of targets allowed in this scrape pool.
prometheus_target_scrape_pool_targetsgaugeins, instance, ip, scrape_job, job, clsCurrent number of targets in this scrape pool.
prometheus_target_scrape_pools_failed_totalcounterins, instance, ip, job, clsTotal number of scrape pool creations that failed.
prometheus_target_scrape_pools_totalcounterins, instance, ip, job, clsTotal number of scrape pool creation attempts.
prometheus_target_scrapes_cache_flush_forced_totalcounterins, instance, ip, job, clsHow many times a scrape cache was flushed due to getting big while scrapes are failing.
prometheus_target_scrapes_exceeded_body_size_limit_totalcounterins, instance, ip, job, clsTotal number of scrapes that hit the body size limit
prometheus_target_scrapes_exceeded_native_histogram_bucket_limit_totalcounterins, instance, ip, job, clsTotal number of scrapes that hit the native histogram bucket limit and were rejected.
prometheus_target_scrapes_exceeded_sample_limit_totalcounterins, instance, ip, job, clsTotal number of scrapes that hit the sample limit and were rejected.
prometheus_target_scrapes_exemplar_out_of_order_totalcounterins, instance, ip, job, clsTotal number of exemplar rejected due to not being out of the expected order.
prometheus_target_scrapes_sample_duplicate_timestamp_totalcounterins, instance, ip, job, clsTotal number of samples rejected due to duplicate timestamps but different values.
prometheus_target_scrapes_sample_out_of_bounds_totalcounterins, instance, ip, job, clsTotal number of samples rejected due to timestamp falling outside of the time bounds.
prometheus_target_scrapes_sample_out_of_order_totalcounterins, instance, ip, job, clsTotal number of samples rejected due to not being out of the expected order.
prometheus_target_sync_failed_totalcounterins, instance, ip, scrape_job, job, clsTotal number of target sync failures.
prometheus_target_sync_length_secondssummaryins, instance, ip, scrape_job, job, cls, quantileActual interval to sync the scrape pool.
prometheus_target_sync_length_seconds_countUnknownins, instance, ip, scrape_job, job, clsN/A
prometheus_target_sync_length_seconds_sumUnknownins, instance, ip, scrape_job, job, clsN/A
prometheus_template_text_expansion_failures_totalcounterins, instance, ip, job, clsThe total number of template text expansion failures.
prometheus_template_text_expansions_totalcounterins, instance, ip, job, clsThe total number of template text expansions.
prometheus_treecache_watcher_goroutinesgaugeins, instance, ip, job, clsThe current number of watcher goroutines.
prometheus_treecache_zookeeper_failures_totalcounterins, instance, ip, job, clsThe total number of ZooKeeper failures.
prometheus_tsdb_blocks_loadedgaugeins, instance, ip, job, clsNumber of currently loaded data blocks
prometheus_tsdb_checkpoint_creations_failed_totalcounterins, instance, ip, job, clsTotal number of checkpoint creations that failed.
prometheus_tsdb_checkpoint_creations_totalcounterins, instance, ip, job, clsTotal number of checkpoint creations attempted.
prometheus_tsdb_checkpoint_deletions_failed_totalcounterins, instance, ip, job, clsTotal number of checkpoint deletions that failed.
prometheus_tsdb_checkpoint_deletions_totalcounterins, instance, ip, job, clsTotal number of checkpoint deletions attempted.
prometheus_tsdb_clean_startgaugeins, instance, ip, job, cls-1: lockfile is disabled. 0: a lockfile from a previous execution was replaced. 1: lockfile creation was clean
prometheus_tsdb_compaction_chunk_range_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
prometheus_tsdb_compaction_chunk_range_seconds_countUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_compaction_chunk_range_seconds_sumUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_compaction_chunk_samples_bucketUnknownins, instance, ip, le, job, clsN/A
prometheus_tsdb_compaction_chunk_samples_countUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_compaction_chunk_samples_sumUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_compaction_chunk_size_bytes_bucketUnknownins, instance, ip, le, job, clsN/A
prometheus_tsdb_compaction_chunk_size_bytes_countUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_compaction_chunk_size_bytes_sumUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_compaction_duration_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
prometheus_tsdb_compaction_duration_seconds_countUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_compaction_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_compaction_populating_blockgaugeins, instance, ip, job, clsSet to 1 when a block is currently being written to the disk.
prometheus_tsdb_compactions_failed_totalcounterins, instance, ip, job, clsTotal number of compactions that failed for the partition.
prometheus_tsdb_compactions_skipped_totalcounterins, instance, ip, job, clsTotal number of skipped compactions due to disabled auto compaction.
prometheus_tsdb_compactions_totalcounterins, instance, ip, job, clsTotal number of compactions that were executed for the partition.
prometheus_tsdb_compactions_triggered_totalcounterins, instance, ip, job, clsTotal number of triggered compactions for the partition.
prometheus_tsdb_data_replay_duration_secondsgaugeins, instance, ip, job, clsTime taken to replay the data on disk.
prometheus_tsdb_exemplar_exemplars_appended_totalcounterins, instance, ip, job, clsTotal number of appended exemplars.
prometheus_tsdb_exemplar_exemplars_in_storagegaugeins, instance, ip, job, clsNumber of exemplars currently in circular storage.
prometheus_tsdb_exemplar_last_exemplars_timestamp_secondsgaugeins, instance, ip, job, clsThe timestamp of the oldest exemplar stored in circular storage. Useful to check for what timerange the current exemplar buffer limit allows. This usually means the last timestampfor all exemplars for a typical setup. This is not true though if one of the series timestamp is in future compared to rest series.
prometheus_tsdb_exemplar_max_exemplarsgaugeins, instance, ip, job, clsTotal number of exemplars the exemplar storage can store, resizeable.
prometheus_tsdb_exemplar_out_of_order_exemplars_totalcounterins, instance, ip, job, clsTotal number of out of order exemplar ingestion failed attempts.
prometheus_tsdb_exemplar_series_with_exemplars_in_storagegaugeins, instance, ip, job, clsNumber of series with exemplars currently in circular storage.
prometheus_tsdb_head_active_appendersgaugeins, instance, ip, job, clsNumber of currently active appender transactions
prometheus_tsdb_head_chunksgaugeins, instance, ip, job, clsTotal number of chunks in the head block.
prometheus_tsdb_head_chunks_created_totalcounterins, instance, ip, job, clsTotal number of chunks created in the head
prometheus_tsdb_head_chunks_removed_totalcounterins, instance, ip, job, clsTotal number of chunks removed in the head
prometheus_tsdb_head_chunks_storage_size_bytesgaugeins, instance, ip, job, clsSize of the chunks_head directory.
prometheus_tsdb_head_gc_duration_seconds_countUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_head_gc_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_head_max_timegaugeins, instance, ip, job, clsMaximum timestamp of the head block. The unit is decided by the library consumer.
prometheus_tsdb_head_max_time_secondsgaugeins, instance, ip, job, clsMaximum timestamp of the head block.
prometheus_tsdb_head_min_timegaugeins, instance, ip, job, clsMinimum time bound of the head block. The unit is decided by the library consumer.
prometheus_tsdb_head_min_time_secondsgaugeins, instance, ip, job, clsMinimum time bound of the head block.
prometheus_tsdb_head_out_of_order_samples_appended_totalcounterins, instance, ip, job, clsTotal number of appended out of order samples.
prometheus_tsdb_head_samples_appended_totalcounterins, instance, ip, type, job, clsTotal number of appended samples.
prometheus_tsdb_head_seriesgaugeins, instance, ip, job, clsTotal number of series in the head block.
prometheus_tsdb_head_series_created_totalcounterins, instance, ip, job, clsTotal number of series created in the head
prometheus_tsdb_head_series_not_found_totalcounterins, instance, ip, job, clsTotal number of requests for series that were not found.
prometheus_tsdb_head_series_removed_totalcounterins, instance, ip, job, clsTotal number of series removed in the head
prometheus_tsdb_head_truncations_failed_totalcounterins, instance, ip, job, clsTotal number of head truncations that failed.
prometheus_tsdb_head_truncations_totalcounterins, instance, ip, job, clsTotal number of head truncations attempted.
prometheus_tsdb_isolation_high_watermarkgaugeins, instance, ip, job, clsThe highest TSDB append ID that has been given out.
prometheus_tsdb_isolation_low_watermarkgaugeins, instance, ip, job, clsThe lowest TSDB append ID that is still referenced.
prometheus_tsdb_lowest_timestampgaugeins, instance, ip, job, clsLowest timestamp value stored in the database. The unit is decided by the library consumer.
prometheus_tsdb_lowest_timestamp_secondsgaugeins, instance, ip, job, clsLowest timestamp value stored in the database.
prometheus_tsdb_mmap_chunk_corruptions_totalcounterins, instance, ip, job, clsTotal number of memory-mapped chunk corruptions.
prometheus_tsdb_mmap_chunks_totalcounterins, instance, ip, job, clsTotal number of chunks that were memory-mapped.
prometheus_tsdb_out_of_bound_samples_totalcounterins, instance, ip, type, job, clsTotal number of out of bound samples ingestion failed attempts with out of order support disabled.
prometheus_tsdb_out_of_order_samples_totalcounterins, instance, ip, type, job, clsTotal number of out of order samples ingestion failed attempts due to out of order being disabled.
prometheus_tsdb_reloads_failures_totalcounterins, instance, ip, job, clsNumber of times the database failed to reloadBlocks block data from disk.
prometheus_tsdb_reloads_totalcounterins, instance, ip, job, clsNumber of times the database reloaded block data from disk.
prometheus_tsdb_retention_limit_bytesgaugeins, instance, ip, job, clsMax number of bytes to be retained in the tsdb blocks, configured 0 means disabled
prometheus_tsdb_retention_limit_secondsgaugeins, instance, ip, job, clsHow long to retain samples in storage.
prometheus_tsdb_size_retentions_totalcounterins, instance, ip, job, clsThe number of times that blocks were deleted because the maximum number of bytes was exceeded.
prometheus_tsdb_snapshot_replay_error_totalcounterins, instance, ip, job, clsTotal number snapshot replays that failed.
prometheus_tsdb_storage_blocks_bytesgaugeins, instance, ip, job, clsThe number of bytes that are currently used for local storage by all blocks.
prometheus_tsdb_symbol_table_size_bytesgaugeins, instance, ip, job, clsSize of symbol table in memory for loaded blocks
prometheus_tsdb_time_retentions_totalcounterins, instance, ip, job, clsThe number of times that blocks were deleted because the maximum time limit was exceeded.
prometheus_tsdb_tombstone_cleanup_seconds_bucketUnknownins, instance, ip, le, job, clsN/A
prometheus_tsdb_tombstone_cleanup_seconds_countUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_tombstone_cleanup_seconds_sumUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_too_old_samples_totalcounterins, instance, ip, type, job, clsTotal number of out of order samples ingestion failed attempts with out of support enabled, but sample outside of time window.
prometheus_tsdb_vertical_compactions_totalcounterins, instance, ip, job, clsTotal number of compactions done on overlapping blocks.
prometheus_tsdb_wal_completed_pages_totalcounterins, instance, ip, job, clsTotal number of completed pages.
prometheus_tsdb_wal_corruptions_totalcounterins, instance, ip, job, clsTotal number of WAL corruptions.
prometheus_tsdb_wal_fsync_duration_secondssummaryins, instance, ip, job, cls, quantileDuration of write log fsync.
prometheus_tsdb_wal_fsync_duration_seconds_countUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_wal_fsync_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_wal_page_flushes_totalcounterins, instance, ip, job, clsTotal number of page flushes.
prometheus_tsdb_wal_segment_currentgaugeins, instance, ip, job, clsWrite log segment index that TSDB is currently writing to.
prometheus_tsdb_wal_storage_size_bytesgaugeins, instance, ip, job, clsSize of the write log directory.
prometheus_tsdb_wal_truncate_duration_seconds_countUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_wal_truncate_duration_seconds_sumUnknownins, instance, ip, job, clsN/A
prometheus_tsdb_wal_truncations_failed_totalcounterins, instance, ip, job, clsTotal number of write log truncations that failed.
prometheus_tsdb_wal_truncations_totalcounterins, instance, ip, job, clsTotal number of write log truncations attempted.
prometheus_tsdb_wal_writes_failed_totalcounterins, instance, ip, job, clsTotal number of write log writes that failed.
prometheus_web_federation_errors_totalcounterins, instance, ip, job, clsTotal number of errors that occurred while sending federation responses.
prometheus_web_federation_warnings_totalcounterins, instance, ip, job, clsTotal number of warnings that occurred while sending federation responses.
promhttp_metric_handler_requests_in_flightgaugeins, instance, ip, job, clsCurrent number of scrapes being served.
promhttp_metric_handler_requests_totalcounterins, instance, ip, job, cls, codeTotal number of scrapes by HTTP status code.
pushgateway_build_infogaugerevision, version, ins, instance, ip, tags, goarch, goversion, job, cls, branch, goosA metric with a constant ‘1’ value labeled by version, revision, branch, goversion from which pushgateway was built, and the goos and goarch for the build.
pushgateway_http_requests_totalcounterins, instance, method, ip, job, cls, code, handlerTotal HTTP requests processed by the Pushgateway, excluding scrapes.
querier_cache_added_new_totalUnknownins, instance, ip, job, cache, clsN/A
querier_cache_added_totalUnknownins, instance, ip, job, cache, clsN/A
querier_cache_entriesgaugeins, instance, ip, job, cache, clsThe total number of entries
querier_cache_evicted_totalUnknownins, instance, ip, job, reason, cache, clsN/A
querier_cache_gets_totalUnknownins, instance, ip, job, cache, clsN/A
querier_cache_memory_bytesgaugeins, instance, ip, job, cache, clsThe current cache size in bytes
querier_cache_misses_totalUnknownins, instance, ip, job, cache, clsN/A
querier_cache_stale_gets_totalUnknownins, instance, ip, job, cache, clsN/A
ring_member_heartbeats_totalUnknownins, instance, ip, job, clsN/A
ring_member_tokens_ownedgaugeins, instance, ip, job, clsThe number of tokens owned in the ring.
ring_member_tokens_to_owngaugeins, instance, ip, job, clsThe number of tokens to own in the ring.
scrape_duration_secondsUnknownins, instance, ip, job, clsN/A
scrape_samples_post_metric_relabelingUnknownins, instance, ip, job, clsN/A
scrape_samples_scrapedUnknownins, instance, ip, job, clsN/A
scrape_series_addedUnknownins, instance, ip, job, clsN/A
upUnknownins, instance, ip, job, clsN/A

PING Metrics

PING job has 54 metrics, provided by blackbox_exporter.

Metric NameTypeLabelsDescription
agent_upUnknownins, ip, job, instance, clsN/A
probe_dns_lookup_time_secondsgaugeins, ip, job, instance, clsReturns the time taken for probe dns lookup in seconds
probe_duration_secondsgaugeins, ip, job, instance, clsReturns how long the probe took to complete in seconds
probe_icmp_duration_secondsgaugeins, ip, job, phase, instance, clsDuration of icmp request by phase
probe_icmp_reply_hop_limitgaugeins, ip, job, instance, clsReplied packet hop limit (TTL for ipv4)
probe_ip_addr_hashgaugeins, ip, job, instance, clsSpecifies the hash of IP address. It’s useful to detect if the IP address changes.
probe_ip_protocolgaugeins, ip, job, instance, clsSpecifies whether probe ip protocol is IP4 or IP6
probe_successgaugeins, ip, job, instance, clsDisplays whether or not the probe was a success
scrape_duration_secondsUnknownins, ip, job, instance, clsN/A
scrape_samples_post_metric_relabelingUnknownins, ip, job, instance, clsN/A
scrape_samples_scrapedUnknownins, ip, job, instance, clsN/A
scrape_series_addedUnknownins, ip, job, instance, clsN/A
upUnknownins, ip, job, instance, clsN/A

PUSH Metrics

PushGateway provides 44 metrics.

Metric NameTypeLabelsDescription
agent_upUnknownjob, cls, instance, ins, ipN/A
go_gc_duration_secondssummaryjob, cls, instance, ins, quantile, ipA summary of the pause duration of garbage collection cycles.
go_gc_duration_seconds_countUnknownjob, cls, instance, ins, ipN/A
go_gc_duration_seconds_sumUnknownjob, cls, instance, ins, ipN/A
go_goroutinesgaugejob, cls, instance, ins, ipNumber of goroutines that currently exist.
go_infogaugejob, cls, instance, ins, ip, versionInformation about the Go environment.
go_memstats_alloc_bytescounterjob, cls, instance, ins, ipTotal number of bytes allocated, even if freed.
go_memstats_alloc_bytes_totalcounterjob, cls, instance, ins, ipTotal number of bytes allocated, even if freed.
go_memstats_buck_hash_sys_bytesgaugejob, cls, instance, ins, ipNumber of bytes used by the profiling bucket hash table.
go_memstats_frees_totalcounterjob, cls, instance, ins, ipTotal number of frees.
go_memstats_gc_sys_bytesgaugejob, cls, instance, ins, ipNumber of bytes used for garbage collection system metadata.
go_memstats_heap_alloc_bytesgaugejob, cls, instance, ins, ipNumber of heap bytes allocated and still in use.
go_memstats_heap_idle_bytesgaugejob, cls, instance, ins, ipNumber of heap bytes waiting to be used.
go_memstats_heap_inuse_bytesgaugejob, cls, instance, ins, ipNumber of heap bytes that are in use.
go_memstats_heap_objectsgaugejob, cls, instance, ins, ipNumber of allocated objects.
go_memstats_heap_released_bytesgaugejob, cls, instance, ins, ipNumber of heap bytes released to OS.
go_memstats_heap_sys_bytesgaugejob, cls, instance, ins, ipNumber of heap bytes obtained from system.
go_memstats_last_gc_time_secondsgaugejob, cls, instance, ins, ipNumber of seconds since 1970 of last garbage collection.
go_memstats_lookups_totalcounterjob, cls, instance, ins, ipTotal number of pointer lookups.
go_memstats_mallocs_totalcounterjob, cls, instance, ins, ipTotal number of mallocs.
go_memstats_mcache_inuse_bytesgaugejob, cls, instance, ins, ipNumber of bytes in use by mcache structures.
go_memstats_mcache_sys_bytesgaugejob, cls, instance, ins, ipNumber of bytes used for mcache structures obtained from system.
go_memstats_mspan_inuse_bytesgaugejob, cls, instance, ins, ipNumber of bytes in use by mspan structures.
go_memstats_mspan_sys_bytesgaugejob, cls, instance, ins, ipNumber of bytes used for mspan structures obtained from system.
go_memstats_next_gc_bytesgaugejob, cls, instance, ins, ipNumber of heap bytes when next garbage collection will take place.
go_memstats_other_sys_bytesgaugejob, cls, instance, ins, ipNumber of bytes used for other system allocations.
go_memstats_stack_inuse_bytesgaugejob, cls, instance, ins, ipNumber of bytes in use by the stack allocator.
go_memstats_stack_sys_bytesgaugejob, cls, instance, ins, ipNumber of bytes obtained from system for stack allocator.
go_memstats_sys_bytesgaugejob, cls, instance, ins, ipNumber of bytes obtained from system.
go_threadsgaugejob, cls, instance, ins, ipNumber of OS threads created.
process_cpu_seconds_totalcounterjob, cls, instance, ins, ipTotal user and system CPU time spent in seconds.
process_max_fdsgaugejob, cls, instance, ins, ipMaximum number of open file descriptors.
process_open_fdsgaugejob, cls, instance, ins, ipNumber of open file descriptors.
process_resident_memory_bytesgaugejob, cls, instance, ins, ipResident memory size in bytes.
process_start_time_secondsgaugejob, cls, instance, ins, ipStart time of the process since unix epoch in seconds.
process_virtual_memory_bytesgaugejob, cls, instance, ins, ipVirtual memory size in bytes.
process_virtual_memory_max_bytesgaugejob, cls, instance, ins, ipMaximum amount of virtual memory available in bytes.
pushgateway_build_infogaugejob, goversion, cls, branch, instance, tags, revision, goarch, ins, ip, version, goosA metric with a constant ‘1’ value labeled by version, revision, branch, goversion from which pushgateway was built, and the goos and goarch for the build.
pushgateway_http_requests_totalcounterjob, cls, method, code, handler, instance, ins, ipTotal HTTP requests processed by the Pushgateway, excluding scrapes.
scrape_duration_secondsUnknownjob, cls, instance, ins, ipN/A
scrape_samples_post_metric_relabelingUnknownjob, cls, instance, ins, ipN/A
scrape_samples_scrapedUnknownjob, cls, instance, ins, ipN/A
scrape_series_addedUnknownjob, cls, instance, ins, ipN/A
upUnknownjob, cls, instance, ins, ipN/A

11.7 - FAQ

Frequently asked questions about the Pigsty INFRA infrastructure module

What components are included in the INFRA module?

  • Ansible: Used for automation configuration, deployment, and daily operations.
  • Nginx: Exposes WebUIs like Grafana, VictoriaMetrics (VMUI), Alertmanager, and hosts local YUM/APT repositories.
  • Self-signed CA: Issues SSL/TLS certificates for components like Nginx, Patroni, pgBackRest.
  • VictoriaMetrics Suite: Replaces Prometheus/Loki, including VictoriaMetrics (TSDB), VMAlert (alert evaluation), VictoriaLogs (centralized logs), VictoriaTraces (tracing).
  • Vector: Node-side log collector, pushes system/database logs to VictoriaLogs.
  • AlertManager: Aggregates and dispatches alert notifications.
  • Grafana: Monitoring/visualization platform with numerous preconfigured dashboards and datasources.
  • Chronyd: Provides NTP time synchronization.
  • DNSMasq: Provides DNS registration and resolution.
  • ETCD: Acts as PostgreSQL HA DCS (can also be deployed on dedicated cluster).
  • PostgreSQL: Acts as CMDB on the admin node (optional).
  • Docker: Runs stateless tools or applications on nodes (optional).

How to re-register monitoring targets to VictoriaMetrics?

VictoriaMetrics uses static service discovery through the /infra/targets/<job>/*.yml directory. If target files are accidentally deleted, use the following commands to re-register:

./infra.yml  -t infra_register   # Re-render infra self-monitoring targets
./node.yml   -t node_register    # Re-render node / HAProxy / Vector targets
./etcd.yml   -t etcd_register    # Re-render etcd targets
./minio.yml  -t minio_register   # Re-render MinIO targets
./pgsql.yml  -t pg_register      # Re-render PGSQL/Patroni targets
./redis.yml  -t redis_register   # Re-render Redis targets

Other modules (like pg_monitor.yml, mongo.yml, mysql.yml) also provide corresponding *_register tags that can be executed as needed.


How to re-register PostgreSQL datasources to Grafana?

PGSQL databases defined in pg_databases are registered as Grafana datasources by default (for use by PGCAT applications).

If you accidentally delete postgres datasources registered in Grafana, you can register them again using the following command:

# Register all pgsql databases (defined in pg_databases) as grafana datasources
./pgsql.yml -t register_grafana

How to re-register node HAProxy admin pages to Nginx?

If you accidentally delete the registered haproxy proxy settings in /etc/nginx/conf.d/haproxy, you can restore them using the following command:

./node.yml -t register_nginx     # Register all haproxy admin page proxy settings to nginx on infra nodes

How to restore DNS registration records in DNSMASQ?

PGSQL cluster/instance domains are registered by default to /etc/hosts.d/<name> on infra nodes. You can restore them using the following command:

./pgsql.yml -t pg_dns    # Register pg DNS names to dnsmasq on infra nodes

How to expose new upstream services via Nginx?

Although you can access services directly via IP:Port, we still recommend consolidating access entry points by using domain names and accessing various WebUI services through Nginx proxy. This helps consolidate access, reduce exposed ports, and facilitate access control and auditing.

If you want to expose new WebUI services through the Nginx portal, you can add service definitions to the infra_portal parameter. For example, here’s the Infra portal configuration used by Pigsty’s official demo, exposing several additional services:

infra_portal:
  home         : { domain: home.pigsty.cc }
  grafana      : { domain: demo.pigsty.io ,endpoint: "${admin_ip}:3000" ,websocket: true }
  prometheus   : { domain: p.pigsty.cc ,endpoint: "${admin_ip}:8428" }
  alertmanager : { domain: a.pigsty.cc ,endpoint: "${admin_ip}:9059" }
  blackbox     : { endpoint: "${admin_ip}:9115" }
  vmalert      : { endpoint: "${admin_ip}:8880" }
  # Additional web portals
  minio        : { domain: sss.pigsty  ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
  postgrest    : { domain: api.pigsty.cc  ,endpoint: "127.0.0.1:8884"   }
  pgadmin      : { domain: adm.pigsty.cc  ,endpoint: "127.0.0.1:8885"   }
  pgweb        : { domain: cli.pigsty.cc  ,endpoint: "127.0.0.1:8886"   }
  bytebase     : { domain: ddl.pigsty.cc  ,endpoint: "127.0.0.1:8887"   }
  gitea        : { domain: git.pigsty.cc  ,endpoint: "127.0.0.1:8889"   }
  wiki         : { domain: wiki.pigsty.cc ,endpoint: "127.0.0.1:9002"   }
  noco         : { domain: noco.pigsty.cc ,endpoint: "127.0.0.1:9003"   }
  supa         : { domain: supa.pigsty.cc ,endpoint: "127.0.0.1:8000", websocket: true }

After completing the Nginx upstream service definition, use the following configuration and commands to register new services to Nginx.

./infra.yml -t nginx_config           # Regenerate Nginx configuration files
./infra.yml -t nginx_launch           # Update and apply Nginx configuration

# You can also manually reload Nginx config with Ansible
ansible infra -b -a 'nginx -s reload'  # Reload Nginx config

If you want HTTPS access, you must delete files/pki/csr/pigsty.csr and files/pki/nginx/pigsty.{key,crt} to force regeneration of Nginx SSL/TLS certificates to include new upstream domains. If you want to use certificates issued by an authoritative CA instead of Pigsty self-signed CA certificates, you can place them in the /etc/nginx/conf.d/cert/ directory and modify the corresponding configuration: /etc/nginx/conf.d/<name>.conf.


How to manually add upstream repo files to nodes?

Pigsty has a built-in wrapper script bin/repo-add that calls the ansible playbook node.yml to add repo files to corresponding nodes.

bin/repo-add <selector> [modules]
bin/repo-add 10.10.10.10           # Add node repo for node 10.10.10.10
bin/repo-add infra   node,infra    # Add node and infra repos for infra group
bin/repo-add infra   node,local    # Add node repo and local pigsty repo for infra group
bin/repo-add pg-test node,pgsql    # Add node and pgsql repos for pg-test group

11.8 - Administration

Infrastructure components and INFRA cluster administration SOP: create, destroy, scale out, scale in, certificates, repositories…

This section covers daily administration and operations for Pigsty deployments.


Create INFRA Module

Use infra.yml playbook to install INFRA module on infra group:

./infra.yml     # Install INFRA module on infra group

Uninstall INFRA Module

Use dedicated infra-rm.yml playbook to remove INFRA module from infra group:

./infra-rm.yml  # Remove INFRA module from infra group

Manage Local Repository

Pigsty includes local yum/apt repo for software packages. Manage repo configuration:

Repo Variables

VariableDescription
repo_enabledEnable local repo on node
repo_upstreamUpstream repos to include
repo_removeRemove upstream repos if true
repo_url_pkgExtra packages to download
repo_cleanClean repo cache (makecache)
repo_pkgPackages to include

Repo Tasks

./infra.yml -t repo              # Create or update repo

Repo location: /www/pigsty served by Nginx.

More: Configuration: INFRA - REPO

11.8.1 - Ansible

Using Ansible to run administration commands

Ansible is installed by default on all INFRA nodes and can be used to manage the entire deployment.

Pigsty implements automation based on Ansible, following the Infrastructure-as-Code philosophy.

Ansible knowledge is useful for managing databases and infrastructure, but not required. You only need to know how to execute Playbooks - YAML files that define a series of automated tasks.


Installation

Pigsty automatically installs ansible and its dependencies during the bootstrap process. For manual installation, use the following commands:

# Debian / Ubuntu
sudo apt install -y ansible python3-jmespath

# EL 10
sudo dnf install -y ansible python-jmespath

# EL 8/9
sudo dnf install -y ansible python3.12-jmespath

# EL 7
sudo yum install -y ansible python-jmespath

macOS

macOS users can install using Homebrew:

brew install ansible
pip3 install jmespath

Basic Usage

To run a playbook, simply execute ./path/to/playbook.yml. Here are the most commonly used Ansible command-line parameters:

PurposeParameterDescription
Where-l / --limit <pattern>Limit target hosts/groups/patterns
What-t / --tags <tags>Only run tasks with specified tags
How-e / --extra-vars <vars>Pass extra command-line variables
Config-i / --inventory <path>Specify inventory file path

Limiting Hosts

Use -l|--limit <pattern> to limit execution to specific groups, hosts, or patterns:

./node.yml                      # Execute on all nodes
./pgsql.yml -l pg-test          # Only execute on pg-test cluster
./pgsql.yml -l pg-*             # Execute on all clusters starting with pg-
./pgsql.yml -l 10.10.10.10      # Only execute on specific IP host

Running playbooks without host limits can be very dangerous! By default, most playbooks execute on all hosts. Use with caution!


Limiting Tasks

Use -t|--tags <tags> to only execute task subsets with specified tags:

./infra.yml -t repo           # Only execute tasks to create local repo
./infra.yml -t repo_upstream  # Only execute tasks to add upstream repos
./node.yml -t node_pkg        # Only execute tasks to install node packages
./pgsql.yml -t pg_hba         # Only execute tasks to render pg_hba.conf

Passing Variables

Use -e|--extra-vars <key=value> to override variables at runtime:

./pgsql.yml -e pg_clean=true         # Force clean existing PG instances
./pgsql-rm.yml -e pg_rm_pkg=false    # Keep packages when uninstalling
./node.yml -e '{"node_tune":"tiny"}' # Pass variables in JSON format
./pgsql.yml -e @/path/to/config.yml  # Load variables from YAML file

Specifying Inventory

By default, Ansible uses pigsty.yml in the current directory as the inventory. Use -i|--inventory <path> to specify a different config file:

./pgsql.yml -i files/pigsty/full.yml -l pg-test

[!NOTE]

To permanently change the default config file path, modify the inventory parameter in ansible.cfg.

11.8.2 - Playbooks

Built-in Ansible playbooks in Pigsty

Pigsty uses idempotent Ansible playbooks for management and control. Running playbooks requires ansible-playbook to be in the system PATH; users must first install Ansible before executing playbooks.

Available Playbooks

ModulePlaybookPurpose
INFRAinstall.ymlOne-click Pigsty installation
INFRAinfra.ymlInitialize Pigsty infrastructure on infra nodes
INFRAinfra-rm.ymlRemove infrastructure components from infra nodes
INFRAcache.ymlCreate offline installation packages from target nodes
INFRAcert.ymlIssue certificates using Pigsty self-signed CA
NODEnode.ymlInitialize nodes, configure to desired state
NODEnode-rm.ymlRemove nodes from Pigsty
PGSQLpgsql.ymlInitialize HA PostgreSQL cluster, or add new replica
PGSQLpgsql-rm.ymlRemove PostgreSQL cluster, or remove replica
PGSQLpgsql-db.ymlAdd new business database to existing cluster
PGSQLpgsql-user.ymlAdd new business user to existing cluster
PGSQLpgsql-pitr.ymlPerform point-in-time recovery (PITR) on cluster
PGSQLpgsql-monitor.ymlMonitor remote PostgreSQL using local exporters
PGSQLpgsql-migration.ymlGenerate migration manual and scripts for PostgreSQL
PGSQLslim.ymlInstall Pigsty with minimal components
REDISredis.ymlInitialize Redis cluster/node/instance
REDISredis-rm.ymlRemove Redis cluster/node/instance
ETCDetcd.ymlInitialize ETCD cluster, or add new member
ETCDetcd-rm.ymlRemove ETCD cluster, or remove existing member
MINIOminio.ymlInitialize MinIO cluster
MINIOminio-rm.ymlRemove MinIO cluster
DOCKERdocker.ymlInstall Docker on nodes
DOCKERapp.ymlInstall applications using Docker Compose
FERRETmongo.ymlInstall Mongo/FerretDB on nodes

Deployment Strategy

The install.yml playbook orchestrates specialized playbooks in the following group order for complete deployment:

  • infra: infra.yml (-l infra)
  • nodes: node.yml
  • etcd: etcd.yml (-l etcd)
  • minio: minio.yml (-l minio)
  • pgsql: pgsql.yml

Circular Dependency Note: There is a weak circular dependency between NODE and INFRA: to register NODE to INFRA, INFRA must already exist; while INFRA module depends on NODE to work. The solution is to initialize infra nodes first, then add other nodes. To complete all deployment at once, use install.yml.


Safety Notes

Most playbooks are idempotent, which means some deployment playbooks may wipe existing databases and create new ones when protection options are not enabled. Use extra caution with pgsql, minio, and infra playbooks. Read the documentation carefully and proceed with caution.

Best Practices

  1. Read playbook documentation carefully before execution
  2. Press Ctrl-C immediately to stop when anomalies occur
  3. Test in non-production environments first
  4. Use -l parameter to limit target hosts, avoiding unintended hosts
  5. Use -t parameter to specify tags, executing only specific tasks

Dry-Run Mode

Use --check --diff options to preview changes without actually executing:

# Preview changes without execution
./pgsql.yml -l pg-test --check --diff

# Check specific tasks with tags
./pgsql.yml -l pg-test -t pg_config --check --diff

11.8.3 - Nginx Management

Nginx management, web portal configuration, web server, upstream services

Pigsty installs Nginx on INFRA nodes as the entry point for all web services, listening on standard ports 80/443.

In Pigsty, you can configure Nginx to provide various services through inventory:

  • Expose web interfaces for monitoring components like Grafana, VictoriaMetrics (VMUI), Alertmanager, and VictoriaLogs
  • Serve static files (software repos, documentation sites, websites, etc.)
  • Proxy custom application services (internal apps, database management UIs, Docker application interfaces, etc.)
  • Automatically issue self-signed HTTPS certificates, or use Certbot to obtain free Let’s Encrypt certificates
  • Expose services through a single port using different subdomains for unified access

Basic Configuration

Customize Nginx behavior via infra_portal parameter:

infra_portal:
  home: { domain: i.pigsty }
  grafana      : { domain: g.pigsty ,endpoint: "${admin_ip}:3000" , websocket: true }
  prometheus   : { domain: p.pigsty ,endpoint: "${admin_ip}:8428" }
  alertmanager : { domain: a.pigsty ,endpoint: "${admin_ip}:9059" }
  blackbox     : { endpoint: "${admin_ip}:9115" }
  vmalert      : { endpoint: "${admin_ip}:8880" }

Server Parameters

ParameterDescription

11.8.4 - Software Repository

Managing local APT/YUM software repositories

Pigsty supports creating and managing local APT/YUM software repositories for offline deployment or accelerated package installation.


Quick Start

To add packages to the local repository:

  1. Add packages to repo_packages (default packages)
  2. Add packages to repo_extra_packages (extra packages)
  3. Run the build command:
./infra.yml -t repo_build   # Build local repo from upstream
./node.yml -t node_repo     # Refresh node repository cache

Package Aliases

Pigsty predefines common package combinations for batch installation:

EL Systems (RHEL/CentOS/Rocky)

AliasDescription
node-bootstrapAnsible, Python3 tools, SSH related
infra-packageNginx, etcd, HAProxy, monitoring exporters, MinIO
pgsql-utilityPatroni, pgBouncer, pgBackRest, PG tools
pgsqlFull PostgreSQL (server, client, extensions)
pgsql-miniMinimal PostgreSQL installation

Debian/Ubuntu Systems

AliasDescription
node-bootstrapAnsible, development tools
infra-packageInfrastructure components (Debian naming)
pgsql-clientPostgreSQL client
pgsql-serverPostgreSQL server and related packages

Playbook Tasks

Main Tasks

TaskDescription
repoCreate local repo from internet or offline packages
repo_buildBuild from upstream if not exists
repo_upstreamAdd upstream repository files
repo_pkgDownload packages and dependencies
repo_createCreate/update YUM or APT repository
repo_nginxStart Nginx file server

Complete Task List

./infra.yml -t repo_dir          # Create local repository directory
./infra.yml -t repo_check        # Check if local repo exists
./infra.yml -t repo_prepare      # Use existing repo directly
./infra.yml -t repo_build        # Build repo from upstream
./infra.yml -t repo_upstream     # Add upstream repositories
./infra.yml -t repo_remove       # Delete existing repo files
./infra.yml -t repo_add          # Add repo to system directory
./infra.yml -t repo_url_pkg      # Download packages from internet
./infra.yml -t repo_cache        # Create metadata cache
./infra.yml -t repo_boot_pkg     # Install bootstrap packages
./infra.yml -t repo_pkg          # Download packages and dependencies
./infra.yml -t repo_create       # Create local repository
./infra.yml -t repo_use          # Add new repo to system
./infra.yml -t repo_nginx        # Start Nginx file server

Common Operations

Add New Packages

# 1. Configure upstream repositories
./infra.yml -t repo_upstream

# 2. Download packages and dependencies
./infra.yml -t repo_pkg

# 3. Build local repository metadata
./infra.yml -t repo_create

Refresh Node Repositories

./node.yml -t node_repo    # Refresh repository cache on all nodes

Complete Repository Rebuild

./infra.yml -t repo        # Create repo from internet or offline packages

11.8.5 - Domain Management

Configure local or public domain names to access Pigsty services.

Use domain names instead of IP addresses to access Pigsty’s various web services.

Quick Start

Add the following static resolution records to /etc/hosts:

10.10.10.10 i.pigsty g.pigsty a.pigsty

Replace IP address with your actual Pigsty node’s IP.


Why Use Domain Names

  • Easier to remember than IP addresses
  • Flexible pointing to different IPs
  • Unified service management through Nginx
  • Support for HTTPS encryption
  • Prevent ISP hijacking in some regions
  • Allow access to internally bound services via proxy

DNS Mechanism

  • DNS Protocol: Resolves domain names to IP addresses. Multiple domains can point to same IP.

  • HTTP Protocol: Uses Host header to route requests to different sites on same port (80/443).


Default Domains

11.8.6 - Module Management

INFRA module management SOP: define, create, destroy, scale out, scale in

This document covers daily management operations for the INFRA module, including installation, uninstallation, scaling, and component maintenance.


Install INFRA Module

Use the infra.yml playbook to install the INFRA module on the infra group:

./infra.yml     # Install INFRA module on infra group

Uninstall INFRA Module

Use the infra-rm.yml playbook to uninstall the INFRA module from the infra group:

./infra-rm.yml  # Uninstall INFRA module from infra group

Scale Out INFRA Module

Assign infra_seq to new nodes and add them to the infra group in the inventory:

all:
  children:
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }  # Existing node
        10.10.10.11: { infra_seq: 2 }  # New node

Use the -l limit option to execute the playbook on the new node only:

./infra.yml -l 10.10.10.11    # Install INFRA module on new node

Manage Local Repository

Local repository management tasks:

./infra.yml -t repo              # Create repo from internet or offline packages
./infra.yml -t repo_upstream     # Add upstream repositories
./infra.yml -t repo_pkg          # Download packages and dependencies
./infra.yml -t repo_create       # Create local yum/apt repository

Complete subtask list:

./infra.yml -t repo_dir          # Create local repository directory
./infra.yml -t repo_check        # Check if local repo exists
./infra.yml -t repo_prepare      # Use existing repo directly
./infra.yml -t repo_build        # Build repo from upstream
./infra.yml -t repo_upstream     # Add upstream repositories
./infra.yml -t repo_remove       # Delete existing repo files
./infra.yml -t repo_add          # Add repo to system directory
./infra.yml -t repo_url_pkg      # Download packages from internet
./infra.yml -t repo_cache        # Create metadata cache
./infra.yml -t repo_boot_pkg     # Install bootstrap packages
./infra.yml -t repo_pkg          # Download packages and dependencies
./infra.yml -t repo_create       # Create local repository
./infra.yml -t repo_use          # Add new repo to system
./infra.yml -t repo_nginx        # Start Nginx file server

Manage Nginx

Nginx management tasks:

./infra.yml -t nginx                       # Reset Nginx component
./infra.yml -t nginx_index                 # Re-render homepage
./infra.yml -t nginx_config,nginx_reload   # Re-render config and reload

Request HTTPS certificate:

./infra.yml -t nginx_certbot,nginx_reload -e certbot_sign=true

Manage Infrastructure Components

Management commands for various infrastructure components:

./infra.yml -t infra           # Configure infrastructure
./infra.yml -t infra_env       # Configure environment variables
./infra.yml -t infra_pkg       # Install packages
./infra.yml -t infra_user      # Set up OS user
./infra.yml -t infra_cert      # Issue certificates
./infra.yml -t dns             # Configure DNSMasq
./infra.yml -t nginx           # Configure Nginx
./infra.yml -t victoria        # Configure VictoriaMetrics/Logs/Traces
./infra.yml -t alertmanager    # Configure AlertManager
./infra.yml -t blackbox        # Configure Blackbox Exporter
./infra.yml -t grafana         # Configure Grafana
./infra.yml -t infra_register  # Register to VictoriaMetrics/Grafana

Common maintenance commands:

./infra.yml -t nginx_index                        # Re-render homepage
./infra.yml -t nginx_config,nginx_reload          # Reconfigure and reload
./infra.yml -t vmetrics_config,vmetrics_launch    # Regenerate VictoriaMetrics config and restart
./infra.yml -t vlogs_config,vlogs_launch          # Update VictoriaLogs config
./infra.yml -t grafana_plugin                     # Download Grafana plugins

11.8.7 - CA and Certificates

Using self-signed CA or real HTTPS certificates

Pigsty uses a self-signed Certificate Authority (CA) by default for internal SSL/TLS encryption. This document covers:


Self-Signed CA

Pigsty automatically creates a self-signed CA during infrastructure initialization (infra.yml). The CA signs certificates for:

  • PostgreSQL server/client SSL
  • Patroni REST API
  • etcd cluster communication
  • MinIO cluster communication
  • Nginx HTTPS (fallback)
  • Infrastructure services

PKI Directory Structure

files/pki/
├── ca/
│   ├── ca.key                # CA private key (keep secure!)
│   └── ca.crt                # CA certificate
├── csr/                      # Certificate signing requests
│   ├── misc/                     # Miscellaneous certificates (cert.yml output)
│   ├── etcd/                     # ETCD certificates
│   ├── pgsql/                    # PostgreSQL certificates
│   ├── minio/                    # MinIO certificates
│   ├── nginx/                    # Nginx certificates
│   └── mongo/                    # FerretDB certificates
└── infra/                    # Infrastructure certificates

CA Variables

VariableDefaultDescription
ca_createtrueCreate CA if not exists, or abort
ca_cnpigsty-caCA certificate common name
cert_validity7300dDefault validity for issued certificates
VariableDefault
:—————-————–—————————————-
CA Certificate100 yearsHardcoded (36500 days)
Server/Client20 yearscert_validity (7300d)
Nginx HTTPS~1 yearnginx_cert_validity (397d)
> Note: Browser vendors limit trust to 398-day certificates. Nginx uses shorter validity for browser compatibility.

Using External CA

To use your own enterprise CA instead of auto-generated one:

1. Set ca_create: false in your configuration.

2. Place your CA files before running playbook:

mkdir -p files/pki/ca
cp /path/to/your/ca.key files/pki/ca/ca.key
cp /path/to/your/ca.crt files/pki/ca/ca.crt
chmod 600 files/pki/ca/ca.key
chmod 644 files/pki/ca/ca.crt

3. Run ./infra.yml


Backup CA Files

The CA private key is critical. Back it up securely:

# Backup with timestamp
tar -czvf pigsty-ca-$(date +%Y%m%d).tar.gz files/pki/ca/

Warning: If you lose CA private key, all certificates signed by it become unverifiable. You’ll need to regenerate everything.


Issue Certificates

Use cert.yml to issue additional certificates signed by Pigsty CA.

Basic Usage

# Issue certificate for database user (client cert)
./cert.yml -e cn=dbuser_dba

# Issue certificate for monitor user
./cert.yml -e cn=dbuser_monitor

Certificates generated in files/pki/misc/<cn>.{key,crt} by default.

Parameters

ParameterDefaultDescription
cnpigstyCommon Name (required)
san[DNS:localhost, IP:127.0.0.1]Subject Alternative Names
orgpigstyOrganization name
unitpigstyOrganizational unit name
expire7300dCertificate validity (20 years)
keyfiles/pki/misc/<cn>.keyPrivate key output path
crtfiles/pki/misc/<cn>.crtCertificate output path

Advanced Examples

# Issue certificate with custom SAN (DNS and IP)
./cert.yml -e cn=myservice -e san=DNS:myservice,IP:10.2.82.163

(File has more lines. Use ‘offset’ parameter to read beyond line 130)

12 - Module: NODE

Tune nodes into the desired state and monitor it, manage node, VIP, HAProxy, and exporters.

Tune nodes into the desired state and monitor it, manage node, VIP, HAProxy, and exporters.

12.1 - Configuration

Configure node identity, cluster, and identity borrowing from PostgreSQL

Pigsty uses IP address as the unique identifier for nodes. This IP should be the internal IP address on which the database instance listens and provides external services.

node-test:
  hosts:
    10.10.10.11: { nodename: node-test-1 }
    10.10.10.12: { nodename: node-test-2 }
    10.10.10.13: { nodename: node-test-3 }
  vars:
    node_cluster: node-test

This IP address must be the address on which the database instance listens and provides external services, but should not be a public IP address. That said, you don’t necessarily have to connect to the database via this IP. For example, managing target nodes indirectly through SSH tunnels or jump hosts is also feasible. However, when identifying database nodes, the primary IPv4 address remains the node’s core identifier. This is critical, and you should ensure this during configuration.

The IP address is the inventory_hostname in the inventory, represented as the key in the <cluster>.hosts object. In addition, each node has two optional identity parameters:

NameTypeLevelNecessityComment
inventory_hostnameip-RequiredNode IP
nodenamestringIOptionalNode Name
node_clusterstringCOptionalNode cluster name

The parameters nodename and node_cluster are optional. If not provided, the node’s existing hostname and the fixed value nodes will be used as defaults. In Pigsty’s monitoring system, these two will be used as the node’s cluster identifier (cls) and instance identifier (ins).

For PGSQL nodes, because Pigsty defaults to a 1:1 exclusive deployment of PG to node, you can use the node_id_from_pg parameter to borrow the PostgreSQL instance’s identity parameters (pg_cluster and pg_seq) for the node’s ins and cls labels. This allows database and node monitoring metrics to share the same labels for cross-analysis.

#nodename:                # [instance] # node instance identity, uses existing hostname if missing, optional
node_cluster: nodes       # [cluster] # node cluster identity, uses 'nodes' if missing, optional
nodename_overwrite: true          # overwrite node's hostname with nodename?
nodename_exchange: false          # exchange nodename among play hosts?
node_id_from_pg: true             # borrow postgres identity as node identity if applicable?

You can also configure rich functionality for host clusters. For example, use HAProxy on the node cluster for load balancing and service exposure, or bind an L2 VIP to the cluster.

12.2 - Parameters

NODE module provides 11 sections with 83 parameters

The NODE module tunes target nodes into the desired state and integrates them into the Pigsty monitoring system.


Parameter SectionDescription
NODE_IDNode identity parameters
NODE_DNSNode DNS resolution
NODE_PACKAGEUpstream repo & package install
NODE_TUNENode tuning & kernel features
NODE_SECNode security configurations
NODE_ADMINAdmin user & SSH keys
NODE_TIMETimezone, NTP, crontab
NODE_VIPOptional L2 VIP for cluster
HAPROXYHAProxy load balancer
NODE_EXPORTERNode monitoring exporter
VECTORVector log collector

Parameters Overview

NODE_ID section defines node identity parameters, including node name, cluster name, and whether to borrow identity from PostgreSQL.

ParameterTypeLevelDescription
nodenamestringInode instance identity, use hostname if missing
node_clusterstringCnode cluster identity, use ’nodes’ if missing
nodename_overwriteboolCoverwrite node’s hostname with nodename?
nodename_exchangeboolCexchange nodename among play hosts?
node_id_from_pgboolCuse postgres identity as node identity if applicable?

NODE_DNS section configures node DNS resolution, including static hosts records and dynamic DNS servers.

ParameterTypeLevelDescription
node_write_etc_hostsboolG/C/Imodify /etc/hosts on target node?
node_default_etc_hostsstring[]Gstatic dns records in /etc/hosts
node_etc_hostsstring[]Cextra static dns records in /etc/hosts
node_dns_methodenumChow to handle dns servers: add,none,overwrite
node_dns_serversstring[]Cdynamic nameserver in /etc/resolv.conf
node_dns_optionsstring[]Cdns resolv options in /etc/resolv.conf

NODE_PACKAGE section configures node software repositories and package installation.

ParameterTypeLevelDescription
node_repo_modulesenumCwhich repo modules to enable on node? local default
node_repo_removeboolCremove existing repo on node when configuring?
node_packagesstring[]Cpackages to be installed on current nodes
node_default_packagesstring[]Gdefault packages to be installed on all nodes

NODE_TUNE section configures node kernel parameters, feature toggles, and tuning templates.

ParameterTypeLevelDescription
node_disable_numaboolCdisable node numa, reboot required
node_disable_swapboolCdisable node swap, use with caution
node_static_networkboolCpreserve dns resolver settings after reboot
node_disk_prefetchboolCsetup disk prefetch on HDD to increase performance
node_kernel_modulesstring[]Ckernel modules to be enabled on this node
node_hugepage_countintCnumber of 2MB hugepage, take precedence over ratio
node_hugepage_ratiofloatCnode mem hugepage ratio, 0 disable it by default
node_overcommit_ratiofloatCnode mem overcommit ratio (50-100), 0 disable it
node_tuneenumCnode tuned profile: none,oltp,olap,crit,tiny
node_sysctl_paramsdictCextra sysctl parameters in k:v format

NODE_SEC section configures node security options, including SELinux and firewall.

ParameterTypeLevelDescription
node_selinux_modeenumCSELinux mode: disabled, permissive, enforcing
node_firewall_modeenumCfirewall mode: off, none, zone
node_firewall_intranetcidr[]Cintranet CIDR list for firewall rules
node_firewall_public_portport[]Cpublic exposed port list, default [22, 80, 443, 5432]

NODE_ADMIN section configures admin user, data directory, and shell aliases.

ParameterTypeLevelDescription
node_datapathCnode main data directory, /data by default
node_admin_enabledboolCcreate a admin user on target node?
node_admin_uidintCuid and gid for node admin user
node_admin_usernameusernameCname of node admin user, dba by default
node_admin_sudoenumCadmin sudo privilege: limited, nopass, all, none
node_admin_ssh_exchangeboolCexchange admin ssh key among node cluster
node_admin_pk_currentboolCadd current user’s ssh pk to admin authorized_keys
node_admin_pk_liststring[]Cssh public keys to be added to admin user
node_aliasesdictCshell aliases in K:V dict format

NODE_TIME section configures timezone, NTP time sync, and crontab.

ParameterTypeLevelDescription
node_timezonestringCsetup node timezone, empty string to skip
node_ntp_enabledboolCenable chronyd time sync service?
node_ntp_serversstring[]Cntp servers in /etc/chrony.conf
node_crontab_overwriteboolCoverwrite or append to /etc/crontab?
node_crontabstring[]Ccrontab entries in /etc/crontab

NODE_VIP section configures L2 VIP for node cluster, implemented by keepalived.

ParameterTypeLevelDescription
vip_enabledboolCenable L2 vip on this node cluster?
vip_addressipCnode vip address in ipv4 format, required if enabled
vip_vridintCinteger 1-254, should be unique in same VLAN
vip_roleenumIoptional, master/backup, backup by default
vip_preemptboolC/Ioptional, true/false, enable vip preemption
vip_interfacestringC/Inode vip network interface, eth0 by default
vip_dns_suffixstringCnode vip dns name suffix, empty string by default
vip_auth_passpasswordCvrrp authentication password, auto-generated if empty
vip_exporter_portportCkeepalived exporter listen port, 9650 by default

HAPROXY section configures HAProxy load balancer and service exposure.

ParameterTypeLevelDescription
haproxy_enabledboolCenable haproxy on this node?
haproxy_cleanboolG/C/Acleanup all existing haproxy config?
haproxy_reloadboolAreload haproxy after config?
haproxy_auth_enabledboolGenable authentication for admin page
haproxy_admin_usernameusernameGhaproxy admin username, admin default
haproxy_admin_passwordpasswordGhaproxy admin password, pigsty default
haproxy_exporter_portportChaproxy exporter port, 9101 by default
haproxy_client_timeoutintervalCclient connection timeout, 24h default
haproxy_server_timeoutintervalCserver connection timeout, 24h default
haproxy_servicesservice[]Clist of haproxy services to expose

NODE_EXPORTER section configures node monitoring exporter.

ParameterTypeLevelDescription
node_exporter_enabledboolCsetup node_exporter on this node?
node_exporter_portportCnode exporter listen port, 9100 default
node_exporter_optionsargCextra server options for node_exporter

VECTOR section configures Vector log collector.

ParameterTypeLevelDescription
vector_enabledboolCenable vector log collector?
vector_cleanboolG/Apurge vector data dir during init?
vector_datapathCvector data directory, /data/vector default
vector_portportCvector metrics listen port, 9598 default
vector_read_fromenumCread log from beginning or end
vector_log_endpointstring[]Clog endpoint, default send to infra group

NODE_ID

Each node has identity parameters that are configured through the parameters in <cluster>.hosts and <cluster>.vars.

Pigsty uses IP address as the unique identifier for database nodes. This IP address must be the one that the database instance listens on and provides services, but should not be a public IP address. However, users don’t have to connect to the database via this IP address. For example, managing target nodes indirectly through SSH tunnels or jump servers is feasible. When identifying database nodes, the primary IPv4 address remains the core identifier. This is very important, and users should ensure this when configuring. The IP address is the inventory_hostname in the inventory, which is the key of the <cluster>.hosts object.

node-test:
  hosts:
    10.10.10.11: { nodename: node-test-1 }
    10.10.10.12: { nodename: node-test-2 }
    10.10.10.13: { nodename: node-test-3 }
  vars:
    node_cluster: node-test

In addition, nodes have two important identity parameters in the Pigsty monitoring system: nodename and node_cluster, which are used as the instance identity (ins) and cluster identity (cls) in the monitoring system.

node_load1{cls="pg-meta", ins="pg-meta-1", ip="10.10.10.10", job="nodes"}
node_load1{cls="pg-test", ins="pg-test-1", ip="10.10.10.11", job="nodes"}
node_load1{cls="pg-test", ins="pg-test-2", ip="10.10.10.12", job="nodes"}
node_load1{cls="pg-test", ins="pg-test-3", ip="10.10.10.13", job="nodes"}

When executing the default PostgreSQL deployment, since Pigsty uses exclusive 1:1 deployment by default, you can borrow the database instance’s identity parameters (pg_cluster) to the node’s ins and cls labels through the node_id_from_pg parameter.

NameTypeLevelRequiredDescription
inventory_hostnameip-RequiredNode IP Address
nodenamestringIOptionalNode Name
node_clusterstringCOptionalNode Cluster Name
#nodename:                # [instance] # node instance identity, use hostname if missing, optional
node_cluster: nodes       # [cluster] # node cluster identity, use 'nodes' if missing, optional
nodename_overwrite: true          # overwrite node's hostname with nodename?
nodename_exchange: false          # exchange nodename among play hosts?
node_id_from_pg: true             # use postgres identity as node identity if applicable?

nodename

name: nodename, type: string, level: I

Node instance identity parameter. If not explicitly set, the existing hostname will be used as the node name. This parameter is optional since it has a reasonable default value.

If node_id_from_pg is enabled (default), and nodename is not explicitly specified, nodename will try to use ${pg_cluster}-${pg_seq} as the instance identity. If the PGSQL module is not defined on this cluster, it will fall back to the default, which is the node’s HOSTNAME.

node_cluster

name: node_cluster, type: string, level: C

This option allows explicitly specifying a cluster name for the node, which is only meaningful when defined at the node cluster level. Using the default empty value will use the fixed value nodes as the node cluster identity.

If node_id_from_pg is enabled (default), and node_cluster is not explicitly specified, node_cluster will try to use ${pg_cluster} as the cluster identity. If the PGSQL module is not defined on this cluster, it will fall back to the default nodes.

nodename_overwrite

name: nodename_overwrite, type: bool, level: C

Overwrite node’s hostname with nodename? Default is true. In this case, if you set a non-empty nodename, it will be used as the current host’s HOSTNAME.

When nodename is empty, if node_id_from_pg is true (default), Pigsty will try to borrow the identity parameters of the PostgreSQL instance defined 1:1 on the node as the node name, i.e., {{ pg_cluster }}-{{ pg_seq }}. If the PGSQL module is not installed on this node, it will fall back to not doing anything.

Therefore, if you leave nodename empty and don’t enable node_id_from_pg, Pigsty will not make any changes to the existing hostname.

nodename_exchange

name: nodename_exchange, type: bool, level: C

Exchange nodename among play hosts? Default is false.

When enabled, nodes executing the node.yml playbook in the same batch will exchange node names with each other, writing them to /etc/hosts.

node_id_from_pg

name: node_id_from_pg, type: bool, level: C

Borrow identity parameters from the PostgreSQL instance/cluster deployed 1:1 on the node? Default is true.

PostgreSQL instances and nodes in Pigsty use 1:1 deployment by default, so you can “borrow” identity parameters from the database instance. This parameter is enabled by default, meaning that if a PostgreSQL cluster has no special configuration, the host node cluster and instance identity parameters will default to matching the database identity parameters. This provides extra convenience for problem analysis and monitoring data processing.


NODE_DNS

Pigsty configures static DNS records and dynamic DNS servers for nodes.

If your node provider has already configured DNS servers for you, you can set node_dns_method to none to skip DNS setup.

node_write_etc_hosts: true        # modify `/etc/hosts` on target node?
node_default_etc_hosts:           # static dns records in `/etc/hosts`
  - "${admin_ip} i.pigsty"
node_etc_hosts: []                # extra static dns records in `/etc/hosts`
node_dns_method: add              # how to handle dns servers: add,none,overwrite
node_dns_servers: ['${admin_ip}'] # dynamic nameserver in `/etc/resolv.conf`
node_dns_options:                 # dns resolv options in `/etc/resolv.conf`
  - options single-request-reopen timeout:1

node_write_etc_hosts

name: node_write_etc_hosts, type: bool, level: G|C|I

Modify /etc/hosts on target node? For example, in container environments, this file usually cannot be modified.

node_default_etc_hosts

name: node_default_etc_hosts, type: string[], level: G

Static DNS records to be written to all nodes’ /etc/hosts. Default value:

["${admin_ip} i.pigsty"]

node_default_etc_hosts is an array. Each element is a DNS record with format <ip> <name>. You can specify multiple domain names separated by spaces.

This parameter is used to configure global static DNS records. If you want to configure specific static DNS records for individual clusters and instances, use the node_etc_hosts parameter.

node_etc_hosts

name: node_etc_hosts, type: string[], level: C

Extra static DNS records to write to node’s /etc/hosts. Default is [] (empty array).

Same format as node_default_etc_hosts, but suitable for configuration at the cluster/instance level.

node_dns_method

name: node_dns_method, type: enum, level: C

How to configure DNS servers? Three options: add, none, overwrite. Default is add.

  • add: Append the records in node_dns_servers to /etc/resolv.conf and keep existing DNS servers. (default)
  • overwrite: Overwrite /etc/resolv.conf with the records in node_dns_servers
  • none: Skip DNS server configuration. If your environment already has DNS servers configured, you can skip DNS configuration directly.

node_dns_servers

name: node_dns_servers, type: string[], level: C

Configure the dynamic DNS server list in /etc/resolv.conf. Default is ["${admin_ip}"], using the admin node as the primary DNS server.

node_dns_options

name: node_dns_options, type: string[], level: C

DNS resolution options in /etc/resolv.conf. Default value:

- "options single-request-reopen timeout:1"

If node_dns_method is configured as add or overwrite, the records in this configuration will be written to /etc/resolv.conf first. Refer to Linux documentation for /etc/resolv.conf format details.


NODE_PACKAGE

Pigsty configures software repositories and installs packages on managed nodes.

node_repo_modules: local          # upstream repo to be added on node, local by default.
node_repo_remove: true            # remove existing repo on node?
node_packages: [openssh-server]   # packages to be installed current nodes with latest version
#node_default_packages:           # default packages to be installed on all nodes

node_repo_modules

name: node_repo_modules, type: string, level: C/A

List of software repository modules to be added on the node, same format as repo_modules. Default is local, using the local software repository specified in repo_upstream.

When Pigsty manages nodes, it filters entries in repo_upstream based on this parameter value. Only entries whose module field matches this parameter value will be added to the node’s software sources.

node_repo_remove

name: node_repo_remove, type: bool, level: C/A

Remove existing software repository definitions on the node? Default is true.

When enabled, Pigsty will remove existing configuration files in /etc/yum.repos.d on the node and back them up to /etc/yum.repos.d/backup. On Debian/Ubuntu systems, it backs up /etc/apt/sources.list(.d) to /etc/apt/backup.

node_packages

name: node_packages, type: string[], level: C

List of software packages to install and upgrade on the current node. Default is [openssh-server], which upgrades sshd to the latest version during installation (to avoid security vulnerabilities).

Each array element is a string of comma-separated package names. Same format as node_default_packages. This parameter is usually used to specify additional packages to install at the node/cluster level.

Packages specified in this parameter will be upgraded to the latest available version. If you need to keep existing node software versions unchanged (just ensure they exist), use the node_default_packages parameter.

node_default_packages

name: node_default_packages, type: string[], level: G

Default packages to be installed on all nodes. Default value is a common RPM package list for EL 7/8/9. Array where each element is a space-separated package list string.

Packages specified in this variable only require existence, not latest. If you need to install the latest version, use the node_packages parameter.

This parameter has no default value (undefined state). If users don’t explicitly specify this parameter in the configuration file, Pigsty will load default values from the node_packages_default variable defined in roles/node_id/vars based on the current node’s OS family.

Default value (EL-based systems):

- lz4,unzip,bzip2,pv,jq,git,ncdu,make,patch,bash,lsof,wget,uuid,tuned,nvme-cli,numactl,sysstat,iotop,htop,rsync,tcpdump
- python3,python3-pip,socat,lrzsz,net-tools,ipvsadm,telnet,ca-certificates,openssl,keepalived,etcd,haproxy,chrony,pig
- zlib,yum,audit,bind-utils,readline,vim-minimal,node_exporter,grubby,openssh-server,openssh-clients,chkconfig,vector

Default value (Debian/Ubuntu):

- lz4,unzip,bzip2,pv,jq,git,ncdu,make,patch,bash,lsof,wget,uuid,tuned,nvme-cli,numactl,sysstat,iotop,htop,rsync
- python3,python3-pip,socat,lrzsz,net-tools,ipvsadm,telnet,ca-certificates,openssl,keepalived,etcd,haproxy,chrony,pig
- zlib1g,acl,dnsutils,libreadline-dev,vim-tiny,node-exporter,openssh-server,openssh-client,vector

Same format as node_packages, but this parameter is usually used to specify default packages that must be installed on all nodes at the global level.


NODE_TUNE

Host node features, kernel modules, and tuning templates.

node_disable_numa: false          # disable node numa, reboot required
node_disable_swap: false          # disable node swap, use with caution
node_static_network: true         # preserve dns resolver settings after reboot
node_disk_prefetch: false         # setup disk prefetch on HDD to increase performance
node_kernel_modules: [ softdog, ip_vs, ip_vs_rr, ip_vs_wrr, ip_vs_sh ]
node_hugepage_count: 0            # number of 2MB hugepage, take precedence over ratio
node_hugepage_ratio: 0            # node mem hugepage ratio, 0 disable it by default
node_overcommit_ratio: 0          # node mem overcommit ratio, 0 disable it by default
node_tune: oltp                   # node tuned profile: none,oltp,olap,crit,tiny
node_sysctl_params: { }           # sysctl parameters in k:v format in addition to tuned

node_disable_numa

name: node_disable_numa, type: bool, level: C

Disable NUMA? Default is false (NUMA not disabled).

Note that disabling NUMA requires a machine reboot to take effect! If you don’t know how to set CPU affinity, it’s recommended to disable NUMA when using databases in production environments.

node_disable_swap

name: node_disable_swap, type: bool, level: C

Disable SWAP? Default is false (SWAP not disabled).

Disabling SWAP is generally not recommended. The exception is if you have enough memory for exclusive PostgreSQL deployment, you can disable SWAP to improve performance.

Exception: SWAP should be disabled when your node is used for Kubernetes deployments.

node_static_network

name: node_static_network, type: bool, level: C

Use static DNS servers? Default is true (enabled).

Enabling static networking means your DNS Resolv configuration won’t be overwritten by machine reboots or NIC changes. Recommended to enable, or have network engineers handle the configuration.

node_disk_prefetch

name: node_disk_prefetch, type: bool, level: C

Enable disk prefetch? Default is false (not enabled).

Can optimize performance for HDD-deployed instances. Recommended to enable when using mechanical hard drives.

node_kernel_modules

name: node_kernel_modules, type: string[], level: C

Which kernel modules to enable? Default enables the following kernel modules:

node_kernel_modules: [ softdog, ip_vs, ip_vs_rr, ip_vs_wrr, ip_vs_sh ]

An array of kernel module names declaring the kernel modules that need to be installed on the node.

node_hugepage_count

name: node_hugepage_count, type: int, level: C

Number of 2MB hugepages to allocate on the node. Default is 0. Related parameter is node_hugepage_ratio.

If both node_hugepage_count and node_hugepage_ratio are 0 (default), hugepages will be completely disabled. This parameter has higher priority than node_hugepage_ratio because it’s more precise.

If a non-zero value is set, it will be written to /etc/sysctl.d/hugepage.conf to take effect. Negative values won’t work, and numbers higher than 90% of node memory will be capped at 90% of node memory.

If not zero, it should be slightly larger than the corresponding pg_shared_buffer_ratio value so PostgreSQL can use hugepages.

node_hugepage_ratio

name: node_hugepage_ratio, type: float, level: C

Ratio of node memory for hugepages. Default is 0. Valid range: 0 ~ 0.40.

This memory ratio will be allocated as hugepages and reserved for PostgreSQL. node_hugepage_count is the higher priority and more precise version of this parameter.

Default: 0, which sets vm.nr_hugepages=0 and completely disables hugepages.

This parameter should equal or be slightly larger than pg_shared_buffer_ratio if not zero.

For example, if you allocate 25% of memory for Postgres shared buffers by default, you can set this value to 0.27 ~ 0.30, and use /pg/bin/pg-tune-hugepage after initialization to precisely reclaim wasted hugepages.

node_overcommit_ratio

name: node_overcommit_ratio, type: int, level: C

Node memory overcommit ratio. Default is 0. This is an integer from 0 to 100+.

Default: 0, which sets vm.overcommit_memory=0. Otherwise, vm.overcommit_memory=2 will be used with this value as vm.overcommit_ratio.

Recommended to set vm.overcommit_ratio on dedicated pgsql nodes to avoid memory overcommit.

node_tune

name: node_tune, type: enum, level: C

Preset tuning profiles for machines, provided through tuned. Four preset modes:

  • tiny: Micro virtual machine
  • oltp: Regular OLTP template, optimizes latency (default)
  • olap: Regular OLAP template, optimizes throughput
  • crit: Core financial business template, optimizes dirty page count

Typically, the database tuning template pg_conf should match the machine tuning template.

node_sysctl_params

name: node_sysctl_params, type: dict, level: C

Sysctl kernel parameters in K:V format, added to the tuned profile. Default is {} (empty object).

This is a KV dictionary parameter where Key is the kernel sysctl parameter name and Value is the parameter value. You can also consider defining extra sysctl parameters directly in the tuned templates in roles/node/templates.


NODE_SEC

Node security related parameters, including SELinux and firewall configuration.

node_selinux_mode: permissive             # selinux mode: disabled, permissive, enforcing
node_firewall_mode: zone                  # firewall mode: disabled, zone, rules
node_firewall_intranet:           # which intranet cidr considered as internal network
  - 10.0.0.0/8
  - 192.168.0.0/16
  - 172.16.0.0/12
node_firewall_public_port:        # expose these ports to public network in (zone, strict) mode
  - 22                            # enable ssh access
  - 80                            # enable http access
  - 443                           # enable https access
  - 5432                          # enable postgresql access (think twice before exposing it!)

node_selinux_mode

name: node_selinux_mode, type: enum, level: C

SELinux running mode. Default is permissive.

Options:

  • disabled: Completely disable SELinux (equivalent to old version’s node_disable_selinux: true)
  • permissive: Permissive mode, logs violations but doesn’t block (recommended, default)
  • enforcing: Enforcing mode, strictly enforces SELinux policies

If you don’t have professional OS/security experts, it’s recommended to use permissive or disabled mode.

Note that SELinux is only enabled by default on EL-based systems. If you want to enable SELinux on Debian/Ubuntu systems, you need to install and enable SELinux configuration yourself. Also, SELinux mode changes may require a system reboot to fully take effect.

node_firewall_mode

name: node_firewall_mode, type: enum, level: C

Firewall running mode. Default is zone.

Options:

  • off: Turn off and disable firewall (equivalent to old version’s node_disable_firewall: true)
  • none: Do nothing, maintain existing firewall rules unchanged
  • zone: Use firewalld / ufw to configure firewall rules: trust intranet, only open specified ports to public

Uses firewalld service on EL systems, ufw service on Debian/Ubuntu systems.

If you’re deploying in a completely trusted intranet environment, or using cloud provider security groups for access control, you can choose none mode to keep existing firewall configuration, or set to off to completely disable the firewall.

Production environments recommend using zone mode with node_firewall_intranet and node_firewall_public_port for fine-grained access control.

Note that zone mode won’t automatically enable the firewall for you.

node_firewall_intranet

name: node_firewall_intranet, type: cidr[], level: C

Intranet CIDR address list. Introduced in v4.0. Default value:

node_firewall_intranet:
  - 10.0.0.0/8
  - 172.16.0.0/12
  - 192.168.0.0/16

This parameter defines IP address ranges considered as “internal network”. Traffic from these networks will be allowed to access all service ports without separate open rules.

Hosts within these CIDR ranges will be treated as trusted intranet hosts with more relaxed firewall rules. Also, in PG/PGB HBA rules, the intranet ranges defined here will be treated as “intranet”.

node_firewall_public_port

name: node_firewall_public_port, type: port[], level: C

Public exposed port list. Default is [22, 80, 443, 5432].

This parameter defines ports exposed to public network (non-intranet CIDR). Default exposed ports include:

  • 22: SSH service port
  • 80: HTTP service port
  • 443: HTTPS service port
  • 5432: PostgreSQL database port

You can adjust this list according to actual needs. For example, if you don’t need to expose the database port externally, remove 5432:

node_firewall_public_port: [22, 80, 443]

PostgreSQL default security policy in Pigsty only allows administrators to access the database port from public networks. If you want other users to access the database from public networks, make sure to correctly configure corresponding access permissions in PG/PGB HBA rules.

If you want to expose other service ports to public networks, you can also add them to this list. If you want to tighten firewall rules, you can remove the 5432 database port to ensure only truly needed service ports are exposed.

Note that this parameter only takes effect when node_firewall_mode is set to zone.


NODE_ADMIN

This section is about administrators on host nodes - who can log in and how.

node_data: /data                  # node main data directory, `/data` by default
node_admin_enabled: true          # create a admin user on target node?
node_admin_uid: 88                # uid and gid for node admin user
node_admin_username: dba          # name of node admin user, `dba` by default
node_admin_sudo: nopass           # admin user's sudo privilege: limited, nopass, all, none
node_admin_ssh_exchange: true     # exchange admin ssh key among node cluster
node_admin_pk_current: true       # add current user's ssh pk to admin authorized_keys
node_admin_pk_list: []            # ssh public keys to be added to admin user
node_aliases: {}                  # alias name -> IP address dict for `/etc/hosts`

node_data

name: node_data, type: path, level: C

Node’s main data directory. Default is /data.

If this directory doesn’t exist, it will be created. This directory should be owned by root with 777 permissions.

node_admin_enabled

name: node_admin_enabled, type: bool, level: C

Create a dedicated admin user on this node? Default is true.

Pigsty creates an admin user on each node by default (with password-free sudo and ssh). The default admin is named dba (uid=88), which can access other nodes in the environment from the admin node via password-free SSH and execute password-free sudo.

node_admin_uid

name: node_admin_uid, type: int, level: C

Admin user UID. Default is 88.

Please ensure the UID is the same across all nodes whenever possible to avoid unnecessary permission issues.

If the default UID 88 is already taken, you can choose another UID. Be careful about UID namespace conflicts when manually assigning.

node_admin_username

name: node_admin_username, type: username, level: C

Admin username. Default is dba.

node_admin_sudo

name: node_admin_sudo, type: enum, level: C

Admin user’s sudo privilege level. Default is nopass (password-free sudo).

Options:

  • none: No sudo privileges
  • limited: Limited sudo privileges (only allowed to execute specific commands)
  • nopass: Password-free sudo privileges (default, allows all commands without password)
  • all: Full sudo privileges (requires password)

Pigsty uses nopass mode by default, allowing admin users to execute any sudo command without password, which is very convenient for automated operations.

In production environments with high security requirements, you may need to adjust this parameter to limited or all to restrict admin privileges.

node_admin_ssh_exchange

name: node_admin_ssh_exchange, type: bool, level: C

Exchange node admin SSH keys between node clusters. Default is true.

When enabled, Pigsty will exchange SSH public keys between members during playbook execution, allowing admin node_admin_username to access each other from different nodes.

node_admin_pk_current

name: node_admin_pk_current, type: bool, level: C

Add current node & user’s public key to admin account? Default is true.

When enabled, the SSH public key (~/.ssh/id_rsa.pub) of the admin user executing this playbook on the current node will be copied to the target node admin user’s authorized_keys.

When deploying in production environments, please pay attention to this parameter, as it will install the default public key of the user currently executing the command to the admin user on all machines.

node_admin_pk_list

name: node_admin_pk_list, type: string[], level: C

List of public keys for admins who can log in. Default is [] (empty array).

Each array element is a string containing the public key to be written to the admin user’s ~/.ssh/authorized_keys. Users with the corresponding private key can log in as admin.

When deploying in production environments, please pay attention to this parameter and only add trusted keys to this list.

node_aliases

name: node_aliases, type: dict, level: C

Shell aliases to be written to host’s /etc/profile.d/node.alias.sh. Default is {} (empty dict).

This parameter allows you to configure convenient shell aliases for the host’s shell environment. The K:V dict defined here will be written to the target node’s profile.d file in the format alias k=v.

For example, the following declares an alias named dp for quickly executing docker compose pull:

node_alias:
  dp: 'docker compose pull'

NODE_TIME

Configuration related to host time/timezone/NTP/scheduled tasks.

Time synchronization is very important for database services. Please ensure the system chronyd time service is running properly.

node_timezone: ''                 # setup node timezone, empty string to skip
node_ntp_enabled: true            # enable chronyd time sync service?
node_ntp_servers:                 # ntp servers in `/etc/chrony.conf`
  - pool pool.ntp.org iburst
node_crontab_overwrite: true      # overwrite or append to `/etc/crontab`?
node_crontab: [ ]                 # crontab entries in `/etc/crontab`

node_timezone

name: node_timezone, type: string, level: C

Set node timezone. Empty string means skip. Default is empty string, which won’t modify the default timezone (usually UTC).

When using in China region, it’s recommended to set to Asia/Hong_Kong / Asia/Shanghai.

node_ntp_enabled

name: node_ntp_enabled, type: bool, level: C

Enable chronyd time sync service? Default is true.

Pigsty will override the node’s /etc/chrony.conf with the NTP server list specified in node_ntp_servers.

If your node already has NTP servers configured, you can set this parameter to false to skip time sync configuration.

node_ntp_servers

name: node_ntp_servers, type: string[], level: C

NTP server list used in /etc/chrony.conf. Default: ["pool pool.ntp.org iburst"]

This parameter is an array where each element is a string representing one line of NTP server configuration. Only takes effect when node_ntp_enabled is enabled.

Pigsty uses the global NTP server pool.ntp.org by default. You can modify this parameter according to your network environment, e.g., cn.pool.ntp.org iburst, or internal time services.

You can also use the ${admin_ip} placeholder in the configuration to use the time server on the admin node.

node_ntp_servers: [ 'pool ${admin_ip} iburst' ]

node_crontab_overwrite

name: node_crontab_overwrite, type: bool, level: C

When handling scheduled tasks in node_crontab, append or overwrite? Default is true (overwrite).

If you want to append scheduled tasks on the node, set this parameter to false, and Pigsty will append rather than overwrite all scheduled tasks on the node’s crontab.

node_crontab

name: node_crontab, type: string[], level: C

Scheduled tasks defined in node’s /etc/crontab. Default is [] (empty array).

Each array element is a string representing one scheduled task line. Use standard cron format for definition.

For example, the following configuration will execute a full backup task as the postgres user at 1am every day:

node_crontab:
  - '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am

NODE_VIP

You can bind an optional L2 VIP to a node cluster. This feature is disabled by default. L2 VIP only makes sense for a group of node clusters. The VIP will switch between nodes in the cluster according to configured priorities, ensuring high availability of node services.

Note that L2 VIP can only be used within the same L2 network segment, which may impose additional restrictions on your network topology. If you don’t want this restriction, you can consider using DNS LB or HAProxy for similar functionality.

When enabling this feature, you need to explicitly assign available vip_address and vip_vrid for this L2 VIP. Users should ensure both are unique within the same network segment.

Note that NODE VIP is different from PG VIP. PG VIP is a VIP serving PostgreSQL instances, managed by vip-manager and bound to the PG cluster primary. NODE VIP is managed by Keepalived and bound to node clusters. It can be in master-backup mode or load-balanced mode, and both can coexist.

vip_enabled: false                # enable vip on this node cluster?
# vip_address:         [IDENTITY] # node vip address in ipv4 format, required if vip is enabled
# vip_vrid:            [IDENTITY] # required, integer, 1-254, should be unique among same VLAN
vip_role: backup                  # optional, `master/backup`, backup by default, use as init role
vip_preempt: false                # optional, `true/false`, false by default, enable vip preemption
vip_interface: eth0               # node vip network interface to listen, `eth0` by default
vip_dns_suffix: ''                # node vip dns name suffix, empty string by default
vip_auth_pass: ''                 # vrrp auth password, empty to use `<cls>-<vrid>` as default
vip_exporter_port: 9650           # keepalived exporter listen port, 9650 by default

vip_enabled

name: vip_enabled, type: bool, level: C

Enable an L2 VIP managed by Keepalived on this node cluster? Default is false.

vip_address

name: vip_address, type: ip, level: C

Node VIP address in IPv4 format (without CIDR suffix). This is a required parameter when vip_enabled is enabled.

This parameter has no default value, meaning you must explicitly assign a unique VIP address for the node cluster.

vip_vrid

name: vip_vrid, type: int, level: C

VRID is a positive integer from 1 to 254 used to identify a VIP in the network. This is a required parameter when vip_enabled is enabled.

This parameter has no default value, meaning you must explicitly assign a unique ID within the network segment for the node cluster.

vip_role

name: vip_role, type: enum, level: I

Node VIP role. Options are master or backup. Default is backup.

This parameter value will be set as keepalived’s initial state.

vip_preempt

name: vip_preempt, type: bool, level: C/I

Enable VIP preemption? Optional parameter. Default is false (no preemption).

Preemption means when a backup node has higher priority than the currently alive and working master node, should it preempt the VIP?

vip_interface

name: vip_interface, type: string, level: C/I

Network interface for node VIP to listen on. Default is eth0.

You should use the same interface name as the node’s primary IP address (the IP address you put in the inventory).

If your nodes have different interface names, you can override it at the instance/node level.

vip_dns_suffix

name: vip_dns_suffix, type: string, level: C/I

DNS name for node cluster L2 VIP. Default is empty string, meaning the cluster name itself is used as the DNS name.

vip_auth_pass

name: vip_auth_pass, type: password, level: C

VRRP authentication password for keepalived. Default is empty string.

When empty, Pigsty will auto-generate a password using the pattern <cluster_name>-<vrid>. For production environments with security requirements, set an explicit strong password.

vip_exporter_port

name: vip_exporter_port, type: port, level: C/I

Keepalived exporter listen port. Default is 9650.


HAPROXY

HAProxy is installed and enabled on all nodes by default, exposing services in a manner similar to Kubernetes NodePort.

The PGSQL module uses HAProxy for services.

haproxy_enabled: true             # enable haproxy on this node?
haproxy_clean: false              # cleanup all existing haproxy config?
haproxy_reload: true              # reload haproxy after config?
haproxy_auth_enabled: true        # enable authentication for haproxy admin page
haproxy_admin_username: admin     # haproxy admin username, `admin` by default
haproxy_admin_password: pigsty    # haproxy admin password, `pigsty` by default
haproxy_exporter_port: 9101       # haproxy admin/exporter port, 9101 by default
haproxy_client_timeout: 24h       # client connection timeout, 24h by default
haproxy_server_timeout: 24h       # server connection timeout, 24h by default
haproxy_services: []              # list of haproxy services to be exposed on node

haproxy_enabled

name: haproxy_enabled, type: bool, level: C

Enable haproxy on this node? Default is true.

haproxy_clean

name: haproxy_clean, type: bool, level: G/C/A

Cleanup all existing haproxy config? Default is false.

haproxy_reload

name: haproxy_reload, type: bool, level: A

Reload haproxy after config? Default is true, will reload haproxy after config changes.

If you want to check before applying, you can disable this option with command arguments, check, then apply.

haproxy_auth_enabled

name: haproxy_auth_enabled, type: bool, level: G

Enable authentication for haproxy admin page. Default is true, which requires HTTP basic auth for the admin page.

Not recommended to disable authentication, as your traffic control page will be exposed, which is risky.

haproxy_admin_username

name: haproxy_admin_username, type: username, level: G

HAProxy admin username. Default is admin.

haproxy_admin_password

name: haproxy_admin_password, type: password, level: G

HAProxy admin password. Default is pigsty.

PLEASE CHANGE THIS PASSWORD IN YOUR PRODUCTION ENVIRONMENT!

haproxy_exporter_port

name: haproxy_exporter_port, type: port, level: C

HAProxy traffic management/metrics exposed port. Default is 9101.

haproxy_client_timeout

name: haproxy_client_timeout, type: interval, level: C

Client connection timeout. Default is 24h.

Setting a timeout can avoid long-lived connections that are difficult to clean up. If you really need long connections, you can set it to a longer time.

haproxy_server_timeout

name: haproxy_server_timeout, type: interval, level: C

Server connection timeout. Default is 24h.

Setting a timeout can avoid long-lived connections that are difficult to clean up. If you really need long connections, you can set it to a longer time.

haproxy_services

name: haproxy_services, type: service[], level: C

List of services to expose via HAProxy on this node. Default is [] (empty array).

Each array element is a service definition. Here’s an example service definition:

haproxy_services:                   # list of haproxy service

  # expose pg-test read only replicas
  - name: pg-test-ro                # [REQUIRED] service name, unique
    port: 5440                      # [REQUIRED] service port, unique
    ip: "*"                         # [OPTIONAL] service listen addr, "*" by default
    protocol: tcp                   # [OPTIONAL] service protocol, 'tcp' by default
    balance: leastconn              # [OPTIONAL] load balance algorithm, roundrobin by default (or leastconn)
    maxconn: 20000                  # [OPTIONAL] max allowed front-end connection, 20000 by default
    default: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'
    options:
      - option httpchk
      - option http-keep-alive
      - http-check send meth OPTIONS uri /read-only
      - http-check expect status 200
    servers:
      - { name: pg-test-1 ,ip: 10.10.10.11 , port: 5432 , options: check port 8008 , backup: true }
      - { name: pg-test-2 ,ip: 10.10.10.12 , port: 5432 , options: check port 8008 }
      - { name: pg-test-3 ,ip: 10.10.10.13 , port: 5432 , options: check port 8008 }

Each service definition will be rendered to /etc/haproxy/<service.name>.cfg configuration file and take effect after HAProxy reload.


NODE_EXPORTER

node_exporter_enabled: true       # setup node_exporter on this node?
node_exporter_port: 9100          # node exporter listen port, 9100 by default
node_exporter_options: '--no-collector.softnet --no-collector.nvme --collector.tcpstat --collector.processes'

node_exporter_enabled

name: node_exporter_enabled, type: bool, level: C

Enable node metrics collector on current node? Default is true.

node_exporter_port

name: node_exporter_port, type: port, level: C

Port used to expose node metrics. Default is 9100.

node_exporter_options

name: node_exporter_options, type: arg, level: C

Command line arguments for node metrics collector. Default value:

--no-collector.softnet --no-collector.nvme --collector.tcpstat --collector.processes

This option enables/disables some metrics collectors. Please adjust according to your needs.


VECTOR

Vector is the log collection component used in Pigsty v4.0. It collects logs from various modules and sends them to VictoriaLogs service on infrastructure nodes.

  • INFRA: Infrastructure component logs, collected only on Infra nodes.

    • nginx-access: /var/log/nginx/access.log
    • nginx-error: /var/log/nginx/error.log
    • grafana: /var/log/grafana/grafana.log
  • NODES: Host-related logs, collection enabled on all nodes.

    • syslog: /var/log/messages (/var/log/syslog on Debian)
    • dmesg: /var/log/dmesg
    • cron: /var/log/cron
  • PGSQL: PostgreSQL-related logs, collection enabled only when node has PGSQL module configured.

    • postgres: /pg/log/postgres/*
    • patroni: /pg/log/patroni.log
    • pgbouncer: /pg/log/pgbouncer/pgbouncer.log
    • pgbackrest: /pg/log/pgbackrest/*.log
  • REDIS: Redis-related logs, collection enabled only when node has REDIS module configured.

    • redis: /var/log/redis/*.log

Log directories are automatically adjusted according to these parameter configurations: pg_log_dir, patroni_log_dir, pgbouncer_log_dir, pgbackrest_log_dir

vector_enabled: true              # enable vector log collector?
vector_clean: false               # purge vector data dir during init?
vector_data: /data/vector         # vector data directory, /data/vector by default
vector_port: 9598                 # vector metrics port, 9598 by default
vector_read_from: beginning       # read log from beginning or end
vector_log_endpoint: [ infra ]    # log endpoint, default send to infra group

vector_enabled

name: vector_enabled, type: bool, level: C

Enable Vector log collection service? Default is true.

Vector is the log collection agent used in Pigsty v4.0, replacing Promtail from previous versions. It collects node and service logs and sends them to VictoriaLogs.

vector_clean

name: vector_clean, type: bool, level: G/A

Clean existing data directory when installing Vector? Default is false.

By default, it won’t clean. When you choose to clean, Pigsty will remove the existing data directory vector_data when deploying Vector. This means Vector will re-collect all logs on the current node and send them to VictoriaLogs.

vector_data

name: vector_data, type: path, level: C

Vector data directory path. Default is /data/vector.

Vector stores log read offsets and buffered data in this directory.

vector_port

name: vector_port, type: port, level: C

Vector metrics listen port. Default is 9598.

This port is used to expose Vector’s own monitoring metrics, which can be scraped by VictoriaMetrics.

vector_read_from

name: vector_read_from, type: enum, level: C

Vector log reading start position. Default is beginning.

Options are beginning (start from beginning) or end (start from end). beginning reads the entire content of existing log files, end only reads newly generated logs.

vector_log_endpoint

name: vector_log_endpoint, type: string[], level: C

Log destination endpoint list. Default is [ infra ].

Specifies which node group’s VictoriaLogs service to send logs to. Default sends to nodes in the infra group.

12.3 - Playbook

How to use built-in Ansible playbooks to manage NODE clusters, with a quick reference for common commands.

Pigsty provides two playbooks related to the NODE module:

  • node.yml: Add nodes to Pigsty and configure them to the desired state
  • node-rm.yml: Remove managed nodes from Pigsty

Two wrapper scripts are also provided: bin/node-add and bin/node-rm, for quickly invoking these playbooks.


node.yml

The node.yml playbook for adding nodes to Pigsty contains the following subtasks:

node-id       : generate node identity
node_name     : setup hostname
node_hosts    : setup /etc/hosts records
node_resolv   : setup DNS resolver /etc/resolv.conf
node_firewall : setup firewall & selinux
node_ca       : add & trust CA certificate
node_repo     : add upstream software repository
node_pkg      : install rpm/deb packages
node_feature  : setup numa, grub, static network
node_kernel   : enable kernel modules
node_tune     : setup tuned profile
node_sysctl   : setup additional sysctl parameters
node_profile  : write /etc/profile.d/node.sh
node_ulimit   : setup resource limits
node_data     : setup data directory
node_admin    : setup admin user and ssh key
node_timezone : setup timezone
node_ntp      : setup NTP server/client
node_crontab  : add/overwrite crontab tasks
node_vip      : setup optional L2 VIP for node cluster
haproxy       : setup haproxy on node to expose services
monitor       : setup node monitoring: node_exporter & vector

node-rm.yml

The node-rm.yml playbook for removing nodes from Pigsty contains the following subtasks:

register       : remove registration from prometheus & nginx
  - prometheus : remove registered prometheus monitoring target
  - nginx      : remove nginx proxy record for haproxy admin
vip            : remove keepalived & L2 VIP (if VIP enabled)
haproxy        : remove haproxy load balancer
node_exporter  : remove node monitoring: Node Exporter
vip_exporter   : remove keepalived_exporter (if VIP enabled)
vector         : remove log collection agent vector
profile        : remove /etc/profile.d/node.sh

Quick Reference

# Basic node management
./node.yml -l <cls|ip|group>          # Add node to Pigsty
./node-rm.yml -l <cls|ip|group>       # Remove node from Pigsty

# Node management shortcuts
bin/node-add node-test                 # Initialize node cluster 'node-test'
bin/node-add 10.10.10.10               # Initialize node '10.10.10.10'
bin/node-rm node-test                  # Remove node cluster 'node-test'
bin/node-rm 10.10.10.10                # Remove node '10.10.10.10'

# Node main initialization
./node.yml -t node                     # Complete node main init (excludes haproxy, monitor)
./node.yml -t haproxy                  # Setup haproxy on node
./node.yml -t monitor                  # Setup node monitoring: node_exporter & vector

# VIP management
./node.yml -t node_vip                 # Setup optional L2 VIP for node cluster
./node.yml -t vip_config,vip_reload    # Refresh node L2 VIP configuration

# HAProxy management
./node.yml -t haproxy_config,haproxy_reload   # Refresh service definitions on node

# Registration management
./node.yml -t register_prometheus      # Re-register node to Prometheus
./node.yml -t register_nginx           # Re-register node haproxy admin to Nginx

# Specific tasks
./node.yml -t node-id                  # Generate node identity
./node.yml -t node_name                # Setup hostname
./node.yml -t node_hosts               # Setup node /etc/hosts records
./node.yml -t node_resolv              # Setup node DNS resolver /etc/resolv.conf
./node.yml -t node_firewall            # Setup firewall & selinux
./node.yml -t node_ca                  # Setup node CA certificate
./node.yml -t node_repo                # Setup node upstream software repository
./node.yml -t node_pkg                 # Install yum packages on node
./node.yml -t node_feature             # Setup numa, grub, static network
./node.yml -t node_kernel              # Enable kernel modules
./node.yml -t node_tune                # Setup tuned profile
./node.yml -t node_sysctl              # Setup additional sysctl parameters
./node.yml -t node_profile             # Setup node environment: /etc/profile.d/node.sh
./node.yml -t node_ulimit              # Setup node resource limits
./node.yml -t node_data                # Setup node primary data directory
./node.yml -t node_admin               # Setup admin user and ssh key
./node.yml -t node_timezone            # Setup node timezone
./node.yml -t node_ntp                 # Setup node NTP server/client
./node.yml -t node_crontab             # Add/overwrite crontab tasks

12.4 - Administration

Node cluster management SOP - create, destroy, expand, shrink, and handle node/disk failures

Here are common administration operations for the NODE module:

For more questions, see FAQ: NODE


Add Node

To add a node to Pigsty, you need passwordless ssh/sudo access to that node.

You can also add an entire cluster at once, or use wildcards to match nodes in the inventory to add to Pigsty.

# ./node.yml -l <cls|ip|group>        # actual playbook to add nodes to Pigsty
# bin/node-add <selector|ip...>       # add node to Pigsty
bin/node-add node-test                # init node cluster 'node-test'
bin/node-add 10.10.10.10              # init node '10.10.10.10'

Remove Node

To remove a node from Pigsty, you can use the following commands:

# ./node-rm.yml -l <cls|ip|group>    # actual playbook to remove node from Pigsty
# bin/node-rm <cls|ip|selector> ...  # remove node from Pigsty
bin/node-rm node-test                # remove node cluster 'node-test'
bin/node-rm 10.10.10.10              # remove node '10.10.10.10'

You can also remove an entire cluster at once, or use wildcards to match nodes in the inventory to remove from Pigsty.


Create Admin

If the current user doesn’t have passwordless ssh/sudo access to the node, you can use another admin user to bootstrap it:

node.yml -t node_admin -k -K -e ansible_user=<another admin>   # enter ssh/sudo password for another admin to complete this task

Bind VIP

You can bind an optional L2 VIP on a node cluster using the vip_enabled parameter.

proxy:
  hosts:
    10.10.10.29: { nodename: proxy-1 }   # you can explicitly specify initial VIP role: MASTER / BACKUP
    10.10.10.30: { nodename: proxy-2 }   # , vip_role: master }
  vars:
    node_cluster: proxy
    vip_enabled: true
    vip_vrid: 128
    vip_address: 10.10.10.99
    vip_interface: eth1
./node.yml -l proxy -t node_vip     # enable VIP for the first time
./node.yml -l proxy -t vip_refresh  # refresh VIP config (e.g., designate master)

Add Node Monitoring

If you want to add or reconfigure monitoring on existing nodes, use the following commands:

./node.yml -t node_exporter,node_register  # configure monitoring and register
./node.yml -t vector                        # configure log collection

Other Tasks

# Play
./node.yml -t node                            # complete node initialization (excludes haproxy, monitoring)
./node.yml -t haproxy                         # setup haproxy on node
./node.yml -t monitor                         # configure node monitoring: node_exporter & vector
./node.yml -t node_vip                        # install, configure, enable L2 VIP for clusters without VIP
./node.yml -t vip_config,vip_reload           # refresh node L2 VIP configuration
./node.yml -t haproxy_config,haproxy_reload   # refresh service definitions on node
./node.yml -t register_prometheus             # re-register node with Prometheus
./node.yml -t register_nginx                  # re-register node haproxy admin page with Nginx

# Task
./node.yml -t node-id        # generate node identity
./node.yml -t node_name      # setup hostname
./node.yml -t node_hosts     # configure node /etc/hosts records
./node.yml -t node_resolv    # configure node DNS resolver /etc/resolv.conf
./node.yml -t node_firewall  # configure firewall & selinux
./node.yml -t node_ca        # configure node CA certificate
./node.yml -t node_repo      # configure node upstream software repository
./node.yml -t node_pkg       # install yum packages on node
./node.yml -t node_feature   # configure numa, grub, static network, etc.
./node.yml -t node_kernel    # configure OS kernel modules
./node.yml -t node_tune      # configure tuned profile
./node.yml -t node_sysctl    # set additional sysctl parameters
./node.yml -t node_profile   # configure node environment variables: /etc/profile.d/node.sh
./node.yml -t node_ulimit    # configure node resource limits
./node.yml -t node_data      # configure node primary data directory
./node.yml -t node_admin     # configure admin user and ssh keys
./node.yml -t node_timezone  # configure node timezone
./node.yml -t node_ntp       # configure node NTP server/client
./node.yml -t node_crontab   # add/overwrite crontab entries
./node.yml -t node_vip       # setup optional L2 VIP for node cluster

12.5 - Monitoring

Monitor NODE in Pigsty with dashboards and alerting rules

The NODE module in Pigsty provides 6 monitoring dashboards and comprehensive alerting rules.


Dashboards

The NODE module provides 6 monitoring dashboards:

NODE Overview

Displays an overall overview of all host nodes in the current environment.

node-overview.jpg

NODE Cluster

Shows detailed monitoring data for a specific host cluster.

node-cluster.jpg

Node Instance

Presents detailed monitoring information for a single host node.

node-instance.jpg

NODE Alert

Centrally displays alert information for all hosts in the environment.

node-alert.jpg

NODE VIP

Monitors detailed status of L2 virtual IPs.

node-vip.jpg

Node Haproxy

Tracks the operational status of HAProxy load balancers.

node-haproxy.jpg


Alert Rules

Pigsty implements the following alerting rules for NODE:

Availability Alerts

RuleLevelDescription
NodeDownCRITNode is offline
HaproxyDownCRITHAProxy service is offline
VectorDownWARNLog collecting agent offline (Vector)
DockerDownWARNContainer engine offline
KeepalivedDownWARNKeepalived daemon offline

CPU Alerts

RuleLevelDescription
NodeCpuHighWARNCPU usage exceeds 70%

Scheduling Alerts

RuleLevelDescription
NodeLoadHighWARNNormalized load exceeds 100%

Memory Alerts

RuleLevelDescription
NodeOutOfMemWARNAvailable memory less than 10%
NodeMemSwappedWARNSwap usage exceeds 1%

Filesystem Alerts

RuleLevelDescription
NodeFsSpaceFullWARNDisk usage exceeds 90%
NodeFsFilesFullWARNInode usage exceeds 90%
NodeFdFullWARNFile descriptor usage exceeds 90%

Disk Alerts

RuleLevelDescription
NodeDiskSlowWARNRead/write latency exceeds 32ms

Network Protocol Alerts

RuleLevelDescription
NodeTcpErrHighWARNTCP error rate exceeds 1/min
NodeTcpRetransHighWARNTCP retransmission rate exceeds 1%

Time Synchronization Alerts

RuleLevelDescription
NodeTimeDriftWARNSystem time not synchronized

12.6 - Metrics

Complete list of monitoring metrics provided by Pigsty NODE module

The NODE module has 747 available metrics.

Metric NameTypeLabelsDescription
ALERTSUnknownalertname, ip, level, severity, ins, job, alertstate, category, instance, clsN/A
ALERTS_FOR_STATEUnknownalertname, ip, level, severity, ins, job, category, instance, clsN/A
deprecated_flags_inuse_totalUnknowninstance, ins, job, ip, clsN/A
go_gc_duration_secondssummaryquantile, instance, ins, job, ip, clsA summary of the pause duration of garbage collection cycles.
go_gc_duration_seconds_countUnknowninstance, ins, job, ip, clsN/A
go_gc_duration_seconds_sumUnknowninstance, ins, job, ip, clsN/A
go_goroutinesgaugeinstance, ins, job, ip, clsNumber of goroutines that currently exist.
go_infogaugeversion, instance, ins, job, ip, clsInformation about the Go environment.
go_memstats_alloc_bytesgaugeinstance, ins, job, ip, clsNumber of bytes allocated and still in use.
go_memstats_alloc_bytes_totalcounterinstance, ins, job, ip, clsTotal number of bytes allocated, even if freed.
go_memstats_buck_hash_sys_bytesgaugeinstance, ins, job, ip, clsNumber of bytes used by the profiling bucket hash table.
go_memstats_frees_totalcounterinstance, ins, job, ip, clsTotal number of frees.
go_memstats_gc_sys_bytesgaugeinstance, ins, job, ip, clsNumber of bytes used for garbage collection system metadata.
go_memstats_heap_alloc_bytesgaugeinstance, ins, job, ip, clsNumber of heap bytes allocated and still in use.
go_memstats_heap_idle_bytesgaugeinstance, ins, job, ip, clsNumber of heap bytes waiting to be used.
go_memstats_heap_inuse_bytesgaugeinstance, ins, job, ip, clsNumber of heap bytes that are in use.
go_memstats_heap_objectsgaugeinstance, ins, job, ip, clsNumber of allocated objects.
go_memstats_heap_released_bytesgaugeinstance, ins, job, ip, clsNumber of heap bytes released to OS.
go_memstats_heap_sys_bytesgaugeinstance, ins, job, ip, clsNumber of heap bytes obtained from system.
go_memstats_last_gc_time_secondsgaugeinstance, ins, job, ip, clsNumber of seconds since 1970 of last garbage collection.
go_memstats_lookups_totalcounterinstance, ins, job, ip, clsTotal number of pointer lookups.
go_memstats_mallocs_totalcounterinstance, ins, job, ip, clsTotal number of mallocs.
go_memstats_mcache_inuse_bytesgaugeinstance, ins, job, ip, clsNumber of bytes in use by mcache structures.
go_memstats_mcache_sys_bytesgaugeinstance, ins, job, ip, clsNumber of bytes used for mcache structures obtained from system.
go_memstats_mspan_inuse_bytesgaugeinstance, ins, job, ip, clsNumber of bytes in use by mspan structures.
go_memstats_mspan_sys_bytesgaugeinstance, ins, job, ip, clsNumber of bytes used for mspan structures obtained from system.
go_memstats_next_gc_bytesgaugeinstance, ins, job, ip, clsNumber of heap bytes when next garbage collection will take place.
go_memstats_other_sys_bytesgaugeinstance, ins, job, ip, clsNumber of bytes used for other system allocations.
go_memstats_stack_inuse_bytesgaugeinstance, ins, job, ip, clsNumber of bytes in use by the stack allocator.
go_memstats_stack_sys_bytesgaugeinstance, ins, job, ip, clsNumber of bytes obtained from system for stack allocator.
go_memstats_sys_bytesgaugeinstance, ins, job, ip, clsNumber of bytes obtained from system.
go_threadsgaugeinstance, ins, job, ip, clsNumber of OS threads created.
haproxy:cls:usageUnknownjob, clsN/A
haproxy:ins:uptimeUnknowninstance, ins, job, ip, clsN/A
haproxy:ins:usageUnknowninstance, ins, job, ip, clsN/A
haproxy_backend_active_serversgaugeproxy, instance, ins, job, ip, clsTotal number of active UP servers with a non-zero weight
haproxy_backend_agg_check_statusgaugestate, proxy, instance, ins, job, ip, clsBackend’s aggregated gauge of servers’ state check status
haproxy_backend_agg_server_check_statusgaugestate, proxy, instance, ins, job, ip, cls[DEPRECATED] Backend’s aggregated gauge of servers’ status
haproxy_backend_agg_server_statusgaugestate, proxy, instance, ins, job, ip, clsBackend’s aggregated gauge of servers’ status
haproxy_backend_backup_serversgaugeproxy, instance, ins, job, ip, clsTotal number of backup UP servers with a non-zero weight
haproxy_backend_bytes_in_totalcounterproxy, instance, ins, job, ip, clsTotal number of request bytes since process started
haproxy_backend_bytes_out_totalcounterproxy, instance, ins, job, ip, clsTotal number of response bytes since process started
haproxy_backend_check_last_change_secondsgaugeproxy, instance, ins, job, ip, clsHow long ago the last server state changed, in seconds
haproxy_backend_check_up_down_totalcounterproxy, instance, ins, job, ip, clsTotal number of failed checks causing UP to DOWN server transitions, per server/backend, since the worker process started
haproxy_backend_client_aborts_totalcounterproxy, instance, ins, job, ip, clsTotal number of requests or connections aborted by the client since the worker process started
haproxy_backend_connect_time_average_secondsgaugeproxy, instance, ins, job, ip, clsAvg. connect time for last 1024 successful connections.
haproxy_backend_connection_attempts_totalcounterproxy, instance, ins, job, ip, clsTotal number of outgoing connection attempts on this backend/server since the worker process started
haproxy_backend_connection_errors_totalcounterproxy, instance, ins, job, ip, clsTotal number of failed connections to server since the worker process started
haproxy_backend_connection_reuses_totalcounterproxy, instance, ins, job, ip, clsTotal number of reused connection on this backend/server since the worker process started
haproxy_backend_current_queuegaugeproxy, instance, ins, job, ip, clsNumber of current queued connections
haproxy_backend_current_sessionsgaugeproxy, instance, ins, job, ip, clsNumber of current sessions on the frontend, backend or server
haproxy_backend_downtime_seconds_totalcounterproxy, instance, ins, job, ip, clsTotal time spent in DOWN state, for server or backend
haproxy_backend_failed_header_rewriting_totalcounterproxy, instance, ins, job, ip, clsTotal number of failed HTTP header rewrites since the worker process started
haproxy_backend_http_cache_hits_totalcounterproxy, instance, ins, job, ip, clsTotal number of HTTP requests not found in the cache on this frontend/backend since the worker process started
haproxy_backend_http_cache_lookups_totalcounterproxy, instance, ins, job, ip, clsTotal number of HTTP requests looked up in the cache on this frontend/backend since the worker process started
haproxy_backend_http_comp_bytes_bypassed_totalcounterproxy, instance, ins, job, ip, clsTotal number of bytes that bypassed HTTP compression for this object since the worker process started (CPU/memory/bandwidth limitation)
haproxy_backend_http_comp_bytes_in_totalcounterproxy, instance, ins, job, ip, clsTotal number of bytes submitted to the HTTP compressor for this object since the worker process started
haproxy_backend_http_comp_bytes_out_totalcounterproxy, instance, ins, job, ip, clsTotal number of bytes emitted by the HTTP compressor for this object since the worker process started
haproxy_backend_http_comp_responses_totalcounterproxy, instance, ins, job, ip, clsTotal number of HTTP responses that were compressed for this object since the worker process started
haproxy_backend_http_requests_totalcounterproxy, instance, ins, job, ip, clsTotal number of HTTP requests processed by this object since the worker process started
haproxy_backend_http_responses_totalcounterip, proxy, ins, code, job, instance, clsTotal number of HTTP responses with status 100-199 returned by this object since the worker process started
haproxy_backend_internal_errors_totalcounterproxy, instance, ins, job, ip, clsTotal number of internal errors since process started
haproxy_backend_last_session_secondsgaugeproxy, instance, ins, job, ip, clsHow long ago some traffic was seen on this object on this worker process, in seconds
haproxy_backend_limit_sessionsgaugeproxy, instance, ins, job, ip, clsFrontend/listener/server’s maxconn, backend’s fullconn
haproxy_backend_loadbalanced_totalcounterproxy, instance, ins, job, ip, clsTotal number of requests routed by load balancing since the worker process started (ignores queue pop and stickiness)
haproxy_backend_max_connect_time_secondsgaugeproxy, instance, ins, job, ip, clsMaximum observed time spent waiting for a connection to complete
haproxy_backend_max_queuegaugeproxy, instance, ins, job, ip, clsHighest value of queued connections encountered since process started
haproxy_backend_max_queue_time_secondsgaugeproxy, instance, ins, job, ip, clsMaximum observed time spent in the queue
haproxy_backend_max_response_time_secondsgaugeproxy, instance, ins, job, ip, clsMaximum observed time spent waiting for a server response
haproxy_backend_max_session_rategaugeproxy, instance, ins, job, ip, clsHighest value of sessions per second observed since the worker process started
haproxy_backend_max_sessionsgaugeproxy, instance, ins, job, ip, clsHighest value of current sessions encountered since process started
haproxy_backend_max_total_time_secondsgaugeproxy, instance, ins, job, ip, clsMaximum observed total request+response time (request+queue+connect+response+processing)
haproxy_backend_queue_time_average_secondsgaugeproxy, instance, ins, job, ip, clsAvg. queue time for last 1024 successful connections.
haproxy_backend_redispatch_warnings_totalcounterproxy, instance, ins, job, ip, clsTotal number of server redispatches due to connection failures since the worker process started
haproxy_backend_requests_denied_totalcounterproxy, instance, ins, job, ip, clsTotal number of denied requests since process started
haproxy_backend_response_errors_totalcounterproxy, instance, ins, job, ip, clsTotal number of invalid responses since the worker process started
haproxy_backend_response_time_average_secondsgaugeproxy, instance, ins, job, ip, clsAvg. response time for last 1024 successful connections.
haproxy_backend_responses_denied_totalcounterproxy, instance, ins, job, ip, clsTotal number of denied responses since process started
haproxy_backend_retry_warnings_totalcounterproxy, instance, ins, job, ip, clsTotal number of server connection retries since the worker process started
haproxy_backend_server_aborts_totalcounterproxy, instance, ins, job, ip, clsTotal number of requests or connections aborted by the server since the worker process started
haproxy_backend_sessions_totalcounterproxy, instance, ins, job, ip, clsTotal number of sessions since process started
haproxy_backend_statusgaugestate, proxy, instance, ins, job, ip, clsCurrent status of the service, per state label value.
haproxy_backend_total_time_average_secondsgaugeproxy, instance, ins, job, ip, clsAvg. total time for last 1024 successful connections.
haproxy_backend_uweightgaugeproxy, instance, ins, job, ip, clsServer’s user weight, or sum of active servers’ user weights for a backend
haproxy_backend_weightgaugeproxy, instance, ins, job, ip, clsServer’s effective weight, or sum of active servers’ effective weights for a backend
haproxy_frontend_bytes_in_totalcounterproxy, instance, ins, job, ip, clsTotal number of request bytes since process started
haproxy_frontend_bytes_out_totalcounterproxy, instance, ins, job, ip, clsTotal number of response bytes since process started
haproxy_frontend_connections_rate_maxgaugeproxy, instance, ins, job, ip, clsHighest value of connections per second observed since the worker process started
haproxy_frontend_connections_totalcounterproxy, instance, ins, job, ip, clsTotal number of new connections accepted on this frontend since the worker process started
haproxy_frontend_current_sessionsgaugeproxy, instance, ins, job, ip, clsNumber of current sessions on the frontend, backend or server
haproxy_frontend_denied_connections_totalcounterproxy, instance, ins, job, ip, clsTotal number of incoming connections blocked on a listener/frontend by a tcp-request connection rule since the worker process started
haproxy_frontend_denied_sessions_totalcounterproxy, instance, ins, job, ip, clsTotal number of incoming sessions blocked on a listener/frontend by a tcp-request connection rule since the worker process started
haproxy_frontend_failed_header_rewriting_totalcounterproxy, instance, ins, job, ip, clsTotal number of failed HTTP header rewrites since the worker process started
haproxy_frontend_http_cache_hits_totalcounterproxy, instance, ins, job, ip, clsTotal number of HTTP requests not found in the cache on this frontend/backend since the worker process started
haproxy_frontend_http_cache_lookups_totalcounterproxy, instance, ins, job, ip, clsTotal number of HTTP requests looked up in the cache on this frontend/backend since the worker process started
haproxy_frontend_http_comp_bytes_bypassed_totalcounterproxy, instance, ins, job, ip, clsTotal number of bytes that bypassed HTTP compression for this object since the worker process started (CPU/memory/bandwidth limitation)
haproxy_frontend_http_comp_bytes_in_totalcounterproxy, instance, ins, job, ip, clsTotal number of bytes submitted to the HTTP compressor for this object since the worker process started
haproxy_frontend_http_comp_bytes_out_totalcounterproxy, instance, ins, job, ip, clsTotal number of bytes emitted by the HTTP compressor for this object since the worker process started
haproxy_frontend_http_comp_responses_totalcounterproxy, instance, ins, job, ip, clsTotal number of HTTP responses that were compressed for this object since the worker process started
haproxy_frontend_http_requests_rate_maxgaugeproxy, instance, ins, job, ip, clsHighest value of http requests observed since the worker process started
haproxy_frontend_http_requests_totalcounterproxy, instance, ins, job, ip, clsTotal number of HTTP requests processed by this object since the worker process started
haproxy_frontend_http_responses_totalcounterip, proxy, ins, code, job, instance, clsTotal number of HTTP responses with status 100-199 returned by this object since the worker process started
haproxy_frontend_intercepted_requests_totalcounterproxy, instance, ins, job, ip, clsTotal number of HTTP requests intercepted on the frontend (redirects/stats/services) since the worker process started
haproxy_frontend_internal_errors_totalcounterproxy, instance, ins, job, ip, clsTotal number of internal errors since process started
haproxy_frontend_limit_session_rategaugeproxy, instance, ins, job, ip, clsLimit on the number of sessions accepted in a second (frontend only, ‘rate-limit sessions’ setting)
haproxy_frontend_limit_sessionsgaugeproxy, instance, ins, job, ip, clsFrontend/listener/server’s maxconn, backend’s fullconn
haproxy_frontend_max_session_rategaugeproxy, instance, ins, job, ip, clsHighest value of sessions per second observed since the worker process started
haproxy_frontend_max_sessionsgaugeproxy, instance, ins, job, ip, clsHighest value of current sessions encountered since process started
haproxy_frontend_request_errors_totalcounterproxy, instance, ins, job, ip, clsTotal number of invalid requests since process started
haproxy_frontend_requests_denied_totalcounterproxy, instance, ins, job, ip, clsTotal number of denied requests since process started
haproxy_frontend_responses_denied_totalcounterproxy, instance, ins, job, ip, clsTotal number of denied responses since process started
haproxy_frontend_sessions_totalcounterproxy, instance, ins, job, ip, clsTotal number of sessions since process started
haproxy_frontend_statusgaugestate, proxy, instance, ins, job, ip, clsCurrent status of the service, per state label value.
haproxy_process_active_peersgaugeinstance, ins, job, ip, clsCurrent number of verified active peers connections on the current worker process
haproxy_process_build_infogaugeversion, instance, ins, job, ip, clsBuild info
haproxy_process_busy_polling_enabledgaugeinstance, ins, job, ip, cls1 if busy-polling is currently in use on the worker process, otherwise zero (config.busy-polling)
haproxy_process_bytes_out_rategaugeinstance, ins, job, ip, clsNumber of bytes emitted by current worker process over the last second
haproxy_process_bytes_out_totalcounterinstance, ins, job, ip, clsTotal number of bytes emitted by current worker process since started
haproxy_process_connected_peersgaugeinstance, ins, job, ip, clsCurrent number of peers having passed the connection step on the current worker process
haproxy_process_connections_totalcounterinstance, ins, job, ip, clsTotal number of connections on this worker process since started
haproxy_process_current_backend_ssl_key_rategaugeinstance, ins, job, ip, clsNumber of SSL keys created on backends in this worker process over the last second
haproxy_process_current_connection_rategaugeinstance, ins, job, ip, clsNumber of front connections created on this worker process over the last second
haproxy_process_current_connectionsgaugeinstance, ins, job, ip, clsCurrent number of connections on this worker process
haproxy_process_current_frontend_ssl_key_rategaugeinstance, ins, job, ip, clsNumber of SSL keys created on frontends in this worker process over the last second
haproxy_process_current_run_queuegaugeinstance, ins, job, ip, clsTotal number of active tasks+tasklets in the current worker process
haproxy_process_current_session_rategaugeinstance, ins, job, ip, clsNumber of sessions created on this worker process over the last second
haproxy_process_current_ssl_connectionsgaugeinstance, ins, job, ip, clsCurrent number of SSL endpoints on this worker process (front+back)
haproxy_process_current_ssl_rategaugeinstance, ins, job, ip, clsNumber of SSL connections created on this worker process over the last second
haproxy_process_current_tasksgaugeinstance, ins, job, ip, clsTotal number of tasks in the current worker process (active + sleeping)
haproxy_process_current_zlib_memorygaugeinstance, ins, job, ip, clsAmount of memory currently used by HTTP compression on the current worker process (in bytes)
haproxy_process_dropped_logs_totalcounterinstance, ins, job, ip, clsTotal number of dropped logs for current worker process since started
haproxy_process_failed_resolutionscounterinstance, ins, job, ip, clsTotal number of failed DNS resolutions in current worker process since started
haproxy_process_frontend_ssl_reusegaugeinstance, ins, job, ip, clsPercent of frontend SSL connections which did not require a new key
haproxy_process_hard_max_connectionsgaugeinstance, ins, job, ip, clsHard limit on the number of per-process connections (imposed by Memmax_MB or Ulimit-n)
haproxy_process_http_comp_bytes_in_totalcounterinstance, ins, job, ip, clsNumber of bytes submitted to the HTTP compressor in this worker process over the last second
haproxy_process_http_comp_bytes_out_totalcounterinstance, ins, job, ip, clsNumber of bytes emitted by the HTTP compressor in this worker process over the last second
haproxy_process_idle_time_percentgaugeinstance, ins, job, ip, clsPercentage of last second spent waiting in the current worker thread
haproxy_process_jobsgaugeinstance, ins, job, ip, clsCurrent number of active jobs on the current worker process (frontend connections, master connections, listeners)
haproxy_process_limit_connection_rategaugeinstance, ins, job, ip, clsHard limit for ConnRate (global.maxconnrate)
haproxy_process_limit_http_compgaugeinstance, ins, job, ip, clsLimit of CompressBpsOut beyond which HTTP compression is automatically disabled
haproxy_process_limit_session_rategaugeinstance, ins, job, ip, clsHard limit for SessRate (global.maxsessrate)
haproxy_process_limit_ssl_rategaugeinstance, ins, job, ip, clsHard limit for SslRate (global.maxsslrate)
haproxy_process_listenersgaugeinstance, ins, job, ip, clsCurrent number of active listeners on the current worker process
haproxy_process_max_backend_ssl_key_rategaugeinstance, ins, job, ip, clsHighest SslBackendKeyRate reached on this worker process since started (in SSL keys per second)
haproxy_process_max_connection_rategaugeinstance, ins, job, ip, clsHighest ConnRate reached on this worker process since started (in connections per second)
haproxy_process_max_connectionsgaugeinstance, ins, job, ip, clsHard limit on the number of per-process connections (configured or imposed by Ulimit-n)
haproxy_process_max_fdsgaugeinstance, ins, job, ip, clsHard limit on the number of per-process file descriptors
haproxy_process_max_frontend_ssl_key_rategaugeinstance, ins, job, ip, clsHighest SslFrontendKeyRate reached on this worker process since started (in SSL keys per second)
haproxy_process_max_memory_bytesgaugeinstance, ins, job, ip, clsWorker process’s hard limit on memory usage in byes (-m on command line)
haproxy_process_max_pipesgaugeinstance, ins, job, ip, clsHard limit on the number of pipes for splicing, 0=unlimited
haproxy_process_max_session_rategaugeinstance, ins, job, ip, clsHighest SessRate reached on this worker process since started (in sessions per second)
haproxy_process_max_socketsgaugeinstance, ins, job, ip, clsHard limit on the number of per-process sockets
haproxy_process_max_ssl_connectionsgaugeinstance, ins, job, ip, clsHard limit on the number of per-process SSL endpoints (front+back), 0=unlimited
haproxy_process_max_ssl_rategaugeinstance, ins, job, ip, clsHighest SslRate reached on this worker process since started (in connections per second)
haproxy_process_max_zlib_memorygaugeinstance, ins, job, ip, clsLimit on the amount of memory used by HTTP compression above which it is automatically disabled (in bytes, see global.maxzlibmem)
haproxy_process_nbprocgaugeinstance, ins, job, ip, clsNumber of started worker processes (historical, always 1)
haproxy_process_nbthreadgaugeinstance, ins, job, ip, clsNumber of started threads (global.nbthread)
haproxy_process_pipes_free_totalcounterinstance, ins, job, ip, clsCurrent number of allocated and available pipes in this worker process
haproxy_process_pipes_used_totalcounterinstance, ins, job, ip, clsCurrent number of pipes in use in this worker process
haproxy_process_pool_allocated_bytesgaugeinstance, ins, job, ip, clsAmount of memory allocated in pools (in bytes)
haproxy_process_pool_failures_totalcounterinstance, ins, job, ip, clsNumber of failed pool allocations since this worker was started
haproxy_process_pool_used_bytesgaugeinstance, ins, job, ip, clsAmount of pool memory currently used (in bytes)
haproxy_process_recv_logs_totalcounterinstance, ins, job, ip, clsTotal number of log messages received by log-forwarding listeners on this worker process since started
haproxy_process_relative_process_idgaugeinstance, ins, job, ip, clsRelative worker process number (1)
haproxy_process_requests_totalcounterinstance, ins, job, ip, clsTotal number of requests on this worker process since started
haproxy_process_spliced_bytes_out_totalcounterinstance, ins, job, ip, clsTotal number of bytes emitted by current worker process through a kernel pipe since started
haproxy_process_ssl_cache_lookups_totalcounterinstance, ins, job, ip, clsTotal number of SSL session ID lookups in the SSL session cache on this worker since started
haproxy_process_ssl_cache_misses_totalcounterinstance, ins, job, ip, clsTotal number of SSL session ID lookups that didn’t find a session in the SSL session cache on this worker since started
haproxy_process_ssl_connections_totalcounterinstance, ins, job, ip, clsTotal number of SSL endpoints on this worker process since started (front+back)
haproxy_process_start_time_secondsgaugeinstance, ins, job, ip, clsStart time in seconds
haproxy_process_stoppinggaugeinstance, ins, job, ip, cls1 if the worker process is currently stopping, otherwise zero
haproxy_process_unstoppable_jobsgaugeinstance, ins, job, ip, clsCurrent number of unstoppable jobs on the current worker process (master connections)
haproxy_process_uptime_secondsgaugeinstance, ins, job, ip, clsHow long ago this worker process was started (seconds)
haproxy_server_bytes_in_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of request bytes since process started
haproxy_server_bytes_out_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of response bytes since process started
haproxy_server_check_codegaugeproxy, instance, ins, job, server, ip, clslayer5-7 code, if available of the last health check.
haproxy_server_check_duration_secondsgaugeproxy, instance, ins, job, server, ip, clsTotal duration of the latest server health check, in seconds.
haproxy_server_check_failures_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of failed individual health checks per server/backend, since the worker process started
haproxy_server_check_last_change_secondsgaugeproxy, instance, ins, job, server, ip, clsHow long ago the last server state changed, in seconds
haproxy_server_check_statusgaugestate, proxy, instance, ins, job, server, ip, clsStatus of last health check, per state label value.
haproxy_server_check_up_down_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of failed checks causing UP to DOWN server transitions, per server/backend, since the worker process started
haproxy_server_client_aborts_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of requests or connections aborted by the client since the worker process started
haproxy_server_connect_time_average_secondsgaugeproxy, instance, ins, job, server, ip, clsAvg. connect time for last 1024 successful connections.
haproxy_server_connection_attempts_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of outgoing connection attempts on this backend/server since the worker process started
haproxy_server_connection_errors_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of failed connections to server since the worker process started
haproxy_server_connection_reuses_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of reused connection on this backend/server since the worker process started
haproxy_server_current_queuegaugeproxy, instance, ins, job, server, ip, clsNumber of current queued connections
haproxy_server_current_sessionsgaugeproxy, instance, ins, job, server, ip, clsNumber of current sessions on the frontend, backend or server
haproxy_server_current_throttlegaugeproxy, instance, ins, job, server, ip, clsThrottling ratio applied to a server’s maxconn and weight during the slowstart period (0 to 100%)
haproxy_server_downtime_seconds_totalcounterproxy, instance, ins, job, server, ip, clsTotal time spent in DOWN state, for server or backend
haproxy_server_failed_header_rewriting_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of failed HTTP header rewrites since the worker process started
haproxy_server_idle_connections_currentgaugeproxy, instance, ins, job, server, ip, clsCurrent number of idle connections available for reuse on this server
haproxy_server_idle_connections_limitgaugeproxy, instance, ins, job, server, ip, clsLimit on the number of available idle connections on this server (server ‘pool_max_conn’ directive)
haproxy_server_internal_errors_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of internal errors since process started
haproxy_server_last_session_secondsgaugeproxy, instance, ins, job, server, ip, clsHow long ago some traffic was seen on this object on this worker process, in seconds
haproxy_server_limit_sessionsgaugeproxy, instance, ins, job, server, ip, clsFrontend/listener/server’s maxconn, backend’s fullconn
haproxy_server_loadbalanced_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of requests routed by load balancing since the worker process started (ignores queue pop and stickiness)
haproxy_server_max_connect_time_secondsgaugeproxy, instance, ins, job, server, ip, clsMaximum observed time spent waiting for a connection to complete
haproxy_server_max_queuegaugeproxy, instance, ins, job, server, ip, clsHighest value of queued connections encountered since process started
haproxy_server_max_queue_time_secondsgaugeproxy, instance, ins, job, server, ip, clsMaximum observed time spent in the queue
haproxy_server_max_response_time_secondsgaugeproxy, instance, ins, job, server, ip, clsMaximum observed time spent waiting for a server response
haproxy_server_max_session_rategaugeproxy, instance, ins, job, server, ip, clsHighest value of sessions per second observed since the worker process started
haproxy_server_max_sessionsgaugeproxy, instance, ins, job, server, ip, clsHighest value of current sessions encountered since process started
haproxy_server_max_total_time_secondsgaugeproxy, instance, ins, job, server, ip, clsMaximum observed total request+response time (request+queue+connect+response+processing)
haproxy_server_need_connections_currentgaugeproxy, instance, ins, job, server, ip, clsEstimated needed number of connections
haproxy_server_queue_limitgaugeproxy, instance, ins, job, server, ip, clsLimit on the number of connections in queue, for servers only (maxqueue argument)
haproxy_server_queue_time_average_secondsgaugeproxy, instance, ins, job, server, ip, clsAvg. queue time for last 1024 successful connections.
haproxy_server_redispatch_warnings_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of server redispatches due to connection failures since the worker process started
haproxy_server_response_errors_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of invalid responses since the worker process started
haproxy_server_response_time_average_secondsgaugeproxy, instance, ins, job, server, ip, clsAvg. response time for last 1024 successful connections.
haproxy_server_responses_denied_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of denied responses since process started
haproxy_server_retry_warnings_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of server connection retries since the worker process started
haproxy_server_safe_idle_connections_currentgaugeproxy, instance, ins, job, server, ip, clsCurrent number of safe idle connections
haproxy_server_server_aborts_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of requests or connections aborted by the server since the worker process started
haproxy_server_sessions_totalcounterproxy, instance, ins, job, server, ip, clsTotal number of sessions since process started
haproxy_server_statusgaugestate, proxy, instance, ins, job, server, ip, clsCurrent status of the service, per state label value.
haproxy_server_total_time_average_secondsgaugeproxy, instance, ins, job, server, ip, clsAvg. total time for last 1024 successful connections.
haproxy_server_unsafe_idle_connections_currentgaugeproxy, instance, ins, job, server, ip, clsCurrent number of unsafe idle connections
haproxy_server_used_connections_currentgaugeproxy, instance, ins, job, server, ip, clsCurrent number of connections in use
haproxy_server_uweightgaugeproxy, instance, ins, job, server, ip, clsServer’s user weight, or sum of active servers’ user weights for a backend
haproxy_server_weightgaugeproxy, instance, ins, job, server, ip, clsServer’s effective weight, or sum of active servers’ effective weights for a backend
haproxy_upUnknowninstance, ins, job, ip, clsN/A
inflight_requestsgaugeinstance, ins, job, route, ip, cls, methodCurrent number of inflight requests.
jaeger_tracer_baggage_restrictions_updates_totalUnknowninstance, ins, job, result, ip, clsN/A
jaeger_tracer_baggage_truncations_totalUnknowninstance, ins, job, ip, clsN/A
jaeger_tracer_baggage_updates_totalUnknowninstance, ins, job, result, ip, clsN/A
jaeger_tracer_finished_spans_totalUnknowninstance, ins, job, sampled, ip, clsN/A
jaeger_tracer_reporter_queue_lengthgaugeinstance, ins, job, ip, clsCurrent number of spans in the reporter queue
jaeger_tracer_reporter_spans_totalUnknowninstance, ins, job, result, ip, clsN/A
jaeger_tracer_sampler_queries_totalUnknowninstance, ins, job, result, ip, clsN/A
jaeger_tracer_sampler_updates_totalUnknowninstance, ins, job, result, ip, clsN/A
jaeger_tracer_span_context_decoding_errors_totalUnknowninstance, ins, job, ip, clsN/A
jaeger_tracer_started_spans_totalUnknowninstance, ins, job, sampled, ip, clsN/A
jaeger_tracer_throttled_debug_spans_totalUnknowninstance, ins, job, ip, clsN/A
jaeger_tracer_throttler_updates_totalUnknowninstance, ins, job, result, ip, clsN/A
jaeger_tracer_traces_totalUnknownstate, instance, ins, job, sampled, ip, clsN/A
loki_experimental_features_in_use_totalUnknowninstance, ins, job, ip, clsN/A
loki_internal_log_messages_totalUnknownlevel, instance, ins, job, ip, clsN/A
loki_log_flushes_bucketUnknowninstance, ins, job, le, ip, clsN/A
loki_log_flushes_countUnknowninstance, ins, job, ip, clsN/A
loki_log_flushes_sumUnknowninstance, ins, job, ip, clsN/A
loki_log_messages_totalUnknownlevel, instance, ins, job, ip, clsN/A
loki_logql_querystats_duplicates_totalUnknowninstance, ins, job, ip, clsN/A
loki_logql_querystats_ingester_sent_lines_totalUnknowninstance, ins, job, ip, clsN/A
loki_querier_index_cache_corruptions_totalUnknowninstance, ins, job, ip, clsN/A
loki_querier_index_cache_encode_errors_totalUnknowninstance, ins, job, ip, clsN/A
loki_querier_index_cache_gets_totalUnknowninstance, ins, job, ip, clsN/A
loki_querier_index_cache_hits_totalUnknowninstance, ins, job, ip, clsN/A
loki_querier_index_cache_puts_totalUnknowninstance, ins, job, ip, clsN/A
net_conntrack_dialer_conn_attempted_totalcounterip, ins, job, instance, cls, dialer_nameTotal number of connections attempted by the given dialer a given name.
net_conntrack_dialer_conn_closed_totalcounterip, ins, job, instance, cls, dialer_nameTotal number of connections closed which originated from the dialer of a given name.
net_conntrack_dialer_conn_established_totalcounterip, ins, job, instance, cls, dialer_nameTotal number of connections successfully established by the given dialer a given name.
net_conntrack_dialer_conn_failed_totalcounterip, ins, job, reason, instance, cls, dialer_nameTotal number of connections failed to dial by the dialer a given name.
node:cls:avail_bytesUnknownjob, clsN/A
node:cls:cpu_countUnknownjob, clsN/A
node:cls:cpu_usageUnknownjob, clsN/A
node:cls:cpu_usage_15mUnknownjob, clsN/A
node:cls:cpu_usage_1mUnknownjob, clsN/A
node:cls:cpu_usage_5mUnknownjob, clsN/A
node:cls:disk_io_bytes_rate1mUnknownjob, clsN/A
node:cls:disk_iops_1mUnknownjob, clsN/A
node:cls:disk_mreads_rate1mUnknownjob, clsN/A
node:cls:disk_mreads_ratio1mUnknownjob, clsN/A
node:cls:disk_mwrites_rate1mUnknownjob, clsN/A
node:cls:disk_mwrites_ratio1mUnknownjob, clsN/A
node:cls:disk_read_bytes_rate1mUnknownjob, clsN/A
node:cls:disk_reads_rate1mUnknownjob, clsN/A
node:cls:disk_write_bytes_rate1mUnknownjob, clsN/A
node:cls:disk_writes_rate1mUnknownjob, clsN/A
node:cls:free_bytesUnknownjob, clsN/A
node:cls:mem_usageUnknownjob, clsN/A
node:cls:network_io_bytes_rate1mUnknownjob, clsN/A
node:cls:network_rx_bytes_rate1mUnknownjob, clsN/A
node:cls:network_rx_pps1mUnknownjob, clsN/A
node:cls:network_tx_bytes_rate1mUnknownjob, clsN/A
node:cls:network_tx_pps1mUnknownjob, clsN/A
node:cls:size_bytesUnknownjob, clsN/A
node:cls:space_usageUnknownjob, clsN/A
node:cls:space_usage_maxUnknownjob, clsN/A
node:cls:stdload1Unknownjob, clsN/A
node:cls:stdload15Unknownjob, clsN/A
node:cls:stdload5Unknownjob, clsN/A
node:cls:time_drift_maxUnknownjob, clsN/A
node:cpu:idle_time_irate1mUnknownip, ins, job, cpu, instance, clsN/A
node:cpu:sched_timeslices_rate1mUnknownip, ins, job, cpu, instance, clsN/A
node:cpu:sched_wait_rate1mUnknownip, ins, job, cpu, instance, clsN/A
node:cpu:time_irate1mUnknownip, mode, ins, job, cpu, instance, clsN/A
node:cpu:total_time_irate1mUnknownip, ins, job, cpu, instance, clsN/A
node:cpu:usageUnknownip, ins, job, cpu, instance, clsN/A
node:cpu:usage_avg15mUnknownip, ins, job, cpu, instance, clsN/A
node:cpu:usage_avg1mUnknownip, ins, job, cpu, instance, clsN/A
node:cpu:usage_avg5mUnknownip, ins, job, cpu, instance, clsN/A
node:dev:disk_avg_queue_sizeUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_io_batch_1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_io_bytes_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_io_rt_1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_io_time_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_iops_1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_mreads_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_mreads_ratio1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_mwrites_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_mwrites_ratio1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_read_batch_1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_read_bytes_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_read_rt_1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_read_time_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_reads_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_util_1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_write_batch_1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_write_bytes_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_write_rt_1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_write_time_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:disk_writes_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:network_io_bytes_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:network_rx_bytes_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:network_rx_pps1mUnknownip, device, ins, job, instance, clsN/A
node:dev:network_tx_bytes_rate1mUnknownip, device, ins, job, instance, clsN/A
node:dev:network_tx_pps1mUnknownip, device, ins, job, instance, clsN/A
node:env:avail_bytesUnknownjobN/A
node:env:cpu_countUnknownjobN/A
node:env:cpu_usageUnknownjobN/A
node:env:cpu_usage_15mUnknownjobN/A
node:env:cpu_usage_1mUnknownjobN/A
node:env:cpu_usage_5mUnknownjobN/A
node:env:device_space_usage_maxUnknowndevice, mountpoint, job, fstypeN/A
node:env:free_bytesUnknownjobN/A
node:env:mem_availUnknownjobN/A
node:env:mem_totalUnknownjobN/A
node:env:mem_usageUnknownjobN/A
node:env:size_bytesUnknownjobN/A
node:env:space_usageUnknownjobN/A
node:env:stdload1UnknownjobN/A
node:env:stdload15UnknownjobN/A
node:env:stdload5UnknownjobN/A
node:fs:avail_bytesUnknownip, device, mountpoint, ins, cls, job, instance, fstypeN/A
node:fs:free_bytesUnknownip, device, mountpoint, ins, cls, job, instance, fstypeN/A
node:fs:inode_freeUnknownip, device, mountpoint, ins, cls, job, instance, fstypeN/A
node:fs:inode_totalUnknownip, device, mountpoint, ins, cls, job, instance, fstypeN/A
node:fs:inode_usageUnknownip, device, mountpoint, ins, cls, job, instance, fstypeN/A
node:fs:inode_usedUnknownip, device, mountpoint, ins, cls, job, instance, fstypeN/A
node:fs:size_bytesUnknownip, device, mountpoint, ins, cls, job, instance, fstypeN/A
node:fs:space_deriv1hUnknownip, device, mountpoint, ins, cls, job, instance, fstypeN/A
node:fs:space_exhaustUnknownip, device, mountpoint, ins, cls, job, instance, fstypeN/A
node:fs:space_predict_1dUnknownip, device, mountpoint, ins, cls, job, instance, fstypeN/A
node:fs:space_usageUnknownip, device, mountpoint, ins, cls, job, instance, fstypeN/A
node:insUnknownid, ip, ins, job, nodename, instance, clsN/A
node:ins:avail_bytesUnknowninstance, ins, job, ip, clsN/A
node:ins:cpu_countUnknowninstance, ins, job, ip, clsN/A
node:ins:cpu_usageUnknowninstance, ins, job, ip, clsN/A
node:ins:cpu_usage_15mUnknowninstance, ins, job, ip, clsN/A
node:ins:cpu_usage_1mUnknowninstance, ins, job, ip, clsN/A
node:ins:cpu_usage_5mUnknowninstance, ins, job, ip, clsN/A
node:ins:ctx_switch_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:disk_io_bytes_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:disk_iops_1mUnknowninstance, ins, job, ip, clsN/A
node:ins:disk_mreads_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:disk_mreads_ratio1mUnknowninstance, ins, job, ip, clsN/A
node:ins:disk_mwrites_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:disk_mwrites_ratio1mUnknowninstance, ins, job, ip, clsN/A
node:ins:disk_read_bytes_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:disk_reads_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:disk_write_bytes_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:disk_writes_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:fd_alloc_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:fd_usageUnknowninstance, ins, job, ip, clsN/A
node:ins:forks_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:free_bytesUnknowninstance, ins, job, ip, clsN/A
node:ins:inode_usageUnknowninstance, ins, job, ip, clsN/A
node:ins:interrupt_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:mem_availUnknowninstance, ins, job, ip, clsN/A
node:ins:mem_commit_ratioUnknowninstance, ins, job, ip, clsN/A
node:ins:mem_kernelUnknowninstance, ins, job, ip, clsN/A
node:ins:mem_rssUnknowninstance, ins, job, ip, clsN/A
node:ins:mem_usageUnknowninstance, ins, job, ip, clsN/A
node:ins:network_io_bytes_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:network_rx_bytes_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:network_rx_pps1mUnknowninstance, ins, job, ip, clsN/A
node:ins:network_tx_bytes_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:network_tx_pps1mUnknowninstance, ins, job, ip, clsN/A
node:ins:pagefault_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:pagein_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:pageout_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:pgmajfault_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:sched_wait_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:size_bytesUnknowninstance, ins, job, ip, clsN/A
node:ins:space_usage_maxUnknowninstance, ins, job, ip, clsN/A
node:ins:stdload1Unknowninstance, ins, job, ip, clsN/A
node:ins:stdload15Unknowninstance, ins, job, ip, clsN/A
node:ins:stdload5Unknowninstance, ins, job, ip, clsN/A
node:ins:swap_usageUnknowninstance, ins, job, ip, clsN/A
node:ins:swapin_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:swapout_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:tcp_active_opens_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:tcp_dropped_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:tcp_errorUnknowninstance, ins, job, ip, clsN/A
node:ins:tcp_error_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:tcp_insegs_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:tcp_outsegs_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:tcp_overflow_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:tcp_passive_opens_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:tcp_retrans_ratio1mUnknowninstance, ins, job, ip, clsN/A
node:ins:tcp_retranssegs_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:tcp_segs_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:time_driftUnknowninstance, ins, job, ip, clsN/A
node:ins:udp_in_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:udp_out_rate1mUnknowninstance, ins, job, ip, clsN/A
node:ins:uptimeUnknowninstance, ins, job, ip, clsN/A
node_arp_entriesgaugeip, device, ins, job, instance, clsARP entries by device
node_boot_time_secondsgaugeinstance, ins, job, ip, clsNode boot time, in unixtime.
node_context_switches_totalcounterinstance, ins, job, ip, clsTotal number of context switches.
node_cooling_device_cur_stategaugeinstance, ins, job, type, ip, clsCurrent throttle state of the cooling device
node_cooling_device_max_stategaugeinstance, ins, job, type, ip, clsMaximum throttle state of the cooling device
node_cpu_guest_seconds_totalcounterip, mode, ins, job, cpu, instance, clsSeconds the CPUs spent in guests (VMs) for each mode.
node_cpu_seconds_totalcounterip, mode, ins, job, cpu, instance, clsSeconds the CPUs spent in each mode.
node_disk_discard_time_seconds_totalcounterip, device, ins, job, instance, clsThis is the total number of seconds spent by all discards.
node_disk_discarded_sectors_totalcounterip, device, ins, job, instance, clsThe total number of sectors discarded successfully.
node_disk_discards_completed_totalcounterip, device, ins, job, instance, clsThe total number of discards completed successfully.
node_disk_discards_merged_totalcounterip, device, ins, job, instance, clsThe total number of discards merged.
node_disk_filesystem_infogaugeip, usage, version, device, uuid, ins, type, job, instance, clsInfo about disk filesystem.
node_disk_infogaugeminor, ip, major, revision, device, model, serial, path, ins, job, instance, clsInfo of /sys/block/<block_device>.
node_disk_io_nowgaugeip, device, ins, job, instance, clsThe number of I/Os currently in progress.
node_disk_io_time_seconds_totalcounterip, device, ins, job, instance, clsTotal seconds spent doing I/Os.
node_disk_io_time_weighted_seconds_totalcounterip, device, ins, job, instance, clsThe weighted # of seconds spent doing I/Os.
node_disk_read_bytes_totalcounterip, device, ins, job, instance, clsThe total number of bytes read successfully.
node_disk_read_time_seconds_totalcounterip, device, ins, job, instance, clsThe total number of seconds spent by all reads.
node_disk_reads_completed_totalcounterip, device, ins, job, instance, clsThe total number of reads completed successfully.
node_disk_reads_merged_totalcounterip, device, ins, job, instance, clsThe total number of reads merged.
node_disk_write_time_seconds_totalcounterip, device, ins, job, instance, clsThis is the total number of seconds spent by all writes.
node_disk_writes_completed_totalcounterip, device, ins, job, instance, clsThe total number of writes completed successfully.
node_disk_writes_merged_totalcounterip, device, ins, job, instance, clsThe number of writes merged.
node_disk_written_bytes_totalcounterip, device, ins, job, instance, clsThe total number of bytes written successfully.
node_dmi_infogaugebios_vendor, ip, product_family, product_version, product_uuid, system_vendor, bios_version, ins, bios_date, cls, job, product_name, instance, chassis_version, chassis_vendor, product_serialA metric with a constant ‘1’ value labeled by bios_date, bios_release, bios_vendor, bios_version, board_asset_tag, board_name, board_serial, board_vendor, board_version, chassis_asset_tag, chassis_serial, chassis_vendor, chassis_version, product_family, product_name, product_serial, product_sku, product_uuid, product_version, system_vendor if provided by DMI.
node_entropy_available_bitsgaugeinstance, ins, job, ip, clsBits of available entropy.
node_entropy_pool_size_bitsgaugeinstance, ins, job, ip, clsBits of entropy pool.
node_exporter_build_infogaugeip, version, revision, goversion, branch, ins, goarch, job, tags, instance, cls, goosA metric with a constant ‘1’ value labeled by version, revision, branch, goversion from which node_exporter was built, and the goos and goarch for the build.
node_filefd_allocatedgaugeinstance, ins, job, ip, clsFile descriptor statistics: allocated.
node_filefd_maximumgaugeinstance, ins, job, ip, clsFile descriptor statistics: maximum.
node_filesystem_avail_bytesgaugeip, device, mountpoint, ins, cls, job, instance, fstypeFilesystem space available to non-root users in bytes.
node_filesystem_device_errorgaugeip, device, mountpoint, ins, cls, job, instance, fstypeWhether an error occurred while getting statistics for the given device.
node_filesystem_filesgaugeip, device, mountpoint, ins, cls, job, instance, fstypeFilesystem total file nodes.
node_filesystem_files_freegaugeip, device, mountpoint, ins, cls, job, instance, fstypeFilesystem total free file nodes.
node_filesystem_free_bytesgaugeip, device, mountpoint, ins, cls, job, instance, fstypeFilesystem free space in bytes.
node_filesystem_readonlygaugeip, device, mountpoint, ins, cls, job, instance, fstypeFilesystem read-only status.
node_filesystem_size_bytesgaugeip, device, mountpoint, ins, cls, job, instance, fstypeFilesystem size in bytes.
node_forks_totalcounterinstance, ins, job, ip, clsTotal number of forks.
node_hwmon_chip_namesgaugechip_name, ip, ins, chip, job, instance, clsAnnotation metric for human-readable chip names
node_hwmon_energy_joule_totalcountersensor, ip, ins, chip, job, instance, clsHardware monitor for joules used so far (input)
node_hwmon_sensor_labelgaugesensor, ip, ins, chip, job, label, instance, clsLabel for given chip and sensor
node_intr_totalcounterinstance, ins, job, ip, clsTotal number of interrupts serviced.
node_ipvs_connections_totalcounterinstance, ins, job, ip, clsThe total number of connections made.
node_ipvs_incoming_bytes_totalcounterinstance, ins, job, ip, clsThe total amount of incoming data.
node_ipvs_incoming_packets_totalcounterinstance, ins, job, ip, clsThe total number of incoming packets.
node_ipvs_outgoing_bytes_totalcounterinstance, ins, job, ip, clsThe total amount of outgoing data.
node_ipvs_outgoing_packets_totalcounterinstance, ins, job, ip, clsThe total number of outgoing packets.
node_load1gaugeinstance, ins, job, ip, cls1m load average.
node_load15gaugeinstance, ins, job, ip, cls15m load average.
node_load5gaugeinstance, ins, job, ip, cls5m load average.
node_memory_Active_anon_bytesgaugeinstance, ins, job, ip, clsMemory information field Active_anon_bytes.
node_memory_Active_bytesgaugeinstance, ins, job, ip, clsMemory information field Active_bytes.
node_memory_Active_file_bytesgaugeinstance, ins, job, ip, clsMemory information field Active_file_bytes.
node_memory_AnonHugePages_bytesgaugeinstance, ins, job, ip, clsMemory information field AnonHugePages_bytes.
node_memory_AnonPages_bytesgaugeinstance, ins, job, ip, clsMemory information field AnonPages_bytes.
node_memory_Bounce_bytesgaugeinstance, ins, job, ip, clsMemory information field Bounce_bytes.
node_memory_Buffers_bytesgaugeinstance, ins, job, ip, clsMemory information field Buffers_bytes.
node_memory_Cached_bytesgaugeinstance, ins, job, ip, clsMemory information field Cached_bytes.
node_memory_CommitLimit_bytesgaugeinstance, ins, job, ip, clsMemory information field CommitLimit_bytes.
node_memory_Committed_AS_bytesgaugeinstance, ins, job, ip, clsMemory information field Committed_AS_bytes.
node_memory_DirectMap1G_bytesgaugeinstance, ins, job, ip, clsMemory information field DirectMap1G_bytes.
node_memory_DirectMap2M_bytesgaugeinstance, ins, job, ip, clsMemory information field DirectMap2M_bytes.
node_memory_DirectMap4k_bytesgaugeinstance, ins, job, ip, clsMemory information field DirectMap4k_bytes.
node_memory_Dirty_bytesgaugeinstance, ins, job, ip, clsMemory information field Dirty_bytes.
node_memory_FileHugePages_bytesgaugeinstance, ins, job, ip, clsMemory information field FileHugePages_bytes.
node_memory_FilePmdMapped_bytesgaugeinstance, ins, job, ip, clsMemory information field FilePmdMapped_bytes.
node_memory_HardwareCorrupted_bytesgaugeinstance, ins, job, ip, clsMemory information field HardwareCorrupted_bytes.
node_memory_HugePages_Freegaugeinstance, ins, job, ip, clsMemory information field HugePages_Free.
node_memory_HugePages_Rsvdgaugeinstance, ins, job, ip, clsMemory information field HugePages_Rsvd.
node_memory_HugePages_Surpgaugeinstance, ins, job, ip, clsMemory information field HugePages_Surp.
node_memory_HugePages_Totalgaugeinstance, ins, job, ip, clsMemory information field HugePages_Total.
node_memory_Hugepagesize_bytesgaugeinstance, ins, job, ip, clsMemory information field Hugepagesize_bytes.
node_memory_Hugetlb_bytesgaugeinstance, ins, job, ip, clsMemory information field Hugetlb_bytes.
node_memory_Inactive_anon_bytesgaugeinstance, ins, job, ip, clsMemory information field Inactive_anon_bytes.
node_memory_Inactive_bytesgaugeinstance, ins, job, ip, clsMemory information field Inactive_bytes.
node_memory_Inactive_file_bytesgaugeinstance, ins, job, ip, clsMemory information field Inactive_file_bytes.
node_memory_KReclaimable_bytesgaugeinstance, ins, job, ip, clsMemory information field KReclaimable_bytes.
node_memory_KernelStack_bytesgaugeinstance, ins, job, ip, clsMemory information field KernelStack_bytes.
node_memory_Mapped_bytesgaugeinstance, ins, job, ip, clsMemory information field Mapped_bytes.
node_memory_MemAvailable_bytesgaugeinstance, ins, job, ip, clsMemory information field MemAvailable_bytes.
node_memory_MemFree_bytesgaugeinstance, ins, job, ip, clsMemory information field MemFree_bytes.
node_memory_MemTotal_bytesgaugeinstance, ins, job, ip, clsMemory information field MemTotal_bytes.
node_memory_Mlocked_bytesgaugeinstance, ins, job, ip, clsMemory information field Mlocked_bytes.
node_memory_NFS_Unstable_bytesgaugeinstance, ins, job, ip, clsMemory information field NFS_Unstable_bytes.
node_memory_PageTables_bytesgaugeinstance, ins, job, ip, clsMemory information field PageTables_bytes.
node_memory_Percpu_bytesgaugeinstance, ins, job, ip, clsMemory information field Percpu_bytes.
node_memory_SReclaimable_bytesgaugeinstance, ins, job, ip, clsMemory information field SReclaimable_bytes.
node_memory_SUnreclaim_bytesgaugeinstance, ins, job, ip, clsMemory information field SUnreclaim_bytes.
node_memory_ShmemHugePages_bytesgaugeinstance, ins, job, ip, clsMemory information field ShmemHugePages_bytes.
node_memory_ShmemPmdMapped_bytesgaugeinstance, ins, job, ip, clsMemory information field ShmemPmdMapped_bytes.
node_memory_Shmem_bytesgaugeinstance, ins, job, ip, clsMemory information field Shmem_bytes.
node_memory_Slab_bytesgaugeinstance, ins, job, ip, clsMemory information field Slab_bytes.
node_memory_SwapCached_bytesgaugeinstance, ins, job, ip, clsMemory information field SwapCached_bytes.
node_memory_SwapFree_bytesgaugeinstance, ins, job, ip, clsMemory information field SwapFree_bytes.
node_memory_SwapTotal_bytesgaugeinstance, ins, job, ip, clsMemory information field SwapTotal_bytes.
node_memory_Unevictable_bytesgaugeinstance, ins, job, ip, clsMemory information field Unevictable_bytes.
node_memory_VmallocChunk_bytesgaugeinstance, ins, job, ip, clsMemory information field VmallocChunk_bytes.
node_memory_VmallocTotal_bytesgaugeinstance, ins, job, ip, clsMemory information field VmallocTotal_bytes.
node_memory_VmallocUsed_bytesgaugeinstance, ins, job, ip, clsMemory information field VmallocUsed_bytes.
node_memory_WritebackTmp_bytesgaugeinstance, ins, job, ip, clsMemory information field WritebackTmp_bytes.
node_memory_Writeback_bytesgaugeinstance, ins, job, ip, clsMemory information field Writeback_bytes.
node_netstat_Icmp6_InErrorsunknowninstance, ins, job, ip, clsStatistic Icmp6InErrors.
node_netstat_Icmp6_InMsgsunknowninstance, ins, job, ip, clsStatistic Icmp6InMsgs.
node_netstat_Icmp6_OutMsgsunknowninstance, ins, job, ip, clsStatistic Icmp6OutMsgs.
node_netstat_Icmp_InErrorsunknowninstance, ins, job, ip, clsStatistic IcmpInErrors.
node_netstat_Icmp_InMsgsunknowninstance, ins, job, ip, clsStatistic IcmpInMsgs.
node_netstat_Icmp_OutMsgsunknowninstance, ins, job, ip, clsStatistic IcmpOutMsgs.
node_netstat_Ip6_InOctetsunknowninstance, ins, job, ip, clsStatistic Ip6InOctets.
node_netstat_Ip6_OutOctetsunknowninstance, ins, job, ip, clsStatistic Ip6OutOctets.
node_netstat_IpExt_InOctetsunknowninstance, ins, job, ip, clsStatistic IpExtInOctets.
node_netstat_IpExt_OutOctetsunknowninstance, ins, job, ip, clsStatistic IpExtOutOctets.
node_netstat_Ip_Forwardingunknowninstance, ins, job, ip, clsStatistic IpForwarding.
node_netstat_TcpExt_ListenDropsunknowninstance, ins, job, ip, clsStatistic TcpExtListenDrops.
node_netstat_TcpExt_ListenOverflowsunknowninstance, ins, job, ip, clsStatistic TcpExtListenOverflows.
node_netstat_TcpExt_SyncookiesFailedunknowninstance, ins, job, ip, clsStatistic TcpExtSyncookiesFailed.
node_netstat_TcpExt_SyncookiesRecvunknowninstance, ins, job, ip, clsStatistic TcpExtSyncookiesRecv.
node_netstat_TcpExt_SyncookiesSentunknowninstance, ins, job, ip, clsStatistic TcpExtSyncookiesSent.
node_netstat_TcpExt_TCPSynRetransunknowninstance, ins, job, ip, clsStatistic TcpExtTCPSynRetrans.
node_netstat_TcpExt_TCPTimeoutsunknowninstance, ins, job, ip, clsStatistic TcpExtTCPTimeouts.
node_netstat_Tcp_ActiveOpensunknowninstance, ins, job, ip, clsStatistic TcpActiveOpens.
node_netstat_Tcp_CurrEstabunknowninstance, ins, job, ip, clsStatistic TcpCurrEstab.
node_netstat_Tcp_InErrsunknowninstance, ins, job, ip, clsStatistic TcpInErrs.
node_netstat_Tcp_InSegsunknowninstance, ins, job, ip, clsStatistic TcpInSegs.
node_netstat_Tcp_OutRstsunknowninstance, ins, job, ip, clsStatistic TcpOutRsts.
node_netstat_Tcp_OutSegsunknowninstance, ins, job, ip, clsStatistic TcpOutSegs.
node_netstat_Tcp_PassiveOpensunknowninstance, ins, job, ip, clsStatistic TcpPassiveOpens.
node_netstat_Tcp_RetransSegsunknowninstance, ins, job, ip, clsStatistic TcpRetransSegs.
node_netstat_Udp6_InDatagramsunknowninstance, ins, job, ip, clsStatistic Udp6InDatagrams.
node_netstat_Udp6_InErrorsunknowninstance, ins, job, ip, clsStatistic Udp6InErrors.
node_netstat_Udp6_NoPortsunknowninstance, ins, job, ip, clsStatistic Udp6NoPorts.
node_netstat_Udp6_OutDatagramsunknowninstance, ins, job, ip, clsStatistic Udp6OutDatagrams.
node_netstat_Udp6_RcvbufErrorsunknowninstance, ins, job, ip, clsStatistic Udp6RcvbufErrors.
node_netstat_Udp6_SndbufErrorsunknowninstance, ins, job, ip, clsStatistic Udp6SndbufErrors.
node_netstat_UdpLite6_InErrorsunknowninstance, ins, job, ip, clsStatistic UdpLite6InErrors.
node_netstat_UdpLite_InErrorsunknowninstance, ins, job, ip, clsStatistic UdpLiteInErrors.
node_netstat_Udp_InDatagramsunknowninstance, ins, job, ip, clsStatistic UdpInDatagrams.
node_netstat_Udp_InErrorsunknowninstance, ins, job, ip, clsStatistic UdpInErrors.
node_netstat_Udp_NoPortsunknowninstance, ins, job, ip, clsStatistic UdpNoPorts.
node_netstat_Udp_OutDatagramsunknowninstance, ins, job, ip, clsStatistic UdpOutDatagrams.
node_netstat_Udp_RcvbufErrorsunknowninstance, ins, job, ip, clsStatistic UdpRcvbufErrors.
node_netstat_Udp_SndbufErrorsunknowninstance, ins, job, ip, clsStatistic UdpSndbufErrors.
node_network_address_assign_typegaugeip, device, ins, job, instance, clsNetwork device property: address_assign_type
node_network_carriergaugeip, device, ins, job, instance, clsNetwork device property: carrier
node_network_carrier_changes_totalcounterip, device, ins, job, instance, clsNetwork device property: carrier_changes_total
node_network_carrier_down_changes_totalcounterip, device, ins, job, instance, clsNetwork device property: carrier_down_changes_total
node_network_carrier_up_changes_totalcounterip, device, ins, job, instance, clsNetwork device property: carrier_up_changes_total
node_network_device_idgaugeip, device, ins, job, instance, clsNetwork device property: device_id
node_network_dormantgaugeip, device, ins, job, instance, clsNetwork device property: dormant
node_network_flagsgaugeip, device, ins, job, instance, clsNetwork device property: flags
node_network_iface_idgaugeip, device, ins, job, instance, clsNetwork device property: iface_id
node_network_iface_linkgaugeip, device, ins, job, instance, clsNetwork device property: iface_link
node_network_iface_link_modegaugeip, device, ins, job, instance, clsNetwork device property: iface_link_mode
node_network_infogaugebroadcast, ip, device, operstate, ins, job, adminstate, duplex, address, instance, clsNon-numeric data from /sys/class/net/, value is always 1.
node_network_mtu_bytesgaugeip, device, ins, job, instance, clsNetwork device property: mtu_bytes
node_network_name_assign_typegaugeip, device, ins, job, instance, clsNetwork device property: name_assign_type
node_network_net_dev_groupgaugeip, device, ins, job, instance, clsNetwork device property: net_dev_group
node_network_protocol_typegaugeip, device, ins, job, instance, clsNetwork device property: protocol_type
node_network_receive_bytes_totalcounterip, device, ins, job, instance, clsNetwork device statistic receive_bytes.
node_network_receive_compressed_totalcounterip, device, ins, job, instance, clsNetwork device statistic receive_compressed.
node_network_receive_drop_totalcounterip, device, ins, job, instance, clsNetwork device statistic receive_drop.
node_network_receive_errs_totalcounterip, device, ins, job, instance, clsNetwork device statistic receive_errs.
node_network_receive_fifo_totalcounterip, device, ins, job, instance, clsNetwork device statistic receive_fifo.
node_network_receive_frame_totalcounterip, device, ins, job, instance, clsNetwork device statistic receive_frame.
node_network_receive_multicast_totalcounterip, device, ins, job, instance, clsNetwork device statistic receive_multicast.
node_network_receive_nohandler_totalcounterip, device, ins, job, instance, clsNetwork device statistic receive_nohandler.
node_network_receive_packets_totalcounterip, device, ins, job, instance, clsNetwork device statistic receive_packets.
node_network_speed_bytesgaugeip, device, ins, job, instance, clsNetwork device property: speed_bytes
node_network_transmit_bytes_totalcounterip, device, ins, job, instance, clsNetwork device statistic transmit_bytes.
node_network_transmit_carrier_totalcounterip, device, ins, job, instance, clsNetwork device statistic transmit_carrier.
node_network_transmit_colls_totalcounterip, device, ins, job, instance, clsNetwork device statistic transmit_colls.
node_network_transmit_compressed_totalcounterip, device, ins, job, instance, clsNetwork device statistic transmit_compressed.
node_network_transmit_drop_totalcounterip, device, ins, job, instance, clsNetwork device statistic transmit_drop.
node_network_transmit_errs_totalcounterip, device, ins, job, instance, clsNetwork device statistic transmit_errs.
node_network_transmit_fifo_totalcounterip, device, ins, job, instance, clsNetwork device statistic transmit_fifo.
node_network_transmit_packets_totalcounterip, device, ins, job, instance, clsNetwork device statistic transmit_packets.
node_network_transmit_queue_lengthgaugeip, device, ins, job, instance, clsNetwork device property: transmit_queue_length
node_network_upgaugeip, device, ins, job, instance, clsValue is 1 if operstate is ‘up’, 0 otherwise.
node_nf_conntrack_entriesgaugeinstance, ins, job, ip, clsNumber of currently allocated flow entries for connection tracking.
node_nf_conntrack_entries_limitgaugeinstance, ins, job, ip, clsMaximum size of connection tracking table.
node_nf_conntrack_stat_dropgaugeinstance, ins, job, ip, clsNumber of packets dropped due to conntrack failure.
node_nf_conntrack_stat_early_dropgaugeinstance, ins, job, ip, clsNumber of dropped conntrack entries to make room for new ones, if maximum table size was reached.
node_nf_conntrack_stat_foundgaugeinstance, ins, job, ip, clsNumber of searched entries which were successful.
node_nf_conntrack_stat_ignoregaugeinstance, ins, job, ip, clsNumber of packets seen which are already connected to a conntrack entry.
node_nf_conntrack_stat_insertgaugeinstance, ins, job, ip, clsNumber of entries inserted into the list.
node_nf_conntrack_stat_insert_failedgaugeinstance, ins, job, ip, clsNumber of entries for which list insertion was attempted but failed.
node_nf_conntrack_stat_invalidgaugeinstance, ins, job, ip, clsNumber of packets seen which can not be tracked.
node_nf_conntrack_stat_search_restartgaugeinstance, ins, job, ip, clsNumber of conntrack table lookups which had to be restarted due to hashtable resizes.
node_os_infogaugeid, ip, version, version_id, ins, instance, job, pretty_name, id_like, clsA metric with a constant ‘1’ value labeled by build_id, id, id_like, image_id, image_version, name, pretty_name, variant, variant_id, version, version_codename, version_id.
node_os_versiongaugeid, ip, ins, instance, job, id_like, clsMetric containing the major.minor part of the OS version.
node_processes_max_processesgaugeinstance, ins, job, ip, clsNumber of max PIDs limit
node_processes_max_threadsgaugeinstance, ins, job, ip, clsLimit of threads in the system
node_processes_pidsgaugeinstance, ins, job, ip, clsNumber of PIDs
node_processes_stategaugestate, instance, ins, job, ip, clsNumber of processes in each state.
node_processes_threadsgaugeinstance, ins, job, ip, clsAllocated threads in system
node_processes_threads_stategaugeinstance, ins, job, thread_state, ip, clsNumber of threads in each state.
node_procs_blockedgaugeinstance, ins, job, ip, clsNumber of processes blocked waiting for I/O to complete.
node_procs_runninggaugeinstance, ins, job, ip, clsNumber of processes in runnable state.
node_schedstat_running_seconds_totalcounterip, ins, job, cpu, instance, clsNumber of seconds CPU spent running a process.
node_schedstat_timeslices_totalcounterip, ins, job, cpu, instance, clsNumber of timeslices executed by CPU.
node_schedstat_waiting_seconds_totalcounterip, ins, job, cpu, instance, clsNumber of seconds spent by processing waiting for this CPU.
node_scrape_collector_duration_secondsgaugeip, collector, ins, job, instance, clsnode_exporter: Duration of a collector scrape.
node_scrape_collector_successgaugeip, collector, ins, job, instance, clsnode_exporter: Whether a collector succeeded.
node_selinux_enabledgaugeinstance, ins, job, ip, clsSELinux is enabled, 1 is true, 0 is false
node_sockstat_FRAG6_inusegaugeinstance, ins, job, ip, clsNumber of FRAG6 sockets in state inuse.
node_sockstat_FRAG6_memorygaugeinstance, ins, job, ip, clsNumber of FRAG6 sockets in state memory.
node_sockstat_FRAG_inusegaugeinstance, ins, job, ip, clsNumber of FRAG sockets in state inuse.
node_sockstat_FRAG_memorygaugeinstance, ins, job, ip, clsNumber of FRAG sockets in state memory.
node_sockstat_RAW6_inusegaugeinstance, ins, job, ip, clsNumber of RAW6 sockets in state inuse.
node_sockstat_RAW_inusegaugeinstance, ins, job, ip, clsNumber of RAW sockets in state inuse.
node_sockstat_TCP6_inusegaugeinstance, ins, job, ip, clsNumber of TCP6 sockets in state inuse.
node_sockstat_TCP_allocgaugeinstance, ins, job, ip, clsNumber of TCP sockets in state alloc.
node_sockstat_TCP_inusegaugeinstance, ins, job, ip, clsNumber of TCP sockets in state inuse.
node_sockstat_TCP_memgaugeinstance, ins, job, ip, clsNumber of TCP sockets in state mem.
node_sockstat_TCP_mem_bytesgaugeinstance, ins, job, ip, clsNumber of TCP sockets in state mem_bytes.
node_sockstat_TCP_orphangaugeinstance, ins, job, ip, clsNumber of TCP sockets in state orphan.
node_sockstat_TCP_twgaugeinstance, ins, job, ip, clsNumber of TCP sockets in state tw.
node_sockstat_UDP6_inusegaugeinstance, ins, job, ip, clsNumber of UDP6 sockets in state inuse.
node_sockstat_UDPLITE6_inusegaugeinstance, ins, job, ip, clsNumber of UDPLITE6 sockets in state inuse.
node_sockstat_UDPLITE_inusegaugeinstance, ins, job, ip, clsNumber of UDPLITE sockets in state inuse.
node_sockstat_UDP_inusegaugeinstance, ins, job, ip, clsNumber of UDP sockets in state inuse.
node_sockstat_UDP_memgaugeinstance, ins, job, ip, clsNumber of UDP sockets in state mem.
node_sockstat_UDP_mem_bytesgaugeinstance, ins, job, ip, clsNumber of UDP sockets in state mem_bytes.
node_sockstat_sockets_usedgaugeinstance, ins, job, ip, clsNumber of IPv4 sockets in use.
node_tcp_connection_statesgaugestate, instance, ins, job, ip, clsNumber of connection states.
node_textfile_scrape_errorgaugeinstance, ins, job, ip, cls1 if there was an error opening or reading a file, 0 otherwise
node_time_clocksource_available_infogaugeip, device, ins, clocksource, job, instance, clsAvailable clocksources read from ‘/sys/devices/system/clocksource’.
node_time_clocksource_current_infogaugeip, device, ins, clocksource, job, instance, clsCurrent clocksource read from ‘/sys/devices/system/clocksource’.
node_time_secondsgaugeinstance, ins, job, ip, clsSystem time in seconds since epoch (1970).
node_time_zone_offset_secondsgaugeinstance, ins, job, time_zone, ip, clsSystem time zone offset in seconds.
node_timex_estimated_error_secondsgaugeinstance, ins, job, ip, clsEstimated error in seconds.
node_timex_frequency_adjustment_ratiogaugeinstance, ins, job, ip, clsLocal clock frequency adjustment.
node_timex_loop_time_constantgaugeinstance, ins, job, ip, clsPhase-locked loop time constant.
node_timex_maxerror_secondsgaugeinstance, ins, job, ip, clsMaximum error in seconds.
node_timex_offset_secondsgaugeinstance, ins, job, ip, clsTime offset in between local system and reference clock.
node_timex_pps_calibration_totalcounterinstance, ins, job, ip, clsPulse per second count of calibration intervals.
node_timex_pps_error_totalcounterinstance, ins, job, ip, clsPulse per second count of calibration errors.
node_timex_pps_frequency_hertzgaugeinstance, ins, job, ip, clsPulse per second frequency.
node_timex_pps_jitter_secondsgaugeinstance, ins, job, ip, clsPulse per second jitter.
node_timex_pps_jitter_totalcounterinstance, ins, job, ip, clsPulse per second count of jitter limit exceeded events.
node_timex_pps_shift_secondsgaugeinstance, ins, job, ip, clsPulse per second interval duration.
node_timex_pps_stability_exceeded_totalcounterinstance, ins, job, ip, clsPulse per second count of stability limit exceeded events.
node_timex_pps_stability_hertzgaugeinstance, ins, job, ip, clsPulse per second stability, average of recent frequency changes.
node_timex_statusgaugeinstance, ins, job, ip, clsValue of the status array bits.
node_timex_sync_statusgaugeinstance, ins, job, ip, clsIs clock synchronized to a reliable server (1 = yes, 0 = no).
node_timex_tai_offset_secondsgaugeinstance, ins, job, ip, clsInternational Atomic Time (TAI) offset.
node_timex_tick_secondsgaugeinstance, ins, job, ip, clsSeconds between clock ticks.
node_udp_queuesgaugeip, queue, ins, job, exported_ip, instance, clsNumber of allocated memory in the kernel for UDP datagrams in bytes.
node_uname_infogaugeip, sysname, version, domainname, release, ins, job, nodename, instance, cls, machineLabeled system information as provided by the uname system call.
node_upUnknowninstance, ins, job, ip, clsN/A
node_vmstat_oom_killunknowninstance, ins, job, ip, cls/proc/vmstat information field oom_kill.
node_vmstat_pgfaultunknowninstance, ins, job, ip, cls/proc/vmstat information field pgfault.
node_vmstat_pgmajfaultunknowninstance, ins, job, ip, cls/proc/vmstat information field pgmajfault.
node_vmstat_pgpginunknowninstance, ins, job, ip, cls/proc/vmstat information field pgpgin.
node_vmstat_pgpgoutunknowninstance, ins, job, ip, cls/proc/vmstat information field pgpgout.
node_vmstat_pswpinunknowninstance, ins, job, ip, cls/proc/vmstat information field pswpin.
node_vmstat_pswpoutunknowninstance, ins, job, ip, cls/proc/vmstat information field pswpout.
process_cpu_seconds_totalcounterinstance, ins, job, ip, clsTotal user and system CPU time spent in seconds.
process_max_fdsgaugeinstance, ins, job, ip, clsMaximum number of open file descriptors.
process_open_fdsgaugeinstance, ins, job, ip, clsNumber of open file descriptors.
process_resident_memory_bytesgaugeinstance, ins, job, ip, clsResident memory size in bytes.
process_start_time_secondsgaugeinstance, ins, job, ip, clsStart time of the process since unix epoch in seconds.
process_virtual_memory_bytesgaugeinstance, ins, job, ip, clsVirtual memory size in bytes.
process_virtual_memory_max_bytesgaugeinstance, ins, job, ip, clsMaximum amount of virtual memory available in bytes.
prometheus_remote_storage_exemplars_in_totalcounterinstance, ins, job, ip, clsExemplars in to remote storage, compare to exemplars out for queue managers.
prometheus_remote_storage_histograms_in_totalcounterinstance, ins, job, ip, clsHistogramSamples in to remote storage, compare to histograms out for queue managers.
prometheus_remote_storage_samples_in_totalcounterinstance, ins, job, ip, clsSamples in to remote storage, compare to samples out for queue managers.
prometheus_remote_storage_string_interner_zero_reference_releases_totalcounterinstance, ins, job, ip, clsThe number of times release has been called for strings that are not interned.
prometheus_sd_azure_failures_totalcounterinstance, ins, job, ip, clsNumber of Azure service discovery refresh failures.
prometheus_sd_consul_rpc_duration_secondssummaryip, call, quantile, ins, job, instance, cls, endpointThe duration of a Consul RPC call in seconds.
prometheus_sd_consul_rpc_duration_seconds_countUnknownip, call, ins, job, instance, cls, endpointN/A
prometheus_sd_consul_rpc_duration_seconds_sumUnknownip, call, ins, job, instance, cls, endpointN/A
prometheus_sd_consul_rpc_failures_totalcounterinstance, ins, job, ip, clsThe number of Consul RPC call failures.
prometheus_sd_consulagent_rpc_duration_secondssummaryip, call, quantile, ins, job, instance, cls, endpointThe duration of a Consul Agent RPC call in seconds.
prometheus_sd_consulagent_rpc_duration_seconds_countUnknownip, call, ins, job, instance, cls, endpointN/A
prometheus_sd_consulagent_rpc_duration_seconds_sumUnknownip, call, ins, job, instance, cls, endpointN/A
prometheus_sd_consulagent_rpc_failures_totalUnknowninstance, ins, job, ip, clsN/A
prometheus_sd_dns_lookup_failures_totalcounterinstance, ins, job, ip, clsThe number of DNS-SD lookup failures.
prometheus_sd_dns_lookups_totalcounterinstance, ins, job, ip, clsThe number of DNS-SD lookups.
prometheus_sd_file_read_errors_totalcounterinstance, ins, job, ip, clsThe number of File-SD read errors.
prometheus_sd_file_scan_duration_secondssummaryquantile, instance, ins, job, ip, clsThe duration of the File-SD scan in seconds.
prometheus_sd_file_scan_duration_seconds_countUnknowninstance, ins, job, ip, clsN/A
prometheus_sd_file_scan_duration_seconds_sumUnknowninstance, ins, job, ip, clsN/A
prometheus_sd_file_watcher_errors_totalcounterinstance, ins, job, ip, clsThe number of File-SD errors caused by filesystem watch failures.
prometheus_sd_kubernetes_events_totalcounterip, event, ins, job, role, instance, clsThe number of Kubernetes events handled.
prometheus_target_scrape_pool_exceeded_label_limits_totalcounterinstance, ins, job, ip, clsTotal number of times scrape pools hit the label limits, during sync or config reload.
prometheus_target_scrape_pool_exceeded_target_limit_totalcounterinstance, ins, job, ip, clsTotal number of times scrape pools hit the target limit, during sync or config reload.
prometheus_target_scrape_pool_reloads_failed_totalcounterinstance, ins, job, ip, clsTotal number of failed scrape pool reloads.
prometheus_target_scrape_pool_reloads_totalcounterinstance, ins, job, ip, clsTotal number of scrape pool reloads.
prometheus_target_scrape_pools_failed_totalcounterinstance, ins, job, ip, clsTotal number of scrape pool creations that failed.
prometheus_target_scrape_pools_totalcounterinstance, ins, job, ip, clsTotal number of scrape pool creation attempts.
prometheus_target_scrapes_cache_flush_forced_totalcounterinstance, ins, job, ip, clsHow many times a scrape cache was flushed due to getting big while scrapes are failing.
prometheus_target_scrapes_exceeded_body_size_limit_totalcounterinstance, ins, job, ip, clsTotal number of scrapes that hit the body size limit
prometheus_target_scrapes_exceeded_sample_limit_totalcounterinstance, ins, job, ip, clsTotal number of scrapes that hit the sample limit and were rejected.
prometheus_target_scrapes_exemplar_out_of_order_totalcounterinstance, ins, job, ip, clsTotal number of exemplar rejected due to not being out of the expected order.
prometheus_target_scrapes_sample_duplicate_timestamp_totalcounterinstance, ins, job, ip, clsTotal number of samples rejected due to duplicate timestamps but different values.
prometheus_target_scrapes_sample_out_of_bounds_totalcounterinstance, ins, job, ip, clsTotal number of samples rejected due to timestamp falling outside of the time bounds.
prometheus_target_scrapes_sample_out_of_order_totalcounterinstance, ins, job, ip, clsTotal number of samples rejected due to not being out of the expected order.
prometheus_template_text_expansion_failures_totalcounterinstance, ins, job, ip, clsThe total number of template text expansion failures.
prometheus_template_text_expansions_totalcounterinstance, ins, job, ip, clsThe total number of template text expansions.
prometheus_treecache_watcher_goroutinesgaugeinstance, ins, job, ip, clsThe current number of watcher goroutines.
prometheus_treecache_zookeeper_failures_totalcounterinstance, ins, job, ip, clsThe total number of ZooKeeper failures.
promhttp_metric_handler_errors_totalcounterip, cause, ins, job, instance, clsTotal number of internal errors encountered by the promhttp metric handler.
promhttp_metric_handler_requests_in_flightgaugeinstance, ins, job, ip, clsCurrent number of scrapes being served.
promhttp_metric_handler_requests_totalcounterip, ins, code, job, instance, clsTotal number of scrapes by HTTP status code.
promtail_batch_retries_totalUnknownhost, ip, ins, job, instance, clsN/A
promtail_build_infogaugeip, version, revision, goversion, branch, ins, goarch, job, tags, instance, cls, goosA metric with a constant ‘1’ value labeled by version, revision, branch, goversion from which promtail was built, and the goos and goarch for the build.
promtail_config_reload_fail_totalUnknowninstance, ins, job, ip, clsN/A
promtail_config_reload_success_totalUnknowninstance, ins, job, ip, clsN/A
promtail_dropped_bytes_totalUnknownhost, ip, ins, job, reason, instance, clsN/A
promtail_dropped_entries_totalUnknownhost, ip, ins, job, reason, instance, clsN/A
promtail_encoded_bytes_totalUnknownhost, ip, ins, job, instance, clsN/A
promtail_file_bytes_totalgaugepath, instance, ins, job, ip, clsNumber of bytes total.
promtail_files_active_totalgaugeinstance, ins, job, ip, clsNumber of active files.
promtail_mutated_bytes_totalUnknownhost, ip, ins, job, reason, instance, clsN/A
promtail_mutated_entries_totalUnknownhost, ip, ins, job, reason, instance, clsN/A
promtail_read_bytes_totalgaugepath, instance, ins, job, ip, clsNumber of bytes read.
promtail_read_lines_totalUnknownpath, instance, ins, job, ip, clsN/A
promtail_request_duration_seconds_bucketUnknownhost, ip, ins, job, status_code, le, instance, clsN/A
promtail_request_duration_seconds_countUnknownhost, ip, ins, job, status_code, instance, clsN/A
promtail_request_duration_seconds_sumUnknownhost, ip, ins, job, status_code, instance, clsN/A
promtail_sent_bytes_totalUnknownhost, ip, ins, job, instance, clsN/A
promtail_sent_entries_totalUnknownhost, ip, ins, job, instance, clsN/A
promtail_targets_active_totalgaugeinstance, ins, job, ip, clsNumber of active total.
promtail_upUnknowninstance, ins, job, ip, clsN/A
request_duration_seconds_bucketUnknowninstance, ins, job, status_code, route, ws, le, ip, cls, methodN/A
request_duration_seconds_countUnknowninstance, ins, job, status_code, route, ws, ip, cls, methodN/A
request_duration_seconds_sumUnknowninstance, ins, job, status_code, route, ws, ip, cls, methodN/A
request_message_bytes_bucketUnknowninstance, ins, job, route, le, ip, cls, methodN/A
request_message_bytes_countUnknowninstance, ins, job, route, ip, cls, methodN/A
request_message_bytes_sumUnknowninstance, ins, job, route, ip, cls, methodN/A
response_message_bytes_bucketUnknowninstance, ins, job, route, le, ip, cls, methodN/A
response_message_bytes_countUnknowninstance, ins, job, route, ip, cls, methodN/A
response_message_bytes_sumUnknowninstance, ins, job, route, ip, cls, methodN/A
scrape_duration_secondsUnknowninstance, ins, job, ip, clsN/A
scrape_samples_post_metric_relabelingUnknowninstance, ins, job, ip, clsN/A
scrape_samples_scrapedUnknowninstance, ins, job, ip, clsN/A
scrape_series_addedUnknowninstance, ins, job, ip, clsN/A
tcp_connectionsgaugeinstance, ins, job, protocol, ip, clsCurrent number of accepted TCP connections.
tcp_connections_limitgaugeinstance, ins, job, protocol, ip, clsThe max number of TCP connections that can be accepted (0 means no limit).
upUnknowninstance, ins, job, ip, clsN/A

12.7 - FAQ

Frequently asked questions about Pigsty NODE module

How to configure NTP service?

NTP is critical for various production services. If NTP is not configured, you can use public NTP services or the Chronyd on the admin node as the time standard.

If your nodes already have NTP configured, you can preserve the existing configuration without making any changes by setting node_ntp_enabled to false.

Otherwise, if you have Internet access, you can use public NTP services such as pool.ntp.org.

If you don’t have Internet access, you can use the following approach to ensure all nodes in the environment are synchronized with the admin node, or use another internal NTP time service.

node_ntp_servers:                 # NTP servers in /etc/chrony.conf
  - pool cn.pool.ntp.org iburst
  - pool ${admin_ip} iburst       # assume non-admin nodes do not have internet access, at least sync with admin node

How to force sync time on nodes?

Use chronyc to sync time. You must configure the NTP service first.

ansible all -b -a 'chronyc -a makestep'     # sync time

You can replace all with any group or host IP address to limit the execution scope.


Remote nodes are not accessible via SSH?

If the target machine is hidden behind an SSH jump host, or some customizations prevent direct access using ssh ip, you can use Ansible connection parameters to specify various SSH connection options, such as:

pg-test:
  vars: { pg_cluster: pg-test }
  hosts:
    10.10.10.11: {pg_seq: 1, pg_role: primary, ansible_host: node-1 }
    10.10.10.12: {pg_seq: 2, pg_role: replica, ansible_port: 22223, ansible_user: admin }
    10.10.10.13: {pg_seq: 3, pg_role: offline, ansible_port: 22224 }

Password required for remote node SSH and SUDO?

When performing deployments and changes, the admin user used must have ssh and sudo privileges for all nodes. Passwordless login is not required.

You can pass ssh and sudo passwords via the -k|-K parameters when executing playbooks, or even use another user to run playbooks via -eansible_host=<another_user>.

However, Pigsty strongly recommends configuring SSH passwordless login with passwordless sudo for the admin user.


How to create a dedicated admin user with an existing admin user?

Use the following command to create a new standard admin user defined by node_admin_username using an existing admin user on that node.

./node.yml -k -K -e ansible_user=<another_admin> -t node_admin

How to expose services using HAProxy on nodes?

You can use haproxy_services in the configuration to expose services, and use node.yml -t haproxy_config,haproxy_reload to update the configuration.

Here’s an example of exposing a MinIO service: Expose MinIO Service


Why are all my /etc/yum.repos.d/* files gone?

Pigsty builds a local software repository on infra nodes that includes all dependencies. All regular nodes will reference and use the local software repository on Infra nodes according to the default configuration of node_repo_modules as local.

This design avoids Internet access and enhances installation stability and reliability. All original repo definition files are moved to the /etc/yum.repos.d/backup directory; you can copy them back as needed.

If you want to preserve the original repo definition files during regular node installation, set node_repo_remove to false.

If you want to preserve the original repo definition files during Infra node local repo construction, set repo_remove to false.


Why did my command line prompt change? How to restore it?

The shell command line prompt used by Pigsty is specified by the environment variable PS1, defined in the /etc/profile.d/node.sh file.

If you don’t like it and want to modify or restore it, you can remove this file and log in again.


Why did my hostname change?

Pigsty will modify your node hostname in two situations:

  • nodename value is explicitly defined (default is empty)
  • The PGSQL module is declared on the node and the node_id_from_pg parameter is enabled (default is true)

If you don’t want the hostname to be modified, you can set nodename_overwrite to false at the global/cluster/instance level (default is true).

For details, see the NODE_ID section.


What compatibility issues exist with Tencent OpenCloudOS?

The softdog kernel module is not available on OpenCloudOS and needs to be removed from node_kernel_modules. Add the following configuration item to the global variables in the config file to override:

node_kernel_modules: [ ip_vs, ip_vs_rr, ip_vs_wrr, ip_vs_sh ]

What common issues exist on Debian systems?

When using Pigsty on Debian/Ubuntu systems, you may encounter the following issues:

Missing locale

If the system reports locale-related errors, you can fix them with the following command:

localedef -i en_US -f UTF-8 en_US.UTF-8

Missing rsync tool

Pigsty relies on rsync for file synchronization. If the system doesn’t have it installed, you can install it with:

apt-get install rsync

13 - Module: ETCD

Pigsty deploys etcd as DCS for reliable distributed config storage, supporting PostgreSQL HA.

ETCD is a distributed, reliable key-value store for critical system config data.

Pigsty uses etcd as DCS (Distributed Config Store), critical for PostgreSQL HA and automatic failover.

The ETCD module depends on NODE module and is required by PGSQL module. Install NODE module to manage nodes before installing ETCD.

Deploy ETCD cluster before any PGSQL cluster—patroni and vip-manager for PG HA rely on etcd for HA and L2 VIP binding to primary.

flowchart LR
    subgraph PGSQL [PGSQL]
        patroni[Patroni]
        vip[VIP Manager]
    end

    subgraph ETCD [ETCD]
        etcd[DCS Service]
    end

    subgraph NODE [NODE]
        node[Software Repo]
    end

    PGSQL -->|depends| ETCD -->|depends| NODE

    style PGSQL fill:#3E668F,stroke:#2d4a66,color:#fff
    style ETCD fill:#5B9CD5,stroke:#4178a8,color:#fff
    style NODE fill:#FCDB72,stroke:#d4b85e,color:#333

    style patroni fill:#2d4a66,stroke:#1e3347,color:#fff
    style vip fill:#2d4a66,stroke:#1e3347,color:#fff
    style etcd fill:#4178a8,stroke:#2d5a7a,color:#fff
    style node fill:#d4b85e,stroke:#b89a4a,color:#333

One etcd cluster per Pigsty deployment serves multiple PG clusters.

Pigsty enables RBAC by default. Each PG cluster uses independent credentials for multi-tenant isolation. Admins use etcd root user with full permissions over all PG clusters.

13.1 - Configuration

Choose etcd cluster size based on requirements, provide reliable access.

Before deployment, define etcd cluster in config inventory. Typical choices:

  • One Node: No HA, suitable for dev, test, demo, or standalone deployments using external S3 backup for PITR
  • Three Nodes: Basic HA, tolerates 1 node failure, suitable for small-medium prod
  • Five Nodes: Better HA, tolerates 2 node failures, suitable for large prod

Even-numbered clusters don’t make sense; 5+ node clusters uncommon. Typical configs: single, 3-node, 5-node.

Cluster SizeQuorumFault ToleranceUse Case
1 node10Dev, test, demo
3 nodes21Small-medium prod
5 nodes32Large prod
7 nodes43Special HA requirements

One Node

Define singleton etcd instance in Pigsty—single line of config:

etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

All single-node config templates include this line. Placeholder IP 10.10.10.10 replaced with current admin node’s IP.

Only required params: etcd_seq and etcd_cluster—uniquely identify each etcd instance.


Three Nodes

Most common config: 3-node etcd cluster tolerates 1 node failure, suitable for small-medium prod.

Example: Pigsty’s 3-node templates trio and safe use 3-node etcd:

etcd:
  hosts:
    10.10.10.10: { etcd_seq: 1 }  # etcd_seq (instance number) required
    10.10.10.11: { etcd_seq: 2 }  # positive integers, sequential from 0 or 1
    10.10.10.12: { etcd_seq: 3 }  # immutable for life, never recycled
  vars: # cluster-level params
    etcd_cluster: etcd    # default cluster name: 'etcd', don't change unless deploying multiple etcd clusters
    etcd_safeguard: false # enable safeguard? Enable after prod init to prevent accidental deletion
    etcd_clean: true      # force remove existing during init? Enable for testing for true idempotency

Five Nodes

5-node cluster tolerates 2 node failures, suitable for large prod.

Example: Pigsty’s prod sim template prod uses 5-node etcd:

etcd:
  hosts:
    10.10.10.21 : { etcd_seq: 1 }
    10.10.10.22 : { etcd_seq: 2 }
    10.10.10.23 : { etcd_seq: 3 }
    10.10.10.24 : { etcd_seq: 4 }
    10.10.10.25 : { etcd_seq: 5 }
  vars: { etcd_cluster: etcd    }

Services Using etcd

Services using etcd in Pigsty:

ServicePurposeConfig File
PatroniPG HA, stores cluster state and config/pg/bin/patroni.yml
VIP-ManagerBinds L2 VIP on PG clusters/etc/default/vip-manager

When etcd cluster membership changes permanently, reload related service configs to ensure correct access.

Update Patroni’s etcd endpoint ref:

./pgsql.yml -t pg_conf                            # regenerate patroni config
ansible all -f 1 -b -a 'systemctl reload patroni' # reload patroni config

Update VIP-Manager’s etcd endpoint ref (only for PGSQL L2 VIP):

./pgsql.yml -t pg_vip_config                           # regenerate vip-manager config
ansible all -f 1 -b -a 'systemctl restart vip-manager' # restart vip-manager

RBAC Authentication Config

v4.0 enables etcd RBAC auth by default. Related params:

ParameterDescriptionDefault
etcd_root_passwordetcd root passwordEtcd.Root
pg_etcd_passwordPatroni’s password for etcdEmpty (uses cluster name)

Prod recommendations:

all:
  vars:
    etcd_root_password: 'YourSecureEtcdPassword'  # change default

etcd:
  hosts:
    10.10.10.10: { etcd_seq: 1 }
    10.10.10.11: { etcd_seq: 2 }
    10.10.10.12: { etcd_seq: 3 }
  vars:
    etcd_cluster: etcd
    etcd_safeguard: true    # enable safeguard for production

Filesystem Layout

Module creates these directories/files on target hosts:

PathPurposePermissions
/etc/etcd/Config dir0750, etcd:etcd
/etc/etcd/etcd.confMain config file0644, etcd:etcd
/etc/etcd/etcd.passRoot password file0640, root:etcd
/etc/etcd/ca.crtCA cert0644, etcd:etcd
/etc/etcd/server.crtServer cert0644, etcd:etcd
/etc/etcd/server.keyServer private key0600, etcd:etcd
/var/lib/etcd/Backup data dir0770, etcd:etcd
/data/etcd/Main data dir (configurable)0700, etcd:etcd
/etc/profile.d/etcdctl.shClient env vars0755, root:root
/etc/systemd/system/etcd.serviceSystemd service0644, root:root



13.2 - Parameters

ETCD module provides 13 configuration parameters for fine-grained control over cluster behavior.

The ETCD module has 13 parameters, divided into two sections:

  • ETCD: 10 parameters for etcd cluster deployment and configuration
  • ETCD_REMOVE: 3 parameters for controlling etcd cluster removal

Parameter Overview

The ETCD parameter group is used for etcd cluster deployment and configuration, including instance identification, cluster name, data directory, ports, and authentication password.

ParameterTypeLevelDescription
etcd_seqintIetcd instance identifier, REQUIRED
etcd_clusterstringCetcd cluster name, fixed to etcd by default
etcd_learnerboolI/Ainitialize etcd instance as learner?
etcd_datapathCetcd data directory, /data/etcd by default
etcd_portportCetcd client port, 2379 by default
etcd_peer_portportCetcd peer port, 2380 by default
etcd_initenumCetcd initial cluster state, new or existing
etcd_election_timeoutintCetcd election timeout, 1000ms by default
etcd_heartbeat_intervalintCetcd heartbeat interval, 100ms by default
etcd_root_passwordpasswordGetcd root user password for RBAC authentication

The ETCD_REMOVE parameter group controls etcd cluster removal behavior, including safeguard protection, data cleanup, and package uninstallation.

ParameterTypeLevelDescription
etcd_safeguardboolG/C/Asafeguard to prevent purging running etcd instances?
etcd_rm_databoolG/C/Aremove etcd data during removal? default is true
etcd_rm_pkgboolG/C/Auninstall etcd packages during removal? default is false

ETCD

This section contains parameters for the etcd role, which are used by the etcd.yml playbook.

Parameters are defined in roles/etcd/defaults/main.yml

#etcd_seq: 1                      # etcd instance identifier, explicitly required
etcd_cluster: etcd                # etcd cluster & group name, etcd by default
etcd_learner: false               # run etcd instance as learner? default is false
etcd_data: /data/etcd             # etcd data directory, /data/etcd by default
etcd_port: 2379                   # etcd client port, 2379 by default
etcd_peer_port: 2380              # etcd peer port, 2380 by default
etcd_init: new                    # etcd initial cluster state, new or existing
etcd_election_timeout: 1000       # etcd election timeout, 1000ms by default
etcd_heartbeat_interval: 100      # etcd heartbeat interval, 100ms by default
etcd_root_password: Etcd.Root     # etcd root user password for RBAC authentication (please change!)

etcd_seq

Parameter: etcd_seq, Type: int, Level: I

etcd instance identifier. This is a required parameter—you must assign a unique identifier to each etcd instance.

Here is an example of a 3-node etcd cluster with identifiers 1 through 3:

etcd: # dcs service for postgres/patroni ha consensus
  hosts:  # 1 node for testing, 3 or 5 for production
    10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
    10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
    10.10.10.12: { etcd_seq: 3 }  # use odd numbers
  vars: # cluster level parameter override roles/etcd
    etcd_cluster: etcd  # mark etcd cluster name etcd
    etcd_safeguard: false # safeguard against purging

etcd_cluster

Parameter: etcd_cluster, Type: string, Level: C

etcd cluster & group name, default value is the hard-coded etcd.

You can modify this parameter when you want to deploy an additional etcd cluster for backup purposes.

etcd_learner

Parameter: etcd_learner, Type: bool, Level: I/A

Initialize etcd instance as learner? Default value is false.

When set to true, the etcd instance will be initialized as a learner, meaning it cannot participate in voting elections within the etcd cluster.

Use Cases:

  • Cluster Expansion: When adding new members to an existing cluster, using learner mode prevents affecting cluster quorum before data synchronization completes
  • Safe Migration: In rolling upgrade or migration scenarios, join as a learner first, then promote after confirming data synchronization

Workflow:

  1. Set etcd_learner: true to initialize the new member as a learner
  2. Wait for data synchronization to complete (check with etcdctl endpoint status)
  3. Use etcdctl member promote <member_id> to promote it to a full member

etcd_data

Parameter: etcd_data, Type: path, Level: C

etcd data directory, default is /data/etcd.

etcd_port

Parameter: etcd_port, Type: port, Level: C

etcd client port, default is 2379.

etcd_peer_port

Parameter: etcd_peer_port, Type: port, Level: C

etcd peer port, default is 2380.

etcd_init

Parameter: etcd_init, Type: enum, Level: C

etcd initial cluster state, can be new or existing, default value: new.

Option Values:

ValueDescriptionUse Case
newCreate a new etcd clusterInitial deployment, cluster rebuild
existingJoin an existing etcd clusterCluster expansion, adding new members

Important Notes:

Usage Examples:

# Create new cluster (default behavior)
./etcd.yml

# Add new member to existing cluster
./etcd.yml -l <new_ip> -e etcd_init=existing

# Or use the convenience script (automatically sets etcd_init=existing)
bin/etcd-add <new_ip>

etcd_election_timeout

Parameter: etcd_election_timeout, Type: int, Level: C

etcd election timeout, default is 1000 (milliseconds), i.e., 1 second.

etcd_heartbeat_interval

Parameter: etcd_heartbeat_interval, Type: int, Level: C

etcd heartbeat interval, default is 100 (milliseconds).

etcd_root_password

Parameter: etcd_root_password, Type: password, Level: G

etcd root user password for RBAC authentication, default value is Etcd.Root.

Pigsty v4.0 enables etcd RBAC (Role-Based Access Control) authentication by default. During cluster initialization, the etcd_auth task automatically creates the root user and enables authentication.

Password Storage Location:

  • Password is stored in /etc/etcd/etcd.pass file
  • File permissions are 0640 (owned by root, readable by etcd group)
  • The etcdctl environment script /etc/profile.d/etcdctl.sh automatically reads this file

Integration with Other Components:

  • Patroni uses the pg_etcd_password parameter to configure the password for connecting to etcd
  • If pg_etcd_password is empty, Patroni will use the cluster name as password (not recommended)
  • VIP-Manager also requires the same authentication credentials to connect to etcd

Security Recommendations:


ETCD_REMOVE

This section contains parameters for the etcd_remove role, which are action flags used by the etcd-rm.yml playbook.

Parameters are defined in roles/etcd_remove/defaults/main.yml

etcd_safeguard: false             # prevent purging running etcd instances?
etcd_rm_data: true                # remove etcd data and config files during removal?
etcd_rm_pkg: false                # uninstall etcd packages during removal?

etcd_safeguard

Parameter: etcd_safeguard, Type: bool, Level: G/C/A

Safeguard to prevent purging running etcd instances? Default value is false.

When enabled, the etcd-rm.yml playbook will abort when detecting running etcd instances, preventing accidental deletion of active etcd clusters.

Recommended Settings:

EnvironmentRecommendedDescription
Dev/TestfalseConvenient for rapid rebuilding and testing
ProductiontruePrevents service interruption from accidental operations

In emergencies, you can override the configuration with command-line parameters:

./etcd-rm.yml -e etcd_safeguard=false

etcd_rm_data

Parameter: etcd_rm_data, Type: bool, Level: G/C/A

Remove etcd data and configuration files during removal? Default value is true.

When enabled, the etcd-rm.yml playbook will delete the following contents when removing a cluster or member:

  • /etc/etcd/ - Configuration directory (including certificates and password files)
  • /var/lib/etcd/ - Alternate data directory
  • {{ etcd_data }} - Primary data directory (default /data/etcd)
  • {{ systemd_dir }}/etcd.service - Systemd service unit file
  • /etc/profile.d/etcdctl.sh - Client environment script
  • /etc/vector/etcd.yaml - Vector log collection config

Use Cases:

ScenarioRecommendedDescription
Complete removaltrue (default)Full cleanup, free disk space
Stop service onlyfalsePreserve data for troubleshooting or recovery
# Stop service only, preserve data
./etcd-rm.yml -e etcd_rm_data=false

etcd_rm_pkg

Parameter: etcd_rm_pkg, Type: bool, Level: G/C/A

Uninstall etcd packages during removal? Default value is false.

When enabled, the etcd-rm.yml playbook will uninstall etcd packages when removing a cluster or member.

Use Cases:

ScenarioRecommendedDescription
Normal removalfalse (default)Keep packages for quick redeployment
Complete cleanuptrueFull uninstall, save disk space
# Uninstall packages during removal
./etcd-rm.yml -e etcd_rm_pkg=true

13.3 - Administration

etcd cluster management SOP: create, destroy, scale, config, and RBAC.

Common etcd admin SOPs:

For more, refer to FAQ: ETCD.


Create Cluster

Define etcd cluster in config inventory:

etcd:
  hosts:
    10.10.10.10: { etcd_seq: 1 }
    10.10.10.11: { etcd_seq: 2 }
    10.10.10.12: { etcd_seq: 3 }
  vars: { etcd_cluster: etcd }

Run etcd.yml playbook:

./etcd.yml  # initialize etcd cluster

For prod etcd clusters, enable safeguard etcd_safeguard to prevent accidental deletion.


Destroy Cluster

Use dedicated etcd-rm.yml playbook to destroy etcd cluster. Use caution!

./etcd-rm.yml                         # remove entire etcd cluster
./etcd-rm.yml -e etcd_safeguard=false # override safeguard

Or use utility script:

bin/etcd-rm                           # remove entire etcd cluster

Removal playbook respects etcd_safeguard. If true, playbook aborts to prevent accidental deletion.


CLI Environment

Uses etcd v3 API by default (v2 removed in v3.6+). Pigsty auto-configures env script /etc/profile.d/etcdctl.sh on etcd nodes, loaded on login.

Example client env config:

alias e="etcdctl"
alias em="etcdctl member"
export ETCDCTL_ENDPOINTS=https://10.10.10.10:2379
export ETCDCTL_CACERT=/etc/etcd/ca.crt
export ETCDCTL_CERT=/etc/etcd/server.crt
export ETCDCTL_KEY=/etc/etcd/server.key

v4.0 enables RBAC auth by default—user auth required:

export ETCDCTL_USER="root:$(cat /etc/etcd/etcd.pass)"

After configuring client env, run etcd CRUD ops:

e put a 10 ; e get a; e del a   # basic KV ops
e member list                    # list cluster members
e endpoint health                # check endpoint health
e endpoint status                # view endpoint status

RBAC Authentication

v4.0 enables etcd RBAC auth by default. During cluster init, etcd_auth task auto-creates root user and enables auth.

Root user password set by etcd_root_password, default: Etcd.Root. Stored in /etc/etcd/etcd.pass with 0640 perms (root-owned, etcd-group readable).

Strongly recommended to change default password in prod:

etcd:
  hosts:
    10.10.10.10: { etcd_seq: 1 }
    10.10.10.11: { etcd_seq: 2 }
    10.10.10.12: { etcd_seq: 3 }
  vars:
    etcd_cluster: etcd
    etcd_root_password: 'YourSecurePassword'  # change default

Client auth methods:

# Method 1: env vars (recommended, auto-configured in /etc/profile.d/etcdctl.sh)
export ETCDCTL_USER="root:$(cat /etc/etcd/etcd.pass)"

# Method 2: command line
etcdctl --user root:YourSecurePassword member list

Patroni and etcd auth:

Patroni uses pg_etcd_password to configure etcd connection password. If empty, Patroni uses cluster name as password (not recommended). Configure separate etcd password per PG cluster in prod.


Reload Config

If etcd cluster membership changes (add/remove members), refresh etcd service endpoint references. These etcd refs in Pigsty need updates:

Config LocationConfig FileUpdate Method
etcd member config/etc/etcd/etcd.conf./etcd.yml -t etcd_conf
etcdctl env vars/etc/profile.d/etcdctl.sh./etcd.yml -t etcd_config
Patroni DCS config/pg/bin/patroni.yml./pgsql.yml -t pg_conf
VIP-Manager config/etc/default/vip-manager./pgsql.yml -t pg_vip_config

Refresh etcd member config:

./etcd.yml -t etcd_conf                           # refresh /etc/etcd/etcd.conf
ansible etcd -f 1 -b -a 'systemctl restart etcd'  # optional: restart etcd instances

Refresh etcdctl client env:

./etcd.yml -t etcd_config                         # refresh /etc/profile.d/etcdctl.sh

Update Patroni DCS endpoint config:

./pgsql.yml -t pg_conf                            # regenerate patroni config
ansible all -f 1 -b -a 'systemctl reload patroni' # reload patroni config

Update VIP-Manager endpoint config (only for PGSQL L2 VIP):

./pgsql.yml -t pg_vip_config                           # regenerate vip-manager config
ansible all -f 1 -b -a 'systemctl restart vip-manager' # restart vip-manager

Add Member

ETCD Reference: Add a member

Use bin/etcd-add script to add new members to existing etcd cluster:

# First add new member definition to config inventory, then:
bin/etcd-add <ip>              # add single new member
bin/etcd-add <ip1> <ip2> ...   # add multiple new members

Script auto-performs:

  • Validates IP address validity
  • Executes etcd.yml playbook (auto-sets etcd_init=existing)
  • Provides safety warnings and countdown
  • Prompts config refresh commands after completion

Manual: Step-by-Step

Add new member to existing etcd cluster:

  1. Update config inventory: Add new instance to etcd group
  2. Notify cluster: Run etcdctl member add (optional, playbook auto-does this)
  3. Initialize new member: Run playbook with etcd_init=existing parameter
  4. Promote member: Promote learner to full member (optional, required when using etcd_learner=true)
  5. Reload config: Update etcd endpoint references for all clients
# After config inventory update, initialize new member
./etcd.yml -l <new_ins_ip> -e etcd_init=existing

# If using learner mode, manually promote
etcdctl member promote <new_ins_server_id>
Detailed: Add member to etcd cluster

Detailed steps. Start from single-instance etcd cluster:

etcd:
  hosts:
    10.10.10.10: { etcd_seq: 1 } # <--- only existing instance in cluster
    10.10.10.11: { etcd_seq: 2 } # <--- add this new member to inventory
  vars: { etcd_cluster: etcd }

Add new member using utility script (recommended):

$ bin/etcd-add 10.10.10.11

Or manual. First use etcdctl member add to announce new learner instance etcd-2 to existing etcd cluster:

$ etcdctl member add etcd-2 --learner=true --peer-urls=https://10.10.10.11:2380
Member 33631ba6ced84cf8 added to cluster 6646fbcf5debc68f

ETCD_NAME="etcd-2"
ETCD_INITIAL_CLUSTER="etcd-2=https://10.10.10.11:2380,etcd-1=https://10.10.10.10:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://10.10.10.11:2380"
ETCD_INITIAL_CLUSTER_STATE="existing"

Check member list with etcdctl member list (or em list), see unstarted new member:

33631ba6ced84cf8, unstarted, , https://10.10.10.11:2380, , true       # unstarted new member here
429ee12c7fbab5c1, started, etcd-1, https://10.10.10.10:2380, https://10.10.10.10:2379, false

Next, use etcd.yml playbook to initialize new etcd instance etcd-2. After completion, new member has started:

$ ./etcd.yml -l 10.10.10.11 -e etcd_init=existing    # must add existing parameter
...
33631ba6ced84cf8, started, etcd-2, https://10.10.10.11:2380, https://10.10.10.11:2379, true
429ee12c7fbab5c1, started, etcd-1, https://10.10.10.10:2380, https://10.10.10.10:2379, false

After new member initialized and running stably, promote from learner to follower:

$ etcdctl member promote 33631ba6ced84cf8   # promote learner to follower
Member 33631ba6ced84cf8 promoted in cluster 6646fbcf5debc68f

$ em list                # check again, new member promoted to full member
33631ba6ced84cf8, started, etcd-2, https://10.10.10.11:2380, https://10.10.10.11:2379, false
429ee12c7fbab5c1, started, etcd-1, https://10.10.10.10:2380, https://10.10.10.10:2379, false

New member added. Don’t forget to reload config so all clients know new member.

Repeat steps to add more members. Prod environments need at least 3 members.


Remove Member

Use bin/etcd-rm script to remove members from etcd cluster:

bin/etcd-rm <ip>              # remove specified member
bin/etcd-rm <ip1> <ip2> ...   # remove multiple members
bin/etcd-rm                   # remove entire etcd cluster

Script auto-performs:

  • Gracefully removes members from cluster
  • Stops and disables etcd service
  • Cleans up data and config files
  • Deregisters from monitoring system

Manual: Step-by-Step

Remove member instance from etcd cluster:

  1. Remove from config inventory: Comment out or delete instance, and reload config
  2. Kick from cluster: Use etcdctl member remove command
  3. Clean up instance: Use etcd-rm.yml playbook to clean up
# Use dedicated removal playbook (recommended)
./etcd-rm.yml -l <ip>

# Or manual
etcdctl member remove <server_id>      # kick from cluster
./etcd-rm.yml -l <ip>                  # clean up instance
Detailed: Remove member from etcd cluster

Example: 3-node etcd cluster, remove instance 3.

Method 1: Utility script (recommended)

$ bin/etcd-rm 10.10.10.12

Script auto-completes all operations: remove from cluster, stop service, clean up data.

Method 2: Manual

First, refresh config by commenting out member to delete, then reload config so all clients stop using this instance.

etcd:
  hosts:
    10.10.10.10: { etcd_seq: 1 }
    10.10.10.11: { etcd_seq: 2 }
    # 10.10.10.12: { etcd_seq: 3 }   # <---- comment out this member
  vars: { etcd_cluster: etcd }

Then use removal playbook:

$ ./etcd-rm.yml -l 10.10.10.12

Playbook auto-executes:

  1. Get member list, find corresponding member ID
  2. Execute etcdctl member remove to kick from cluster
  3. Stop etcd service
  4. Clean up data and config files

If manual:

$ etcdctl member list
429ee12c7fbab5c1, started, etcd-1, https://10.10.10.10:2380, https://10.10.10.10:2379, false
33631ba6ced84cf8, started, etcd-2, https://10.10.10.11:2380, https://10.10.10.11:2379, false
93fcf23b220473fb, started, etcd-3, https://10.10.10.12:2380, https://10.10.10.12:2379, false  # <--- remove this

$ etcdctl member remove 93fcf23b220473fb # kick from cluster
Member 93fcf23b220473fb removed from cluster 6646fbcf5debc68f

After execution, permanently remove from config inventory. Member removal complete.

Repeat to remove more members. Combined with Add Member, perform rolling upgrades and migrations of etcd cluster.


Utility Scripts

v3.6+ provides utility scripts to simplify etcd cluster scaling:

bin/etcd-add

Add new members to existing etcd cluster:

bin/etcd-add <ip>              # add single new member
bin/etcd-add <ip1> <ip2> ...   # add multiple new members

Script features:

  • Validates IP addresses in config inventory
  • Auto-sets etcd_init=existing parameter
  • Executes etcd.yml playbook to complete member addition
  • Prompts config refresh commands after completion

bin/etcd-rm

Remove members or entire cluster from etcd:

bin/etcd-rm <ip>              # remove specified member
bin/etcd-rm <ip1> <ip2> ...   # remove multiple members
bin/etcd-rm                   # remove entire etcd cluster

Script features:

  • Provides safety warnings and confirmation countdown
  • Auto-executes etcd-rm.yml playbook
  • Gracefully removes members from cluster
  • Cleans up data and config files

13.4 - Playbook

Manage etcd clusters with Ansible playbooks and quick command reference.

The ETCD module provides two core playbooks: etcd.yml for installing and configuring etcd clusters, and etcd-rm.yml for removing etcd clusters or members.


etcd.yml

Playbook source: etcd.yml

This playbook installs and configures an etcd cluster on the hardcoded etcd group, then launches the etcd service.

The following subtasks are available in etcd.yml:

  • etcd_assert : Validate etcd identity parameters (etcd_seq must be defined as a non-negative integer)
  • etcd_install : Install etcd packages
  • etcd_dir : Create etcd data and configuration directories
  • etcd_config : Generate etcd configuration
    • etcd_conf : Generate etcd main config file /etc/etcd/etcd.conf
    • etcd_cert : Generate etcd TLS certificates (CA, server cert, private key)
  • etcd_member : Add new member to existing cluster (only runs when etcd_init=existing)
  • etcd_launch : Launch etcd service
  • etcd_auth : Enable RBAC authentication (create root user and enable auth)
  • etcd_register : Register etcd to VictoriaMetrics/Prometheus monitoring

etcd-rm.yml

Playbook source: etcd-rm.yml

A dedicated playbook for removing etcd clusters or individual members. The following subtasks are available in etcd-rm.yml:

  • etcd_safeguard : Check safeguard and abort if enabled
  • etcd_pause : Pause for 3 seconds, allowing user to abort with Ctrl-C
  • etcd_deregister : Remove etcd registration from VictoriaMetrics monitoring targets
  • etcd_leave : Try graceful leaving etcd cluster before purge
  • etcd_svc : Stop and disable etcd service with systemd
  • etcd_data : Remove etcd data (disable with etcd_rm_data=false)
  • etcd_pkg : Uninstall etcd packages (enable with etcd_rm_pkg=true)

The removal playbook uses the etcd_remove role with the following configurable parameters:

  • etcd_safeguard: Prevents accidental removal when set to true
  • etcd_rm_data: Controls whether ETCD data is deleted (default: true)
  • etcd_rm_pkg: Controls whether ETCD packages are uninstalled (default: false)

Demo

asciicast


Cheatsheet

Etcd Installation & Configuration:

./etcd.yml                                      # Initialize etcd cluster
./etcd.yml -t etcd_launch                       # Restart entire etcd cluster
./etcd.yml -t etcd_conf                         # Refresh /etc/etcd/etcd.conf with latest state
./etcd.yml -t etcd_cert                         # Regenerate etcd TLS certificates
./etcd.yml -l 10.10.10.12 -e etcd_init=existing # Scale out: add new member to existing cluster

Etcd Removal & Cleanup:

./etcd-rm.yml                                   # Remove entire etcd cluster
./etcd-rm.yml -l 10.10.10.12                    # Remove single etcd member
./etcd-rm.yml -e etcd_safeguard=false           # Override safeguard to force removal
./etcd-rm.yml -e etcd_rm_data=false             # Stop service only, preserve data
./etcd-rm.yml -e etcd_rm_pkg=true               # Also uninstall etcd packages

Convenience Scripts:

bin/etcd-add <ip>                               # Add new member to existing cluster (recommended)
bin/etcd-rm <ip>                                # Remove specific member from cluster (recommended)
bin/etcd-rm                                     # Remove entire etcd cluster

Safeguard

To prevent accidental deletion, Pigsty’s ETCD module provides a safeguard mechanism controlled by the etcd_safeguard parameter, which defaults to false (safeguard disabled).

For production etcd clusters that have been initialized, it’s recommended to enable the safeguard to prevent accidental deletion of existing etcd instances:

etcd:
  hosts:
    10.10.10.10: { etcd_seq: 1 }
    10.10.10.11: { etcd_seq: 2 }
    10.10.10.12: { etcd_seq: 3 }
  vars:
    etcd_cluster: etcd
    etcd_safeguard: true  # Enable safeguard protection

When etcd_safeguard is set to true, the etcd-rm.yml playbook will detect running etcd instances and abort to prevent accidental deletion. You can override this behavior using command-line parameters:

./etcd-rm.yml -e etcd_safeguard=false  # Force override safeguard

Unless you clearly understand what you’re doing, we do not recommend arbitrarily removing etcd clusters.

13.5 - Monitoring

etcd monitoring dashboards, metrics, and alert rules.

Dashboards

ETCD module provides one monitoring dashboard: Etcd Overview.

ETCD Overview Dashboard

ETCD Overview: Overview of ETCD cluster

Dashboard provides key ETCD status info. Notable: ETCD Aliveness—shows overall etcd cluster service status.

Red bands = instance downtime; blue-gray below = cluster unavailable.

etcd-overview.jpg


Alert Rules

Pigsty provides 5 preset alert rules for etcd, defined in files/prometheus/rules/etcd.yml:

  • EtcdServerDown: etcd node down, CRIT alert
  • EtcdNoLeader: etcd cluster no leader, CRIT alert
  • EtcdQuotaFull: etcd quota > 90%, WARN alert
  • EtcdNetworkPeerRTSlow: etcd network latency slow, INFO alert
  • EtcdWalFsyncSlow: etcd disk fsync slow, INFO alert
#==============================================================#
#                         Aliveness                            #
#==============================================================#
# etcd server instance down
- alert: EtcdServerDown
  expr: etcd_up < 1
  for: 1m
  labels: { level: 0, severity: CRIT, category: etcd }
  annotations:
    summary: "CRIT EtcdServerDown {{ $labels.ins }}@{{ $labels.instance }}"
    description: |
      etcd_up[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value }} < 1
      https://demo.pigsty.io/d/etcd-overview

#==============================================================#
#                         Error                                #
#==============================================================#
# Etcd no Leader triggers P0 alert immediately
# if dcs_failsafe mode not enabled, may cause global outage
- alert: EtcdNoLeader
  expr: min(etcd_server_has_leader) by (cls) < 1
  for: 15s
  labels: { level: 0, severity: CRIT, category: etcd }
  annotations:
    summary: "CRIT EtcdNoLeader: {{ $labels.cls }} {{ $value }}"
    description: |
      etcd_server_has_leader[cls={{ $labels.cls }}] = {{ $value }} < 1
      https://demo.pigsty.io/d/etcd-overview?from=now-5m&to=now&var-cls={{$labels.cls}}

#==============================================================#
#                        Saturation                            #
#==============================================================#
- alert: EtcdQuotaFull
  expr: etcd:cls:quota_usage > 0.90
  for: 1m
  labels: { level: 1, severity: WARN, category: etcd }
  annotations:
    summary: "WARN EtcdQuotaFull: {{ $labels.cls }}"
    description: |
      etcd:cls:quota_usage[cls={{ $labels.cls }}] = {{ $value | printf "%.3f" }} > 90%
      https://demo.pigsty.io/d/etcd-overview

#==============================================================#
#                         Latency                              #
#==============================================================#
# etcd network peer rt p95 > 200ms for 1m
- alert: EtcdNetworkPeerRTSlow
  expr: etcd:ins:network_peer_rt_p95_5m > 0.200
  for: 1m
  labels: { level: 2, severity: INFO, category: etcd }
  annotations:
    summary: "INFO EtcdNetworkPeerRTSlow: {{ $labels.cls }} {{ $labels.ins }}"
    description: |
      etcd:ins:network_peer_rt_p95_5m[cls={{ $labels.cls }}, ins={{ $labels.ins }}] = {{ $value }} > 200ms
      https://demo.pigsty.io/d/etcd-instance?from=now-10m&to=now&var-cls={{ $labels.cls }}
# Etcd wal fsync rt p95 > 50ms
- alert: EtcdWalFsyncSlow
  expr: etcd:ins:wal_fsync_rt_p95_5m > 0.050
  for: 1m
  labels: { level: 2, severity: INFO, category: etcd }
  annotations:
    summary: "INFO EtcdWalFsyncSlow: {{ $labels.cls }} {{ $labels.ins }}"
    description: |
      etcd:ins:wal_fsync_rt_p95_5m[cls={{ $labels.cls }}, ins={{ $labels.ins }}] = {{ $value }} > 50ms
      https://demo.pigsty.io/d/etcd-instance?from=now-10m&to=now&var-cls={{ $labels.cls }}

13.6 - Metrics

Complete monitoring metrics list provided by Pigsty ETCD module

The ETCD module has 177 available metrics.

Metric NameTypeLabelsDescription
etcd:ins:backend_commit_rt_p99_5mUnknowncls, ins, instance, job, ipN/A
etcd:ins:disk_fsync_rt_p99_5mUnknowncls, ins, instance, job, ipN/A
etcd:ins:network_peer_rt_p99_1mUnknowncls, To, ins, instance, job, ipN/A
etcd_cluster_versiongaugecls, cluster_version, ins, instance, job, ipRunning version. 1 = ‘cluster_version’ label with current version
etcd_debugging_auth_revisiongaugecls, ins, instance, job, ipCurrent auth store revision.
etcd_debugging_disk_backend_commit_rebalance_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_debugging_disk_backend_commit_rebalance_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_debugging_disk_backend_commit_rebalance_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_debugging_disk_backend_commit_spill_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_debugging_disk_backend_commit_spill_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_debugging_disk_backend_commit_spill_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_debugging_disk_backend_commit_write_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_debugging_disk_backend_commit_write_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_debugging_disk_backend_commit_write_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_debugging_lease_granted_totalcountercls, ins, instance, job, ipTotal granted leases.
etcd_debugging_lease_renewed_totalcountercls, ins, instance, job, ipRenewed leases seen by leader.
etcd_debugging_lease_revoked_totalcountercls, ins, instance, job, ipRevoked leases.
etcd_debugging_lease_ttl_total_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_debugging_lease_ttl_total_countUnknowncls, ins, instance, job, ipN/A
etcd_debugging_lease_ttl_total_sumUnknowncls, ins, instance, job, ipN/A
etcd_debugging_mvcc_compact_revisiongaugecls, ins, instance, job, ipLast compaction revision in store.
etcd_debugging_mvcc_current_revisiongaugecls, ins, instance, job, ipCurrent store revision.
etcd_debugging_mvcc_db_compaction_keys_totalcountercls, ins, instance, job, ipDB keys compacted.
etcd_debugging_mvcc_db_compaction_lastgaugecls, ins, instance, job, ipLast db compaction unix time. Resets to 0 on start.
etcd_debugging_mvcc_db_compaction_pause_duration_milliseconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_debugging_mvcc_db_compaction_pause_duration_milliseconds_countUnknowncls, ins, instance, job, ipN/A
etcd_debugging_mvcc_db_compaction_pause_duration_milliseconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_debugging_mvcc_db_compaction_total_duration_milliseconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_debugging_mvcc_db_compaction_total_duration_milliseconds_countUnknowncls, ins, instance, job, ipN/A
etcd_debugging_mvcc_db_compaction_total_duration_milliseconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_debugging_mvcc_events_totalcountercls, ins, instance, job, ipEvents sent by this member.
etcd_debugging_mvcc_index_compaction_pause_duration_milliseconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_debugging_mvcc_index_compaction_pause_duration_milliseconds_countUnknowncls, ins, instance, job, ipN/A
etcd_debugging_mvcc_index_compaction_pause_duration_milliseconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_debugging_mvcc_keys_totalgaugecls, ins, instance, job, ipTotal keys.
etcd_debugging_mvcc_pending_events_totalgaugecls, ins, instance, job, ipPending events to send.
etcd_debugging_mvcc_range_totalcountercls, ins, instance, job, ipRanges seen by this member.
etcd_debugging_mvcc_slow_watcher_totalgaugecls, ins, instance, job, ipUnsynced slow watchers.
etcd_debugging_mvcc_total_put_size_in_bytesgaugecls, ins, instance, job, ipTotal put kv size seen by this member.
etcd_debugging_mvcc_watch_stream_totalgaugecls, ins, instance, job, ipWatch streams.
etcd_debugging_mvcc_watcher_totalgaugecls, ins, instance, job, ipWatchers.
etcd_debugging_server_lease_expired_totalcountercls, ins, instance, job, ipExpired leases.
etcd_debugging_snap_save_marshalling_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_debugging_snap_save_marshalling_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_debugging_snap_save_marshalling_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_debugging_snap_save_total_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_debugging_snap_save_total_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_debugging_snap_save_total_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_debugging_store_expires_totalcountercls, ins, instance, job, ipExpired keys.
etcd_debugging_store_reads_totalcountercls, action, ins, instance, job, ipReads (get/getRecursive) to this member.
etcd_debugging_store_watch_requests_totalcountercls, ins, instance, job, ipIncoming watch requests (new/reestablished).
etcd_debugging_store_watchersgaugecls, ins, instance, job, ipActive watchers.
etcd_debugging_store_writes_totalcountercls, action, ins, instance, job, ipWrites (set/compareAndDelete) to this member.
etcd_disk_backend_commit_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_disk_backend_commit_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_disk_backend_commit_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_disk_backend_defrag_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_disk_backend_defrag_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_disk_backend_defrag_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_disk_backend_snapshot_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_disk_backend_snapshot_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_disk_backend_snapshot_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_disk_defrag_inflightgaugecls, ins, instance, job, ipDefrag active. 1 = active, 0 = not.
etcd_disk_wal_fsync_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_disk_wal_fsync_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_disk_wal_fsync_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_disk_wal_write_bytes_totalgaugecls, ins, instance, job, ipWAL bytes written.
etcd_grpc_proxy_cache_hits_totalgaugecls, ins, instance, job, ipCache hits.
etcd_grpc_proxy_cache_keys_totalgaugecls, ins, instance, job, ipKeys/ranges cached.
etcd_grpc_proxy_cache_misses_totalgaugecls, ins, instance, job, ipCache misses.
etcd_grpc_proxy_events_coalescing_totalcountercls, ins, instance, job, ipEvents coalescing.
etcd_grpc_proxy_watchers_coalescing_totalgaugecls, ins, instance, job, ipCurrent watchers coalescing.
etcd_mvcc_db_open_read_transactionsgaugecls, ins, instance, job, ipOpen read transactions.
etcd_mvcc_db_total_size_in_bytesgaugecls, ins, instance, job, ipDB physical bytes allocated.
etcd_mvcc_db_total_size_in_use_in_bytesgaugecls, ins, instance, job, ipDB logical bytes in use.
etcd_mvcc_delete_totalcountercls, ins, instance, job, ipDeletes seen by this member.
etcd_mvcc_hash_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_mvcc_hash_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_mvcc_hash_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_mvcc_hash_rev_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_mvcc_hash_rev_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_mvcc_hash_rev_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_mvcc_put_totalcountercls, ins, instance, job, ipPuts seen by this member.
etcd_mvcc_range_totalcountercls, ins, instance, job, ipRanges seen by this member.
etcd_mvcc_txn_totalcountercls, ins, instance, job, ipTxns seen by this member.
etcd_network_active_peersgaugecls, ins, Local, instance, job, ip, RemoteActive peer connections.
etcd_network_client_grpc_received_bytes_totalcountercls, ins, instance, job, ipgRPC client bytes received.
etcd_network_client_grpc_sent_bytes_totalcountercls, ins, instance, job, ipgRPC client bytes sent.
etcd_network_peer_received_bytes_totalcountercls, ins, instance, job, ip, FromPeer bytes received.
etcd_network_peer_round_trip_time_seconds_bucketUnknowncls, To, ins, instance, job, le, ipN/A
etcd_network_peer_round_trip_time_seconds_countUnknowncls, To, ins, instance, job, ipN/A
etcd_network_peer_round_trip_time_seconds_sumUnknowncls, To, ins, instance, job, ipN/A
etcd_network_peer_sent_bytes_totalcountercls, To, ins, instance, job, ipPeer bytes sent.
etcd_server_apply_duration_seconds_bucketUnknowncls, version, ins, instance, job, le, success, ip, opN/A
etcd_server_apply_duration_seconds_countUnknowncls, version, ins, instance, job, success, ip, opN/A
etcd_server_apply_duration_seconds_sumUnknowncls, version, ins, instance, job, success, ip, opN/A
etcd_server_client_requests_totalcounterclient_api_version, cls, ins, instance, type, job, ipClient requests per version.
etcd_server_go_versiongaugecls, ins, instance, job, server_go_version, ipGo version running. 1 = ‘server_go_version’ label with current version.
etcd_server_has_leadergaugecls, ins, instance, job, ipLeader exists. 1 = exists, 0 = not.
etcd_server_health_failurescountercls, ins, instance, job, ipFailed health checks.
etcd_server_health_successcountercls, ins, instance, job, ipSuccessful health checks.
etcd_server_heartbeat_send_failures_totalcountercls, ins, instance, job, ipLeader heartbeat send failures (likely overloaded from slow disk).
etcd_server_idgaugecls, ins, instance, job, server_id, ipServer/member ID (hex). 1 = ‘server_id’ label with current ID.
etcd_server_is_leadergaugecls, ins, instance, job, ipMember is leader. 1 if is, 0 otherwise.
etcd_server_is_learnergaugecls, ins, instance, job, ipMember is learner. 1 if is, 0 otherwise.
etcd_server_leader_changes_seen_totalcountercls, ins, instance, job, ipLeader changes seen.
etcd_server_learner_promote_successescountercls, ins, instance, job, ipSuccessful learner promotions while this member is leader.
etcd_server_proposals_applied_totalgaugecls, ins, instance, job, ipConsensus proposals applied.
etcd_server_proposals_committed_totalgaugecls, ins, instance, job, ipConsensus proposals committed.
etcd_server_proposals_failed_totalcountercls, ins, instance, job, ipFailed proposals seen.
etcd_server_proposals_pendinggaugecls, ins, instance, job, ipPending proposals to commit.
etcd_server_quota_backend_bytesgaugecls, ins, instance, job, ipBackend storage quota bytes.
etcd_server_read_indexes_failed_totalcountercls, ins, instance, job, ipFailed read indexes seen.
etcd_server_slow_apply_totalcountercls, ins, instance, job, ipSlow apply requests (likely overloaded from slow disk).
etcd_server_slow_read_indexes_totalcountercls, ins, instance, job, ipPending read indexes not in sync with leader or timed out read index requests.
etcd_server_snapshot_apply_in_progress_totalgaugecls, ins, instance, job, ip1 if server applying incoming snapshot. 0 if none.
etcd_server_versiongaugecls, server_version, ins, instance, job, ipVersion running. 1 = ‘server_version’ label with current version.
etcd_snap_db_fsync_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_snap_db_fsync_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_snap_db_fsync_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_snap_db_save_total_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_snap_db_save_total_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_snap_db_save_total_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_snap_fsync_duration_seconds_bucketUnknowncls, ins, instance, job, le, ipN/A
etcd_snap_fsync_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
etcd_snap_fsync_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
etcd_upUnknowncls, ins, instance, job, ipN/A
go_gc_duration_secondssummarycls, ins, instance, job, quantile, ipGC pause duration summary.
go_gc_duration_seconds_countUnknowncls, ins, instance, job, ipN/A
go_gc_duration_seconds_sumUnknowncls, ins, instance, job, ipN/A
go_goroutinesgaugecls, ins, instance, job, ipGoroutines.
go_infogaugecls, version, ins, instance, job, ipGo environment info.
go_memstats_alloc_bytesgaugecls, ins, instance, job, ipBytes allocated and in use.
go_memstats_alloc_bytes_totalcountercls, ins, instance, job, ipBytes allocated, even if freed.
go_memstats_buck_hash_sys_bytesgaugecls, ins, instance, job, ipBytes used by profiling bucket hash table.
go_memstats_frees_totalcountercls, ins, instance, job, ipFrees.
go_memstats_gc_cpu_fractiongaugecls, ins, instance, job, ipGC CPU fraction since program started.
go_memstats_gc_sys_bytesgaugecls, ins, instance, job, ipBytes used for GC system metadata.
go_memstats_heap_alloc_bytesgaugecls, ins, instance, job, ipHeap bytes allocated and in use.
go_memstats_heap_idle_bytesgaugecls, ins, instance, job, ipHeap bytes waiting to be used.
go_memstats_heap_inuse_bytesgaugecls, ins, instance, job, ipHeap bytes in use.
go_memstats_heap_objectsgaugecls, ins, instance, job, ipAllocated objects.
go_memstats_heap_released_bytesgaugecls, ins, instance, job, ipHeap bytes released to OS.
go_memstats_heap_sys_bytesgaugecls, ins, instance, job, ipHeap bytes obtained from system.
go_memstats_last_gc_time_secondsgaugecls, ins, instance, job, ipSeconds since 1970 of last GC.
go_memstats_lookups_totalcountercls, ins, instance, job, ipPointer lookups.
go_memstats_mallocs_totalcountercls, ins, instance, job, ipMallocs.
go_memstats_mcache_inuse_bytesgaugecls, ins, instance, job, ipBytes in use by mcache structures.
go_memstats_mcache_sys_bytesgaugecls, ins, instance, job, ipBytes used for mcache structures from system.
go_memstats_mspan_inuse_bytesgaugecls, ins, instance, job, ipBytes in use by mspan structures.
go_memstats_mspan_sys_bytesgaugecls, ins, instance, job, ipBytes used for mspan structures from system.
go_memstats_next_gc_bytesgaugecls, ins, instance, job, ipHeap bytes when next GC will take place.
go_memstats_other_sys_bytesgaugecls, ins, instance, job, ipBytes used for other system allocations.
go_memstats_stack_inuse_bytesgaugecls, ins, instance, job, ipBytes in use by stack allocator.
go_memstats_stack_sys_bytesgaugecls, ins, instance, job, ipBytes obtained from system for stack allocator.
go_memstats_sys_bytesgaugecls, ins, instance, job, ipBytes obtained from system.
go_threadsgaugecls, ins, instance, job, ipOS threads created.
grpc_server_handled_totalcountercls, ins, instance, job, grpc_code, grpc_method, grpc_type, ip, grpc_serviceRPCs completed on server.
grpc_server_msg_received_totalcountercls, ins, instance, job, grpc_type, grpc_method, ip, grpc_serviceRPC stream messages received on server.
grpc_server_msg_sent_totalcountercls, ins, instance, job, grpc_type, grpc_method, ip, grpc_servicegRPC stream messages sent on server.
grpc_server_started_totalcountercls, ins, instance, job, grpc_type, grpc_method, ip, grpc_serviceRPCs started on server.
os_fd_limitgaugecls, ins, instance, job, ipFD limit.
os_fd_usedgaugecls, ins, instance, job, ipUsed FDs.
process_cpu_seconds_totalcountercls, ins, instance, job, ipUser + system CPU seconds.
process_max_fdsgaugecls, ins, instance, job, ipMax FDs.
process_open_fdsgaugecls, ins, instance, job, ipOpen FDs.
process_resident_memory_bytesgaugecls, ins, instance, job, ipResident memory bytes.
process_start_time_secondsgaugecls, ins, instance, job, ipStart time (unix epoch seconds).
process_virtual_memory_bytesgaugecls, ins, instance, job, ipVirtual memory bytes.
process_virtual_memory_max_bytesgaugecls, ins, instance, job, ipMax virtual memory bytes.
promhttp_metric_handler_requests_in_flightgaugecls, ins, instance, job, ipCurrent scrapes.
promhttp_metric_handler_requests_totalcountercls, ins, instance, job, ip, codeScrapes by HTTP status code.
scrape_duration_secondsUnknowncls, ins, instance, job, ipN/A
scrape_samples_post_metric_relabelingUnknowncls, ins, instance, job, ipN/A
scrape_samples_scrapedUnknowncls, ins, instance, job, ipN/A
scrape_series_addedUnknowncls, ins, instance, job, ipN/A
upUnknowncls, ins, instance, job, ipN/A

13.7 - FAQ

Frequently asked questions about Pigsty etcd module

What is etcd’s role in Pigsty?

etcd is a distributed, reliable key-value store for critical system data. Pigsty uses etcd as DCS (Distributed Config Store) service for Patroni, storing PG HA status.

Patroni uses etcd for: cluster failure detection, auto failover, primary-replica switchover, and cluster config management.

etcd is critical for PG HA. etcd’s availability and DR ensured through multiple distributed nodes.


What’s the appropriate etcd cluster size?

If more than half (including exactly half) of etcd instances unavailable, etcd cluster enters unavailable state—refuses service.

Example: 3-node cluster allows max 1 node failure while 2 others continue; 5-node cluster tolerates 2 node failures.

Note: Learner instances don’t count toward members—3-node cluster with 1 learner = 2 actual members, zero fault tolerance.

In prod, use odd number of instances. For prod, recommend 3-node or 5-node for reliability.


Impact of etcd unavailability?

If etcd cluster unavailable, affects PG control plane but not data plane—existing PG clusters continue running, but Patroni management ops fail.

During etcd failure: PG HA can’t auto failover, can’t use patronictl for PG management (config changes, manual failover, etc.).

Ansible playbooks unaffected by etcd failure: create DB, create user, refresh HBA/Service config. During etcd failure, operate PG clusters directly.

Note: Behavior applies to Patroni >=3.0 (Pigsty >=2.0). With older Patroni (<3.0, Pigsty 1.x), etcd/consul failure causes severe global impact:

All PG clusters demote: primaries → replicas, reject writes, etcd failure amplifies to global PG failure. Patroni 3.0 introduced DCS Failsafe—significantly improved.


What data does etcd store?

In Pigsty, etcd is PG HA only—no other config/state data.

PG HA component Patroni auto-generates and manages etcd data. If lost in etcd, Patroni auto-rebuilds.

Thus, by default, etcd in Pigsty = “stateless service”—destroyable and rebuildable, simplifies maintenance.

If using etcd for other purposes (K8s metadata, custom storage), backup etcd data yourself and restore after cluster recovery.


Recover from etcd failure?

Since etcd in Pigsty = PG HA only = “stateless service”—disposable, rebuildable. Failures? “restart” or “reset” to stop bleeding.

Restart etcd cluster:

./etcd.yml -t etcd_launch

Reset etcd cluster:

./etcd.yml

For custom etcd data: backup and restore after recovery.


Etcd maintenance considerations?

Simple answer: don’t fill up etcd.

Pigsty v2.6+ enables etcd auto-compaction and 16GB backend quota—usually fine.

etcd’s data model = each write generates new version.

Frequent writes (even few keys) = growing etcd DB size. At capacity limit, etcd rejects writes → PG HA breaks.

Pigsty’s default etcd config includes optimizations:

auto-compaction-mode: periodic      # periodic auto compaction
auto-compaction-retention: "24h"    # retain 24 hours history
quota-backend-bytes: 17179869184    # 16 GiB quota

More details: etcd official maintenance guide.


Enable etcd auto garbage collection?

Earlier Pigsty (v2.0 - v2.5)? Enable etcd auto-compaction in prod to avoid quota-based unavailability.

Edit etcd config template: roles/etcd/templates/etcd.conf.j2:

auto-compaction-mode: periodic
auto-compaction-retention: "24h"
quota-backend-bytes: 17179869184

Then set related PG clusters to maintenance mode and redeploy etcd with ./etcd.yml.

This increases default quota from 2 GiB → 16 GiB, retains last 24h writes—avoids infinite growth.


Where is PG HA data stored in etcd?

By default, Patroni uses pg_namespace prefix (default: /pg) for all metadata keys, followed by PG cluster name.

Example: PG cluster pg-meta stores metadata under /pg/pg-meta.

etcdctl get /pg/pg-meta --prefix

Sample data:

/pg/pg-meta/config
{"ttl":30,"loop_wait":10,"retry_timeout":10,"primary_start_timeout":10,"maximum_lag_on_failover":1048576,"maximum_lag_on_syncnode":-1,"primary_stop_timeout":30,"synchronous_mode":false,"synchronous_mode_strict":false,"failsafe_mode":true,"pg_version":16,"pg_cluster":"pg-meta","pg_shard":"pg-meta","pg_group":0,"postgresql":{"use_slots":true,"use_pg_rewind":true,"remove_data_directory_on_rewind_failure":true,"parameters":{"max_connections":100,"superuser_reserved_connections":10,"max_locks_per_transaction":200,"max_prepared_transactions":0,"track_commit_timestamp":"on","wal_level":"logical","wal_log_hints":"on","max_worker_processes":16,"max_wal_senders":50,"max_replication_slots":50,"password_encryption":"scram-sha-256","ssl":"on","ssl_cert_file":"/pg/cert/server.crt","ssl_key_file":"/pg/cert/server.key","ssl_ca_file":"/pg/cert/ca.crt","shared_buffers":"7969MB","maintenance_work_mem":"1993MB","work_mem":"79MB","max_parallel_workers":8,"max_parallel_maintenance_workers":2,"max_parallel_workers_per_gather":0,"hash_mem_multiplier":8.0,"huge_pages":"try","temp_file_limit":"7GB","vacuum_cost_delay":"20ms","vacuum_cost_limit":2000,"bgwriter_delay":"10ms","bgwriter_lru_maxpages":800,"bgwriter_lru_multiplier":5.0,"min_wal_size":"7GB","max_wal_size":"28GB","max_slot_wal_keep_size":"42GB","wal_buffers":"16MB","wal_writer_delay":"20ms","wal_writer_flush_after":"1MB","commit_delay":20,"commit_siblings":10,"checkpoint_timeout":"15min","checkpoint_completion_target":0.8,"archive_mode":"on","archive_timeout":300,"archive_command":"pgbackrest --stanza=pg-meta archive-push %p","max_standby_archive_delay":"10min","max_standby_streaming_delay":"3min","wal_receiver_status_interval":"1s","hot_standby_feedback":"on","wal_receiver_timeout":"60s","max_logical_replication_workers":8,"max_sync_workers_per_subscription":6,"random_page_cost":1.1,"effective_io_concurrency":1000,"effective_cache_size":"23907MB","default_statistics_target":200,"log_destination":"csvlog","logging_collector":"on","l...
ode=prefer"}}
/pg/pg-meta/failsafe
{"pg-meta-2":"http://10.10.10.11:8008/patroni","pg-meta-1":"http://10.10.10.10:8008/patroni"}
/pg/pg-meta/initialize
7418384210787662172
/pg/pg-meta/leader
pg-meta-1
/pg/pg-meta/members/pg-meta-1
{"conn_url":"postgres://10.10.10.10:5432/postgres","api_url":"http://10.10.10.10:8008/patroni","state":"running","role":"primary","version":"4.0.1","tags":{"clonefrom":true,"version":"16","spec":"8C.32G.125G","conf":"tiny.yml"},"xlog_location":184549376,"timeline":1}
/pg/pg-meta/members/pg-meta-2
{"conn_url":"postgres://10.10.10.11:5432/postgres","api_url":"http://10.10.10.11:8008/patroni","state":"running","role":"replica","version":"4.0.1","tags":{"clonefrom":true,"version":"16","spec":"8C.32G.125G","conf":"tiny.yml"},"xlog_location":184549376,"replication_state":"streaming","timeline":1}
/pg/pg-meta/status
{"optime":184549376,"slots":{"pg_meta_2":184549376,"pg_meta_1":184549376},"retain_slots":["pg_meta_1","pg_meta_2"]}

Use external existing etcd cluster?

Config inventory hardcodes etcd group—members used as DCS servers for PGSQL. Initialize with etcd.yml or assume external cluster exists.

To use external etcd: define as usual. Skip etcd.yml execution since cluster exists—no deployment needed.

Requirement: external etcd cluster certificate must use same CA as Pigsty—otherwise clients can’t use Pigsty’s self-signed certs.


Add new member to existing etcd cluster?

For detailed process, refer to Add member to etcd cluster

Recommended: Utility script

# First add new member to config inventory, then:
bin/etcd-add <ip>      # add single new member
bin/etcd-add <ip1>     # add multiple new members

Manual method:

etcdctl member add <etcd-?> --learner=true --peer-urls=https://<new_ins_ip>:2380 # announce new member
./etcd.yml -l <new_ins_ip> -e etcd_init=existing                                 # initialize new member
etcdctl member promote <new_ins_server_id>                                       # promote to full member

Recommend: add one new member at a time.


Remove member from existing etcd cluster?

For detailed process, refer to Remove member from etcd cluster

Recommended: Utility script

bin/etcd-rm <ip>              # remove specified member
bin/etcd-rm                   # remove entire etcd cluster

Manual method:

./etcd-rm.yml -l <ins_ip>                    # use dedicated removal playbook
etcdctl member remove <etcd_server_id>       # kick from cluster
./etcd-rm.yml -l <ins_ip>                    # clean up instance

Configure etcd RBAC authentication?

Pigsty v4.0 enables etcd RBAC auth by default. Root password set by etcd_root_password, default: Etcd.Root.

Prod recommendation: change default password

all:
  vars:
    etcd_root_password: 'YourSecurePassword'

Client auth:

# On etcd nodes, env vars auto-configured
source /etc/profile.d/etcdctl.sh
etcdctl member list

# Manual auth config
export ETCDCTL_USER="root:YourSecurePassword"
export ETCDCTL_CACERT=/etc/etcd/ca.crt
export ETCDCTL_CERT=/etc/etcd/server.crt
export ETCDCTL_KEY=/etc/etcd/server.key

More: RBAC Authentication.

14 - Module: MINIO

Pigsty has built-in MinIO support, an open-source S3-compatible object storage that can be used for PGSQL cold backup storage.

MinIO is an S3-compatible multi-cloud object storage software, open-sourced under the AGPLv3 license.

MinIO can be used to store documents, images, videos, and backups. Pigsty natively supports deploying various MinIO clusters with native multi-node multi-disk high availability support, easy to scale, secure, and ready to use out of the box. It has been used in production environments at 10PB+ scale.

MinIO is an optional module in Pigsty. You can use MinIO as an optional storage repository for PostgreSQL backups, supplementing the default local POSIX filesystem repository. If using the MinIO backup repository, the MINIO module should be installed before any PGSQL modules. MinIO requires a trusted CA certificate to work, so it depends on the NODE module.


Quick Start

Here’s a simple example of MinIO single-node single-disk deployment:

# Define MinIO cluster in the config inventory
minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }
./minio.yml -l minio    # Deploy MinIO module on the minio group

After deployment, you can access MinIO via:

  • S3 API: https://sss.pigsty:9000 (requires DNS resolution for the domain)
  • Web Console: https://<minio-ip>:9001 (default username/password: minioadmin / S3User.MinIO)
  • Command Line: mcli ls sss/ (alias pre-configured on the admin node)

Deployment Modes

MinIO supports three major deployment modes:

ModeDescriptionUse Cases
Single-Node Single-Disk (SNSD)Single node, single data directoryDevelopment, testing, demo
Single-Node Multi-Disk (SNMD)Single node, multiple disksResource-constrained small-scale deployments
Multi-Node Multi-Disk (MNMD)Multiple nodes, multiple disks per nodeRecommended for production

Additionally, you can use multi-pool deployment to scale existing clusters, or deploy multiple clusters.


Key Features

  • S3 Compatible: Fully compatible with AWS S3 API, seamlessly integrates with various S3 clients and tools
  • High Availability: Native support for multi-node multi-disk deployment, tolerates node and disk failures
  • Secure: HTTPS encrypted transmission enabled by default, supports server-side encryption
  • Monitoring: Out-of-the-box Grafana dashboards and Prometheus alerting rules
  • Easy to Use: Pre-configured mcli client alias, one-click deployment and management

14.1 - Usage

Getting started: how to use MinIO? How to reliably access MinIO? How to use mc / rclone client tools?

After you configure and deploy the MinIO cluster with the playbook, you can start using and accessing the MinIO cluster by following the instructions here.


Deploy Cluster

Deploying an out-of-the-box single-node single-disk MinIO instance in Pigsty is straightforward. First, define a MinIO cluster in the config inventory:

minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

Then, run the minio.yml playbook provided by Pigsty against the defined group (here minio):

./minio.yml -l minio

Note that in install.yml, pre-defined MinIO clusters will be automatically created, so you don’t need to manually run the minio.yml playbook again.

If you plan to deploy a production-grade large-scale multi-node MinIO cluster, we strongly recommend reading the Pigsty MinIO configuration documentation and the MinIO official documentation before proceeding.


Access Cluster

Note: MinIO services must be accessed via domain name and HTTPS, so make sure the MinIO service domain (default sss.pigsty) correctly points to the MinIO server node.

  1. You can add static resolution records in node_etc_hosts, or manually modify the /etc/hosts file
  2. You can add a record on the internal DNS server if you already have an existing DNS service
  3. If you have enabled the DNS server on Infra nodes, you can add records in dns_records

For production environment access to MinIO, we recommend using the first method: static DNS resolution records, to avoid MinIO’s additional dependency on DNS.

You should point the MinIO service domain to the IP address and service port of the MinIO server node, or the IP address and service port of the load balancer. Pigsty uses the default MinIO service domain sss.pigsty, which defaults to localhost for single-node deployment, serving on port 9000.

In some examples, HAProxy instances are also deployed on the MinIO cluster to expose services. In this case, 9002 is the service port used in the templates.


Adding Alias

To access the MinIO server cluster using the mcli client, you need to first configure the server alias:

mcli alias ls  # list minio alias (default is sss)
mcli alias set sss https://sss.pigsty:9000 minioadmin S3User.MinIO            # root user
mcli alias set sss https://sss.pigsty:9002 minioadmin S3User.MinIO            # root user, using load balancer port 9002

mcli alias set pgbackrest https://sss.pigsty:9000 pgbackrest S3User.Backup    # use backup user

On the admin user of the admin node, a MinIO alias named sss is pre-configured and can be used directly.

For the full functionality reference of the MinIO client tool mcli, please refer to the documentation: MinIO Client.


User Management

You can manage business users in MinIO using mcli. For example, here we can create two business users using the command line:

mcli admin user list sss     # list all users on sss
set +o history # hide password in history and create minio users
mcli admin user add sss dba S3User.DBA
mcli admin user add sss pgbackrest S3User.Backup
set -o history

Bucket Management

You can perform CRUD operations on buckets in MinIO:

mcli ls sss/                         # list all buckets on alias 'sss'
mcli mb --ignore-existing sss/hello  # create a bucket named 'hello'
mcli rb --force sss/hello            # force delete the 'hello' bucket

Object Management

You can also perform CRUD operations on objects within buckets. For details, please refer to the official documentation: Object Management

mcli cp /www/pigsty/* sss/infra/     # upload local repo content to MinIO infra bucket
mcli cp sss/infra/plugins.tgz /tmp/  # download file from minio to local
mcli ls sss/infra                    # list all files in the infra bucket
mcli rm sss/infra/plugins.tgz        # delete specific file in infra bucket
mcli cat sss/infra/repo_complete     # view file content in infra bucket

Using rclone

Pigsty repository provides rclone, a convenient multi-cloud object storage client that you can use to access MinIO services.

yum install rclone;  # EL-compatible systems
apt install rclone;  # Debian/Ubuntu systems

mkdir -p ~/.config/rclone/;
tee ~/.config/rclone/rclone.conf > /dev/null <<EOF
[sss]
type = s3
access_key_id = minioadmin
secret_access_key = S3User.MinIO
endpoint = https://sss.pigsty:9000
EOF

rclone ls sss:/

Configure Backup Repository

In Pigsty, the default use case for MinIO is as a backup storage repository for pgBackRest. When you modify pgbackrest_method to minio, the PGSQL module will automatically switch the backup repository to MinIO.

pgbackrest_method: local          # pgbackrest repo method: local,minio,[user-defined...]
pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
  local:                          # default pgbackrest repo with local posix fs
    path: /pg/backup              # local backup directory, `/pg/backup` by default
    retention_full_type: count    # retention full backups by count
    retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
  minio:                          # optional minio repo for pgbackrest
    type: s3                      # minio is s3-compatible, so s3 is used
    s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
    s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
    s3_bucket: pgsql              # minio bucket name, `pgsql` by default
    s3_key: pgbackrest            # minio user access key for pgbackrest
    s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
    s3_uri_style: path            # use path style uri for minio rather than host style
    path: /pgbackrest             # minio backup path, default is `/pgbackrest`
    storage_port: 9000            # minio port, 9000 by default
    storage_ca_file: /pg/cert/ca.crt  # minio ca file path, `/pg/cert/ca.crt` by default
    bundle: y                     # bundle small files into a single file
    cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
    cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
    retention_full_type: time     # retention full backup by time on minio repo
    retention_full: 14            # keep full backup for last 14 days

Note that if you are using a multi-node MinIO cluster and exposing services through a load balancer, you need to modify the s3_endpoint and storage_port parameters accordingly.




14.2 - Configuration

Choose the appropriate MinIO deployment type based on your requirements and provide reliable access.

Before deploying MinIO, you need to define a MinIO cluster in the config inventory. MinIO has three classic deployment modes:

  • Single-Node Single-Disk: SNSD: Single-node single-disk mode, can use any directory as a data disk, for development, testing, and demo only.
  • Single-Node Multi-Disk: SNMD: Compromise mode, using multiple disks (>=2) on a single server, only when resources are extremely limited.
  • Multi-Node Multi-Disk: MNMD: Multi-node multi-disk mode, standard production deployment with the best reliability, but requires multiple servers.

We recommend using SNSD and MNMD modes - the former for development and testing, the latter for production deployment. SNMD should only be used when resources are limited (only one server).

Additionally, you can use multi-pool deployment to scale existing MinIO clusters, or directly deploy multiple clusters.

When using a multi-node MinIO cluster, you can access the service from any node, so the best practice is to use load balancing with high availability service access in front of the MinIO cluster.


Core Parameters

In MinIO deployment, MINIO_VOLUMES is a core configuration parameter that specifies the MinIO deployment mode. Pigsty provides convenient parameters to automatically generate MINIO_VOLUMES and other configuration values based on the config inventory, but you can also specify them directly.

  • Single-Node Single-Disk: MINIO_VOLUMES points to a regular directory on the local machine, specified by minio_data, defaulting to /data/minio.
  • Single-Node Multi-Disk: MINIO_VOLUMES points to a series of mount points on the local machine, also specified by minio_data, but requires special syntax to explicitly specify real mount points, e.g., /data{1...4}.
  • Multi-Node Multi-Disk: MINIO_VOLUMES points to mount points across multiple servers, automatically generated from two parts:
    • First, use minio_data to specify the disk mount point sequence for each cluster member /data{1...4}
    • Also use minio_node to specify the node naming pattern ${minio_cluster}-${minio_seq}.pigsty
  • Multi-Pool: You need to explicitly specify the minio_volumes parameter to allocate nodes for each storage pool

Single-Node Single-Disk

SNSD mode, deployment reference: MinIO Single-Node Single-Drive

In Pigsty, defining a singleton MinIO instance is straightforward:

# 1 Node 1 Driver (DEFAULT)
minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

In single-node mode, the only required parameters are minio_seq and minio_cluster, which uniquely identify each MinIO instance.

Single-node single-disk mode is for development purposes only, so you can use a regular directory as the data directory, specified by minio_data, defaulting to /data/minio.

When using MinIO, we strongly recommend accessing it via a statically resolved domain name. For example, if minio_domain uses the default sss.pigsty, you can add a static resolution on all nodes to facilitate access to this service.

node_etc_hosts: ["10.10.10.10 sss.pigsty"] # domain name to access minio from all nodes (required)

Single-Node Multi-Disk

SNMD mode, deployment reference: MinIO Single-Node Multi-Drive

To use multiple disks on a single node, the operation is similar to Single-Node Single-Disk, but you need to specify minio_data in the format {{ prefix }}{x...y}, which defines a series of disk mount points.

minio:
  hosts: { 10.10.10.10: { minio_seq: 1 } }
  vars:
    minio_cluster: minio         # minio cluster name, minio by default
    minio_data: '/data{1...4}'   # minio data dir(s), use {x...y} to specify multi drivers

For example, the Vagrant MinIO sandbox defines a single-node MinIO cluster with 4 disks: /data1, /data2, /data3, and /data4. Before starting MinIO, you need to mount them properly (be sure to format disks with xfs):

mkfs.xfs /dev/vdb; mkdir /data1; mount -t xfs /dev/sdb /data1;   # mount disk 1...
mkfs.xfs /dev/vdc; mkdir /data2; mount -t xfs /dev/sdb /data2;   # mount disk 2...
mkfs.xfs /dev/vdd; mkdir /data3; mount -t xfs /dev/sdb /data3;   # mount disk 3...
mkfs.xfs /dev/vde; mkdir /data4; mount -t xfs /dev/sdb /data4;   # mount disk 4...

Disk mounting is part of server provisioning and beyond Pigsty’s scope. Mounted disks should be written to /etc/fstab for auto-mounting after server restart.

/dev/vdb /data1 xfs defaults,noatime,nodiratime 0 0
/dev/vdc /data2 xfs defaults,noatime,nodiratime 0 0
/dev/vdd /data3 xfs defaults,noatime,nodiratime 0 0
/dev/vde /data4 xfs defaults,noatime,nodiratime 0 0

SNMD mode can utilize multiple disks on a single machine to provide higher performance and capacity, and tolerate partial disk failures. However, single-node mode cannot tolerate entire node failure, and you cannot add new nodes at runtime, so we do not recommend using SNMD mode in production unless you have special reasons.


Multi-Node Multi-Disk

MNMD mode, deployment reference: MinIO Multi-Node Multi-Drive

In addition to minio_data for specifying disk drives as in Single-Node Multi-Disk mode, multi-node MinIO deployment requires an additional minio_node parameter.

For example, the following configuration defines a MinIO cluster with four nodes, each with four disks:

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 }  # actual nodename: minio-1.pigsty
    10.10.10.11: { minio_seq: 2 }  # actual nodename: minio-2.pigsty
    10.10.10.12: { minio_seq: 3 }  # actual nodename: minio-3.pigsty
    10.10.10.13: { minio_seq: 4 }  # actual nodename: minio-4.pigsty
  vars:
    minio_cluster: minio
    minio_data: '/data{1...4}'                         # 4-disk per node
    minio_node: '${minio_cluster}-${minio_seq}.pigsty' # minio node name pattern

The minio_node parameter specifies the MinIO node name pattern, used to generate a unique name for each node. By default, the node name is ${minio_cluster}-${minio_seq}.pigsty, where ${minio_cluster} is the cluster name and ${minio_seq} is the node sequence number. The MinIO instance name is crucial and will be automatically written to /etc/hosts on MinIO nodes for static resolution. MinIO relies on these names to identify and access other nodes in the cluster.

In this case, MINIO_VOLUMES will be set to https://minio-{1...4}.pigsty/data{1...4} to identify the four disks on four nodes. You can directly specify the minio_volumes parameter in the MinIO cluster to override the automatically generated value. However, this is usually not necessary as Pigsty will automatically generate it based on the config inventory.


Multi-Pool

MinIO’s architecture allows scaling by adding new storage pools. In Pigsty, you can achieve cluster scaling by explicitly specifying the minio_volumes parameter to allocate nodes for each storage pool.

For example, suppose you have already created the MinIO cluster defined in the Multi-Node Multi-Disk example, and now you want to add a new storage pool with four more nodes.

You need to directly override the minio_volumes parameter:

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 }
    10.10.10.11: { minio_seq: 2 }
    10.10.10.12: { minio_seq: 3 }
    10.10.10.13: { minio_seq: 4 }

    10.10.10.14: { minio_seq: 5 }
    10.10.10.15: { minio_seq: 6 }
    10.10.10.16: { minio_seq: 7 }
    10.10.10.17: { minio_seq: 8 }
  vars:
    minio_cluster: minio
    minio_data: "/data{1...4}"
    minio_node: '${minio_cluster}-${minio_seq}.pigsty' # minio node name pattern
    minio_volumes: 'https://minio-{1...4}.pigsty:9000/data{1...4} https://minio-{5...8}.pigsty:9000/data{1...4}'

Here, the two space-separated parameters represent two storage pools, each with four nodes and four disks per node. For more information on storage pools, refer to Administration: MinIO Cluster Expansion


Multiple Clusters

You can deploy new MinIO nodes as a completely new MinIO cluster by defining a new group with a different cluster name. The following configuration declares two independent MinIO clusters:

minio1:
  hosts:
    10.10.10.10: { minio_seq: 1 }
    10.10.10.11: { minio_seq: 2 }
    10.10.10.12: { minio_seq: 3 }
    10.10.10.13: { minio_seq: 4 }
  vars:
    minio_cluster: minio2
    minio_data: "/data{1...4}"

minio2:
  hosts:
    10.10.10.14: { minio_seq: 5 }
    10.10.10.15: { minio_seq: 6 }
    10.10.10.16: { minio_seq: 7 }
    10.10.10.17: { minio_seq: 8 }
  vars:
    minio_cluster: minio2
    minio_data: "/data{1...4}"
    minio_alias: sss2
    minio_domain: sss2.pigsty
    minio_endpoint: sss2.pigsty:9000

Note that Pigsty defaults to having only one MinIO cluster per deployment. If you need to deploy multiple MinIO clusters, some parameters with default values must be explicitly set and cannot be omitted, otherwise naming conflicts will occur, as shown above.


Expose Service

MinIO serves on port 9000 by default. A multi-node MinIO cluster can be accessed by connecting to any one of its nodes.

Service access falls under the scope of the NODE module, and we’ll provide only a basic introduction here.

High-availability access to a multi-node MinIO cluster can be achieved using L2 VIP or HAProxy. For example, you can use keepalived to bind an L2 VIP to the MinIO cluster, or use the haproxy component provided by the NODE module to expose MinIO services through a load balancer.

# minio cluster with 4 nodes and 4 drivers per node
minio:
  hosts:
    10.10.10.10: { minio_seq: 1 , nodename: minio-1 }
    10.10.10.11: { minio_seq: 2 , nodename: minio-2 }
    10.10.10.12: { minio_seq: 3 , nodename: minio-3 }
    10.10.10.13: { minio_seq: 4 , nodename: minio-4 }
  vars:
    minio_cluster: minio
    minio_data: '/data{1...4}'
    minio_buckets: [ { name: pgsql }, { name: infra }, { name: redis } ]
    minio_users:
      - { access_key: dba , secret_key: S3User.DBA, policy: consoleAdmin }
      - { access_key: pgbackrest , secret_key: S3User.SomeNewPassWord , policy: readwrite }

    # bind a node l2 vip (10.10.10.9) to minio cluster (optional)
    node_cluster: minio
    vip_enabled: true
    vip_vrid: 128
    vip_address: 10.10.10.9
    vip_interface: eth1

    # expose minio service with haproxy on all nodes
    haproxy_services:
      - name: minio                    # [REQUIRED] service name, unique
        port: 9002                     # [REQUIRED] service port, unique
        balance: leastconn             # [OPTIONAL] load balancer algorithm
        options:                       # [OPTIONAL] minio health check
          - option httpchk
          - option http-keep-alive
          - http-check send meth OPTIONS uri /minio/health/live
          - http-check expect status 200
        servers:
          - { name: minio-1 ,ip: 10.10.10.10 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-2 ,ip: 10.10.10.11 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-3 ,ip: 10.10.10.12 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-4 ,ip: 10.10.10.13 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

For example, the configuration above enables HAProxy on all nodes of the MinIO cluster, exposing MinIO services on port 9002, and binds a Layer 2 VIP to the cluster. When in use, users should point the sss.pigsty domain name to the VIP address 10.10.10.9 and access MinIO services using port 9002. This ensures high availability, as the VIP will automatically switch to another node if any node fails.

In this scenario, you may also need to globally modify the domain name resolution destination and the minio_endpoint parameter to change the endpoint address for the MinIO alias on the admin node:

minio_endpoint: https://sss.pigsty:9002   # Override the default: https://sss.pigsty:9000
node_etc_hosts: ["10.10.10.9 sss.pigsty"] # Other nodes will use sss.pigsty domain to access MinIO

Dedicated Load Balancer

Pigsty allows using a dedicated load balancer server group instead of the cluster itself to run VIP and HAProxy. For example, the prod template uses this approach.

proxy:
  hosts:
    10.10.10.18 : { nodename: proxy1 ,node_cluster: proxy ,vip_interface: eth1 ,vip_role: master }
    10.10.10.19 : { nodename: proxy2 ,node_cluster: proxy ,vip_interface: eth1 ,vip_role: backup }
  vars:
    vip_enabled: true
    vip_address: 10.10.10.20
    vip_vrid: 20

    haproxy_services:      # expose minio service : sss.pigsty:9000
      - name: minio        # [REQUIRED] service name, unique
        port: 9000         # [REQUIRED] service port, unique
        balance: leastconn # Use leastconn algorithm and minio health check
        options: [ "option httpchk", "option http-keep-alive", "http-check send meth OPTIONS uri /minio/health/live", "http-check expect status 200" ]
        servers:           # reload service with ./node.yml -t haproxy_config,haproxy_reload
          - { name: minio-1 ,ip: 10.10.10.21 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-2 ,ip: 10.10.10.22 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-3 ,ip: 10.10.10.23 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-4 ,ip: 10.10.10.24 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-5 ,ip: 10.10.10.25 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

In this case, you typically need to globally modify the MinIO domain resolution to point sss.pigsty to the load balancer address, and modify the minio_endpoint parameter to change the endpoint address for the MinIO alias on the admin node:

minio_endpoint: https://sss.pigsty:9002    # overwrite the defaults: https://sss.pigsty:9000
node_etc_hosts: ["10.10.10.20 sss.pigsty"] # domain name to access minio from all nodes (required)

Access Service

To access MinIO exposed via HAProxy, taking PGSQL backup configuration as an example, you can modify the configuration in pgbackrest_repo to add a new backup repository definition:

# This is the newly added HA MinIO Repo definition, USE THIS INSTEAD!
minio_ha:
  type: s3
  s3_endpoint: minio-1.pigsty   # s3_endpoint can be any load balancer: 10.10.10.1{0,1,2}, or domain names pointing to any of the nodes
  s3_region: us-east-1          # you can use external domain name: sss.pigsty, which resolves to any member (`minio_domain`)
  s3_bucket: pgsql              # instance & nodename can be used: minio-1.pigsty minio-1.pigsty minio-1.pigsty minio-1 minio-2 minio-3
  s3_key: pgbackrest            # Better using a dedicated password for MinIO pgbackrest user
  s3_key_secret: S3User.SomeNewPassWord
  s3_uri_style: path
  path: /pgbackrest
  storage_port: 9002            # Use load balancer port 9002 instead of default 9000 (direct access)
  storage_ca_file: /etc/pki/ca.crt
  bundle: y
  cipher_type: aes-256-cbc      # Better using a new cipher password for your production environment
  cipher_pass: pgBackRest.With.Some.Extra.PassWord.And.Salt.${pg_cluster}
  retention_full_type: time
  retention_full: 14

Expose Console

MinIO provides a Web console interface on port 9001 by default (specified by the minio_admin_port parameter).

Exposing the admin interface to external networks may pose security risks. If you want to do this, add MinIO to infra_portal and refresh the Nginx configuration.

# ./infra.yml -t nginx
infra_portal:
  home         : { domain: h.pigsty }
  grafana      : { domain: g.pigsty ,endpoint: "${admin_ip}:3000" , websocket: true }
  prometheus   : { domain: p.pigsty ,endpoint: "${admin_ip}:9090" }
  alertmanager : { domain: a.pigsty ,endpoint: "${admin_ip}:9093" }
  blackbox     : { endpoint: "${admin_ip}:9115" }
  loki         : { endpoint: "${admin_ip}:3100" }

  # MinIO console requires HTTPS / Websocket to work
  minio        : { domain: m.pigsty     ,endpoint: "10.10.10.10:9001" ,scheme: https ,websocket: true }
  minio10      : { domain: m10.pigsty   ,endpoint: "10.10.10.10:9001" ,scheme: https ,websocket: true }
  minio11      : { domain: m11.pigsty   ,endpoint: "10.10.10.11:9001" ,scheme: https ,websocket: true }
  minio12      : { domain: m12.pigsty   ,endpoint: "10.10.10.12:9001" ,scheme: https ,websocket: true }
  minio13      : { domain: m13.pigsty   ,endpoint: "10.10.10.13:9001" ,scheme: https ,websocket: true }

Note that the MinIO console requires HTTPS. Please DO NOT expose an unencrypted MinIO console in production.

This means you typically need to add a resolution record for m.pigsty in your DNS server or local /etc/hosts file to access the MinIO console.

Meanwhile, if you are using Pigsty’s self-signed CA rather than a proper public CA, you usually need to manually trust the CA or certificate to skip the “insecure” warning in the browser.




14.3 - Parameters

MinIO module provides 21 configuration parameters for customizing your MinIO cluster.

The MinIO module parameter list contains 21 parameters in two groups:

  • MINIO: 18 parameters for MinIO cluster deployment and configuration
  • MINIO_REMOVE: 3 parameters for MinIO cluster removal

Parameter Overview

The MINIO parameter group is used for MinIO cluster deployment and configuration, including identity, storage paths, ports, authentication credentials, and provisioning of buckets and users.

ParameterTypeLevelDescription
minio_seqintIminio instance identifier, REQUIRED
minio_clusterstringCminio cluster name, minio by default
minio_userusernameCminio os user, minio by default
minio_httpsboolG/Cenable HTTPS for MinIO? true by default
minio_nodestringCminio node name pattern
minio_datapathCminio data dir, use {x...y} for multiple disks
minio_volumesstringCminio core parameter for nodes and disks, auto-gen
minio_domainstringGminio external domain, sss.pigsty by default
minio_portportCminio service port, 9000 by default
minio_admin_portportCminio console port, 9001 by default
minio_access_keyusernameCroot access key, minioadmin by default
minio_secret_keypasswordCroot secret key, S3User.MinIO by default
minio_extra_varsstringCextra environment variables for minio server
minio_provisionboolG/Crun minio provisioning tasks? true by default
minio_aliasstringGminio client alias for the deployment
minio_endpointstringCendpoint for the minio client alias
minio_bucketsbucket[]Clist of minio buckets to be created
minio_usersuser[]Clist of minio users to be created

The MINIO_REMOVE parameter group controls MinIO cluster removal behavior, including safeguard protection, data cleanup, and package uninstallation.

ParameterTypeLevelDescription
minio_safeguardboolG/C/Aprevent accidental removal? false by default
minio_rm_databoolG/C/Aremove minio data during removal? true by default
minio_rm_pkgboolG/C/Auninstall minio packages during removal? false by default

The minio_volumes and minio_endpoint are auto-generated parameters, but you can explicitly override them.


Defaults

MINIO: 18 parameters, defined in roles/minio/defaults/main.yml

#-----------------------------------------------------------------
# MINIO
#-----------------------------------------------------------------
#minio_seq: 1                     # minio instance identifier, REQUIRED
minio_cluster: minio              # minio cluster name, minio by default
minio_user: minio                 # minio os user, `minio` by default
minio_https: true                 # enable HTTPS for MinIO? true by default
minio_node: '${minio_cluster}-${minio_seq}.pigsty' # minio node name pattern
minio_data: '/data/minio'         # minio data dir, use `{x...y}` for multiple disks
#minio_volumes:                   # minio core parameter, auto-generated if not specified
minio_domain: sss.pigsty          # minio external domain, `sss.pigsty` by default
minio_port: 9000                  # minio service port, 9000 by default
minio_admin_port: 9001            # minio console port, 9001 by default
minio_access_key: minioadmin      # root access key, `minioadmin` by default
minio_secret_key: S3User.MinIO    # root secret key, `S3User.MinIO` by default
minio_extra_vars: ''              # extra environment variables for minio server
minio_provision: true             # run minio provisioning tasks?
minio_alias: sss                  # minio client alias for the deployment
#minio_endpoint: https://sss.pigsty:9000 # endpoint for alias, auto-generated if not specified
minio_buckets:                    # list of minio buckets to be created
  - { name: pgsql }
  - { name: meta ,versioning: true }
  - { name: data }
minio_users:                      # list of minio users to be created
  - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
  - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
  - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

MINIO_REMOVE: 3 parameters, defined in roles/minio_remove/defaults/main.yml

#-----------------------------------------------------------------
# MINIO_REMOVE
#-----------------------------------------------------------------
minio_safeguard: false            # prevent accidental removal? false by default
minio_rm_data: true               # remove minio data during removal? true by default
minio_rm_pkg: false               # uninstall minio packages during removal? false by default

MINIO

This section contains parameters for the minio role, used by the minio.yml playbook.

minio_seq

Parameter: minio_seq, Type: int, Level: I

MinIO instance identifier, a required identity parameter. No default value—you must assign it manually.

Best practice is to start from 1, increment by 1, and never reuse previously assigned sequence numbers. The sequence number, together with the cluster name minio_cluster, uniquely identifies each MinIO instance (e.g., minio-1).

In multi-node deployments, sequence numbers are also used to generate node names, which are written to the /etc/hosts file for static resolution.


minio_cluster

Parameter: minio_cluster, Type: string, Level: C

MinIO cluster name, default is minio. This is useful when deploying multiple MinIO clusters.

The cluster name, together with the sequence number minio_seq, uniquely identifies each MinIO instance. For example, with cluster name minio and sequence 1, the instance name is minio-1.

Note that Pigsty defaults to a single MinIO cluster per deployment. If you need multiple MinIO clusters, you must explicitly set minio_alias, minio_domain, minio_endpoint, and other parameters to avoid naming conflicts.


minio_user

Parameter: minio_user, Type: username, Level: C

MinIO operating system user, default is minio.

The MinIO service runs under this user. SSL certificates used by MinIO are stored in this user’s home directory (default /home/minio), under the ~/.minio/certs/ directory.


minio_https

Parameter: minio_https, Type: bool, Level: G/C

Enable HTTPS for MinIO service? Default is true.

Note that pgBackREST requires MinIO to use HTTPS to work properly. If you don’t use MinIO for PostgreSQL backups and don’t need HTTPS, you can set this to false.

When HTTPS is enabled, Pigsty automatically issues SSL certificates for the MinIO server, containing the domain specified in minio_domain and the IP addresses of each node.


minio_node

Parameter: minio_node, Type: string, Level: C

MinIO node name pattern, used for multi-node deployments.

Default value: ${minio_cluster}-${minio_seq}.pigsty, which uses the instance name plus .pigsty suffix as the default node name.

The domain pattern specified here is used to generate node names, which are written to the /etc/hosts file on all MinIO nodes.


minio_data

Parameter: minio_data, Type: path, Level: C

MinIO data directory(s), default value: /data/minio, a common directory for single-node deployments.

For multi-node-multi-drive and single-node-multi-drive deployments, use the {x...y} notation to specify multiple disks.


minio_volumes

Parameter: minio_volumes, Type: string, Level: C

MinIO core parameter. By default, this is not specified and is auto-generated using the following rule:

minio_volumes: "{% if minio_cluster_size|int > 1 %}https://{{ minio_node|replace('${minio_cluster}', minio_cluster)|replace('${minio_seq}',minio_seq_range) }}:{{ minio_port|default(9000) }}{% endif %}{{ minio_data }}"
  • In single-node deployment (single or multi-drive), minio_volumes directly uses the minio_data value.
  • In multi-node deployment, minio_volumes uses minio_node, minio_port, and minio_data to generate multi-node addresses.
  • In multi-pool deployment, you typically need to explicitly specify and override minio_volumes to define multiple node pool addresses.

When specifying this parameter, ensure the values are consistent with minio_node, minio_port, and minio_data.


minio_domain

Parameter: minio_domain, Type: string, Level: G

MinIO service domain name, default is sss.pigsty.

Clients can access the MinIO S3 service via this domain name. This name is registered in local DNSMASQ and included in SSL certificates’ SAN (Subject Alternative Name) field.

It’s recommended to add a static DNS record in node_etc_hosts pointing this domain to the MinIO server node’s IP (single-node deployment) or load balancer VIP (multi-node deployment).


minio_port

Parameter: minio_port, Type: port, Level: C

MinIO service port, default is 9000.

This is the MinIO S3 API listening port. Clients access the object storage service through this port. In multi-node deployments, this port is also used for inter-node communication.


minio_admin_port

Parameter: minio_admin_port, Type: port, Level: C

MinIO console port, default is 9001.

This is the listening port for MinIO’s built-in web management console. You can access MinIO’s graphical management interface at https://<minio-ip>:9001.

To expose the MinIO console through Nginx, add it to infra_portal. Note that the MinIO console requires HTTPS and WebSocket support.


minio_access_key

Parameter: minio_access_key, Type: username, Level: C

Root access key (username), default is minioadmin.

This is the MinIO super administrator username with full access to all buckets and objects. It’s recommended to change this default value in production environments.


minio_secret_key

Parameter: minio_secret_key, Type: password, Level: C

Root secret key (password), default is S3User.MinIO.

This is the MinIO super administrator’s password, used together with minio_access_key.


minio_extra_vars

Parameter: minio_extra_vars, Type: string, Level: C

Extra environment variables for MinIO server. See the MinIO Server documentation for the complete list.

Default is an empty string. You can use multiline strings to pass multiple environment variables:

minio_extra_vars: |
  MINIO_BROWSER_REDIRECT_URL=https://minio.example.com
  MINIO_SERVER_URL=https://s3.example.com

minio_provision

Parameter: minio_provision, Type: bool, Level: G/C

Run MinIO provisioning tasks? Default is true.

When enabled, Pigsty automatically creates the buckets and users defined in minio_buckets and minio_users. Set this to false if you don’t need automatic provisioning of these resources.


minio_alias

Parameter: minio_alias, Type: string, Level: G

MinIO client alias for the local MinIO cluster, default value: sss.

This alias is written to the MinIO client configuration file (~/.mcli/config.json) for the admin user on the admin node, allowing you to directly use mcli <alias> commands to access the MinIO cluster, e.g., mcli ls sss/.

If deploying multiple MinIO clusters, specify different aliases for each cluster to avoid conflicts.


minio_endpoint

Parameter: minio_endpoint, Type: string, Level: C

Endpoint for the client alias. If specified, this minio_endpoint (e.g., https://sss.pigsty:9002) will replace the default value as the target endpoint for the MinIO alias written on the admin node.

mcli alias set {{ minio_alias }} {% if minio_endpoint is defined and minio_endpoint != '' %}{{ minio_endpoint }}{% else %}https://{{ minio_domain }}:{{ minio_port }}{% endif %} {{ minio_access_key }} {{ minio_secret_key }}

This MinIO alias is configured on the admin node as the default admin user.


minio_buckets

Parameter: minio_buckets, Type: bucket[], Level: C

List of MinIO buckets to create by default:

minio_buckets:
  - { name: pgsql }
  - { name: meta ,versioning: true }
  - { name: data }

Three default buckets are created with different purposes and policies:

  • pgsql bucket: Used by default for PostgreSQL pgBackREST backup storage.
  • meta bucket: Open bucket with versioning enabled, suitable for storing important metadata requiring version management.
  • data bucket: Open bucket for other purposes, e.g., Supabase templates may use this bucket for business data.

Each bucket has a corresponding access policy with the same name. For example, the pgsql policy has full access to the pgsql bucket, and so on.

You can also add a lock flag to bucket definitions to enable object locking, preventing accidental deletion of objects in the bucket.


minio_users

Parameter: minio_users, Type: user[], Level: C

List of MinIO users to create, default value:

minio_users:
  - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
  - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
  - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

The default configuration creates three users corresponding to three default buckets:

  • pgbackrest: For PostgreSQL pgBackREST backups, with access to the pgsql bucket.
  • s3user_meta: For accessing the meta bucket.
  • s3user_data: For accessing the data bucket.

MINIO_REMOVE

This section contains parameters for the minio_remove role, used by the minio-rm.yml playbook.

minio_safeguard

Parameter: minio_safeguard, Type: bool, Level: G/C/A

Safeguard switch to prevent accidental deletion, default value is false.

When enabled, the minio-rm.yml playbook will abort and refuse to remove the MinIO cluster, providing protection against accidental deletions.

It’s recommended to enable this safeguard in production environments to prevent data loss from accidental operations:

minio_safeguard: true   # When enabled, minio-rm.yml will refuse to execute

minio_rm_data

Parameter: minio_rm_data, Type: bool, Level: G/C/A

Remove MinIO data during removal? Default value is true.

When enabled, the minio-rm.yml playbook will delete MinIO data directories and configuration files during cluster removal.


minio_rm_pkg

Parameter: minio_rm_pkg, Type: bool, Level: G/C/A

Uninstall MinIO packages during removal? Default value is false.

When enabled, the minio-rm.yml playbook will uninstall MinIO packages during cluster removal. This is disabled by default to preserve the MinIO installation for potential future use.

14.4 - Playbook

Manage MinIO clusters with Ansible playbooks and quick command reference.

The MinIO module provides two built-in playbooks for cluster management:


minio.yml

Playbook minio.yml installs the MinIO module on nodes.

  • minio-id : Generate/validate minio identity parameters
  • minio_install : Install minio
    • minio_os_user : Create OS user minio
    • minio_pkg : Install minio/mcli packages
    • minio_dir : Create minio directories
  • minio_config : Generate minio configuration
    • minio_conf : Minio main config file
    • minio_cert : Minio SSL certificate issuance
    • minio_dns : Minio DNS record insertion
  • minio_launch : Launch minio service
  • minio_register : Register minio to monitoring
  • minio_provision : Create minio aliases/buckets/users
    • minio_alias : Create minio client alias (on admin node)
    • minio_bucket : Create minio buckets
    • minio_user : Create minio business users

Before running the playbook, complete the MinIO cluster configuration in the config inventory.


minio-rm.yml

Playbook minio-rm.yml removes the MinIO cluster.

  • minio-id : Generate minio identity parameters for removal (with any_errors_fatal - stops immediately on identity validation failure)
  • minio_safeguard : Safety check, prevent accidental deletion (default: false)
  • minio_pause : Pause 3 seconds, allow user to abort (Ctrl+C to cancel)
  • minio_deregister : Remove targets from Victoria/Prometheus monitoring, clean up DNS records
  • minio_svc : Stop and disable minio systemd service
  • minio_data : Remove minio data directory (disable with minio_rm_data=false)
  • minio_pkg : Uninstall minio packages (enable with minio_rm_pkg=true)

The removal playbook uses the minio_remove role with the following configurable parameters:

  • minio_safeguard: Prevents accidental deletion when set to true
  • minio_rm_data: Controls whether MinIO data is deleted (default: true)
  • minio_rm_pkg: Controls whether MinIO packages are uninstalled (default: false)

Cheatsheet

Common MINIO playbook commands:

./minio.yml -l <cls>                      # Install MINIO module on group <cls>
./minio.yml -l minio -t minio_install     # Install MinIO service, prepare data dirs, without configure & launch
./minio.yml -l minio -t minio_config      # Reconfigure MinIO cluster
./minio.yml -l minio -t minio_launch      # Restart MinIO cluster
./minio.yml -l minio -t minio_provision   # Re-run provisioning (create buckets and users)

./minio-rm.yml -l minio                   # Remove MinIO cluster (using dedicated removal playbook)
./minio-rm.yml -l minio -e minio_rm_data=false  # Remove cluster but preserve data
./minio-rm.yml -l minio -e minio_rm_pkg=true    # Remove cluster and uninstall packages

Safeguard

To prevent accidental deletion, Pigsty’s MINIO module provides a safeguard mechanism controlled by the minio_safeguard parameter.

By default, minio_safeguard is false, allowing removal operations. If you want to protect the MinIO cluster from accidental deletion, enable this safeguard in the config inventory:

minio_safeguard: true   # When enabled, minio-rm.yml will refuse to execute

If you need to remove a protected cluster, override with command-line parameters:

./minio-rm.yml -l minio -e minio_safeguard=false

Demo

asciicast

14.5 - Administration

MinIO cluster management SOP: create, destroy, expand, shrink, and handle node and disk failures.

Create Cluster

To create a cluster, define it in the config inventory and run the minio.yml playbook.

minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

For example, the above configuration defines an SNSD Single-Node Single-Disk MinIO cluster. Use the following command to create this MinIO cluster:

./minio.yml -l minio  # Install MinIO module on the minio group

Remove Cluster

To destroy a cluster, run the dedicated minio-rm.yml playbook:

./minio-rm.yml -l minio                   # Remove MinIO cluster
./minio-rm.yml -l minio -e minio_rm_data=false  # Remove cluster but keep data
./minio-rm.yml -l minio -e minio_rm_pkg=true    # Remove cluster and uninstall packages

The removal playbook automatically performs the following:

  • Deregisters MinIO targets from Victoria/Prometheus monitoring
  • Removes records from the DNS service on INFRA nodes
  • Stops and disables MinIO systemd service
  • Deletes MinIO data directory and configuration files (optional)
  • Uninstalls MinIO packages (optional)

Expand Cluster

MinIO cannot scale at the node/disk level, but can scale at the storage pool (multiple nodes) level.

Assume you have a four-node MinIO cluster and want to double the capacity by adding a new four-node storage pool.

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 , nodename: minio-1 }
    10.10.10.11: { minio_seq: 2 , nodename: minio-2 }
    10.10.10.12: { minio_seq: 3 , nodename: minio-3 }
    10.10.10.13: { minio_seq: 4 , nodename: minio-4 }
  vars:
    minio_cluster: minio
    minio_data: '/data{1...4}'
    minio_buckets: [ { name: pgsql }, { name: infra }, { name: redis } ]
    minio_users:
      - { access_key: dba , secret_key: S3User.DBA, policy: consoleAdmin }
      - { access_key: pgbackrest , secret_key: S3User.SomeNewPassWord , policy: readwrite }

    # bind a node l2 vip (10.10.10.9) to minio cluster (optional)
    node_cluster: minio
    vip_enabled: true
    vip_vrid: 128
    vip_address: 10.10.10.9
    vip_interface: eth1

    # expose minio service with haproxy on all nodes
    haproxy_services:
      - name: minio                    # [REQUIRED] service name, unique
        port: 9002                     # [REQUIRED] service port, unique
        balance: leastconn             # [OPTIONAL] load balancer algorithm
        options:                       # [OPTIONAL] minio health check
          - option httpchk
          - option http-keep-alive
          - http-check send meth OPTIONS uri /minio/health/live
          - http-check expect status 200
        servers:
          - { name: minio-1 ,ip: 10.10.10.10 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-2 ,ip: 10.10.10.11 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-3 ,ip: 10.10.10.12 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-4 ,ip: 10.10.10.13 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

First, modify the MinIO cluster definition to add four new nodes, assigning sequence numbers 5 to 8. The key step is to modify the minio_volumes parameter to designate the new four nodes as a new storage pool.

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 , nodename: minio-1 }
    10.10.10.11: { minio_seq: 2 , nodename: minio-2 }
    10.10.10.12: { minio_seq: 3 , nodename: minio-3 }
    10.10.10.13: { minio_seq: 4 , nodename: minio-4 }
    # new nodes
    10.10.10.14: { minio_seq: 5 , nodename: minio-5 }
    10.10.10.15: { minio_seq: 6 , nodename: minio-6 }
    10.10.10.16: { minio_seq: 7 , nodename: minio-7 }
    10.10.10.17: { minio_seq: 8 , nodename: minio-8 }

  vars:
    minio_cluster: minio
    minio_data: '/data{1...4}'
    minio_volumes: 'https://minio-{1...4}.pigsty:9000/data{1...4} https://minio-{5...8}.pigsty:9000/data{1...4}'  # new cluster config
    # ... other configs omitted

Step 2: Add these nodes to Pigsty:

./node.yml -l 10.10.10.14,10.10.10.15,10.10.10.16,10.10.10.17

Step 3: On the new nodes, use the Ansible playbook to install and prepare MinIO software:

./minio.yml -l 10.10.10.14,10.10.10.15,10.10.10.16,10.10.10.17 -t minio_install

Step 4: On the entire cluster, use the Ansible playbook to reconfigure the MinIO cluster:

./minio.yml -l minio -t minio_config

This step updates the MINIO_VOLUMES configuration on the existing four nodes

Step 5: Restart the entire MinIO cluster at once (be careful, do not rolling restart!):

./minio.yml -l minio -t minio_launch -f 10   # 8 parallel, ensure simultaneous restart

Step 6 (optional): If you are using a load balancer, make sure the load balancer configuration is updated. For example, add the new four nodes to the load balancer configuration:

# expose minio service with haproxy on all nodes
haproxy_services:
  - name: minio                    # [REQUIRED] service name, unique
    port: 9002                     # [REQUIRED] service port, unique
    balance: leastconn             # [OPTIONAL] load balancer algorithm
    options:                       # [OPTIONAL] minio health check
      - option httpchk
      - option http-keep-alive
      - http-check send meth OPTIONS uri /minio/health/live
      - http-check expect status 200
    servers:
      - { name: minio-1 ,ip: 10.10.10.10 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-2 ,ip: 10.10.10.11 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-3 ,ip: 10.10.10.12 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-4 ,ip: 10.10.10.13 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

      - { name: minio-5 ,ip: 10.10.10.14 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-6 ,ip: 10.10.10.15 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-7 ,ip: 10.10.10.16 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-8 ,ip: 10.10.10.17 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

Then, run the haproxy subtask of the node.yml playbook to update the load balancer configuration:

./node.yml -l minio -t haproxy_config,haproxy_reload   # Update and reload load balancer config

If you use L2 VIP for reliable load balancer access, you also need to add new nodes (if any) to the existing NODE VIP group:

./node.yml -l minio -t node_vip  # Refresh cluster L2 VIP configuration

Shrink Cluster

MinIO cannot shrink at the node/disk level, but can retire at the storage pool (multiple nodes) level — add a new storage pool, drain the old storage pool to the new one, then retire the old storage pool.


Upgrade Cluster

First, download the new version of MinIO packages to the local software repository on the INFRA node, then rebuild the repository index:

./infra.yml -t repo_create

Next, use Ansible to batch upgrade MinIO packages:

ansible minio -m package -b -a 'name=minio state=latest'  # Upgrade MinIO server
ansible minio -m package -b -a 'name=mcli state=latest'   # Upgrade MinIO client

Finally, use the mc command line tool to instruct the MinIO cluster to restart:

mc admin service restart sss

Node Failure Recovery

# 1. Remove the failed node from the cluster
bin/node-rm <your_old_node_ip>

# 2. Replace the failed node with the same node name (if IP changes, modify the MinIO cluster definition)
bin/node-add <your_new_node_ip>

# 3. Install and configure MinIO on the new node
./minio.yml -l <your_new_node_ip>

# 4. Instruct MinIO to perform heal action
mc admin heal

Disk Failure Recovery

# 1. Unmount the failed disk from the cluster
umount /dev/<your_disk_device>

# 2. Replace the failed disk, format with xfs
mkfs.xfs /dev/sdb -L DRIVE1

# 3. Don't forget to setup fstab for auto-mount
vi /etc/fstab
# LABEL=DRIVE1     /mnt/drive1    xfs     defaults,noatime  0       2

# 4. Remount
mount -a

# 5. Instruct MinIO to perform heal action
mc admin heal

14.6 - Monitoring

How to monitor MinIO in Pigsty? How to use MinIO’s built-in console? What alerting rules are worth noting?

Built-in Console

MinIO has a built-in management console. By default, you can access this interface via HTTPS through the admin port (minio_admin_port, default 9001) of any MinIO instance.

In most configuration templates that provide MinIO services, MinIO is exposed as a custom service at m.pigsty. After configuring domain name resolution, you can access the MinIO console at https://m.pigsty.

Log in with the admin credentials configured by minio_access_key and minio_secret_key (default minioadmin / S3User.MinIO).


Pigsty Monitoring

Pigsty provides two monitoring dashboards related to the MINIO module:

  • MinIO Overview: Displays overall monitoring metrics for the MinIO cluster, including cluster status, storage usage, request rates, etc.
  • MinIO Instance: Displays monitoring metrics details for a single MinIO instance, including CPU, memory, network, disk, etc.

minio-overview.jpg

MinIO monitoring metrics are collected through MinIO’s native Prometheus endpoint (/minio/v2/metrics/cluster), and by default are scraped and stored by Victoria Metrics.


Pigsty Alerting

Pigsty provides the following three alerting rules for MinIO:

  • MinIO Server Down
  • MinIO Node Offline
  • MinIO Disk Offline
#==============================================================#
#                         Aliveness                            #
#==============================================================#
# MinIO server instance down
- alert: MinioServerDown
  expr: minio_up < 1
  for: 1m
  labels: { level: 0, severity: CRIT, category: minio }
  annotations:
    summary: "CRIT MinioServerDown {{ $labels.ins }}@{{ $labels.instance }}"
    description: |
      minio_up[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value }} < 1
      http://g.pigsty/d/minio-overview

#==============================================================#
#                         Error                                #
#==============================================================#
# MinIO node offline triggers a p1 alert
- alert: MinioNodeOffline
  expr: avg_over_time(minio_cluster_nodes_offline_total{job="minio"}[5m]) > 0
  for: 3m
  labels: { level: 1, severity: WARN, category: minio }
  annotations:
    summary: "WARN MinioNodeOffline: {{ $labels.cls }} {{ $value }}"
    description: |
      minio_cluster_nodes_offline_total[cls={{ $labels.cls }}] = {{ $value }} > 0
      http://g.pigsty/d/minio-overview?from=now-5m&to=now&var-cls={{$labels.cls}}

# MinIO disk offline triggers a p1 alert
- alert: MinioDiskOffline
  expr: avg_over_time(minio_cluster_disk_offline_total{job="minio"}[5m]) > 0
  for: 3m
  labels: { level: 1, severity: WARN, category: minio }
  annotations:
    summary: "WARN MinioDiskOffline: {{ $labels.cls }} {{ $value }}"
    description: |
      minio_cluster_disk_offline_total[cls={{ $labels.cls }}] = {{ $value }} > 0
      http://g.pigsty/d/minio-overview?from=now-5m&to=now&var-cls={{$labels.cls}}

14.7 - Metrics

Complete list of monitoring metrics provided by the Pigsty MINIO module with explanations

The MINIO module contains 79 available monitoring metrics.

Metric NameTypeLabelsDescription
minio_audit_failed_messagescounterip, job, target_id, cls, instance, server, insTotal number of messages that failed to send since start
minio_audit_target_queue_lengthgaugeip, job, target_id, cls, instance, server, insNumber of unsent messages in queue for target
minio_audit_total_messagescounterip, job, target_id, cls, instance, server, insTotal number of messages sent since start
minio_cluster_bucket_totalgaugeip, job, cls, instance, server, insTotal number of buckets in the cluster
minio_cluster_capacity_raw_free_bytesgaugeip, job, cls, instance, server, insTotal free capacity online in the cluster
minio_cluster_capacity_raw_total_bytesgaugeip, job, cls, instance, server, insTotal capacity online in the cluster
minio_cluster_capacity_usable_free_bytesgaugeip, job, cls, instance, server, insTotal free usable capacity online in the cluster
minio_cluster_capacity_usable_total_bytesgaugeip, job, cls, instance, server, insTotal usable capacity online in the cluster
minio_cluster_drive_offline_totalgaugeip, job, cls, instance, server, insTotal drives offline in this cluster
minio_cluster_drive_online_totalgaugeip, job, cls, instance, server, insTotal drives online in this cluster
minio_cluster_drive_totalgaugeip, job, cls, instance, server, insTotal drives in this cluster
minio_cluster_health_erasure_set_healing_drivesgaugepool, ip, job, cls, set, instance, server, insGet the count of healing drives of this erasure set
minio_cluster_health_erasure_set_online_drivesgaugepool, ip, job, cls, set, instance, server, insGet the count of the online drives in this erasure set
minio_cluster_health_erasure_set_read_quorumgaugepool, ip, job, cls, set, instance, server, insGet the read quorum for this erasure set
minio_cluster_health_erasure_set_statusgaugepool, ip, job, cls, set, instance, server, insGet current health status for this erasure set
minio_cluster_health_erasure_set_write_quorumgaugepool, ip, job, cls, set, instance, server, insGet the write quorum for this erasure set
minio_cluster_health_statusgaugeip, job, cls, instance, server, insGet current cluster health status
minio_cluster_nodes_offline_totalgaugeip, job, cls, instance, server, insTotal number of MinIO nodes offline
minio_cluster_nodes_online_totalgaugeip, job, cls, instance, server, insTotal number of MinIO nodes online
minio_cluster_objects_size_distributiongaugeip, range, job, cls, instance, server, insDistribution of object sizes across a cluster
minio_cluster_objects_version_distributiongaugeip, range, job, cls, instance, server, insDistribution of object versions across a cluster
minio_cluster_usage_deletemarker_totalgaugeip, job, cls, instance, server, insTotal number of delete markers in a cluster
minio_cluster_usage_object_totalgaugeip, job, cls, instance, server, insTotal number of objects in a cluster
minio_cluster_usage_total_bytesgaugeip, job, cls, instance, server, insTotal cluster usage in bytes
minio_cluster_usage_version_totalgaugeip, job, cls, instance, server, insTotal number of versions (includes delete marker) in a cluster
minio_cluster_webhook_failed_messagescounterip, job, cls, instance, server, insNumber of messages that failed to send
minio_cluster_webhook_onlinegaugeip, job, cls, instance, server, insIs the webhook online?
minio_cluster_webhook_queue_lengthcounterip, job, cls, instance, server, insWebhook queue length
minio_cluster_webhook_total_messagescounterip, job, cls, instance, server, insTotal number of messages sent to this target
minio_cluster_write_quorumgaugeip, job, cls, instance, server, insMaximum write quorum across all pools and sets
minio_node_file_descriptor_limit_totalgaugeip, job, cls, instance, server, insLimit on total number of open file descriptors for the MinIO Server process
minio_node_file_descriptor_open_totalgaugeip, job, cls, instance, server, insTotal number of open file descriptors by the MinIO Server process
minio_node_go_routine_totalgaugeip, job, cls, instance, server, insTotal number of go routines running
minio_node_ilm_expiry_pending_tasksgaugeip, job, cls, instance, server, insNumber of pending ILM expiry tasks in the queue
minio_node_ilm_transition_active_tasksgaugeip, job, cls, instance, server, insNumber of active ILM transition tasks
minio_node_ilm_transition_missed_immediate_tasksgaugeip, job, cls, instance, server, insNumber of missed immediate ILM transition tasks
minio_node_ilm_transition_pending_tasksgaugeip, job, cls, instance, server, insNumber of pending ILM transition tasks in the queue
minio_node_ilm_versions_scannedcounterip, job, cls, instance, server, insTotal number of object versions checked for ilm actions since server start
minio_node_io_rchar_bytescounterip, job, cls, instance, server, insTotal bytes read by the process from the underlying storage system including cache, /proc/[pid]/io rchar
minio_node_io_read_bytescounterip, job, cls, instance, server, insTotal bytes read by the process from the underlying storage system, /proc/[pid]/io read_bytes
minio_node_io_wchar_bytescounterip, job, cls, instance, server, insTotal bytes written by the process to the underlying storage system including page cache, /proc/[pid]/io wchar
minio_node_io_write_bytescounterip, job, cls, instance, server, insTotal bytes written by the process to the underlying storage system, /proc/[pid]/io write_bytes
minio_node_process_cpu_total_secondscounterip, job, cls, instance, server, insTotal user and system CPU time spent in seconds
minio_node_process_resident_memory_bytesgaugeip, job, cls, instance, server, insResident memory size in bytes
minio_node_process_starttime_secondsgaugeip, job, cls, instance, server, insStart time for MinIO process per node, time in seconds since Unix epoc
minio_node_process_uptime_secondsgaugeip, job, cls, instance, server, insUptime for MinIO process per node in seconds
minio_node_scanner_bucket_scans_finishedcounterip, job, cls, instance, server, insTotal number of bucket scans finished since server start
minio_node_scanner_bucket_scans_startedcounterip, job, cls, instance, server, insTotal number of bucket scans started since server start
minio_node_scanner_directories_scannedcounterip, job, cls, instance, server, insTotal number of directories scanned since server start
minio_node_scanner_objects_scannedcounterip, job, cls, instance, server, insTotal number of unique objects scanned since server start
minio_node_scanner_versions_scannedcounterip, job, cls, instance, server, insTotal number of object versions scanned since server start
minio_node_syscall_read_totalcounterip, job, cls, instance, server, insTotal read SysCalls to the kernel. /proc/[pid]/io syscr
minio_node_syscall_write_totalcounterip, job, cls, instance, server, insTotal write SysCalls to the kernel. /proc/[pid]/io syscw
minio_notify_current_send_in_progressgaugeip, job, cls, instance, server, insNumber of concurrent async Send calls active to all targets (deprecated, please use ‘minio_notify_target_current_send_in_progress’ instead)
minio_notify_events_errors_totalcounterip, job, cls, instance, server, insEvents that were failed to be sent to the targets (deprecated, please use ‘minio_notify_target_failed_events’ instead)
minio_notify_events_sent_totalcounterip, job, cls, instance, server, insTotal number of events sent to the targets (deprecated, please use ‘minio_notify_target_total_events’ instead)
minio_notify_events_skipped_totalcounterip, job, cls, instance, server, insEvents that were skipped to be sent to the targets due to the in-memory queue being full
minio_s3_requests_4xx_errors_totalcounterip, job, cls, instance, server, ins, apiTotal number of S3 requests with (4xx) errors
minio_s3_requests_errors_totalcounterip, job, cls, instance, server, ins, apiTotal number of S3 requests with (4xx and 5xx) errors
minio_s3_requests_incoming_totalgaugeip, job, cls, instance, server, insTotal number of incoming S3 requests
minio_s3_requests_inflight_totalgaugeip, job, cls, instance, server, ins, apiTotal number of S3 requests currently in flight
minio_s3_requests_rejected_auth_totalcounterip, job, cls, instance, server, insTotal number of S3 requests rejected for auth failure
minio_s3_requests_rejected_header_totalcounterip, job, cls, instance, server, insTotal number of S3 requests rejected for invalid header
minio_s3_requests_rejected_invalid_totalcounterip, job, cls, instance, server, insTotal number of invalid S3 requests
minio_s3_requests_rejected_timestamp_totalcounterip, job, cls, instance, server, insTotal number of S3 requests rejected for invalid timestamp
minio_s3_requests_totalcounterip, job, cls, instance, server, ins, apiTotal number of S3 requests
minio_s3_requests_ttfb_seconds_distributiongaugeip, job, cls, le, instance, server, ins, apiDistribution of time to first byte across API calls
minio_s3_requests_waiting_totalgaugeip, job, cls, instance, server, insTotal number of S3 requests in the waiting queue
minio_s3_traffic_received_bytescounterip, job, cls, instance, server, insTotal number of s3 bytes received
minio_s3_traffic_sent_bytescounterip, job, cls, instance, server, insTotal number of s3 bytes sent
minio_software_commit_infogaugeip, job, cls, instance, commit, server, insGit commit hash for the MinIO release
minio_software_version_infogaugeip, job, cls, instance, version, server, insMinIO Release tag for the server
minio_upUnknownip, job, cls, instance, insN/A
minio_usage_last_activity_nano_secondsgaugeip, job, cls, instance, server, insTime elapsed (in nano seconds) since last scan activity.
scrape_duration_secondsUnknownip, job, cls, instance, insN/A
scrape_samples_post_metric_relabelingUnknownip, job, cls, instance, insN/A
scrape_samples_scrapedUnknownip, job, cls, instance, insN/A
scrape_series_addedUnknownip, job, cls, instance, insN/A
upUnknownip, job, cls, instance, insN/A

14.8 - FAQ

Frequently asked questions about the Pigsty MINIO object storage module

What version of MinIO does Pigsty use?

MinIO announced entering maintenance mode on 2025-12-03, no longer releasing new feature versions, only security patches and maintenance versions, and stopped releasing binary RPM/DEB on 2025-10-15. So Pigsty forked its own MinIO and used minio/pkger to create the latest 2025-12-03 version.

This version fixes the MinIO CVE-2025-62506 security vulnerability, ensuring Pigsty users’ MinIO deployments are safe and reliable. You can find the RPM/DEB packages and build scripts in the Pigsty Infra repository.


Why does MinIO require HTTPS?

When pgBackRest uses object storage as a backup repository, HTTPS is mandatory to ensure data transmission security. If your MinIO is not used for pgBackRest backup, you can still choose to use HTTP protocol. You can disable HTTPS by modifying the parameter minio_https.


Getting invalid certificate error when accessing MinIO from containers?

Unless you use certificates issued by a real enterprise CA, MinIO uses self-signed certificates by default, which causes client tools inside containers (such as mc / rclone / awscli, etc.) to be unable to verify the identity of the MinIO server, resulting in invalid certificate errors.

For example, for Node.js applications, you can mount the MinIO server’s CA certificate into the container and specify the CA certificate path via the environment variable NODE_EXTRA_CA_CERTS:

    environment:
      NODE_EXTRA_CA_CERTS: /etc/pki/ca.crt
    volumes:
      - /etc/pki/ca.crt:/etc/pki/ca.crt:ro

Of course, if your MinIO is not used as a pgBackRest backup repository, you can also choose to disable MinIO’s HTTPS support and use HTTP protocol instead.


What if multi-node/multi-disk MinIO cluster fails to start?

In Single-Node Multi-Disk or Multi-Node Multi-Disk mode, if the data directory is not a valid disk mount point, MinIO will refuse to start. Please use mounted disks as MinIO’s data directory instead of regular directories. You can only use regular directories as MinIO’s data directory in Single-Node Single-Disk mode, which is only suitable for development testing or non-critical scenarios.


How to add new members to an existing MinIO cluster?

Before deployment, you should plan MinIO cluster capacity, as adding new members requires a global restart.

You can scale MinIO by adding new server nodes to the existing cluster to create a new storage pool.

Note that once MinIO is deployed, you cannot modify the number of nodes and disks in the existing cluster! You can only scale by adding new storage pools.

For detailed steps, please refer to the Pigsty documentation: Expand Cluster, and the MinIO official documentation: Expand MinIO Deployment


How to remove a MinIO cluster?

Starting from Pigsty v3.6, removing a MinIO cluster requires using the dedicated minio-rm.yml playbook:

./minio-rm.yml -l minio                   # Remove MinIO cluster
./minio-rm.yml -l minio -e minio_rm_data=false  # Remove cluster but keep data

If you have enabled minio_safeguard protection, you need to explicitly override it to perform removal:

./minio-rm.yml -l minio -e minio_safeguard=false

What’s the difference between mcli and mc commands?

mcli is a renamed version of the official MinIO client mc. In Pigsty, we use mcli instead of mc to avoid conflicts with Midnight Commander (a common file manager that also uses the mc command).

Both have identical functionality, just with different command names. You can find the complete command reference in the MinIO Client documentation.


How to monitor MinIO cluster status?

Pigsty provides out-of-the-box monitoring capabilities for MinIO:

  • Grafana Dashboards: MinIO Overview and MinIO Instance
  • Alerting Rules: Including MinIO down, node offline, disk offline alerts
  • MinIO Built-in Console: Access via https://<minio-ip>:9001

For details, please refer to the Monitoring documentation

15 - Module: REDIS

Pigsty has built-in Redis support, a high-performance in-memory data structure server. Deploy Redis in standalone, cluster, or sentinel mode as a companion to PostgreSQL.

Redis is a widely popular open-source high-performance in-memory data structure server, and a great companion to PostgreSQL. Redis in Pigsty is a production-ready complete solution supporting master-slave replication, sentinel high availability, and native cluster mode, with integrated monitoring and logging capabilities, along with automated installation, configuration, and operation playbooks.

15.1 - Configuration

Choose the appropriate Redis mode for your use case and express your requirements through the inventory

Concept

The entity model of Redis is almost the same as that of PostgreSQL, which also includes the concepts of Cluster and Instance. Note that the Cluster here does not refer to the native Redis Cluster mode.

The core difference between the REDIS module and the PGSQL module is that Redis uses a single-node multi-instance deployment rather than the 1:1 deployment: multiple Redis instances are typically deployed on a physical/virtual machine node to utilize multi-core CPUs fully. Therefore, the ways to configure and administer Redis instances are slightly different from PGSQL.

In Redis managed by Pigsty, nodes are entirely subordinate to the cluster, which means that currently, it is not allowed to deploy Redis instances of two different clusters on one node. However, this does not affect deploying multiple independent Redis primary-replica instances on one node. Of course, there are some limitations; for example, in this case, you cannot specify different passwords for different instances on the same node.


Identity Parameters

Redis identity parameters are required parameters when defining a Redis cluster.

NameAttributeDescriptionExample
redis_clusterREQUIRED, cluster levelCluster nameredis-test
redis_nodeREQUIRED, node levelNode sequence number1,2
redis_instancesREQUIRED, node levelInstance definition{ 6001 : {} ,6002 : {}}
  • redis_cluster: Redis cluster name, serves as the top-level namespace for cluster resources.
  • redis_node: Redis node number, an integer unique within the cluster to distinguish different nodes.
  • redis_instances: JSON object where keys are instance port numbers and values are JSON objects containing other instance configurations.

Redis Mode

There are three different working modes for Redis, specified by the redis_mode parameter:

  • standalone: Default standalone master-slave mode
  • cluster: Redis native distributed cluster mode
  • sentinel: Sentinel mode, providing high availability for standalone master-slave Redis

Here are three examples of Redis cluster definitions:

  • A 1-node, one master & one slave Redis Standalone cluster: redis-ms
  • A 1-node, 3-instance Redis Sentinel cluster: redis-sentinel
  • A 2-node, 6-instance Redis Cluster: redis-cluster
redis-ms: # redis classic primary & replica
  hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
  vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

redis-meta: # redis sentinel x 3
  hosts: { 10.10.10.11: { redis_node: 1 , redis_instances: { 26379: { } ,26380: { } ,26381: { } } } }
  vars:
    redis_cluster: redis-meta
    redis_password: 'redis.meta'
    redis_mode: sentinel
    redis_max_memory: 16MB
    redis_sentinel_monitor: # primary list for redis sentinel, use cls as name, primary ip:port
      - { name: redis-ms, host: 10.10.10.10, port: 6379 ,password: redis.ms, quorum: 2 }

redis-test: # redis native cluster: 3m x 3s
  hosts:
    10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
    10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
  vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }

Limitations

  • A Redis node can only belong to one Redis cluster, which means you cannot assign a node to two different Redis clusters simultaneously.
  • On each Redis node, you need to assign a unique port number to each Redis instance to avoid port conflicts.
  • Typically, the same Redis cluster will use the same password, but multiple Redis instances on a Redis node cannot have different passwords (because redis_exporter only allows one password).
  • Redis Cluster has built-in HA, while standalone master-slave HA requires additional manual configuration in Sentinel since we don’t know if you have deployed Sentinel.
  • Fortunately, configuring HA for standalone Redis is straightforward through Sentinel. For details, see Administration - Configure HA with Sentinel.

Typical Configuration Examples

Here are some common Redis configuration examples for different scenarios:

Cache Cluster (Pure In-Memory)

For pure caching scenarios with no data persistence requirements:

redis-cache:
  hosts:
    10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { } } }
    10.10.10.11: { redis_node: 2 , redis_instances: { 6379: { }, 6380: { } } }
  vars:
    redis_cluster: redis-cache
    redis_password: 'cache.password'
    redis_max_memory: 2GB
    redis_mem_policy: allkeys-lru    # evict LRU keys when memory is full
    redis_rdb_save: []               # disable RDB persistence
    redis_aof_enabled: false         # disable AOF persistence

Session Store Cluster

For web application session storage with some persistence needs:

redis-session:
  hosts:
    10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } }
  vars:
    redis_cluster: redis-session
    redis_password: 'session.password'
    redis_max_memory: 1GB
    redis_mem_policy: volatile-lru   # only evict keys with expire set
    redis_rdb_save: ['300 1']        # save every 5 minutes if at least 1 change
    redis_aof_enabled: false

Message Queue Cluster

For simple message queue scenarios requiring higher data reliability:

redis-queue:
  hosts:
    10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } }
  vars:
    redis_cluster: redis-queue
    redis_password: 'queue.password'
    redis_max_memory: 4GB
    redis_mem_policy: noeviction     # reject writes when memory full, don't evict
    redis_rdb_save: ['60 1']         # save every minute if at least 1 change
    redis_aof_enabled: true          # enable AOF for better persistence

High Availability Master-Slave Cluster

Master-slave cluster with Sentinel automatic failover:

# Master-slave cluster
redis-ha:
  hosts:
    10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { } } }                              # primary
    10.10.10.11: { redis_node: 2 , redis_instances: { 6379: { replica_of: '10.10.10.10 6379' } } } # replica 1
    10.10.10.12: { redis_node: 3 , redis_instances: { 6379: { replica_of: '10.10.10.10 6379' } } } # replica 2
  vars:
    redis_cluster: redis-ha
    redis_password: 'ha.password'
    redis_max_memory: 8GB

# Sentinel cluster (manages the above master-slave cluster)
redis-sentinel:
  hosts:
    10.10.10.10: { redis_node: 1 , redis_instances: { 26379: { } } }
    10.10.10.11: { redis_node: 2 , redis_instances: { 26379: { } } }
    10.10.10.12: { redis_node: 3 , redis_instances: { 26379: { } } }
  vars:
    redis_cluster: redis-sentinel
    redis_password: 'sentinel.password'
    redis_mode: sentinel
    redis_max_memory: 64MB
    redis_sentinel_monitor:
      - { name: redis-ha, host: 10.10.10.10, port: 6379, password: 'ha.password', quorum: 2 }

Large-Scale Native Cluster

For high-volume, high-throughput scenarios using native distributed cluster:

redis-cluster:
  hosts:
    10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { }, 6381: { } } }
    10.10.10.11: { redis_node: 2 , redis_instances: { 6379: { }, 6380: { }, 6381: { } } }
    10.10.10.12: { redis_node: 3 , redis_instances: { 6379: { }, 6380: { }, 6381: { } } }
    10.10.10.13: { redis_node: 4 , redis_instances: { 6379: { }, 6380: { }, 6381: { } } }
  vars:
    redis_cluster: redis-cluster
    redis_password: 'cluster.password'
    redis_mode: cluster
    redis_cluster_replicas: 1        # 1 replica per primary shard
    redis_max_memory: 16GB           # max memory per instance
    redis_rdb_save: ['900 1']
    redis_aof_enabled: false

# This creates a 6-primary, 6-replica native cluster
# Total capacity ~96GB (6 * 16GB)

Security Hardening Configuration

Recommended security configuration for production environments:

redis-secure:
  hosts:
    10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { } } }
  vars:
    redis_cluster: redis-secure
    redis_password: 'StrongP@ssw0rd!'  # use strong password
    redis_bind_address: ''             # bind to internal IP instead of 0.0.0.0
    redis_max_memory: 4GB
    redis_rename_commands:             # rename dangerous commands
      FLUSHDB: 'DANGEROUS_FLUSHDB'
      FLUSHALL: 'DANGEROUS_FLUSHALL'
      DEBUG: ''                        # disable command
      CONFIG: 'ADMIN_CONFIG'

15.2 - Parameters

REDIS module provides 18 deployment parameters + 3 removal parameters

Parameter list for the REDIS module.


Parameter Overview

The REDIS parameter group is used for Redis cluster deployment and configuration, including identity, instance definitions, operating mode, memory configuration, persistence, and monitoring.

ParameterTypeLevelDescription
redis_clusterstringCRedis cluster name, required identity parameter
redis_instancesdictIRedis instance definitions on this node
redis_nodeintIRedis node number, unique positive integer in cluster
redis_fs_mainpathCRedis main data directory, /data by default
redis_exporter_enabledboolCEnable Redis Exporter?
redis_exporter_portportCRedis Exporter listen port
redis_exporter_optionsstringC/IRedis Exporter CLI arguments
redis_modeenumCRedis mode: standalone, cluster, sentinel
redis_confstringCRedis config template, except sentinel
redis_bind_addressipCRedis bind address, empty uses host IP
redis_max_memorysizeC/IMax memory for each Redis instance
redis_mem_policyenumCRedis memory eviction policy
redis_passwordpasswordCRedis password, empty disables password
redis_rdb_savestring[]CRedis RDB save directives, empty list disables RDB
redis_aof_enabledboolCEnable Redis AOF?
redis_rename_commandsdictCRename dangerous Redis commands
redis_cluster_replicasintCReplicas per master in Redis native cluster
redis_sentinel_monitormaster[]CMaster list for Redis Sentinel to monitor

The REDIS_REMOVE parameter group controls Redis instance removal behavior.

ParameterTypeLevelDescription
redis_safeguardboolG/C/APrevent removing running Redis instances?
redis_rm_databoolG/C/ARemove Redis data directory when removing?
redis_rm_pkgboolG/C/AUninstall Redis packages when removing?

The Redis module contains 18 deployment parameters and 3 removal parameters.

#redis_cluster:             <CLUSTER> # Redis cluster name, required identity parameter
#redis_node: 1              <NODE>    # Redis node number, unique in cluster
#redis_instances: {}        <NODE>    # Redis instance definitions on this node
redis_fs_main: /data                  # Redis main data directory, `/data` by default
redis_exporter_enabled: true          # Enable Redis Exporter?
redis_exporter_port: 9121             # Redis Exporter listen port
redis_exporter_options: ''            # Redis Exporter CLI arguments
redis_mode: standalone                # Redis mode: standalone, cluster, sentinel
redis_conf: redis.conf                # Redis config template, except sentinel
redis_bind_address: '0.0.0.0'         # Redis bind address, empty uses host IP
redis_max_memory: 1GB                 # Max memory for each Redis instance
redis_mem_policy: allkeys-lru         # Redis memory eviction policy
redis_password: ''                    # Redis password, empty disables password
redis_rdb_save: ['1200 1']            # Redis RDB save directives, empty disables RDB
redis_aof_enabled: false              # Enable Redis AOF?
redis_rename_commands: {}             # Rename dangerous Redis commands
redis_cluster_replicas: 1             # Replicas per master in Redis native cluster
redis_sentinel_monitor: []            # Master list for Sentinel, sentinel mode only

# REDIS_REMOVE
redis_safeguard: false                # Prevent removing running Redis instances?
redis_rm_data: true                   # Remove Redis data directory when removing?
redis_rm_pkg: false                   # Uninstall Redis packages when removing?

redis_cluster

Parameter: redis_cluster, Type: string, Level: C

Redis cluster name, a required identity parameter that must be explicitly configured at the cluster level. It serves as the namespace for resources within the cluster.

Must follow the naming pattern [a-z][a-z0-9-]* to comply with various identity constraints. Using redis- as a cluster name prefix is recommended.

redis_node

Parameter: redis_node, Type: int, Level: I

Redis node sequence number, a required identity parameter that must be explicitly configured at the node (Host) level.

A positive integer that should be unique within the cluster, used to distinguish and identify different nodes. Assign starting from 0 or 1.

redis_instances

Parameter: redis_instances, Type: dict, Level: I

Redis instance definitions on the current node, a required parameter that must be explicitly configured at the node (Host) level.

Format is a JSON key-value object where keys are numeric port numbers and values are instance-specific JSON configuration items.

redis-test: # redis native cluster: 3m x 3s
  hosts:
    10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
    10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
  vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }

Each Redis instance listens on a unique port on its node. The replica_of field in instance configuration sets the upstream master address to establish replication:

redis_instances:
    6379: {}
    6380: { replica_of: '10.10.10.13 6379' }
    6381: { replica_of: '10.10.10.13 6379' }

redis_fs_main

Parameter: redis_fs_main, Type: path, Level: C

Main data disk mount point for Redis, default is /data. Pigsty creates a redis directory under this path to store Redis data.

The actual data storage directory is /data/redis, owned by the redis OS user. See FHS: Redis for internal structure details.

redis_exporter_enabled

Parameter: redis_exporter_enabled, Type: bool, Level: C

Enable Redis Exporter monitoring component?

Enabled by default, deploying one exporter per Redis node, listening on redis_exporter_port 9121 by default. It scrapes metrics from all Redis instances on the node.

When set to false, roles/redis/tasks/exporter.yml still renders config files but skips starting the redis_exporter systemd service (the redis_exporter_launch task has when: redis_exporter_enabled|bool), allowing manually configured exporters to remain.

redis_exporter_port

Parameter: redis_exporter_port, Type: port, Level: C

Redis Exporter listen port, default value: 9121

redis_exporter_options

Parameter: redis_exporter_options, Type: string, Level: C/I

Extra CLI arguments for Redis Exporter, rendered to /etc/default/redis_exporter (see roles/redis/tasks/exporter.yml), default is empty string. REDIS_EXPORTER_OPTS is appended to the systemd service’s ExecStart=/bin/redis_exporter $REDIS_EXPORTER_OPTS, useful for configuring extra scrape targets or filtering behavior.

redis_mode

Parameter: redis_mode, Type: enum, Level: C

Redis cluster operating mode, three options: standalone, cluster, sentinel. Default: standalone

  • standalone: Default, independent Redis master-slave mode
  • cluster: Redis native cluster mode
  • sentinel: Redis high availability component: Sentinel

When using standalone mode, Pigsty sets up Redis replication based on the replica_of parameter.

When using cluster mode, Pigsty creates a native Redis cluster using all defined instances based on the redis_cluster_replicas parameter.

When redis_mode=sentinel, redis.yml executes the redis-ha phase (lines 80-130 of redis.yml) to distribute targets from redis_sentinel_monitor to all sentinels. When redis_mode=cluster, it also executes the redis-join phase (lines 134-180) calling redis-cli --cluster create --cluster-yes ... --cluster-replicas {{ redis_cluster_replicas }}. Both phases are automatically triggered in normal ./redis.yml -l <cluster> runs, or can be run separately with -t redis-ha or -t redis-join.

redis_conf

Parameter: redis_conf, Type: string, Level: C

Redis config template path, except for Sentinel.

Default: redis.conf, a template file at roles/redis/templates/redis.conf.

To use your own Redis config template, place it in the templates/ directory and set this parameter to the template filename.

Note: Redis Sentinel uses a different template file: roles/redis/templates/redis-sentinel.conf.

redis_bind_address

Parameter: redis_bind_address, Type: ip, Level: C

IP address Redis server binds to. Empty string uses the hostname defined in the inventory.

Default: 0.0.0.0, binding to all available IPv4 addresses on the host.

For security in production environments, bind only to internal IPs by setting this to empty string ''.

When empty, the template roles/redis/templates/redis.conf uses inventory_hostname to render bind <ip>, binding to the management address declared in the inventory.

redis_max_memory

Parameter: redis_max_memory, Type: size, Level: C/I

Maximum memory for each Redis instance, default: 1GB.

redis_mem_policy

Parameter: redis_mem_policy, Type: enum, Level: C

Redis memory eviction policy, default: allkeys-lru

  • noeviction: Don’t save new values when memory limit is reached; only applies to primary when using replication
  • allkeys-lru: Keep most recently used keys; remove least recently used (LRU) keys
  • allkeys-lfu: Keep frequently used keys; remove least frequently used (LFU) keys
  • volatile-lru: Remove least recently used keys with expire field set
  • volatile-lfu: Remove least frequently used keys with expire field set
  • allkeys-random: Randomly remove keys to make space for new data
  • volatile-random: Randomly remove keys with expire field set
  • volatile-ttl: Remove keys with expire field set and shortest remaining TTL

See Redis Eviction Policy for details.

redis_password

Parameter: redis_password, Type: password, Level: C/N

Redis password. Empty string disables password, which is the default behavior.

Note that due to redis_exporter implementation limitations, you can only set one redis_password per node. This is usually not a problem since Pigsty doesn’t allow deploying two different Redis clusters on the same node.

Pigsty automatically writes this password to /etc/default/redis_exporter (REDIS_PASSWORD=...) and uses it in the redis-ha phase with redis-cli -a <password>, so no need to separately configure exporter or Sentinel authentication.

Use a strong password in production environments

redis_rdb_save

Parameter: redis_rdb_save, Type: string[], Level: C

Redis RDB save directives. Use empty list to disable RDB.

Default is ["1200 1"]: dump dataset to disk every 20 minutes if at least 1 key changed.

See Redis Persistence for details.

redis_aof_enabled

Parameter: redis_aof_enabled, Type: bool, Level: C

Enable Redis AOF? Default is false, meaning AOF is not used.

redis_rename_commands

Parameter: redis_rename_commands, Type: dict, Level: C

Rename dangerous Redis commands. A k:v dictionary where old is the command to rename and new is the new name.

Default: {}. You can hide dangerous commands like FLUSHDB and FLUSHALL. Example:

{
  "keys": "op_keys",
  "flushdb": "op_flushdb",
  "flushall": "op_flushall",
  "config": "op_config"
}

redis_cluster_replicas

Parameter: redis_cluster_replicas, Type: int, Level: C

Number of replicas per master/primary in Redis native cluster. Default: 1, meaning one replica per master.

redis_sentinel_monitor

Parameter: redis_sentinel_monitor, Type: master[], Level: C

List of masters for Redis Sentinel to monitor, used only on sentinel clusters. Each managed master is defined as:

redis_sentinel_monitor:  # primary list for redis sentinel, use cls as name, primary ip:port
  - { name: redis-src, host: 10.10.10.45, port: 6379 ,password: redis.src, quorum: 1 }
  - { name: redis-dst, host: 10.10.10.48, port: 6379 ,password: redis.dst, quorum: 1 }

name and host are required; port, password, and quorum are optional. quorum sets the number of sentinels needed to agree on master failure, typically more than half of sentinel instances (default is 1).

Starting from Pigsty 4.0, you can add remove: true to an entry, causing the redis-ha phase to only execute SENTINEL REMOVE <name>, useful for cleaning up targets no longer needed.


REDIS_REMOVE

The following parameters are used by the redis_remove role, invoked by the redis-rm.yml playbook, controlling Redis instance removal behavior.

redis_safeguard

Parameter: redis_safeguard, Type: bool, Level: G/C/A

Redis safety guard to prevent accidental removal: when enabled, the redis-rm.yml playbook cannot remove running Redis instances.

Default is false. When set to true, the redis-rm.yml playbook refuses to execute, preventing accidental deletion of running Redis instances.

Override with CLI argument -e redis_safeguard=false to force removal.

redis_rm_data

Parameter: redis_rm_data, Type: bool, Level: G/C/A

Remove Redis data directory when removing Redis instances? Default is true.

The data directory (/data/redis/) contains Redis RDB and AOF files. If not removed, newly deployed Redis instances will load data from these backup files.

Set to false to preserve data directories for later recovery.

redis_rm_pkg

Parameter: redis_rm_pkg, Type: bool, Level: G/C/A

Uninstall Redis and redis_exporter packages when removing Redis instances? Default is false.

Typically not needed to uninstall packages; only enable when completely cleaning up a node.

15.3 - Playbook

Manage Redis clusters with Ansible playbooks and quick command reference.

The REDIS module provides two playbooks for deploying/removing Redis clusters/nodes/instances:


redis.yml

The redis.yml playbook for deploying Redis contains the following subtasks:

redis_node        : Init redis node
  - redis_install : Install redis & redis_exporter
  - redis_user    : Create OS user redis
  - redis_dir     : Configure redis FHS directory structure
redis_exporter    : Configure redis_exporter monitoring
  - redis_exporter_config  : Generate redis_exporter config
  - redis_exporter_launch  : Launch redis_exporter
redis_instance    : Init and restart redis cluster/node/instance
  - redis_config  : Generate redis instance config
  - redis_launch  : Launch redis instance
redis_register    : Register redis to infrastructure
redis_ha          : Configure redis sentinel (sentinel mode only)
redis_join        : Join redis native cluster (cluster mode only)

Operation Levels

redis.yml supports three operation levels, controlled by -l to limit target scope and -e redis_port=<port> to specify a single instance:

LevelParametersDescription
Cluster-l <cluster>Deploy all nodes and instances of the entire Redis cluster
Node-l <ip>Deploy all Redis instances on the specified node
Instance-l <ip> -e redis_port=<port>Deploy only a single instance on the specified node

Cluster-Level Operations

Deploy an entire Redis cluster, including all instances on all nodes:

./redis.yml -l redis-ms           # deploy the entire redis-ms cluster
./redis.yml -l redis-test         # deploy the entire redis-test cluster
./redis.yml -l redis-sentinel     # deploy sentinel cluster

Cluster-level operations will:

  • Install Redis packages on all nodes
  • Create redis user and directory structure on all nodes
  • Start redis_exporter on all nodes
  • Deploy and start all defined Redis instances
  • Register all instances to the monitoring system
  • If sentinel mode, configure sentinel monitoring targets
  • If cluster mode, form the native cluster

Node-Level Operations

Deploy only all Redis instances on the specified node:

./redis.yml -l 10.10.10.10        # deploy all instances on this node
./redis.yml -l 10.10.10.11        # deploy another node

Node-level operations are useful for:

  • Scaling up by adding new nodes to an existing cluster
  • Redeploying all instances on a specific node
  • Reinitializing after node failure recovery

Note: Node-level operations do not execute the redis-ha and redis-join stages. If you need to add a new node to a native cluster, you must manually run redis-cli --cluster add-node

Instance-Level Operations

Use the -e redis_port=<port> parameter to operate on a single instance:

# Deploy only the 6379 port instance on 10.10.10.10
./redis.yml -l 10.10.10.10 -e redis_port=6379

# Deploy only the 6380 port instance on 10.10.10.11
./redis.yml -l 10.10.10.11 -e redis_port=6380

Instance-level operations are useful for:

  • Adding new instances to an existing node
  • Redeploying a single failed instance
  • Updating a single instance’s configuration

When redis_port is specified:

  • Only renders the config file for that port
  • Only starts/restarts the systemd service for that port
  • Only registers that instance to the monitoring system
  • Does not affect other instances on the same node

Common Tags

Use the -t <tag> parameter to selectively execute certain tasks:

# Install packages only, don't start services
./redis.yml -l redis-ms -t redis_node

# Update config and restart instances only
./redis.yml -l redis-ms -t redis_config,redis_launch

# Update monitoring registration only
./redis.yml -l redis-ms -t redis_register

# Configure sentinel monitoring targets only (sentinel mode)
./redis.yml -l redis-sentinel -t redis-ha

# Form native cluster only (cluster mode, auto-runs after first deployment)
./redis.yml -l redis-cluster -t redis-join

Idempotency

redis.yml is idempotent and safe to run repeatedly:

  • Repeated execution overwrites existing config files
  • Repeated execution restarts Redis instances
  • Does not check if instances already exist; directly renders config and restarts
  • Suitable for batch updates after configuration changes

Tip: If you only want to update configs without restarting all instances, use -t redis_config to render configs only, then manually restart the instances you need.


redis-rm.yml

The redis-rm.yml playbook for removing Redis contains the following subtasks:

redis_safeguard  : Safety check, abort if redis_safeguard=true
redis_deregister : Remove registration from monitoring system
  - rm_metrics   : Delete /infra/targets/redis/*.yml
  - rm_logs      : Revoke /etc/vector/redis.yaml
redis_exporter   : Stop and disable redis_exporter
redis            : Stop and disable redis instances
redis_data       : Delete data directories (when redis_rm_data=true)
redis_pkg        : Uninstall packages (when redis_rm_pkg=true)

Operation Levels

redis-rm.yml also supports three operation levels:

LevelParametersDescription
Cluster-l <cluster>Remove all nodes and instances of the entire Redis cluster
Node-l <ip>Remove all Redis instances on the specified node
Instance-l <ip> -e redis_port=<port>Remove only a single instance on the specified node

Cluster-Level Removal

Remove an entire Redis cluster:

./redis-rm.yml -l redis-ms        # remove entire redis-ms cluster
./redis-rm.yml -l redis-test      # remove entire redis-test cluster

Cluster-level removal will:

  • Deregister all instances on all nodes from the monitoring system
  • Stop redis_exporter on all nodes
  • Stop and disable all Redis instances
  • Delete all data directories (if redis_rm_data=true)
  • Uninstall packages (if redis_rm_pkg=true)

Node-Level Removal

Remove only all Redis instances on the specified node:

./redis-rm.yml -l 10.10.10.10     # remove all instances on this node
./redis-rm.yml -l 10.10.10.11     # remove another node

Node-level removal is useful for:

  • Scaling down by removing an entire node
  • Cleanup before node decommission
  • Preparation before node migration

Node-level removal will:

  • Deregister all instances on that node from the monitoring system
  • Stop redis_exporter on that node
  • Stop all Redis instances on that node
  • Delete all data directories on that node
  • Delete Vector logging config on that node

Instance-Level Removal

Use the -e redis_port=<port> parameter to remove a single instance:

# Remove only the 6379 port instance on 10.10.10.10
./redis-rm.yml -l 10.10.10.10 -e redis_port=6379

# Remove only the 6380 port instance on 10.10.10.11
./redis-rm.yml -l 10.10.10.11 -e redis_port=6380

Instance-level removal is useful for:

  • Removing a single replica from a node
  • Removing instances no longer needed
  • Removing the original primary after failover

Behavioral differences when redis_port is specified:

ComponentNode-Level (no redis_port)Instance-Level (with redis_port)
Monitoring registrationDelete entire node’s registration fileOnly remove that instance from registration file
redis_exporterStop and disableNo operation (other instances still need it)
Redis instancesStop all instancesOnly stop the specified port’s instance
Data directoryDelete entire /data/redis/ directoryOnly delete /data/redis/<cluster>-<node>-<port>/
Vector configDelete /etc/vector/redis.yamlNo operation (other instances still need it)
PackagesOptionally uninstallNo operation

Control Parameters

redis-rm.yml provides the following control parameters:

ParameterDefaultDescription
redis_safeguardfalseSafety guard; when true, refuses to execute removal
redis_rm_datatrueWhether to delete data directories (RDB/AOF files)
redis_rm_pkgfalseWhether to uninstall Redis packages

Usage examples:

# Remove cluster but keep data directories
./redis-rm.yml -l redis-ms -e redis_rm_data=false

# Remove cluster and uninstall packages
./redis-rm.yml -l redis-ms -e redis_rm_pkg=true

# Bypass safeguard to force removal
./redis-rm.yml -l redis-ms -e redis_safeguard=false

Safeguard Mechanism

When a cluster has redis_safeguard: true configured, redis-rm.yml will refuse to execute:

redis-production:
  vars:
    redis_safeguard: true    # enable protection for production
$ ./redis-rm.yml -l redis-production
TASK [ABORT due to redis_safeguard enabled] ***
fatal: [10.10.10.10]: FAILED! => {"msg": "Abort due to redis_safeguard..."}

Explicit override is required to execute:

./redis-rm.yml -l redis-production -e redis_safeguard=false

Quick Reference

Deployment Quick Reference

# Deploy entire cluster
./redis.yml -l <cluster>

# Scale up: deploy new node
./redis.yml -l <new-node-ip>

# Scale up: add new instance to existing node (add definition to config first)
./redis.yml -l <ip> -e redis_port=<new-port>

# Update config and restart
./redis.yml -l <cluster> -t redis_config,redis_launch

# Update single instance config only
./redis.yml -l <ip> -e redis_port=<port> -t redis_config,redis_launch

Removal Quick Reference

# Remove entire cluster
./redis-rm.yml -l <cluster>

# Scale down: remove entire node
./redis-rm.yml -l <ip>

# Scale down: remove single instance
./redis-rm.yml -l <ip> -e redis_port=<port>

# Remove but keep data
./redis-rm.yml -l <cluster> -e redis_rm_data=false

# Complete cleanup (including packages)
./redis-rm.yml -l <cluster> -e redis_rm_pkg=true

Wrapper Scripts

Pigsty provides convenient wrapper scripts:

# Deploy
bin/redis-add <cluster>           # deploy cluster
bin/redis-add <ip>                # deploy node
bin/redis-add <ip> <port>         # deploy instance

# Remove
bin/redis-rm <cluster>            # remove cluster
bin/redis-rm <ip>                 # remove node
bin/redis-rm <ip> <port>          # remove instance

Demo

Initialize Redis cluster with Redis playbook:

asciicast

15.4 - Administration

Redis cluster management SOPs for creating, destroying, scaling, and configuring high availability

Here are some common Redis administration task SOPs (Standard Operating Procedures):

Basic Operations

High Availability

Scaling & Migration

Troubleshooting

For more questions, please refer to FAQ: REDIS.


Initialize Redis

You can use the redis.yml playbook to initialize Redis clusters, nodes, or instances:

# Initialize all Redis instances in the cluster
./redis.yml -l <cluster>      # init redis cluster

# Initialize all Redis instances on a specific node
./redis.yml -l 10.10.10.10    # init redis node

# Initialize a specific Redis instance: 10.10.10.11:6379
./redis.yml -l 10.10.10.11 -e redis_port=6379 -t redis

You can also use wrapper scripts to initialize:

bin/redis-add redis-ms          # create redis cluster 'redis-ms'
bin/redis-add 10.10.10.10       # create redis node '10.10.10.10'
bin/redis-add 10.10.10.10 6379  # create redis instance '10.10.10.10:6379'

Remove Redis

You can use the redis-rm.yml playbook to remove Redis clusters, nodes, or instances:

# Remove Redis cluster `redis-test`
./redis-rm.yml -l redis-test

# Remove Redis cluster `redis-test` and uninstall Redis packages
./redis-rm.yml -l redis-test -e redis_rm_pkg=true

# Remove all instances on Redis node 10.10.10.13
./redis-rm.yml -l 10.10.10.13

# Remove a specific Redis instance 10.10.10.13:6379
./redis-rm.yml -l 10.10.10.13 -e redis_port=6379

You can also use wrapper scripts to remove Redis clusters/nodes/instances:

bin/redis-rm redis-ms          # remove redis cluster 'redis-ms'
bin/redis-rm 10.10.10.10       # remove redis node '10.10.10.10'
bin/redis-rm 10.10.10.10 6379  # remove redis instance '10.10.10.10:6379'

Reconfigure Redis

You can partially run the redis.yml playbook to reconfigure Redis clusters, nodes, or instances:

./redis.yml -l <cluster> -t redis_config,redis_launch

Note that Redis cannot reload configuration online. You must restart Redis using the launch task to make configuration changes take effect.


Using Redis Client

Access Redis instances with redis-cli:

$ redis-cli -h 10.10.10.10 -p 6379 # <--- connect with host and port
10.10.10.10:6379> auth redis.ms    # <--- authenticate with password
OK
10.10.10.10:6379> set a 10         # <--- set a key
OK
10.10.10.10:6379> get a            # <--- get the key value
"10"

Redis provides the redis-benchmark tool, which can be used for Redis performance evaluation or to generate load for testing.

redis-benchmark -h 10.10.10.13 -p 6379

Configure Redis Replica

https://redis.io/commands/replicaof/

# Promote a Redis instance to primary
> REPLICAOF NO ONE
"OK"

# Make a Redis instance a replica of another instance
> REPLICAOF 127.0.0.1 6799
"OK"

Configure HA with Sentinel

Redis standalone master-slave clusters can be configured for automatic high availability through Redis Sentinel. For detailed information, please refer to the Sentinel official documentation.

Using the four-node sandbox environment as an example, a Redis Sentinel cluster redis-meta can be used to manage multiple standalone Redis master-slave clusters.

Taking the one-master-one-slave Redis standalone cluster redis-ms as an example, you need to add the target on each Sentinel instance using SENTINEL MONITOR and provide the password using SENTINEL SET, and the high availability is configured.

# For each sentinel, add the redis master to sentinel management: (26379,26380,26381)
$ redis-cli -h 10.10.10.11 -p 26379 -a redis.meta
10.10.10.11:26379> SENTINEL MONITOR redis-ms 10.10.10.10 6379 1
10.10.10.11:26379> SENTINEL SET redis-ms auth-pass redis.ms      # if auth enabled, password needs to be configured

If you want to remove a Redis master-slave cluster managed by Sentinel, use SENTINEL REMOVE <name>.

You can use the redis_sentinel_monitor parameter defined on the Sentinel cluster to automatically configure the list of masters managed by Sentinel.

redis_sentinel_monitor:  # list of masters to be monitored, port, password, quorum (should be more than 1/2 of sentinels) are optional
  - { name: redis-src, host: 10.10.10.45, port: 6379 ,password: redis.src, quorum: 1 }
  - { name: redis-dst, host: 10.10.10.48, port: 6379 ,password: redis.dst, quorum: 1 }

The redis-ha stage in redis.yml will render /tmp/<cluster>.monitor on each sentinel instance based on this list and execute SENTINEL REMOVE and SENTINEL MONITOR commands sequentially, ensuring the sentinel management state remains consistent with the inventory. If you only want to remove a target without re-adding it, set remove: true on the monitor object, and the playbook will skip re-registration after SENTINEL REMOVE.

Use the following command to refresh the managed master list on the Redis Sentinel cluster:

./redis.yml -l redis-meta -t redis-ha   # replace redis-meta if your Sentinel cluster has a different name

Initialize Redis Native Cluster

When redis_mode is set to cluster, redis.yml will additionally execute the redis-join stage: it uses redis-cli --cluster create --cluster-yes ... --cluster-replicas {{ redis_cluster_replicas }} in /tmp/<cluster>-join.sh to join all instances into a native cluster.

This step runs automatically during the first deployment. Subsequently re-running ./redis.yml -l <cluster> -t redis-join will regenerate and execute the same command. Since --cluster create is not idempotent, you should only trigger this stage separately when you are sure you need to rebuild the entire native cluster.


Scale Up Redis Nodes

Scale Up Standalone Cluster

When adding new nodes/instances to an existing Redis master-slave cluster, first add the new definition in the inventory:

redis-ms:
  hosts:
    10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } }
    10.10.10.11: { redis_node: 2 , redis_instances: { 6379: { replica_of: '10.10.10.10 6379' } } }  # new node
  vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

Then deploy only the new node:

./redis.yml -l 10.10.10.11   # deploy only the new node

Scale Up Native Cluster

Adding new nodes to a Redis native cluster requires additional steps:

# 1. Add the new node definition in the inventory
# 2. Deploy the new node
./redis.yml -l 10.10.10.14

# 3. Add the new node to the cluster (manual execution)
redis-cli --cluster add-node 10.10.10.14:6379 10.10.10.12:6379

# 4. Reshard slots if needed
redis-cli --cluster reshard 10.10.10.12:6379

Scale Up Sentinel Cluster

To add new instances to a Sentinel cluster:

# Add new sentinel instances in the inventory, then execute:
./redis.yml -l <sentinel-cluster> -t redis_instance

Scale Down Redis Nodes

Scale Down Standalone Cluster

# 1. If removing a replica, just remove it directly
./redis-rm.yml -l 10.10.10.11 -e redis_port=6379

# 2. If removing the primary, first perform a failover
redis-cli -h 10.10.10.10 -p 6380 REPLICAOF NO ONE      # promote replica
redis-cli -h 10.10.10.10 -p 6379 REPLICAOF 10.10.10.10 6380  # demote original primary

# 3. Then remove the original primary
./redis-rm.yml -l 10.10.10.10 -e redis_port=6379

# 4. Update the inventory to remove the definition

Scale Down Native Cluster

# 1. First migrate data slots
redis-cli --cluster reshard 10.10.10.12:6379 \
  --cluster-from <node-id> --cluster-to <target-node-id> --cluster-slots <count>

# 2. Remove node from cluster
redis-cli --cluster del-node 10.10.10.12:6379 <node-id>

# 3. Remove the instance
./redis-rm.yml -l 10.10.10.14

# 4. Update the inventory

Backup and Restore

Manual Backup

# Trigger RDB snapshot
redis-cli -h 10.10.10.10 -p 6379 -a <password> BGSAVE

# Check snapshot status
redis-cli -h 10.10.10.10 -p 6379 -a <password> LASTSAVE

# Copy RDB file (default location)
cp /data/redis/redis-ms-1-6379/dump.rdb /backup/redis-ms-$(date +%Y%m%d).rdb

Data Restore

# 1. Stop Redis instance
sudo systemctl stop redis-ms-1-6379

# 2. Replace RDB file
cp /backup/redis-ms-20241231.rdb /data/redis/redis-ms-1-6379/dump.rdb
chown redis:redis /data/redis/redis-ms-1-6379/dump.rdb

# 3. Start Redis instance
sudo systemctl start redis-ms-1-6379

Using AOF Persistence

If you need higher data safety, enable AOF:

redis-ms:
  vars:
    redis_aof_enabled: true
    redis_rdb_save: ['900 1', '300 10', '60 10000']  # keep RDB as well

Redeploy to apply AOF configuration:

./redis.yml -l redis-ms -t redis_config,redis_launch

Common Issue Diagnosis

Connection Troubleshooting

# Check Redis service status
systemctl status redis-ms-1-6379

# Check port listening
ss -tlnp | grep 6379

# Check firewall
sudo iptables -L -n | grep 6379

# Test connection
redis-cli -h 10.10.10.10 -p 6379 PING

Memory Troubleshooting

# Check memory usage
redis-cli -h 10.10.10.10 -p 6379 INFO memory

# Find big keys
redis-cli -h 10.10.10.10 -p 6379 --bigkeys

# Memory analysis report
redis-cli -h 10.10.10.10 -p 6379 MEMORY DOCTOR

Performance Troubleshooting

# Check slow query log
redis-cli -h 10.10.10.10 -p 6379 SLOWLOG GET 10

# Real-time command monitoring
redis-cli -h 10.10.10.10 -p 6379 MONITOR

# Check client connections
redis-cli -h 10.10.10.10 -p 6379 CLIENT LIST

Replication Troubleshooting

# Check replication status
redis-cli -h 10.10.10.10 -p 6379 INFO replication

# Check replication lag
redis-cli -h 10.10.10.10 -p 6380 INFO replication | grep lag

Performance Tuning

Memory Optimization

redis-cache:
  vars:
    redis_max_memory: 4GB           # set based on available memory
    redis_mem_policy: allkeys-lru   # LRU recommended for cache scenarios
    redis_conf: redis.conf

Persistence Optimization

# Pure cache scenario: disable persistence
redis-cache:
  vars:
    redis_rdb_save: []              # disable RDB
    redis_aof_enabled: false        # disable AOF

# Data safety scenario: enable both RDB and AOF
redis-data:
  vars:
    redis_rdb_save: ['900 1', '300 10', '60 10000']
    redis_aof_enabled: true

Connection Pool Recommendations

When connecting to Redis from client applications:

  • Use connection pooling to avoid frequent connection creation
  • Set reasonable timeout values (recommended 1-3 seconds)
  • Enable TCP keepalive
  • For high-concurrency scenarios, consider using Pipeline for batch operations

Key Monitoring Metrics

Monitor these metrics through Grafana dashboards:

  • Memory usage: Pay attention when redis:ins:mem_usage > 80%
  • CPU usage: Pay attention when redis:ins:cpu_usage > 70%
  • QPS: Watch for spikes and abnormal fluctuations
  • Response time: Investigate when redis:ins:rt > 1ms
  • Connection count: Monitor connection growth trends
  • Replication lag: Important for master-slave replication scenarios

15.5 - Monitoring

How to monitor Redis? What alert rules are worth paying attention to?

Dashboards

The REDIS module provides 3 monitoring dashboards:

  • Redis Overview: Overview of all Redis clusters
  • Redis Cluster: Details of a single Redis cluster
  • Redis Instance: Details of a single Redis instance

Monitoring

Pigsty provides three monitoring dashboards for the REDIS module:


Redis Overview

Redis Overview: Overview of all Redis clusters/instances

redis-overview.jpg


Redis Cluster

Redis Cluster: Details of a single Redis cluster

Redis Cluster Dashboard

redis-cluster.jpg



Redis Instance

Redis Instance: Details of a single Redis instance

Redis Instance Dashboard

redis-instance



Alert Rules

Pigsty provides the following six predefined alert rules for Redis, defined in files/victoria/rules/redis.yml:

  • RedisDown: Redis instance is down
  • RedisRejectConn: Redis instance rejecting connections
  • RedisRTHigh: Redis instance response time is too high
  • RedisCPUHigh: Redis instance CPU usage is too high
  • RedisMemHigh: Redis instance memory usage is too high
  • RedisQPSHigh: Redis instance QPS is too high
#==============================================================#
#                         Error                                #
#==============================================================#
# redis down triggers a P0 alert
- alert: RedisDown
  expr: redis_up < 1
  for: 1m
  labels: { level: 0, severity: CRIT, category: redis }
  annotations:
    summary: "CRIT RedisDown: {{ $labels.ins }} {{ $labels.instance }} {{ $value }}"
    description: |
      redis_up[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value }} == 0
      http://g.pigsty/d/redis-instance?from=now-5m&to=now&var-ins={{$labels.ins}}

# redis reject connection in last 5m
- alert: RedisRejectConn
  expr: redis:ins:conn_reject > 0
  labels: { level: 0, severity: CRIT, category: redis }
  annotations:
    summary: "CRIT RedisRejectConn: {{ $labels.ins }} {{ $labels.instance }} {{ $value }}"
    description: |
      redis:ins:conn_reject[cls={{ $labels.cls }}, ins={{ $labels.ins }}][5m] = {{ $value }} > 0
      http://g.pigsty/d/redis-instance?from=now-10m&to=now&viewPanel=88&fullscreen&var-ins={{ $labels.ins }}



#==============================================================#
#                         Latency                              #
#==============================================================#
# redis avg query response time > 160 µs
- alert: RedisRTHigh
  expr: redis:ins:rt > 0.00016
  for: 1m
  labels: { level: 1, severity: WARN, category: redis }
  annotations:
    summary: "WARN RedisRTHigh: {{ $labels.cls }} {{ $labels.ins }}"
    description: |
      pg:ins:query_rt[cls={{ $labels.cls }}, ins={{ $labels.ins }}] = {{ $value }} > 160µs
      http://g.pigsty/d/redis-instance?from=now-10m&to=now&viewPanel=97&fullscreen&var-ins={{ $labels.ins }}



#==============================================================#
#                        Saturation                            #
#==============================================================#
# redis cpu usage more than 70% for 1m
- alert: RedisCPUHigh
  expr: redis:ins:cpu_usage > 0.70
  for: 1m
  labels: { level: 1, severity: WARN, category: redis }
  annotations:
    summary: "WARN RedisCPUHigh: {{ $labels.cls }} {{ $labels.ins }}"
    description: |
      redis:ins:cpu_all[cls={{ $labels.cls }}, ins={{ $labels.ins }}] = {{ $value }} > 60%
      http://g.pigsty/d/redis-instance?from=now-10m&to=now&viewPanel=43&fullscreen&var-ins={{ $labels.ins }}

# redis mem usage more than 70% for 1m
- alert: RedisMemHigh
  expr: redis:ins:mem_usage > 0.70
  for: 1m
  labels: { level: 1, severity: WARN, category: redis }
  annotations:
    summary: "WARN RedisMemHigh: {{ $labels.cls }} {{ $labels.ins }}"
    description: |
      redis:ins:mem_usage[cls={{ $labels.cls }}, ins={{ $labels.ins }}] = {{ $value }} > 80%
      http://g.pigsty/d/redis-instance?from=now-10m&to=now&viewPanel=7&fullscreen&var-ins={{ $labels.ins }}

#==============================================================#
#                         Traffic                              #
#==============================================================#
# redis qps more than 32000 for 5m
- alert: RedisQPSHigh
  expr: redis:ins:qps > 32000
  for: 5m
  labels: { level: 2, severity: INFO, category: redis }
  annotations:
    summary: "INFO RedisQPSHigh: {{ $labels.cls }} {{ $labels.ins }}"
    description: |
      redis:ins:qps[cls={{ $labels.cls }}, ins={{ $labels.ins }}] = {{ $value }} > 16000
      http://g.pigsty/d/redis-instance?from=now-10m&to=now&viewPanel=96&fullscreen&var-ins={{ $labels.ins }}

15.6 - Metrics

Complete list of monitoring metrics provided by the Pigsty REDIS module with explanations

The REDIS module contains 275 available monitoring metrics.

Metric NameTypeLabelsDescription
ALERTSUnknowncls, ip, level, severity, instance, category, ins, alertname, job, alertstateN/A
ALERTS_FOR_STATEUnknowncls, ip, level, severity, instance, category, ins, alertname, jobN/A
redis:cls:aof_rewrite_timeUnknowncls, jobN/A
redis:cls:blocked_clientsUnknowncls, jobN/A
redis:cls:clientsUnknowncls, jobN/A
redis:cls:cmd_qpsUnknowncls, cmd, jobN/A
redis:cls:cmd_rtUnknowncls, cmd, jobN/A
redis:cls:cmd_timeUnknowncls, cmd, jobN/A
redis:cls:conn_rateUnknowncls, jobN/A
redis:cls:conn_rejectUnknowncls, jobN/A
redis:cls:cpu_sysUnknowncls, jobN/A
redis:cls:cpu_sys_childUnknowncls, jobN/A
redis:cls:cpu_usageUnknowncls, jobN/A
redis:cls:cpu_usage_childUnknowncls, jobN/A
redis:cls:cpu_userUnknowncls, jobN/A
redis:cls:cpu_user_childUnknowncls, jobN/A
redis:cls:fork_timeUnknowncls, jobN/A
redis:cls:key_evictUnknowncls, jobN/A
redis:cls:key_expireUnknowncls, jobN/A
redis:cls:key_hitUnknowncls, jobN/A
redis:cls:key_hit_rateUnknowncls, jobN/A
redis:cls:key_missUnknowncls, jobN/A
redis:cls:mem_maxUnknowncls, jobN/A
redis:cls:mem_usageUnknowncls, jobN/A
redis:cls:mem_usage_maxUnknowncls, jobN/A
redis:cls:mem_usedUnknowncls, jobN/A
redis:cls:net_trafficUnknowncls, jobN/A
redis:cls:qpsUnknowncls, jobN/A
redis:cls:qps_muUnknowncls, jobN/A
redis:cls:qps_realtimeUnknowncls, jobN/A
redis:cls:qps_sigmaUnknowncls, jobN/A
redis:cls:rtUnknowncls, jobN/A
redis:cls:rt_muUnknowncls, jobN/A
redis:cls:rt_sigmaUnknowncls, jobN/A
redis:cls:rxUnknowncls, jobN/A
redis:cls:sizeUnknowncls, jobN/A
redis:cls:txUnknowncls, jobN/A
redis:env:blocked_clientsUnknownjobN/A
redis:env:clientsUnknownjobN/A
redis:env:cmd_qpsUnknowncmd, jobN/A
redis:env:cmd_rtUnknowncmd, jobN/A
redis:env:cmd_timeUnknowncmd, jobN/A
redis:env:conn_rateUnknownjobN/A
redis:env:conn_rejectUnknownjobN/A
redis:env:cpu_usageUnknownjobN/A
redis:env:cpu_usage_childUnknownjobN/A
redis:env:key_evictUnknownjobN/A
redis:env:key_expireUnknownjobN/A
redis:env:key_hitUnknownjobN/A
redis:env:key_hit_rateUnknownjobN/A
redis:env:key_missUnknownjobN/A
redis:env:mem_usageUnknownjobN/A
redis:env:net_trafficUnknownjobN/A
redis:env:qpsUnknownjobN/A
redis:env:qps_muUnknownjobN/A
redis:env:qps_realtimeUnknownjobN/A
redis:env:qps_sigmaUnknownjobN/A
redis:env:rtUnknownjobN/A
redis:env:rt_muUnknownjobN/A
redis:env:rt_sigmaUnknownjobN/A
redis:env:rxUnknownjobN/A
redis:env:txUnknownjobN/A
redis:insUnknowncls, id, instance, ins, jobN/A
redis:ins:blocked_clientsUnknowncls, ip, instance, ins, jobN/A
redis:ins:clientsUnknowncls, ip, instance, ins, jobN/A
redis:ins:cmd_qpsUnknowncls, cmd, ip, instance, ins, jobN/A
redis:ins:cmd_rtUnknowncls, cmd, ip, instance, ins, jobN/A
redis:ins:cmd_timeUnknowncls, cmd, ip, instance, ins, jobN/A
redis:ins:conn_rateUnknowncls, ip, instance, ins, jobN/A
redis:ins:conn_rejectUnknowncls, ip, instance, ins, jobN/A
redis:ins:cpu_sysUnknowncls, ip, instance, ins, jobN/A
redis:ins:cpu_sys_childUnknowncls, ip, instance, ins, jobN/A
redis:ins:cpu_usageUnknowncls, ip, instance, ins, jobN/A
redis:ins:cpu_usage_childUnknowncls, ip, instance, ins, jobN/A
redis:ins:cpu_userUnknowncls, ip, instance, ins, jobN/A
redis:ins:cpu_user_childUnknowncls, ip, instance, ins, jobN/A
redis:ins:key_evictUnknowncls, ip, instance, ins, jobN/A
redis:ins:key_expireUnknowncls, ip, instance, ins, jobN/A
redis:ins:key_hitUnknowncls, ip, instance, ins, jobN/A
redis:ins:key_hit_rateUnknowncls, ip, instance, ins, jobN/A
redis:ins:key_missUnknowncls, ip, instance, ins, jobN/A
redis:ins:lsn_rateUnknowncls, ip, instance, ins, jobN/A
redis:ins:mem_usageUnknowncls, ip, instance, ins, jobN/A
redis:ins:net_trafficUnknowncls, ip, instance, ins, jobN/A
redis:ins:qpsUnknowncls, ip, instance, ins, jobN/A
redis:ins:qps_muUnknowncls, ip, instance, ins, jobN/A
redis:ins:qps_realtimeUnknowncls, ip, instance, ins, jobN/A
redis:ins:qps_sigmaUnknowncls, ip, instance, ins, jobN/A
redis:ins:rtUnknowncls, ip, instance, ins, jobN/A
redis:ins:rt_muUnknowncls, ip, instance, ins, jobN/A
redis:ins:rt_sigmaUnknowncls, ip, instance, ins, jobN/A
redis:ins:rxUnknowncls, ip, instance, ins, jobN/A
redis:ins:txUnknowncls, ip, instance, ins, jobN/A
redis:node:ipUnknowncls, ip, instance, ins, jobN/A
redis:node:mem_allocUnknowncls, ip, jobN/A
redis:node:mem_totalUnknowncls, ip, jobN/A
redis:node:mem_usedUnknowncls, ip, jobN/A
redis:node:qpsUnknowncls, ip, jobN/A
redis_active_defrag_runninggaugecls, ip, instance, ins, jobactive_defrag_running metric
redis_allocator_active_bytesgaugecls, ip, instance, ins, joballocator_active_bytes metric
redis_allocator_allocated_bytesgaugecls, ip, instance, ins, joballocator_allocated_bytes metric
redis_allocator_frag_bytesgaugecls, ip, instance, ins, joballocator_frag_bytes metric
redis_allocator_frag_ratiogaugecls, ip, instance, ins, joballocator_frag_ratio metric
redis_allocator_resident_bytesgaugecls, ip, instance, ins, joballocator_resident_bytes metric
redis_allocator_rss_bytesgaugecls, ip, instance, ins, joballocator_rss_bytes metric
redis_allocator_rss_ratiogaugecls, ip, instance, ins, joballocator_rss_ratio metric
redis_aof_current_rewrite_duration_secgaugecls, ip, instance, ins, jobaof_current_rewrite_duration_sec metric
redis_aof_enabledgaugecls, ip, instance, ins, jobaof_enabled metric
redis_aof_last_bgrewrite_statusgaugecls, ip, instance, ins, jobaof_last_bgrewrite_status metric
redis_aof_last_cow_size_bytesgaugecls, ip, instance, ins, jobaof_last_cow_size_bytes metric
redis_aof_last_rewrite_duration_secgaugecls, ip, instance, ins, jobaof_last_rewrite_duration_sec metric
redis_aof_last_write_statusgaugecls, ip, instance, ins, jobaof_last_write_status metric
redis_aof_rewrite_in_progressgaugecls, ip, instance, ins, jobaof_rewrite_in_progress metric
redis_aof_rewrite_scheduledgaugecls, ip, instance, ins, jobaof_rewrite_scheduled metric
redis_blocked_clientsgaugecls, ip, instance, ins, jobblocked_clients metric
redis_client_recent_max_input_buffer_bytesgaugecls, ip, instance, ins, jobclient_recent_max_input_buffer_bytes metric
redis_client_recent_max_output_buffer_bytesgaugecls, ip, instance, ins, jobclient_recent_max_output_buffer_bytes metric
redis_clients_in_timeout_tablegaugecls, ip, instance, ins, jobclients_in_timeout_table metric
redis_cluster_connectionsgaugecls, ip, instance, ins, jobcluster_connections metric
redis_cluster_current_epochgaugecls, ip, instance, ins, jobcluster_current_epoch metric
redis_cluster_enabledgaugecls, ip, instance, ins, jobcluster_enabled metric
redis_cluster_known_nodesgaugecls, ip, instance, ins, jobcluster_known_nodes metric
redis_cluster_messages_received_totalgaugecls, ip, instance, ins, jobcluster_messages_received_total metric
redis_cluster_messages_sent_totalgaugecls, ip, instance, ins, jobcluster_messages_sent_total metric
redis_cluster_my_epochgaugecls, ip, instance, ins, jobcluster_my_epoch metric
redis_cluster_sizegaugecls, ip, instance, ins, jobcluster_size metric
redis_cluster_slots_assignedgaugecls, ip, instance, ins, jobcluster_slots_assigned metric
redis_cluster_slots_failgaugecls, ip, instance, ins, jobcluster_slots_fail metric
redis_cluster_slots_okgaugecls, ip, instance, ins, jobcluster_slots_ok metric
redis_cluster_slots_pfailgaugecls, ip, instance, ins, jobcluster_slots_pfail metric
redis_cluster_stategaugecls, ip, instance, ins, jobcluster_state metric
redis_cluster_stats_messages_meet_receivedgaugecls, ip, instance, ins, jobcluster_stats_messages_meet_received metric
redis_cluster_stats_messages_meet_sentgaugecls, ip, instance, ins, jobcluster_stats_messages_meet_sent metric
redis_cluster_stats_messages_ping_receivedgaugecls, ip, instance, ins, jobcluster_stats_messages_ping_received metric
redis_cluster_stats_messages_ping_sentgaugecls, ip, instance, ins, jobcluster_stats_messages_ping_sent metric
redis_cluster_stats_messages_pong_receivedgaugecls, ip, instance, ins, jobcluster_stats_messages_pong_received metric
redis_cluster_stats_messages_pong_sentgaugecls, ip, instance, ins, jobcluster_stats_messages_pong_sent metric
redis_commands_duration_seconds_totalcountercls, cmd, ip, instance, ins, jobTotal amount of time in seconds spent per command
redis_commands_failed_calls_totalcountercls, cmd, ip, instance, ins, jobTotal number of errors prior command execution per command
redis_commands_latencies_usec_bucketUnknowncls, cmd, ip, le, instance, ins, jobN/A
redis_commands_latencies_usec_countUnknowncls, cmd, ip, instance, ins, jobN/A
redis_commands_latencies_usec_sumUnknowncls, cmd, ip, instance, ins, jobN/A
redis_commands_processed_totalcountercls, ip, instance, ins, jobcommands_processed_total metric
redis_commands_rejected_calls_totalcountercls, cmd, ip, instance, ins, jobTotal number of errors within command execution per command
redis_commands_totalcountercls, cmd, ip, instance, ins, jobTotal number of calls per command
redis_config_io_threadsgaugecls, ip, instance, ins, jobconfig_io_threads metric
redis_config_maxclientsgaugecls, ip, instance, ins, jobconfig_maxclients metric
redis_config_maxmemorygaugecls, ip, instance, ins, jobconfig_maxmemory metric
redis_connected_clientsgaugecls, ip, instance, ins, jobconnected_clients metric
redis_connected_slave_lag_secondsgaugecls, ip, slave_ip, instance, slave_state, ins, slave_port, jobLag of connected slave
redis_connected_slave_offset_bytesgaugecls, ip, slave_ip, instance, slave_state, ins, slave_port, jobOffset of connected slave
redis_connected_slavesgaugecls, ip, instance, ins, jobconnected_slaves metric
redis_connections_received_totalcountercls, ip, instance, ins, jobconnections_received_total metric
redis_cpu_sys_children_seconds_totalcountercls, ip, instance, ins, jobcpu_sys_children_seconds_total metric
redis_cpu_sys_main_thread_seconds_totalcountercls, ip, instance, ins, jobcpu_sys_main_thread_seconds_total metric
redis_cpu_sys_seconds_totalcountercls, ip, instance, ins, jobcpu_sys_seconds_total metric
redis_cpu_user_children_seconds_totalcountercls, ip, instance, ins, jobcpu_user_children_seconds_total metric
redis_cpu_user_main_thread_seconds_totalcountercls, ip, instance, ins, jobcpu_user_main_thread_seconds_total metric
redis_cpu_user_seconds_totalcountercls, ip, instance, ins, jobcpu_user_seconds_total metric
redis_db_keysgaugecls, ip, instance, ins, db, jobTotal number of keys by DB
redis_db_keys_expiringgaugecls, ip, instance, ins, db, jobTotal number of expiring keys by DB
redis_defrag_hitsgaugecls, ip, instance, ins, jobdefrag_hits metric
redis_defrag_key_hitsgaugecls, ip, instance, ins, jobdefrag_key_hits metric
redis_defrag_key_missesgaugecls, ip, instance, ins, jobdefrag_key_misses metric
redis_defrag_missesgaugecls, ip, instance, ins, jobdefrag_misses metric
redis_dump_payload_sanitizationscountercls, ip, instance, ins, jobdump_payload_sanitizations metric
redis_errors_totalcountercls, ip, err, instance, ins, jobTotal number of errors per error type
redis_evicted_keys_totalcountercls, ip, instance, ins, jobevicted_keys_total metric
redis_expired_keys_totalcountercls, ip, instance, ins, jobexpired_keys_total metric
redis_expired_stale_percentagegaugecls, ip, instance, ins, jobexpired_stale_percentage metric
redis_expired_time_cap_reached_totalgaugecls, ip, instance, ins, jobexpired_time_cap_reached_total metric
redis_exporter_build_infogaugecls, golang_version, ip, commit_sha, instance, version, ins, job, build_dateredis exporter build_info
redis_exporter_last_scrape_connect_time_secondsgaugecls, ip, instance, ins, jobexporter_last_scrape_connect_time_seconds metric
redis_exporter_last_scrape_duration_secondsgaugecls, ip, instance, ins, jobexporter_last_scrape_duration_seconds metric
redis_exporter_last_scrape_errorgaugecls, ip, instance, ins, jobThe last scrape error status.
redis_exporter_scrape_duration_seconds_countUnknowncls, ip, instance, ins, jobN/A
redis_exporter_scrape_duration_seconds_sumUnknowncls, ip, instance, ins, jobN/A
redis_exporter_scrapes_totalcountercls, ip, instance, ins, jobCurrent total redis scrapes.
redis_instance_infogaugecls, ip, os, role, instance, run_id, redis_version, tcp_port, process_id, ins, redis_mode, maxmemory_policy, redis_build_id, jobInformation about the Redis instance
redis_io_threaded_reads_processedcountercls, ip, instance, ins, jobio_threaded_reads_processed metric
redis_io_threaded_writes_processedcountercls, ip, instance, ins, jobio_threaded_writes_processed metric
redis_io_threads_activegaugecls, ip, instance, ins, jobio_threads_active metric
redis_keyspace_hits_totalcountercls, ip, instance, ins, jobkeyspace_hits_total metric
redis_keyspace_misses_totalcountercls, ip, instance, ins, jobkeyspace_misses_total metric
redis_last_key_groups_scrape_duration_millisecondsgaugecls, ip, instance, ins, jobDuration of the last key group metrics scrape in milliseconds
redis_last_slow_execution_duration_secondsgaugecls, ip, instance, ins, jobThe amount of time needed for last slow execution, in seconds
redis_latency_percentiles_usecsummarycls, cmd, ip, instance, quantile, ins, jobA summary of latency percentile distribution per command
redis_latency_percentiles_usec_countUnknowncls, cmd, ip, instance, ins, jobN/A
redis_latency_percentiles_usec_sumUnknowncls, cmd, ip, instance, ins, jobN/A
redis_latest_fork_secondsgaugecls, ip, instance, ins, joblatest_fork_seconds metric
redis_lazyfree_pending_objectsgaugecls, ip, instance, ins, joblazyfree_pending_objects metric
redis_loading_dump_filegaugecls, ip, instance, ins, jobloading_dump_file metric
redis_master_last_io_seconds_agogaugecls, ip, master_host, instance, ins, job, master_portMaster last io seconds ago
redis_master_link_upgaugecls, ip, master_host, instance, ins, job, master_portMaster link status on Redis slave
redis_master_repl_offsetgaugecls, ip, instance, ins, jobmaster_repl_offset metric
redis_master_sync_in_progressgaugecls, ip, master_host, instance, ins, job, master_portMaster sync in progress
redis_mem_clients_normalgaugecls, ip, instance, ins, jobmem_clients_normal metric
redis_mem_clients_slavesgaugecls, ip, instance, ins, jobmem_clients_slaves metric
redis_mem_fragmentation_bytesgaugecls, ip, instance, ins, jobmem_fragmentation_bytes metric
redis_mem_fragmentation_ratiogaugecls, ip, instance, ins, jobmem_fragmentation_ratio metric
redis_mem_not_counted_for_eviction_bytesgaugecls, ip, instance, ins, jobmem_not_counted_for_eviction_bytes metric
redis_memory_max_bytesgaugecls, ip, instance, ins, jobmemory_max_bytes metric
redis_memory_used_bytesgaugecls, ip, instance, ins, jobmemory_used_bytes metric
redis_memory_used_dataset_bytesgaugecls, ip, instance, ins, jobmemory_used_dataset_bytes metric
redis_memory_used_lua_bytesgaugecls, ip, instance, ins, jobmemory_used_lua_bytes metric
redis_memory_used_overhead_bytesgaugecls, ip, instance, ins, jobmemory_used_overhead_bytes metric
redis_memory_used_peak_bytesgaugecls, ip, instance, ins, jobmemory_used_peak_bytes metric
redis_memory_used_rss_bytesgaugecls, ip, instance, ins, jobmemory_used_rss_bytes metric
redis_memory_used_scripts_bytesgaugecls, ip, instance, ins, jobmemory_used_scripts_bytes metric
redis_memory_used_startup_bytesgaugecls, ip, instance, ins, jobmemory_used_startup_bytes metric
redis_migrate_cached_sockets_totalgaugecls, ip, instance, ins, jobmigrate_cached_sockets_total metric
redis_module_fork_in_progressgaugecls, ip, instance, ins, jobmodule_fork_in_progress metric
redis_module_fork_last_cow_sizegaugecls, ip, instance, ins, jobmodule_fork_last_cow_size metric
redis_net_input_bytes_totalcountercls, ip, instance, ins, jobnet_input_bytes_total metric
redis_net_output_bytes_totalcountercls, ip, instance, ins, jobnet_output_bytes_total metric
redis_number_of_cached_scriptsgaugecls, ip, instance, ins, jobnumber_of_cached_scripts metric
redis_process_idgaugecls, ip, instance, ins, jobprocess_id metric
redis_pubsub_channelsgaugecls, ip, instance, ins, jobpubsub_channels metric
redis_pubsub_patternsgaugecls, ip, instance, ins, jobpubsub_patterns metric
redis_pubsubshard_channelsgaugecls, ip, instance, ins, jobpubsubshard_channels metric
redis_rdb_bgsave_in_progressgaugecls, ip, instance, ins, jobrdb_bgsave_in_progress metric
redis_rdb_changes_since_last_savegaugecls, ip, instance, ins, jobrdb_changes_since_last_save metric
redis_rdb_current_bgsave_duration_secgaugecls, ip, instance, ins, jobrdb_current_bgsave_duration_sec metric
redis_rdb_last_bgsave_duration_secgaugecls, ip, instance, ins, jobrdb_last_bgsave_duration_sec metric
redis_rdb_last_bgsave_statusgaugecls, ip, instance, ins, jobrdb_last_bgsave_status metric
redis_rdb_last_cow_size_bytesgaugecls, ip, instance, ins, jobrdb_last_cow_size_bytes metric
redis_rdb_last_save_timestamp_secondsgaugecls, ip, instance, ins, jobrdb_last_save_timestamp_seconds metric
redis_rejected_connections_totalcountercls, ip, instance, ins, jobrejected_connections_total metric
redis_repl_backlog_first_byte_offsetgaugecls, ip, instance, ins, jobrepl_backlog_first_byte_offset metric
redis_repl_backlog_history_bytesgaugecls, ip, instance, ins, jobrepl_backlog_history_bytes metric
redis_repl_backlog_is_activegaugecls, ip, instance, ins, jobrepl_backlog_is_active metric
redis_replica_partial_resync_acceptedgaugecls, ip, instance, ins, jobreplica_partial_resync_accepted metric
redis_replica_partial_resync_deniedgaugecls, ip, instance, ins, jobreplica_partial_resync_denied metric
redis_replica_resyncs_fullgaugecls, ip, instance, ins, jobreplica_resyncs_full metric
redis_replication_backlog_bytesgaugecls, ip, instance, ins, jobreplication_backlog_bytes metric
redis_second_repl_offsetgaugecls, ip, instance, ins, jobsecond_repl_offset metric
redis_sentinel_master_ckquorum_statusgaugecls, ip, message, instance, ins, master_name, jobMaster ckquorum status
redis_sentinel_master_ok_sentinelsgaugecls, ip, instance, ins, master_address, master_name, jobThe number of okay sentinels monitoring this master
redis_sentinel_master_ok_slavesgaugecls, ip, instance, ins, master_address, master_name, jobThe number of okay slaves of the master
redis_sentinel_master_sentinelsgaugecls, ip, instance, ins, master_address, master_name, jobThe number of sentinels monitoring this master
redis_sentinel_master_setting_ckquorumgaugecls, ip, instance, ins, master_address, master_name, jobShow the current ckquorum config for each master
redis_sentinel_master_setting_down_after_millisecondsgaugecls, ip, instance, ins, master_address, master_name, jobShow the current down-after-milliseconds config for each master
redis_sentinel_master_setting_failover_timeoutgaugecls, ip, instance, ins, master_address, master_name, jobShow the current failover-timeout config for each master
redis_sentinel_master_setting_parallel_syncsgaugecls, ip, instance, ins, master_address, master_name, jobShow the current parallel-syncs config for each master
redis_sentinel_master_slavesgaugecls, ip, instance, ins, master_address, master_name, jobThe number of slaves of the master
redis_sentinel_master_statusgaugecls, ip, master_status, instance, ins, master_address, master_name, jobMaster status on Sentinel
redis_sentinel_mastersgaugecls, ip, instance, ins, jobThe number of masters this sentinel is watching
redis_sentinel_running_scriptsgaugecls, ip, instance, ins, jobNumber of scripts in execution right now
redis_sentinel_scripts_queue_lengthgaugecls, ip, instance, ins, jobQueue of user scripts to execute
redis_sentinel_simulate_failure_flagsgaugecls, ip, instance, ins, jobFailures simulations
redis_sentinel_tiltgaugecls, ip, instance, ins, jobSentinel is in TILT mode
redis_slave_expires_tracked_keysgaugecls, ip, instance, ins, jobslave_expires_tracked_keys metric
redis_slave_infogaugecls, ip, master_host, instance, read_only, ins, job, master_portInformation about the Redis slave
redis_slave_prioritygaugecls, ip, instance, ins, jobslave_priority metric
redis_slave_repl_offsetgaugecls, ip, master_host, instance, ins, job, master_portSlave replication offset
redis_slowlog_last_idgaugecls, ip, instance, ins, jobLast id of slowlog
redis_slowlog_lengthgaugecls, ip, instance, ins, jobTotal slowlog
redis_start_time_secondsgaugecls, ip, instance, ins, jobStart time of the Redis instance since unix epoch in seconds.
redis_target_scrape_request_errors_totalcountercls, ip, instance, ins, jobErrors in requests to the exporter
redis_total_error_repliescountercls, ip, instance, ins, jobtotal_error_replies metric
redis_total_reads_processedcountercls, ip, instance, ins, jobtotal_reads_processed metric
redis_total_system_memory_bytesgaugecls, ip, instance, ins, jobtotal_system_memory_bytes metric
redis_total_writes_processedcountercls, ip, instance, ins, jobtotal_writes_processed metric
redis_tracking_clientsgaugecls, ip, instance, ins, jobtracking_clients metric
redis_tracking_total_itemsgaugecls, ip, instance, ins, jobtracking_total_items metric
redis_tracking_total_keysgaugecls, ip, instance, ins, jobtracking_total_keys metric
redis_tracking_total_prefixesgaugecls, ip, instance, ins, jobtracking_total_prefixes metric
redis_unexpected_error_repliescountercls, ip, instance, ins, jobunexpected_error_replies metric
redis_upgaugecls, ip, instance, ins, jobInformation about the Redis instance
redis_uptime_in_secondsgaugecls, ip, instance, ins, jobuptime_in_seconds metric
scrape_duration_secondsUnknowncls, ip, instance, ins, jobN/A
scrape_samples_post_metric_relabelingUnknowncls, ip, instance, ins, jobN/A
scrape_samples_scrapedUnknowncls, ip, instance, ins, jobN/A
scrape_series_addedUnknowncls, ip, instance, ins, jobN/A
upUnknowncls, ip, instance, ins, jobN/A

15.7 - FAQ

Frequently asked questions about the Pigsty REDIS module

ABORT due to redis_safeguard enabled

This means the Redis instance you are trying to remove has the safeguard enabled: this happens when attempting to remove a Redis instance with redis_safeguard set to true. The redis-rm.yml playbook refuses to execute to prevent accidental deletion of running Redis instances.

You can override this protection with the CLI argument -e redis_safeguard=false to force removal of the Redis instance. This is what redis_safeguard is designed for.


How to add a new Redis instance on a node?

Use bin/redis-add <ip> <port> to deploy a new Redis instance on the node.


How to remove a specific instance from a node?

Use bin/redis-rm <ip> <port> to remove a single Redis instance from the node.


Are there plans to upgrade to Valkey or the latest version?

Since Redis is not a core component of this project, there are currently no plans to update to the latest Redis RSAL / AGPLv3 version or Valkey. The Redis version in Pigsty is locked to 7.2.6, the last version using the BSD license.

This version has been validated in large-scale production environments, and Pigsty no longer has such scenarios to re-validate the stability and reliability of newer versions.

16 - Module: FERRET

Add MongoDB-compatible protocol support to PostgreSQL using FerretDB

FERRET is an optional module in Pigsty for deploying FerretDB — a protocol translation middleware built on the PostgreSQL kernel and the DocumentDB extension. It enables applications using MongoDB drivers to connect and translates those requests into PostgreSQL operations.

Pigsty is a community partner of FerretDB. We have built binary packages for FerretDB and DocumentDB (FerretDB-specific fork), and provide a ready-to-use configuration template mongo.yml to help you easily deploy enterprise-grade FerretDB clusters.

16.1 - Usage

Install client tools, connect to and use FerretDB

This document describes how to install MongoDB client tools and connect to FerretDB.


Installing Client Tools

You can use MongoDB’s command-line tool MongoSH to access FerretDB.

Use the pig command to add the MongoDB repository, then install mongosh using yum or apt:

pig repo add mongo -u   # Add the official MongoDB repository
yum install mongodb-mongosh   # RHEL/CentOS/Rocky/Alma
apt install mongodb-mongosh   # Debian/Ubuntu

After installation, you can use the mongosh command to connect to FerretDB.


Connecting to FerretDB

You can access FerretDB using any language’s MongoDB driver via a MongoDB connection string. Here’s an example using the mongosh CLI tool:

$ mongosh
Current Mongosh Log ID:	67ba8c1fe551f042bf51e943
Connecting to:		mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.4.0
Using MongoDB:		7.0.77
Using Mongosh:		2.4.0

For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/

test>

Using Connection Strings

FerretDB authentication is entirely based on PostgreSQL. Since Pigsty-managed PostgreSQL clusters use scram-sha-256 authentication by default, you must specify the PLAIN authentication mechanism in the connection string:

mongosh 'mongodb://dbuser_meta:[email protected]:27017?authMechanism=PLAIN'

Connection string format:

mongodb://<username>:<password>@<host>:<port>/<database>?authMechanism=PLAIN

Using Different Users

You can connect to FerretDB using any user that has been created in PostgreSQL:

# Using dbuser_dba user
mongosh 'mongodb://dbuser_dba:[email protected]:27017?authMechanism=PLAIN'

# Using mongod superuser
mongosh 'mongodb://mongod:[email protected]:27017?authMechanism=PLAIN'

# Connecting to a specific database
mongosh 'mongodb://test:[email protected]:27017/test?authMechanism=PLAIN'

Basic Operations

After connecting to FerretDB, you can operate it just like MongoDB. Here are some basic operation examples:

Database Operations

// Switch to / create database
use mydb

// Show all databases
show dbs

// Drop current database
db.dropDatabase()

Collection Operations

// Create collection
db.createCollection('users')

// Show all collections
show collections

// Drop collection
db.users.drop()

Document Operations

// Insert a single document
db.users.insertOne({
    name: 'Alice',
    age: 30,
    email: '[email protected]'
})

// Insert multiple documents
db.users.insertMany([
    { name: 'Bob', age: 25 },
    { name: 'Charlie', age: 35 }
])

// Query documents
db.users.find()
db.users.find({ age: { $gt: 25 } })
db.users.findOne({ name: 'Alice' })

// Update documents
db.users.updateOne(
    { name: 'Alice' },
    { $set: { age: 31 } }
)

// Delete documents
db.users.deleteOne({ name: 'Bob' })
db.users.deleteMany({ age: { $lt: 30 } })

Index Operations

// Create indexes
db.users.createIndex({ name: 1 })
db.users.createIndex({ age: -1 })

// View indexes
db.users.getIndexes()

// Drop index
db.users.dropIndex('name_1')

Differences from MongoDB

FerretDB implements MongoDB’s wire protocol but uses PostgreSQL for underlying storage. This means:

  • MongoDB commands are translated to SQL statements for execution
  • Most basic operations are compatible with MongoDB
  • Some advanced features may differ or not be supported

You can consult the following resources for detailed information:


Programming Language Drivers

In addition to the mongosh command-line tool, you can also connect to FerretDB using MongoDB drivers for various programming languages:

Python

from pymongo import MongoClient

client = MongoClient('mongodb://dbuser_meta:[email protected]:27017/?authMechanism=PLAIN')
db = client.test
collection = db.users
collection.insert_one({'name': 'Alice', 'age': 30})

Node.js

const { MongoClient } = require('mongodb');

const uri = 'mongodb://dbuser_meta:[email protected]:27017/?authMechanism=PLAIN';
const client = new MongoClient(uri);

async function run() {
    await client.connect();
    const db = client.db('test');
    const collection = db.collection('users');
    await collection.insertOne({ name: 'Alice', age: 30 });
}

Go

import (
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

uri := "mongodb://dbuser_meta:[email protected]:27017/?authMechanism=PLAIN"
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))

Key point: All drivers require the authMechanism=PLAIN parameter in the connection string.

16.2 - Configuration

Configure the FerretDB module and define cluster topology

Before deploying a FerretDB cluster, you need to define it in the configuration inventory using the relevant parameters.


FerretDB Cluster

The following example uses the default single-node pg-meta cluster’s meta database as FerretDB’s underlying storage:

all:
  children:

    #----------------------------------#
    # ferretdb for mongodb on postgresql
    #----------------------------------#
    # ./mongo.yml -l ferret
    ferret:
      hosts:
        10.10.10.10: { mongo_seq: 1 }
      vars:
        mongo_cluster: ferret
        mongo_pgurl: 'postgres://mongod:[email protected]:5432/meta'

Here, mongo_cluster and mongo_seq are essential identity parameters. For FerretDB, mongo_pgurl is also required to specify the underlying PostgreSQL location.

Note that the mongo_pgurl parameter requires a PostgreSQL superuser. In this example, a dedicated mongod superuser is defined for FerretDB.

Note that FerretDB’s authentication is entirely based on PostgreSQL. You can create other regular users using either FerretDB or PostgreSQL.


PostgreSQL Cluster

FerretDB 2.0+ requires an extension: DocumentDB, which depends on several other extensions. Here’s a template for creating a PostgreSQL cluster for FerretDB:

all:
  children:

    #----------------------------------#
    # pgsql (singleton on current node)
    #----------------------------------#
    # postgres cluster: pg-meta
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: mongod      ,password: DBUser.Mongo  ,pgbouncer: true ,roles: [dbrole_admin ] ,superuser: true ,comment: ferretdb super user }
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: meta, owner: mongod ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ documentdb, postgis, vector, pg_cron, rum ]}
        pg_hba_rules:
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
          - { user: mongod      , db: all ,addr: world ,auth: pwd ,title: 'mongodb password access from everywhere' }
        pg_extensions:
          - documentdb, citus, postgis, pgvector, pg_cron, rum
        pg_parameters:
          cron.database_name: meta
        pg_libs: 'pg_documentdb, pg_documentdb_core, pg_cron, pg_stat_statements, auto_explain'

Key configuration points:

  • User configuration: You need to create a mongod user with superuser privileges for FerretDB to use
  • Database configuration: The database needs to have the documentdb extension and its dependencies installed
  • HBA rules: Allow the mongod user to connect from any address with password authentication
  • Shared libraries: pg_documentdb and pg_documentdb_core need to be preloaded in pg_libs

High Availability

You can use Services to connect to a highly available PostgreSQL cluster, deploy multiple FerretDB instance replicas, and bind an L2 VIP for the FerretDB layer to achieve high availability.

ferret:
  hosts:
    10.10.10.45: { mongo_seq: 1 }
    10.10.10.46: { mongo_seq: 2 }
    10.10.10.47: { mongo_seq: 3 }
  vars:
    mongo_cluster: ferret
    mongo_pgurl: 'postgres://mongod:[email protected]:5436/test'
    vip_enabled: true
    vip_vrid: 128
    vip_address: 10.10.10.99
    vip_interface: eth1

In this high-availability configuration:

  • Multi-instance deployment: Deploy FerretDB instances on three nodes, with all instances connecting to the same PostgreSQL backend
  • VIP configuration: Use Keepalived to bind the virtual IP 10.10.10.99, enabling failover at the FerretDB layer
  • Service address: Use PostgreSQL’s service address (port 5436 is typically the primary service), ensuring connections go to the correct primary

With this configuration, clients can connect to FerretDB through the VIP address. Even if one FerretDB instance fails, the VIP will automatically float to another available instance.

16.3 - Parameters

Customize FerretDB with 9 parameters

Parameter Overview

The FERRET parameter group is used for FerretDB deployment and configuration, including identity, underlying PostgreSQL connection, listen ports, and SSL settings.

ParameterTypeLevelDescription
mongo_seqintImongo instance number, required identity param
mongo_clusterstringCmongo cluster name, required identity param
mongo_pgurlpgurlC/IPostgreSQL URL for FerretDB backend
mongo_ssl_enabledboolCEnable SSL? default is false
mongo_listenipCListen address, empty listens on all addresses
mongo_portportCService port, default 27017
mongo_ssl_portportCTLS listen port, default 27018
mongo_exporter_portportCExporter port, default 9216
mongo_extra_varsstringCExtra environment variables, empty by default

Defaults

Default parameters are defined in roles/ferret/defaults/main.yml:

# mongo_cluster:        #CLUSTER  # mongo cluster name, required identity param
# mongo_seq: 0          #INSTANCE # mongo instance sequence, required identity param
# mongo_pgurl: 'postgres:///'     # mongo/ferretdb underlying postgresql url, required
mongo_ssl_enabled: false          # mongo/ferretdb ssl enabled, default false
mongo_listen: ''                  # mongo/ferretdb listen address, '' for all
mongo_port: 27017                 # mongo/ferretdb listen port, default 27017
mongo_ssl_port: 27018             # mongo/ferretdb tls listen port, default 27018
mongo_exporter_port: 9216         # mongo/ferretdb exporter port, default 9216
mongo_extra_vars: ''              # mongo/ferretdb extra environment variables

mongo_cluster

Parameter: mongo_cluster, Type: string, Level: C

mongo cluster name, a required identity parameter.

No default value—you must explicitly define it for production environments.

The cluster name must comply with the regex [a-z][a-z0-9-]*. Using descriptive names is recommended.


mongo_seq

Parameter: mongo_seq, Type: int, Level: I

mongo instance sequence number, a unique integer identifier within the cluster.

You must explicitly define the sequence number for each mongo instance. Integers start from 0 or 1.


mongo_pgurl

Parameter: mongo_pgurl, Type: pgurl, Level: C/I

PostgreSQL URL for FerretDB backend connection, a required parameter.

No default value—you must explicitly define it. This is the PostgreSQL database connection string that FerretDB will use as its backend storage.

Format: postgres://username:password@host:port/database

Notes:

  • The user needs to be a PostgreSQL superuser
  • The target database needs the documentdb extension installed
  • Using a dedicated mongod user is recommended

mongo_ssl_enabled

Parameter: mongo_ssl_enabled, Type: bool, Level: C

Enable SSL/TLS encryption for FerretDB.

Default is false. Set to true to enable SSL/TLS encryption for mongo connections.

When enabled, FerretDB will:

  • Generate and issue SSL certificates
  • Listen for encrypted connections on mongo_ssl_port

mongo_listen

Parameter: mongo_listen, Type: ip, Level: C

Listen address for mongo binding.

Default is empty string '', meaning listen on all available addresses (0.0.0.0). You can specify a specific IP address to bind to.


mongo_port

Parameter: mongo_port, Type: port, Level: C

Service port for mongo client connections.

Default is 27017, which is the standard MongoDB port. Change this port if you need to avoid port conflicts or have security considerations.


mongo_ssl_port

Parameter: mongo_ssl_port, Type: port, Level: C

TLS listen port for mongo encrypted connections.

Default is 27018. When SSL/TLS is enabled via mongo_ssl_enabled, FerretDB will accept encrypted connections on this port.


mongo_exporter_port

Parameter: mongo_exporter_port, Type: port, Level: C

Exporter port for mongo metrics collection.

Default is 9216. This port is used by FerretDB’s built-in metrics exporter to expose monitoring metrics to Prometheus.


mongo_extra_vars

Parameter: mongo_extra_vars, Type: string, Level: C

Extra environment variables for FerretDB server.

Default is empty string ''. You can specify additional environment variables to pass to the FerretDB process in KEY=VALUE format, with multiple variables separated by spaces.

Example:

mongo_extra_vars: 'FERRETDB_LOG_LEVEL=debug FERRETDB_TELEMETRY=disable'

16.4 - Administration

Create, remove, expand, shrink, and upgrade FerretDB clusters

This document describes daily administration operations for FerretDB clusters.


Create FerretDB Cluster

After defining a FerretDB cluster in the configuration inventory, you can install it with the following command:

./mongo.yml -l ferret   # Install FerretDB on the ferret group

Since FerretDB uses PostgreSQL as its underlying storage, running this playbook multiple times is generally safe (idempotent).

The FerretDB service is configured to automatically restart on failure (Restart=on-failure), providing basic resilience for this stateless proxy layer.


Remove FerretDB Cluster

To remove a FerretDB cluster, run the mongo_purge subtask of the mongo.yml playbook with the mongo_purge parameter:

./mongo.yml -l ferret -e mongo_purge=true -t mongo_purge

Important: Always use the -l <cluster> parameter to limit the execution scope and avoid accidentally removing other clusters.

This command will:

  • Stop the FerretDB service
  • Remove the systemd service file
  • Clean up configuration files and certificates
  • Deregister from Prometheus monitoring

Connect to FerretDB

You can access FerretDB using a MongoDB connection string with any language’s MongoDB driver. Here’s an example using the mongosh command-line tool:

mongosh 'mongodb://dbuser_meta:[email protected]:27017?authMechanism=PLAIN'
mongosh 'mongodb://test:[email protected]:27017/test?authMechanism=PLAIN'

Pigsty-managed PostgreSQL clusters use scram-sha-256 as the default authentication method, so you must use PLAIN authentication when connecting to FerretDB. See FerretDB: Authentication for details.

You can also use other PostgreSQL users to access FerretDB by specifying them in the connection string:

mongosh 'mongodb://dbuser_dba:[email protected]:27017?authMechanism=PLAIN'

Quick Start

After connecting to FerretDB, you can operate it just like MongoDB:

$ mongosh 'mongodb://dbuser_meta:[email protected]:27017?authMechanism=PLAIN'

MongoDB commands are translated to SQL commands and executed in the underlying PostgreSQL:

use test                            // CREATE SCHEMA test;
db.dropDatabase()                   // DROP SCHEMA test;
db.createCollection('posts')        // CREATE TABLE posts(_data JSONB,...)
db.posts.insert({                   // INSERT INTO posts VALUES(...);
    title: 'Post One',
    body: 'Body of post one',
    category: 'News',
    tags: ['news', 'events'],
    user: {name: 'John Doe', status: 'author'},
    date: Date()
})
db.posts.find().limit(2).pretty()   // SELECT * FROM posts LIMIT 2;
db.posts.createIndex({ title: 1 })  // CREATE INDEX ON posts(_data->>'title');

If you’re not familiar with MongoDB, here’s a quick start tutorial that also applies to FerretDB: Perform CRUD Operations with MongoDB Shell


Benchmark

If you want to generate some sample load, you can use mongosh to execute the following simple test script:

cat > benchmark.js <<'EOF'
const coll = "testColl";
const numDocs = 10000;

for (let i = 0; i < numDocs; i++) {  // insert
  db.getCollection(coll).insert({ num: i, name: "MongoDB Benchmark Test" });
}

for (let i = 0; i < numDocs; i++) {  // select
  db.getCollection(coll).find({ num: i });
}

for (let i = 0; i < numDocs; i++) {  // update
  db.getCollection(coll).update({ num: i }, { $set: { name: "Updated" } });
}

for (let i = 0; i < numDocs; i++) {  // delete
  db.getCollection(coll).deleteOne({ num: i });
}
EOF

mongosh 'mongodb://dbuser_meta:[email protected]:27017?authMechanism=PLAIN' benchmark.js

You can check the MongoDB commands supported by FerretDB, as well as some known differences. For basic usage, these differences usually aren’t a significant problem.

16.5 - Playbook

Ansible playbooks available for the FERRET module

Pigsty provides a built-in playbook mongo.yml for installing FerretDB on nodes.

Important: This playbook only executes on hosts where mongo_seq is defined. Running the playbook against hosts without mongo_seq will skip all tasks safely, making it safe to run against mixed host groups.


mongo.yml

Playbook location: mongo.yml

Function: Install MongoDB/FerretDB on target hosts where mongo_seq is defined.

This playbook contains the following subtasks:

SubtaskDescription
mongo_checkCheck mongo identity parameters
mongo_dbsuCreate OS user mongod
mongo_installInstall ferretdb RPM/DEB packages
mongo_purgePurge existing FerretDB (not by default)
mongo_configConfigure FerretDB service
mongo_certIssue FerretDB SSL certificates
mongo_launchLaunch FerretDB service
mongo_registerRegister FerretDB to Prometheus

Task Details

mongo_check

Check that required identity parameters are defined:

  • mongo_cluster: Cluster name
  • mongo_seq: Instance sequence number
  • mongo_pgurl: PostgreSQL connection string

If any parameter is missing, the playbook will exit with an error.

mongo_dbsu

Create OS user and group required for FerretDB:

  • Create mongod user group
  • Create mongod user with home directory /var/lib/mongod

mongo_install

Install FerretDB packages:

  • Install ferretdb2 package on RPM-based distributions
  • Install corresponding deb package on DEB-based distributions

mongo_purge

Purge existing FerretDB cluster. This task does not run by default and requires explicit specification:

./mongo.yml -l <cluster> -e mongo_purge=true -t mongo_purge

Important: Always use the -l <cluster> parameter to limit the execution scope.

Purge operations include:

  • Stop and disable ferretdb service
  • Remove systemd service file
  • Remove configuration files and SSL certificates
  • Deregister from Prometheus monitoring targets

mongo_config

Configure FerretDB service:

  • Render environment variable config file /etc/default/ferretdb
  • Create systemd service file

mongo_cert

When mongo_ssl_enabled is set to true, this task will:

  • Generate FerretDB SSL private key
  • Create Certificate Signing Request (CSR)
  • Issue SSL certificate using CA
  • Deploy certificate files to /var/lib/mongod/

mongo_launch

Launch FerretDB service:

  • Reload systemd configuration
  • Start and enable ferretdb service
  • Wait for service to be available on specified port (default 27017)

The FerretDB service is configured with Restart=on-failure, so it will automatically restart if the process crashes unexpectedly. This provides basic resilience for this stateless proxy service.

mongo_register

Register FerretDB instance to Prometheus monitoring system:

  • Create monitoring target file on all infra nodes
  • Target file path: /infra/targets/mongo/<cluster>-<seq>.yml
  • Contains instance IP, labels, and metrics port information

Usage Examples

# Deploy FerretDB on ferret group
./mongo.yml -l ferret

# Run config task only
./mongo.yml -l ferret -t mongo_config

# Reissue SSL certificates
./mongo.yml -l ferret -t mongo_cert

# Restart FerretDB service
./mongo.yml -l ferret -t mongo_launch

# Purge FerretDB cluster
./mongo.yml -l ferret -e mongo_purge=true -t mongo_purge

16.6 - Monitoring

Monitoring dashboards and alerting rules for the FerretDB module

The FERRET module currently provides one monitoring dashboard.


Mongo Overview

Mongo Overview: Mongo/FerretDB cluster overview

This dashboard provides basic monitoring metrics for FerretDB, including:

  • Instance status: Running state of FerretDB instances
  • Client connections: Client connection count and request statistics
  • Resource usage: CPU, memory, goroutine count, etc.
  • PostgreSQL connection pool: Backend PostgreSQL connection pool status

mongo-overview.jpg

Since FerretDB uses PostgreSQL as its underlying storage engine, for more monitoring metrics please refer to PostgreSQL Monitoring.


Metrics

FerretDB exposes Prometheus-format metrics through its built-in exporter on the mongo_exporter_port (default 9216) port.

Key metric categories include:

Metric PrefixDescription
ferretdb_*FerretDB core metrics
ferretdb_client_*Client connection and request stats
ferretdb_postgresql_*PostgreSQL backend status
go_*Go runtime metrics
process_*Process-level metrics

For the complete list of metrics, see Metrics.


Alerting Rules

The FerretDB module currently uses basic instance liveness alerts:

- alert: FerretDBDown
  expr: ferretdb_up == 0
  for: 1m
  labels:
    severity: critical
  annotations:
    summary: "FerretDB instance {{ $labels.ins }} is down"
    description: "FerretDB instance {{ $labels.ins }} on {{ $labels.ip }} has been down for more than 1 minute."

Since FerretDB is a stateless proxy layer, the primary monitoring and alerting should focus on the underlying PostgreSQL cluster.

16.7 - Metrics

Complete list of monitoring metrics provided by the FerretDB module

The MONGO module contains 54 available monitoring metrics.

Metric NameTypeLabelsDescription
ferretdb_client_accepts_totalUnknownerror, cls, ip, ins, instance, jobN/A
ferretdb_client_duration_seconds_bucketUnknownerror, le, cls, ip, ins, instance, jobN/A
ferretdb_client_duration_seconds_countUnknownerror, cls, ip, ins, instance, jobN/A
ferretdb_client_duration_seconds_sumUnknownerror, cls, ip, ins, instance, jobN/A
ferretdb_client_requests_totalUnknowncls, ip, ins, opcode, instance, command, jobN/A
ferretdb_client_responses_totalUnknownresult, argument, cls, ip, ins, opcode, instance, command, jobN/A
ferretdb_postgresql_metadata_databasesgaugecls, ip, ins, instance, jobThe current number of database in the registry.
ferretdb_postgresql_pool_sizegaugecls, ip, ins, instance, jobThe current number of pools.
ferretdb_upgaugecls, version, commit, ip, ins, dirty, telemetry, package, update_available, uuid, instance, job, branch, debugFerretDB instance state.
go_gc_duration_secondssummarycls, ip, ins, instance, quantile, jobA summary of the pause duration of garbage collection cycles.
go_gc_duration_seconds_countUnknowncls, ip, ins, instance, jobN/A
go_gc_duration_seconds_sumUnknowncls, ip, ins, instance, jobN/A
go_goroutinesgaugecls, ip, ins, instance, jobNumber of goroutines that currently exist.
go_infogaugecls, version, ip, ins, instance, jobInformation about the Go environment.
go_memstats_alloc_bytesgaugecls, ip, ins, instance, jobNumber of bytes allocated and still in use.
go_memstats_alloc_bytes_totalcountercls, ip, ins, instance, jobTotal number of bytes allocated, even if freed.
go_memstats_buck_hash_sys_bytesgaugecls, ip, ins, instance, jobNumber of bytes used by the profiling bucket hash table.
go_memstats_frees_totalcountercls, ip, ins, instance, jobTotal number of frees.
go_memstats_gc_sys_bytesgaugecls, ip, ins, instance, jobNumber of bytes used for garbage collection system metadata.
go_memstats_heap_alloc_bytesgaugecls, ip, ins, instance, jobNumber of heap bytes allocated and still in use.
go_memstats_heap_idle_bytesgaugecls, ip, ins, instance, jobNumber of heap bytes waiting to be used.
go_memstats_heap_inuse_bytesgaugecls, ip, ins, instance, jobNumber of heap bytes that are in use.
go_memstats_heap_objectsgaugecls, ip, ins, instance, jobNumber of allocated objects.
go_memstats_heap_released_bytesgaugecls, ip, ins, instance, jobNumber of heap bytes released to OS.
go_memstats_heap_sys_bytesgaugecls, ip, ins, instance, jobNumber of heap bytes obtained from system.
go_memstats_last_gc_time_secondsgaugecls, ip, ins, instance, jobNumber of seconds since 1970 of last garbage collection.
go_memstats_lookups_totalcountercls, ip, ins, instance, jobTotal number of pointer lookups.
go_memstats_mallocs_totalcountercls, ip, ins, instance, jobTotal number of mallocs.
go_memstats_mcache_inuse_bytesgaugecls, ip, ins, instance, jobNumber of bytes in use by mcache structures.
go_memstats_mcache_sys_bytesgaugecls, ip, ins, instance, jobNumber of bytes used for mcache structures obtained from system.
go_memstats_mspan_inuse_bytesgaugecls, ip, ins, instance, jobNumber of bytes in use by mspan structures.
go_memstats_mspan_sys_bytesgaugecls, ip, ins, instance, jobNumber of bytes used for mspan structures obtained from system.
go_memstats_next_gc_bytesgaugecls, ip, ins, instance, jobNumber of heap bytes when next garbage collection will take place.
go_memstats_other_sys_bytesgaugecls, ip, ins, instance, jobNumber of bytes used for other system allocations.
go_memstats_stack_inuse_bytesgaugecls, ip, ins, instance, jobNumber of bytes in use by the stack allocator.
go_memstats_stack_sys_bytesgaugecls, ip, ins, instance, jobNumber of bytes obtained from system for stack allocator.
go_memstats_sys_bytesgaugecls, ip, ins, instance, jobNumber of bytes obtained from system.
go_threadsgaugecls, ip, ins, instance, jobNumber of OS threads created.
mongo_upUnknowncls, ip, ins, instance, jobN/A
process_cpu_seconds_totalcountercls, ip, ins, instance, jobTotal user and system CPU time spent in seconds.
process_max_fdsgaugecls, ip, ins, instance, jobMaximum number of open file descriptors.
process_open_fdsgaugecls, ip, ins, instance, jobNumber of open file descriptors.
process_resident_memory_bytesgaugecls, ip, ins, instance, jobResident memory size in bytes.
process_start_time_secondsgaugecls, ip, ins, instance, jobStart time of the process since unix epoch in seconds.
process_virtual_memory_bytesgaugecls, ip, ins, instance, jobVirtual memory size in bytes.
process_virtual_memory_max_bytesgaugecls, ip, ins, instance, jobMaximum amount of virtual memory available in bytes.
promhttp_metric_handler_errors_totalcounterjob, cls, ip, ins, instance, causeTotal number of internal errors encountered by the promhttp metric handler.
promhttp_metric_handler_requests_in_flightgaugecls, ip, ins, instance, jobCurrent number of scrapes being served.
promhttp_metric_handler_requests_totalcounterjob, cls, ip, ins, instance, codeTotal number of scrapes by HTTP status code.
scrape_duration_secondsUnknowncls, ip, ins, instance, jobN/A
scrape_samples_post_metric_relabelingUnknowncls, ip, ins, instance, jobN/A
scrape_samples_scrapedUnknowncls, ip, ins, instance, jobN/A
scrape_series_addedUnknowncls, ip, ins, instance, jobN/A
upUnknowncls, ip, ins, instance, jobN/A

16.8 - FAQ

Frequently asked questions about FerretDB and DocumentDB modules

Why Use FerretDB?

MongoDB was an amazing technology that allowed developers to escape the “schema constraints” of relational databases and rapidly build applications. However, over time, MongoDB abandoned its open-source roots and changed its license to SSPL, making it unusable for many open-source projects and early-stage commercial ventures. Most MongoDB users don’t actually need the advanced features MongoDB offers, but they do need an easy-to-use open-source document database solution. To fill this gap, FerretDB was born.

PostgreSQL’s JSON support is already quite comprehensive: binary JSONB storage, GIN indexes for arbitrary fields, various JSON processing functions, JSON PATH and JSON Schema—it has long been a fully-featured, high-performance document database. But providing alternative functionality is not the same as direct emulation. FerretDB can provide a smooth migration path to PostgreSQL for applications using MongoDB drivers.


Pigsty’s FerretDB Support History

Pigsty has provided Docker-based FerretDB templates since 1.x and added native deployment support in v2.3. As an optional component, it greatly enriches the PostgreSQL ecosystem. The Pigsty community has become a partner of the FerretDB community, and deeper collaboration and integration support will follow.

FERRET is an optional module in Pigsty. Since v2.0, it requires the documentdb extension to work. Pigsty has packaged this extension and provides a mongo.yml template to help you easily deploy FerretDB clusters.


Installing MongoSH

You can use MongoSH as a client tool to access FerretDB clusters.

The recommended approach is to use the pig command to add the MongoDB repository and install:

pig repo add mongo -u   # Add the official MongoDB repository
yum install mongodb-mongosh   # RHEL/CentOS/Rocky/Alma
apt install mongodb-mongosh   # Debian/Ubuntu

You can also manually add the MongoDB repository:

# RHEL/CentOS family
cat > /etc/yum.repos.d/mongo.repo <<EOF
[mongodb-org-7.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/\$releasever/mongodb-org/7.0/\$basearch/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-7.0.asc
EOF
yum install -y mongodb-mongosh

Authentication Method

FerretDB authentication is entirely based on the underlying PostgreSQL. Since Pigsty-managed PostgreSQL clusters use scram-sha-256 authentication by default, you must specify the PLAIN authentication mechanism in the connection string:

mongosh 'mongodb://user:password@host:27017?authMechanism=PLAIN'

If you forget to add the authMechanism=PLAIN parameter, the connection will fail with an authentication error.


Compatibility with MongoDB

FerretDB implements MongoDB’s wire protocol but uses PostgreSQL for underlying storage. This means:

  • Most basic CRUD operations are compatible with MongoDB
  • Some advanced features may not be supported or may differ
  • Aggregation pipeline support is limited

For detailed compatibility information, see:


Why Is a Superuser Required?

FerretDB 2.0+ uses the documentdb extension, which requires superuser privileges to create and manage internal structures. Therefore, the user specified in mongo_pgurl must be a PostgreSQL superuser.

It’s recommended to create a dedicated mongod superuser for FerretDB to use, rather than using the default postgres user.


How to Achieve High Availability

FerretDB itself is stateless—all data is stored in the underlying PostgreSQL. To achieve high availability:

  1. PostgreSQL layer: Use Pigsty’s PGSQL module to deploy a highly available PostgreSQL cluster
  2. FerretDB layer: Deploy multiple FerretDB instances with a VIP or load balancer

For detailed configuration, see High Availability Configuration.


Performance Considerations

FerretDB’s performance depends on the underlying PostgreSQL cluster. Since MongoDB commands need to be translated to SQL, there is some performance overhead. For most OLTP scenarios, the performance is acceptable.

If you need higher performance, you can:

  • Use faster storage (NVMe SSD)
  • Increase PostgreSQL resource allocation
  • Optimize PostgreSQL parameters
  • Use connection pooling to reduce connection overhead

17 - Module: DOCKER

Docker daemon service that enables one-click deployment of containerized stateless software templates and additional functionality.

Docker is the most popular containerization platform, providing standardized software delivery capabilities.

Pigsty does not rely on Docker to deploy any of its components; instead, it provides the ability to deploy and install Docker — this is an optional module.

Pigsty offers a series of Docker software/tool/application templates for you to choose from as needed. This allows users to quickly spin up various containerized stateless software templates, adding extra functionality. You can use external, Pigsty-managed highly available database clusters while placing stateless applications inside containers.

Pigsty’s Docker module automatically configures accessible registry mirrors for users in mainland China to improve image pulling speed (and availability). You can easily configure Registry and Proxy settings to flexibly access different image sources.

17.1 - Usage

Docker module quick start guide - installation, removal, download, repository, mirrors, proxy, and image pulling.

Pigsty has built-in Docker support, which you can use to quickly deploy containerized applications.


Getting Started

Docker is an optional module, and in most of Pigsty’s configuration templates, Docker is not enabled by default. Therefore, users need to explicitly download and configure it to use Docker in Pigsty.

For example, in the default meta template, Docker is not downloaded or installed by default. However, in the rich single-node template, Docker is downloaded and installed.

The key difference between these two configurations lies in these two parameters: repo_modules and repo_packages.

repo_modules: infra,node,pgsql,docker  # <--- Enable Docker repository
repo_packages:
  - node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-common, docker   # <--- Download Docker

After Docker is downloaded, you need to set the docker_enabled: true flag on the nodes where you want to install Docker, and configure other parameters as needed.

infra:
  hosts:
    10.10.10.10: { infra_seq: 1 ,nodename: infra-1 }
    10.10.10.11: { infra_seq: 2 ,nodename: infra-2 }
  vars:
    docker_enabled: true  # Install Docker on this group!

Finally, use the docker.yml playbook to install it on the nodes:

./docker.yml -l infra    # Install Docker on the infra group

Installation

If you want to temporarily install Docker directly from the internet on certain nodes, you can use the following command:

./node.yml -e '{"node_repo_modules":"node,docker","node_packages":["docker-ce,docker-compose-plugin"]}' -t node_repo,node_pkg -l <select_group_ip>

This command will first enable the upstream software sources for the node,docker modules on the target nodes, then install the docker-ce and docker-compose-plugin packages (same package names for EL/Debian).

If you want Docker-related packages to be automatically downloaded during Pigsty initialization, refer to the instructions below.


Removal

Because it’s so simple, Pigsty doesn’t provide an uninstall playbook for the Docker module. You can directly remove Docker using an Ansible command:

ansible minio -m package -b -a 'name=docker-ce state=absent'  # Remove docker

This command will uninstall the docker-ce package using the OS package manager.


Download

To download Docker during Pigsty installation, modify the repo_modules parameter in the configuration inventory to enable the Docker software repository, then specify Docker packages to download in the repo_packages or repo_extra_packages parameters.

repo_modules: infra,node,pgsql,docker  # <--- Enable Docker repository
repo_packages:
  - node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-common, docker   # <--- Download Docker
repo_extra_packages:
  - pgsql-main docker # <--- Can also be specified here

The docker specified here (which actually corresponds to the docker-ce and docker-compose-plugin packages) will be automatically downloaded to the local repository during the default install.yml process. After downloading, the Docker packages will be available to all nodes via the local repository.

If you’ve already completed Pigsty installation and the local repository is initialized, you can run ./infra.yml -t repo_build after modifying the configuration to re-download and rebuild the offline repository.

Installing Docker requires the Docker YUM/APT repository, which is included by default in Pigsty but not enabled. You need to add docker to repo_modules to enable it before installation.


Repository

Downloading Docker requires upstream internet software repositories, which are defined in the default repo_upstream with module name docker:

- { name: docker-ce ,description: 'Docker CE' ,module: docker  ,releases: [7,8,9] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.docker.com/linux/centos/$releasever/$basearch/stable'    ,china: 'https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/$basearch/stable'  ,europe: 'https://mirrors.xtom.de/docker-ce/linux/centos/$releasever/$basearch/stable' }}
- { name: docker-ce ,description: 'Docker CE' ,module: docker  ,releases: [11,12,20,22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.docker.com/linux/${distro_name} ${distro_codename} stable' ,china: 'https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux//${distro_name} ${distro_codename} stable' }}

You can reference this repository using the docker module name in the repo_modules and node_repo_modules parameters.

Note that Docker’s official software repository is blocked by default in mainland China. You need to use mirror sites in China to complete the download.

If you’re in mainland China and encounter Docker download failures, check whether region is set to default in your configuration inventory. The automatically configured region: china can resolve this issue.


Proxy

If your network environment requires a proxy server to access the internet, you can configure the proxy_env parameter in Pigsty’s configuration inventory. This parameter will be written to the proxy related configuration in Docker’s configuration file.

proxy_env:
  no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.aliyuncs.com,mirrors.tuna.tsinghua.edu.cn,mirrors.zju.edu.cn"
  #http_proxy: 'http://username:[email protected]'
  #https_proxy: 'http://username:[email protected]'
  #all_proxy: 'http://username:[email protected]'

When running configure with the -x parameter, the proxy server configuration from your current environment will be automatically generated into Pigsty’s configuration file under proxy_env.

In addition to using a proxy server, you can also configure Docker Registry Mirrors to bypass blocks.


Registry Mirrors

You can use the docker_registry_mirrors parameter to specify Docker Registry Mirrors:

For users outside the firewall, in addition to the official DockerHub site, you can also consider using the quay.io mirror site. If your internal network environment already has mature image infrastructure, you can use your internal Docker registry mirrors to avoid being affected by external mirror sites and improve download speeds.

Users of public cloud providers can consider using free internal Docker mirrors. For example, if you’re using Alibaba Cloud, you can use Alibaba Cloud’s internal Docker mirror site (requires login):

["https://registry.cn-hangzhou.aliyuncs.com"]   # Alibaba Cloud mirror, requires explicit login

If you’re using Tencent Cloud, you can use Tencent Cloud’s internal Docker mirror site (requires internal network):

["https://ccr.ccs.tencentyun.com"]   # Tencent Cloud mirror, internal network only

Additionally, you can use CF-Workers-docker.io to quickly set up your own Docker image proxy. You can also consider using free Docker proxy mirrors (use at your own risk!)


Pulling Images

The docker_image and docker_image_cache parameters can be used to directly specify a list of images to pull during Docker installation.

Using this feature, Docker will come with the specified images after installation (provided they can be successfully pulled; this task will be automatically ignored and skipped on failure).

For example, you can specify images to pull in the configuration inventory:

infra:
  hosts:
    10.10.10.10: { infra_seq: 1 }
  vars:
    docker_enabled: true  # Install Docker on this group!
    docker_image:
      - redis:latest      # Pull the latest Redis image

Another way to preload images is to use locally saved tgz archives: if you’ve previously exported Docker images using docker save xxx | gzip -c > /tmp/docker/xxx.tgz. These exported image files can be automatically loaded via the glob specified by the docker_image_cache parameter. The default location is: /tmp/docker/*.tgz.

This means you can place images in the /tmp/docker directory beforehand, and after running docker.yml to install Docker, these image packages will be automatically loaded.

For example, in the self-hosted Supabase tutorial, this technique is used. Before spinning up Supabase and installing Docker, the *.tgz image archives from the local /tmp/supabase directory are copied to the target node’s /tmp/docker directory.

- name: copy local docker images
  copy: src="{{ item }}" dest="/tmp/docker/"
  with_fileglob: "{{ supa_images }}"
  vars: # you can override this with -e cli args
    supa_images: /tmp/supabase/*.tgz

Applications

Pigsty provides a series of ready-to-use, Docker Compose-based software templates, which you can use to spin up business software that uses external Pigsty-managed database clusters.




17.2 - Parameters

DOCKER module provides 8 configuration parameters

The DOCKER module provides 8 configuration parameters.

Parameter Overview

The DOCKER parameter group is used for Docker container engine deployment and configuration, including enable switch, data directory, storage driver, registry mirrors, and monitoring.

ParameterTypeLevelDescription
docker_enabledboolG/C/IEnable Docker on current node? disabled by default
docker_datapathG/C/IDocker data directory, /data/docker by default
docker_storage_driverenumG/C/IDocker storage driver, overlay2 by default
docker_cgroups_driverenumG/C/IDocker cgroup driver: cgroupfs or systemd
docker_registry_mirrorsstring[]G/C/IDocker registry mirror list
docker_exporter_portportGDocker metrics exporter port, 9323 by default
docker_imagestring[]G/C/IDocker images to pull, empty list by default
docker_image_cachepathG/C/IDocker image cache tarball path, /tmp/docker/*.tgz

You can use the docker.yml playbook to install and enable Docker on nodes.

Default parameters are defined in roles/docker/defaults/main.yml

docker_enabled: false             # Enable Docker on current node?
docker_data: /data/docker         # Docker data directory, /data/docker by default
docker_storage_driver: overlay2   # Docker storage driver, overlay2/zfs/btrfs...
docker_cgroups_driver: systemd    # Docker cgroup driver: cgroupfs or systemd
docker_registry_mirrors: []       # Docker registry mirror list
docker_exporter_port: 9323        # Docker metrics exporter port, 9323 by default
docker_image: []                  # Docker images to pull after startup
docker_image_cache: /tmp/docker/*.tgz # Docker image cache tarball glob pattern

docker_enabled

Parameter: docker_enabled, Type: bool, Level: G/C/I

Enable Docker on current node? Default: false, meaning Docker is not enabled.

docker_data

Parameter: docker_data, Type: path, Level: G/C/I

Docker data directory, default is /data/docker.

This directory stores Docker images, containers, volumes, and other data. If you have a dedicated data disk, it’s recommended to point this directory to that disk’s mount point.

docker_storage_driver

Parameter: docker_storage_driver, Type: enum, Level: G/C/I

Docker storage driver, default is overlay2.

See official documentation: https://docs.docker.com/engine/storage/drivers/select-storage-driver/

Available storage drivers include:

  • overlay2: Recommended default driver, suitable for most scenarios
  • fuse-overlayfs: For rootless container scenarios
  • btrfs: When using Btrfs filesystem
  • zfs: When using ZFS filesystem
  • vfs: For testing purposes, not recommended for production

docker_cgroups_driver

Parameter: docker_cgroups_driver, Type: enum, Level: G/C/I

Docker cgroup filesystem driver, can be cgroupfs or systemd, default: systemd

docker_registry_mirrors

Parameter: docker_registry_mirrors, Type: string[], Level: G/C/I

Docker registry mirror list, default: [] empty array.

You can use Docker mirror sites to accelerate image pulls. Here are some examples:

["https://docker.m.daocloud.io"]                # DaoCloud mirror
["https://docker.1ms.run"]                      # 1ms mirror
["https://mirror.ccs.tencentyun.com"]           # Tencent Cloud internal mirror
["https://registry.cn-hangzhou.aliyuncs.com"]   # Alibaba Cloud mirror (requires login)

You can also consider using a Cloudflare Worker to set up a Docker Proxy for faster access.

If pull speeds are still too slow, consider using alternative registries: docker login quay.io

docker_exporter_port

Parameter: docker_exporter_port, Type: port, Level: G

Docker metrics exporter port, default is 9323.

The Docker daemon exposes Prometheus-format monitoring metrics on this port for collection by monitoring infrastructure.

docker_image

Parameter: docker_image, Type: string[], Level: G/C/I

List of Docker images to pull, default is empty list [].

Docker image names specified here will be automatically pulled during the installation phase.

docker_image_cache

Parameter: docker_image_cache, Type: path, Level: G/C/I

Local Docker image cache tarball glob pattern, default is /tmp/docker/*.tgz.

You can use docker save | gzip to package images and automatically import them during Docker installation via this parameter.

.tgz tarball files matching this pattern will be imported into Docker one by one using:

cat *.tgz | gzip -d -c - | docker load

17.3 - Playbooks

How to use the built-in Ansible playbook to manage Docker and quick reference for common management commands.

The Docker module provides a default playbook docker.yml for installing Docker Daemon and Docker Compose.


docker.yml

Playbook source file: docker.yml

Running this playbook will install docker-ce and docker-compose-plugin on target nodes with the docker_enabled: true flag, and enable the dockerd service.

The following are the available task subsets in the docker.yml playbook:

  • docker_install : Install Docker and Docker Compose packages on the node
  • docker_admin : Add specified users to the Docker admin user group
  • docker_alias : Generate Docker command completion and alias scripts
  • docker_dir : Create Docker related directories
  • docker_config : Generate Docker daemon service configuration file
  • docker_launch : Start the Docker daemon service
  • docker_register : Register Docker daemon as a Prometheus monitoring target
  • docker_image : Attempt to load pre-cached image tarballs from /tmp/docker/*.tgz (if they exist)

The Docker module does not provide a dedicated uninstall playbook. If you need to uninstall Docker, you can manually stop Docker and then remove it:

systemctl stop docker                        # Stop Docker daemon service
yum remove docker-ce docker-compose-plugin   # Uninstall Docker on EL systems
apt remove docker-ce docker-compose-plugin   # Uninstall Docker on Debian systems



17.4 - Metrics

Complete list of monitoring metrics provided by the Pigsty Docker module

The DOCKER module contains 123 available monitoring metrics.

Metric NameTypeLabelsDescription
builder_builds_failed_totalcounterip, cls, reason, ins, job, instanceNumber of failed image builds
builder_builds_triggered_totalcounterip, cls, ins, job, instanceNumber of triggered image builds
docker_upUnknownip, cls, ins, job, instanceN/A
engine_daemon_container_actions_seconds_bucketUnknownip, cls, ins, job, instance, le, actionN/A
engine_daemon_container_actions_seconds_countUnknownip, cls, ins, job, instance, actionN/A
engine_daemon_container_actions_seconds_sumUnknownip, cls, ins, job, instance, actionN/A
engine_daemon_container_states_containersgaugeip, cls, ins, job, instance, stateThe count of containers in various states
engine_daemon_engine_cpus_cpusgaugeip, cls, ins, job, instanceThe number of cpus that the host system of the engine has
engine_daemon_engine_infogaugeip, cls, architecture, ins, job, instance, os_version, kernel, version, graphdriver, os, daemon_id, commit, os_typeThe information related to the engine and the OS it is running on
engine_daemon_engine_memory_bytesgaugeip, cls, ins, job, instanceThe number of bytes of memory that the host system of the engine has
engine_daemon_events_subscribers_totalgaugeip, cls, ins, job, instanceThe number of current subscribers to events
engine_daemon_events_totalcounterip, cls, ins, job, instanceThe number of events logged
engine_daemon_health_checks_failed_totalcounterip, cls, ins, job, instanceThe total number of failed health checks
engine_daemon_health_check_start_duration_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
engine_daemon_health_check_start_duration_seconds_countUnknownip, cls, ins, job, instanceN/A
engine_daemon_health_check_start_duration_seconds_sumUnknownip, cls, ins, job, instanceN/A
engine_daemon_health_checks_totalcounterip, cls, ins, job, instanceThe total number of health checks
engine_daemon_host_info_functions_seconds_bucketUnknownip, cls, ins, job, instance, le, functionN/A
engine_daemon_host_info_functions_seconds_countUnknownip, cls, ins, job, instance, functionN/A
engine_daemon_host_info_functions_seconds_sumUnknownip, cls, ins, job, instance, functionN/A
engine_daemon_image_actions_seconds_bucketUnknownip, cls, ins, job, instance, le, actionN/A
engine_daemon_image_actions_seconds_countUnknownip, cls, ins, job, instance, actionN/A
engine_daemon_image_actions_seconds_sumUnknownip, cls, ins, job, instance, actionN/A
engine_daemon_network_actions_seconds_bucketUnknownip, cls, ins, job, instance, le, actionN/A
engine_daemon_network_actions_seconds_countUnknownip, cls, ins, job, instance, actionN/A
engine_daemon_network_actions_seconds_sumUnknownip, cls, ins, job, instance, actionN/A
etcd_debugging_snap_save_marshalling_duration_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
etcd_debugging_snap_save_marshalling_duration_seconds_countUnknownip, cls, ins, job, instanceN/A
etcd_debugging_snap_save_marshalling_duration_seconds_sumUnknownip, cls, ins, job, instanceN/A
etcd_debugging_snap_save_total_duration_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
etcd_debugging_snap_save_total_duration_seconds_countUnknownip, cls, ins, job, instanceN/A
etcd_debugging_snap_save_total_duration_seconds_sumUnknownip, cls, ins, job, instanceN/A
etcd_disk_wal_fsync_duration_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
etcd_disk_wal_fsync_duration_seconds_countUnknownip, cls, ins, job, instanceN/A
etcd_disk_wal_fsync_duration_seconds_sumUnknownip, cls, ins, job, instanceN/A
etcd_disk_wal_write_bytes_totalgaugeip, cls, ins, job, instanceTotal number of bytes written in WAL.
etcd_snap_db_fsync_duration_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
etcd_snap_db_fsync_duration_seconds_countUnknownip, cls, ins, job, instanceN/A
etcd_snap_db_fsync_duration_seconds_sumUnknownip, cls, ins, job, instanceN/A
etcd_snap_db_save_total_duration_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
etcd_snap_db_save_total_duration_seconds_countUnknownip, cls, ins, job, instanceN/A
etcd_snap_db_save_total_duration_seconds_sumUnknownip, cls, ins, job, instanceN/A
etcd_snap_fsync_duration_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
etcd_snap_fsync_duration_seconds_countUnknownip, cls, ins, job, instanceN/A
etcd_snap_fsync_duration_seconds_sumUnknownip, cls, ins, job, instanceN/A
go_gc_duration_secondssummaryip, cls, ins, job, instance, quantileA summary of the pause duration of garbage collection cycles.
go_gc_duration_seconds_countUnknownip, cls, ins, job, instanceN/A
go_gc_duration_seconds_sumUnknownip, cls, ins, job, instanceN/A
go_goroutinesgaugeip, cls, ins, job, instanceNumber of goroutines that currently exist.
go_infogaugeip, cls, ins, job, version, instanceInformation about the Go environment.
go_memstats_alloc_bytescounterip, cls, ins, job, instanceTotal number of bytes allocated, even if freed.
go_memstats_alloc_bytes_totalcounterip, cls, ins, job, instanceTotal number of bytes allocated, even if freed.
go_memstats_buck_hash_sys_bytesgaugeip, cls, ins, job, instanceNumber of bytes used by the profiling bucket hash table.
go_memstats_frees_totalcounterip, cls, ins, job, instanceTotal number of frees.
go_memstats_gc_sys_bytesgaugeip, cls, ins, job, instanceNumber of bytes used for garbage collection system metadata.
go_memstats_heap_alloc_bytesgaugeip, cls, ins, job, instanceNumber of heap bytes allocated and still in use.
go_memstats_heap_idle_bytesgaugeip, cls, ins, job, instanceNumber of heap bytes waiting to be used.
go_memstats_heap_inuse_bytesgaugeip, cls, ins, job, instanceNumber of heap bytes that are in use.
go_memstats_heap_objectsgaugeip, cls, ins, job, instanceNumber of allocated objects.
go_memstats_heap_released_bytesgaugeip, cls, ins, job, instanceNumber of heap bytes released to OS.
go_memstats_heap_sys_bytesgaugeip, cls, ins, job, instanceNumber of heap bytes obtained from system.
go_memstats_last_gc_time_secondsgaugeip, cls, ins, job, instanceNumber of seconds since 1970 of last garbage collection.
go_memstats_lookups_totalcounterip, cls, ins, job, instanceTotal number of pointer lookups.
go_memstats_mallocs_totalcounterip, cls, ins, job, instanceTotal number of mallocs.
go_memstats_mcache_inuse_bytesgaugeip, cls, ins, job, instanceNumber of bytes in use by mcache structures.
go_memstats_mcache_sys_bytesgaugeip, cls, ins, job, instanceNumber of bytes used for mcache structures obtained from system.
go_memstats_mspan_inuse_bytesgaugeip, cls, ins, job, instanceNumber of bytes in use by mspan structures.
go_memstats_mspan_sys_bytesgaugeip, cls, ins, job, instanceNumber of bytes used for mspan structures obtained from system.
go_memstats_next_gc_bytesgaugeip, cls, ins, job, instanceNumber of heap bytes when next garbage collection will take place.
go_memstats_other_sys_bytesgaugeip, cls, ins, job, instanceNumber of bytes used for other system allocations.
go_memstats_stack_inuse_bytesgaugeip, cls, ins, job, instanceNumber of bytes in use by the stack allocator.
go_memstats_stack_sys_bytesgaugeip, cls, ins, job, instanceNumber of bytes obtained from system for stack allocator.
go_memstats_sys_bytesgaugeip, cls, ins, job, instanceNumber of bytes obtained from system.
go_threadsgaugeip, cls, ins, job, instanceNumber of OS threads created.
logger_log_entries_size_greater_than_buffer_totalcounterip, cls, ins, job, instanceNumber of log entries which are larger than the log buffer
logger_log_read_operations_failed_totalcounterip, cls, ins, job, instanceNumber of log reads from container stdio that failed
logger_log_write_operations_failed_totalcounterip, cls, ins, job, instanceNumber of log write operations that failed
process_cpu_seconds_totalcounterip, cls, ins, job, instanceTotal user and system CPU time spent in seconds.
process_max_fdsgaugeip, cls, ins, job, instanceMaximum number of open file descriptors.
process_open_fdsgaugeip, cls, ins, job, instanceNumber of open file descriptors.
process_resident_memory_bytesgaugeip, cls, ins, job, instanceResident memory size in bytes.
process_start_time_secondsgaugeip, cls, ins, job, instanceStart time of the process since unix epoch in seconds.
process_virtual_memory_bytesgaugeip, cls, ins, job, instanceVirtual memory size in bytes.
process_virtual_memory_max_bytesgaugeip, cls, ins, job, instanceMaximum amount of virtual memory available in bytes.
promhttp_metric_handler_requests_in_flightgaugeip, cls, ins, job, instanceCurrent number of scrapes being served.
promhttp_metric_handler_requests_totalcounterip, cls, ins, job, instance, codeTotal number of scrapes by HTTP status code.
scrape_duration_secondsUnknownip, cls, ins, job, instanceN/A
scrape_samples_post_metric_relabelingUnknownip, cls, ins, job, instanceN/A
scrape_samples_scrapedUnknownip, cls, ins, job, instanceN/A
scrape_series_addedUnknownip, cls, ins, job, instanceN/A
swarm_dispatcher_scheduling_delay_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
swarm_dispatcher_scheduling_delay_seconds_countUnknownip, cls, ins, job, instanceN/A
swarm_dispatcher_scheduling_delay_seconds_sumUnknownip, cls, ins, job, instanceN/A
swarm_manager_configs_totalgaugeip, cls, ins, job, instanceThe number of configs in the cluster object store
swarm_manager_leadergaugeip, cls, ins, job, instanceIndicates if this manager node is a leader
swarm_manager_networks_totalgaugeip, cls, ins, job, instanceThe number of networks in the cluster object store
swarm_manager_nodesgaugeip, cls, ins, job, instance, stateThe number of nodes
swarm_manager_secrets_totalgaugeip, cls, ins, job, instanceThe number of secrets in the cluster object store
swarm_manager_services_totalgaugeip, cls, ins, job, instanceThe number of services in the cluster object store
swarm_manager_tasks_totalgaugeip, cls, ins, job, instance, stateThe number of tasks in the cluster object store
swarm_node_managergaugeip, cls, ins, job, instanceWhether this node is a manager or not
swarm_raft_snapshot_latency_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
swarm_raft_snapshot_latency_seconds_countUnknownip, cls, ins, job, instanceN/A
swarm_raft_snapshot_latency_seconds_sumUnknownip, cls, ins, job, instanceN/A
swarm_raft_transaction_latency_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
swarm_raft_transaction_latency_seconds_countUnknownip, cls, ins, job, instanceN/A
swarm_raft_transaction_latency_seconds_sumUnknownip, cls, ins, job, instanceN/A
swarm_store_batch_latency_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
swarm_store_batch_latency_seconds_countUnknownip, cls, ins, job, instanceN/A
swarm_store_batch_latency_seconds_sumUnknownip, cls, ins, job, instanceN/A
swarm_store_lookup_latency_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
swarm_store_lookup_latency_seconds_countUnknownip, cls, ins, job, instanceN/A
swarm_store_lookup_latency_seconds_sumUnknownip, cls, ins, job, instanceN/A
swarm_store_memory_store_lock_duration_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
swarm_store_memory_store_lock_duration_seconds_countUnknownip, cls, ins, job, instanceN/A
swarm_store_memory_store_lock_duration_seconds_sumUnknownip, cls, ins, job, instanceN/A
swarm_store_read_tx_latency_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
swarm_store_read_tx_latency_seconds_countUnknownip, cls, ins, job, instanceN/A
swarm_store_read_tx_latency_seconds_sumUnknownip, cls, ins, job, instanceN/A
swarm_store_write_tx_latency_seconds_bucketUnknownip, cls, ins, job, instance, leN/A
swarm_store_write_tx_latency_seconds_countUnknownip, cls, ins, job, instanceN/A
swarm_store_write_tx_latency_seconds_sumUnknownip, cls, ins, job, instanceN/A
upUnknownip, cls, ins, job, instanceN/A

17.5 - FAQ

Frequently asked questions about the Pigsty Docker module

Who Can Run Docker Commands?

By default, Pigsty adds both the management user running the playbook on the remote node (i.e., the SSH login user on the target node) and the admin user specified in the node_admin_username parameter to the Docker operating system group. All users in this group (docker) can manage Docker using the docker CLI command.

If you want other users to be able to run Docker commands, add that OS user to the docker group:

usermod -aG docker <username>

Working Through a Proxy

During Docker installation, if the proxy_env parameter exists, the HTTP proxy server configuration will be written to the /etc/docker/daemon.json configuration file.

Docker will use this proxy server when pulling images from upstream registries.

Tip: Running configure with the -x flag will write the proxy server configuration from your current environment into proxy_env.


Using Mirror Registries

If you’re in mainland China and affected by the Great Firewall, you can consider using Docker mirror sites available within China, such as quay.io:

docker login quay.io    # Enter username and password to log in

Update (June 2024): All previously accessible Docker mirror sites in China have been blocked. Please use a proxy server to access and pull images.


Adding Docker to Monitoring

During Docker module installation, you can register Docker as a monitoring target by running the docker_register or register_prometheus subtask for specific nodes:

./docker.yml -l <your-node-selector> -t register_prometheus

Using Software Templates

Pigsty provides a collection of software templates that can be launched using Docker Compose, ready to use out of the box.

But you need to install the Docker module first.

18 - Module: PILOT

Extra modules in pilot development.

18.1 - Module: MySQL

Deploy a MySQL 8.0 cluster with Pigsty for demonstration or benchmarking purposes.

MySQL used to be the “most popular open-source relational database in the world”.

Installation | Configuration | Administration | Playbook | Monitoring | Parameters


Overview

MySQL module is currently available in Pigsty Pro as a Beta Preview. Note that you should NOT use this MySQL deployment for production environments.


Installation

You can install MySQL 8.0 from the official software source on EL systems directly on the nodes managed by Pigsty.

# el 7,8,9
./node.yml -t node_install -e '{"node_repo_modules":"node,mysql","node_packages":["mysql-community-server,mysql-community-client"]}'

# debian / ubuntu
./node.yml -t node_install -e '{"node_repo_modules":"node,mysql","node_packages":["mysql-server"]}'

You can also add the MySQL package to the local repo and use the playbook mysql.yml for production deployment.


Configuration

This config snippet defines a single-node MySQL instance, along with its Databases and Users.

my-test:
  hosts: { 10.10.10.10: { mysql_seq: 1, mysql_role: primary } }
  vars:
    mysql_cluster: my-test
    mysql_databases:
      - { name: meta }
    mysql_users:
      - { name: dbuser_meta    ,host: '%' ,password: 'dbuesr_meta'    ,priv: { "*.*": "SELECT, UPDATE, DELETE, INSERT" } }
      - { name: dbuser_dba     ,host: '%' ,password: 'DBUser.DBA'     ,priv: { "*.*": "ALL PRIVILEGES" } }
      - { name: dbuser_monitor ,host: '%' ,password: 'DBUser.Monitor' ,priv: { "*.*": "SELECT, PROCESS, REPLICATION CLIENT" } ,connlimit: 3 }

Administration

Here are some basic MySQL cluster management operations:

Create MySQL cluster with mysql.yml:

./mysql.yml -l my-test

Playbook

Pigsty has the following playbooks related to the MYSQL module:

  • mysql.yml: Deploy MySQL according to the inventory

mysql.yml

The playbook mysql.yml contains the following subtasks:

mysql-id       : generate mysql instance identity
mysql_clean    : remove existing mysql instance (DANGEROUS)
mysql_dbsu     : create os user mysql
mysql_install  : install mysql rpm/deb packages
mysql_dir      : create mysql data & conf dir
mysql_config   : generate mysql config file
mysql_boot     : bootstrap mysql cluster
mysql_launch   : launch mysql service
mysql_pass     : write mysql password
mysql_db       : create mysql biz database
mysql_user     : create mysql biz user
mysql_exporter : launch mysql exporter
mysql_register : register mysql service to prometheus

Monitoring

Pigsty has two built-in MYSQL dashboards:

MYSQL Overview: MySQL cluster overview

MYSQL Instance: MySQL instance overview


Parameters

MySQL’s available parameters:

#-----------------------------------------------------------------
# MYSQL_IDENTITY
#-----------------------------------------------------------------
# mysql_cluster:           #CLUSTER  # mysql cluster name, required identity parameter
# mysql_role: replica      #INSTANCE # mysql role, required, could be primary,replica
# mysql_seq: 0             #INSTANCE # mysql instance seq number, required identity parameter

#-----------------------------------------------------------------
# MYSQL_BUSINESS
#-----------------------------------------------------------------
# mysql business object definition, overwrite in group vars
mysql_users: []                      # mysql business users
mysql_databases: []                  # mysql business databases
mysql_services: []                   # mysql business services

# global credentials, overwrite in global vars
mysql_root_username: root
mysql_root_password: DBUser.Root
mysql_replication_username: replicator
mysql_replication_password: DBUser.Replicator
mysql_admin_username: dbuser_dba
mysql_admin_password: DBUser.DBA
mysql_monitor_username: dbuser_monitor
mysql_monitor_password: DBUser.Monitor

#-----------------------------------------------------------------
# MYSQL_INSTALL
#-----------------------------------------------------------------
# - install - #
mysql_dbsu: mysql                    # os dbsu name, mysql by default, better not change it
mysql_dbsu_uid: 27                   # os dbsu uid and gid, 306 for default mysql users and groups
mysql_dbsu_home: /var/lib/mysql      # mysql home directory, `/var/lib/mysql` by default
mysql_dbsu_ssh_exchange: true        # exchange mysql dbsu ssh key among same mysql cluster
mysql_packages:                      # mysql packages to be installed, `mysql-community*` by default
  - mysql-community*
  - mysqld_exporter

# - bootstrap - #
mysql_data: /data/mysql              # mysql data directory, `/data/mysql` by default
mysql_listen: '0.0.0.0'              # mysql listen addresses, comma separated IP list
mysql_port: 3306                     # mysql listen port, 3306 by default
mysql_sock: /var/lib/mysql/mysql.sock # mysql socket dir, `/var/lib/mysql/mysql.sock` by default
mysql_pid: /var/run/mysqld/mysqld.pid # mysql pid file, `/var/run/mysqld/mysqld.pid` by default
mysql_conf: /etc/my.cnf              # mysql config file, `/etc/my.cnf` by default
mysql_log_dir: /var/log              # mysql log dir, `/var/log/mysql` by default

mysql_exporter_port: 9104            # mysqld_exporter listen port, 9104 by default

mysql_parameters: {}                 # extra parameters for mysqld
mysql_default_parameters:            # default parameters for mysqld

18.2 - Module: Kafka

Deploy Kafka KRaft cluster with Pigsty: open-source distributed event streaming platform

Kafka is an open-source distributed event streaming platform: Installation | Configuration | Administration | Playbook | Monitoring | Parameters | Resources


Overview

Kafka module is currently available in Pigsty Pro as a Beta Preview.


Installation

If you are using the open-source version of Pigsty, you can install Kafka and its Java dependencies on the specified node using the following command.

Pigsty provides Kafka 3.8.0 RPM and DEB packages in the official Infra repository, which can be downloaded and installed directly.

./node.yml -t node_install  -e '{"node_repo_modules":"infra","node_packages":["kafka"]}'

Kafka requires a Java runtime environment, so you need to install an available JDK when installing Kafka (OpenJDK 17 is used by default, but other JDKs and versions, such as 8 and 11, can also be used).

# EL7 (no JDK 17 support)
./node.yml -t node_install  -e '{"node_repo_modules":"node","node_packages":["java-11-openjdk-headless"]}'

# EL8 / EL9 (use OpenJDK 17)
./node.yml -t node_install  -e '{"node_repo_modules":"node","node_packages":["java-17-openjdk-headless"]}'

# Debian / Ubuntu (use OpenJDK 17)
./node.yml -t node_install  -e '{"node_repo_modules":"node","node_packages":["openjdk-17-jdk"]}'

Configuration

Single node Kafka configuration example. Please note that in Pigsty single machine deployment mode, the 9093 port on the admin node is already occupied by AlertManager.

It is recommended to use other ports when installing Kafka on the admin node, such as (9095).

kf-main:
  hosts:
    10.10.10.10: { kafka_seq: 1, kafka_role: controller }
  vars:
    kafka_cluster: kf-main
    kafka_data: /data/kafka
    kafka_peer_port: 9095     # 9093 is already hold by alertmanager

3-node Kraft mode Kafka cluster configuration example:

kf-test:
  hosts:
    10.10.10.11: { kafka_seq: 1, kafka_role: controller   }
    10.10.10.12: { kafka_seq: 2, kafka_role: controller   }
    10.10.10.13: { kafka_seq: 3, kafka_role: controller   }
  vars:
    kafka_cluster: kf-test

Administration

Here are some basic Kafka cluster management operations:

Create Kafka clusters with kafka.yml playbook:

./kafka.yml -l kf-main
./kafka.yml -l kf-test

Create a topic named test:

kafka-topics.sh --create --topic test --partitions 1 --replication-factor 1 --bootstrap-server localhost:9092

Here the --replication-factor 1 means each data will be replicated once, and --partitions 1 means only one partition will be created.

Use the following command to view the list of Topics in Kafka:

kafka-topics.sh --bootstrap-server localhost:9092 --list

Use the built-in Kafka producer to send messages to the test Topic:

kafka-console-producer.sh --topic test --bootstrap-server localhost:9092
>haha
>xixi
>hoho
>hello
>world
> ^D

Use the built-in Kafka consumer to read messages from the test Topic:

kafka-console-consumer.sh --topic test --from-beginning --bootstrap-server localhost:9092

Playbook

Pigsty provides 1 playbook related to the Kafka module for managing Kafka clusters.


kafka.yml

The kafka.yml playbook for deploying Kafka KRaft mode cluster contains the following subtasks:

kafka-id       : generate kafka instance identity
kafka_clean    : remove existing kafka instance (DANGEROUS)
kafka_user     : create os user kafka
kafka_pkg      : install kafka rpm/deb packages
kafka_link     : create symlink to /usr/kafka
kafka_path     : add kafka bin path to /etc/profile.d
kafka_svc      : install kafka systemd service
kafka_dir      : create kafka data & conf dir
kafka_config   : generate kafka config file
kafka_boot     : bootstrap kafka cluster
kafka_launch   : launch kafka service
kafka_exporter : launch kafka exporter
kafka_register : register kafka service to prometheus

Monitoring

Pigsty has provided two monitoring panels related to the KAFKA module:

KAFKA Overview shows the overall monitoring metrics of the Kafka cluster.

KAFKA Instance shows the monitoring metrics details of a single Kafka instance.


Parameters

Available parameters for Kafka module:

#kafka_cluster:           #CLUSTER  # kafka cluster name, required identity parameter
#kafka_role: controller   #INSTANCE # kafka role, controller, broker, or controller-only
#kafka_seq: 0             #INSTANCE # kafka instance seq number, required identity parameter
kafka_clean: false                  # cleanup kafka during init? false by default
kafka_data: /data/kafka             # kafka data directory, `/data/kafka` by default
kafka_version: 3.8.0                # kafka version string
scala_version: 2.13                 # kafka binary scala version
kafka_port: 9092                    # kafka broker listen port
kafka_peer_port: 9093               # kafka broker peer listen port, 9093 by default (conflict with alertmanager)
kafka_exporter_port: 9308           # kafka exporter listen port, 9308 by default
kafka_parameters:                   # kafka parameters to be added to server.properties
  num.network.threads: 3
  num.io.threads: 8
  socket.send.buffer.bytes: 102400
  socket.receive.buffer.bytes: 102400
  socket.request.max.bytes: 104857600
  num.partitions: 1
  num.recovery.threads.per.data.dir: 1
  offsets.topic.replication.factor: 1
  transaction.state.log.replication.factor: 1
  transaction.state.log.min.isr: 1
  log.retention.hours: 168
  log.segment.bytes: 1073741824
  log.retention.check.interval.ms: 300000
  #log.retention.bytes: 1073741824
  #log.flush.interval.ms: 1000
  #log.flush.interval.messages: 10000

Resources

Pigsty provides some Kafka-related extension plugins for PostgreSQL:

  • kafka_fdw: A useful FDW that allows users to read and write Kafka Topic data directly from PostgreSQL
  • wal2json: Used to logically decode WAL from PostgreSQL and generate JSON-formatted change data
  • wal2mongo: Used to logically decode WAL from PostgreSQL and generate BSON-formatted change data
  • decoder_raw: Used to logically decode WAL from PostgreSQL and generate SQL-formatted change data
  • test_decoding: Used to logically decode WAL from PostgreSQL and generate RAW-formatted change data

18.3 - Module: DuckDB

Install DuckDB, a high-performance embedded analytical database component.

DuckDB is a fast in-process analytical database: Installation | Resources


Overview

DuckDB is an embedded database, so it does not require deployment or service management. You only need to install the DuckDB package on the node to use it.


Installation

Pigsty already provides DuckDB software package (RPM / DEB) in the Infra software repository, you can install it with the following command:

./node.yml -t node_install  -e '{"node_repo_modules":"infra","node_packages":["duckdb"]}'

Resources

There are some DuckDB-related extension plugins provided by Pigsty for PostgreSQL:

  • pg_analytics: Add OLAP capabilities to PostgreSQL based on DuckDB
  • pg_lakehouse: Data lakehouse plugin by ParadeDB, wrapping DuckDB. (Currently planned to be renamed back to pg_analytics)
  • duckdb_fdw: Foreign data wrapper for DuckDB, read/write DuckDB data files from PG
  • pg_duckdb: WIP extension plugin by DuckDB official MotherDuck and Hydra (only available on EL systems as a pilot)

18.4 - Module: TigerBeetle

Deploy TigerBeetle, the Financial Transactions Database that is 1000x faster.

TigerBeetle is a financial accounting transaction database offering extreme performance and reliability.


Overview

The TigerBeetle module is currently available for Beta preview only in the Pigsty Professional Edition.


Installation

Pigsty Infra Repo has the RPM / DEB packages for TigerBeetle, use the following command to install:

./node.yml -t node_install -e '{"node_repo_modules":"infra","node_packages":["tigerbeetle"]}'

After installation, please refer to the official documentation for configuration: https://github.com/tigerbeetle/tigerbeetle

18.5 - Module: Kubernetes

Deploy Kubernetes, the Production-Grade Container Orchestration Platform.

Kubernetes is a production-grade, open-source container orchestration platform. It helps you automate, deploy, scale, and manage containerized applications.

Pigsty has native support for ETCD clusters, which can be used by Kubernetes. Therefore, the pro version also provides the KUBE module for deploying production-grade Kubernetes clusters.

The KUBE module is currently in Beta status and only available for Pro edition customers.

However, you can directly specify node repositories in Pigsty, install Kubernetes packages, and use Pigsty to adjust environment configurations and provision nodes for K8S deployment, solving the last mile delivery problem.


SealOS

SealOS is a lightweight, high-performance, and easy-to-use Kubernetes distribution. It is designed to simplify the deployment and management of Kubernetes clusters.

Pigsty provides SealOS 5.0 RPM and DEB packages in the Infra repository, which can be downloaded and installed directly, and use SealOS to manage clusters.

./node.yml -t node_install -e '{"node_repo_modules":"infra","node_packages":["sealos"]}'

Kubernetes

If you prefer to deploy Kubernetes using the classic Kubeadm, please refer to the module reference below.

./node.yml -t node_install -e '{"node_repo_modules":"kube","node_packages":["kubeadm,kubelet,kubectl"]}'

Kubernetes supports multiple container runtimes. If you want to use Containerd as the container runtime, please make sure Containerd is installed on the node.

./node.yml -t node_install -e '{"node_repo_modules":"node,docker","node_packages":["containerd.io"]}'

If you want to use Docker as the container runtime, you need to install Docker and bridge with the cri-dockerd project (not available on EL9/D11/U20 yet):

./node.yml -t node_install -e '{"node_repo_modules":"node,infra,docker","node_packages":["docker-ce,docker-compose-plugin,cri-dockerd"]}'

Playbook

kube.yml playbook (TBD)


Monitoring

TBD


Parameters

Kubernetes module parameters:

#kube_cluster:                                          #IDENTITY# # define kubernetes cluster name
kube_role: node                                                    # default kubernetes role (master|node)
kube_version: 1.31.0                                               # kubernetes version
kube_registry: registry.aliyuncs.com/google_containers             # kubernetes version aliyun k8s miiror repository
kube_pod_cidr: "10.11.0.0/16"                                      # kubernetes pod network cidr
kube_service_cidr: "10.12.0.0/16"                                  # kubernetes service network cidr
kube_dashboard_admin_user: dashboard-admin-sa                      # kubernetes dashboard admin user name

18.6 - Module: Consul

Deploy Consul, the alternative to Etcd, with Pigsty.

Consul is a distributed DCS + KV + DNS + service registry/discovery component.

In the old version (1.x) of Pigsty, Consul was used as the default high-availability DCS. Now this support has been removed, but it will be provided as a separate module in the future.


Configuration

To deploy Consul, you need to add the IP addresses and hostnames of all nodes to the consul group.

At least one node should be designated as the consul server with consul_role: server, while other nodes default to consul_role: node.

consul:
  hosts:
    10.10.10.10: { nodename: meta , consul_role: server }
    10.10.10.11: { nodename: node-1 }
    10.10.10.12: { nodename: node-2 }
    10.10.10.13: { nodename: node-3 }

For production deployments, we recommend using an odd number of Consul Servers, preferably three.


Parameters

#-----------------------------------------------------------------
# CONSUL
#-----------------------------------------------------------------
consul_role: node                 # consul role, node or server, node by default
consul_dc: pigsty                 # consul data center name, `pigsty` by default
consul_data: /data/consul         # consul data dir, `/data/consul`
consul_clean: true                # consul purge flag, if true, clean consul during init
consul_ui: false                  # enable consul ui, the default value for consul server is true

18.7 - Module: Victoria

Deploy VictoriaMetrics & VictoriaLogs, the in-place replacement for Prometheus & Loki.

VictoriaMetrics is the in-place replacement for Prometheus, offering better performance and compression ratio.


Overview

Victoria is currently only available in the Pigsty Professional Edition Beta preview. It includes the deployment and management of VictoriaMetrics and VictoriaLogs components.


Installation

Pigsty Infra Repo has the RPM / DEB packages for VictoriaMetrics, use the following command to install:

./node.yml -t node_install -e '{"node_repo_modules":"infra","node_packages":["victoria-metrics"]}'
./node.yml -t node_install -e '{"node_repo_modules":"infra","node_packages":["victoria-metrics-cluster"]}'
./node.yml -t node_install -e '{"node_repo_modules":"infra","node_packages":["victoria-metrics-utils"]}'
./node.yml -t node_install -e '{"node_repo_modules":"infra","node_packages":["victoria-logs"]}'

For common users, installing the standalone version of VictoriaMetrics is sufficient. If you need to deploy a cluster, you can install the victoria-metrics-cluster package.

18.8 - Module: Jupyter

Launch Jupyter notebook server with Pigsty, a web-based interactive scientific notebook.

Run Jupyter notebook with Docker, you have to:

  1. Change the default password in .env: JUPYTER_TOKEN
  2. Create data dir with proper permission: make dir, owned by 1000:100
  3. make up to pull up Jupyter with docker compose
cd ~/pigsty/app/jupyter ; make dir up

Visit http://lab.pigsty or http://10.10.10.10:8888, the default password is pigsty

Prepare

Create a data directory /data/jupyter, with the default uid & gid 1000:100:

make dir   # mkdir -p /data/jupyter; chown -R 1000:100 /data/jupyter

Connect to Postgres

Use the Jupyter terminal to install psycopg2-binary & psycopg2 package.

pip install psycopg2-binary psycopg2

# install with a mirror
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple psycopg2-binary psycopg2

pip install --upgrade pip
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

Or installation with conda:

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/

Then use the driver in your notebook:

import psycopg2

conn = psycopg2.connect('postgres://dbuser_dba:[email protected]:5432/meta')
cursor = conn.cursor()
cursor.execute('SELECT * FROM pg_stat_activity')
for i in cursor.fetchall():
    print(i)

Alias

make up         # pull up jupyter with docker compose
make dir        # create required /data/jupyter and set owner
make run        # launch jupyter with docker
make view       # print jupyter access point
make log        # tail -f jupyter logs
make info       # introspect jupyter with jq
make stop       # stop jupyter container
make clean      # remove jupyter container
make pull       # pull latest jupyter image
make rmi        # remove jupyter image
make save       # save jupyter image to /tmp/docker/jupyter.tgz
make load       # load jupyter image from /tmp/docker/jupyter.tgz

19 - Miscellaneous

20 - PIG the PGPM

PostgreSQL Extension Ecosystem Package Manager

Postgres Install Genius, the missing extension package manager for the PostgreSQL ecosystem

PIG is a command-line tool specifically designed for installing, managing, and building PostgreSQL and its extensions. Developed in Go, it’s ready to use out of the box, simple, and lightweight (4MB). PIG is not a reinvented wheel, but rather a PiggyBack — a high-level abstraction layer that leverages existing Linux distribution package managers (apt/dnf). It abstracts away the differences between operating systems, chip architectures, and PG major versions, allowing you to install and manage PG kernels and 431+ extensions with just a few simple commands.

Note: For extension installation, pig is not a mandatory component — you can still use apt/dnf package managers to directly access the Pigsty PGSQL repository.

Quick Start

Use the following command to install PIG on your system:

Default Installation (Cloudflare CDN):

curl -fsSL https://repo.pigsty.io/pig | bash

China Mirror:

curl -fsSL https://repo.pigsty.cc/pig | bash

After installation, you can get started with just a few commands. For example, to install PG 18 and the pg_duckdb extension:

$ pig repo set                        # One-time setup for Linux, Pigsty + PGDG repos (overwrites!)
$ pig install pg18                    # Install PostgreSQL 18 kernel (native PGDG packages)
$ pig install pg_duckdb -v 18         # Install pg_duckdb extension (for PG 18)
$ pig install -y postgis timescaledb  # Install multiple extensions for current active PG version
$ pig install -y vector               # You can use extension name (vector) or package name (pgvector)!

Command Reference

Run pig help <command> to get detailed help for subcommands.

About

The pig CLI tool is developed by Vonng ([email protected]) and is open-sourced under the Apache 2.0 license.

You can also check out the PIGSTY project, which provides a complete PostgreSQL RDS DBaaS experience including extension delivery.

  • PGEXT: Extension data and management tools
  • PIG: PostgreSQL package manager
  • PIGSTY: Batteries-included PostgreSQL distribution

20.1 - Getting Started

Quick start with pig, the PostgreSQL package manager

Here’s a simple getting started tutorial to help you experience the core capabilities of the PIG package manager.

Short Version

curl -fsSL https://repo.pigsty.io/pig | bash   # Install PIG from Cloudflare
pig repo set                                   # One-time setup for Linux, Pigsty + PGDG repos (overwrites!)
pig install -v 18 -y pg18 pg_duckdb vector     # Install PG 18 kernel, pg_duckdb, pgvector extensions...

Installation

You can install pig with the following command:

Default Installation (Cloudflare CDN):

curl -fsSL https://repo.pigsty.io/pig | bash

China Mirror:

curl -fsSL https://repo.pigsty.cc/pig | bash

The PIG binary is approximately 4 MB and will automatically use rpm or dpkg to install the latest available version on Linux:

[INFO] kernel = Linux
[INFO] machine = x86_64
[INFO] package = rpm
[INFO] pkg_url = https://repo.pigsty.io/pkg/pig/v0.9.0/pig-0.9.0-1.x86_64.rpm
[INFO] download = /tmp/pig-0.7.2-1.x86_64.rpm
[INFO] downloading pig v0.7.2
curl -fSL https://repo.pigsty.io/pkg/pig/v0.7.2/pig-0.7.2-1.x86_64.rpm -o /tmp/pig-0.7.2-1.x86_64.rpm
######################################################################## 100.0%
[INFO] md5sum = 85d75c16dfd3ce935d9d889fae345430
[INFO] installing: rpm -ivh /tmp/pig-0.7.2-1.x86_64.rpm
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:pig-0.7.2-1                      ################################# [100%]
[INFO] pig v0.7.2 installed successfully
check https://ext.pigsty.io for details

Check Environment

PIG is a Go-written binary program, installed by default at /usr/bin/pig. pig version prints version information:

$ pig version

pig version 0.7.2 linux/amd64
build: HEAD 9cdb57a 2025-11-10T11:14:17Z

Use the pig status command to print the current environment status, OS code, PG installation status, and repository accessibility with latency.

$ pig status

# [Configuration] ================================
Pig Version      : 0.7.2
Pig Config       : /root/.pig/config.yml
Log Level        : info
Log Path         : stderr

# [OS Environment] ===============================
OS Distro Code   : el10
OS OSArch        : amd64
OS Package Type  : rpm
OS Vendor ID     : rocky
OS Version       : 10
OS Version Full  : 10.0
OS Version Code  : el10

# [PG Environment] ===============================
No PostgreSQL installation found

No active PostgreSQL found in PATH:
- /root/.local/bin
- /root/bin
- /usr/local/sbin
- /usr/local/bin
- /usr/sbin
- /usr/bin

# [Pigsty Environment] ===========================
Inventory Path   : Not Found
Pigsty Home      : Not Found

# [Network Conditions] ===========================
pigsty.cc  ping ok: 612 ms
pigsty.io  ping ok: 1222 ms
google.com request error
Internet Access   :  true
Pigsty Repo       :  pigsty.io
Inferred Region   :  china
Latest Pigsty Ver :  v3.6.1

List Extensions

Use the pig ext list command to print the built-in PG extension data catalog.

[root@pg-meta ~]# pig ext list

Name                            Version     Cate   Flags   License       RPM      DEB      PG Ver  Description
----                            -------     ----   ------  -------       ------   ------   ------  ---------------------
timescaledb                     2.23.0      TIME   -dsl--  Timescale     PIGSTY   PIGSTY   15-18   Enables scalable inserts and complex queries for time-series dat...
timescaledb_toolkit             1.22.0      TIME   -ds-t-  Timescale     PIGSTY   PIGSTY   15-18   Library of analytical hyperfunctions, time-series pipelining, an...
timeseries                      0.1.7       TIME   -d----  PostgreSQL    PIGSTY   PIGSTY   13-18   Convenience API for time series stack
periods                         1.2.3       TIME   -ds---  PostgreSQL    PGDG     PGDG     13-18   Provide Standard SQL functionality for PERIODs and SYSTEM VERSIO...
temporal_tables                 1.2.2       TIME   -ds--r  BSD 2-Clause  PIGSTY   PIGSTY   13-18   temporal tables
.........
pg_fact_loader                  2.0.1       ETL    -ds--x  MIT           PGDG     PGDG     13-18   build fact tables with Postgres
pg_bulkload                     3.1.22      ETL    bds---  BSD 3-Clause  PGDG     PIGSTY   13-17   pg_bulkload is a high speed data loading utility for PostgreSQL
test_decoding                   -           ETL    --s--x  PostgreSQL    CONTRIB  CONTRIB  13-18   SQL-based test/example module for WAL logical decoding
pgoutput                        -           ETL    --s---  PostgreSQL    CONTRIB  CONTRIB  13-18   Logical Replication output plugin

(431 Rows) (Flags: b = HasBin, d = HasDDL, s = HasLib, l = NeedLoad, t = Trusted, r = Relocatable, x = Unknown)

All extension metadata is defined in a data file named extension.csv. This file is updated with each pig version release. You can update it directly using the pig ext reload command. The updated file is placed in ~/.pig/extension.csv by default, which you can view and modify — you can also find the authoritative version of this data file in the project.

Add Repositories

To install extensions, you first need to add upstream repositories. pig repo can be used to manage Linux APT/YUM/DNF software repository configuration.

You can use the straightforward pig repo set to overwrite existing repository configuration, ensuring only necessary repositories exist in the system:

pig repo set                # One-time setup for all repos including Linux system, PGDG, PIGSTY (PGSQL+INFRA)

Warning: pig repo set will backup and clear existing repository configuration, then add required repositories, implementing Overwrite semantics — please be aware!

Or choose the gentler pig repo add to add needed repositories:

pig repo add pgdg pigsty     # Add PGDG official repo and PIGSTY supplementary repo
pig repo add pgsql           # [Optional] You can also add PGDG and PIGSTY together as one "pgsql" module
pig repo update              # Update cache: apt update / yum makecache

PIG will detect your network environment and choose to use Cloudflare global CDN or China cloud CDN, but you can force a specific region with the --region parameter.

pig repo set      --region=china              # Use China region mirror repos for faster downloads
pig repo add pgdg --region=default --update   # Force using PGDG upstream repo

PIG itself doesn’t support offline installation. You can download RPM/DEB packages yourself and copy them to network-isolated production servers for installation. The related PIGSTY project provides local software repositories that can use pig to install already-downloaded extensions from local repos.

Install PG

After adding repositories, you can use the pig ext add subcommand to install extensions (and related packages)

pig ext add -v 18 -y pgsql timescaledb postgis vector pg_duckdb pg_mooncake # Install PG 18 kernel and extensions, auto-confirm

# This command automatically translates packages to:
INFO[20:34:44] translate alias 'pgsql' to package: postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit
INFO[20:34:44] translate extension 'timescaledb' to package: timescaledb-tsl_18*
INFO[20:34:44] translate extension 'postgis' to package: postgis36_18*
INFO[20:34:44] translate extension 'vector' to package: pgvector_18*
INFO[20:34:44] translate extension 'pg_duckdb' to package: pg_duckdb_18*
INFO[20:34:44] translate extension 'pg_mooncake' to package: pg_mooncake_18*
INFO[20:34:44] installing packages: dnf install -y postgresql18 postgresql18-server postgresql18-libs postgresql18-contrib postgresql18-plperl postgresql18-plpython3 postgresql18-pltcl postgresql18-llvmjit timescaledb-tsl_18* postgis36_18* pgvector_18* pg_duckdb_18* pg_mooncake_18*

This uses an “alias translation” mechanism to translate clean PG kernel/extension logical package names into actual RPM/DEB lists. If you don’t need alias translation, you can use apt/dnf directly, or use the -n|--no-translation parameter with the variant pig install:

pig install vector     # With translation, installs pgvector_18 or postgresql-18-pgvector for current PG 18
pig install vector -n  # Without translation, installs the package literally named 'vector' (a log collector from pigsty-infra repo)

Alias Translation

PostgreSQL kernels and extensions correspond to a series of RPM/DEB packages. Remembering these packages is tedious, so pig provides many common aliases to simplify the installation process:

For example, on EL systems, the following aliases will be translated to the corresponding RPM package list on the right:

pgsql:        "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit"
pg18:         "postgresql18 postgresql18-server postgresql18-libs postgresql18-contrib postgresql18-plperl postgresql18-plpython3 postgresql18-pltcl postgresql18-llvmjit"
pg17-client:  "postgresql17"
pg17-server:  "postgresql17-server postgresql17-libs postgresql17-contrib"
pg17-devel:   "postgresql17-devel"
pg17-basic:   "pg_repack_17* wal2json_17* pgvector_17*"
pg16-mini:    "postgresql16 postgresql16-server postgresql16-libs postgresql16-contrib"
pg15-full:    "postgresql15 postgresql15-server postgresql15-libs postgresql15-contrib postgresql15-plperl postgresql15-plpython3 postgresql15-pltcl postgresql15-llvmjit postgresql15-test postgresql15-devel"
pg14-main:    "postgresql14 postgresql14-server postgresql14-libs postgresql14-contrib postgresql14-plperl postgresql14-plpython3 postgresql14-pltcl postgresql14-llvmjit pg_repack_14* wal2json_14* pgvector_14*"
pg13-core:    "postgresql13 postgresql13-server postgresql13-libs postgresql13-contrib postgresql13-plperl postgresql13-plpython3 postgresql13-pltcl postgresql13-llvmjit"

Note that the $v placeholder is replaced with the PG major version number, so when you use the pgsql alias, $v is actually replaced with 18, 17, etc. Therefore, when you install the pg17-server alias, on EL it actually installs postgresql17-server, postgresql17-libs, postgresql17-contrib, and on Debian/Ubuntu it installs postgresql-17 — pig handles all the details.

Common PostgreSQL Aliases

EL alias translation list

"pgsql":        "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit",
"pgsql-mini":   "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib",
"pgsql-core":   "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit",
"pgsql-full":   "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit postgresql$v-test postgresql$v-devel",
"pgsql-main":   "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit pg_repack_$v* wal2json_$v* pgvector_$v*",
"pgsql-client": "postgresql$v",
"pgsql-server": "postgresql$v-server postgresql$v-libs postgresql$v-contrib",
"pgsql-devel":  "postgresql$v-devel",
"pgsql-basic":  "pg_repack_$v* wal2json_$v* pgvector_$v*",

Debian/Ubuntu alias translation

"pgsql":        "postgresql-$v postgresql-client-$v postgresql-plpython3-$v postgresql-plperl-$v postgresql-pltcl-$v",
"pgsql-mini":   "postgresql-$v postgresql-client-$v",
"pgsql-core":   "postgresql-$v postgresql-client-$v postgresql-plpython3-$v postgresql-plperl-$v postgresql-pltcl-$v",
"pgsql-full":   "postgresql-$v postgresql-client-$v postgresql-plpython3-$v postgresql-plperl-$v postgresql-pltcl-$v postgresql-server-dev-$v",
"pgsql-main":   "postgresql-$v postgresql-client-$v postgresql-plpython3-$v postgresql-plperl-$v postgresql-pltcl-$v postgresql-$v-repack postgresql-$v-wal2json postgresql-$v-pgvector",
"pgsql-client": "postgresql-client-$v",
"pgsql-server": "postgresql-$v",
"pgsql-devel":  "postgresql-server-dev-$v",
"pgsql-basic":  "postgresql-$v-repack postgresql-$v-wal2json postgresql-$v-pgvector",

These aliases can be used directly and instantiated with major version numbers via parameters, or you can use alias variants with major version numbers: replacing pgsql with pg18, pg17, pgxx, etc. For example, for PostgreSQL 18, you can directly use these aliases:

pgsqlpg18pg17pg16pg15pg14pg13
pgsqlpg18pg17pg16pg15pg14pg13
pgsql-minipg18-minipg17-minipg16-minipg15-minipg14-minipg13-mini
pgsql-corepg18-corepg17-corepg16-corepg15-corepg14-corepg13-core
pgsql-fullpg18-fullpg17-fullpg16-fullpg15-fullpg14-fullpg13-full
pgsql-mainpg18-mainpg17-mainpg16-mainpg15-mainpg14-mainpg13-main
pgsql-clientpg18-clientpg17-clientpg16-clientpg15-clientpg14-clientpg13-client
pgsql-serverpg18-serverpg17-serverpg16-serverpg15-serverpg14-serverpg13-server
pgsql-develpg18-develpg17-develpg16-develpg15-develpg14-develpg13-devel
pgsql-basicpg18-basicpg17-basicpg16-basicpg15-basicpg14-basicpg13-basic

Install Extensions

pig detects the PostgreSQL installation in the current system environment. If it detects an active PG installation (based on pg_config in PATH), pig will automatically install extensions for that PG major version without you explicitly specifying it.

pig install pg_smtp_client          # Simpler
pig install pg_smtp_client -v 18    # Explicitly specify major version, more stable and reliable
pig install pg_smtp_client -p /usr/lib/postgresql/16/bin/pg_config   # Another way to specify PG version
dnf install pg_smtp_client_18       # Most direct... but not all extensions are this simple...

Tip: To add a specific major version of PostgreSQL kernel binaries to PATH, use the pig ext link command:

pig ext link pg17             # Create /usr/pgsql symlink and write to /etc/profile.d/pgsql.sh
. /etc/profile.d/pgsql.sh     # Take effect immediately, update PATH environment variable

If you want to install a specific version of software, you can use the name=ver syntax:

pig ext add -v 17 pgvector=0.7.2 # install pgvector 0.7.2 for PG 17
pig ext add pg16=16.5            # install PostgreSQL 16 with a specific minor version

Warning: Note that currently only PGDG YUM repository provides historical extension versions. PIGSTY repository and PGDG APT repository only provide the latest version of extensions.

Show Extensions

The pig ext status command can be used to show currently installed extensions.

$ pig ext status -v 18

Installed:
- PostgreSQL 18.0  80  Extensions

No active PostgreSQL found in PATH:
- /root/.local/bin
- /root/bin
- /usr/local/sbin
- /usr/local/bin
- /usr/sbin
- /usr/bin
Extension Stat  :  11 Installed (PIGSTY 3, PGDG 8) + 69 CONTRIB = 80 Total

Name                          Version  Cate  Flags   License     Repo    Package              Description
----                          -------  ----  ------  -------     ------  ------------         ---------------------
timescaledb                   2.23.0   TIME  -dsl--  Timescale   PIGSTY  timescaledb-tsl_18*  Enables scalable inserts and complex queries for time-series dat
postgis                       3.6.0    GIS   -ds---  GPL-2.0     PGDG    postgis36_18*        PostGIS geometry and geography spatial types and functions
postgis_topology              3.6.0    GIS   -ds---  GPL-2.0     PGDG    postgis36_18*        PostGIS topology spatial types and functions
postgis_raster                3.6.0    GIS   -ds---  GPL-2.0     PGDG    postgis36_18*        PostGIS raster types and functions
postgis_sfcgal                3.6.0    GIS   -ds--r  GPL-2.0     PGDG    postgis36_18*        PostGIS SFCGAL functions
postgis_tiger_geocoder        3.6.0    GIS   -ds-t-  GPL-2.0     PGDG    postgis36_18*        PostGIS tiger geocoder and reverse geocoder
address_standardizer          3.6.0    GIS   -ds--r  GPL-2.0     PGDG    postgis36_18*        Used to parse an address into constituent elements. Generally us
address_standardizer_data_us  3.6.0    GIS   -ds--r  GPL-2.0     PGDG    postgis36_18*        Address Standardizer US dataset example
vector                        0.8.1    RAG   -ds--r  PostgreSQL  PGDG    pgvector_18*         vector data type and ivfflat and hnsw access methods
pg_duckdb                     1.1.0    OLAP  -dsl--  MIT         PIGSTY  pg_duckdb_18*        DuckDB Embedded in Postgres
pg_mooncake                   0.2.0    OLAP  -d----  MIT         PIGSTY  pg_mooncake_18*      Columnstore Table in Postgres

If PostgreSQL cannot be found in your current system path (based on pg_config in PATH), please make sure to specify the PG major version number or pg_config path via -v|-p.

Scan Extensions

pig ext scan provides lower-level extension scanning functionality, scanning shared libraries in the specified PostgreSQL directory to discover installed extensions:

root@s37451:~# pig ext scan
Installed:
* PostgreSQL 17.6 (Debian 17.6-2.pgdg13+1)    70  Extensions
- PostgreSQL 15.14 (Debian 15.14-1.pgdg13+1)  69  Extensions
- PostgreSQL 14.19 (Debian 14.19-1.pgdg13+1)  66  Extensions
- PostgreSQL 13.22 (Debian 13.22-1.pgdg13+1)  64  Extensions
- PostgreSQL 18.0 (Debian 18.0-1.pgdg13+3)    70  Extensions
- PostgreSQL 16.10 (Debian 16.10-1.pgdg13+1)  70  Extensions

Active:
PG Version      :  PostgreSQL 17.6 (Debian 17.6-2.pgdg13+1)
Config Path     :  /usr/lib/postgresql/17/bin/pg_config
Binary Path     :  /usr/lib/postgresql/17/bin
Library Path    :  /usr/lib/postgresql/17/lib
Extension Path  :  /usr/share/postgresql/17/extension
Name                 Version  SharedLibs                                       Description            Meta
----                 -------  ----------                                       ---------------------  ------
amcheck              1.4      functions for verifying relation integrity       relocatable=true module_pathname=$libdir/amcheck lib=amcheck.so
...
pg_duckdb            1.1.0    DuckDB Embedded in Postgres                      module_pathname=$libdir/pg_duckdb relocatable=false schema=public lib=libduckdb.so, pg_duckdb.so
pg_mooncake          0.2.0    Real-time analytics on Postgres tables           module_pathname=pg_mooncake relocatable=false requires=pg_duckdb superuser=true lib=pg_mooncake.so
pg_prewarm           1.2      prewarm relation data                            module_pathname=$libdir/pg_prewarm relocatable=true lib=pg_prewarm.so
pg_smtp_client       0.2.1    PostgreSQL extension to send email using SMTP    relocatable=false superuser=false schema=smtp_client module_pathname=$libdir/pg_smtp_client lib=pg_smtp_client.so
...
Encoding Libs: cyrillic_and_mic, euc2004_sjis2004, euc_cn_and_mic, euc_jp_and_sjis, euc_kr_and_mic, euc_tw_and_big5, latin2_and_win1250, latin_and_mic, utf8_and_big5, utf8_and_cyrillic, utf8_and_euc2004, utf8_and_euc_cn, utf8_and_euc_jp, utf8_and_euc_kr, utf8_and_euc_tw, utf8_and_gb18030, utf8_and_gbk, utf8_and_iso8859, utf8_and_iso8859_1, utf8_and_johab, utf8_and_sjis, utf8_and_sjis2004, utf8_and_uhc, utf8_and_win
Built-in Libs: dict_snowball, libpqwalreceiver, llvmjit

Container Practice

You can create a fresh virtual machine, or use the following Docker container for testing. Create a d13 directory with a Dockerfile:

FROM debian:13
USER root
WORKDIR /root/
CMD ["/bin/bash"]

RUN apt update && apt install -y ca-certificates curl && curl https://repo.pigsty.io/pig | bash
docker build -t d13:latest .
docker run -it d13:latest /bin/bash

pig repo set --region=china    # Add China region repositories
pig install -y pg18            # Install PGDG 18 kernel packages
pig install -y postgis timescaledb pgvector pg_duckdb

20.2 - Introduction

Why do we need yet another package manager? Especially for Postgres extensions?

Have you ever struggled with installing or upgrading PostgreSQL extensions? Digging through outdated documentation, cryptic configuration scripts, or searching GitHub for forks and patches? Postgres’s rich extension ecosystem also means complex deployment processes — especially tricky across multiple distributions and architectures. PIG can solve these headaches for you.

This is exactly why Pig was created. Developed in Go, Pig is dedicated to one-stop management of Postgres and its 430+ extensions. Whether it’s TimescaleDB, Citus, PGVector, 30+ Rust extensions, or all the components needed to self-host Supabase — Pig’s unified CLI makes everything accessible. It completely eliminates source compilation and messy repositories, directly providing version-aligned RPM/DEB packages that perfectly support Debian, Ubuntu, RedHat, and other mainstream distributions on both x86 and Arm architectures — no guessing, no hassle.

Pig isn’t reinventing the wheel; it fully leverages native system package managers (APT, YUM, DNF) and strictly follows PGDG official packaging standards for seamless integration. You don’t need to choose between “the standard way” and “shortcuts”; Pig respects existing repositories, follows OS best practices, and coexists harmoniously with existing repositories and packages. If your Linux system and PostgreSQL major version aren’t in the supported list, you can use pig build to compile extensions for your specific combination.

Want to supercharge your Postgres and escape the hassle? Visit the PIG official documentation for guides and check out the extensive extension list, turning your local Postgres database into an all-capable multi-modal data platform with one click. If Postgres’s future is unmatched extensibility, then Pig is the magic lamp that helps you unlock it. After all, no one ever complains about “too many extensions.”

ANNOUNCE pig: The Postgres Extension Wizard


Linux Compatibility

PIG and the Pigsty extension repository support the following Linux distribution and PostgreSQL version combinations:

OS CodeVendorMajorMinorFull NamePG VersionsNotes
el7.x86_64EL77.9CentOS 7 x8613-15EOL
el8.x86_64EL88.10RockyLinux 8 x8613-18Near EOL
el8.aarch64EL88.10RockyLinux 8 ARM13-18Near EOL
el9.x86_64EL99.6RockyLinux 9 x8613-18
el9.aarch64EL99.6RockyLinux 9 ARM13-18
el10.x86_64EL1010.0RockyLinux 10 x8613-18
el10.aarch64EL1010.0RockyLinux 10 ARM13-18
d11.x86_64Debian1111.11Debian 11 x8613-18EOL
d11.aarch64Debian1111.11Debian 11 ARM13-18EOL
d12.x86_64Debian1212.12Debian 12 x8613-18
d12.aarch64Debian1212.12Debian 12 ARM13-18
d13.x86_64Debian1313.1Debian 13 x8613-18
d13.aarch64Debian1313.1Debian 13 ARM13-18
u20.x86_64Ubuntu2020.04.6Ubuntu 20.04 x8613-18EOL
u20.aarch64Ubuntu2020.04.6Ubuntu 20.04 ARM13-18EOL
u22.x86_64Ubuntu2222.04.5Ubuntu 22.04 x8613-18
u22.aarch64Ubuntu2222.04.5Ubuntu 22.04 ARM13-18
u24.x86_64Ubuntu2424.04.3Ubuntu 24.04 x8613-18
u24.aarch64Ubuntu2424.04.3Ubuntu 24.04 ARM13-18

Notes:

  • EL refers to RHEL-compatible distributions, including RHEL, CentOS, RockyLinux, AlmaLinux, OracleLinux, etc.
  • EOL indicates the operating system has reached or is about to reach end of support; upgrading to a newer version is recommended
  • indicates full support; recommended for use
  • PG versions 13-18 means support for PostgreSQL 13, 14, 15, 16, 17, and 18 major versions

20.3 - Installation

How to download and install the pig package manager

Script Installation

The simplest way to install pig is to run the following installation script:

Default Installation (Cloudflare CDN):

curl -fsSL https://repo.pigsty.io/pig | bash

China Mirror:

curl -fsSL https://repo.pigsty.cc/pig | bash

This script downloads the latest pig RPM/DEB package from the Pigsty software repository and installs it using rpm or dpkg.

Specify Version

You can specify a particular version to install by passing the version number as an argument:

Default Installation (Cloudflare CDN):

curl -fsSL https://repo.pigsty.io/pig | bash -s 0.9.0

China Mirror:

curl -fsSL https://repo.pigsty.cc/pig | bash -s 0.9.0

Download from Release Page

You can also download pig installation packages (RPM/DEB/tarball) directly from the Pigsty repository: GitHub Latest Release Page

latest
└── v0.9.0
    ├── pig_0.9.0-1_amd64.deb
    ├── pig_0.9.0-1_arm64.deb
    ├── pig-0.9.0-1.aarch64.rpm
    ├── pig-0.9.0-1.x86_64.rpm
    ├── pig-v0.9.0.linux-amd64.tar.gz
    ├── pig-v0.9.0.linux-arm64.tar.gz
    ├── pig-v0.9.0.darwin-amd64.tar.gz
    └── pig-v0.9.0.darwin-arm64.tar.gz

After extracting, place the binary file in your system PATH.

Repository Installation

The pig software is located in the pigsty-infra repository. You can add this repository to your operating system and then install using the OS package manager:

YUM

For RHEL, RockyLinux, CentOS, Alma Linux, OracleLinux, and other EL distributions:

sudo tee /etc/yum.repos.d/pigsty-infra.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.io/yum/infra/$basearch
enabled = 1
gpgcheck = 0
module_hotfixes=1
EOF

sudo yum makecache;
sudo yum install -y pig

APT

For Debian, Ubuntu, and other DEB distributions:

sudo tee /etc/apt/sources.list.d/pigsty-infra.list > /dev/null <<EOF
deb [trusted=yes] https://repo.pigsty.io/apt/infra generic main
EOF

sudo apt update;
sudo apt install -y pig

Update

To upgrade an existing pig version to the latest available version, use the following command:

pig update            # Upgrade pig itself to the latest version

To update the extension data of an existing pig to the latest available version, use the following command:

pig ext reload        # Update pig extension data to the latest version

Uninstall

apt remove -y pig     # Debian / Ubuntu and other Debian-based systems
yum remove -y pig     # RHEL / CentOS / RockyLinux and other EL distributions
rm -rf /usr/bin/pig   # If installed directly from binary, just delete the binary file

Build from Source

You can also build pig yourself. pig is developed in Go and is very easy to build. The source code is hosted at github.com/pgsty/pig

git clone https://github.com/pgsty/pig.git; cd pig
go get -u; go build

All RPM/DEB packages are automatically built through GitHub CI/CD workflow using goreleaser.

20.4 - Release

pig — PostgreSQL Package Manager Release Notes

The latest stable version is v0.9.0.

VersionDateSummaryGitHub
v0.9.02025-12-28Adjust pig sty command options, fix aliasv0.9.0
v0.8.02025-12-26440 extensions, remove sysupdate repov0.8.0
v0.7.52025-12-12Routine extension update, fixed aliyun mirrorv0.7.5
v0.7.42025-12-01Update ivory/pgtde kernel and pgdg extrasv0.7.4
v0.7.32025-11-24Fix repo for el10 & debian13v0.7.3
v0.7.22025-11-20437 extensions, fix pig build issuev0.7.2
v0.7.12025-11-10New Website, improve in-docker experiencev0.7.1
v0.7.02025-11-05Build Enhancement and massive upgradev0.7.0
v0.6.22025-10-03PG 18 official Repov0.6.2
v0.6.12025-08-14CI/CD, el10 stub, PGDG CN Mirrorv0.6.1
v0.6.02025-07-17423 extension, percona pg_tde, mcp toolboxv0.6.0
v0.5.02025-06-30422 extension, new extension catalogv0.5.0
v0.4.22025-05-27421 extension, halo & oriole debv0.4.2
v0.4.12025-05-07414 extension, pg18 alias supportv0.4.1
v0.4.02025-05-01do & pt sub-cmd, halo & orioledbv0.4.0
v0.3.42025-04-05routine updatev0.3.4
v0.3.32025-03-25alias, repo, depsv0.3.3
v0.3.22025-03-21new extensionsv0.3.2
v0.3.12025-03-19minor bug fixv0.3.1
v0.3.02025-02-24new home page and extension catalogv0.3.0
v0.2.22025-02-22404 extensionsv0.2.2
v0.2.02025-02-14400 extensionsv0.2.0
v0.1.42025-02-12routine bugfixv0.1.4
v0.1.32025-01-23390 extensionsv0.1.3
v0.1.22025-01-12the anon extension and 350 other extv0.1.2
v0.1.12025-01-09Update Extension Listv0.1.1
v0.1.02024-12-29repo, ext, sty, and self-updatev0.1.0
v0.0.12024-12-23Genesis Releasev0.0.1

v0.9.0

  • Refactor command pig sty install to pig sty deploy
  • Add new parameters for command pig sty conf, aligned with configure script
  • Add llvmjit package to pgsql-full alias

Checksums

ea0c098d0829720b6e364d2f2a91328876962c7f0ae94eee7bdcde0bd43313fa  pig-0.9.0-1.aarch64.rpm
707f4e1fde76d3faa05165ac11e97969c22a8740c97ef84da52727d0328990cc  pig-0.9.0-1.x86_64.rpm
56aeb61674ddfb64368e6f5535e06a38b76f62e3d6c9536a63be7df6babed93e  pig-v0.9.0.darwin-amd64.tar.gz
a213d16817d6124ffa83d93ad880a040598b6ed3fe23a74d43420c095ed43de4  pig-v0.9.0.darwin-arm64.tar.gz
6a1a1836217fa723ca42bc2276ecf1453cd2ee0acacddfc313164701b24a452f  pig-v0.9.0.linux-amd64.tar.gz
5e5728aa5922138c61c900a731f97cdc1b9653c14d7fe804b6753fb6f222b8b0  pig-v0.9.0.linux-arm64.tar.gz
e80d2cb3ceb5fd58fc0262ab4b39b44e8dcccb7712151c73a41ba50cb510353b  pig_0.9.0-1_amd64.deb
ecb504efffde8d696b765579332fc0b3304751fa8077c4c0394e7f3c44aa0fe2  pig_0.9.0-1_arm64.deb

Release: https://github.com/pgsty/pig/releases/tag/v0.9.0


v0.8.0

Extension Updates

  • Total extensions reached 440
  • New extension: pg_ai_query 0.1.1
  • New extension: pg_textsearch 0.1.0
  • New extension: pg_clickhouse 0.1.0
  • pg_biscuit upgraded from 1.0 to 2.0.1 (switched to new repo, renamed to biscuit)
  • pg_search upgraded from 0.20.3 to 0.20.5
  • pg_duckdb upgraded to official release 1.1.1
  • vchord_bm25 upgraded from 0.2.2 to 0.3.0
  • pg_semver upgraded from 0.40.0 to 0.41.0
  • pg_timeseries upgraded from 0.1.7 to 0.1.8
  • Fixed debian/ubuntu pg18 extension issues: supautils, pg_summarize, pg_vectorize, pg_tiktoken, pg_tzf, pglite_fusion, pgsmcrypto, pgx_ulid, plprql
  • Pigsty version synced to 4.0.0

Repository Updates

  • Removed pgdg yum sysupdate repo due to upstream changes
  • Removed pgdg yum llvmjit package due to upstream changes
  • Fixed patroni 3.0.4 duplicate package issue on el9.aarch64
  • Added priority for el repo definitions, docker repo skipped when unavailable
  • Added epel 10 / pgdg 9/10 OS minor version hotfix

Checksums

e457832fb290e2f9975bf719966dc36e650bdcbf8505d319c9e0431f4c03bc9e  pig-0.8.0-1.aarch64.rpm
c97b1bfdd7541f0f464cab0ecc273e65535c8dd2603c38d5cf8dccbf7e95b523  pig-0.8.0-1.x86_64.rpm
d892f06d3d3b440671529f40e6cc7949686e0167e2a4758adc666b8a3d75254d  pig-v0.8.0.darwin-amd64.tar.gz
222413bafdf5a62dc682dac32ea1118cbc34ec3544e2a1b85076ec450b9cc7ae  pig-v0.8.0.darwin-arm64.tar.gz
d50aa9806bbab8fee5ad9228e104fc9e7ead48729228116b5bf889000791fedc  pig-v0.8.0.linux-amd64.tar.gz
d2f410f7b243a8323c8d479f462a0267ac72d217aa4a506c80b5a9927d12dff8  pig-v0.8.0.linux-arm64.tar.gz
4ccd330a995911d4f732e8c9d62aa0db479c21c9596f64c4bc129ec43f156abe  pig_0.8.0-1_amd64.deb
5cb9eccce659110f3ba58e502575564bd6befffd51992a43d84df5a17f8eb8a0  pig_0.8.0-1_arm64.deb

Release: https://github.com/pgsty/pig/releases/tag/v0.8.0


v0.7.5

Extension Updates

  • timescaledb 2.23.1 -> 2.24.0
  • pg_search 0.20.0 -> 0.20.3
  • convert 0.0.4 -> 0.0.5
  • pglinter 1.0.0 -> 1.0.1
  • pgdd 0.6.0 -> 0.6.1
  • pg_session_jwt 0.3.3 -> 0.4.0
  • pg_anon 2.4.1 -> 2.5.1
  • pg_enigma 0.4.0 -> 0.5.0
  • wrappers 0.5.6 -> 0.5.7
  • pg_vectorize 0.25.0 -> 0.26.0

Repository Updates

Use the fixed Aliyun PGDG mirror repository

Checksums

9de11ac1404fc4100074113f2a5d50e4ec42c353b6e122a0b29edc17e53feca6  pig-0.7.5-1.aarch64.rpm
071d655580f1cc63b33d41a8fb49368556b7b5a276318f4bd772a6ab50e22b34  pig-0.7.5-1.x86_64.rpm
befe0a8f786e5243669ed7219acde8156d13d9adb0a5c2fb88ccf0f614a51f9b  pig-v0.7.5.darwin-amd64.tar.gz
4766b4e9ba390a32a7115e9f2dd6b65cf158439e28f9c099bab5c7f2e588bae2  pig-v0.7.5.darwin-arm64.tar.gz
dc45726c5e7fccd502cacaffc94c659570844151cdc279f2cac6500836071ade  pig-v0.7.5.linux-amd64.tar.gz
1483cf967d4bc9c12d4c6724567644d6b88fcd2a93aaf1d317fc6ad4e1672c13  pig-v0.7.5.linux-arm64.tar.gz
0152b7bd254eccadd640e563845abd9fa62efa68f11c6b67a5f9f0eebfa2d92e  pig_0.7.5-1_amd64.deb
7d22116d26ca09c5e2b8afbf086bb1acb1aea1148905efcc38944c18908fb105  pig_0.7.5-1_arm64.deb

Release: https://github.com/pgsty/pig/releases/tag/v0.7.5


v0.7.4

  • Update extension metadata: pg_search, pgmq, pg_stat_monitor
  • Update pgdg repo URL, the extras now move to parent directory
  • Bump ivorysql to 5.0 (compatible with PG 18.0)
  • Bump Percona Postgres TDE Kernel to 18.1

Checksums

5769b0051f04dcda22dd92b30b8effc8ddfa40097308bded76ce2b38d012ce57  pig-0.7.4-1.aarch64.rpm
d15c829fa2e3ce8dcd1adc063c107607b8e70f2cf747646aaa2fa257cdbf979c  pig-0.7.4-1.x86_64.rpm
bb4c90e253a3d470e50316e633a41e90ed2d4a5c5a1fd3a8dbb68ee87d831d47  pig-v0.7.4.darwin-amd64.tar.gz
faaf7ac7b08390f5048c081bb7a78100714387e35dc890e26d9746fc1caef415  pig-v0.7.4.darwin-arm64.tar.gz
037cacddd0dc1283f13dd2c9bace87ad7f2c74ffc245e629f1420be94bbf93df  pig-v0.7.4.linux-amd64.tar.gz
2ce819b2c3686cfb9f86790fdf61acd30bf7798bd6cd3c4f589df22e273dc867  pig-v0.7.4.linux-arm64.tar.gz
97f62d62f1cca61ce6d335efed88e3855d94ea2cd4ed941f2755fbac73931fcd  pig_0.7.4-1_amd64.deb
d2b80af89ed42601716f6b41eda3f8bee16db34023527df9deef8a43aa25a498  pig_0.7.4-1_arm64.deb

Release: https://github.com/pgsty/pig/releases/tag/v0.7.4


v0.7.3

  • Add new command: pig repo reload to update repo metadata
  • Fix EL PGDG sysupdate aarch64 repo issue (now aarch64 repo ready)
  • Fix EL10.aarch64 PGDG repo renaming issue
  • Update extension versions
  • Bump Pigsty version to 3.7.0

Checksums

786d72f6b685d6d6abf5f255f0a7de9204988a05630a26a53bfc7631823c0c6f  pig-0.7.3-1.aarch64.rpm
da59e24ef79d1164e348bacc43e3222e8e2778ec0e103e7ffc0c6df064758e8f  pig-0.7.3-1.x86_64.rpm
73062a979749095e89abc07dd583d34d4f57908bb4ee935cf7640f129ca6a2cb  pig-v0.7.3.darwin-amd64.tar.gz
ca5f5576f6d0d9be1d10cad769821be9daa62220b2fb56b94d6e4c0cede6da61  pig-v0.7.3.darwin-arm64.tar.gz
d193b4b87cf9a6e4775b1b07709802d30f0233ccb1b728843a09decb545168d3  pig-v0.7.3.linux-amd64.tar.gz
e7f612df0e8e4d9fac6df3765862b9e491bb50aad651856abf7a6935986e6f99  pig-v0.7.3.linux-arm64.tar.gz
3d5306ce95dcf704dd498b05325d942637564b13115f1e5a5bb9ef6781df1ba6  pig_0.7.3-1_amd64.deb
32e695ba2d49a741d8cd92008f8f2dec29f10754d35b732035f48517b382c30d  pig_0.7.3-1_arm64.deb

Release: https://github.com/pgsty/pig/releases/tag/v0.7.3


v0.7.2

  • Extension list update, + 6 new extensions, 437 total

  • Add PGDG EL10 Sysupdate repo

  • Add LLVM APT repo

  • Use local extension.csv catalog in pig build sub command

  • Updated extensions: vchord pg_later pgvectorscale pglite_fusion pgx_ulid pg_search citus timescaledb pg_profile pg_stat_monitor documentdb

  • New extensions: pglinter pg_typeid pg_enigma pg_retry pg_biscuit pg_weighted_statistics

Checksums

f303c391fc28bc74832712e0aa58319abe0ebcae4f6c07fdf9a9e542b735d2ec  pig-0.7.2-1.aarch64.rpm
c096a61a4e3a49b1238659664bbe2cd7f29954c43fb6bb8e8e9fb271f95a612e  pig-0.7.2-1.x86_64.rpm
5e037c891dff23b46856485108d6f64bede5216dfbd4f38a481f0d0672ee910b  pig-v0.7.2.darwin-amd64.tar.gz
736b4b47999c543c3c886781f4d8dddbf4276f363c35c7bf50094b6f18d14600  pig-v0.7.2.darwin-arm64.tar.gz
20b13f059efed29dd76f6927b3e8d7b597c0c8d734f9e22ba3d0a2af6dbcd3bf  pig-v0.7.2.linux-amd64.tar.gz
9548b530c05f2ffdc8d73b8f890718d47b74a51eb62852a99c08b1b52e47f014  pig-v0.7.2.linux-arm64.tar.gz
b6faad9f92b926546a10f590274f2cb2afff21b9cea878094cfc5caf09e67d2c  pig_0.7.2-1_amd64.deb
452f73f1fa035e5417ab49fc51d797925550179ffcc023e8f03d80144309212a  pig_0.7.2-1_arm64.deb

Release: https://github.com/pgsty/pig/releases/tag/v0.7.2


v0.7.1

  • The brand-new website: https://pgext.cloud
  • Remove unnecessary sudo usage, now can be used inside docker
  • Allow using pg18, pg17 arg format in pig ext link command
  • Add environment var PIG_NO_SUDO to force not using sudo
  • RPM Changelog: Add PG 18 support to almost all extensions
  • DEB Changelog: Add PG 18 support to almost all extensions
  • Infra Changelog: Routine update to the latest version

Checksums

a696c9ec784e2fc248e5f3d87cc8aae4116e890f78c5997957d30593f2c85ca6  pig-0.7.1-1.aarch64.rpm
f669538a99cd1dc592d3005b949628fcceb9e78114fc78862d7726b340ee194d  pig-0.7.1-1.x86_64.rpm
e42bdaaf93b720c5b76b32b57362320e4b447109740c76089aefe030b7c8b836  pig-v0.7.1.darwin-amd64.tar.gz
b4c240aadad34e785666ee0a755d9b7455724f790c2d088a1dd7c37ad3b2a457  pig-v0.7.1.darwin-arm64.tar.gz
ffc687add0ca71ac90cba5749c8a7a6075cf7618cba85584072831cf3eb182f7  pig-v0.7.1.linux-amd64.tar.gz
7b0d1f158150d0a40c525692f02b6bce9f5b4ac523a4e59278d702c334e222e1  pig-v0.7.1.linux-arm64.tar.gz
43e91a3bea273d7cacb2d7a58c0a5745501dbd06348b5cb3af971171fae70268  pig_0.7.1-1_amd64.deb
fc2a34aeb46e07cb0ae93611de47d6622c3bd46fe4c415ce4c9091840e0e08a2  pig_0.7.1-1_arm64.deb

Release: https://github.com/pgsty/pig/releases/tag/v0.7.1


v0.7.0

  • Add support for Debian 13 and EL 10 distributions
  • Massive extension updates to the latest versions with PostgreSQL 18 support
  • Almost all Rust extensions now support PG 18 via pgrx 0.16.1
  • pig build command overhaul
    • pig build pkg <pkg> will now download source, prepare deps, and build in one go
    • pig build pgrx is now separated from pig build rust
    • pig build pgrx [-v pgrx_version] can now use existing PG installation directly
    • pig build dep will now handle extension dependencies on both EL and Debian systems
    • pig build ext now has more compact and elegant output, can build RPM on EL without build script
    • pig build spec now supports downloading spec files directly from Pigsty repo
    • pig build repo / pig repo add / pig repo set now use node,pgsql,infra as default repo modules instead of node,pgdg,pigsty
  • Optimized error logging
  • Brand new catalog website based on hugo and hextra

Checksums

ad60f9abcde954769e46eb23de61965e  pig_0.7.0-1_amd64.deb
aa15d7088d561528e38b2778fe8f7cf9  pig_0.7.0-1_arm64.deb
05549fe01008e04f8d5a59d4f2a5f0b8  pig-0.7.0-1.aarch64.rpm
0cc9e46c7c72d43c127a6ad115873b67  pig-0.7.0-1.x86_64.rpm
ddacfb052f3f3e5567a02e92fdb31cdd  pig-v0.7.0.darwin-amd64.tar.gz
17d25b565308d3d35513e4b0d824946b  pig-v0.7.0.darwin-arm64.tar.gz
ee7e055ceff638039956765fb747f80b  pig-v0.7.0.linux-amd64.tar.gz
284e674807b87447d4b33691fd7a420d  pig-v0.7.0.linux-arm64.tar.gz

Release: https://github.com/pgsty/pig/releases/tag/v0.7.0


v0.6.2

  • Use official PG 18 repo instead of testing repo
  • Add v prefix when specifying pigsty version string
  • Improved network connectivity check

Checksums

01f5b7dc20644226c762dbb229768347  pig_0.6.2-1_amd64.deb
ce4f00256adc12cbea91467b7f2241cd  pig_0.6.2-1_arm64.deb
cefc36ae8f348aede533b30836fba720  pig-0.6.2-1.aarch64.rpm
d04a287c6eb92b11ecbf99542c2db602  pig-0.6.2-1.x86_64.rpm
e637ca86a7f38866c67686b060223d9a  pig-v0.6.2.darwin-amd64.tar.gz
79749bc69c683586bd8d761bdf6af98e  pig-v0.6.2.darwin-arm64.tar.gz
ad4f02993c7d7d8eec142f0224551bb4  pig-v0.6.2.linux-amd64.tar.gz
9793affa4a0cb60e9753e65b7cba3dca  pig-v0.6.2.linux-arm64.tar.gz

Release: https://github.com/pgsty/pig/releases/tag/v0.6.2


v0.6.1

  • Add el10 and debian 13 trixie support stub
  • Dedicated website: https://pgext.cloud/pig
  • Rebuild with go 1.25 and CI/CD pipeline
  • Use PIGSTY PGDG mirror in mainland China
  • Remove unused pgdg-el10fix repo
  • Use Pigsty WiltonDB mirror
  • Add EL 10 dedicated epel repo
  • pig version output with go build environment

Release: https://github.com/pgsty/pig/releases/tag/v0.6.1


v0.6.0

  • New extension catalog: https://ext.pgsty.com
  • New subcommand: pig install to simplify pig ext install
  • Add new kernel support: percona with pg_tde
  • Add new package: Google GenAI MCP toolbox for databases
  • Add new repo: percona repo and clickhouse repo
  • Change extension summary info links to https://ext.pgsty.com
  • Fix orioledb broken on the Debian/Ubuntu system
  • Fix epel repo on EL distributions
  • Bump golang to 1.24.5
  • Bump pigsty to v3.6.0

Checksums

1804766d235b9267701a08f95903bc3b  pig_0.6.0-1_amd64.deb
35f4efa35c1eaecdd12aa680d29eadcb  pig_0.6.0-1_arm64.deb
b523b54d9f2d7dcc5999bcc6bd046b1d  pig-0.6.0-1.aarch64.rpm
9434d9dca7fd9725ea574c5fae1a7f52  pig-0.6.0-1.x86_64.rpm
f635c12d9ad46a779aa7174552977d11  pig-v0.6.0.linux-amd64.tar.gz
165af4e63ec0031d303fe8b6c35c5732  pig-v0.6.0.linux-arm64.tar.gz

Release: https://github.com/pgsty/pig/releases/tag/v0.6.0


v0.5.0

  • Update the extension list to 422
  • New extension: pgactive from AWS
  • Bump timescaledb to 2.20.3
  • Bump citus to 13.1.0
  • Bump vchord to 0.4.3
  • Bug fix pgvectorscale debian/ubuntu pg17 failure
  • Bump kubernetes repo to 1.33
  • Bump default pigsty version to 3.5.0

Checksums

9ec6f3caf3edbe867caab5de0e0ccb33  pig_0.5.0-1_amd64.deb
4fbb0a42cd8a88bce50b3c9d85745d77  pig_0.5.0-1_arm64.deb
9cf8208396b068cab438f72c90d39efe  pig-0.5.0-1.aarch64.rpm
d9a8d78c30f45e098b29c3d16471aa8d  pig-0.5.0-1.x86_64.rpm
761df804ff7b83965c41492700717674  pig-v0.5.0.linux-amd64.tar.gz
5d1830069d98030728f08835f883ea39  pig-v0.5.0.linux-arm64.tar.gz

Release: https://github.com/pgsty/pig/releases/tag/v0.5.0


v0.4.2

  • Update the extension list to 421
  • Add openhalo/orioledb support for Debian / Ubuntu
  • pgdd 0.6.0 (pgrx 0.14.1)
  • convert 0.0.4 (pgrx 0.14.1)
  • pg_idkit 0.3.0 (pgrx 0.14.1)
  • pg_tokenizer.rs 0.1.0 (pgrx 0.13.1)
  • pg_render 0.1.2 (pgrx 0.12.8)
  • pgx_ulid 0.2.0 (pgrx 0.12.7)
  • pg_ivm 1.11.0 for debian/ubuntu
  • orioledb 1.4.0 beta11
  • Add el7 repo back

Checksums

bbf83fa3e3ec9a4dca82eeed921ae90a  pig_0.4.2-1_amd64.deb
e45753335faf80a70d4f2ef1d3100d72  pig_0.4.2-1_arm64.deb
966d60bbc2025ba9cc53393011605f9f  pig-0.4.2-1.aarch64.rpm
1f31f54da144f10039fa026b7b6e75ad  pig-0.4.2-1.x86_64.rpm
1eec26c4e69b40921e209bcaa4fe257a  pig-v0.4.2.linux-amd64.tar.gz
768d43441917a3625c462ce9f2b9d4ef  pig-v0.4.2.linux-arm64.tar.gz

Release: https://github.com/pgsty/pig/releases/tag/v0.4.2


v0.4.1

  • Update the extension list to 414
  • Add citus_wal2json and citus_pgoutput to pig ext scan mapping
  • Add PG 18 beta repo
  • Add PG 18 package alias

Release: https://github.com/pgsty/pig/releases/tag/v0.4.1


v0.4.0

  • Updated extension list, available extensions reached 407
  • Added pig do subcommand for executing Pigsty playbook tasks
  • Added pig pt subcommand for wrapping Patroni command-line tools
  • Added extension aliases: openhalo and orioledb
  • Added gitlab-ce / gitlab-ee repository distinction
  • Built with the latest Go 1.24.2 and upgraded dependency versions
  • Fixed pig ext status panic issue under specific conditions
  • Fixed pig ext scan unable to match several extensions

Release: https://github.com/pgsty/pig/releases/tag/v0.4.0


v0.3.4

curl https://repo.pigsty.io/pig | bash -s 0.3.4
  • Routine extension metadata update
  • Use aliyun epel mirror instead of broken tsinghua tuna mirror
  • Bump pigsty version string
  • Add gitlab repo to the repo list

Release: https://github.com/pgsty/pig/releases/tag/v0.3.4


v0.3.3

  • Add pig build dep command to install extension build dependencies
  • Update default repo list
  • Use pigsty.io mirror for mssql module (wiltondb/babelfish)
  • Merge docker module into infra
  • Remove pg16/17 from el7 target
  • Allow installing extensions in el7
  • Update package alias

Release: https://github.com/pgsty/pig/releases/tag/v0.3.3


v0.3.2

Enhancement

  • New extensions
  • Use upx to reduce binary size
  • Remove embedded pigsty to reduce binary size

Release: https://github.com/pgsty/pig/releases/tag/v0.3.2


v0.3.1

Routine bugfix

  • Fix repo format string
  • Fix ext info links
  • Update pg_mooncake metadata

Release: https://github.com/pgsty/pig/releases/tag/v0.3.1


v0.3.0

The pig project now has a new homepage, along with the PostgreSQL Extension Catalog.

Release: https://github.com/pgsty/pig/releases/tag/v0.3.0


v0.2.2

404 Extensions Available in Pig v0.2.2

Release: https://github.com/pgsty/pig/releases/tag/v0.2.2


v0.2.0

Release: https://github.com/pgsty/pig/releases/tag/v0.2.0


v0.1.4

Release: https://github.com/pgsty/pig/releases/tag/v0.1.4


v0.1.3

v0.1.3, routine update, with 390 extensions available now!

Release: https://github.com/pgsty/pig/releases/tag/v0.1.3


v0.1.2

351 PostgreSQL Extensions, including the powerful postgresql-anonymizer 2.0

Release: https://github.com/pgsty/pig/releases/tag/v0.1.2


v0.1.0

pig CLI v0.1 released

Release: https://github.com/pgsty/pig/releases/tag/v0.1.0


v0.0.1

Genesis Release

Release: https://github.com/pgsty/pig/releases/tag/v0.0.1

20.5 - Command Reference

20.6 - CMD: pig

pig CLI command reference overview

The pig CLI provides comprehensive tools for managing PostgreSQL installations, extensions, repositories, and building extensions from source. Check command documentation with pig help <command>.

Overview

pig - the Linux Package Manager for PostgreSQL

Usage:
  pig [command]

Examples:

  pig repo add -ru            # overwrite existing repo & update cache
  pig install pg17            # install postgresql 17 PGDG package
  pig install pg_duckdb       # install certain postgresql extension
  pig install pgactive -v 18  # install extension for specifc pg major

  check https://pgext.cloud for details

PostgreSQL Extension Manager
  build       Build Postgres Extension
  ext         Manage PostgreSQL Extensions (pgext)
  repo        Manage Linux Software Repo (apt/dnf)
  install     Install packages using native package manager

Pigsty Management Commands
  do          Run admin tasks
  sty         Manage Pigsty installation

Additional Commands:
  completion  Generate the autocompletion script for the specified shell
  help        Help about any command
  status      Show Environment Status
  update      Upgrade pig itself
  version     Show pig version info

Flags:
      --debug              enable debug mode
  -h, --help               help for pig
  -H, --home string        pigsty home path
  -i, --inventory string   config inventory path
      --log-level string   log level: debug, info, warn, error, fatal, panic (default "info")
      --log-path string    log file path, terminal by default

Use "pig [command] --help" for more information about a command.

pig repo

Manage APT/YUM repositories for PostgreSQL packages. See pig repo for details.

pig repo list                    # List available repositories
pig repo info   pgdg             # Show repository details
pig repo status                  # Check current repo status
pig repo add    pgdg pigsty -u   # Add repositories
pig repo rm     old-repo         # Remove repositories
pig repo update                  # Update package cache
pig repo create /www/pigsty      # Create local repository
pig repo cache                   # Create offline package
pig repo boot                    # Bootstrap from offline package

pig ext

Manage PostgreSQL extensions and kernel packages. See pig ext for details.

pig ext list    duck             # Search extensions
pig ext info    pg_duckdb        # Extension details
pig ext status                   # Show installed extensions
pig ext add     pg_duckdb -y     # Install extension
pig ext rm      old_extension    # Remove extension
pig ext update                   # Update extensions
pig ext scan                     # Scan installed extensions
pig ext import  pg_duckdb        # Download for offline use
pig ext link    17               # Link PG version to PATH
pig ext reload                   # Refresh extension catalog

pig build

Build PostgreSQL extensions from source. See pig build for details.

# Environment setup
pig build spec                   # Initialize build specs
pig build repo                   # Setup repositories
pig build tool                   # Install build tools
pig build rust -y                # Install Rust (for Rust extensions)
pig build pgrx                   # Install PGRX framework

# Build extensions
pig build pkg citus              # Complete build pipeline = get + dep + ext
pig build get citus              # Download source
pig build dep citus              # Install dependencies
pig build ext citus              # Build package

pig sty

Install Pigsty distribution. See pig sty for details.

pig sty init                     # Install Pigsty to ~/pigsty
pig sty boot                     # Install Ansible prerequisites
pig sty conf                     # Generate configuration
pig sty deploy                   # Run deployment playbook

20.7 - CMD: pig ext

Manage PostgreSQL extensions with pig ext subcommand

The pig ext command is a comprehensive tool for managing PostgreSQL extensions. It allows users to search, install, remove, update, and manage PostgreSQL extensions and even kernel packages.

CommandDescriptionNotes
ext listSearch extensions
ext infoShow extension details
ext statusShow installed extensions
ext addInstall extensionsRequires sudo or root
ext rmRemove extensionsRequires sudo or root
ext updateUpdate extensionsRequires sudo or root
ext scanScan installed extensions
ext importDownload for offline useRequires sudo or root
ext linkLink PG version to PATHRequires sudo or root
ext reloadRefresh extension catalog

Quick Start

pig ext list                     # List all extensions
pig ext list duck                # Search for "duck" extensions
pig ext info pg_duckdb           # Show pg_duckdb extension info
pig install pg_duckdb            # Install pg_duckdb extension
pig install pg_duckdb -v 17      # Install pg_duckdb for PG 17
pig ext status                   # Show installed extensions

ext list

List or search extensions.

pig ext list                     # List all extensions
pig ext list duck                # Search for "duck" extensions
pig ext list vector ai           # Search multiple keywords
pig ext list -c RAG              # Filter by category
pig ext list -v 17               # Filter by PG version

Options:

  • -c|--category: Filter by category (TIME, GIS, RAG, FTS, OLAP, FEAT, LANG, TYPE, UTIL, FUNC, ADMIN, STAT, SEC, FDW, SIM, ETL)
  • -v|--version: Filter by PG version

ext info

Display detailed information about specific extensions.

pig ext info pg_duckdb           # Show pg_duckdb info
pig ext info vector postgis      # Show info for multiple extensions

ext status

Display the status of installed extensions for the active PostgreSQL instance.

pig ext status                   # Show installed extensions
pig ext status -v 17             # Show installed extensions for PG 17

ext add

Install extensions. Also available via alias pig install.

pig ext add pg_duckdb            # Install pg_duckdb
pig ext add pg_duckdb -v 17      # Install for PG 17
pig ext add pg_duckdb -y         # Auto-confirm installation
pig ext add vector postgis       # Install multiple extensions

# Using alias
pig install pg_duckdb
pig install pg_duckdb -v 17 -y

Options:

  • -v|--version: Specify PG major version
  • -y|--yes: Auto-confirm installation
  • -n|--no-translation: Disable alias translation

ext rm

Remove extensions. Also available via alias pig remove.

pig ext rm pg_duckdb             # Remove pg_duckdb
pig ext rm pg_duckdb -v 17       # Remove for PG 17
pig remove pg_duckdb             # Using alias

ext update

Update installed extensions.

pig ext update                   # Update all extensions
pig ext update pg_duckdb         # Update specific extension

ext scan

Scan installed PostgreSQL installations and their extensions.

pig ext scan                     # Scan all installed PG versions
pig ext scan -v 17               # Scan PG 17

ext import

Download extension packages for offline use.

pig ext import pg_duckdb         # Download pg_duckdb
pig ext import pg_duckdb -v 17   # Download for PG 17

Link a specific PG version to the system PATH.

pig ext link 17                  # Link PG 17 to PATH

This command creates a /usr/pgsql symlink and writes to /etc/profile.d/pgsql.sh.

ext reload

Refresh extension metadata from GitHub.

pig ext reload                   # Refresh extension catalog

The updated file is placed in ~/.pig/extension.csv.


Examples

To install PostgreSQL extensions, you’ll have to add the repo first:

pig repo add pgdg pigsty -u    # gentle way to add pgdg and pigsty repo
pig repo set -u                # brute way to remove and add all required repos

Then you can search and install PostgreSQL extensions:

pig ext install pg_duckdb
pig ext install pg_partman
pig ext install pg_cron
pig ext install pg_repack
pig ext install pg_stat_statements
pig ext install pg_stat_kcache

Check extension list for available extensions and their names.

Notes:

  1. When no PostgreSQL version is specified, the tool will try to detect the active PostgreSQL installation from pg_config in your PATH
  2. PostgreSQL can be specified either by major version number (-v) or by pg_config path (-p). If -v is given, pig will use the well-known default path of PGDG kernel packages for the given version.
    • On EL distros, it’s /usr/pgsql-$v/bin/pg_config for PG$v
    • On DEB distros, it’s /usr/lib/postgresql/$v/bin/pg_config for PG$v
    • If -p is given, pig will use the pg_config path to find the PostgreSQL installation
  3. The extension manager supports different package formats based on the underlying operating system:
    • RPM packages for RHEL/CentOS/Rocky Linux/AlmaLinux
    • DEB packages for Debian/Ubuntu
  4. Some extensions may have dependencies that will be automatically resolved during installation
  5. Use the -y flag with caution as it will automatically confirm all prompts

Pigsty assumes you already have installed the official PGDG kernel packages. If not, you can install them with:

pig ext install pg17          # install PostgreSQL 17 kernels (all but devel)

20.8 - CMD: pig repo

Manage software repositories with pig repo subcommand

The pig repo command is a comprehensive tool for managing package repositories on Linux systems. It provides functionality to add, remove, create, and manage software repositories for both RPM-based (RHEL/CentOS/Rocky/Alma) and Debian-based (Debian/Ubuntu) distributions.

CommandDescriptionNotes
repo listPrint available repo and module list
repo infoGet repo detailed information
repo statusShow current repo status
repo addAdd new repositoryRequires sudo or root
repo setWipe, overwrite, and update repositoryRequires sudo or root
repo rmRemove repositoryRequires sudo or root
repo updateUpdate repo cacheRequires sudo or root
repo createCreate local YUM/APT repositoryRequires sudo or root
repo cacheCreate offline package from local repoRequires sudo or root
repo bootBootstrap repo from offline packageRequires sudo or root

Quick Start

# Method 1: Clean existing repos, add all necessary repos and update cache (recommended)
pig repo add all --remove --update    # Remove old repos, add all essentials, update cache

# Method 1 variant: One-step
pig repo set                          # = pig repo add all --remove --update

# Method 2: Gentle approach - only add required repos, keep existing config
pig repo add pgsql                    # Add PGDG and Pigsty repos with cache update
pig repo add pigsty --region=china    # Add Pigsty repo, specify China region
pig repo add pgdg   --region=default  # Add PGDG, specify default region
pig repo add infra  --region=europe   # Add INFRA repo, specify Europe region

# If no -u|--update option above, run this command additionally
pig repo update                       # Update system package cache

Modules

In pig, APT/YUM repositories are organized into modules — groups of repositories serving a specific purpose.

ModuleDescriptionRepository List
allAll core modules needed to install PGnode + infra + pgsql
pgsqlPGDG + Pigsty PG extensionspigsty-pgsql + pgdg
pigstyPigsty Infra + PGSQL repospigsty-infra, pigsty-pgsql
pgdgPGDG official repositorypgdg-common, pgdg13-18
nodeLinux system repositoriesbase, updates, extras, epel…
infraInfrastructure component repospigsty-infra, nginx, docker-ce

repo add

Add repository configuration files to the system. Requires root/sudo privileges.

pig repo add pgdg                # Add PGDG repository
pig repo add pgdg pigsty         # Add multiple repositories
pig repo add all                 # Add all essential repos (pgdg + pigsty + node)
pig repo add pigsty -u           # Add and update cache
pig repo add all -r              # Remove existing repos before adding
pig repo add all -ru             # Remove, add, and update (complete reset)
pig repo add pgdg --region=china # Use China mirrors

Options:

  • -r|--remove: Remove existing repos before adding new ones
  • -u|--update: Run package cache update after adding repos
  • --region <region>: Use regional mirror repositories (default / china / europe)

repo set

Equivalent to repo add --remove --update. Wipes existing repositories and sets up new ones, then updates cache.

pig repo set                     # Replace with default repos
pig repo set pgdg pigsty         # Replace with specific repos and update
pig repo set all --region=china  # Use China mirrors

repo rm

Remove repository configuration files and back them up.

pig repo rm                      # Remove all repos
pig repo rm pgdg                 # Remove specific repo
pig repo rm pgdg pigsty -u       # Remove and update cache

repo update

Update package manager cache to reflect repository changes.

pig repo update                  # Update package cache
PlatformEquivalent Command
ELdnf makecache
Debianapt update

repo create

Create local package repository for offline installations.

pig repo create                  # Create at default location (/www/pigsty)
pig repo create /srv/repo        # Create at custom location

repo cache

Create compressed tarball of repository contents for offline distribution.

pig repo cache                   # Default: /www to /tmp/pkg.tgz
pig repo cache -f                # Force overwrite existing
pig repo cache -d /srv           # Custom source directory

repo boot

Extract and set up local repository from offline package.

pig repo boot                    # Default: /tmp/pkg.tgz to /www
pig repo boot -p /mnt/pkg.tgz   # Custom package path
pig repo boot -d /srv           # Custom target directory

Common Scenarios

Scenario 1: Fresh PostgreSQL Installation

# Setup repositories
sudo pig repo add -ru

# Install PostgreSQL 17
sudo pig ext install pg17

# Install popular extensions
sudo pig ext add pg_duckdb postgis timescaledb

Scenario 2: Air-gapped Environment

# On internet-connected machine:
sudo pig repo add -ru
sudo pig ext install pg17
sudo pig ext add pg_duckdb postgis
sudo pig repo create
sudo pig repo cache

# Transfer /tmp/pkg.tgz to air-gapped machine

# On air-gapped machine:
sudo pig repo boot
sudo pig repo add local
sudo pig ext install pg17
sudo pig ext add pg_duckdb postgis

Scenario 3: Using Regional Mirrors

# For users in China
sudo pig repo add all --region=china -u

# Check mirror URLs
pig repo info pgdg

20.9 - CMD: pig sty

Manage Pigsty installation with pig sty subcommand

The pig can also be used as a CLI tool for Pigsty — the battery-included free PostgreSQL RDS. Which brings HA, PITR, Monitoring, IaC, and all the extensions to your PostgreSQL cluster.

CommandDescriptionNotes
sty initInstall Pigsty
sty bootInstall Ansible prerequisitesRequires sudo or root
sty confGenerate configuration
sty deployRun deployment playbook

Quick Start

pig sty init                     # Install Pigsty to ~/pigsty
pig sty boot                     # Install Ansible prerequisites
pig sty conf                     # Generate configuration
pig sty deploy                   # Run deployment playbook

sty init

Download and install Pigsty distribution to ~/pigsty directory.

pig sty init                     # Install latest Pigsty
pig sty init -v 3.5.0            # Install specific version
pig sty init -d /opt/pigsty      # Install to specific directory

Options:

  • -v|--version: Specify Pigsty version
  • -d|--dir: Specify installation directory
  • -f|--force: Overwrite existing pigsty directory

sty boot

Install Ansible and its dependencies.

pig sty boot                     # Install Ansible
pig sty boot -y                  # Auto-confirm
pig sty boot -r china            # Use China region mirrors

Options:

  • -r|--region: Upstream repo region (default, china, europe)
  • -k|--keep: Keep existing upstream repo during bootstrap

sty conf

Generate Pigsty configuration file.

pig sty conf                     # Generate default configuration
pig sty conf -c rich             # Use conf/rich.yml template (more extensions)
pig sty conf -c slim             # Use conf/slim.yml template (minimal install)
pig sty conf -c supabase         # Use conf/supabase.yml template (self-hosting)
pig sty conf -g                  # Generate with random passwords (recommended!)
pig sty conf -v 17               # Use PostgreSQL 17
pig sty conf -r china            # Use China region mirrors
pig sty conf --ip 10.10.10.10    # Specify IP address

Options:

  • -c|--conf: Config template name
  • -v|--version: PostgreSQL major version
  • -r|--region: Upstream repo region
  • --ip: Primary IP address
  • -g|--generate: Generate random passwords
  • -s|--skip: Skip IP address probing
  • -o|--output: Output config file path

sty deploy

Run Pigsty deployment playbook.

pig sty deploy                   # Run full deployment

This command runs the deploy.yml playbook from your Pigsty installation.

Warning: This operation makes changes to your system. Use with caution!


Complete Workflow

Here’s the complete workflow to set up Pigsty:

# 1. Download and install Pigsty
pig sty init

# 2. Install Ansible and dependencies
cd ~/pigsty
pig sty boot

# 3. Generate configuration
pig sty conf -g                  # Generate with random passwords

# 4. Deploy Pigsty
pig sty deploy

For detailed setup instructions, check Get Started.


Configuration Templates

Available configuration templates (-c option):

TemplateDescription
metaDefault single-node meta configuration
richConfiguration with more extensions enabled
slimMinimal installation
fullFull 4-node HA template
supabaseSelf-hosting Supabase template

Example:

pig sty conf -c rich -g -v 17 -r china

This generates a configuration using the rich template with PostgreSQL 17, random passwords, and China region mirrors.

20.10 - CMD: pig build

Build PostgreSQL extensions from source with pig build subcommand

The pig build command is a powerful tool that simplifies the entire workflow of building PostgreSQL extensions from source. It provides a complete build infrastructure setup, dependency management, and compilation environment for both standard and custom PostgreSQL extensions across different operating systems.

Subcommands

CommandDescriptionNotes
build specInitialize building spec repo
build repoInitialize required reposRequires sudo or root
build toolInitialize build toolsRequires sudo or root
build rustInstall Rust toolchainRequires sudo or root
build pgrxInstall and initialize pgrxRequires sudo or root
build pkgComplete build pipelineRequires sudo or root
build getDownload source code tarball
build depInstall extension build dependenciesRequires sudo or root
build extBuild extension packageRequires sudo or root

Quick Start

# Setup build environment
pig build spec                   # Initialize build specs
pig build repo                   # Setup repositories
pig build tool                   # Install build tools

# Install Rust (for Rust extensions)
pig build rust -y                # Install Rust
pig build pgrx                   # Install PGRX framework

# Build extensions
pig build pkg citus              # Complete build pipeline

build spec

Initialize build specification files.

pig build spec                   # Create default spec files
pig build spec -f                # Force overwrite existing files

build repo

Setup repositories required for building.

pig build repo                   # Setup repositories

build tool

Install build toolchain (gcc, make, cmake, etc.).

pig build tool                   # Install build tools
pig build tool -y                # Auto-confirm

build rust

Install Rust toolchain (for building Rust extensions).

pig build rust                   # Install Rust
pig build rust -y                # Auto-confirm

build pgrx

Install PGRX framework (for building PGRX extensions).

pig build pgrx                   # Install PGRX
pig build pgrx -v 17             # Install for PG 17

build pkg

Complete build pipeline: download source, install dependencies, build extension.

pig build pkg citus              # Build citus
pig build pkg citus -v 17        # Build for PG 17
pig build pkg citus -y           # Auto-confirm

build get

Download extension source code.

pig build get citus              # Download citus source

build dep

Install extension build dependencies.

pig build dep citus              # Install citus dependencies
pig build dep citus -y           # Auto-confirm

build ext

Build extension package from source.

pig build ext citus              # Build citus
pig build ext citus -v 17        # Build for PG 17

Build Infrastructure

Build Specifications

The build system uses specification files that define how each extension should be built. These specs include:

  • Source code location and version
  • Build dependencies
  • Compilation flags
  • PostgreSQL version compatibility
  • Platform-specific build instructions

Directory Structure

~/ext/                           # Default build spec directory
├── Makefile                     # Master build makefile
├── <extension>/                 # Per-extension directory
│   ├── Makefile                # Extension-specific makefile
│   ├── <extension>.spec        # RPM spec file (EL)
│   └── debian/                 # Debian packaging files
│       ├── control
│       ├── rules
│       └── ...

Build output locations:

  • EL Systems: ~/rpmbuild/RPMS/<arch>/
  • Debian Systems: ~/ (deb files)

Common Workflows

Workflow 1: Building Standard Extension

# 1. Setup build environment (once)
pig build spec
pig build repo
pig build tool

# 2. Build extension
pig build pkg pg_partman

# 3. Install built package
sudo rpm -ivh ~/rpmbuild/RPMS/x86_64/pg_partman*.rpm  # EL
sudo dpkg -i ~/pg_partman*.deb                         # Debian

Workflow 2: Building Rust Extension

# 1. Setup Rust environment
pig build spec
pig build tool
pig build rust -y
pig build pgrx

# 2. Build Rust extension
pig build pkg pgmq

# 3. Install
sudo pig ext add pgmq

Workflow 3: Building Multiple Versions

# Build extension for multiple PostgreSQL versions
pig build pkg citus --pg 15,16,17

# Results in packages for each version:
# citus_15-*.rpm
# citus_16-*.rpm
# citus_17-*.rpm

Troubleshooting

Build Tools Not Found

# Install build tools
pig build tool

# For specific compiler
sudo dnf groupinstall "Development Tools"  # EL
sudo apt install build-essential          # Debian

Missing Dependencies

# Install extension dependencies
pig build dep <extension>

# Check error messages for specific packages
# Install manually if needed
sudo dnf install <package>  # EL
sudo apt install <package>  # Debian

PostgreSQL Headers Not Found

# Install PostgreSQL development package
sudo pig ext install pg17-devel

# Or specify pg_config path
export PG_CONFIG=/usr/pgsql-17/bin/pg_config

Rust/PGRX Issues

# Reinstall Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Update PGRX
cargo install cargo-pgrx --force

# Reinitialize PGRX
cargo pgrx init

21 - Linux Repository

The infrastructure to deliver PostgreSQL Extensions

Pigsty has a repository that provides 340+ extra PostgreSQL extensions on mainstream Linux Distros. It is designed to work together with the official PostgreSQL Global Development Group (PGDG) repo. Together, they can provide up to 400+ PostgreSQL Extensions out-of-the-box.

PGSQL RepoDescriptionLink
PGSQL RepoPigsty Extension Repo, 340+ extra extensionspgsql.md
INFRA RepoPigsty Infrastructure Repo, monitoring/toolsinfra.md
PGDG RepoPGDG Official Repo Mirror, PG Kernelpgdg.md
GPG KeyGPG Public Key, signature verificationgpg.md

Compatibility Overview

OS / ArchOSx86_64aarch64
EL8el818 17 16 15 14 1318 17 16 15 14 13
EL9el918 17 16 15 14 1318 17 16 15 14 13
EL10el1018 17 16 15 14 1318 17 16 15 14 13
Debian 12d1218 17 16 15 14 1318 17 16 15 14 13
Debian 13d1318 17 16 15 14 1318 17 16 15 14 13
Ubuntu 22.04u2218 17 16 15 14 1318 17 16 15 14 13
Ubuntu 24.04u2418 17 16 15 14 1318 17 16 15 14 13

Get Started

You can enable the pigsty infra & pgsql repo with the pig CLI tool:

curl https://repo.pigsty.io/pig | bash      # download and install the pig CLI tool
pig repo add all -u                         # add linux, pgdg, pigsty repo and update cache
curl https://repo.pigsty.cc/pig | bash      # download from mirror site
pig repo add -u                             # add linux, pgdg, pigsty repo and update cache

Manual Install

You can also add these repos to your system manually with the default apt, dnf, yum approach.

# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.io/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

# Get Debian distribution codename (distro_codename=jammy, focal, bullseye, bookworm), and write the corresponding upstream repository address to the APT List file
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-io.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/infra generic main
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/pgsql/${distro_codename} ${distro_codename} main
EOF

# Refresh APT repository cache
sudo apt update
# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.io/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

# Add Pigsty Repo definition files to /etc/yum.repos.d/ directory, including two repositories
sudo tee /etc/yum.repos.d/pigsty-io.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.io/yum/infra/$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty
module_hotfixes=1

[pigsty-pgsql]
name=Pigsty PGSQL For el$releasever.$basearch
baseurl=https://repo.pigsty.io/yum/pgsql/el$releasever.$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty
module_hotfixes=1
EOF

# Refresh YUM/DNF repository cache
sudo yum makecache;

All the RPM / DEB packages are signed with GPG Key fingerprint (B9BD8B20) in Pigsty repository.


Repository Components

Pigsty has two major repos: INFRA and PGSQL, providing DEB / RPM packages for x86_64 and aarch64 architecture.

The INFRA repo contains packages that are generic to any PostgreSQL version and Linux major version, including Prometheus & Grafana stack, admin tools for Postgres, and many utilities written in Go.

LinuxPackagex86_64aarch64
ELrpm
Debiandeb

The PGSQL repo contains packages that are ad hoc to specific PostgreSQL Major Versions (often ad hoc to a specific Linux distro major version, too). Including extensions and some kernel forks.


Compatibility Details

OS CodeVendorMajorMinorFullnamePG Major VersionComment
el7.x86_64EL77.9CentOS 7 x8615 14 13EOL
el8.x86_64EL88.10RockyLinux 8 x8618 17 16 15 14 13Near EOL
el8.aarch64EL88.10RockyLinux 8 ARM18 17 16 15 14 13Near EOL
el9.x86_64EL99.6RockyLinux 9 x8618 17 16 15 14 13OK
el9.aarch64EL99.6RockyLinux 9 ARM18 17 16 15 14 13OK
el10.x86_64EL1010.0RockyLinux 10 x8618 17 16 15 14 13OK
el10.aarch64EL1010.0RockyLinux 10 ARM18 17 16 15 14 13OK
d11.x86_64Debian1111.11Debian 11 x8617 16 15 14 13EOL
d11.aarch64Debian1111.11Debian 11 ARM17 16 15 14 13EOL
d12.x86_64Debian1212.12Debian 12 x8618 17 16 15 14 13OK
d12.aarch64Debian1212.12Debian 12 ARM18 17 16 15 14 13OK
d13.x86_64Debian1313.1Debian 13 x8618 17 16 15 14 13OK
d13.aarch64Debian1313.1Debian 13 ARM18 17 16 15 14 13OK
u20.x86_64Ubuntu2020.04.6Ubuntu 20.04 x8617 16 15 14 13EOL
u20.aarch64Ubuntu2020.04.6Ubuntu 20.04 ARM17 16 15 14 13EOL
u22.x86_64Ubuntu2222.04.5Ubuntu 22.04 x8618 17 16 15 14 13OK
u22.aarch64Ubuntu2222.04.5Ubuntu 22.04 ARM18 17 16 15 14 13OK
u24.x86_64Ubuntu2424.04.3Ubuntu 24.04 x8618 17 16 15 14 13OK
u24.aarch64Ubuntu2424.04.3Ubuntu 24.04 ARM18 17 16 15 14 13OK

Source

Building specs of these repos and packages are open-sourced on GitHub:

21.1 - PGDG Repo

The official PostgreSQL APT/YUM repository

The Pigsty PGSQL Repo is designed to work together with the official PostgreSQL Global Development Group (PGDG) repo. Together, they can provide up to 400+ PostgreSQL Extensions out-of-the-box.

Mirror synced at 2025-12-29 12:00:00


Quick Start

You can install pig - the CLI tool, and add pgdg repo with it (recommended):

pig repo add pgdg                           # add pgdg repo file
pig repo add pgdg -u                        # add pgdg repo and update cache
pig repo add pgdg -u --region=default       # add pgdg repo, enforce using the default repo (postgresql.org)
pig repo add pgdg -u --region=china         # add pgdg repo, always use the china mirror (repo.pigsty.cc)
pig repo add pgsql -u                       # pgsql = pgdg + pigsty-pgsql (add pigsty + official PGDG)
pig repo add -u                             # all = node + pgsql (pgdg + pigsty) + infra

Mirror

Since 2025-05, PGDG has closed the rsync/ftp sync channel, which makes almost all mirror sites out-of-sync.

Currently, Pigsty, Yandex, and Xtom are providing regular synced mirror service.

The Pigsty PGDG mirror is a subset of the official PGDG repo, covering EL 7-10, Debian 11-13, Ubuntu 20.04 - 24.04, with x86_64 & arm64 and PG 13 - 19alpha.


Compatibility

OS CodeVendorMajorPG Major VersionComment
el7.x86_64EL718 17 16 15 14 13EOL
el8.x86_64EL818 17 16 15 14 13Near EOL
el8.aarch64EL818 17 16 15 14 13Near EOL
el9.x86_64EL918 17 16 15 14 13OK
el9.aarch64EL918 17 16 15 14 13OK
el10.x86_64EL1018 17 16 15 14 13OK
el10.aarch64EL1018 17 16 15 14 13OK
d11.x86_64Debian1118 17 16 15 14 13EOL
d11.aarch64Debian1118 17 16 15 14 13EOL
d12.x86_64Debian1218 17 16 15 14 13OK
d12.aarch64Debian1218 17 16 15 14 13OK
d13.x86_64Debian1318 17 16 15 14 13OK
d13.aarch64Debian1318 17 16 15 14 13OK
u20.x86_64Ubuntu2018 17 16 15 14 13EOL
u20.aarch64Ubuntu2018 17 16 15 14 13EOL
u22.x86_64Ubuntu2218 17 16 15 14 13OK
u22.aarch64Ubuntu2218 17 16 15 14 13OK
u24.x86_64Ubuntu2418 17 16 15 14 13OK
u24.aarch64Ubuntu2418 17 16 15 14 13OK

Repo Configuration

EL YUM/DNF Repo

- { name: pgdg13         ,description: 'PostgreSQL 13'      ,module: pgsql   ,releases: [7,8,9,10]       ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/13/redhat/rhel-$releasever-$basearch' ,china: 'https://repo.pigsty.cc/yum/pgdg/13/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/13/redhat/rhel-$releasever-$basearch' }}
- { name: pgdg14         ,description: 'PostgreSQL 14'      ,module: pgsql   ,releases: [7,8,9,10]       ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/14/redhat/rhel-$releasever-$basearch' ,china: 'https://repo.pigsty.cc/yum/pgdg/14/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/14/redhat/rhel-$releasever-$basearch' }}
- { name: pgdg15         ,description: 'PostgreSQL 15'      ,module: pgsql   ,releases: [7,8,9,10]       ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/15/redhat/rhel-$releasever-$basearch' ,china: 'https://repo.pigsty.cc/yum/pgdg/15/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/15/redhat/rhel-$releasever-$basearch' }}
- { name: pgdg16         ,description: 'PostgreSQL 16'      ,module: pgsql   ,releases: [  8,9,10]       ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/16/redhat/rhel-$releasever-$basearch' ,china: 'https://repo.pigsty.cc/yum/pgdg/16/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/16/redhat/rhel-$releasever-$basearch' }}
- { name: pgdg17         ,description: 'PostgreSQL 17'      ,module: pgsql   ,releases: [  8,9,10]       ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/17/redhat/rhel-$releasever-$basearch' ,china: 'https://repo.pigsty.cc/yum/pgdg/17/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/17/redhat/rhel-$releasever-$basearch' }}
- { name: pgdg18         ,description: 'PostgreSQL 18'      ,module: pgsql   ,releases: [  8,9,10]       ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/18/redhat/rhel-$releasever-$basearch' ,china: 'https://repo.pigsty.cc/yum/pgdg/18/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/18/redhat/rhel-$releasever-$basearch' }}
- { name: pgdg19-beta    ,description: 'PostgreSQL 19 Beta' ,module: beta    ,releases: [  8,9,10]       ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/testing/19/redhat/rhel-$releasever-$basearch' ,china: 'https://repo.pigsty.cc/yum/pgdg/testing/19/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/testing/19/redhat/rhel-$releasever-$basearch' }}

Debian / Ubuntu APT Repo

- { name: pgdg           ,description: 'PGDG'               ,module: pgsql   ,releases: [11,12,13,   22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://apt.postgresql.org/pub/repos/apt/ ${distro_codename}-pgdg main'            ,china: 'https://repo.pigsty.cc/apt/pgdg/ ${distro_codename}-pgdg main' }}
- { name: pgdg-beta      ,description: 'PGDG Beta'          ,module: beta    ,releases: [11,12,13,   22,24] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://apt.postgresql.org/pub/repos/apt/ ${distro_codename}-pgdg-testing main 19' ,china: 'https://repo.pigsty.cc/apt/pgdg/ ${distro_codename}-pgdg-testing main 19' }}

APT GPG Key

PGDG APT repo is signed with the following GPG key: B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8 (ACCC4CF8)

MD5 checksum is f54c5c1aa1329dc26e33b29762faaec4, see https://www.postgresql.org/download/linux/debian/ for details.

sudo curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc
. /etc/os-release
sudo sh -c "echo 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $VERSION_CODENAME-pgdg main' > /etc/apt/sources.list.d/pgdg.list"
sudo curl -fsSL https://repo.pigsty.cc/apt/pgdg/ACCC4CF8.key -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc
. /etc/os-release
sudo sh -c "echo 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://repo.pigsty.cc/apt/pgdg/ $VERSION_CODENAME-pgdg main' > /etc/apt/sources.list.d/pgdg.list"

YUM GPG Key

PGDG YUM repo is signed with a series of keys from https://ftp.postgresql.org/pub/repos/yum/keys/. Please choose and use as needed.

21.2 - GPG Key

Import the GPG key for Pigsty repository

You can verify the integrity of the packages you download from Pigsty repository by checking the GPG signature. This document describes how to import the GPG key used to sign the packages.


Summary

All the RPM / DEB packages are signed with GPG key fingerprint (B9BD8B20) in Pigsty repository.

Full: 9592A7BC7A682E7333376E09E7935D8DB9BD8B20 Ruohang Feng (Pigsty) [email protected]

pub   rsa4096 2024-07-16 [SC]
      9592A7BC7A682E7333376E09E7935D8DB9BD8B20
uid           [ultimate] Ruohang Feng (Pigsty) <[email protected]>
sub   rsa4096 2024-07-16 [E]

You can find the public GPG key at: https://repo.pigsty.io/key or https://repo.pigsty.cc/key


Import

On RHEL compatible Linux distributions, you can import this key with the following command:

curl -fsSL https://repo.pigsty.io/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null
curl -fsSL https://repo.pigsty.cc/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

On Debian / Ubuntu compatible Linux distributions, you can import this key with the following command:

curl -fsSL https://repo.pigsty.io/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg
curl -fsSL https://repo.pigsty.cc/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

Public Key

The corresponding public key block is:

-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBGaV5PwBEACbErI+7yOrsXTT3mR83O6Fw9WyHJqozhyNPF3dA1gAtWpfWqd4
S9x6vBjVwUbIRn21jYgov0hDiaLABNQhRzifvVr0r1IjBW8lhA8zJGaO42Uz0aBW
YIkajOklsXgYMX+gSmy5WXzM31sDQVMnzptHh9dwW067hMM5pJKDslu2pLMwSb9K
QgIFcYsaR0taBkcDg4dNu1gncriD/GcdXIS0/V4R82DIYeIqj2S0lt0jDTACbUz3
C6esrTw2XerCeHKHb9c/V+KMhqvLJOOpy/aJWLrTGBoaH7xw6v0qg32OYiBxlUj9
VEzoQbDfbRkR+jlxiuYP3scUs/ziKrSh+0mshVbeuLRSNfuHLa7C4xTEnATcgD1J
MZeMaJXIcDt+DN+1aHVQjY5YNvr5wA3ykxW51uReZf7/odgqVW3+1rhW5pd8NQKQ
qoVUHOtIrC9KaiGfrczEtJTNUxcNZV9eBgcKHYDXB2hmR2pIf7WvydgXTs/qIsXg
SIzfKjisi795Dd5GrvdLYXVnu9YzylWlkJ5rjod1wnSxkI/CcCJaoPLnXZA9KV7A
cpMWWaUEXP/XBIwIU+vxDd1taBIaPIOv1KIdzvG7QqAQtf5Lphi5HfaGvBud/CVt
mvWhRPJMr1J0ER2xAgU2iZR7dN0vSF6zDqc0W09RAoC0nDS3tupDX2BrOwARAQAB
tCRSdW9oYW5nIEZlbmcgKFBpZ3N0eSkgPHJoQHZvbm5nLmNvbT6JAlEEEwEIADsW
IQSVkqe8emguczM3bgnnk12Nub2LIAUCZpXk/AIbAwULCQgHAgIiAgYVCgkICwIE
FgIDAQIeBwIXgAAKCRDnk12Nub2LIOMuEACBLVc09O4icFwc45R3KMvOMu14Egpn
UkpmBKhErjup0TIunzI0zZH6HG8LGuf6XEdH4ItCJeLg5349UE00BUHNmxk2coo2
u4Wtu28LPqmxb6sqpuRAaefedU6vqfs7YN6WWp52pVF1KdOHkIOcgAQ9z3ZHdosM
I/Y/UxO2t4pjdCAfJHOmGPrbgLcHSMpoLLxjuf3YIwS5NSfjNDd0Y8sKFUcMGLCF
5P0lv5feLLdZvh2Una34UmHKhZlXC5E3vlY9bf/LgsRzXRFQosD0RsCXbz3Tk+zF
+j/eP3WhUvJshqIDuY6eJYCzMjiA8sM5gety+htVJuD0mewp+qAhjxE0d4bIr4qO
BKQzBt9tT2ackCPdgW42VPS+IZymm1oMET0hgZfKiVpwsKO6qxeWn4RW2jJ0zkUJ
MsrrxOPFdZQAtuFcLwa5PUAHHs6XQT2vzxDpeE9lInQ14lshofU5ZKIeb9sbvb/w
P+xnDqvZ1pcotEIBvDK0S0jHbHHqtioIUdDFvdCBlBlYP1TQRNPlJ7TJDBBvhj8i
fmjQsYSV1u36aHOJVGYNHv+SyJpVd3nHCZn97ADM9qHnDm7xljyHXPzIx4FMmBGJ
UTiLH5yxa1xhWr42Iv3TykaQJVbpydmBuegFR8WbWitAvVqI3HvRG+FalLsjJruc
8YDAf7gHdj/937kCDQRmleT8ARAAmJxscC76NZzqFBiaeq2+aJxOt1HGPqKb4pbz
jLKRX9sFkeXuzhfZaNDljnr2yrnQ75rit9Aah/loEhbSHanNUDCNmvOeSEISr9yA
yfOnqlcVOtcwWQK57n6MvlCSM8Js3jdoSmCFHVtdFFwxejE5ok0dk1VFYDIg6DRk
ZBMuxGO7ZJW7TzCxhK4AL+NNYA2wX6b+IVMn6CA9kwNwCNrrnGHR1sblSxZp7lPo
+GsqzYY0LXGR2eEicgKd4lk38gaO8Q4d1mlpX95vgdhGKxR+CM26y9QU0qrO1hXP
Fw6lX9HfIUkVNrqAa1mzgneYXivnLvcj8gc7bFAdweX4MyBHsmiPm32WqjUJFAmw
kcKYaiyfDJ+1wusa/b+7RCnshWc8B9udYbXfvcpOGgphpUuvomKT8at3ToJfEWmR
BzToYYTsgAAX8diY/X53BHCE/+MhLccglEUYNZyBRkTwDLrS9QgNkhrADaTwxsv1
8PwnVKve/ZxwOU0QGf4ZOhA2YQOE5hkRDR5uY2OHsOS5vHsd9Y6kNNnO8EBy99d1
QiBJOW3AP0nr4Cj1/NhdigAujsYRKiCAuPT7dgqART58VU4bZ3PgonMlziLe7+ht
YYxV+wyP6LVqicDd0MLLvG7r/JOiWuABOUxsFFaRecehoPJjeAEQxnWJjedokXKL
HVOFaEkAEQEAAYkCNgQYAQgAIBYhBJWSp7x6aC5zMzduCeeTXY25vYsgBQJmleT8
AhsMAAoJEOeTXY25vYsgG8sP/3UdsWuiwTsf/x4BTW82K+Uk9YwZDnUNH+4dUMED
bKT1C6CbuSZ7Mnbi2rVsmGzOMs9MehIx6Ko8/iCR2OCeWi8Q+wM+iffAfWuT1GK6
7f/VIfoYBUWEa+kvDcPgEbd5Tu7ZdUO/jROVBSlXRSjzK9LpIj7GozBTJ8Vqy5x7
oqbWPPEYtGDVHime8o6f5/wfhNgL3mFnoq6srK7KhwACwfTXlNqAlGiXGa30Yj+b
Cj6IvmxoII49E67/ovMEmzDCb3RXiaL6OATy25P+HQJvWvAam7Qq5Xn+bZg65Mup
vXq3zoX0a7EKXc5vsJVNtTlXO1ATdYszKP5uNzkHrNAN52VRYaowq1vPy/MVMbSI
rL/hTFKr7ZNhmC7jmS3OuJyCYQsfEerubtBUuc/W6JDc2oTI3xOG1S2Zj8f4PxLl
H7vMG4E+p6eOrUGw6VQXjFsH9GtwhkPh/ZGMKENb2+JztJ02674Cok4s5c/lZFKz
mmRUcNjX2bm2K0GfGG5/hAog/CHCeUZvwIh4hZLkdeJ1QsIYpN8xbvY7QP6yh4VB
XrL18+2sontZ45MsGResrRibB35x7IrCrxZsVtRJZthHqshiORPatgy+AiWcAtEv
UWEnnC1xBSasNebw4fSE8AJg9JMCRw+3GAetlotOeW9q7PN6yrXD9rGuV/QquQNd
/c7w
=4rRi
-----END PGP PUBLIC KEY BLOCK-----

Usage

If you wish to distribute your own Repo with your own GPG key, here’s a tutorial:

Install GPG

brew install gnupg pinentry-mac
sudo apt install gnupg2 pinentry-curses
sudo dnf install gnupg2 pinentry-curses

Generate GPG Key

You can generate a GPG key with the following command:

gpg --full-generate-key

Import GPG Key

If you have a GPG Private key, you can just import it with:

gpg --import mykey.sec.as

List GPG Key

You can list GPG public keys and secret keys with the following commands:

$ gpg --list-key
[keyboxd]
---------
pub   rsa4096 2024-07-16 [SC]
      9592A7BC7A682E7333376E09E7935D8DB9BD8B20
uid           [ unknown] Ruohang Feng (Pigsty) <[email protected]>
sub   rsa4096 2024-07-16 [E]

$ gpg --list-secret-key
[keyboxd]
---------
sec   rsa4096 2024-07-16 [SC]
      9592A7BC7A682E7333376E09E7935D8DB9BD8B20
uid           [ unknown] Ruohang Feng (Pigsty) <[email protected]>
ssb   rsa4096 2024-07-16 [E]

Sign RPM Packages

If you wish to sign your RPM packages with a specific GPG key, you can specify the key in the ~/.rpmmacros file:

%_signature   gpg
%_gpg_path    ~/.gnupg
%_gpg_name    B9BD8B20
%_gpg_digest_algo  sha256
rpm --addsign yourpackage.rpm

Sign DEB Packages

To sign your DEB packages, add the key id to reprepro configuration:

Origin: Pigsty
Label: Pigsty INFRA
Codename: generic
Architectures: amd64 arm64
Components: main
Description: pigsty apt repository for infra components
SignWith: 9592A7BC7A682E7333376E09E7935D8DB9BD8B20

21.3 - INFRA Repo

Packages that are generic to any PostgreSQL version and Linux major version.

The pigsty-infra repo contains packages that are generic to any PostgreSQL version and Linux major version, including Prometheus & Grafana stack, admin tools for Postgres, and many utilities written in Go.

This repo is maintained by Ruohang Feng (Vonng) @ Pigsty, you can find all the build specs on https://github.com/pgsty/infra-pkg. Prebuilt RPM / DEB packages for RHEL / Debian / Ubuntu distros available for x86_64 and aarch64 arch. Hosted on Cloudflare CDN for free global access.

LinuxPackagex86_64aarch64
ELrpm
Debiandeb

You can check the Release - Infra Changelog for the latest updates.


Quick Start

You can add the pigsty-infra repo with the pig CLI tool, it will automatically choose from apt/yum/dnf.

curl https://repo.pigsty.io/pig | bash  # download and install the pig CLI tool
pig repo add infra                      # add pigsty-infra repo file to your system
pig repo update                         # update local repo cache with apt / dnf
# use when in mainland China or Cloudflare is down
curl https://repo.pigsty.cc/pig | bash  # install pig from China CDN mirror
pig repo add infra                      # add pigsty-infra repo file to your system
pig repo update                         # update local repo cache with apt / dnf
# you can manage infra repo with these commands:
pig repo add infra -u       # add repo file, and update cache
pig repo add infra -ru      # remove all existing repo, add repo and make cache
pig repo set infra          # = pigsty repo add infra -ru

pig repo add all            # add infra, node, pgsql repo to your system
pig repo set all            # remove existing repo, add above repos and update cache

Manual Setup

You can also use this repo directly without the pig CLI tool, by adding them to your Linux OS repo list manually:

APT Repo

On Debian / Ubuntu compatible Linux distros, you can add the GPG Key and APT repo file manually with:

# Add Pigsty's GPG public key to your system keychain to verify package signatures, or just trust
curl -fsSL https://repo.pigsty.io/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

# Get Debian distribution codename (distro_codename=jammy, focal, bullseye, bookworm)
# and write the corresponding upstream repository address to the APT List file
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-infra.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/infra generic main
EOF

# Refresh APT repository cache
sudo apt update
# use when in mainland China or Cloudflare is down
# Add Pigsty's GPG public key to your system keychain to verify package signatures, or just trust
curl -fsSL https://repo.pigsty.cc/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

# Get Debian distribution codename (distro_codename=jammy, focal, bullseye, bookworm)
# and write the corresponding upstream repository address to the APT List file
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-infra.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.cc/apt/infra generic main
EOF

# Refresh APT repository cache
sudo apt update
# If you don't want to trust any GPG key, just trust the repo directly
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-infra.list > /dev/null <<EOF
deb [trust=yes] https://repo.pigsty.io/apt/infra generic main
EOF

sudo apt update

YUM Repo

On RHEL compatible Linux distros, you can add the GPG Key and YUM repo file manually with:

# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.io/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

# Add Pigsty Repo definition files to /etc/yum.repos.d/ directory
sudo tee /etc/yum.repos.d/pigsty-infra.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.io/yum/infra/$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty
module_hotfixes=1
EOF

# Refresh YUM/DNF repository cache
sudo yum makecache;
# use when in mainland China or Cloudflare is down
# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.cc/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

# Add Pigsty Repo definition files to /etc/yum.repos.d/ directory
sudo tee /etc/yum.repos.d/pigsty-infra.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.cc/yum/infra/$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty
module_hotfixes=1
EOF

# Refresh YUM/DNF repository cache
sudo yum makecache;
# If you don't want to trust any GPG key, just trust the repo directly
sudo tee /etc/yum.repos.d/pigsty-infra.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.io/yum/infra/$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 0
module_hotfixes=1
EOF

sudo yum makecache;

Content

For a detailed list of all packages available in the Infra repository, see the Package List.

For the changelog and release history, see the Release Log.


Source

Building specs of this repo is open-sourced on GitHub:

If the platform is not supported, you can also build the packages from source code by yourself.

21.3.1 - Package List

Available packages in the Infra repository

Grafana Stack

NameVersionLicenseComment
grafana12.3.1AGPLv3Observability and visualization platform
loki3.1.1AGPLv3Log aggregation system (deprecated)
promtail3.0.0AGPLv3Loki log collection agent (deprecated)
grafana-infinity-ds3.6.0Apache-2.0JSON/CSV/XML datasource support
grafana-plugins12.3.0Apache-2.0Extra panel plugins by Pigsty

Victoria Stack

NameVersionLicenseComment
victoria-metrics1.132.0Apache-2.0High-performance TSDB, Prometheus alternative
victoria-logs1.43.1Apache-2.0High-performance log storage and query engine
victoria-traces0.5.1Apache-2.0Distributed tracing backend
victoria-metrics-cluster1.132.0Apache-2.0VictoriaMetrics distributed cluster
vmutils1.132.0Apache-2.0VictoriaMetrics CLI utilities
vlogscli1.43.1Apache-2.0VictoriaLogs interactive query client
vlagent1.43.1Apache-2.0VictoriaLogs log collection agent
grafana-victorialogs-ds0.23.2Apache-2.0VictoriaLogs Grafana datasource
grafana-victoriametrics-ds0.19.7Apache-2.0VictoriaMetrics Grafana datasource

Prometheus Stack

NameVersionLicenseComment
prometheus3.8.1Apache-2.0Cloud-native monitoring & TSDB
pushgateway1.11.2Apache-2.0Metrics push gateway for short-lived jobs
alertmanager0.30.0Apache-2.0Alert management & notification dispatch
blackbox_exporter0.27.0Apache-2.0Blackbox probing, endpoint availability

Metric Exporters

NameVersionLicenseComment
pg_exporter1.1.1Apache-2.0Advanced Postgres metrics exporter
pgbackrest_exporter0.22.0MITExpose pgbackrest metrics
node_exporter1.10.2Apache-2.0Expose Linux node metrics
keepalived_exporter1.7.0GPL-3.0Expose keepalived/VIP metrics
nginx_exporter1.5.1Apache-2.0Expose nginx metrics
zfs_exporter3.8.1MITExpose zfs metrics
mysqld_exporter0.18.0Apache-2.0Expose mysql metrics
redis_exporter1.80.1MITExpose redis metrics
kafka_exporter1.9.0Apache-2.0Expose kafka metrics
mongodb_exporter0.47.2Apache-2.0Expose mongodb metrics
mtail3.0.8Apache-2.0Parse logs and generate metrics
vector0.52.0MPL-2.0Versatile log collector

Object Storage

NameVersionLicenseComment
minio20251203120000AGPLv3FOSS S3 server, now built by pgsty
mcli20250813083541AGPLv3FOSS S3 client
rustfs1.0.0-a71Apache-2.0FOSS MinIO, Alpha
garage2.1.0AGPL-3.0Lightweight S3
seaweedfs4.01Apache-2.0S3 for small files
rclone1.72.1MITS3 command line tool
restic0.18.1BSD-2Backup tool
juicefs1.3.1Apache-2.0Filesystem over S3

Databases

PostgreSQL related tools, DBMS, and other utilities

NameVersionLicenseComment
etcd3.6.7Apache-2.0Fault-tolerant distributed coordination
kafka4.0.0Apache-2.0Message queue
duckdb1.4.3MITEmbedded OLAP
ferretdb2.7.0Apache-2.0MongoDB over PG
tigerbeetle0.16.65Apache-2.0Financial OLTP
IvorySQL5.1Apache-2.0Oracle compatible PG 18.1

Utilities

Pig package manager, PostgreSQL tools, and other database related utilities

NameVersionLicenseComment
pig0.9.0Apache-2.0PG package manager
vip-manager4.0.0BSD-2Bind L2 VIP to PG primary
pgflo0.0.15Apache-2.0Stream, transform, route PG data in real-time
pgschema1.4.2Apache-2.0Perform PG schema migration
pg_timetable6.2.0PostgreSQLAdvanced scheduling for PostgreSQL
timescaledb-tools0.18.1Apache-2.0Optimize timescaledb params
timescaledb-event-streamer0.20.0Apache-2.0CDC on timescaledb hypertable
dblab0.34.2MITMulti-database CLI tool
sqlcmd1.8.0MITMS SQL Server CLI client
pev21.19.0PostgreSQLPostgreSQL explain visualizer 2
sealos5.0.1Apache-2.0Battery-included Kubernetes distribution
vray5.28.0MITBuild proxies to bypass network restrictions
asciinema3.0.1GPL-3.0Terminal session recording and playback
postgrest14.3MITRESTful API for PostgreSQL
npgsqlrest3.3.3MIT.NET REST API generator for PostgreSQL

AI Coding

AI Agent, MCP tools, python package manager, web IDE, etc…

NameVersionLicenseComment
claude2.1.1ProprietaryClaude Code - Anthropic’s agentic coding tool
opencode1.0.223MITTerminal-based AI coding assistant
code-server4.107.0MITVS Code in the browser
genai-toolbox0.24.0Apache-2.0Google database MCP server
uv0.9.18MITNext-gen Python package manager
golang1.25.5BSD-3Go compiler
nodejs24.12.0MIT/MixedRun Javascript on serverside

21.3.2 - Release Log

pigsty-infra repository changelog and observability package release notes

2026-01-08

NameOld VerNew VerNote
pg_exporter1.1.01.1.1new pg_timeline collector
npgsqlrest-3.3.3new
postgrest-14.3new
opencode1.0.223new
code-server4.107.0new
claude2.0.762.1.1update
genai-toolbox0.23.00.24.0remove broken oracle driver
golang-1.25.5new
nodejs-24.12.0new

2025-12-25

NameOld VerNew VerNote
pig0.8.00.9.0routine update
etcd3.6.63.6.7routine update
uv-0.9.18new python package manager
ccm-2.0.76new claude code
asciinema-3.0.1new terminal recorder
ivorysql5.05.1
grafana12.3.012.3.1
vector0.51.10.52.0
prometheus3.8.03.8.1
alertmanager0.29.00.30.0
victoria-logs1.41.01.43.1
pgbackrest_exporter0.21.00.22.0
grafana-victorialogs-ds0.22.40.23.2

2025-12-16

NameOld VerNew VerNote
victoria-metrics1.131.01.132.0
victoria-logs1.40.01.41.0
blackbox_exporter0.27.00.28.0
duckdb1.4.21.4.3
rclone1.72.01.72.1
pev21.17.01.19.0
pg_exporter1.0.31.1.0
pig0.7.40.8.0
genai-toolbox0.22.00.23.0
minio2025090716130920251203120000by pgsty

2025-12-04

NameOld VerNew VerNote
rustfs-1.0.0-a71new
seaweedfs-4.1.0new
garage-2.1.0new
rclone1.71.21.72.0
vector0.51.00.51.1
prometheus3.7.33.8.0
victoria-metrics0.130.00.131.0
victoria-logs0.38.00.40.0
victoria-traces-0.5.1new
grafana-victorialogs-ds0.22.10.22.4
redis_exporter1.80.01.80.1
mongodb_exporter0.47.10.47.2
genai-toolbox0.21.00.22.0

2025-11-23

NameOld VerNew VerNote
pgschema-1.4.2new
pgflo-0.0.15new
vector0.51.00.51.1bug fix
sealos5.0.15.1.1
etcd3.6.53.6.6
duckdb1.4.11.4.2
pg_exporter1.0.21.0.3
pig0.7.10.7.2
grafana12.1.012.3.0
pg_timetable6.1.06.2.0
genai-toolbox0.16.00.21.0
timescaledb-tools0.18.00.18.1moved from PGSQL to INFRA
timescaledb-event-streamer0.12.00.20.0
tigerbeetle0.16.600.16.65
victoria-metrics1.129.11.130.0
victoria-logs1.37.21.38.0
grafana-victorialogs-ds0.21.40.22.1
grafana-victoriametrics-ds0.19.60.19.7
grafana-plugins12.0.012.3.0

2025-11-11

NameOld VerNew VerNote
grafana12.1.012.2.1download url change
prometheus3.6.03.7.3
pushgateway1.11.11.11.2
alertmanager0.28.10.29.0
nginx_exporter1.5.01.5.1
node_exporter1.9.11.10.2
pgbackrest_exporter0.20.00.21.0
redis_exporter1.77.01.80.0
duckdb1.4.01.4.1
dblab0.33.00.34.2
pg_timetable5.13.06.1.0
vector0.50.00.51.0
rclone1.71.11.71.2
victoria-metrics1.126.01.129.1
victoria-logs1.35.01.37.2
grafana-victorialogs-ds0.21.00.21.4
grafana-victoriametrics-ds0.19.40.19.6
grafana-infinity-ds3.5.03.6.0
genai-toolbox0.16.00.18.0
pev21.16.01.17.0
pig0.6.20.7.1

2025-10-18

NameOld VerNew VerNote
prometheus3.5.03.6.0
nginx_exporter1.4.21.5.0
mysqld_exporter0.17.20.18.0
redis_exporter1.75.01.77.0
mongodb_exporter0.47.00.47.1
victoria-metrics1.121.01.126.0
victoria-logs1.25.11.35.0
duckdb1.3.21.4.0
etcd3.6.43.6.5
restic0.18.00.18.1
tigerbeetle0.16.540.16.60
grafana-victorialogs-ds0.19.30.21.0
grafana-victoriametrics-ds0.18.30.19.4
grafana-infinity-ds3.3.03.5.0
genai-toolbox0.9.00.16.0
grafana12.1.012.2.0
vector0.49.00.50.0
rclone1.70.31.71.1
minio2025072315540220250907161309
mcli2025072105280820250813083541

2025-08-15

NameOld VerNew VerNote
grafana12.0.012.1.0
pg_exporter1.0.11.0.2
pig0.6.00.6.1
vector0.48.00.49.0
redis_exporter1.74.01.75.0
mongodb_exporter0.46.00.47.0
victoria-metrics1.121.01.123.0
victoria-logs1.25.01.28.0
grafana-victoriametrics-ds0.17.00.18.3
grafana-victorialogs-ds0.18.30.19.3
grafana-infinity-ds3.3.03.4.1
etcd3.6.13.6.4
ferretdb2.3.12.5.0
tigerbeetle0.16.500.16.54
genai-toolbox0.9.00.12.0

2025-07-24

NameOld VerNew VerNote
ferretdb-2.4.0pair with documentdb 1.105
etcd-3.6.3
minio-20250723155402
mcli-20250721052808
ivorysql-4.5-0ffca11-20250709fix libxcrypt dep issue

2025-07-16

NameOld VerNew VerNote
genai-toolbox0.8.00.9.0MCP toolbox for various DBMS
victoria-metrics1.120.01.121.0split into various packages
victoria-logs1.24.01.25.0split into various packages
prometheus3.4.23.5.0
duckdb1.3.11.3.2
etcd3.6.13.6.2
tigerbeetle0.16.480.16.50
grafana-victoriametrics-ds0.16.00.17.0
rclone1.69.31.70.3
pig0.5.00.6.0
pev21.15.01.16.0
pg_exporter1.0.01.0.1

2025-07-04

NameOld VerNew VerNote
prometheus3.4.13.4.2
grafana12.0.112.0.2
vector0.47.00.48.0
rclone1.69.01.70.2
vip-manager3.0.04.0.0
blackbox_exporter0.26.00.27.0
redis_exporter1.72.11.74.0
duckdb1.3.01.3.1
etcd3.6.03.6.1
ferretdb2.2.02.3.1
dblab0.32.00.33.0
tigerbeetle0.16.410.16.48
grafana-victorialogs-ds0.16.30.18.1
grafana-victoriametrics-ds0.15.10.16.0
grafana-infinity-ds3.2.13.3.0
victoria-logs1.22.21.24.0
victoria-metrics1.117.11.120.0

2025-06-01

NameOld VerNew VerNote
grafana-12.0.1
prometheus-3.4.1
keepalived_exporter-1.7.0
redis_exporter-1.73.0
victoria-metrics-1.118.0
victoria-logs-1.23.1
tigerbeetle-0.16.42
grafana-victorialogs-ds-0.17.0
grafana-infinity-ds-3.2.2

2025-05-22

NameOld VerNew VerNote
dblab-0.32.0
prometheus-3.4.0
duckdb-1.3.0
etcd-3.6.0
pg_exporter-1.0.0
ferretdb-2.2.0
rclone-1.69.3
minio-20250422221226last version with admin GUI
mcli-20250416181326
nginx_exporter-1.4.2
keepalived_exporter-1.6.2
pgbackrest_exporter-0.20.0
redis_exporter-1.27.1
victoria-metrics-1.117.1
victoria-logs-1.22.2
pg_timetable-5.13.0
tigerbeetle-0.16.41
pev2-1.15.0
grafana-12.0.0
grafana-victorialogs-ds-0.16.3
grafana-victoriametrics-ds-0.15.1
grafana-infinity-ds-3.2.1
grafana-plugins-12.0.0

2025-04-23

NameOld VerNew VerNote
mtail-3.0.8new
pig-0.4.0
pg_exporter-0.9.0
prometheus-3.3.0
pushgateway-1.11.1
keepalived_exporter-1.6.0
redis_exporter-1.70.0
victoria-metrics-1.115.0
victoria-logs-1.20.0
duckdb-1.2.2
pg_timetable-5.12.0
vector-0.46.1
minio-20250422221226
mcli-20250416181326

2025-04-05

NameOld VerNew VerNote
pig-0.3.4
etcd-3.5.21
restic-0.18.0
ferretdb-2.1.0
tigerbeetle-0.16.34
pg_exporter-0.8.1
node_exporter-1.9.1
grafana-11.6.0
zfs_exporter-3.8.1
mongodb_exporter-0.44.0
victoria-metrics-1.114.0
minio-20250403145628
mcli-20250403170756

2025-03-23

NameOld VerNew VerNote
etcd-3.5.20
pgbackrest_exporter-0.19.0rebuilt
victoria-logs-1.17.0
vlogscli-1.17.0

2025-03-17

NameOld VerNew VerNote
kafka-4.0.0
prometheus-3.2.1
alertmanager-0.28.1
blackbox_exporter-0.26.0
node_exporter-1.9.0
mysqld_exporter-0.17.2
kafka_exporter-1.9.0
redis_exporter-1.69.0
duckdb-1.2.1
etcd-3.5.19
ferretdb-2.0.0
tigerbeetle-0.16.31
vector-0.45.0
victoria-metrics-1.114.0
victoria-logs-1.16.0
rclone-1.69.1
pev2-1.14.0
grafana-victorialogs-ds-0.16.0
grafana-victoriametrics-ds-0.14.0
grafana-infinity-ds-3.0.0
timescaledb-event-streamer-0.12.0new
restic-0.17.3new
juicefs-1.2.3new

2025-02-12

NameOld VerNew VerNote
pushgateway1.10.01.11.0
alertmanager0.27.00.28.0
nginx_exporter1.4.01.4.1
pgbackrest_exporter0.18.00.19.0
redis_exporter1.66.01.67.0
mongodb_exporter0.43.00.43.1
victoria-metrics1.107.01.111.0
victoria-logs1.3.21.9.1
duckdb1.1.31.2.0
etcd3.5.173.5.18
pg_timetable5.10.05.11.0
ferretdb1.24.02.0.0
tigerbeetle0.16.130.16.27
grafana11.4.011.5.1
vector0.43.10.44.0
minio2024121813154420250207232109
mcli2024112117215420250208191421
rclone1.68.21.69.0

2024-11-19

NameOld VerNew VerNote
prometheus2.54.03.0.0
victoria-metrics1.102.11.106.1
victoria-logs0.28.01.0.0
mysqld_exporter0.15.10.16.0
redis_exporter1.62.01.66.0
mongodb_exporter0.41.20.42.0
keepalived_exporter1.3.31.4.0
duckdb1.1.21.1.3
etcd3.5.163.5.17
tigerbeetle16.80.16.13
grafana-11.3.0
vector-0.42.0

21.4 - PGSQL Repo

The repo for PostgreSQL Extensions & Kernel Forks

The pigsty-pgsql repo contains packages that are ad hoc to specific PostgreSQL Major Versions (often ad hoc to a specific Linux distro major version, too). Including extensions and some kernel forks.

You can check the Release - RPM Changelog / Release - DEB Changelog for the latest updates.


Compatibility

OS / ArchOSx86_64aarch64
EL8el818 17 16 15 14 1318 17 16 15 14 13
EL9el918 17 16 15 14 1318 17 16 15 14 13
EL10el1018 17 16 15 14 1318 17 16 15 14 13
Debian 12d1218 17 16 15 14 1318 17 16 15 14 13
Debian 13d1318 17 16 15 14 1318 17 16 15 14 13
Ubuntu 22.04u2218 17 16 15 14 1318 17 16 15 14 13
Ubuntu 24.04u2418 17 16 15 14 1318 17 16 15 14 13

Quick Start

PIG

You can install pig - the CLI tool, and add pgdg / pigsty repo with it (recommended):

pig repo add pigsty                         # add pigsty-pgsql repo
pig repo add pigsty -u                      # add pigsty-pgsql repo, and update cache
pig repo add pigsty -u --region=default     # add pigsty-pgsql repo and enforce default region (pigsty.io)
pig repo add pigsty -u --region=china       # add pigsty-pgsql repo with china region   (pigsty.cc)
pig repo add pgsql -u                       # pgsql = pgdg + pigsty-pgsql (add pigsty + official PGDG)
pig repo add -u                             # all = node + pgsql (pgdg + pigsty) + infra

Hint: If you are in mainland China, consider using the China CDN mirror (replace pigsty.io with pigsty.cc)

APT

You can also enable this repo with apt directly on Debian / Ubuntu:

# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.io/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

# Get Debian distribution codename (distro_codename=jammy, focal, bullseye, bookworm), and write the corresponding upstream repository address to the APT List file
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-io.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/pgsql/${distro_codename} ${distro_codename} main
EOF

# Refresh APT repository cache
sudo apt update
# Use when in mainland China or Cloudflare is unavailable
# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.cc/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

# Get Debian distribution codename, and write the corresponding upstream repository address to the APT List file
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-io.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.cc/apt/pgsql/${distro_codename} ${distro_codename} main
EOF

# Refresh APT repository cache
sudo apt update

DNF

You can also enable this repo with dnf/yum directly on EL-compatible systems:

# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.io/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

# Add Pigsty Repo definition files to /etc/yum.repos.d/ directory, including two repositories
sudo tee /etc/yum.repos.d/pigsty-pgsql.repo > /dev/null <<-'EOF'
[pigsty-pgsql]
name=Pigsty PGSQL For el$releasever.$basearch
baseurl=https://repo.pigsty.io/yum/pgsql/el$releasever.$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty
module_hotfixes=1
EOF

# Refresh YUM/DNF repository cache
sudo dnf makecache;
# Use when in mainland China or Cloudflare is unavailable
# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.cc/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

# Add Pigsty Repo definition files to /etc/yum.repos.d/ directory
sudo tee /etc/yum.repos.d/pigsty-pgsql.repo > /dev/null <<-'EOF'
[pigsty-pgsql]
name=Pigsty PGSQL For el$releasever.$basearch
baseurl=https://repo.pigsty.cc/yum/pgsql/el$releasever.$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty
module_hotfixes=1
EOF

# Refresh YUM/DNF repository cache
sudo dnf makecache;

Source

Building specs of this repo is open-sourced on GitHub:

If the platform is not supported, you can also build the packages from source code by yourself.

The pig build provides an easy way to build extension RPM/DEB on your own systems.

21.4.1 - DNF Changelog

PostgreSQL and Extension RPM package changelog and release notes

2025-12-25

NameOld VerNew VerNote
pg_duckdb1.1.01.1.1
pg_search0.20.40.20.5
vchord_bm250.2.20.3.0
pg_semver0.40.00.41.0
pg_timeseries0.1.70.1.8

2025-12-16

NameOld VerNew VerNote
pg_textsearch-0.1.0new extension
pg_clickhouse-0.1.0new extension
pg_ai_query-0.1.1new extension
timescaledb2.23.12.24.0
pg_search0.20.00.20.4
pg_duckdb1.1.0-11.1.0-2official release
pg_biscuit1.02.0.1switch to new repo
pg_convert0.0.40.0.5removed pg13 support
pgdd0.6.00.6.1removed pg13 support
pglinter1.0.01.0.1
pg_session_jwt0.3.30.4.0
pg_anon2.4.12.5.1
pg_enigma0.4.00.5.0
wrappers0.5.60.5.7
pg_vectorize0.25.00.26.0
synchdb-1.3EL9 only

2025-11-20

NameOld VerNew VerNote
vchord0.5.31.0.0
pg_later0.3.10.4.0
pgvectorscale0.8.00.9.0-pg13, +pg18
pglite_fusion0.0.50.0.6
pgx_ulid0.2.10.2.2
pg_search0.19.50.19.7resume PIGSTY building
citus13.2.013.2.0official tag build
timescaledb2.23.02.23.1
pg_profile4.104.11
pglinter1.0.0new
pg_typeid0.3.0align pg18 support
pg_enigma0.4.0vonng patched pgrx version
pg_retry1.0.0new, pg17-18
pg_biscuit1.0new, pg16-18
pg_weighted_statistics1.0.0new, pg13-18
pg_stat_monitor2.2.02.3.0fix PGDG pg18 missing issue
documentdb0.1060.107ferretdb fork
polardb15.1515.15.5.0-38948055

2025-11-10

Add PostgreSQL 18 support for almost all extensions

NameOld VerNew VerNote
omni_csv-0.1.1new ext
omni_datasets-0.1.0new ext
omni_shmem-0.1.0new ext
pg_csv-1.0.1new ext
pg_dbms_errlog-2.2new ext
pg_rrule-0.2.0new ext
plxslt-0.20140221new ext
anon2.3.02.4.1+pg18
collection1.0.01.1.0+pg18
credcheck3.04.2+pg18
emaj4.7.04.7.1+pg18
explain_ui0.0.10.0.2+pg18
firebird_fdw1.4.01.4.1+pg18
logerrors2.1.32.1.5+pg18
multicorn3.03.2+pg18
omni0.2.90.2.14+pg18
omni_email00.1.0+pg18
omni_httpc0.1.50.1.10+pg18
omni_httpd0.4.60.4.11+pg18
omni_id0.4.20.4.3+pg18
omni_kube0.1.10.4.2+pg18
omni_ledger0.1.20.1.3+pg18
omni_sql0.5.10.5.3+pg18
omni_sqlite0.1.20.2.2+pg18
omni_types0.3.40.3.6+pg18
omni_vfs0.2.10.2.2+pg18
omni_worker0.1.00.2.1+pg18
periods1.2.21.2.3+pg18
pg_bestmatch0.0.10.0.2+pg18
pg_cardano1.0.51.1.1+pg18
pg_checksums1.11.3+pg18
pg_duckdb0.3.11.1.0+pg18
pg_failover_slots1.1.01.2.0+pg18
pg_graphql1.5.111.5.12+pg18
pg_idkit0.3.10.4.0+pg18
pg_later0.3.00.3.1+pg18
pg_mooncake0.1.20.2.0+pg18
pg_net0.9.20.20.0+pg18
pg_parquet0.4.30.5.1+pg18
pg_render0.1.20.1.3+pg18
pg_session_jwt0.3.10.3.3+pg18
pg_smtp_client0.2.00.2.1+pg18
pg_sphere1.5.11.5.2+pg18
pg_statement_rollback1.41.5+pg18
pg_store_plans1.81.9+pg18
pg_tle1.5.11.5.2+pg18
pg_tokenizer0.1.00.1.1+pg18
pg_uuidv71.6.01.7.0+pg18
pgactive2.1.62.1.7+pg18
pglogical2.4.52.4.6+pg18
pglogical_origin2.4.52.4.6+pg18
pgmq1.5.11.7.0+pg18
pgsmcrypto0.1.00.1.1+pg18
pgx_ulid0.2.00.2.1+pg18
pldbgapi1.81.9+pg18
pljava1.6.81.6.10+pg18
plprql1.0.018.0.0+pg18
roaringbitmap0.5.40.5.5+pg18
semver0.32.10.40.0+pg18
supautils2.10.03.0.2+pg18
tds_fdw2.0.42.0.5+pg18
timescaledb2.22.02.23.0+pg18
timescaledb_toolkit1.21.01.22.0+pg18
timeseries0.1.60.1.7+pg18
pg_tzf0.2.20.2.3+pg18
vchord0.5.10.5.3+pg18
vchord_bm250.2.10.2.2+pg18
vectorize0.22.20.25.0+pg18
wrappers0.5.40.5.6+pg18
gzip1.0.11.0.0+pg18
hypopg1.4.11.4.2+pg18
mobilitydb1.2.01.3.0+pg18
mongo_fdw5.5.15.5.3+pg18
orafce4.14.44.14.6+pg18
pg_hint_plan1.7.11.8.0+pg18
pg_ivm1.111.13+pg18
pg_partman5.2.45.3.1+pg18
pg_search0.18.10.19.2+pg18
pg_show_plans2.1.62.1.7+pg18
pgpcre10.20190509+pg18
pgroonga4.0.04.0.4+pg18
pgroonga_database4.0.04.0.4+pg18
plpgsql_check2.8.22.8.3+pg18
uint1.202312061.20250815+pg18
uint1281.1.01.1.1+pg18
omni_*2025052520251108+pg18
acl1.0.4+pg18
aggs_for_arrays1.3.3+pg18
aggs_for_vecs1.4.0+pg18
arraymath1.1+pg18
asn1oid1.6+pg18
aws_s30.0.1+pg18
base361.0.0+pg18
base620.0.1+pg18
bzip1.0.0+pg18
chkpass1.0+pg18
convert0.0.4+pg18
count_distinct3.0.2+pg18
country0.0.3+pg18
cryptint1.0.0+pg18
currency0.0.3+pg18
data_historization1.1.0+pg18
db_migrator1.0.0+pg18
dbt20.61.7+pg18
ddl_historization0.0.7+pg18
ddsketch1.0.1+pg18
decoder_raw1.0+pg18
decoderbufs3.2.0+pg18
emailaddr0+pg18
envvar1.0.1+pg18
faker0.5.3+pg18
financial1.0.1+pg18
fio1.0+pg18
first_last_agg0.1.4+pg18
floatfile1.3.1+pg18
floatvec1.1.1+pg18
geoip0.3.0+pg18
hashlib1.1+pg18
hashtypes0.1.5+pg18
hll2.18+pg18
hunspell_*1.0+pg18
imgsmlr1.0+pg18
index_advisor0.2.0+pg18
kafka_fdw0.0.3+pg18
login_hook1.7+pg18
oracle_fdw2.8.0+pg18
pg_auth_mon3.0+pg18
pg_background1.3+pg18
pg_bigm1.2+pg18
pg_cron1.6.7+pg18
pg_profile4.10+pg18
pg_stat_kcache2.3.0+pg18
pgdd0.6.0+pg18
pgjwt0.2.0+pg18
pgnodemx1.7+pg18
pgsodium3.1.9+pg18
pgtap1.3.3+pg18
plprofiler4.2.5+pg18
plproxy2.11.0+pg18
plr8.4.8+pg18
plv83.2.4+pg18
pointcloud1.2.5+pg18
powa5.0.1+pg18
prefix1.2.10+pg18
q3c2.0.1+pg18
redis_fdw1.0+pg18
session_variable3.4+pg18
set_user4.1.0+pg18
system_stats3.2+pg18
temporal_tables1.2.2+pg18
topn2.7.0+pg18
unit7.10+pg18
zhparser2.3+pg18
zstd1.1.2+pg18

2025-09-04

NameOld VerNew VerNote
timescaledb2.21.12.22.0
citus13.1.013.2.0
documentdb0.105.00.106.0work with ferretdb 2.5
ddlx0.290.30+ pg18
icu_ext1.9.01.10.0+ pg18
asn1oid1.51.6+ pg18
uint1281.0.01.1.0+ pg18
toastinfo1.51.6+ pg18
vchord0.4.30.5.1pgrx 0.16.0
pg_idkit0.3.00.3.1pgrx 0.15.0
pg_search0.17.30.18.0pgrx 0.15.0
pg_parquet0.4.00.4.3pgrx 0.16.0
wrappers0.5.30.5.4pgrx 0.14.3
pg_rewrite-2.0.0+ Debian/Ubuntu (PGDG)
pg_tracing-0.1.3-2+ pg 14/18
pg_curl2.42.4.5new version epoch
pg_rewrite-2.0.0Import from PGDG
pg_tracing-1.3.0+ pg14 / pg18
pgactive2.1.52.1.6+ pg18
pgsentinel1.11.21.2
pg_tle1.5.1-11.5.1-2+ pg18
redis_fdw+ pg18
pgextwlist1.171.19+ pg18
wal2json1.6+ pg18
pgvector0.8.1+ pg18

2025-07-24

NameOld VerNew VerNote
orioledbbeta11 1.4beta12 1.5pair with oriolepg 17.11
oriolepg17.917.11pair with orioledb 1.5 beta12
documentdb0.104.00.105.0pair with ferretdb 2.4
timescaledb2.20.02.21.1
supautils2.9.22.10.0.so location changed
plv83.2.33.2.4
postgresql_anonymizer3.1.12.3.0(pgrx 0.14.3)
wrappers0.5.00.5.3(pgrx 0.14.3) pgrx change
pgvectorscale0.7.10.8.0(pgrx 0.12.9)
pg_search0.15.80.17.0fix el icu dep, download

2025-06-24

NameOld VerNew VerNote
citus13.0.313.1.0
timescaledb2.20.02.21.0
vchord0.3.00.4.3
pgactive-2.1.5requires pgfeutils
documentdb0.103.00.104.0add arm support

2025-05-26

NameOld VerNew VerNote
pgdd0.5.00.6.0
convert-0.0.4
pg_idkit0.2.00.3.0
pg_tokenizer-0.1.0
pg_render-0.1.2
pgx_ulid-0.2.0
orioledb1.4.0b101.4.0b11

2025-05-22

NameOld VerNew VerNote
openhalodb-14.10
spat-0.1.0a4
pgsentinel-1.1.0
timescaledb-2.20.0
sqlite_fdw-2.5.0
documentdb-0.103.0
pg_tzf-0.2.2
pg_vectorize-0.22.2
wrappers-0.5.0

2025-05-07

NameOld VerNew VerNote
omnigres-20250507
citus-12.0.3
timescaledb-2.19.3
supautils-2.9.1
pg_envvar-1.0.1
pgcollection-1.0.0
aggs_for_vecs-1.4.0
pg_tracing-0.1.3
pgmq-1.5.1
pg_tzf-0.2.0
pg_search-0.15.18
anon-2.1.1
pg_parquet-0.4.0
pg_cardano-1.0.5
pglite_fusion-0.0.5
vchord_bm25-0.2.1
vchord-0.3.0
timescaledb_toolkit-1.21.0
pgvectorscale-0.7.1
pg_session_jwt-0.3.1

2025-03-20

NameOld VerNew VerNote
timescaledb-2.19.0
citus-13.0.2
documentdb-1.102
pg_analytics-0.3.7
pg_search-0.15.8
emaj-4.6.0
pgsql_tweaks-0.11.0
pgvectorscale-0.6.0
pg_session_jwt-0.2.0
wrappers-0.4.5
pg_parquet-0.3.1
vchord-0.2.2
pg_tle1.2.01.5.0
supautils2.5.02.6.0
sslutils1.31.4
pg_profile4.74.8
pg_jsonschema0.3.20.3.3
pg_incremental1.1.11.2.0
ddl_historization0.70.0.7
pg_sqlog3.1.71.6
pg_random--
pg_stat_monitor2.1.02.1.1
pg_profile4.74.8

2024-10-16

NameOld VerNew VerNote
pg_timeseries-0.1.6
pgmq-1.4.4
pg_protobuf-16 17
pg_uuidv7-1.6
pg_readonly-latest
pgddl-0.28
pg_safeupdate-latest
pg_stat_monitor-2.1
pg_profile-4.7
system_stats-3.2
pg_auth_mon-3.0
login_hook-1.6
logerrors-2.1.3
pg_orphaned-latest
pgnodemx-1.7
sslutils-1.4+pg16, +pg17

21.4.2 - APT Changelog

PostgreSQL and Extension DEB package changelog and release notes

2025-12-25

NameOld VerNew VerNote
pg_duckdb1.1.01.1.1
pg_search0.20.40.20.5
vchord_bm250.2.20.3.0
pg_semver0.40.00.41.0
pg_timeseries0.1.70.1.8
supautils3.0.2-13.0.2-2fix pg18
pg_summarize0.0.1-10.0.1-2fix pg18

2025-12-16

NameOld VerNew VerNote
pg_textsearch-0.1.0new
pg_clickhouse-0.1.0new
pg_ai_query-0.1.1new
timescaledb2.23.12.24.0
pg_search0.20.00.20.4
pg_duckdb1.1.0-11.1.0-2official release
pg_biscuit1.02.0.1new repo
pg_convert0.0.40.0.5removed pg13 support
pgdd0.6.00.6.1removed pg13 support
pglinter1.0.01.0.1
pg_session_jwt0.3.30.4.0
pg_anon2.4.12.5.1
pg_enigma0.4.00.5.0
wrappers0.5.60.5.7
pg_vectorize0.25.00.26.0fix pg18
pg_tiktoken--fix pg18
pg_tzf--fix pg18
pglite_fusion--fix pg18
pgsmcrypto--fix pg18
pgx_ulid--fix pg18
plprql--fix pg18
synchdb-1.3Ubuntu 22/24 only

2025-11-20

NameOld VerNew VerNote
vchord0.5.31.0.0
pg_later0.3.10.4.0
pgvectorscale0.8.00.9.0-pg13, +pg18
pglite_fusion0.0.50.0.6
pgx_ulid0.2.10.2.2
pg_search0.19.50.19.7resume PIGSTY building
citus13.2.013.2.0official tag
timescaledb2.23.02.23.1
pg_profile4.104.11
pglinter1.0.0new
pg_typeid0.3.0head with pg18 support
pg_enigma0.4.0vonng patched pgrx version
pg_retry1.0.0new, pg17-18
pg_biscuit1.0new, pg16-18
pg_weighted_statistics1.0.0new, pg13-18
documentdb0.1060.107ferretdb fork
polardb15.1515.15.5.0-38948055

2025-11-10

Add PostgreSQL 18 support for almost all extensions

NameOld VerNew VerNote
omni_csv-0.1.1new
omni_datasets-0.1.0new
omni_shmem-0.1.0new
pg_csv-1.0.1new
pljs-1.0.3new
plxslt-0.20140221new
credcheck3.04.2+pg18
dbt20.45.00.61.7+pg18
h34.1.34.2.3+pg18
h3_postgis4.1.34.2.3+pg18
mongo_fdw1.15.5.3+pg18
multicorn3.03.2+pg18
orafce4.14.44.14.6+pg18
pg_hint_plan1.7.01.8.0+pg18
pg_search0.18.10.19.2+pg18
pg_show_plans2.1.62.1.7+pg18
pgactive2.1.62.1.7+pg18
pgpcre10.20190509+pg18
plpgsql_check2.8.22.8.3+pg18
roaringbitmap0.5.40.5.5+pg18
uint1.202312061.20250815+pg18
uint1281.1.01.1.1+pg18
anon2.3.02.4.1+pg18
collection1.0.01.1.0+pg18
emaj4.7.04.7.1+pg18
explain_ui0.0.10.0.2+pg18
firebird_fdw1.4.01.4.1+pg18
login_hook1.61.7+pg18
logerrors2.1.32.1.5+pg18
mobilitydb1.2.01.3.0+pg18
omni0.2.90.2.14+pg18
omni_httpc0.1.50.1.10+pg18
omni_httpd0.4.60.4.11+pg18
omni_kube0.1.10.4.2+pg18
omni_sql0.5.10.5.3+pg18
omni_sqlite0.1.20.2.2+pg18
omni_worker0.1.00.2.1+pg18
pg_cardano1.0.51.1.1+pg18
pg_checksums1.21.3+pg18
pg_cron1.6.51.6.7+pg18
pg_duckdb0.3.11.1.0+pg18
pg_failover_slots1.1.01.2.0+pg18
pg_graphql1.5.111.5.12+pg18
pg_idkit0.3.10.4.0+pg18
pg_mooncake0.1.20.2.0+pg18
pg_net0.9.20.20.0+pg18
pg_parquet0.4.30.5.1+pg18
pg_partman5.2.45.3.0+pg18
pg_session_jwt0.3.10.3.3+pg18
pg_sphere1.5.11.5.2+pg18
pg_stat_monitor2.2.02.3.0+pg18
pg_statement_rollback1.41.5+pg18
pg_store_plans1.81.9+pg18
pg_task1.0.02.1.12+pg18
pg_tle1.5.11.5.2+pg18
pg_uuidv71.6.01.7.0+pg18
pglogical2.4.52.4.6+pg18
pgmq1.5.11.7.0+pg18
pgroonga4.0.04.0.4+pg18
pgsql_tweaks0.11.31.0.2+pg18
pldbgapi1.81.9+pg18
plprql1.0.018.0.0+pg18
supautils2.10.03.0.2+pg18
timescaledb2.22.02.23.0+pg18
timescaledb_toolkit1.21.01.22.0+pg18
vchord0.5.10.5.3+pg18
vectorize0.22.20.25.0+pg18
wrappers0.5.40.5.6+pg18
acl1.0.4-+pg18
aggs_for_arrays1.3.3-+pg18
aggs_for_vecs1.4.0-+pg18
base361.0.0-+pg18
hashlib1.1-+pg18
hll2.18-+pg18
imgsmlr1.0-+pg18
index_advisor0.2.0-+pg18
kafka_fdw0.0.3-+pg18
pg_auth_mon3.0-+pg18
pg_background1.3-+pg18
pg_bigm1.2-+pg18
pg_profile4.10-+pg18
pg_stat_kcache2.3.0-+pg18
pgdd0.6.0-+pg18
pgjwt0.2.0-+pg18
pgmp1.0.5-+pg18
plprofiler4.2.5-+pg18
plv83.2.4-+pg18
redis_fdw1.0-+pg18
repmgr5.5.0-+pg18
system_stats3.2-+pg18
topn2.7.0-+pg18
zhparser2.3-+pg18

2025-09-06

NameOld VerNew VerNote
timesacledb2.21.12.22.0
citus13.1.013.2.0
documentdb0.105.00.106.0work with ferretdb 2.5
ddlx0.290.30+ pg18
uint1281.0.01.1.0+ pg18
vchord0.4.30.5.1pgrx 0.16.0
pg_idkit0.3.00.3.1pgrx 0.15.0
pg_search0.17.30.18.0pgrx 0.15.0
pg_parquet0.4.00.4.3pgrx 0.16.0
wrappers0.5.30.5.4pgrx 0.14.3
pg_rewrite-2.0.0+ Debian/Ubuntu
pg_tracing-0.1.3-2+ pg 14/18
pg_curl2.42.4.5
pg_ivm1.111.12+ pg18
pg_rewrite-2.0.0new extension
pg_tracing-1.3.0+ pg14 / pg18
pgactive2.1.52.1.6+ pg18
pgsentinel1.11.21.2
pg_tle1.5.1-11.5.1-2+ pg18
redis_fdw+ pg18
emaj4.64.7
table_version1.11.01.11.1

2025-07-24

NameOld VerNew VerNote
orioledbbeta11 1.4beta12 1.5pair with oriolepg 17.11
oriolepg17.917.11pair with orioledb 1.5 beta12
documentdb0.104.00.105.0pair with ferretdb 2.4
timescaledb2.20.02.21.1
supautils2.9.22.10.0.so location changed
plv83.2.33.2.4
postgresql_anonymizer3.1.12.3.0 (pgrx 0.14.3)
wrappers0.5.00.5.3 (pgrx 0.14.3)pgrx version change
pgvectorscale0.7.10.8.0 (pgrx 0.12.9)
pg_search0.15.80.17.0 (download)fix el icu dep issue
pg_profile4.8.04.10.0

2025-07-04

NameOld VerNew VerNote
orioledb1.4 beta11rebuilt
pgvectorscale0.7.10.7.1rebuilt fix bug
pg_stat_monitor2.1.12.2.0
pgsql-tweaks0.11.10.11.3
pg_tle1.5.01.5.1
pg_curl2.42.4.5

2025-06-24

NameOld VerNew VerNote
citus13.0.313.1.0
timescaledb2.20.02.21.0
vchord0.3.00.4.3
pgactive-2.1.5requires pgfeutils
documentdb0.103.00.104.0add arm support

2025-05-26

NameOld VerNew VerNote
pgdd0.5.00.6.0
convert-0.0.4
pg_idkit0.2.00.3.0
pg_tokenizer.rs-0.1.0
pg_render-0.1.2
pgx_ulid-0.2.0
pg_ivm1.10.01.11.0
orioledb1.4.0b101.4.0b11

2025-05-22

NameOld VerNew VerNote
openhanded-14.10
spat-0.1.0a4
pgsentinel-1.1.0
timescaledb-2.20.0
sqlite_fdw-2.5.0
documentdb-0.103.0
tzf-0.2.2
pg_vectorize-0.22.2
wrappers-0.5.0

2025-05-07

NameOld VerNew VerNote
omnigres-20250507
citus-12.0.3
timescaledb-2.19.3
supautils-2.9.1
pg_envvar-1.0.1
pgcollection-1.0.0
aggs_for_vecs-1.4.0
pg_tracing-0.1.3
pgmq-1.5.1
tzf-pg-0.2.0
pg_search-0.15.18
anon-2.1.1
pg_parquet-0.4.0
pg_cardano-1.0.5
pglite_fusion-0.0.5
vchord_bm25-0.2.1
vchord-0.3.0
timescaledb-toolkit-1.21.0
pgvectorscale-0.7.1
pg_session_jwt-0.3.1

2025-03-20

NameOld VerNew VerNote
timescaledb-2.19.0
citus-13.0.2
documentdb-1.102
pg_analytics-0.3.7
pg_search-0.15.8
pg_ivm-1.10
emaj-4.6.0
pgsql_tweaks-0.11.0
pgvectorscale-0.6.0
pg_session_jwt-0.2.0
wrappers-0.4.5
pg_parquet-0.3.1
vchord-0.2.2
pg_tle1.2.01.5.0
supautils2.5.02.6.0
sslutils1.31.4
pg_profile4.74.8
pg_jsonschema0.3.20.3.3
pg_incremental1.1.11.2.0
ddl_historization0.70.0.7
pg_sqlog3.1.71.6
pg_random--
pg_stat_monitor2.1.02.1.1
pg_profile4.74.8

2024-10-16

NameOld VerNew VerNote
pg_ivm-1.9
pg_timeseries-0.1.6
pgmq-1.4.4
pg_protobuf-16 17
pg_uuidv7-1.6
pg_readonly-latest
pgddl-0.28
pg_safeupdate-latest
pg_stat_monitor-2.1
pg_profile-4.7
system_stats-3.2
pg_auth_mon-3.0
login_hook-1.6
logerrors-2.1.3
pg-orphaned-latest
pgnodemx-1.7
sslutils-1.4 (+16,17)

22 - PG Exporter

Advanced PostgreSQL & pgBouncer Metrics Exporter for Prometheus

The ultimate monitoring experience for PostgreSQL with 600+ metrics, declarative configuration, and dynamic planning capabilities.

Get Started | GitHub | Live Demo


Features

FeatureDescription
Comprehensive MetricsMonitor PostgreSQL (10-18+) and pgBouncer (1.8-1.24+) with 600+ metrics and ~3K time series per instance
Declarative ConfigurationDefine custom metrics through YAML configs with fine-grained control over timeout, caching, and skip conditions
Custom CollectorsDefine your own metrics with declarative YAML configuration and dynamic query planning
Auto-DiscoveryAutomatically discover and monitor multiple databases within a PostgreSQL instance
Dynamic PlanningAutomatically adapt metric collection based on PostgreSQL version, extensions, and server characteristics
Production ReadyBattle-tested in real-world environments across 12K+ cores for 6+ years with enterprise reliability
Health Check APIsComprehensive HTTP endpoints for service health and traffic routing with primary/replica detection
Smart CachingBuilt-in caching mechanism with configurable TTL to reduce database load and improve performance
Extension AwareNative support for TimescaleDB, Citus, pg_stat_statements, pg_wait_sampling and automatic detection

Installation

PG Exporter provides multiple install methods to fit your infrastructure:

docker run -d --name pg_exporter -p 9630:9630 -e PG_EXPORTER_URL="postgres://user:pass@host:5432/postgres" pgsty/pg_exporter:latest
# RPM-based systems
sudo tee /etc/yum.repos.d/pigsty-infra.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.io/yum/infra/$basearch
enabled = 1
gpgcheck = 0
module_hotfixes=1
EOF

sudo yum makecache;
sudo yum install -y pg_exporter
sudo tee /etc/apt/sources.list.d/pigsty-infra.list > /dev/null <<EOF
deb [trusted=yes] https://repo.pigsty.io/apt/infra generic main
EOF

sudo apt update;
sudo apt install -y pg-exporter
wget https://github.com/pgsty/pg_exporter/releases/download/v1.1.1/pg_exporter-1.1.1.linux-amd64.tar.gz
tar -xf pg_exporter-1.1.1.linux-amd64.tar.gz
sudo install pg_exporter-1.1.1.linux-amd64/pg_exporter /usr/bin/
sudo install pg_exporter-1.1.1.linux-amd64/pg_exporter.yml /etc/pg_exporter.yml
# Build from source
git clone https://github.com/pgsty/pg_exporter.git
cd pg_exporter
make build

Quick Start

Get PG Exporter up and running in minutes, Getting Started with:

# Run with PostgreSQL URL
PG_EXPORTER_URL='postgres://user:pass@localhost:5432/postgres' pg_exporter

# Access metrics
curl http://localhost:9630/metrics

Documentation


Live Demo

Experience PG Exporter in action with our live demo environment: https://g.pgsty.com

The demo showcases real PostgreSQL clusters monitored by PG Exporter, featuring:

  • Real-time metrics visualization with Grafana
  • Multiple PostgreSQL versions and configurations
  • Extension-specific metrics and monitoring
  • Complete observability stack powered by Pigsty

Community & Support

  • GitHub - Source code, issues, and contributions
  • Discussions - Ask questions and share experiences
  • Pigsty - Complete PostgreSQL Distro with PG Exporter

License

PG Exporter is open-source software licensed under the Apache License 2.0.

Copyright 2018-2025 © Ruohang Feng / [email protected]

22.1 - Getting Started

PG Exporter is an advanced PostgreSQL and pgBouncer metrics exporter for Prometheus. This guide will help you get up and running quickly.

Prerequisites

Before you begin, ensure you have:

  • PostgreSQL 10+ or pgBouncer 1.8+ instance to monitor
  • A user account with appropriate permissions for monitoring
  • Prometheus Compatible System (for metrics scraping)
  • Basic understanding of PostgreSQL connection strings

Quick Start

The fastest way to get started with PG Exporter:

# Download and install the latest release
curl -L https://github.com/pgsty/pg_exporter/releases/latest/download/pg_exporter-$(uname -s)-$(uname -m).tar.gz | tar xz
sudo install pg_exporter /usr/bin/

# Run with PostgreSQL connection URL
PG_EXPORTER_URL='postgres://user:pass@localhost:5432/postgres' pg_exporter

# Verify metrics are available
curl http://localhost:9630/metrics

Understanding the Basics

Connection String

PG Exporter uses standard PostgreSQL connection URLs:

postgres://[user][:password]@[host][:port]/[database][?param=value]

Examples:

  • Local PostgreSQL: postgres:///postgres
  • Remote with auth: postgres://monitor:[email protected]:5432/postgres
  • With SSL: postgres://user:pass@host/db?sslmode=require
  • pgBouncer: postgres://pgbouncer:password@localhost:6432/pgbouncer

Built-in Metrics

PG Exporter provides 4 core built-in metrics out of the box:

MetricTypeDescription
pg_upGauge1 if exporter can connect to PostgreSQL, 0 otherwise
pg_versionGaugePostgreSQL server version number
pg_in_recoveryGauge1 if server is in recovery mode (replica), 0 if primary
pg_exporter_build_infoGaugeExporter version and build information

Configuration File

All other metrics (600+) are defined in the pg_exporter.yml configuration file. By default, PG Exporter looks for this file in:

  1. Path specified by --config flag
  2. Path in PG_EXPORTER_CONFIG environment variable
  3. Current directory (./pg_exporter.yml)
  4. System config (/etc/pg_exporter.yml or /etc/pg_exporter/)

Your First Monitoring Setup

Step 1: Create a Monitoring User

Create a dedicated PostgreSQL user for monitoring:

-- Create monitoring user
CREATE USER pg_monitor WITH PASSWORD 'secure_password';

-- Grant necessary permissions
GRANT pg_monitor TO pg_monitor;
GRANT CONNECT ON DATABASE postgres TO pg_monitor;

-- For PostgreSQL 10+, pg_monitor role provides read access to monitoring views
-- For older versions, you may need additional grants

Step 2: Test Connection

Verify the exporter can connect to your database:

# Set connection URL
export PG_EXPORTER_URL='postgres://pg_monitor:secure_password@localhost:5432/postgres'

# Run in dry-run mode to test configuration
pg_exporter --dry-run

Step 3: Run the Exporter

Start PG Exporter:

# Run with default settings
pg_exporter

# Or with custom flags
pg_exporter \
  --url='postgres://pg_monitor:secure_password@localhost:5432/postgres' \
  --web.listen-address=':9630' \
  --log.level=info

Step 4: Configure Prometheus

Add PG Exporter as a target in your prometheus.yml:

scrape_configs:
  - job_name: 'postgresql'
    static_configs:
      - targets: ['localhost:9630']
        labels:
          instance: 'postgres-primary'

Step 5: Verify Metrics

Check that metrics are being collected:

# View raw metrics
curl http://localhost:9630/metrics | grep pg_

# Check exporter statistics
curl http://localhost:9630/stat

# Verify server detection
curl http://localhost:9630/explain

Auto-Discovery Mode

PG Exporter can automatically discover and monitor all databases in a PostgreSQL instance:

# Enable auto-discovery (default behavior)
pg_exporter --auto-discovery

# Exclude specific databases
pg_exporter --auto-discovery \
  --exclude-database="template0,template1,postgres"

# Include only specific databases
pg_exporter --auto-discovery \
  --include-database="app_db,analytics_db"

When auto-discovery is enabled:

  • Cluster-level metrics (1xx-5xx) are collected once per instance
  • Database-level metrics (6xx-8xx) are collected for each discovered database
  • Metrics are labeled with datname to distinguish between databases

Monitoring pgBouncer

To monitor pgBouncer instead of PostgreSQL:

# Connect to pgBouncer admin database
PG_EXPORTER_URL='postgres://pgbouncer:password@localhost:6432/pgbouncer' \
pg_exporter --config=/etc/pg_exporter.yml

The exporter automatically detects pgBouncer and:

  • Uses pgbouncer namespace for metrics
  • Executes pgBouncer-specific collectors (9xx series)
  • Provides pgBouncer-specific health checks

Using Docker

Run PG Exporter in a container:

docker run -d \
  --name pg_exporter \
  -p 9630:9630 \
  -e PG_EXPORTER_URL="postgres://user:[email protected]:5432/postgres" \
  pgsty/pg_exporter:latest

With custom configuration:

docker run -d \
  --name pg_exporter \
  -p 9630:9630 \
  -v /path/to/pg_exporter.yml:/etc/pg_exporter.yml \
  -e PG_EXPORTER_URL="postgres://user:pass@db:5432/postgres" \
  pgsty/pg_exporter:latest

Health Checks

PG Exporter provides health check endpoints for load balancers and orchestrators:

# Basic health check
curl http://localhost:9630/up
# Returns: 200 if connected, 503 if not

# Primary detection
curl http://localhost:9630/primary
# Returns: 200 if primary, 404 if replica, 503 if unknown

# Replica detection
curl http://localhost:9630/replica
# Returns: 200 if replica, 404 if primary, 503 if unknown

Troubleshooting

Connection Issues

# Test with detailed logging
pg_exporter --log.level=debug --dry-run

# Check server planning
pg_exporter --explain

Permission Errors

Ensure the monitoring user has necessary permissions:

-- Check current permissions
SELECT * FROM pg_roles WHERE rolname = 'pg_monitor';

-- Grant additional permissions if needed
GRANT USAGE ON SCHEMA pg_catalog TO pg_monitor;
GRANT SELECT ON ALL TABLES IN SCHEMA pg_catalog TO pg_monitor;

Slow Scrapes

If scrapes are timing out:

  1. Check slow queries: curl http://localhost:9630/stat
  2. Adjust collector timeouts in configuration
  3. Use caching for expensive queries (set ttl in collector config)
  4. Disable expensive collectors if not needed

Next Steps

22.2 - Installation

How to download and install the pg_exporter

PG Exporter provides multiple installation methods to suit different deployment scenarios. This guide covers all available installation options with detailed instructions for each platform.

Pigsty

The easiest way to get started with pg_exporter is to use Pigsty, which is a complete PostgreSQL distribution with built-in Observability best practices based on pg_exporter, Prometheus, and Grafana. You don’t even need to know any details about pg_exporter, it just gives you all the metrics and dashboard panels

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty;

Release

You can also download pg_exporter package (RPM/DEB/ Tarball) directly from the Latest GitHub Release Page:

v1.1.1 Release Files:

TypeFile
DEB (amd64)pg-exporter_1.1.1-1_amd64.deb
DEB (arm64)pg-exporter_1.1.1-1_arm64.deb
DEB (ppc64le)pg-exporter_1.1.1-1_ppc64le.deb
RPM (aarch64)pg_exporter-1.1.1-1.aarch64.rpm
RPM (x86_64)pg_exporter-1.1.1-1.x86_64.rpm
RPM (ppc64le)pg_exporter-1.1.1-1.ppc64le.rpm
Tarball (Linux amd64)pg_exporter-1.1.1.linux-amd64.tar.gz
Tarball (Linux arm64)pg_exporter-1.1.1.linux-arm64.tar.gz
Tarball (Linux ppc64le)pg_exporter-1.1.1.linux-ppc64le.tar.gz
Tarball (macOS amd64)pg_exporter-1.1.1.darwin-amd64.tar.gz
Tarball (macOS arm64)pg_exporter-1.1.1.darwin-arm64.tar.gz
Tarball (Windows amd64)pg_exporter-1.1.1.windows-amd64.tar.gz

You can install it directly with your OS package manager (rpm/dpkg), or even put the binary in your $PATH.

Repository

The pig package is also available in the pigsty-infra repo, You can add the repo to your system, and install it with OS package manager:

YUM

For EL distribution such as RHEL,RockyLinux,CentOS,Alma Linux,OracleLinux,…:

sudo tee /etc/yum.repos.d/pigsty-infra.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.io/yum/infra/$basearch
enabled = 1
gpgcheck = 0
module_hotfixes=1
EOF

sudo yum makecache;
sudo yum install -y pg_exporter

APT

For Debian, Ubuntu and compatible Linux Distributions:

sudo tee /etc/apt/sources.list.d/pigsty-infra.list > /dev/null <<EOF
deb [trusted=yes] https://repo.pigsty.io/apt/infra generic main
EOF

sudo apt update;
sudo apt install -y pg-exporter

Docker

We have prebuilt docker images for amd64 and arm64 architectures on docker hub: pgsty/pg_exporter.

# Basic usage
docker run -d \
  --name pg_exporter \
  -p 9630:9630 \
  -e PG_EXPORTER_URL="postgres://user:password@host:5432/postgres" \
  pgsty/pg_exporter:latest

# With custom configuration
docker run -d \
  --name pg_exporter \
  -p 9630:9630 \
  -v /path/to/pg_exporter.yml:/etc/pg_exporter.yml:ro \
  -e PG_EXPORTER_CONFIG="/etc/pg_exporter.yml" \
  -e PG_EXPORTER_URL="postgres://user:password@host:5432/postgres" \
  pgsty/pg_exporter:latest

# With auto-discovery enabled
docker run -d \
  --name pg_exporter \
  -p 9630:9630 \
  -e PG_EXPORTER_URL="postgres://user:password@host:5432/postgres" \
  -e PG_EXPORTER_AUTO_DISCOVERY="true" \
  -e PG_EXPORTER_EXCLUDE_DATABASE="template0,template1" \
  pgsty/pg_exporter:latest

Binary

The pg_exporter can be installed as a standalone binary.

Compatibility

The current pg_exporter support PostgreSQL version 10 and above. While it is designed to work with any PostgreSQL major version (back to 9.x).

The only problem to use with legacy version (9.6 and below) is that we removed older metrics collector branches definition due to EOL.

You can always retrieve these legacy version of config files and use against historic versions of PostgreSQL

PostgreSQL VersionSupport Status
10 ~ 17✅ Full Support
9.6-⚠️ Legacy Conf

pg_exporter works with pgbouncer 1.8+, Since v1.8 is the first version with SHOW command support.

pgBouncer VersionSupport Status
1.8.x ~ 1.24.x✅ Full Support
before 1.8.x⚠️ No Metrics

22.3 - Configuration

PG Exporter uses a powerful and flexible configuration system that allows you to define custom metrics, control collection behavior, and optimize performance. This guide covers all aspects of configuration from basic setup to advanced customization.

Metrics Collectors

PG Exporter uses a declarative YAML configuration system that provides incredible flexibility and control over metric collection. This guide covers all aspects of configuring PG Exporter for your specific monitoring needs.

Configuration Overview

PG Exporter’s configuration is centered around collectors - individual metric queries with associated metadata. The configuration can be:

  • A single monolithic YAML file (pg_exporter.yml)
  • A directory containing multiple YAML files (merged alphabetically)
  • Custom path specified via command-line or environment variable

Configuration Loading

PG Exporter searches for configuration in the following order:

  1. Command-line argument: --config=/path/to/config
  2. Environment variable: PG_EXPORTER_CONFIG=/path/to/config
  3. Current directory: ./pg_exporter.yml
  4. System config file: /etc/pg_exporter.yml
  5. System config directory: /etc/pg_exporter/

Collector Structure

Each collector is a top-level object in the YAML configuration with a unique name and various properties:

collector_branch_name:           # Unique identifier for this collector
  name: metric_namespace         # Metric prefix (defaults to branch name)
  desc: "Collector description"  # Human-readable description
  query: |                       # SQL query to execute
    SELECT column1, column2
    FROM table
  
  # Execution Control
  ttl: 10                        # Cache time-to-live in seconds
  timeout: 0.1                   # Query timeout in seconds
  fatal: false                   # If true, failure fails entire scrape
  skip: false                    # If true, collector is disabled
  
  # Version Compatibility
  min_version: 100000            # Minimum PostgreSQL version (inclusive)
  max_version: 999999            # Maximum PostgreSQL version (exclusive)
  
  # Execution Tags
  tags: [cluster, primary]       # Conditions for execution
  
  # Predicate Queries (optional)
  predicate_queries:
    - name: "check_function"
      predicate_query: |
        SELECT EXISTS (...)
  
  # Metric Definitions
  metrics:
    - column_name:
        usage: GAUGE             # GAUGE, COUNTER, LABEL, or DISCARD
        rename: metric_name      # Optional: rename the metric
        description: "Help text" # Metric description
        default: 0               # Default value if NULL
        scale: 1000              # Scale factor for the value

Core Configuration Elements

Collector Branch Name

The top-level key uniquely identifies a collector across the entire configuration:

pg_stat_database:  # Must be unique
  name: pg_db      # Actual metric namespace

Query Definition

The SQL query that retrieves metrics:

query: |
  SELECT 
    datname,
    numbackends,
    xact_commit,
    xact_rollback,
    blks_read,
    blks_hit
  FROM pg_stat_database
  WHERE datname NOT IN ('template0', 'template1')

Metric Types

Each column in the query result must be mapped to a metric type:

UsageDescriptionExample
GAUGEInstantaneous value that can go up or downCurrent connections
COUNTERCumulative value that only increasesTotal transactions
LABELUse as a Prometheus labelDatabase name
DISCARDIgnore this columnInternal values

Cache Control (TTL)

The ttl parameter controls result caching:

# Fast queries - minimal caching
pg_stat_activity:
  ttl: 1  # Cache for 1 second

# Expensive queries - longer caching
pg_table_bloat:
  ttl: 3600  # Cache for 1 hour

Best practices:

  • Set TTL less than your scrape interval
  • Use longer TTL for expensive queries
  • TTL of 0 disables caching

Timeout Control

Prevent queries from running too long:

timeout: 0.1   # 100ms default
timeout: 1.0   # 1 second for complex queries
timeout: -1    # Disable timeout (not recommended)

Version Compatibility

Control which PostgreSQL versions can run this collector:

min_version: 100000  # PostgreSQL 10.0+
max_version: 140000  # Below PostgreSQL 14.0

Version format: MMMMMMPP00 where:

  • MMMMMM = Major version (6 digits)
  • PP = Minor version (2 digits)
  • Examples: 100000 = 10.0, 130200 = 13.2, 160100 = 16.1

Tag System

Tags control when and where collectors execute:

Built-in Tags

TagDescription
clusterExecute once per PostgreSQL cluster
primary / masterOnly on primary servers
standby / replicaOnly on replica servers
pgbouncerOnly for pgBouncer connections

Prefixed Tags

PrefixExampleDescription
dbname:dbname:postgresOnly on specific database
username:username:monitorOnly with specific user
extension:extension:pg_stat_statementsOnly if extension installed
schema:schema:publicOnly if schema exists
not:not:slowNOT when exporter has tag

Custom Tags

Pass custom tags to the exporter:

pg_exporter --tag="production,critical"

Then use in configuration:

expensive_metrics:
  tags: [critical]  # Only runs with 'critical' tag

Predicate Queries

Execute conditional checks before main query:

predicate_queries:
  - name: "Check pg_stat_statements"
    predicate_query: |
      SELECT EXISTS (
        SELECT 1 FROM pg_extension 
        WHERE extname = 'pg_stat_statements'
      )

The main query only executes if all predicates return true.

Metric Definition

Basic Definition

metrics:
  - numbackends:
      usage: GAUGE
      description: "Number of backends connected"

Advanced Options

metrics:
  - checkpoint_write_time:
      usage: COUNTER
      rename: write_time        # Rename metric
      scale: 0.001              # Convert ms to seconds
      default: 0                # Use 0 if NULL
      description: "Checkpoint write time in seconds"

Collector Organization

PG Exporter ships with pre-organized collectors:

RangeCategoryDescription
0xxDocumentationExamples and documentation
1xxBasicServer info, settings, metadata
2xxReplicationReplication, slots, receivers
3xxPersistenceI/O, checkpoints, WAL
4xxActivityConnections, locks, queries
5xxProgressVacuum, index creation progress
6xxDatabasePer-database statistics
7xxObjectsTables, indexes, functions
8xxOptionalExpensive/optional metrics
9xxpgBouncerConnection pooler metrics
10xx+ExtensionsExtension-specific metrics

Real-World Examples

Simple Gauge Collector

pg_connections:
  desc: "Current database connections"
  query: |
    SELECT 
      count(*) as total,
      count(*) FILTER (WHERE state = 'active') as active,
      count(*) FILTER (WHERE state = 'idle') as idle,
      count(*) FILTER (WHERE state = 'idle in transaction') as idle_in_transaction
    FROM pg_stat_activity
    WHERE pid != pg_backend_pid()
  ttl: 1
  metrics:
    - total: {usage: GAUGE, description: "Total connections"}
    - active: {usage: GAUGE, description: "Active connections"}
    - idle: {usage: GAUGE, description: "Idle connections"}
    - idle_in_transaction: {usage: GAUGE, description: "Idle in transaction"}

Counter with Labels

pg_table_stats:
  desc: "Table statistics"
  query: |
    SELECT 
      schemaname,
      tablename,
      n_tup_ins,
      n_tup_upd,
      n_tup_del,
      n_live_tup,
      n_dead_tup
    FROM pg_stat_user_tables
  ttl: 10
  metrics:
    - schemaname: {usage: LABEL}
    - tablename: {usage: LABEL}
    - n_tup_ins: {usage: COUNTER, description: "Tuples inserted"}
    - n_tup_upd: {usage: COUNTER, description: "Tuples updated"}
    - n_tup_del: {usage: COUNTER, description: "Tuples deleted"}
    - n_live_tup: {usage: GAUGE, description: "Live tuples"}
    - n_dead_tup: {usage: GAUGE, description: "Dead tuples"}

Version-Specific Collector

pg_wal_stats:
  desc: "WAL statistics (PG 14+)"
  min_version: 140000
  query: |
    SELECT 
      wal_records,
      wal_bytes,
      wal_buffers_full,
      wal_write_time,
      wal_sync_time
    FROM pg_stat_wal
  ttl: 10
  tags: [cluster]
  metrics:
    - wal_records: {usage: COUNTER}
    - wal_bytes: {usage: COUNTER}
    - wal_buffers_full: {usage: COUNTER}
    - wal_write_time: {usage: COUNTER, scale: 0.001}
    - wal_sync_time: {usage: COUNTER, scale: 0.001}

Extension-Dependent Collector

pg_stat_statements_metrics:
  desc: "Query performance statistics"
  tags: [extension:pg_stat_statements]
  query: |
    SELECT 
      sum(calls) as total_calls,
      sum(total_exec_time) as total_time,
      sum(mean_exec_time * calls) / sum(calls) as mean_time
    FROM pg_stat_statements
  ttl: 60
  metrics:
    - total_calls: {usage: COUNTER}
    - total_time: {usage: COUNTER, scale: 0.001}
    - mean_time: {usage: GAUGE, scale: 0.001}

Custom Collectors

Creating Your Own Metrics

  1. Create a new YAML file in your config directory:
# /etc/pg_exporter/custom_metrics.yml
app_metrics:
  desc: "Application-specific metrics"
  query: |
    SELECT 
      (SELECT count(*) FROM users WHERE active = true) as active_users,
      (SELECT count(*) FROM orders WHERE created_at > NOW() - '1 hour'::interval) as recent_orders,
      (SELECT avg(processing_time) FROM jobs WHERE completed_at > NOW() - '5 minutes'::interval) as avg_job_time
  ttl: 30
  metrics:
    - active_users: {usage: GAUGE, description: "Currently active users"}
    - recent_orders: {usage: GAUGE, description: "Orders in last hour"}
    - avg_job_time: {usage: GAUGE, description: "Average job processing time"}
  1. Test your collector:
pg_exporter --explain --config=/etc/pg_exporter/

Conditional Metrics

Use predicate queries for conditional metrics:

partition_metrics:
  desc: "Partitioned table metrics"
  predicate_queries:
    - name: "Check if partitioning is used"
      predicate_query: |
        SELECT EXISTS (
          SELECT 1 FROM pg_class 
          WHERE relkind = 'p' LIMIT 1
        )
  query: |
    SELECT 
      parent.relname as parent_table,
      count(*) as partition_count,
      sum(pg_relation_size(child.oid)) as total_size
    FROM pg_inherits
    JOIN pg_class parent ON parent.oid = pg_inherits.inhparent
    JOIN pg_class child ON child.oid = pg_inherits.inhrelid
    WHERE parent.relkind = 'p'
    GROUP BY parent.relname
  ttl: 300
  metrics:
    - parent_table: {usage: LABEL}
    - partition_count: {usage: GAUGE}
    - total_size: {usage: GAUGE}

Performance Optimization

Query Optimization Tips

  1. Use appropriate TTL values:

    • Fast queries: 1-10 seconds
    • Medium queries: 10-60 seconds
    • Expensive queries: 300-3600 seconds
  2. Set realistic timeouts:

    • Default: 100ms
    • Complex queries: 500ms-1s
    • Never disable timeout in production
  3. Use cluster-level tags:

    tags: [cluster]  # Run once per cluster, not per database
    
  4. Disable expensive collectors:

    pg_table_bloat:
      skip: true  # Disable if not needed
    

Monitoring Collector Performance

Check collector execution statistics:

# View collector statistics
curl http://localhost:9630/stat

# Check which collectors are slow
curl http://localhost:9630/metrics | grep pg_exporter_collector_duration

Troubleshooting Configuration

Validate Configuration

# Dry run - shows parsed configuration
pg_exporter --dry-run

# Explain - shows planned queries
pg_exporter --explain

Common Issues

ProblemSolution
Metrics missingCheck tags and version compatibility
Slow scrapesIncrease TTL, add timeout, disable expensive queries
High memory usageReduce result set size, use LIMIT
Permission errorsVerify query permissions for monitoring user

Debug Logging

Enable debug logging to troubleshoot:

pg_exporter --log.level=debug

22.4 - API Reference

PG Exporter provides a comprehensive REST API for metrics collection, health checking, traffic routing, and operational control. All endpoints are exposed via HTTP on the configured port (default: 9630).

Endpoint Overview

EndpointMethodDescription
/metricsGETPrometheus metrics endpoint
/upGETBasic aliveness check
/healthGETDetailed health status
/primaryGETPrimary server check
/replicaGETReplica server check
/readGETRead traffic routing
/reloadGETReload configuration
/explainGETExplain query planning
/statGETRuntime statistics

Metrics Endpoint

GET /metrics

The primary endpoint that exposes all collected metrics in Prometheus format.

Request

curl http://localhost:9630/metrics

Response

# HELP pg_up PostgreSQL server is up and accepting connections
# TYPE pg_up gauge
pg_up 1

# HELP pg_version PostgreSQL server version number
# TYPE pg_version gauge
pg_version 140000

# HELP pg_in_recovery PostgreSQL server is in recovery mode
# TYPE pg_in_recovery gauge
pg_in_recovery 0

# HELP pg_exporter_build_info PG Exporter build information
# TYPE pg_exporter_build_info gauge
pg_exporter_build_info{version="1.1.1",branch="main",revision="abc123"} 1

# ... additional metrics

Response Format

Metrics follow the Prometheus exposition format:

# HELP <metric_name> <description>
# TYPE <metric_name> <type>
<metric_name>{<label_name>="<label_value>",...} <value> <timestamp>

Health Check Endpoints

Health check endpoints provide various ways to monitor PG Exporter and the target database status.

GET /up

Simple binary health check.

Response Codes

CodeStatusDescription
200OKExporter and database are up
503Service UnavailableDatabase is down or unreachable

Example

# Check if service is up
curl -I http://localhost:9630/up

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

GET /health

Alias for /up with same behavior.

curl http://localhost:9630/health

GET /liveness

Kubernetes liveness probe endpoint.

# Liveness probe configuration
livenessProbe:
  httpGet:
    path: /liveness
    port: 9630
  initialDelaySeconds: 30
  periodSeconds: 10

GET /readiness

Kubernetes readiness probe endpoint.

# Readiness probe configuration
readinessProbe:
  httpGet:
    path: /readiness
    port: 9630
  initialDelaySeconds: 5
  periodSeconds: 5

Traffic Routing Endpoints

These endpoints are designed for load balancers and proxies to route traffic based on server role.

GET /primary

Check if the server is a primary (master) instance.

Response Codes

CodeStatusDescription
200OKServer is primary and accepting writes
404Not FoundServer is not primary (is replica)
503Service UnavailableServer is down

Aliases

  • /leader
  • /master
  • /read-write
  • /rw

Example

# Check if server is primary
curl -I http://localhost:9630/primary

# Use in HAProxy configuration
backend pg_primary
  option httpchk GET /primary
  server pg1 10.0.0.1:5432 check port 9630
  server pg2 10.0.0.2:5432 check port 9630

GET /replica

Check if the server is a replica (standby) instance.

Response Codes

CodeStatusDescription
200OKServer is replica and in recovery
404Not FoundServer is not replica (is primary)
503Service UnavailableServer is down

Aliases

  • /standby
  • /slave
  • /read-only
  • /ro

Example

# Check if server is replica
curl -I http://localhost:9630/replica

# Use in load balancer configuration
backend pg_replicas
  option httpchk GET /replica
  server pg2 10.0.0.2:5432 check port 9630
  server pg3 10.0.0.3:5432 check port 9630

GET /read

Check if the server can handle read traffic (both primary and replica).

Response Codes

CodeStatusDescription
200OKServer is up and can handle reads
503Service UnavailableServer is down

Example

# Check if server can handle reads
curl -I http://localhost:9630/read

# Route read traffic to any available server
backend pg_read
  option httpchk GET /read
  server pg1 10.0.0.1:5432 check port 9630
  server pg2 10.0.0.2:5432 check port 9630
  server pg3 10.0.0.3:5432 check port 9630

Operational Endpoints

POST /reload

Reload configuration without restarting the exporter.

Request

curl -X POST http://localhost:9630/reload

Response

{
  "status": "success",
  "message": "Configuration reloaded successfully",
  "timestamp": "2024-01-15T10:30:00Z"
}

Response Codes

CodeStatusDescription
200OKConfiguration reloaded successfully
500Internal Server ErrorReload failed

Use Cases

  • Update collector definitions
  • Change query parameters
  • Modify cache TTL values
  • Add or remove collectors

GET /explain

Display query execution planning information for all configured collectors.

Request

curl http://localhost:9630/explain

Response

Collector: pg_stat_database
  Query: SELECT datname, numbackends FROM pg_stat_database
  Tags: [cluster]
  TTL: 10s
  Timeout: 100ms
  Version: 100000-999999
  Status: Active

Collector: pg_stat_replication
  Query: SELECT client_addr, state FROM pg_stat_replication
  Tags: [primary]
  TTL: 5s
  Timeout: 100ms
  Version: 100000-999999
  Status: Active (primary only)

...

22.5 - Deployment

This guide covers production deployment strategies, best practices, and real-world configurations for PG Exporter.

pg_exporter itself can be configured through:

  1. Command-line arguments (higher priority)
  2. Environment variables (lower priority)

The metrics collectors are configured with a YAML configuration file (dir/files):

  • /etc/pg_exporter.yml (default)
  • /etc/pg_exporter/ (directory with multiple files)

The configuration file uses YAML format and consists of collector definitions that specify what metrics to collect and how to collect them.

CLI Arg

All configuration options can be specified via command-line flags:

pg_exporter \
  --url="postgres://user:pass@localhost:5432/postgres" \
  --config="/etc/pg_exporter/pg_exporter.yml" \
  --web.listen-address=":9630" \
  --auto-discovery \
  --exclude-database="template0,template1" \
  --log.level="info"

Run pg_exporter --help for a complete list of available flags:

Flags:
  -h, --[no-]help                Show context-sensitive help (also try --help-long and --help-man).
  -u, --url=URL                  postgres target url
  -c, --config=CONFIG            path to config dir or file
      --[no-]web.systemd-socket  Use systemd socket activation listeners instead of port listeners (Linux only).
      --web.listen-address=:9630 ...
                                 Addresses on which to expose metrics and web interface. Repeatable for multiple addresses. Examples: `:9100` or `[::1]:9100` for http, `vsock://:9100` for vsock
      --web.config.file=""       Path to configuration file that can enable TLS or authentication. See: https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md
  -l, --label=""                 constant lables:comma separated list of label=value pair ($PG_EXPORTER_LABEL)
  -t, --tag=""                   tags,comma separated list of server tag ($PG_EXPORTER_TAG)
  -C, --[no-]disable-cache       force not using cache ($PG_EXPORTER_DISABLE_CACHE)
  -m, --[no-]disable-intro       disable collector level introspection metrics ($PG_EXPORTER_DISABLE_INTRO)
  -a, --[no-]auto-discovery      automatically scrape all database for given server ($PG_EXPORTER_AUTO_DISCOVERY)
  -x, --exclude-database="template0,template1,postgres"
                                 excluded databases when enabling auto-discovery ($PG_EXPORTER_EXCLUDE_DATABASE)
  -i, --include-database=""      included databases when enabling auto-discovery ($PG_EXPORTER_INCLUDE_DATABASE)
  -n, --namespace=""             prefix of built-in metrics, (pg|pgbouncer) by default ($PG_EXPORTER_NAMESPACE)
  -f, --[no-]fail-fast           fail fast instead of waiting during start-up ($PG_EXPORTER_FAIL_FAST)
  -T, --connect-timeout=100      connect timeout in ms, 100 by default ($PG_EXPORTER_CONNECT_TIMEOUT)
  -P, --web.telemetry-path="/metrics"
                                 URL path under which to expose metrics. ($PG_EXPORTER_TELEMETRY_PATH)
  -D, --[no-]dry-run             dry run and print raw configs
  -E, --[no-]explain             explain server planned queries
      --log.level="info"         log level: debug|info|warn|error]
      --log.format="logfmt"      log format: logfmt|json
      --[no-]version             Show application version.

Environment Variables

All command-line arguments have corresponding environment variables:

PG_EXPORTER_URL='postgres://:5432/?sslmode=disable'
PG_EXPORTER_CONFIG=/etc/pg_exporter.yml
PG_EXPORTER_LABEL=""
PG_EXPORTER_TAG=""
PG_EXPORTER_DISABLE_CACHE=false
PG_EXPORTER_AUTO_DISCOVERY=true
PG_EXPORTER_EXCLUDE_DATABASE="template0,template1,postgres"
PG_EXPORTER_INCLUDE_DATABASE=""
PG_EXPORTER_NAMESPACE="pg"
PG_EXPORTER_FAIL_FAST=false
PG_EXPORTER_CONNECT_TIMEOUT=100
PG_EXPORTER_TELEMETRY_PATH="/metrics"
PG_EXPORTER_OPTS='--log.level=info'

pg_exporter

Deployment Architecture

The simplest deployment with one exporter per PostgreSQL instance:

┌─────────────┐     ┌──────────────┐     ┌────────────┐
│ Prometheus  │────▶│ PG Exporter  │────▶│ PostgreSQL │
└─────────────┘     └──────────────┘     └────────────┘
                         :9630                :5432

Multi-Database Environment

Using auto-discovery to monitor multiple databases, which is enabled by default

┌─────────────┐     ┌────────────────┐     ┌────────────┐
│ Prometheus  │────▶│ PG Exporter    │────▶│ PostgreSQL │
└─────────────┘     │     with       │     │  ├─ db1    │
                    │ auto-discovery │     │  ├─ db2    │
                    └────────────────┘     │  └─ db3    │
                                           └────────────┘

Production Configuration

PostgreSQL User Setup

Create a dedicated monitoring user with minimal required permissions:

-- Create monitoring role
CREATE ROLE pg_monitor WITH LOGIN PASSWORD 'strong_password' CONNECTION LIMIT 5;

-- Grant necessary permissions
GRANT pg_monitor TO pg_monitor;  -- PostgreSQL 10+ built-in role
GRANT CONNECT ON DATABASE postgres TO pg_monitor;

-- For specific databases
GRANT CONNECT ON DATABASE app_db TO pg_monitor;
GRANT USAGE ON SCHEMA public TO pg_monitor;

-- Additional permissions for extended monitoring
GRANT SELECT ON ALL TABLES IN SCHEMA pg_catalog TO pg_monitor;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA pg_catalog TO pg_monitor;

Connection Security

Using SSL/TLS

# Connection string with SSL
PG_EXPORTER_URL='postgres://pg_monitor:[email protected]:5432/postgres?sslmode=require&sslcert=/path/to/client.crt&sslkey=/path/to/client.key&sslrootcert=/path/to/ca.crt'

Using .pgpass File

# Create .pgpass file
echo "db.example.com:5432:*:pg_monitor:password" > ~/.pgpass
chmod 600 ~/.pgpass

# Use without password in URL
PG_EXPORTER_URL='postgres://[email protected]:5432/postgres'

Systemd Service Configuration

Complete production systemd setup:

[Unit]
Description=Prometheus exporter for PostgreSQL/Pgbouncer server metrics
Documentation=https://github.com/pgsty/pg_exporter
After=network.target

[Service]
EnvironmentFile=-/etc/default/pg_exporter
User=prometheus
ExecStart=/usr/bin/pg_exporter $PG_EXPORTER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target

Environment file /etc/default/pg_exporter:

PG_EXPORTER_URL='postgres://:5432/?sslmode=disable'
PG_EXPORTER_CONFIG=/etc/pg_exporter.yml
PG_EXPORTER_LABEL=""
PG_EXPORTER_TAG=""
PG_EXPORTER_DISABLE_CACHE=false
PG_EXPORTER_AUTO_DISCOVERY=true
PG_EXPORTER_EXCLUDE_DATABASE="template0,template1,postgres"
PG_EXPORTER_INCLUDE_DATABASE=""
PG_EXPORTER_NAMESPACE="pg"
PG_EXPORTER_FAIL_FAST=false
PG_EXPORTER_CONNECT_TIMEOUT=100
PG_EXPORTER_TELEMETRY_PATH="/metrics"
PG_EXPORTER_OPTS='--log.level=info'

22.6 - Release Notes

The latest stable version of pg_exporter is v1.1.1

VersionDateSummaryGitHub
v1.1.12025-12-30New pg_timeline collector, pg_sub_16 branch, bug fixesv1.1.1
v1.1.02025-12-15Update default metrics collectors, bump to go 1.25.5v1.1.0
v1.0.32025-11-20Routine update on 1.25.4, fix unsupported libpq envv1.0.3
v1.0.22025-08-14Build for more os arch with goreleaserv1.0.2
v1.0.12025-07-17DockerHub images, Go 1.24.5, disable pg_tsdb_hypertablev1.0.1
v1.0.02025-05-06PostgreSQL 18 support, new WAL/checkpointer/I/O metricsv1.0.0
v0.9.02025-04-26TimescaleDB, Citus, pg_wait_sampling collectorsv0.9.0
v0.8.12025-02-14Dependencies update, docker image tagsv0.8.1
v0.8.02025-02-14PgBouncer 1.24 support, Go 1.24, logging refactorv0.8.0
v0.7.12024-12-29Routine update, configuration as Reader supportv0.7.1
v0.7.02024-08-13PostgreSQL 17 support, predicate queries featurev0.7.0
v0.6.02023-10-18PostgreSQL 16 support, ARM64 packages, security fixesv0.6.0
v0.5.02022-04-27RPM/DEB builds, column scaling, metrics enhancementsv0.5.0
v0.4.12022-03-08Collector updates, connect-timeout parameterv0.4.1
v0.4.02021-07-12PostgreSQL 14 support, auto-discovery featurev0.4.0
v0.3.22021-02-01Shadow DSN fixes, documentation updatesv0.3.2
v0.3.12020-12-04Configuration fixes for older PostgreSQL versionsv0.3.1
v0.3.02020-10-29PostgreSQL 13 support, REST APIs, dummy serverv0.3.0
v0.2.02020-03-21YUM packages, configuration reload supportv0.2.0
v0.1.22020-02-20Dynamic configuration reload, bulky modev0.1.2
v0.1.12020-01-10Startup hang bug fixv0.1.1
v0.1.02020-01-08Initial stable releasev0.1.0
v0.0.42019-12-20Production tested releasev0.0.4
v0.0.32019-12-14Production environment testingv0.0.3
v0.0.22019-12-09Early testing releasev0.0.2
v0.0.12019-12-06Initial release with PgBouncer modev0.0.1

v1.1.1

Minor release with new collectors and bug fixes.

New Features:

  • New pg_timeline collector for timeline monitoring
  • New pg_sub_16 collector branch to exclude parallel operations in subscriptions (PostgreSQL 16+ compatibility)

Bug Fixes:

  • Fix: Add coalesce for slotname in pg_recv collector to handle NULL values

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.1.1/checksums.txt

fd5ee96511676fc11b975115a4870ed0c811056519f79ad7f24ab7ec538fa278  pg-exporter_1.1.1-1_amd64.deb
b90a08d16a6e4707d82f8f3ae282cb76acb331de607e7544532fd0b774b7aa27  pg-exporter_1.1.1-1_arm64.deb
163955f59a71da48901ffa26bb2f2db0712d31d8aeb1ab3fa463683f719a6d3a  pg-exporter_1.1.1-1_ppc64le.deb
cf4f8bc12bb8a2d1e55553f891fd31c43324e4348249727972eb44f82cd4e6c8  pg_exporter-1.1.1-1.aarch64.rpm
5a425b2f61f308b32f2d107372830c34eb685bfb312ee787f11877a20f1c4a2e  pg_exporter-1.1.1-1.ppc64le.rpm
23606ccea565368971ac2e7f39766455b507021f09457bcf61db13cb10501a16  pg_exporter-1.1.1-1.x86_64.rpm
ce74624eba92573318f50764cee4f355fa1f35697d209f70a4240f8f9d976188  pg_exporter-1.1.1.darwin-amd64.tar.gz
35fba12521dbdcc54a3792278ed4822e4ca9e951665b5e53dff7c2a0f7014ae3  pg_exporter-1.1.1.darwin-arm64.tar.gz
7699bdef15dd306289645beee8d40a123ca75dc988e46d89cdd75a1c1f650bef  pg_exporter-1.1.1.linux-amd64.tar.gz
f4baba59d27a8eb67f0c5209fed7b9f00f78db796e583cc3487701e7803671c6  pg_exporter-1.1.1.linux-arm64.tar.gz
810c3817c27358fa667714f8bfe8d52840a7ea010035e29547919ccb7c9fa781  pg_exporter-1.1.1.linux-ppc64le.tar.gz
3f6df693b3eb92fdaeaeccf99ea7e5977b2c65028a4f00bdfabbc0405b9f5f93  pg_exporter-1.1.1.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.1.1

v1.1.0

Build with Go 1.25.5 and latest dependencies, collector updates:

Collector Changes:

  • pg_setting: Major refactor for PG10-18 compatibility with missing_ok support
    • Add 13 new metrics: max_parallel_workers, max_parallel_workers_per_gather, max_parallel_maintenance_workers, shared_buffers, maintenance_work_mem, effective_cache_size, fsync, full_page_writes, autovacuum, autovacuum_max_workers, checkpoint_timeout, checkpoint_completion_target, hot_standby, synchronous_commit, io_method
    • Rename work_memory_size to work_mem
    • Change min_version from 9.6 to 10, explicit ::int type casting
  • pg_size: Fix log directory size detection, use logging_collector check instead of path pattern matching
  • pg_table: Performance optimization, replace LATERAL subqueries with JOIN for better query performance; fix tuples and frozenxid metric type from COUNTER to GAUGE; increase timeout from 1s to 2s
  • pg_vacuuming: Add PG17 collector branch with new metrics indexes_total, indexes_processed, dead_tuple_bytes for index vacuum progress tracking
  • pg_query: Increase timeout from 1s to 2s for high-load scenarios
  • pg_io: Fix typo in reuses description (“in reused” -> “is reused”)
  • pg_checkpointer: Fix description for pg_checkpointer_10 (“9.4+” -> “9.4-17”)
  • pg_db_confl: Fix description for pg_db_confl_15 (“9.1 - 16” -> “9.1 - 15”)
  • Format alignment fixes for pg_db, pg_indexing, pg_clustering, pg_backup

Other Changes:

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.0.3/checksums.txt

9c65f43e76213bb8a49d1eab2c76a27d9ab694e67bc79f0ad12769ea362b5ca2  pg-exporter_1.1.0-1_amd64.deb
bcd2cacb4febc5fb92f9eda8e733c161c8c6721416e16ec91a773503241c972d  pg-exporter_1.1.0-1_arm64.deb
2c9d4a9cb06d07af0b6dd9dd6e568af073dc9f6775abde63b45f0aae34d171b1  pg-exporter_1.1.0-1_ppc64le.deb
2934ab5b0fb16dca5a96ec1e8f230e32c72b30ca076b5e5ddf8ec553c821f7b8  pg_exporter-1.1.0-1.aarch64.rpm
3c9955f31ba93532cc7f95ff60b0658f4b6eca6a827710e2f70c0716b34eab43  pg_exporter-1.1.0-1.ppc64le.rpm
9fdefbd8e7660dcb130207901a27762e0a381857ba8cf12b63184744f92dea05  pg_exporter-1.1.0-1.x86_64.rpm
7159002016754309e0ed625a9a48049d21177883fa11d1e448eb7655ceb690cc  pg_exporter-1.1.0.darwin-amd64.tar.gz
7d55ac5cda0b1fd8ffbd5e76b9c1c1784ac8e353104a206caaadce89adda6d65  pg_exporter-1.1.0.darwin-arm64.tar.gz
8211ec24277554b9b1a36920d7865153e21c2621031d3d08f22d94cdd2ddf02f  pg_exporter-1.1.0.linux-amd64.tar.gz
d17ab7f9bf04442e642483d432d005d25bb62e0c9caa73cb7e69ee19eb89b3ae  pg_exporter-1.1.0.linux-arm64.tar.gz
c074aeb345cc30f7b6e16aa153ae3d9a12789e4425987590c3fd77c4e68a40b6  pg_exporter-1.1.0.linux-ppc64le.tar.gz
13d653e2abb023ce9526bdc2815135b82f49c044d237030f3f56b09fb016fcb7  pg_exporter-1.1.0.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.1.0

v1.0.3

  • Build with Go 1.25.4 and latest dependencies
  • Fix #80 Conflict with libpq env variables
  • Chanage default value of auto-discovery to true by @kadaffy

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.0.3/checksums.txt

7efa1a77dfd5b94813c32c7ac015b1d479b1f04fb958f6b1ed5af333e354d015  pg-exporter_1.0.3-1_amd64.deb
41e18bf18eba2ab90ac371bfb46e9152da9fe628ebd8e26766cac08325eb3b07  pg-exporter_1.0.3-1_arm64.deb
7da8ed738d254c120d42aa51d6137f84e7f4e3188bc764d4f9a1438220363a43  pg-exporter_1.0.3-1_ppc64le.deb
a214b555981156da7b7d248b1f728f8ac88a07ac8f77a66c5d8e43b40670d6b4  pg_exporter-1.0.3-1.aarch64.rpm
d876fc66e208612ebffe3c43dabce88b088d915f92584260d710b85a3a131413  pg_exporter-1.0.3-1.ppc64le.rpm
75f62d314fec50c836c534996c884d25ecea77810ab33e7ba0e9c4b783e775b4  pg_exporter-1.0.3-1.x86_64.rpm
47829a19707284bcee1b8dc47cc7d0172398bb533e6b4043950f787486712769  pg_exporter-1.0.3.darwin-amd64.tar.gz
38b6ccb72315cadea542b1f2a7b7022d0e8d48ffd4ab177bb69a0a909b99af6b  pg_exporter-1.0.3.darwin-arm64.tar.gz
36e8dff84d61a7593ff1fcec567ca4ffeaecd0be2f9eabd227ceac71b12a919a  pg_exporter-1.0.3.linux-amd64.tar.gz
6477e8ef873773a09c4f39a29444f21b5b2c71e717e52ca425bcc8e8e5448791  pg_exporter-1.0.3.linux-arm64.tar.gz
a083b51ebed2b280e2eaa0f19558494e7fa6f122a0a86a1d117206fcd090820c  pg_exporter-1.0.3.linux-ppc64le.tar.gz
a1f9b27b7190f478726d96f270a72d9dc4d3f2bcc3b0326b7c4a2607e62ea588  pg_exporter-1.0.3.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.0.3

v1.0.2

  • Build with Go 1.25.0 and latest dependencies
  • Dedicate website and homepage: https://exp.pgsty.com
  • Release with goreleaser for more os/arch with CI/CD pipeline:
    • add windows amd64 support
    • add linux ppc64le support

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.0.2/checksums.txt

683bf97f22173f2f2ec319a88e136939c2958a1f5ced4f4aa09a1357fc1c44c5  pg-exporter_1.0.2-1_amd64.deb
f62d479a92be2d03211c162b8419f968cea87ceef5b1f25f2bcd390e0b72ccb5  pg-exporter_1.0.2-1_arm64.deb
e1bbfc5a4c1b93e6f92bc7adcb4364583ab763e76e156aa5c979d6d1040f4c7a  pg-exporter_1.0.2-1_ppc64le.deb
f51d5b45448e6bbec3467d1d1dc049b1e16976f723af713c4262541ac55a039c  pg_exporter-1.0.2-1.aarch64.rpm
18380011543674e4c48b2410266b41165974d780cbc8918fc562152ba623939e  pg_exporter-1.0.2-1.ppc64le.rpm
198372d894b9598c166a0e91ca36d3c9271cb65298415f63dbffcf6da611f2bb  pg_exporter-1.0.2-1.x86_64.rpm
cbe7e07df6d180507c830cdab4cf86d40ccd62774723946307b5331d4270477d  pg_exporter-1.0.2.darwin-amd64.tar.gz
20c4a35fa244287766c1d1a19cd2e393b3fa451a96a81e5635401e69bef04b97  pg_exporter-1.0.2.darwin-arm64.tar.gz
d742111185f6a89fff34bfd304b851c8eb7a8e38444f0220786e11ed1934eff1  pg_exporter-1.0.2.linux-amd64.tar.gz
0b1f4c97c1089c4767d92eb22419b8f29c9f46fb90ddfd1e8514cc42dc41054f  pg_exporter-1.0.2.linux-arm64.tar.gz
895083fd2c7fc5409cc1a2dbaaef1e47ac7aa6a3fd5db2359012922d90bcdcc3  pg_exporter-1.0.2.linux-ppc64le.tar.gz
5f751228e7120604af9a482fb70197489fa633c38a0f2b6a3489393fbc6a10aa  pg_exporter-1.0.2.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.0.2

v1.0.1

  • Add dockerhub images: pgsty/pg_exporter
  • Bump go dependencies to the latest version, build with go 1.24.5
  • Disable pg_tsdb_hypertable collector by default, since timescaledb catalog is changed.

Checksums

d5e2d6a656eef0ae1b29cd49695f9773  pg_exporter-1.0.1-1.aarch64.rpm
cb01bb78d7b216a235363e9342803cb3  pg_exporter-1.0.1-1.x86_64.rpm
67093a756b04845f69ad333b6d458e81  pg_exporter-v1.0.1.darwin-amd64.tar.gz
2d3fdc10045d1cf494b9c1ee7f94f127  pg_exporter-v1.0.1.darwin-arm64.tar.gz
e242314461becfa99c3978ae72838ab0  pg_exporter-v1.0.1.linux-amd64.tar.gz
63de91da9ef711a53718bc60b89c82a6  pg_exporter-v1.0.1.linux-arm64.tar.gz
718f6afc004089f12c1ca6553f9b9ba5  pg-exporter_1.0.1_amd64.deb
57da7a8005cdf91ba8c1fb348e0d7367  pg-exporter_1.0.1_arm64.deb

https://github.com/pgsty/pg_exporter/releases/tag/v1.0.1

v1.0.0

Add PostgreSQL 18 metrics support

  • new collector branch pg_wal_18:
  • remove write, sync, write_time, sync_time metrics
  • move to pg_stat_io
  • new collector branch pg_checkpointer_18:
  • new metric num_done
  • new metric slru_written
  • new collector branch pg_db_18:
  • new metric parallel_workers_to_launch
  • new metric parallel_workers_launched
  • new collector branch pg_table_18:
  • table_parallel_workers_to_launch
  • table_parallel_workers_launched
  • new collector branch pg_io_18:
  • new series about WAL statistics
  • new metric read_bytes
  • new metric write_bytes
  • new metric extend_bytes
  • remove op_bytes due to fixed value
  • new collector branch pg_vacuuming_18
  • new metric delay_time
8637bc1a05b93eedfbfd3816cca468dd  pg_exporter-1.0.0-1.aarch64.rpm
a28c4c0dcdd3bf412268a2dbff79f5b9  pg_exporter-1.0.0-1.x86_64.rpm
229129209b8e6bc356c28043c7c22359  pg_exporter-v1.0.0.darwin-amd64.tar.gz
d941c2c28301269e62a8853c93facf12  pg_exporter-v1.0.0.darwin-arm64.tar.gz
5bbb94db46cacca4075d4c341c54db37  pg_exporter-v1.0.0.linux-amd64.tar.gz
da9ad428a50546a507a542d808f1c0fa  pg_exporter-v1.0.0.linux-arm64.tar.gz
0fa2395d9d7a43ab87e5c87e5b06ffcc  pg-exporter_1.0.0_amd64.deb
fed56f8a37e30cc59e85f03c81fce3f5  pg-exporter_1.0.0_arm64.deb

https://github.com/pgsty/pg_exporter/releases/tag/v1.0.0

v0.9.0

Default Collectors

  • new metrics collector for timescaledb hypertable
  • new metrics collector for citus dist node
  • new metrics collector for pg_wait_sampling wait event profile
  • pg_slot overhaul: Add 16/17 pg_replication_slot metrics
  • allow pg_slot collector run on replica since 16/17
  • refactor pg_wait collector to agg from all processes
  • restrict pg_clustering, pg_indexing, pg_vacuuming run on primary
  • mark all reset_time as GAUGE rather than COUNTER
  • fix pg_recovery_prefetch_skip_fpw type from GAUGE to COUNTER
  • fix pg_recv.state type from LABEL to GAUGE
  • Format collector in compact mode
  • new default metric pg_exporter_build_info / pgbouncer_exporter_build_info
  • add server_encoding to pg_meta collector
  • add 12 new setting metrics to pg_setting collector
  • wal_block_size
  • segment_size
  • wal_segment_size
  • wal_level
  • wal_log_hints
  • work_mem
  • hugepage_count
  • hugepage_status
  • max_wal_size
  • min_wal_size
  • max_slot_wal_keep_size

Exporter Codebase

  • normalize collector branch name with min pg ver suffix
  • Add license file to binary packages
  • move pgsty/pg_exporter repo to pgsty/pg_exporter
  • refactor server.go to reduce Compatible and PostgresPrecheck complexity
  • rename metrics collector with extra number prefix for better sorting
  • bump dependencies to the latest version
  • execute fatal collectors ahead of all non-fatal collectors, and fail fast

https://github.com/pgsty/pg_exporter/releases/tag/v0.9.0

v0.8.1

https://github.com/pgsty/pg_exporter/releases/tag/v0.8.1

v0.8.0

https://github.com/pgsty/pg_exporter/releases/tag/v0.8.0

v0.7.1

Routine update with dependabot

https://github.com/pgsty/pg_exporter/releases/tag/v0.7.1

v0.7.0

Refactor codebase for the latest go version.

https://github.com/pgsty/pg_exporter/releases/tag/v0.7.0

v0.6.0

https://github.com/pgsty/pg_exporter/releases/tag/v0.6.0

v0.5.0

Exporter Enhancement

  • Build rpm & deb with nfpm
  • Add column.default, replace when metric value is NULL
  • Add column.scale, multiply scale factor when metric value is float/int (e.g µs to second)
  • Fix /stat endpoint output
  • Add docker container pgsty/pg_exporter

Metrics Collector

  • scale bgwriter & pg_wal time unit to second
  • remove pg_class collector and move it to pg_table & pg_inex
  • add pg_class metrics to pg_table
  • add pg_class metrics to pg_index
  • enable pg_table_size by default
  • scale pg_query pg_db pg_bgwriter pg_ssl pgbouncer_stat time metrics to second

https://github.com/pgsty/pg_exporter/releases/tag/v0.5.0

v0.4.1

  • update default collectors
    • omit citus & timescaledb schemas on object monitoring
    • avoid duplicate pg_statio tuples
    • support pgbouncer v1.16
    • bug fix: pg_repl collector overlap on pg 12
  • new parameter: -T connect-timeout PG_EXPORTER_CONNECT_TIMEOUT this can be useful when monitoring remote Postgres instances.
  • now pg_exporter.yaml are renamed as pg_exporter.yml in rpm package.

https://github.com/pgsty/pg_exporter/releases/tag/v0.4.1

v0.4.0

  • Add PG 14 support
  • Default metrics configuration overhaul. (BUT you can still use the old configuration)
  • add auto-discovery , include-database and exclude-database option
  • Add multiple database monitoring implementations (with auto-discovery = on)

https://github.com/pgsty/pg_exporter/releases/tag/v0.4.0

v0.3.2

  • fix shadow DSN corner case
  • fix typo & docs

https://github.com/pgsty/pg_exporter/releases/tag/v0.3.2

v0.3.1

fix default configuration problems (especially for versions lower than 13)

  • setting primary_conninfo not exists until PG13
  • add funcid label to pg_func collector to avoid func name duplicate label
  • fix version string to pg_exporter

https://github.com/pgsty/pg_exporter/releases/tag/v0.3.1

v0.3.0

https://github.com/pgsty/pg_exporter/releases/tag/v0.3.0

  • Change default configuration, Support PostgreSQL 13 new metrics (pg_slru, pg_shmem, pg_query13,pg_backup, etc…)
  • Add a series of new REST APIs for health / recovery status check
  • Add a dummy server with fake pg_up 0 metric, which serves before PgExporter is initialized.
  • Add sslmode=disable to URL if sslmode is not given
  • fix typos and bugs

v0.2.0

  • add yum package and linux service definition
  • add a ‘skip’ flag into query config
  • fix pgbouncer_up metrics
  • add conf reload support

https://github.com/pgsty/pg_exporter/releases/tag/v0.2.0

v0.1.2

  • fix pgbouncer_up metrics
  • add dynamic configuration reload
  • remove ‘shard’ related logic
  • add a ‘bulky’ mode to default settings

https://github.com/pgsty/pg_exporter/releases/tag/v0.1.2

v0.1.1

Fix the bug that pg_exporter will hang during start-up if any query is failed.

https://github.com/pgsty/pg_exporter/releases/tag/v0.1.1

v0.1.0

It works, looks good to me.

https://github.com/pgsty/pg_exporter/releases/tag/v0.1.0

v0.0.4

Tested in real world production environment with 200+ nodes for about 2 weeks. Looks good !

https://github.com/pgsty/pg_exporter/releases/tag/v0.0.4

v0.0.3

v0.0.3 Release, Tested in Production Environment

This version is already tested in a production environment.

This project is still under rapid evolution, I would say if you want use it in production , try with caution.

https://github.com/pgsty/pg_exporter/releases/tag/v0.0.3

v0.0.2

It’s ok to try now

https://github.com/pgsty/pg_exporter/releases/tag/v0.0.2

v0.0.1

Add pgbouncer mode

https://github.com/pgsty/pg_exporter/releases/tag/v0.0.1