@@ -4,7 +4,7 @@ title: "Gateway API Annotation Placement Clarity"
44version : v1alpha1
55authors : " @lexfrei"
66creation-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+
272274Implement annotation merging logic where:
273275
2742761. Gateway annotations serve as **defaults** for all Routes attached to that Gateway
2752772. 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
301303func 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 {
325323apiVersion: gateway.networking.k8s.io/v1
326324kind: Gateway
327325metadata:
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---
335334apiVersion: gateway.networking.k8s.io/v1
336335kind: HTTPRoute
337336metadata:
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
340339spec:
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---
346359apiVersion: gateway.networking.k8s.io/v1
347360kind: HTTPRoute
348361metadata:
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
354367spec:
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
539562This approach provides immediate relief while keeping options open for more comprehensive solutions in the future.
0 commit comments