Skip to content

feat(evals): host Phoenix on Cloud Run and Cloud SQL - #979

Merged
chughtapan merged 2 commits into
mainfrom
feat/hosted-phoenix
Aug 6, 2026
Merged

feat(evals): host Phoenix on Cloud Run and Cloud SQL#979
chughtapan merged 2 commits into
mainfrom
feat/hosted-phoenix

Conversation

@chughtapan

Copy link
Copy Markdown
Owner

Summary

Terraform for a hosted Arize Phoenix the evals publisher can target: Cloud Run (digest-pinned image) + Cloud SQL Postgres via the Cloud SQL connector, PHOENIX_ENABLE_AUTH from the first deploy (an unauthenticated revision never exists), secrets in Secret Manager, admin-bootstraps-then-provisions-viewers account model documented, and a validate/fmt static check target. The publisher needs exactly PHOENIX_HOST (the Cloud Run URL) + PHOENIX_API_KEY — no code changes.

Why Cloud Run and not on-cluster or Phoenix Cloud: the GKE cluster is ephemeral by design (cluster.sh down/delete are routine) so dashboards must outlive it; SaaS moves eval data out of the project and needs an api_key-header code change.

/simplify applied (second commit).

🤖 Generated with Claude Code

chughtapan and others added 2 commits August 6, 2026 01:08
Published dashboards outlive the cluster that produced them. The GKE
qualification profile treats deletion as routine, so an in-cluster Phoenix
would be destroyed and re-seeded on every recycle; this module gives the
publisher an endpoint whose lifecycle is independent of it.

Cloud Run reaches Cloud SQL through the Auth proxy socket. The connection
string leaves the authority empty and passes the socket directory as a
`host` query parameter, because the instance connection name contains
colons that are read as a port anywhere else — which is also why the
PHOENIX_POSTGRES_* family cannot address it. Verified against the pinned
image before it was written down.

Authentication is set in the first revision rather than added later, so no
unauthenticated Phoenix is ever reachable, and the well-known default admin
password is overridden with a generated one held in Secret Manager. The
image ships an assistant that can run shell commands inside the container;
it is disabled here.

It lives beside the publisher that reads PHOENIX_HOST rather than beside the
cluster's Terraform, so that one `terraform destroy` cannot take both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…k load-bearing

The check was wired to nothing. It had no CI caller, and its nx `inputs`
were inert without `cache: true`, so it re-ran in full whenever someone
remembered to type it. It now runs beside the simulator profile checks and
caches on the module, the lock file, and the installed terraform version —
the last so that a machine without terraform cannot cache a skip as a pass.

Four variables are gone. `sql_disk_size_gb` was inert: its default equalled
its floor and `ignore_changes` swallowed every later change, so an operator
raising it got a clean plan and no disk. `max_instances` and `ingress` were
knobs that must not be turned — their own descriptions said so while their
validation accepted the values that break the deployment. Those two are now
the constants they always were. `upstream_repository_id` named an object
nobody interacts with and was the one name not derived from `name_prefix`,
so two applies into one project collided on it.

The secret map no longer exists twice. The comment justifying the split
claimed a map with sensitive values cannot be a `for_each` argument; that
rule applies to a map marked sensitive as a whole, not to one with sensitive
elements, and the module is the second case. Verified on the declared
version floor. Keeping the identifiers in one place is also what stops a
secret being added without the IAM grant that makes it readable.

Three `depends_on` entries were already implied transitively — confirmed by
diffing the plan graph with them removed. Four remain because Terraform
cannot infer IAM propagation from an attribute reference.

The README no longer argues the same decision in two places, and it now
states what the thing costs: standing Cloud Run and Cloud SQL charges were
the one property the module never disclosed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chughtapan
chughtapan merged commit 36ace31 into main Aug 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant