Skip to content

fixes an issue where unhealthy endpoints for service entries are not removed from routing#14222

Merged
davidjumani merged 4 commits into
kgateway-dev:mainfrom
nmnellis:fix/serviceentry-endpoint-readiness
Jun 15, 2026
Merged

fixes an issue where unhealthy endpoints for service entries are not removed from routing#14222
davidjumani merged 4 commits into
kgateway-dev:mainfrom
nmnellis:fix/serviceentry-endpoint-readiness

Conversation

@nmnellis

@nmnellis nmnellis commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Description

ServiceEntry clusters that select pod endpoints via workloadSelector now respect pod readiness: pod-backed endpoints whose Kubernetes Ready condition is not True are excluded from the cluster's EDS, mirroring the EndpointSlice-based Service path. This lets locality failover promote endpoints in a peer cluster when all local pods for a selected workload go NotReady (e.g. during graceful termination, where kubelet flips the pod's Ready condition to False).

Scope:

  • Only ServiceEntries with workloadSelector-backed pod endpoints are affected.
  • WorkloadEntry and inline ServiceEntry endpoints are treated as always Ready and are never filtered, since pod readiness does not apply to them (their health is managed by the remote/owning system).

Change Type

/kind fix

Changelog

ServiceEntry clusters with workloadSelector-backed pod endpoints now respect pod readiness: NotReady pods are excluded from routing, matching the EndpointSlice-based Service behavior and enabling locality failover when all locally selected pods are NotReady. WorkloadEntry and inline ServiceEntry endpoints are unaffected.

Copilot AI review requested due to automatic review settings June 10, 2026 15:57
@gateway-bot gateway-bot added kind/fix Categorizes issue or PR as related to a bug. release-note labels Jun 10, 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

Note

Copilot was unable to run its full agentic suite in this review.

Add readiness-awareness to ServiceEntry-derived endpoints so NotReady pod-backed workloads are excluded, matching the EndpointSlice-based Service behavior and enabling locality failover when all local pods are NotReady.

Changes:

  • Add a Ready field to krtcollections.LocalityPod and include it in equality comparisons.
  • Populate Ready for pod-backed workloads and default Ready=true for WorkloadEntry/inline endpoints.
  • Filter out !Ready workloads when computing ServiceEntry endpoints.

Reviewed changes

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

File Description
pkg/krtcollections/pods.go Introduces LocalityPod.Ready and sets it for pod-backed workloads.
pkg/kgateway/extensions2/plugins/serviceentry/endpoints.go Skips NotReady workloads when building ServiceEntry endpoints.
pkg/kgateway/extensions2/plugins/serviceentry/collections.go Marks WorkloadEntry/inline endpoints as always ready.

Comment on lines 127 to +135
Locality ir.PodLocality
AugmentedLabels map[string]string
Addresses []string
// Ready reflects the pod's Kubernetes readiness (the Ready condition is True).
// It is used to exclude NotReady pods from ServiceEntry-derived endpoints,
// mirroring the EndpointSlice-based Service path which skips NotReady endpoints.
// Synthetic LocalityPods built from WorkloadEntries / inline endpoints set this
// to true, since pod readiness does not apply to them.
Ready bool
Comment on lines +121 to +129
// Skip NotReady pod-backed workloads so that ingress (and any other
// ServiceEntry consumer) does not send traffic to pods that Kubernetes has
// marked NotReady. This mirrors the EndpointSlice-based Service path, which
// skips endpoints whose Ready condition is not true, and lets locality
// failover promote endpoints in a peer cluster when all local pods are
// NotReady. WorkloadEntry and inline endpoints set Ready=true.
if !workload.Ready {
continue
}
Comment on lines 300 to 304
AugmentedLabels: labels,
Locality: l,
Addresses: extractPodIPs(pod),
Ready: isPodReadyConditionTrue(pod.Status),
}
@nmnellis
nmnellis force-pushed the fix/serviceentry-endpoint-readiness branch from 98b3a99 to 3107aff Compare June 10, 2026 18:27
@nmnellis
nmnellis force-pushed the fix/serviceentry-endpoint-readiness branch from 3107aff to 42dc3cf Compare June 11, 2026 12:49

@ymesika ymesika 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.

Changes make sense to me and aligned with the Service behavior.

Filtering on Ready covers graceful termination (kubelet marks draining pods NotReady). Terminal state check would be redundant since it's a subset of !Ready. Can you just confirm the repro shows the draining pod reporting NotReady, so we know the signal fires on termination and not only on a manually failed probe?

Could you phrase the description and release-note in terms of this repo construct this actually operates on - ServiceEntry clusters with workloadSelector-backed pod endpoints respecting pod readiness rather than global services?

@nmnellis

Copy link
Copy Markdown
Contributor Author

Thanks @ymesika. Agreed - filtering on the pod Ready condition is exactly the signal kubelet flips during graceful termination: once a pod enters Terminating, kubelet sets its Ready condition to False (well before the container exits), so isPodReadyConditionTrue returns false and the endpoint is dropped. That makes the explicit terminal/DeletionTimestamp check redundant since it's a strict subset of !Ready, so I've left it out.

On the repro: the draining pod reports Ready=False (not just a manually failed probe) - that's the same condition the EndpointSlice path keys off of, which is why this now matches Service behavior.

I've also reframed the description and release-note around the actual construct this operates on - ServiceEntry clusters with workloadSelector-backed pod endpoints respecting pod readiness - rather than "global services".

I also fixed the unit test failure: the setup-test fixture pods (testdata/setup_yaml/pods.yaml) had no Ready condition, so the new filter dropped all pod-backed endpoints in TestServiceEntry/se-backendref. Added Ready=True to the reviews pods to reflect their intended serving state; the full setup suite passes.

@nmnellis nmnellis changed the title fixes an issue where unhealthy endpoints for global services are not removed from routing fixes an issue where unhealthy endpoints for service entries are not removed from routing Jun 15, 2026
readiness filter on ServiceEntry-derived endpoints dropped all
pod-backed endpoints and TestServiceEntry/se-backendref failed.
Add a Ready=True condition to the reviews pods to reflect their
intended serving state.

Signed-off-by: Nick Nellis <[email protected]>
@nmnellis
nmnellis force-pushed the fix/serviceentry-endpoint-readiness branch from 1ea888c to ab9f44d Compare June 15, 2026 12:11
@nmnellis

Copy link
Copy Markdown
Contributor Author

/retest

@ymesika
ymesika added this pull request to the merge queue Jun 15, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 15, 2026
@davidjumani
davidjumani added this pull request to the merge queue Jun 15, 2026
Merged via the queue into kgateway-dev:main with commit b6eb1ba Jun 15, 2026
42 of 43 checks passed
@nmnellis
nmnellis deleted the fix/serviceentry-endpoint-readiness branch June 16, 2026 11:57
davidjumani pushed a commit that referenced this pull request Jun 16, 2026
…removed from routing (#14222)

Signed-off-by: Nick Nellis <[email protected]>
Signed-off-by: David Jumani <[email protected]>
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.

5 participants