Skip to content

Commit e7fa6c0

Browse files
lexfreiclaude
andcommitted
docs(proposal): update Solution 2 to reflect reference implementation
- Change status from draft to provisional - Add reference to PR kubernetes-sigs#5998 - Update pseudocode: target annotation is now inheritable and overridable - Update example to show intranet/public target override use case - Add benefit: solves User Story 2 (per-Route target overrides) - Update recommendation to include near-term merging of Solution 2 Co-Authored-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
1 parent 50f98d5 commit e7fa6c0

File tree

1 file changed

+43
-20
lines changed

1 file changed

+43
-20
lines changed

docs/proposal/004-gateway-api-annotation-placement.md

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: "Gateway API Annotation Placement Clarity"
44
version: v1alpha1
55
authors: "@lexfrei"
66
creation-date: 2025-10-23
7-
status: draft
7+
status: provisional
88
---
99
```
1010

@@ -269,11 +269,13 @@ metadata:
269269
270270
#### Solution 2: Annotation Inheritance and Merging (Long-term - Feature Enhancement)
271271
272+
**Reference Implementation**: [PR #5998](https://github.com/kubernetes-sigs/external-dns/pull/5998)
273+
272274
Implement annotation merging logic where:
273275
274276
1. Gateway annotations serve as **defaults** for all Routes attached to that Gateway
275277
2. Route annotations **override** Gateway annotations for specific Routes
276-
3. Explicit validation to prevent silent failures
278+
3. **All annotations are inheritable**, including `target` — enabling per-Route target overrides
277279

278280
**Proposed implementation** (pseudocode):
279281

@@ -299,14 +301,10 @@ func (src *gatewayRouteSource) Endpoints(ctx context.Context) ([]*endpoint.Endpo
299301
300302
// Helper function
301303
func mergeAnnotations(gateway, route map[string]string) map[string]string {
302-
merged := make(map[string]string)
304+
merged := make(map[string]string, len(gateway)+len(route))
303305
304306
// Copy Gateway annotations (defaults)
305307
for k, v := range gateway {
306-
// Skip 'target' annotation - it's Gateway-specific and shouldn't be inherited
307-
if k == "external-dns.alpha.kubernetes.io/target" {
308-
continue
309-
}
310308
merged[k] = v
311309
}
312310
@@ -325,45 +323,65 @@ func mergeAnnotations(gateway, route map[string]string) map[string]string {
325323
apiVersion: gateway.networking.k8s.io/v1
326324
kind: Gateway
327325
metadata:
328-
name: cloudflare-gateway
326+
name: intranet-gateway
329327
annotations:
330-
external-dns.alpha.kubernetes.io/target: "203.0.113.1"
328+
# Default target for internal services
329+
external-dns.alpha.kubernetes.io/target: "172.16.6.6"
331330
# Set default for all Routes using this Gateway
332331
external-dns.alpha.kubernetes.io/cloudflare-proxied: "true"
333332
external-dns.alpha.kubernetes.io/ttl: "300"
334333
---
335334
apiVersion: gateway.networking.k8s.io/v1
336335
kind: HTTPRoute
337336
metadata:
338-
name: api-route
339-
# Inherits: cloudflare-proxied=true, ttl=300 from Gateway
337+
name: internal-api
338+
# Inherits: target=172.16.6.6, cloudflare-proxied=true, ttl=300 from Gateway
340339
spec:
341340
parentRefs:
342-
- name: cloudflare-gateway
341+
- name: intranet-gateway
342+
hostnames:
343+
- api.internal.example.com
344+
---
345+
apiVersion: gateway.networking.k8s.io/v1
346+
kind: HTTPRoute
347+
metadata:
348+
name: public-api
349+
annotations:
350+
# Override: expose this route to the public internet
351+
external-dns.alpha.kubernetes.io/target: "203.0.113.1"
352+
# Inherits: cloudflare-proxied=true, ttl=300 from Gateway
353+
spec:
354+
parentRefs:
355+
- name: intranet-gateway
343356
hostnames:
344357
- api.example.com
345358
---
346359
apiVersion: gateway.networking.k8s.io/v1
347360
kind: HTTPRoute
348361
metadata:
349-
name: static-route
362+
name: static-assets
350363
annotations:
351-
# Override: disable proxying for this specific route
364+
# Override: disable proxying for static content
352365
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
353-
# Inherits: ttl=300 from Gateway
366+
# Inherits: target=172.16.6.6, ttl=300 from Gateway
354367
spec:
355368
parentRefs:
356-
- name: cloudflare-gateway
369+
- name: intranet-gateway
357370
hostnames:
358-
- static.example.com
371+
- static.internal.example.com
359372
```
360373

374+
This example demonstrates a common use case: an intranet Gateway where most services are internal
375+
(`172.16.6.6`), but specific Routes can be exposed publicly (`203.0.113.1`) by overriding the
376+
`target` annotation.
377+
361378
**Benefits:**
362379

363380
- Reduces configuration duplication
364381
- Enables centralized defaults at Gateway level
365382
- Maintains flexibility with Route-level overrides
366383
- Better matches user mental model (infrastructure defaults + application overrides)
384+
- **Solves User Story 2**: Enables per-Route target overrides without creating separate Gateways
367385

368386
**Risks:**
369387

@@ -531,9 +549,14 @@ annotation merging after standardization is resolved
531549
- Can be merged quickly
532550
- Addresses immediate pain points
533551

534-
2. **Future (post-PR #5080 resolution)**: Re-evaluate Solution 2 (Annotation Merging)
535-
- Gather user feedback on whether documentation alone is sufficient
552+
2. **Near-term**: Review and merge Solution 2 (Annotation Merging)
553+
- Reference implementation available: [PR #5998](https://github.com/kubernetes-sigs/external-dns/pull/5998)
554+
- Includes comprehensive test coverage
555+
- Backward compatible (no breaking changes for existing configurations)
556+
- Solves User Story 2 (per-Route target overrides)
557+
558+
3. **Future (post-PR #5080 resolution)**: Re-evaluate if additional changes are needed
536559
- Assess compatibility with annotation standardization outcomes
537-
- Consider feature flag approach for gradual rollout if proceeding
560+
- Gather user feedback on the annotation inheritance behavior
538561

539562
This approach provides immediate relief while keeping options open for more comprehensive solutions in the future.

0 commit comments

Comments
 (0)