Skip to content

fix: use rooted FQDN for xDS cluster address to avoid DNS search expansion#14291

Merged
puertomontt merged 2 commits into
kgateway-dev:mainfrom
puertomontt:fix-xds-fqdn-trailing-dot
Jun 23, 2026
Merged

fix: use rooted FQDN for xDS cluster address to avoid DNS search expansion#14291
puertomontt merged 2 commits into
kgateway-dev:mainfrom
puertomontt:fix-xds-fqdn-trailing-dot

Conversation

@puertomontt

@puertomontt puertomontt commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Description

The Envoy bootstrap rendered by kgateway sets the xds_cluster socket address to the kgateway control-plane FQDN without a trailing dot, e.g. kgateway.kgateway-system.svc.cluster.local. Because this name has 4 dots and is not rooted, the default ndots:5 resolver config treats it as a relative name. The xds_cluster uses envoy.cluster.strict_dns with respect_dns_ttl: true, so on every re-resolution cycle (every 5s, matching the kgateway Service TTL) Envoy's c-ares resolver walks every search domain before the bare-name attempt — 8 NXDOMAIN lookups followed by the successful one. At a 5s TTL this is ~96 wasted CoreDNS queries per minute per gateway pod, scaling with pods and replicas.

The address originates in pkg/kgateway/controller/start.go, where kubeutils.ServiceFQDN(...) returns the dotless FQDN. This change appends a trailing dot so the name is absolute (rooted), so the resolver skips search-domain expansion entirely (1–2 queries instead of 9–10).

Only the kgateway-generated FQDN is normalized. An explicitly configured XdsServiceHost (which may be an IP literal or a short name) is intentionally left untouched.

The e2e deployer assertion (xdsClusterAssertion) is updated to expect the rooted FQDN. The deployer golden tests set XdsHost explicitly (mirroring the user-supplied branch), so they are unaffected.

Fixes #14284

Change Type

/kind fix

Changelog

Fix excessive DNS queries from gateway pods by rendering the xDS cluster address as a rooted FQDN (trailing dot), preventing DNS search-domain expansion under the default ndots:5 resolver config.

…nsion

The auto-generated xDS service address is an in-cluster FQDN with 4 dots
and no trailing dot. Under the default ndots:5 resolver config, Envoy's
strict_dns cluster treats it as a relative name and expands every search
domain on each re-resolution cycle, producing a burst of NXDOMAIN lookups
(~96 wasted CoreDNS queries/min per gateway pod with the 5s service TTL).

Append a trailing dot so the name is absolute. Only the kgateway-generated
FQDN is normalized; an explicitly configured XdsServiceHost (which may be an
IP or short name) is left untouched.

Fixes kgateway-dev#14284

Signed-off-by: omar <[email protected]>
Copilot AI review requested due to automatic review settings June 23, 2026 16:07
@gateway-bot gateway-bot added do-not-merge/description-invalid kind/fix Categorizes issue or PR as related to a bug. release-note labels Jun 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces unnecessary DNS traffic from gateway pods by rendering the internally-generated xDS service hostname as a rooted (absolute) FQDN (trailing dot), preventing resolver search-domain expansion under default ndots:5 behavior.

Changes:

  • Append a trailing dot to the default (auto-derived) XdsServiceHost used for the xDS cluster address.
  • Update the e2e deployer assertion to expect a rooted xDS service FQDN.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
pkg/kgateway/controller/start.go Root the auto-derived xDS Service FQDN by adding a trailing dot to avoid DNS search expansion.
test/e2e/features/deployer/suite.go Adjust e2e assertion to match the rooted xDS cluster socket address.

Comment thread pkg/kgateway/controller/start.go Outdated
Comment on lines +238 to +241
xdsHost = kubeutils.ServiceFQDN(metav1.ObjectMeta{
Name: globalSettings.XdsServiceName,
Namespace: namespaces.GetPodNamespace(),
})
}) + "."
Comment on lines 597 to +599
g.Expect(xdsSocketAddress.GetAddress()).To(gomega.Equal(
fmt.Sprintf("%s.%s.svc.cluster.local", wellknown.DefaultXdsService, testInstallation.Metadata.InstallNamespace),
), "xds socket address points to kgateway service, in installation namespace")
fmt.Sprintf("%s.%s.svc.cluster.local.", wellknown.DefaultXdsService, testInstallation.Metadata.InstallNamespace),
), "xds socket address points to kgateway service, in installation namespace, as a rooted FQDN")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree with Copilot here. For one, this pattern already exists in the test. For another, our e2e environment is tightly enough controlled that we aren't really worried about environments with a non-default cluster domain. I think your existing code is fine.

Guard against a double trailing dot when ServiceFQDN already returns a
rooted name (e.g. a CLUSTER_DOMAIN env var set with a trailing dot, which
GetClusterDomainName returns verbatim). A double dot would itself break
DNS resolution.

Signed-off-by: omar <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment on lines +239 to +242
// NXDOMAIN lookups. TrimSuffix keeps this idempotent in case the FQDN is
// already rooted (e.g. a CLUSTER_DOMAIN env var set with a trailing dot),
// avoiding a double dot that would itself break resolution.
xdsHost = strings.TrimSuffix(kubeutils.ServiceFQDN(metav1.ObjectMeta{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Copilot on this one. TrimRight is available and, if used, would make the code match what the comment states the code is doing.

@chandler-solo chandler-solo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Full stop..

@JCigan JCigan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fairly small thing, but I think you should make the change Copilot is suggesting in start.go and use strings.TrimRight instead of strings.TrimSuffix. Don't think you need to make the other change it's suggesting.

Comment on lines +239 to +242
// NXDOMAIN lookups. TrimSuffix keeps this idempotent in case the FQDN is
// already rooted (e.g. a CLUSTER_DOMAIN env var set with a trailing dot),
// avoiding a double dot that would itself break resolution.
xdsHost = strings.TrimSuffix(kubeutils.ServiceFQDN(metav1.ObjectMeta{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Copilot on this one. TrimRight is available and, if used, would make the code match what the comment states the code is doing.

Comment on lines 597 to +599
g.Expect(xdsSocketAddress.GetAddress()).To(gomega.Equal(
fmt.Sprintf("%s.%s.svc.cluster.local", wellknown.DefaultXdsService, testInstallation.Metadata.InstallNamespace),
), "xds socket address points to kgateway service, in installation namespace")
fmt.Sprintf("%s.%s.svc.cluster.local.", wellknown.DefaultXdsService, testInstallation.Metadata.InstallNamespace),
), "xds socket address points to kgateway service, in installation namespace, as a rooted FQDN")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree with Copilot here. For one, this pattern already exists in the test. For another, our e2e environment is tightly enough controlled that we aren't really worried about environments with a non-default cluster domain. I think your existing code is fine.

@puertomontt
puertomontt added this pull request to the merge queue Jun 23, 2026
Merged via the queue into kgateway-dev:main with commit 73b6acd Jun 23, 2026
32 checks passed
@puertomontt
puertomontt deleted the fix-xds-fqdn-trailing-dot branch June 23, 2026 19:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/fix Categorizes issue or PR as related to a bug. release-note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

xds_cluster bootstrap FQDN missing trailing dot causes excessive DNS queries (~96/min per gateway pod)

5 participants