# yaml-language-server: $schema=https://schema.zeabur.app/template.json
apiVersion: zeabur.com/v1
kind: Template
metadata:
    name: PostgreSQL HA
spec:
    description: |
        High Availability PostgreSQL cluster with Patroni and etcd. Provides automatic failover and replication for production-grade database deployments.
    coverImage: https://raw.githubusercontent.com/canyugs/zeabur-template/refs/heads/main/postgresql-ha/cover.png
    icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/postgresql.svg
    variables:
        - key: POSTGRES_SUPERUSER_PASSWORD
          type: PASSWORD
          name: Superuser Password
          description: Password for PostgreSQL superuser (postgres user)
        - key: POSTGRES_REPLICATION_PASSWORD
          type: PASSWORD
          name: Replication Password
          description: Password for PostgreSQL replication user
        - key: POSTGRES_ADMIN_PASSWORD
          type: PASSWORD
          name: Admin Password
          description: Password for PostgreSQL admin user
    tags:
        - Database
        - PostgreSQL
        - High Availability
        - Patroni
    readme: "# PostgreSQL High Availability Cluster\n\nThis template deploys a highly available PostgreSQL cluster using:\n- **Patroni**: PostgreSQL HA solution with automatic failover\n- **Spilo**: Docker image combining PostgreSQL and Patroni\n- **etcd**: Distributed configuration and service discovery\n\n## Architecture\n\n- 3x etcd cluster nodes for distributed consensus\n- 3x PostgreSQL nodes with Patroni for automatic failover\n- Built-in replication and health monitoring\n\n## Connection Information\n\nUse any of the Patroni nodes to connect to the cluster:\n- **Host**: Use the hostname of patroni1, patroni2, or patroni3\n- **Port**: 5432\n- **Username**: postgres (superuser) or admin\n- **Password**: Check the environment variables in Zeabur dashboard\n\nPatroni will automatically route connections to the master node.\n\n### User Accounts\n\n| Account | Username | Privileges | Use Case |\n|---------|----------|------------|----------|\n| **Superuser** | `postgres` | Full system privileges | System administration, backup/restore |\n| **Admin** | `admin` | `CREATEDB`, `CREATEROLE` | Application connections, daily development |\n\n> **Security**: Use `admin` or create dedicated users for applications. Avoid using `superuser` directly.\n\n## Features\n\n- **Automatic Failover**: If the master fails, Patroni automatically promotes a replica\n- **Synchronous Replication**: Data consistency across nodes\n- **Health Monitoring**: REST API on port 8008 for each node\n- **Rolling Updates**: Update nodes without downtime\n- **Horizontal Scaling**: Easily add or remove nodes\n\n## Cluster Sizing\n\nThis 3-node configuration provides standard production HA (tolerates 1 node failure).\n\n| Nodes | Fault Tolerance | Use Case |\n|-------|----------------|----------|\n| 3     | 1 failure      | ✅ Production (standard) |\n| 5     | 2 failures     | ✅ Production (high availability) |\n\n## Scaling the Cluster\n\n### Adding Nodes (Scale to 5 Nodes)\n\nTo scale from 3 to 5 nodes for higher availability:\n\n1. **Add etcd nodes**:\n   - Deploy [**etcd4**](https://zeabur.com/templates/X877ER)\n   - Deploy [**etcd5**](https://zeabur.com/templates/DYGT7Y)\n\n2. **Add Patroni nodes**:\n   - Deploy [**Patroni4**](https://zeabur.com/templates/3ZC549)\n   - Deploy [**Patroni5**](https://zeabur.com/templates/LNFEJI)\n\n3. **Update existing Patroni** `ETCD3_HOSTS` to include new etcd nodes:\n   ```\n   etcd1:2379,etcd2:2379,etcd3:2379,etcd4:2379,etcd5:2379\n   ```\n\n### Removing Nodes\n\nTo scale down the cluster:\n\n1. Remove Patroni replica nodes (never remove the master)\n2. Remove etcd nodes after updating cluster configuration\n3. Always maintain odd number of nodes (3, 5, etc.)\n\n⚠️ **Important**: Never reduce below 3 nodes in production to maintain HA.\n\n\U0001F4D6 **Full Guide**: See the [complete README](https://github.com/canyugs/zeabur-template/blob/main/postgresql-ha/README.md) for step-by-step removal instructions.\n\n## Management\n\nRun inside any Patroni container:\n```bash\n# Cluster status\npatronictl list pg-ha\n\n# Show cluster configuration\npatronictl show-config pg-ha\n```\n\n## Troubleshooting\n\nCommon operations:\n\n```bash\n# Check etcd cluster health\ncurl http://etcd1:2379/health\n\n# List etcd members\ncurl -X POST http://etcd1:2379/v3/cluster/member/list\n\n# Check Patroni cluster status (run inside patroni container)\npatronictl list pg-ha\n\n# Check PostgreSQL replication\npsql -U postgres -c \"SELECT * FROM pg_stat_replication;\"\n```\n\n\U0001F4D6 **Full Troubleshooting Guide**: See the [complete README](https://github.com/canyugs/zeabur-template/blob/main/postgresql-ha/README.md#troubleshooting).\n\n## Changing Passwords\n\nTo change passwords after deployment:\n\n1. **Change in PostgreSQL**: `ALTER USER postgres PASSWORD 'new_password';`\n2. **Update environment variables** in ALL Patroni services\n3. **Rolling restart** all Patroni services\n\n\U0001F4D6 **Full Guide**: See [Password Change Guide](https://github.com/canyugs/zeabur-template/blob/main/postgresql-ha/README.md#changing-passwords)\n\n## Related Templates\n\n**etcd Expansion:**\n- [**etcd4**](https://zeabur.com/templates/X877ER): Add 4th etcd node\n- [**etcd5**](https://zeabur.com/templates/DYGT7Y): Add 5th etcd node\n\n**Patroni Expansion:**\n- [**Patroni4**](https://zeabur.com/templates/3ZC549): Add 4th PostgreSQL node\n- [**Patroni5**](https://zeabur.com/templates/LNFEJI): Add 5th PostgreSQL node\n\n## Documentation\n\n- [Complete Setup and Scaling Guide](https://github.com/canyugs/zeabur-template/blob/main/postgresql-ha/README.md)\n- [Patroni Documentation](https://patroni.readthedocs.io/)\n- [Spilo GitHub](https://github.com/zalando/spilo)\n- [etcd Documentation](https://etcd.io/docs/)\n"
    services:
        - name: etcd1
          icon: https://raw.githubusercontent.com/cncf/artwork/master/projects/etcd/icon/color/etcd-icon-color.svg
          template: PREBUILT_V2
          spec:
            source:
                image: gcr.io/etcd-development/etcd:v3.6.6
            ports:
                - id: client
                  port: 2379
                  type: TCP
                - id: peer
                  port: 2380
                  type: TCP
                - id: metrics
                  port: 2381
                  type: HTTP
            volumes:
                - id: data
                  dir: /etcd-data
            instructions:
                - title: Client Endpoint
                  content: http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}
                - title: List Members
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/cluster/member/list
                - title: Add Member (replace service name)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/cluster/member/add -d '{"peerURLs":["http://etcd4:2380"]}'
                - title: Delete Member (replace member-id)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/cluster/member/remove -d '{"ID":"<member-id>"}'
                - title: Cluster Health
                  content: curl http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/health
                - title: Put Key (test=hello)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/kv/put -d '{"key":"dGVzdA==","value":"aGVsbG8="}'
                - title: Get Key (test)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/kv/range -d '{"key":"dGVzdA=="}'
            env:
                ETCD_ADVERTISE_CLIENT_URLS:
                    default: http://etcd1:2379
                ETCD_DATA_DIR:
                    default: /etcd-data
                ETCD_INITIAL_ADVERTISE_PEER_URLS:
                    default: http://etcd1:2380
                ETCD_INITIAL_CLUSTER:
                    default: etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
                ETCD_INITIAL_CLUSTER_STATE:
                    default: new
                ETCD_INITIAL_CLUSTER_TOKEN:
                    default: etcd-cluster-pg-ha
                ETCD_LISTEN_CLIENT_URLS:
                    default: http://0.0.0.0:2379
                ETCD_LISTEN_METRICS_URLS:
                    default: http://0.0.0.0:2381
                ETCD_LISTEN_PEER_URLS:
                    default: http://0.0.0.0:2380
                ETCD_NAME:
                    default: etcd1
        - name: etcd2
          icon: https://raw.githubusercontent.com/cncf/artwork/master/projects/etcd/icon/color/etcd-icon-color.svg
          template: PREBUILT_V2
          spec:
            source:
                image: gcr.io/etcd-development/etcd:v3.6.6
            ports:
                - id: client
                  port: 2379
                  type: TCP
                - id: peer
                  port: 2380
                  type: TCP
                - id: metrics
                  port: 2381
                  type: HTTP
            volumes:
                - id: data
                  dir: /etcd-data
            instructions:
                - title: Client Endpoint
                  content: http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}
                - title: List Members
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/cluster/member/list
                - title: Add Member (replace service name)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/cluster/member/add -d '{"peerURLs":["http://etcd4:2380"]}'
                - title: Delete Member (replace member-id)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/cluster/member/remove -d '{"ID":"<member-id>"}'
                - title: Cluster Health
                  content: curl http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/health
                - title: Put Key (test=hello)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/kv/put -d '{"key":"dGVzdA==","value":"aGVsbG8="}'
                - title: Get Key (test)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/kv/range -d '{"key":"dGVzdA=="}'
            env:
                ETCD_ADVERTISE_CLIENT_URLS:
                    default: http://etcd2:2379
                ETCD_DATA_DIR:
                    default: /etcd-data
                ETCD_INITIAL_ADVERTISE_PEER_URLS:
                    default: http://etcd2:2380
                ETCD_INITIAL_CLUSTER:
                    default: etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
                ETCD_INITIAL_CLUSTER_STATE:
                    default: new
                ETCD_INITIAL_CLUSTER_TOKEN:
                    default: etcd-cluster-pg-ha
                ETCD_LISTEN_CLIENT_URLS:
                    default: http://0.0.0.0:2379
                ETCD_LISTEN_METRICS_URLS:
                    default: http://0.0.0.0:2381
                ETCD_LISTEN_PEER_URLS:
                    default: http://0.0.0.0:2380
                ETCD_NAME:
                    default: etcd2
        - name: etcd3
          icon: https://raw.githubusercontent.com/cncf/artwork/master/projects/etcd/icon/color/etcd-icon-color.svg
          template: PREBUILT_V2
          spec:
            source:
                image: gcr.io/etcd-development/etcd:v3.6.6
            ports:
                - id: client
                  port: 2379
                  type: TCP
                - id: peer
                  port: 2380
                  type: TCP
                - id: metrics
                  port: 2381
                  type: HTTP
            volumes:
                - id: data
                  dir: /etcd-data
            instructions:
                - title: Client Endpoint
                  content: http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}
                - title: List Members
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/cluster/member/list
                - title: Add Member (replace service name)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/cluster/member/add -d '{"peerURLs":["http://etcd4:2380"]}'
                - title: Delete Member (replace member-id)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/cluster/member/remove -d '{"ID":"<member-id>"}'
                - title: Cluster Health
                  content: curl http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/health
                - title: Put Key (test=hello)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/kv/put -d '{"key":"dGVzdA==","value":"aGVsbG8="}'
                - title: Get Key (test)
                  content: curl -X POST http://${PORT_FORWARDED_HOSTNAME}:${CLIENT_PORT_FORWARDED_PORT}/v3/kv/range -d '{"key":"dGVzdA=="}'
            env:
                ETCD_ADVERTISE_CLIENT_URLS:
                    default: http://etcd3:2379
                ETCD_DATA_DIR:
                    default: /etcd-data
                ETCD_INITIAL_ADVERTISE_PEER_URLS:
                    default: http://etcd3:2380
                ETCD_INITIAL_CLUSTER:
                    default: etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
                ETCD_INITIAL_CLUSTER_STATE:
                    default: new
                ETCD_INITIAL_CLUSTER_TOKEN:
                    default: etcd-cluster-pg-ha
                ETCD_LISTEN_CLIENT_URLS:
                    default: http://0.0.0.0:2379
                ETCD_LISTEN_METRICS_URLS:
                    default: http://0.0.0.0:2381
                ETCD_LISTEN_PEER_URLS:
                    default: http://0.0.0.0:2380
                ETCD_NAME:
                    default: etcd3
        - name: patroni1
          icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/postgresql.svg
          dependencies:
            - etcd1
            - etcd2
            - etcd3
          template: PREBUILT_V2
          spec:
            source:
                image: ghcr.io/zalando/spilo-15:3.2-p1
                command:
                    - sh
                    - -c
                    - |
                      # Wrapper to fix ownership after basebackup
                      (
                        while sleep 10; do
                          if [ -d /home/postgres/pgdata/pgroot ]; then
                            chown -R postgres:postgres /home/postgres/pgdata/pgroot 2>/dev/null || true
                          fi
                        done
                      ) &
                      exec /launch.sh init
            ports:
                - id: database
                  port: 5432
                  type: TCP
                - id: api
                  port: 8008
                  type: HTTP
            volumes:
                - id: data
                  dir: /home/postgres/pgdata
            instructions:
                - title: Superuser Connection String
                  content: postgresql://postgres:${POSTGRES_SUPERUSER_PASSWORD}@${PORT_FORWARDED_HOSTNAME}:${DATABASE_PORT_FORWARDED_PORT}/postgres
                - title: Admin Connection String
                  content: postgresql://admin:${POSTGRES_ADMIN_PASSWORD}@${PORT_FORWARDED_HOSTNAME}:${DATABASE_PORT_FORWARDED_PORT}/postgres
                - title: Superuser Username
                  content: postgres
                - title: Superuser Password
                  content: ${POSTGRES_SUPERUSER_PASSWORD}
                - title: Admin Username
                  content: admin
                - title: Admin Password
                  content: ${POSTGRES_ADMIN_PASSWORD}
                - title: Cluster Status (run in container)
                  content: patronictl list pg-ha
            env:
                ETCD3_HOSTS:
                    default: etcd1:2379,etcd2:2379,etcd3:2379
                PASSWORD:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                PATRONI_NAME:
                    default: patroni1
                PATRONI_POSTGRESQL_CONNECT_ADDRESS:
                    default: ${CONTAINER_HOSTNAME}:5432
                PATRONI_POSTGRESQL_LISTEN:
                    default: 0.0.0.0:5432
                PATRONI_REPLICATION_PASSWORD:
                    default: ${POSTGRES_REPLICATION_PASSWORD}
                PATRONI_REPLICATION_USERNAME:
                    default: replicator
                PATRONI_RESTAPI_CONNECT_ADDRESS:
                    default: ${CONTAINER_HOSTNAME}:8008
                PATRONI_RESTAPI_LISTEN:
                    default: 0.0.0.0:8008
                PATRONI_SUPERUSER_PASSWORD:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                PATRONI_SUPERUSER_USERNAME:
                    default: postgres
                PATRONI_admin_PASSWORD:
                    default: ${POSTGRES_ADMIN_PASSWORD}
                PATRONI_admin_USERNAME:
                    default: admin
                PGPASSWORD_ADMIN:
                    default: ${POSTGRES_ADMIN_PASSWORD}
                PGPASSWORD_STANDBY:
                    default: ${POSTGRES_REPLICATION_PASSWORD}
                PGPASSWORD_SUPERUSER:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                POSTGRES_CONNECTION_STRING:
                    default: postgresql://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DATABASE}
                    expose: true
                POSTGRES_DATABASE:
                    default: postgres
                    expose: true
                POSTGRES_DB:
                    default: postgres
                POSTGRES_HOST:
                    default: ${CONTAINER_HOSTNAME}
                    expose: true
                POSTGRES_PASSWORD:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                    expose: true
                POSTGRES_PORT:
                    default: ${DATABASE_PORT}
                    expose: true
                POSTGRES_USER:
                    default: postgres
                POSTGRES_USERNAME:
                    default: postgres
                    expose: true
                SCOPE:
                    default: pg-ha
            healthCheck:
                type: HTTP
                port: api
                http:
                    path: /health
        - name: patroni2
          icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/postgresql.svg
          dependencies:
            - etcd1
            - etcd2
            - etcd3
          template: PREBUILT_V2
          spec:
            source:
                image: ghcr.io/zalando/spilo-15:3.2-p1
                command:
                    - sh
                    - -c
                    - |
                      # Wrapper to fix ownership after basebackup
                      (
                        while sleep 10; do
                          if [ -d /home/postgres/pgdata/pgroot ]; then
                            chown -R postgres:postgres /home/postgres/pgdata/pgroot 2>/dev/null || true
                          fi
                        done
                      ) &
                      exec /launch.sh init
            ports:
                - id: database
                  port: 5432
                  type: TCP
                - id: api
                  port: 8008
                  type: HTTP
            volumes:
                - id: data
                  dir: /home/postgres/pgdata
            instructions:
                - title: Superuser Connection String
                  content: postgresql://postgres:${POSTGRES_SUPERUSER_PASSWORD}@${PORT_FORWARDED_HOSTNAME}:${DATABASE_PORT_FORWARDED_PORT}/postgres
                - title: Admin Connection String
                  content: postgresql://admin:${POSTGRES_ADMIN_PASSWORD}@${PORT_FORWARDED_HOSTNAME}:${DATABASE_PORT_FORWARDED_PORT}/postgres
                - title: Superuser Username
                  content: postgres
                - title: Superuser Password
                  content: ${POSTGRES_SUPERUSER_PASSWORD}
                - title: Admin Username
                  content: admin
                - title: Admin Password
                  content: ${POSTGRES_ADMIN_PASSWORD}
                - title: Cluster Status (run in container)
                  content: patronictl list pg-ha
            env:
                ETCD3_HOSTS:
                    default: etcd1:2379,etcd2:2379,etcd3:2379
                PASSWORD:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                PATRONI_NAME:
                    default: patroni2
                PATRONI_POSTGRESQL_CONNECT_ADDRESS:
                    default: ${CONTAINER_HOSTNAME}:5432
                PATRONI_POSTGRESQL_LISTEN:
                    default: 0.0.0.0:5432
                PATRONI_REPLICATION_PASSWORD:
                    default: ${POSTGRES_REPLICATION_PASSWORD}
                PATRONI_REPLICATION_USERNAME:
                    default: replicator
                PATRONI_RESTAPI_CONNECT_ADDRESS:
                    default: ${CONTAINER_HOSTNAME}:8008
                PATRONI_RESTAPI_LISTEN:
                    default: 0.0.0.0:8008
                PATRONI_SUPERUSER_PASSWORD:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                PATRONI_SUPERUSER_USERNAME:
                    default: postgres
                PATRONI_admin_PASSWORD:
                    default: ${POSTGRES_ADMIN_PASSWORD}
                PATRONI_admin_USERNAME:
                    default: admin
                PGPASSWORD_ADMIN:
                    default: ${POSTGRES_ADMIN_PASSWORD}
                PGPASSWORD_STANDBY:
                    default: ${POSTGRES_REPLICATION_PASSWORD}
                PGPASSWORD_SUPERUSER:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                POSTGRES_CONNECTION_STRING:
                    default: postgresql://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DATABASE}
                    expose: true
                POSTGRES_DATABASE:
                    default: postgres
                    expose: true
                POSTGRES_DB:
                    default: postgres
                POSTGRES_HOST:
                    default: ${CONTAINER_HOSTNAME}
                    expose: true
                POSTGRES_PASSWORD:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                    expose: true
                POSTGRES_PORT:
                    default: ${DATABASE_PORT}
                    expose: true
                POSTGRES_USER:
                    default: postgres
                POSTGRES_USERNAME:
                    default: postgres
                    expose: true
                SCOPE:
                    default: pg-ha
            healthCheck:
                type: HTTP
                port: api
                http:
                    path: /health
        - name: patroni3
          icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/postgresql.svg
          dependencies:
            - etcd1
            - etcd2
            - etcd3
          template: PREBUILT_V2
          spec:
            source:
                image: ghcr.io/zalando/spilo-15:3.2-p1
                command:
                    - sh
                    - -c
                    - |
                      # Wrapper to fix ownership after basebackup
                      (
                        while sleep 10; do
                          if [ -d /home/postgres/pgdata/pgroot ]; then
                            chown -R postgres:postgres /home/postgres/pgdata/pgroot 2>/dev/null || true
                          fi
                        done
                      ) &
                      exec /launch.sh init
            ports:
                - id: database
                  port: 5432
                  type: TCP
                - id: api
                  port: 8008
                  type: HTTP
            volumes:
                - id: data
                  dir: /home/postgres/pgdata
            instructions:
                - title: Superuser Connection String
                  content: postgresql://postgres:${POSTGRES_SUPERUSER_PASSWORD}@${PORT_FORWARDED_HOSTNAME}:${DATABASE_PORT_FORWARDED_PORT}/postgres
                - title: Admin Connection String
                  content: postgresql://admin:${POSTGRES_ADMIN_PASSWORD}@${PORT_FORWARDED_HOSTNAME}:${DATABASE_PORT_FORWARDED_PORT}/postgres
                - title: Superuser Username
                  content: postgres
                - title: Superuser Password
                  content: ${POSTGRES_SUPERUSER_PASSWORD}
                - title: Admin Username
                  content: admin
                - title: Admin Password
                  content: ${POSTGRES_ADMIN_PASSWORD}
                - title: Cluster Status (run in container)
                  content: patronictl list pg-ha
            env:
                ETCD3_HOSTS:
                    default: etcd1:2379,etcd2:2379,etcd3:2379
                PASSWORD:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                PATRONI_NAME:
                    default: patroni3
                PATRONI_POSTGRESQL_CONNECT_ADDRESS:
                    default: ${CONTAINER_HOSTNAME}:5432
                PATRONI_POSTGRESQL_LISTEN:
                    default: 0.0.0.0:5432
                PATRONI_REPLICATION_PASSWORD:
                    default: ${POSTGRES_REPLICATION_PASSWORD}
                PATRONI_REPLICATION_USERNAME:
                    default: replicator
                PATRONI_RESTAPI_CONNECT_ADDRESS:
                    default: ${CONTAINER_HOSTNAME}:8008
                PATRONI_RESTAPI_LISTEN:
                    default: 0.0.0.0:8008
                PATRONI_SUPERUSER_PASSWORD:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                PATRONI_SUPERUSER_USERNAME:
                    default: postgres
                PATRONI_admin_PASSWORD:
                    default: ${POSTGRES_ADMIN_PASSWORD}
                PATRONI_admin_USERNAME:
                    default: admin
                PGPASSWORD_ADMIN:
                    default: ${POSTGRES_ADMIN_PASSWORD}
                PGPASSWORD_STANDBY:
                    default: ${POSTGRES_REPLICATION_PASSWORD}
                PGPASSWORD_SUPERUSER:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                POSTGRES_CONNECTION_STRING:
                    default: postgresql://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DATABASE}
                    expose: true
                POSTGRES_DATABASE:
                    default: postgres
                    expose: true
                POSTGRES_DB:
                    default: postgres
                POSTGRES_HOST:
                    default: ${CONTAINER_HOSTNAME}
                    expose: true
                POSTGRES_PASSWORD:
                    default: ${POSTGRES_SUPERUSER_PASSWORD}
                    expose: true
                POSTGRES_PORT:
                    default: ${DATABASE_PORT}
                    expose: true
                POSTGRES_USER:
                    default: postgres
                POSTGRES_USERNAME:
                    default: postgres
                    expose: true
                SCOPE:
                    default: pg-ha
            healthCheck:
                type: HTTP
                port: api
                http:
                    path: /health
