Dennis Hinnenkamp
09/11/2025, 11:04 AMMarvin
09/11/2025, 11:04 AMDennis Hinnenkamp
09/11/2025, 11:05 AMMarvin
09/11/2025, 11:05 AMMarvin
09/11/2025, 11:08 AMvalues.yaml snippets for the server and database config?
- Are you using Cloud SQL for Postgres (private IP or Cloud SQL Auth Proxy), or another Postgres?
- Can you paste the exact error lines from the failing pod(s) that mention “prefect-server-postgresql-connection”?
In the meantime, here are the most common root causes and how to check them:
1) Verify the database connection env var is present in the server pods
- Prefect 3.x expects PREFECT_API_DATABASE_CONNECTION_URL to be set to an async Postgres URL:
<postgresql+asyncpg://USER:PASSWORD@HOST:PORT/DBNAME?sslmode=require>
If you use postgresql://... without +asyncpg, connections will fail.
- Check that this env var is actually present in the API pod:
kubectl -n <namespace> exec -it deploy/prefect-server-api -- printenv | grep PREFECT_API_DATABASE_CONNECTION_URL
- If you’re referencing a Kubernetes Secret, confirm the Secret name/key matches what your Deployment expects. The name “prefect-server-postgresql-connection” looks like a Secret name. Make sure it exists and the key inside matches the env var source.
2) Inspect the failing pods and events
- Check the API and migration pods for Postgres errors:
kubectl -n <namespace> logs deploy/prefect-server-api --tail=200
kubectl -n <namespace> get pods
kubectl -n <namespace> logs <prefect-server-migrations-pod-name> --tail=200
kubectl -n <namespace> describe pod <prefect-server-api-pod>
kubectl -n <namespace> get events --sort-by='.lastTimestamp'
- If migrations are failing, that usually points to bad credentials, missing permissions on the database, or an unreachable database host.
3) Cloud SQL specifics (if applicable)
- If you’re using Cloud SQL:
- With private IP: ensure your GKE nodes can reach the Cloud SQL private IP and firewall rules/network policies allow it.
- With the Cloud SQL Auth Proxy: run it as a sidecar or DaemonSet and point the HOST:PORT in the connection URL to the proxy (usually 127.0.0.1:5432) and include sslmode=disable or whatever is appropriate for the proxy configuration.
- Test connectivity from the cluster with a temporary pod (replace placeholders):
kubectl -n <namespace> run psql-test --rm -it --image=postgres:16 --restart=Never -- \
psql "host=<HOST> port=<PORT> user=<USER> dbname=<DBNAME> sslmode=require"
If this fails, the issue is networking/credentials rather than Prefect.
4) Validate credentials and permissions
- Ensure the Postgres user in the URL can connect to the DB and run migrations (CREATE/ALTER on the schema).
- If you rotated passwords or changed secrets, make sure the Deployment picked up the change (roll the pods).
5) Confirm Helm values/Secret wiring (if using the Helm chart)
- The chart should set PREFECT_API_DATABASE_CONNECTION_URL via values or a Secret. Double-check:
- The Secret exists:
kubectl -n <namespace> get secret prefect-server-postgresql-connection -o yaml
- The key name in the Secret matches the `envFrom`/`valueFrom` reference in the Deployment.
- After fixes, restart pods:
kubectl -n <namespace> rollout restart deploy/prefect-server-api
Helpful references:
- Prefect 3: Deploy Prefect Server with Helm
- Prefect 3: PREFECT_API_DATABASE_CONNECTION_URL setting
- Prefect 3: Self-hosted server CLI
If you can share:
- The exact Postgres error lines
- Your values.yaml DB section (with secrets redacted)Marvin
09/11/2025, 11:08 AMDennis Hinnenkamp
09/11/2025, 11:11 AMpostgresql:
enabled: true
primary:
# Ephemeral PostgreSQL for dev/testing.
persistence:
enabled: false
resources:
# DB pod resources
requests:
cpu: 1
memory: 1Gi
limits:
cpu: 1
memory: 1Gi
ingress:
enabled: true
className: nginx-internal-traffic
annotations:
<http://cert-manager.io/cluster-issuer|cert-manager.io/cluster-issuer>: letsencrypt-internal-v2
<http://acme.cert-manager.io/http01-ingress-class|acme.cert-manager.io/http01-ingress-class>: nginx-internal-traffic
# OAuth2 Proxy
<http://nginx.ingress.kubernetes.io/auth-url|nginx.ingress.kubernetes.io/auth-url>: "<http://oauth2-proxy.oauth2-proxy.svc.cluster.local/oauth2/auth>"
<http://nginx.ingress.kubernetes.io/auth-signin|nginx.ingress.kubernetes.io/auth-signin>: "<https://oauth2.dglecom.net/oauth2/start?rd=https://$host$escaped_request_uri>"
<http://nginx.ingress.kubernetes.io/auth-snippet|nginx.ingress.kubernetes.io/auth-snippet>: |
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Method $request_method;
<http://nginx.ingress.kubernetes.io/ssl-redirect|nginx.ingress.kubernetes.io/ssl-redirect>: "true"
<http://nginx.ingress.kubernetes.io/configuration-snippet|nginx.ingress.kubernetes.io/configuration-snippet>: |
if ($scheme = https) {
add_header Strict-Transport-Security "max-age=0;";
}
proxy_intercept_errors off;
host:
hostname: <http://prefect.svc.dglecom.net|prefect.svc.dglecom.net>
path: /
pathType: Prefix
tls: true
extraTls:
- hosts:
- <http://prefect.svc.dglecom.net|prefect.svc.dglecom.net>
secretName: prefect-origin-tls
extraPaths:
- path: /api
backend:
service:
name: prefect-server
port:
number: 4200
server:
uiConfig:
# External URL of public API; informs the UI and remote clients.
prefectUiApiUrl: "<https://prefect.svc.dglecom.net/api>"
resources:
# Prefect server container resources;
requests:
cpu: "1"
memory: 1Gi
limits:
cpu: "1"
memory: 1GiMarvin
09/11/2025, 11:11 AMMarvin
09/11/2025, 11:13 AMhelm list -n <namespace>
kubectl -n <namespace> get svc,secret | grep -E 'prefect|postgresql'
kubectl -n <namespace> get all -l <http://app.kubernetes.io/instance=<your-release-name|app.kubernetes.io/instance=<your-release-name>>
- If your release name is “prefect”, you’ll typically see “prefect-postgresql”, not “prefect-server-postgresql”. That would explain the “Resource not found” messages.
2) Fix your Ingress backend service name
- You have:
extraPaths:
- path: /api
backend:
service:
name: prefect-server
port:
number: 4200
- Confirm the Prefect API Service name actually matches “prefect-server”. If not, change it to the real service name you found in step 1. For example, if your release is “prefect” and the chart created a service named “prefect-server” or “prefect”, use that exact name.
3) Remove/replace references to non-existent Secrets
- These errors suggest something is referencing Secrets named:
- prefect-server-postgresql
- prefect-server-postgresql-connection
- With postgresql.enabled: true, you should NOT need a connection Secret for Prefect; the chart wires the DB automatically to the in-cluster Postgres.
- Search your values for any fields like:
- existingSecret, extraEnvFromSecret, extraEnvFrom, envFrom, or similar
that reference “prefect-server-postgresql-connection” (or “prefect-server-postgresql”) and remove them.
- If you do want to provide your own DB connection Secret (external Postgres), either:
- Create the Secret your values reference:
kubectl -n <namespace> create secret generic prefect-server-postgresql-connection \
--from-literal=PREFECT_API_DATABASE_CONNECTION_URL='<postgresql+asyncpg://USER:PASSWORD@HOST:5432/DBNAME?sslmode=require>'
…and set postgresql.enabled: false, or
- Update your values to reference the actual Secret name you created.
4) Confirm namespace and release name consistency
- If you installed the chart with a different release name (e.g., “prefect” vs “prefect-server”), your resources will have different prefixes. Make sure any hard-coded names in your values (Ingress backends, Secret references) are updated to match your release name and namespace.
5) Reconcile and restart
- After updating values, run a Helm upgrade with the same release name and namespace you used to install.
- Then validate:
kubectl -n <namespace> get svc,secret | grep -E 'prefect|postgresql'
kubectl -n <namespace> describe ingress <your-ingress>
If you can share:
- Your Helm release name and namespace
- Output of:
helm get values <release> -n <namespace>
kubectl -n <namespace> get svc,secret | grep -E 'prefect|postgresql'
…I can tell you the exact service name to use in your Ingress and whether any Secret references need to be removed or renamed.
References:
- Prefect 3: Deploy Prefect Server with Helm
- PREFECT_API_DATABASE_CONNECTION_URL settingMarvin
09/11/2025, 11:18 AMprefect-server-postgresql, but it doesn’t exist in the target namespace.
What that secret is
- It’s the PostgreSQL credentials Secret created by the chart-managed PostgreSQL subchart (Bitnami) when postgresql.enabled is true.
- By default, its name is <release-name>-postgresql (e.g., if your Helm release is prefect-server, the secret is prefect-server-postgresql).
- If you disable chart-managed PostgreSQL, the chart should not reference that secret; you must provide your own DB credentials/URL instead.
Quick checks
- Confirm namespace and existence:
kubectl get secret prefect-server-postgresql -n <namespace>
- Check for any similar secrets (name override or different release name):
kubectl get secrets -n <namespace> | grep -i postgresql
- Verify the Helm release name/namespace ArgoCD is using matches where your Prefect resources deploy.
Common causes and fixes
1) You want the chart to manage PostgreSQL (recommended simplest path)
- Ensure it’s enabled and let the subchart create the secret:
postgresql:
enabled: true
# optionally set auth values; if not set, the subchart generates credentials and the Secret automatically
# auth:
# username: prefect
# database: prefect
- If you previously set an existing secret name, either:
- Remove it (let the subchart generate credentials/secret), or
- Create the Secret it references (see next section).
- ArgoCD tips:
- Ensure Application.spec.destination.namespace matches where the release is installed.
- Don’t split the Prefect app and its PostgreSQL subchart into different namespaces.
- If you’re using a separate app to create a Secret (e.g., SealedSecret/ExternalSecret), give that app a lower sync wave so it applies before the Prefect app.
2) You want the chart to use a pre-existing Secret for the Bitnami PostgreSQL subchart
- Configure the chart to point at your existing Secret:
postgresql:
enabled: true
auth:
existingSecret: prefect-server-postgresql
# Depending on your Bitnami PostgreSQL version, you may also need to match specific key names in that Secret.
- Create the Secret before syncing the app (keys depend on the Bitnami chart version; check with your chart version):
kubectl -n <namespace> create secret generic prefect-server-postgresql \
--from-literal=postgres-password='<admin-password>' \
--from-literal=password='<app-user-password>'
Notes:
- The required keys and names vary by Bitnami chart version (e.g., postgres-password/password/replication-password). Run this to confirm what your version expects:
helm show values <oci://registry-1.docker.io/bitnamicharts/postgresql> --version <your-version>
- If you’re not sure, share your values.yaml (postgresql section) and we’ll tailor the exact keys.
3) You’re using an external database and do NOT want the chart-managed PostgreSQL
- Disable the subchart and stop referencing its Secret:
postgresql:
enabled: false
- Provide the database connection config to Prefect Server (typically via a Secret containing the connection URL and chart values that wire it to the API and migrations job). Exact keys differ by chart version; see the Helm docs and we can help map your values.
- If you still see references to <release>-postgresql, something in your values is still toggling those templates on—share your values and we’ll pinpoint it.
ArgoCD-specific nuances
- Namespace mismatches are the most common cause: ArgoCD installs the release into namespace A, but a Secret was created/applied in namespace B.
- If your Secret comes from another ArgoCD Application (e.g., SealedSecrets/ExternalSecrets operator), use sync-waves so the Secret manifests apply before Prefect Server.Marvin
09/11/2025, 11:18 AMpostgresql: section and any DB/secret/env settings).
- The ArgoCD Application manifest (destination.namespace and Helm values section).
- The output of:
kubectl get secrets -n <namespace> | grep -i postgresql
…I can give you an exact set of values and a Secret manifest to resolve it.
Docs for reference
- Prefect Server on Helm: docs-3.prefect.io/v3/advanced/server-helm
- Secrets guidance: docs-3.prefect.io/v3/how-to-guides/configuration/store-secrets
Summary of typical values snippets
- Chart-managed PostgreSQL (auto-secret):
postgresql:
enabled: true
- Chart-managed PostgreSQL using your existing Secret:
postgresql:
enabled: true
auth:
existingSecret: prefect-server-postgresql
# Make sure you create the Secret ahead of time with the keys your Bitnami PostgreSQL version expects.
- External DB (no chart-managed PostgreSQL):
postgresql:
enabled: false
# Then point the Prefect API and migration job to your external DB via a Secret/env.
# The exact keys/paths are chart-version-specific; share your values or follow the chart docs.
If you post your current values and namespace, I’ll help you adjust them precisely.Bring your towel and join one of the fastest growing data communities. Welcome to our second-generation open source orchestration platform, a completely rethought approach to dataflow automation.
Powered by