ExternalDNS: Gateway API
Definitions
● An Endpoint contains the data for a DNS record (e.g. hostname, targets, TTL, etc.), with some
additional metadata (e.g. labels).
● A Resource is a Kubernetes Object.
● A Source provides Endpoints.
Background
● Resource types from the same API Group are usually enabled and handled independently as
separate Sources.
○ e.g.
■ Istio's Gateway and VirtualService
■ Contour's IngressRoute and HTTPProxy
○ Gateway's HTTPRoute, TLSRoute, TCPRoute, and UDPRoute are enabled and handled
independently as separate Sources.
● Sources generate a set of Endpoints for each Resource, without regard for other Resources.
○ A conflict resolver is used when planning DNS changes from candidate Endpoints.
■ If it's an existing Hostname and a particular Resource is associated with the
record, that Resource’s Endpoint will continue to be used as long as it exists.
This requires using a registry to track Endpoint metadata.
■ If it's a new Hostname, the candidate with the minimal targets is used.
○ Nothing special is added to resolve conflicts within Gateway API Routes.
● Resources may be restricted by namespace, labels, and annotations.
○ Gateway namespace and label filters are added.
● There are existing mechanisms to provide Hostnames for Resources without them.
○ e.g.
■ A Resource annotation: external-dns.alpha.kubernetes.io/hostname.
■ A flag-defined Go template that takes the Resource as input.
○ This is necessary for UDPRoutes and TCPRoutes, but is supported on all Gateway API
Routes which may be a potential footgun.
Algorithm
● Routes are generalized and share an underlying Source implementation.
type gatewayRoute interface {
// Object returns the underlying route object
// to be used by templates.
Object() kubeObject
// Metadata returns the route's metadata.
Metadata() *metav1.ObjectMeta
// Hostnames returns the route's specified hostnames.
Hostnames() []v1alpha2.Hostname
// Protocol returns the route's protocol type.
Protocol() v1alpha2.ProtocolType
// RouteStatus returns the route's common status.
RouteStatus() v1alpha2.RouteStatus
}
● Start with an empty list of Endpoints.
● List all Routes for the user-provided Namespace(s) and Label filters.
● List all Gateways for the user-provided Namespace(s) and Label filters.
● List all Namespaces.
● Create lookup tables for Namespaces, Gateways, and Listeners.
● For each Route:
○ Skip the Route if the user-provided Annotations filter doesn't match.
○ Skip the Route if it's owned by a different DNS controller.
○ Resolve hostnames and their targets for the Route.
■ Create an empty mapping of Hostnames to Address lists.
■ Build a list of hostnames associated with the Route.
● Add Hostnames provided by the Route directly.
● Add Hostnames provided by Route annotations.
● Add Hostnames provided by templates.
● If there were no directly provided Hostnames, add an empty one.
■ For each Parent in the Route's status:
● Skip the Parent if it's not a gateway.networking.k8s.io/Gateway
● Lookup the Gateway, using its ParentRef Name and Namespace. If no
Namespace is provided in the ParentRef, use the Namespace of the
Route.
● Skip the Parent if the Gateway isn't found.
● Skip the Parent if its Conditions don't contain Accepted=True
● Lookup the Listener for the Gateway using the SectionName of the
Parent. If the SectionName is empty use all Listeners for the Gateway.
● For each Listener:
○ Skip the Listener if its Protocol and the Route's Protocol don't
match. HTTPRoutes match HTTP or HTTPS protocols. All other
Routes match only one protocol (e.g. UDP, TCP, TLS).
○ Skip the Listener if the Route isn't Allowed.
■ Confirm that the Route's Namespace is allowed by the
Listener by applying All, Same, or Selector filters as
specified. Default to Same if unspecified. Skip the Listener
if an unknown FromNamespaces is specified.
■ If the Listener specifies supported Kinds, confirm that the
Route's GroupKind is in the list.
○ For all Route Hostnames:
■ Skip if the Route Hostname and Listener Hostname are
both empty.
■ Find the most-defined matching Hostname between the
Route Hostname and Listener Hostname.
● Lowercase ASCII in both Hostnames.
● If either Hostname is empty, return the other one.
● Split both Hostnames into parts at dots/periods.
● If they have a different number of parts, they don't
match.
● If either Hostname’s first part is an asterisk and the
remaining parts match, return the other one.
● If all parts match, return either Hostname.
● Otherwise, they don’t match.
■ If there is a match, append the Gateway Status Addresses
to the matching Hostname's mapping.
■ For each Address list in the Hostname mapping:
● Deduplicate the list, because a Hostname may match multiple Listeners
on the same Gateway (e.g. HTTP and HTTPS).
■ Return resolved Hostnames and their Addresses.
○ Pull additional features from the Route's annotations (e.g. TTL).
○ Append Endpoints for each hostname with its targets and annotated features.
● Return all Endpoints.