Skip to content

Commit 33b8a64

Browse files
committed
add readme
1 parent e83d65e commit 33b8a64

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

pkg/ingress/README.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Ingress Controller (Ingress-to-Gateway Translation)
2+
3+
4+
This is a Kubernetes controller that implements the `networkingv1.Ingress` API
5+
specification.
6+
7+
Its primary purpose is to act as a translation layer, not a data plane. It
8+
watches `Ingress` resources and translates their semantics into `Gateway API`
9+
resources, specifically `Gateway` and `HTTPRoute`. The actual proxying and
10+
traffic management can then be done by a separate, conformant `Gateway API`
11+
implementation that reads these translated resources.
12+
13+
The controller's goal is to provide the exact semantics of the `Ingress` API
14+
using a standard `Gateway API` data plane.
15+
16+
17+
## Architecture
18+
19+
The controller's logic is built on four key components that work together to
20+
mimic `Ingress` behavior.
21+
22+
### Singleton Namespace Gateway
23+
24+
The controller ensures that a single `gatewayv1.Gateway` resource exists for
25+
each namespace that contains a managed `Ingress`.
26+
27+
This `Gateway` is given a predictable name (e.g., kind-ingress-gateway).
28+
29+
It acts as the single, consolidated entry point for all `Ingress` traffic within
30+
that namespace.
31+
32+
It is configured with a `GatewayClassName` provided to the controller, which
33+
links it to the underlying `Gateway API` data plane implementation.
34+
35+
### Ingress-to-HTTPRoute Translation (1:N Mapping)
36+
37+
To correctly implement `Ingress` precedence (where exact hosts and paths are
38+
matched before wildcards or prefixes), the controller implements a 1-to-Many
39+
(1:N) mapping for each `Ingress` resource:
40+
41+
* **Per-Host Rule:** For each rule defined in `ingress.spec.rules` (e.g., host:
42+
"foo.example.com"), a dedicated `HTTPRoute` resource is created. This
43+
`HTTPRoute` contains only the hostnames and rules (paths) for that specific
44+
host. This design correctly isolates rules per host.
45+
46+
* **Default Backend Rule:** A single, separate `HTTPRoute` is created to handle
47+
the default backend. This route has its hostnames field omitted (nil), which
48+
in `Gateway API` semantics means it matches all traffic that wasn't captured
49+
by a more specific (per-host) `HTTPRoute`.
50+
51+
Precedence: The controller implements `Ingress` default backend precedence. If
52+
an `Ingress` defines a rule with an empty host (host: ""), that rule's paths are
53+
used for the default backend `HTTPRoute`. If no such rule exists, the
54+
ingress.spec.defaultBackend is used as a fallback.
55+
56+
### Namespace-Wide TLS Aggregation
57+
58+
The `Ingress` spec allows multiple `Ingress`es to provide TLS secrets. The
59+
controller consolidates this for the singleton Gateway.
60+
61+
On every reconciliation, the controller scans all managed `Ingress`es in the
62+
namespace.
63+
64+
It aggregates every unique secretName from all ingress.spec.tls sections.
65+
66+
This combined, sorted list of secrets is set on the certificateRefs field of the
67+
singleton Gateway's HTTPS listener.
68+
69+
This means all `Ingress`es in a namespace share one set of TLS certificates on a
70+
single listener, which is consistent with how `Ingress` is typically
71+
implemented.
72+
73+
### Ingress Status Reconciliation
74+
75+
The controller watches the status of the singleton namespace Gateway.
76+
77+
When the underlying Gateway API implementation provisions an IP or hostname for
78+
the Gateway, the controller detects this change.
79+
80+
It copies this IP/hostname to the `status.loadBalancer` field of every managed
81+
`Ingress` in that namespace.
82+
83+
### Reconciliation Flow (syncHandler)
84+
85+
The simplified logic for a single `Ingress` change (Create, Update) is as
86+
follows:
87+
88+
1. An `Ingress` event is received for ingress-A in namespace-foo.
89+
90+
2. The controller re-scans all `Ingress`es in namespace-foo to get a fresh,
91+
aggregated list of all TLS secrets.
92+
93+
3. It reconciles the singleton Gateway in namespace-foo, ensuring it exists and
94+
its HTTPS listener has the correct (sorted) list of aggregated secrets.
95+
96+
4. The controller generates a "desired" list of `HTTPRoute` resources for
97+
ingress-A (e.g., one for a.example.com and one for the default backend).
98+
99+
5. It lists all "existing" `HTTPRoute`s in namespace-foo that are owned by
100+
ingress-A.
101+
102+
6. It compares the "desired" and "existing" lists:
103+
104+
7. New routes are created.
105+
106+
8. Existing routes are updated if their spec (paths, backends) has changed.
107+
108+
9. Stale routes (e.g., for a host that was removed from ingress-A) are deleted.
109+
110+
10. The controller fetches the latest `Gateway.status` and updates
111+
ingress-A.status (and all other Ingresses in the namespace) with the
112+
provisioned IP/hostname.
113+
114+
## Known Incompatibilities
115+
116+
This translation model is highly conformant but has known semantic mismatches
117+
with the `Ingress` API, as identified by the `Ingress` conformance test suite.
118+
119+
Wildcard Host Matching: The `Ingress` API specifies that host: "*.foo.com"
120+
should not match baz.bar.foo.com (it matches only one DNS label). The Gateway
121+
API specifies that hostnames: ["*.foo.com"] does match baz.bar.foo.com (it
122+
matches all subdomains). This controller follows the Gateway API specification,
123+
as that is its underlying data plane.

0 commit comments

Comments
 (0)