Skip to content

Commit 809babe

Browse files
fix(deploy): let the cluster own the Gateway, keep only the route (#518)
This repo cannot know the cluster it lands in, and gateway-listeners.yaml was trying to. Between them, the ListenerSet and its routes hardcoded four facts about cfp-live-cluster — the shared Gateway's name and namespace, the ClusterIssuer, the TLS Secret name, and the ListenerSet API itself — and three were wrong there: - cert-manager.io/cluster-issuer: letsencrypt-prod is dead. It solves ACME over ingress-nginx, which requires PROXY protocol on every connection and is therefore unreachable from inside the cluster. No certificate has issued through it since May. - certificateRefs: balancer-tls is the legacy Ingress Secret. Gateway certs are <app>-gw-tls. - ListenerSet is not reconciled by Envoy Gateway v1.7.3. It watches XListenerSet and logs "XListenerSet CRD not found, skipping XListenerSet watch". The object applies cleanly and is then ignored — the app just has no listener, with nothing in any log to say why. None of that is a mistake anyone could have avoided from this repo. It isn't knowable here. So stop trying to know it. Split on what each side actually knows: this repo -> HTTPRoute: paths, backend Services, ports. App facts. They change when the app changes, in the same commit. cluster -> Gateway: listeners, hostnames, TLS, issuers. Cluster facts. They differ per environment and are shared with every other app. The route now attaches to a Gateway the cluster provides, named after the app, and declares no hostnames — a route that omits hostnames inherits them from the listeners it attaches to. So one file serves balancerproject.org in live and balancer.sandbox.k8s.phl.io in sandbox, with no patches and no placeholders. The HOSTNAME_PLACEHOLDER substitutions and the overlay routing patches are gone. Drops balancer-http-redirect too: the cluster already redirects every hostname reaching it on port 80. Worse than redundant — a route claiming an exact hostname on the shared HTTP listener outranks the catch-all redirect and can shadow cert-manager's ACME solver route, which is what produced the apex 404 that #517 set out to fix. That 404 was a stuck certificate, and it cleared the moment the cert issued. Adds a README stating the contract, so the next person doesn't have to infer it. Refs CodeForPhilly/cfp-live-cluster#166, #168
1 parent 1b93133 commit 809babe

6 files changed

Lines changed: 80 additions & 106 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# balancer deployment manifests
2+
3+
Consumed by the Code for Philly cluster repos
4+
([cfp-live-cluster](https://github.com/CodeForPhilly/cfp-live-cluster),
5+
[cfp-sandbox-cluster](https://github.com/CodeForPhilly/cfp-sandbox-cluster)), which project
6+
`base/` into their GitOps trees. Also usable directly against a local `kind` cluster
7+
(`deploy/kind-config.yaml`).
8+
9+
## Who owns what
10+
11+
Routing is split along a single line: **this repo declares what the app serves; the
12+
cluster declares where it's reachable.**
13+
14+
| This repo owns | The cluster owns |
15+
| --- | --- |
16+
| `HTTPRoute` — paths, backend Services, ports | `Gateway` — listeners, hostnames, TLS |
17+
| Deployment, Service, app config | Certificates, ClusterIssuers, `GatewayClass` |
18+
19+
Paths and ports are facts about the application: they change when the app changes, and
20+
they belong in the same commit as that change. Hostnames, TLS, and issuers are facts
21+
about the cluster: they differ between live and sandbox, they're negotiated across every
22+
app sharing the ingress, and they change when the *cluster* changes.
23+
24+
## The contract
25+
26+
**The cluster provides a `Gateway` named after the app, in the app's namespace.** That
27+
sentence is the whole interface.
28+
29+
`base/httproute.yaml` attaches to it by name and declares no hostnames:
30+
31+
```yaml
32+
spec:
33+
parentRefs:
34+
- name: balancer # the Gateway the cluster provides
35+
# no hostnames — inherited from the Gateway's listeners
36+
```
37+
38+
A route that omits `hostnames` inherits them from the listeners it attaches to. So the
39+
same file serves `balancerproject.org` in live and `balancer.sandbox.k8s.phl.io` in
40+
sandbox, with no patching and no placeholders.
41+
42+
## What must NOT live in this repo
43+
44+
Anything that names a cluster implementation detail:
45+
46+
- **`Gateway` or `ListenerSet` resources.** Cluster-owned.
47+
- **`cert-manager.io/cluster-issuer` annotations**, or any ClusterIssuer name.
48+
- **TLS `certificateRefs` / cert Secret names.**
49+
- **`gatewayClassName`**, or the name/namespace of any shared Gateway.
50+
- **An HTTP→HTTPS redirect.** The cluster already redirects every hostname reaching it
51+
on port 80. An app-level redirect is redundant, and a route claiming an exact hostname
52+
on the shared HTTP listener can shadow cert-manager's ACME solver route.
53+
54+
None of these are knowable from this repo, and getting one wrong fails in ways that are
55+
hard to see. A `ListenerSet`, for instance, applies cleanly to the API server and is then
56+
silently ignored by Envoy Gateway v1.7.3 — the app simply has no listener, with nothing
57+
in any log to say why.
58+
59+
If you need something from the cluster that isn't here, open an issue on the cluster repo
60+
rather than guessing at its internals.

deploy/manifests/balancer/base/gateway-listeners.yaml

Lines changed: 0 additions & 27 deletions
This file was deleted.

deploy/manifests/balancer/base/httproute.yaml

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,20 @@ apiVersion: gateway.networking.k8s.io/v1
22
kind: HTTPRoute
33
metadata:
44
name: balancer
5-
annotations:
6-
hostname: HOSTNAME_PLACEHOLDER
75
spec:
6+
# Attaches to the Gateway the cluster provides for this app. The cluster names
7+
# it after the app, in the app's namespace — that convention is the entire
8+
# contract. See ../README.md.
89
parentRefs:
9-
- name: balancer-listeners
10-
kind: ListenerSet
11-
group: gateway.networking.k8s.io
12-
sectionName: https
13-
hostnames:
14-
- HOSTNAME_PLACEHOLDER
10+
- name: balancer
11+
12+
# No `hostnames` on purpose.
13+
#
14+
# A route that omits hostnames inherits the hostnames of the listeners it
15+
# attaches to, so the cluster's Gateway decides where this app is reachable —
16+
# balancerproject.org in live, balancer.sandbox.k8s.phl.io in sandbox — and
17+
# this file stays identical in every environment.
18+
1519
rules:
1620
- matches:
1721
- path:
@@ -20,24 +24,3 @@ spec:
2024
backendRefs:
2125
- name: balancer
2226
port: 80
23-
---
24-
apiVersion: gateway.networking.k8s.io/v1
25-
kind: HTTPRoute
26-
metadata:
27-
name: balancer-http-redirect
28-
annotations:
29-
hostname: HOSTNAME_PLACEHOLDER
30-
spec:
31-
parentRefs:
32-
- name: balancer-listeners
33-
kind: ListenerSet
34-
group: gateway.networking.k8s.io
35-
sectionName: http
36-
hostnames:
37-
- HOSTNAME_PLACEHOLDER
38-
rules:
39-
- filters:
40-
- type: RequestRedirect
41-
requestRedirect:
42-
scheme: https
43-
statusCode: 301

deploy/manifests/balancer/base/kustomization.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ resources:
55
- namespace.yaml
66
- deployment.yaml
77
- service.yaml
8-
- gateway-listeners.yaml
98
- httproute.yaml
109

1110
labels:

deploy/manifests/balancer/overlays/production/kustomization.yaml

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,9 @@ labels:
2424
environment: production
2525
app.kubernetes.io/instance: balancer-production
2626

27-
patches:
28-
- target:
29-
kind: ListenerSet
30-
name: balancer-listeners
31-
patch: |
32-
- op: replace
33-
path: /spec/listeners/0/hostname
34-
value: balancerproject.org
35-
- op: replace
36-
path: /spec/listeners/1/hostname
37-
value: balancerproject.org
38-
- target:
39-
kind: HTTPRoute
40-
name: balancer
41-
patch: |
42-
- op: replace
43-
path: /spec/hostnames/0
44-
value: balancerproject.org
45-
- target:
46-
kind: HTTPRoute
47-
name: balancer-http-redirect
48-
patch: |
49-
- op: replace
50-
path: /spec/hostnames/0
51-
value: balancerproject.org
27+
# No routing patches. The cluster's Gateway carries the hostname and TLS, and
28+
# the HTTPRoute inherits it — see ../../README.md.
29+
#
30+
# HOSTNAME above is still set here because the *application* needs to know its
31+
# own public name (Django ALLOWED_HOSTS / CSRF_TRUSTED_ORIGINS). That's app
32+
# config, not routing.

deploy/manifests/balancer/overlays/sandbox/kustomization.yaml

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,31 +25,9 @@ labels:
2525
environment: sandbox
2626
app.kubernetes.io/instance: balancer-sandbox
2727

28+
# No routing patches — the cluster's Gateway carries the hostname and TLS, and
29+
# the HTTPRoute inherits it. See ../../README.md.
2830
patches:
29-
- target:
30-
kind: ListenerSet
31-
name: balancer-listeners
32-
patch: |
33-
- op: replace
34-
path: /spec/listeners/0/hostname
35-
value: sandbox.balancerproject.org
36-
- op: replace
37-
path: /spec/listeners/1/hostname
38-
value: sandbox.balancerproject.org
39-
- target:
40-
kind: HTTPRoute
41-
name: balancer
42-
patch: |
43-
- op: replace
44-
path: /spec/hostnames/0
45-
value: sandbox.balancerproject.org
46-
- target:
47-
kind: HTTPRoute
48-
name: balancer-http-redirect
49-
patch: |
50-
- op: replace
51-
path: /spec/hostnames/0
52-
value: sandbox.balancerproject.org
5331
- target:
5432
kind: Deployment
5533
name: balancer

0 commit comments

Comments
 (0)