{"id":31904110,"url":"https://github.com/cloudfoundry-community/postgres-boshrelease","last_synced_at":"2025-10-13T13:47:23.010Z","repository":{"id":5664484,"uuid":"53687366","full_name":"cloudfoundry-community/postgres-boshrelease","owner":"cloudfoundry-community","description":"A BOSH release for deploying PostgreSQL","archived":false,"fork":false,"pushed_at":"2025-08-22T23:37:08.000Z","size":210,"stargazers_count":8,"open_issues_count":4,"forks_count":10,"subscribers_count":36,"default_branch":"main","last_synced_at":"2025-08-23T01:34:34.738Z","etag":null,"topics":["bosh-release"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudfoundry-community.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-03-11T18:15:20.000Z","updated_at":"2024-09-20T23:09:52.000Z","dependencies_parsed_at":"2022-08-06T19:00:43.911Z","dependency_job_id":null,"html_url":"https://github.com/cloudfoundry-community/postgres-boshrelease","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/cloudfoundry-community/postgres-boshrelease","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudfoundry-community%2Fpostgres-boshrelease","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudfoundry-community%2Fpostgres-boshrelease/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudfoundry-community%2Fpostgres-boshrelease/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudfoundry-community%2Fpostgres-boshrelease/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudfoundry-community","download_url":"https://codeload.github.com/cloudfoundry-community/postgres-boshrelease/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudfoundry-community%2Fpostgres-boshrelease/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279015339,"owners_count":26085685,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bosh-release"],"created_at":"2025-10-13T13:47:21.874Z","updated_at":"2025-10-13T13:47:23.004Z","avatar_url":"https://github.com/cloudfoundry-community.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PostgreSQL, BOSH-Style\n\nThis BOSH release packages up PostgreSQL so that you can deploy it\non BOSH.  It supports standalone, clustered, and HA\nconfigurations.\n\n# Supported Topologies\n\n## Standalone Configuration\n\nFor a single, standalone PostgreSQL node, you only need the\n`postgres` job:\n\n```\ninstance_groups:\n  - name: db\n    jobs:\n      - name:    postgres\n        release: postgres\n```\n\n## Clustered Configuration\n\nTo enable replication, deploy multiple nodes and set the\n`postgres.replication.enabled` property to \"yes\":\n\n```\ninstance_groups:\n  - name: db\n    instances: 4\n    jobs:\n      - name:    postgres\n        release: postgres\n        properties:\n          replication:\n            enabled: true\n```\n\nIn replicated mode, the bootstrap VM will assume the role of\nmaster, and the remaining nodes will replicate from it, forming a\nstar topology.  No special query routing is done in this\nconfiguration; applications that wish to make use of read replicas\nmust do so explicitly.\n\nPromotion of a replica is left to the operator.\n\n## HA Configuration\n\nFor a highly-available, single-IP pair of PostgreSQL nodes, the\n`vip` job can be added.  Note that you *must* deploy exactly two\ninstances, or HA won't work.  Replication must also be enabled.\n\n```\ninstance_groups:\n  - name: db\n    jobs:\n      - name:    postgres\n        release: postgres\n        properties:\n          replication:\n            enabled: true   # don't forget this!\n\n      - name:    vip\n        release: postgres\n        properties:\n          vip: 10.3.4.5\n```\n\nHA is implemented with automatic failover, if you set\n`postgres.replication.enabled` to true.\n\nOn bootstrap, if there is no data directory, the postgres job will\nrevert to a normal, index-based setup.  The first node will assume\nthe role of the master, and the second will become a replica.\n\nOnce the data directory has been populated, future restarts of the\npostgres job will attempt to contact the other node to see if it\nis a master.  If the other node responds, and reports itself as a\nmaster, the local node will attempt a `pg_basebackup` from the\nmaster and assume the role of a replica.\n\nIf the other node doesn't respond, or reports itself as a replica,\nthe local node will keep trying, for up to\n`postgres.replication.grace` seconds, at which point it will\nassume the mantle of leadership and become the master node,\nusing its current data directory as the canonical truth.\n\nEach node then starts up a `monitor` process; this process is\nresponsible for ultimately promoting a local replica to be a\nmaster, in the event that the real master goes offline.  It works\nlike this:\n\n  1. Busy-loop (via 1-second sleeps) until the local postgres\n     instance is available on its configured port.  This prevents\n     monitor from trying to restart the postgres while it is\n     running a replica `pg_basebackup`.\n\n  2. Busy-loop (again via 1-second sleeps) for as long as the\n     local postgres is a master.\n\n  3. Busy-loop (again via 1-second sleeps), checking the master\n     status of the other postgres node, until it detects that\n     either the master node has gone away (via a connection\n     timeout), or the master node has somehow become a replica.\n\n  4. Promote the local postgres node to a master.\n\nIntelligent routing can be done by colocating the `haproxy` and\n`keepalived` jobs on the instance groups with `postgres`.  HAproxy\nis configured with an external check that will only treat the\nmaster postgres node as healthy.  This ensures that either load\nbalancer node will only ever route to the write master.\n\nThe `keepalived` node trades a VRRP VIP between the `haproxy`\ninstances.  This ensures that the cluster can be accessed over a\nsingle, fixed IP address.  Each keepalived process watches its own\nhaproxy process; if it notices haproxy is down, it will terminate,\nto allow the VIP to transgress to the other node, who is assumed\nto be healthy.\n\nIt is possible to \"instance-up\" a single postgres node deploy to a\nHA cluster by adding the `vip` job and changing postgres `instances`\nto 2. More information about this can be found in `manifests/ha.yml`\n\nFor backup purposes, a route is exposed through haproxy which\nroutes directly to the read-only replica for backup jobs. By default\nit is port `7432`, but is also configurable via `vip.readonly_port`\n\nHere's a diagram:\n\n![High Availability Diagram](docs/ha.png)\n\nThe following parameters affect high availability:\n\n  - `postgres.replication.enabled` - Enables replication, which is\n    necessary for HA.  Defaults to `false`.\n\n  - `postgres.replication.grace` - How many seconds to wait for\n    the other node to report itself as a master, during boot.\n    Defaults to `15`.\n\n  - `postgres.replication.connect_timeout` - How many seconds to\n    allow a `psql` health check to attempt to connect to the other\n    node before considering it a failure.  The lower this value,\n    the faster your cluster will failover, but the higher a risk\n    of accidental failover and split-brain.  Defaults to `5`.\n\n  - `postgres.replication.psql_error_count` - How many failed PSQL\n    commands allowed before considering it a failure. The health\n    checks are PSQL commands executed every second. Poor network\n    conditions may result in a \"Connection dropped\" PSQL error.\n    The lower this value, the higher potential for accidental\n    failover and split-brain. Defaults to `3`.\n\n  - `vip.readonly_port` - Which port to access the read-only node\n    of the cluster. Defaults to `7542`.\n\n  - `vip.vip` - Which IP to use as a VIP that is traded between the\n    two nodes.\n\n### HA Failure Modes\n\nOur HA solution is focused on preventing downtime in the face of\nupgrades or other single-node failure. As such, we do not attempt to\nsolve scenarios where the two databases cannot communicate with one\nanother (e.g. network partition). In this case, it is possible that the\nreplica believes the master to be down, and will promote itself to be\nmaster. The Postgres servers are then in a state of \"split-brain\" and\nrequests to the DB will be split between the two nodes.\n\nTo mitigate this, each node checks to see who is master. If both\nnodes are master (split-brain), both immediately shut down to prevent\ninconsistent data states. *This will result in downtime*. But we\nbelieve downtime is preferable over inconsistent database states.\n\nHowever, this mitigation is not a silver bullet; it is possible that\nprolonged network outage between the two nodes will prevent them from\nchecking who is master, and will continue to operate in split-brain\nfashion. We do not attempt to solve this.\n\n### Recovery From Failure Mode\n\nAfter the database has been validated, and a node to become master\nis chosen, SSH into the node via `bosh ssh postgres/#` and then \nexecute  `/var/vcap/jobs/postgres/bin/recover` as root. This node \nwill then become master.\n\nOnce the script executes successfully, then SSH into the other node\nvia `bosh ssh postgres/#` and then execute \n`/var/vcap/jobs/postgres/bin/recover` as root. This node will then\nreplicate from the new master.\n\nYou will now have a nominal Postgres running.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudfoundry-community%2Fpostgres-boshrelease","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudfoundry-community%2Fpostgres-boshrelease","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudfoundry-community%2Fpostgres-boshrelease/lists"}