From a36563543b2f6fe904e36dbe0fdf16b9ed1434c2 Mon Sep 17 00:00:00 2001 From: tegwick Date: Fri, 21 Aug 2026 03:24:14 +0200 Subject: [PATCH] Give the reuse landing catch-all its own Ingress and an explicit priority MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /health returned nginx 404 through the ingress while the service answered 200 in-cluster. The ingress rule was correct on paper — /health Exact -> reuse-surface:8000 alongside / Prefix -> reuse-surface-landing:8080 — but Traefik derives router priority from the length of the generated rule string, and Path(`/health`) and PathPrefix(`/`) are both 15 characters. The tie broke toward the landing page. PathPrefix(`/v1`) is longer, which is why /v1 worked and the fault looked like a /health-only bug. traefik.ingress.kubernetes.io/router.priority applies per Ingress, not per path, so the catch-all moves into its own Ingress with priority 1. Every API route now outranks it regardless of rule length. This is not cosmetic: make reuse-smoke curls /health and false-negatives on an otherwise healthy release. Co-Authored-By: Claude Opus 5 --- charts/reuse-surface/templates/ingress.yaml | 8 +--- .../templates/landing-ingress.yaml | 44 +++++++++++++++++++ charts/reuse-surface/values.yaml | 5 +++ 3 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 charts/reuse-surface/templates/landing-ingress.yaml diff --git a/charts/reuse-surface/templates/ingress.yaml b/charts/reuse-surface/templates/ingress.yaml index 12e2d33..5e58f13 100644 --- a/charts/reuse-surface/templates/ingress.yaml +++ b/charts/reuse-surface/templates/ingress.yaml @@ -28,13 +28,7 @@ spec: port: number: {{ $.Values.service.port }} {{- end }} - - path: / - pathType: Prefix - backend: - service: - name: {{ include "reuse.landingFullname" . }} - port: - number: {{ .Values.landing.service.port }} + {{- /* the landing catch-all is a separate Ingress; see landing-ingress.yaml */}} {{- else }} - path: / pathType: Prefix diff --git a/charts/reuse-surface/templates/landing-ingress.yaml b/charts/reuse-surface/templates/landing-ingress.yaml new file mode 100644 index 0000000..872860b --- /dev/null +++ b/charts/reuse-surface/templates/landing-ingress.yaml @@ -0,0 +1,44 @@ +{{- if and .Values.ingress.enabled .Values.landing.enabled }} +{{- /* + The landing catch-all lives in its own Ingress so it can carry an explicit + Traefik router priority. + + Traefik derives router priority from the length of the generated rule string. + With the catch-all in the same Ingress as the API paths, Path(`/health`) and + PathPrefix(`/`) are both 15 characters — an exact tie, broken arbitrarily, and + in practice the landing nginx won and /health returned 404 through the ingress + while the service answered 200 in-cluster. PathPrefix(`/v1`) is longer, so /v1 + was unaffected, which is why the fault looked like a /health-only bug. + + An explicit low priority here keeps the browser landing page as a true + fallback: every API route outranks it regardless of rule length. +*/}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "reuse.landingFullname" . }} + labels: {{- include "reuse.labels" . | nindent 4 }} + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.tls: "true" + traefik.ingress.kubernetes.io/router.priority: {{ .Values.landing.ingress.priority | quote }} +spec: + ingressClassName: {{ .Values.ingress.className }} + {{- if .Values.ingress.tls }} + tls: + - hosts: + - {{ .Values.ingress.host }} + secretName: {{ include "reuse.fullname" . }}-tls + {{- end }} + rules: + - host: {{ .Values.ingress.host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ include "reuse.landingFullname" . }} + port: + number: {{ .Values.landing.service.port }} +{{- end }} diff --git a/charts/reuse-surface/values.yaml b/charts/reuse-surface/values.yaml index e0b68c8..fb54e76 100644 --- a/charts/reuse-surface/values.yaml +++ b/charts/reuse-surface/values.yaml @@ -35,6 +35,11 @@ landing: service: port: 8080 targetPort: 8080 + ingress: + # Explicit Traefik router priority for the landing catch-all. Traefik + # otherwise derives priority from rule-string length, where PathPrefix(`/`) + # ties with Path(`/health`) and can win. Keep this below every API route. + priority: 1 noindex: true title: "Railiance service endpoint" eyebrow: "Railiance S5"