From 0f2fe93ebf413cd4d1128da5c6dd5d7580918fb6 Mon Sep 17 00:00:00 2001 From: chrisfu Date: Tue, 21 Apr 2026 12:05:40 -0700 Subject: [PATCH] fix(net): GCE BackendConfig rejects type: TCP; switch to HTTP /healthz Follow-up to 391c4f5. Live deploy showed GCE's L7 BackendConfig CRD hard-rejects type: TCP with: Error syncing to GCP: error running backend syncing routine: error ensuring health check: Protocol "TCP" is not valid, must be one of [HTTP,HTTPS,HTTP2] The sync never completes, so the LB has no healthy backend and TCP connections to the public endpoint just close (ERR_CONNECTION_CLOSED). Fix: switch all three BackendConfigs to type: HTTP with request paths that return 200: - supabase-kong & knoe-svc-kong: add a dedicated /healthz route to the Kong declarative config via the request-termination plugin, which returns 200 synchronously with no upstream call. Equivalent liveness semantics to the TCP check we wanted (backend is alive as long as Kong accepts connections) but over HTTP, which GCE actually accepts. - supabase/helm/knoe-supabase/templates/kong/config.yaml - etc/init_kong.sh (inline kong.yml heredoc) - supabase-studio: Studio returns 301 on / (Next.js default) so we point the probe at /favicon.ico -- Next.js serves it as a static asset with 200 unconditionally. Not as clean as a real readiness endpoint but Studio does not expose one that returns 200 without auth. - supabase/helm/knoe-supabase/templates/studio/backendconfig.yaml Verified locally via helm template -f values.generated.json: the rendered BackendConfigs come out with the HTTP protocol + correct paths, and the Kong ConfigMap has the healthz service block before the auth-v1-open service. Co-Authored-By: Claude Opus 4.7 (1M context) --- etc/init_kong.sh | 30 ++++++++++++++++--- .../templates/kong/backendconfig.yaml | 18 +++++++---- .../knoe-supabase/templates/kong/config.yaml | 19 ++++++++++++ .../templates/studio/backendconfig.yaml | 15 +++++++--- 4 files changed, 69 insertions(+), 13 deletions(-) diff --git a/etc/init_kong.sh b/etc/init_kong.sh index bac2b82..cae4e3b 100755 --- a/etc/init_kong.sh +++ b/etc/init_kong.sh @@ -378,6 +378,23 @@ _format_version: "3.0" _transform: true services: + # Dedicated health endpoint for the GCE LB BackendConfig. request-termination + # returns 200 synchronously with no upstream call, so the probe passes as long + # as the Kong proxy itself is running. GCE rejects \`type: TCP\` in BackendConfig + # (only HTTP/HTTPS/HTTP2 accepted), so we use this route for HTTP liveness. + - name: healthz + url: http://127.0.0.1:${KONG_PROXY_PORT}/ + routes: + - name: healthz + paths: + - /healthz + strip_path: true + plugins: + - name: request-termination + config: + status_code: 200 + message: ok + - name: prole-service url: ${PROLE_SERVICE_UPSTREAM_URL} routes: @@ -608,9 +625,13 @@ EOF # BackendConfig: GCE default healthCheck is HTTP GET / on the backend port # and Kong returns 404 on an unrouted path, so the backend never goes - # HEALTHY. A TCP healthCheck on the proxy port is sufficient for our case - # (backend is alive as long as Kong is accepting connections). Service is - # annotated below with cloud.google.com/backend-config so GCE picks this up. + # HEALTHY. We wanted TCP (Kong is alive as long as it accepts connections), + # but GCE's BackendConfig CRD rejects `type: TCP` with + # `Protocol "TCP" is not valid, must be one of [HTTP,HTTPS,HTTP2]` + # so we fall back to HTTP against the `/healthz` route we add to the + # knoe-svc-kong declarative config above (request-termination plugin + # returns 200 synchronously, no upstream dependency -- equivalent liveness + # semantics to a TCP check but over a protocol GCE accepts). echo "Reconciling BackendConfig (${SVC_KNOE_BACKEND_CONFIG_NAME}) for ${KONG_NAME} in ns=${NAMESPACE} ..." kubectl apply -f - <