<@ULVA73B9P> For prefect 3.7.0 using prefect-helm ...
# ask-marvin
r
@Marvin For prefect 3.7.0 using prefect-helm show how a fully fledged postgresql and pybouncer app would look like in terms of kubernetes charts. Spec for loads of, say 5,000, flow runs per day. Currently using the prefect-server postresql subchart, but want to move away from that. The new apps would be in the same namespace.
m
thought for 143.4 seconds
Yes — for Prefect 3.7.0 with
prefect-helm
, a good production direction is: 1. disable the built-in PostgreSQL subchart 2. run PostgreSQL as its own app/chart 3. run PgBouncer as its own app/chart 4. point Prefect at PgBouncer, not directly at PostgreSQL That gives you cleaner separation, easier upgrades, and better DB connection handling. Important Prefect-specific note: if you put PgBouncer in transaction pooling mode, you should disable asyncpg/prepared statement caching for Prefect. --- ## High-level layout In the same namespace, the apps would typically look like:
Copy code
text
namespace: prefect

- prefect-server          (Helm release: prefect/prefect-server)
- postgres                (separate chart/app)
- pgbouncer               (separate chart/app)
- redis                   (either part of prefect chart or separate)
- secrets/configmaps
- PVCs for postgres
Traffic flow:
Copy code
text
Prefect API / background services
            |
            v
       PgBouncer service
            |
            v
      PostgreSQL service
--- ## What Prefect expects With the Helm chart, the key pattern is: -
postgresql.enabled: false
-
sqlite.enabled: false
- provide DB connection info via the chart secret / env - use
host: pgbouncer...
and
port: 6432
Research indicates Prefect is fine with PgBouncer as long as the connection URL points to it. The main caveat is connection/pool compatibility settings. --- ## Recommended chart/app split For your scale — ~5,000 flow runs/day — this is very reasonable: ### 1) PostgreSQL app Use a dedicated PostgreSQL chart/app, for example: - Bitnami PostgreSQL - CloudNativePG - Crunchy - or your managed PostgreSQL if you later move off-cluster If you want “fully fledged,” I would not use a hand-written Deployment for production unless you really want to own all HA/backup logic yourself. A real Postgres operator/chart is better. ### 2) PgBouncer app Use a dedicated PgBouncer chart/app. This can be: - Bitnami PgBouncer - another PgBouncer chart - or your own Deployment if you want full control ### 3) Prefect app Use
prefect/prefect-server
, but configured against the external DB. --- ## Example architecture using Helm releases
Copy code
text
helm release: postgres
chart: bitnami/postgresql

helm release: pgbouncer
chart: bitnami/pgbouncer

helm release: prefect
chart: prefect/prefect-server
All in namespace
prefect
. --- ## Prefect values example Here is what the Prefect Helm values would look like conceptually.
Copy code
yaml
postgresql:
  enabled: false

sqlite:
  enabled: false

secret:
  create: true
  name: prefect-db-connection
  username: prefect_user
  password: your-strong-password
  host: pgbouncer.prefect.svc.cluster.local
  port: "6432"
  database: prefect

global:
  prefect:
    env:
      - name: PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_SIZE
        value: "5"
      - name: PREFECT_SERVER_DATABASE_SQLALCHEMY_MAX_OVERFLOW
        value: "10"
      - name: PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_TIMEOUT
        value: "30"
      - name: PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_RECYCLE
        value: "3600"

      # Important for PgBouncer transaction pooling
      - name: PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_STATEMENT_CACHE_SIZE
        value: "0"

server:
  replicaCount: 2
  resources:
    requests:
      cpu: 500m
      memory: 512Mi
    limits:
      cpu: "1"
      memory: 1Gi

backgroundServices:
  runAsSeparateDeployment: true
  replicaCount: 1
  resources:
    requests:
      cpu: 500m
      memory: 512Mi
    limits:
      cpu: "1"
      memory: 1Gi

redis:
  enabled: true
If you already run Redis elsewhere, you could externalize that too. --- ## PostgreSQL app example If using a separate PostgreSQL chart, a production-ish baseline would look like: ```yaml auth: username: prefect_user password: your-strong-password database: prefect primary: persistence: enabled: true size: 200Gi resources: requests:
cpu: 1 memory: 4Gi limits: cpu: 2 memory: 8Gi extendedConfiguration: | max_connections = 200 shared_buffers = 2GB effective_cache_size = 6GB maintenance_work_mem = 512MB checkpoint_completion_target = 0.9 wal_buffers = 16MB default_statistics_target = 100 random_page_cost = 1.1 effective_io_concurrency = 200 architecture: standalone
Copy code
For *5,000 flow runs/day*, this is not an enormous workload for PostgreSQL, but retention/logging/task-run cardinality matters a lot. I’d treat these numbers as *starting points*, not exact sizing.

If you need HA, backups, PITR, and failover, I’d strongly lean toward an operator like CloudNativePG instead of a simple standalone chart.

---

## PgBouncer app example

A production-ish PgBouncer config for Prefect usually looks like this:

```yaml
config:
  databases:
    prefect:
      host: postgres-postgresql.prefect.svc.cluster.local
      port: 5432
      dbname: prefect

  pgbouncer:
    pool_mode: transaction
    max_client_conn: 1000
    default_pool_size: 25
    min_pool_size: 10
    reserve_pool_size: 5
    reserve_pool_timeout: 3
    server_lifetime: 3600
    server_idle_timeout: 600
    server_connect_timeout: 15
    stats_period: 60

replicaCount: 2

resources:
  requests:
    cpu: 100m
    memory: 256Mi
  limits:
    cpu: 500m
    memory: 512Mi

auth:
  username: prefect_user
  password: your-strong-password
The key setting is:
Copy code
yaml
pool_mode: transaction
And then in Prefect:
Copy code
yaml
- name: PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_STATEMENT_CACHE_SIZE
  value: "0"
That combination is the important compatibility piece. --- ## “Fully fledged” app picture If you want a more realistic production picture, I’d think of it like this: ### PostgreSQL app responsibilities - persistent storage - backups / snapshots - possibly replicas - monitoring - vacuum/autovacuum tuning - versioned upgrades independent of Prefect ### PgBouncer app responsibilities - absorb many short-lived app connections - smooth spikes from API/background services/workers - let Postgres keep a lower real connection count - allow rolling restarts of Prefect with less DB churn ### Prefect app responsibilities - API - UI - orchestration logic - background services - migrations --- ## Suggested scaling for your workload For ~5,000 flow runs/day, I’d start around here: ### Prefect -
server.replicaCount: 2
-
backgroundServices.runAsSeparateDeployment: true
-
backgroundServices.replicaCount: 1
or
2
depending on HA goals ### PgBouncer -
2
replicas -
default_pool_size: 20-25
-
max_client_conn: 500-1000
### PostgreSQL - 1 primary, 4-8 GiB memory, decent SSD-backed PVC - 100-200 GiB storage to give yourself breathing room - monitor growth before over-optimizing Again, total DB size depends a lot on: - flow run retention - task run volume per flow - event/log verbosity - automations/events usage --- ## Example install order 1. install PostgreSQL 2. install PgBouncer 3. install Prefect configured to use PgBouncer 4. validate migrations/connectivity 5. cut over from the old subchart-backed DB --- ## Example Helm release flow Conceptually:
Copy code
bash
helm install postgres bitnami/postgresql -n prefect -f postgres-values.yaml
helm install pgbouncer bitnami/pgbouncer -n prefect -f pgbouncer-values.yaml
helm install prefect prefect/prefect-server -n prefect -f prefect-values.yaml
I’m not giving exact CLI flags beyond the basic shape since chart names/values differ a bit by chart source, but this is the pattern. --- ## Practical recommendations ### 1) Prefer a real Postgres chart/operator If this is important production infrastructure, use a proper PostgreSQL chart/operator instead of raw manifests. ### 2) Use PgBouncer in front of Prefect This is a good fit if you have multiple Prefect pods and bursty orchestration activity. ### 3) Keep DB credentials in K8s secrets
Prefer secret references over inline values in Git. ### 4) Separate background services Using separate background services is useful so scheduler/services are not tightly coupled to API pod scaling. ### 5) Test migrations on the new DB Before cutover, validate: - schema migrations - UI/API startup - flow run creation - worker polling - logs/events --- ## What I would deploy If you want a concise recommendation: - PostgreSQL: CloudNativePG or Bitnami PostgreSQL - PgBouncer: separate chart, 2 replicas, transaction pooling - Prefect: external DB config, built-in PostgreSQL disabled - Namespace: same namespace is totally fine --- ## Useful links - Prefect Helm repo: prefect-helm - Prefect Helm chart docs: prefect-server chart - Prefect server repo/docs: Prefect --- If you want, I can next give you one of these two things: 1. a complete three-chart example using Bitnami PostgreSQL + Bitnami PgBouncer + prefect-server values, or 2. an Argo CD / Flux app-of-apps layout for these three apps in the same namespace.
n
let me know if you have any issues with this! we use flux for some large prefect server instances backed by managed pg / redis. could probably document some patterns from that if it'd be helpful
r
@Nate cheers! I am ramping up the prefect load quite a bit, and people get understandably concerned that it's just me mucking about with calibrating the Postgres settings to match the load. So not urgent, but yeah some kind of intelligent profiler to look at the days flow runs, artifacts, events, and recommend the relevant settings. Not just for Postgres but for background services and redis and all those gleeful backend stuff I am slowly becoming an orange belt in… thinking there could be a utility flow to advise on that. Perhaps with a fastmcp hook into Marvin? Dunno just thinking how to leverage. Been working on heaps of flows for sysop admin check and whatnot. So maybe a bit beyond the normal metrics. In theory one could write a set of generic sysop scripts to do this… ok, enough blue sky for now. But if you have something later let me know