mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 01:15:03 +03:00
feat(self-hosted): add pgbouncer override (#49052)
This commit is contained in:
1 parent
facc2df09e
commit
768cf11b9c
5 files changed
+123
-7
No files matched your search
@@ -20,7 +20,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config: [default, logs, kong, rustfs, kong-rustfs]
|
||||
config: [default, logs, kong, rustfs, kong-rustfs, pgbouncer]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
@@ -57,6 +57,8 @@ jobs:
|
||||
docker compose -f docker-compose.yml -f docker-compose.rustfs.yml up --quiet-pull --wait --wait-timeout 180
|
||||
elif [ "${{ matrix.config }}" = "kong-rustfs" ]; then
|
||||
docker compose -f docker-compose.yml -f docker-compose.kong.yml -f docker-compose.rustfs.yml up --quiet-pull --wait --wait-timeout 180
|
||||
elif [ "${{ matrix.config }}" = "pgbouncer" ]; then
|
||||
docker compose -f docker-compose.yml -f docker-compose.pgbouncer.yml up --quiet-pull --wait --wait-timeout 180
|
||||
else
|
||||
docker compose up --quiet-pull --wait --wait-timeout 180
|
||||
fi
|
||||
|
||||
+8
-3
@@ -119,19 +119,24 @@ POSTGRES_PORT=5432
|
||||
|
||||
|
||||
############
|
||||
# Supavisor - Database pooler
|
||||
# Database pooler
|
||||
############
|
||||
|
||||
# Self-hosted Supabase uses Supavisor as the default database pooler.
|
||||
# If you use the PgBouncer docker-compose override, Supavisor is disabled
|
||||
# and the pooler settings below are used to configure PgBouncer instead.
|
||||
#
|
||||
# Supavisor exposes POSTGRES_PORT and POOLER_PROXY_PORT_TRANSACTION,
|
||||
# POSTGRES_PORT is used for session mode pooling
|
||||
# PgBouncer only exposes POOLER_PROXY_PORT_TRANSACTION.
|
||||
#
|
||||
# Port to use for transaction mode pooling connections
|
||||
POOLER_PROXY_PORT_TRANSACTION=6543
|
||||
|
||||
# Maximum number of PostgreSQL connections Supavisor opens per pool
|
||||
# Maximum number of PostgreSQL connections Supavisor or PgBouncer opens per pool
|
||||
POOLER_DEFAULT_POOL_SIZE=20
|
||||
|
||||
# Maximum number of client connections Supavisor accepts per pool
|
||||
# Maximum number of client connections Supavisor or PgBouncer accepts per pool
|
||||
POOLER_MAX_CLIENT_CONN=100
|
||||
|
||||
# Unique Supavisor tenant identifier
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# PgBouncer override for self-hosted Supabase
|
||||
#
|
||||
# Replaces the default Supavisor pooler with PgBouncer in transaction mode.
|
||||
#
|
||||
# Usage:
|
||||
# docker compose -f docker-compose.yml -f docker-compose.pgbouncer.yml up -d
|
||||
#
|
||||
# Or use run.sh to add PgBouncer to the stack:
|
||||
# sh run.sh config add pgbouncer
|
||||
# sh run.sh start
|
||||
#
|
||||
|
||||
services:
|
||||
supavisor: !reset null
|
||||
|
||||
# To expose Postgres directly on POSTGRES_PORT (5432), uncomment the "db"
|
||||
# section below.
|
||||
# WARNING: this opens Postgres to the external traffic. Restrict access at the
|
||||
# network level if necessary.
|
||||
#db:
|
||||
# ports:
|
||||
# - ${POSTGRES_PORT}:${POSTGRES_PORT}
|
||||
|
||||
pgbouncer:
|
||||
container_name: supabase-pgbouncer
|
||||
image: edoburu/pgbouncer:v1.25.2-p0
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- ${POOLER_PROXY_PORT_TRANSACTION}:6432
|
||||
healthcheck:
|
||||
test: ['CMD', 'pg_isready', '-h', 'localhost', '-p', '6432']
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 5s
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
# PgBouncer connects to Postgres as the dedicated `pgbouncer` role and
|
||||
# looks up every other role's password on demand via the auth_query below.
|
||||
DB_USER: pgbouncer
|
||||
DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
DB_HOST: ${POSTGRES_HOST}
|
||||
DB_PORT: ${POSTGRES_PORT}
|
||||
DB_NAME: ${POSTGRES_DB}
|
||||
LISTEN_PORT: 6432
|
||||
AUTH_TYPE: scram-sha-256
|
||||
AUTH_QUERY: SELECT * FROM pgbouncer.get_auth($$1)
|
||||
# POOL_MODE can be: session, transaction, or statement
|
||||
POOL_MODE: transaction
|
||||
DEFAULT_POOL_SIZE: ${POOLER_DEFAULT_POOL_SIZE}
|
||||
MAX_CLIENT_CONN: ${POOLER_MAX_CLIENT_CONN}
|
||||
# Only the `pgbouncer` role may run get_auth / the admin console.
|
||||
ADMIN_USERS: pgbouncer
|
||||
STATS_USERS: pgbouncer
|
||||
@@ -148,9 +148,19 @@ check_logs_if_running analytics \
|
||||
'Executing startup tasks' \
|
||||
'Ensuring single tenant user is seeded'
|
||||
|
||||
check_logs supavisor \
|
||||
'Connected to Postgres database' \
|
||||
'HEAD /api/health$'
|
||||
# Database pooler: Supavisor by default, or PgBouncer when the pgbouncer
|
||||
# override is enabled (which disables Supavisor). Check whichever is running.
|
||||
if is_service_running supavisor; then
|
||||
check_logs supavisor \
|
||||
'Connected to Postgres database' \
|
||||
'HEAD /api/health$'
|
||||
elif is_service_running pgbouncer; then
|
||||
check_logs pgbouncer \
|
||||
'process up: PgBouncer' \
|
||||
'listening on .*6432'
|
||||
else
|
||||
fail_msg "pooler (neither supavisor nor pgbouncer is running)"
|
||||
fi
|
||||
|
||||
check_logs_if_running vector \
|
||||
'Vector has started'
|
||||
|
||||
@@ -77,6 +77,16 @@ http_body() {
|
||||
curl -s "$@" "$url"
|
||||
}
|
||||
|
||||
# Is a compose service running? Falls back to a label lookup so it works
|
||||
# regardless of which override files are loaded in this shell.
|
||||
service_running() {
|
||||
svc="$1"
|
||||
docker compose ps --services --status running 2>/dev/null | grep -qx "$svc" && return 0
|
||||
docker ps --filter "label=com.docker.compose.project=${COMPOSE_PROJECT_NAME:-supabase}" \
|
||||
--filter "label=com.docker.compose.service=$svc" \
|
||||
--filter "status=running" --quiet | grep -q '.'
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo "=== Self-hosted smoke test against $BASE_URL ==="
|
||||
echo ""
|
||||
@@ -487,6 +497,39 @@ check "Realtime /api/openapi blocked" "403" \
|
||||
"$(http_status "$BASE_URL/realtime/v1/api/openapi" \
|
||||
-H "apikey: $ANON_KEY")"
|
||||
|
||||
# ---------------------------------------------
|
||||
# 10. Database pooler (transaction mode)
|
||||
# ---------------------------------------------
|
||||
|
||||
echo ""
|
||||
echo "--- Database pooler (transaction mode) ---"
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
pg_password=$(grep '^POSTGRES_PASSWORD=' .env | cut -d= -f2-)
|
||||
pooler_tenant_id=$(grep '^POOLER_TENANT_ID=' .env | cut -d= -f2-)
|
||||
# Connect as the postgres role through whichever transaction pooler is running:
|
||||
# Supavisor (default) -> service 'supavisor', port 6543, user 'postgres.<tenant>'
|
||||
# PgBouncer (override) -> service 'pgbouncer', port 6432 (published as 6543), user 'postgres'
|
||||
# psql runs inside the db container (always has a client) and reaches the
|
||||
# pooler over the compose network.
|
||||
if service_running supavisor; then
|
||||
pooler_user="postgres.$pooler_tenant_id"; pooler_host="supavisor"; pooler_port=6543
|
||||
elif service_running pgbouncer; then
|
||||
pooler_user="postgres"; pooler_host="pgbouncer"; pooler_port=6432
|
||||
else
|
||||
pooler_user=""
|
||||
fi
|
||||
if [ -n "$pooler_user" ]; then
|
||||
pooler_result=$(docker exec -e PGPASSWORD="$pg_password" supabase-db \
|
||||
psql "host=$pooler_host port=$pooler_port user=$pooler_user dbname=postgres sslmode=disable" \
|
||||
-tAc "select 'pooler_ok';" 2>/dev/null | tr -d '[:space:]')
|
||||
check "Pooler transaction-mode query (as postgres)" "pooler_ok" "$pooler_result"
|
||||
else
|
||||
check "Pooler running (supavisor or pgbouncer)" "true" "false"
|
||||
fi
|
||||
else
|
||||
echo " SKIP: docker not available"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------
|
||||
# Summary
|
||||
# ---------------------------------------------
|
||||
|
||||
Reference in new issue
Block a user