Skip to content

docs: add a task for active and passive health checking - #10474

Open
lyelgate wants to merge 5 commits into
envoyproxy:mainfrom
lyelgate:docs/health-checking
Open

lyelgate wants to merge 5 commits into
envoyproxy:mainfrom
lyelgate:docs/health-checking

Conversation

@lyelgate

@lyelgate lyelgate commented Nov 1, 2026

Copy link
Copy Markdown

What this PR does / why we need it:

There's no task page for health checking today. healthCheck only appears in passing in the Failover task and the Health Check Logging task, so users have to work out the API from the reference.

This PR adds tasks/traffic/health-check.md, following the structure of the other BackendTrafficPolicy tasks (circuit breakers, retry), on top of the quickstart:

  • Active health checking: an HTTP health check on the quickstart backend route, and how to see each endpoint's health flags through the Envoy admin /clusters endpoint (the same port-forward the backend utilization task uses).
  • Simulating a failing endpoint: setting expectedStatuses: [204], which the echo backend never returns, to show /failed_active_hc. Then it explains the panic threshold, which surprises a lot of people: with the default 50%, a backend whose only endpoint is unhealthy keeps receiving traffic. Setting panicThreshold: 0 makes the same request fail with 503 no healthy upstream.
  • Other active checkers: TCP with send/receive, gRPC with service, and HTTP with expectedStatuses and overrides.port.
  • Passive health checking: outlier detection with consecutive5XxErrors, interval, baseEjectionTime and maxEjectionPercent, and how the ejection time grows.

It links to the ActiveHealthCheck and PassiveHealthCheck API reference for the full field list, and to the existing health check logging task.

Testing:

  • Every policy in the page (the HTTP check, the expectedStatuses and panicThreshold patches, TCP, gRPC, HTTP with overrides.port, and passive) was run through egctl x translate against the quickstart resources. Each one is Accepted, and the generated httproute/default/backend/rule/0 cluster has the expected healthChecks (httpHealthCheck with expected statuses [200,201) or [204,205), tcpHealthCheck, grpcHealthCheck), commonLbConfig.healthyPanicThreshold of 0 for panicThreshold: 0, and outlierDetection for the passive example.
  • Relative links follow the ../../../api/... convention of the other task pages. The API anchors #activehealthcheck and #passivehealthcheck exist in extension_types.md.
  • codespell is clean, and the enabled markdownlint rules (MD001, MD009, MD037, MD038) were checked by hand.

Which issue(s) this PR fixes:

Fixes #2418


PR Checklist

  • Authorship & ownership: Coding agents / AI assistants are welcome, but I have reviewed every change, understand how and why it works, can explain and maintain it, and take full responsibility for this PR. I have not submitted generated output I do not understand.
  • DCO: All commits are signed off (git commit -s). See DCO: Sign your work.
  • API agreed first: N/A: no changes under /api.
  • Required checks pass: make generate gen-check, make lint, and the unit-test/coverage build pass. (Flaky e2e failures are not considered breakages, but gen-check, lint, and coverage MUST pass.) N/A: docs only.
  • Tests added/updated: New/changed code is covered by appropriate tests. N/A: docs only.
  • Docs: User-facing changes update the docs, either in this PR or a follow-up PR.
  • Release notes: N/A: docs only.
  • Generated files committed: N/A: no API, Helm chart or module changes.
  • Scope & compatibility: The PR is reasonably scoped (no unrelated changes) and preserves backward compatibility, or any breaking change is called out above and documented in release-notes/current/breaking_changes/.
  • Codex review: Requested a Codex review and addressed all of its comments.
  • Copilot review: Requested a Copilot review and addressed all of its comments.

Health checking is only covered in passing today, inside the failover
task and the health check logging task. Add a task that shows how to
configure active health checks with BackendTrafficPolicy and check the
result through the Envoy admin interface, how panic mode keeps a
backend serving when its endpoints fail, the TCP and gRPC checkers, and
passive health checking with outlier detection.

Fixes envoyproxy#2418

Signed-off-by: Lakhan Yelgate <39281685+lyelgate@users.noreply.github.com>
An unexpected HTTP status marks an endpoint unhealthy right away; only
timeouts, connection failures and retriableStatuses count toward
unhealthyThreshold. The passive example needs alwaysEjectOneEndpoint to
eject the quickstart backend's single endpoint, combined checks are
still subject to panic mode, and readers without a LoadBalancer need
GATEWAY_HOST pointed at the port-forward.

Signed-off-by: Lakhan Yelgate <39281685+lyelgate@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3b2dd8fba4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +210 to +211
An ejected endpoint is reported with the `failed_outlier_check` health flag. It stays ejected for `baseEjectionTime`
multiplied by the number of times it has been ejected, so an endpoint that keeps failing is ejected for longer. See [PassiveHealthCheck][] for every field and its default.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Account for active checks ending passive ejections

Because the merge patch above retains the successful active GET / check, Envoy's default successful_active_health_check_uneject_host=true clears a passive outlier ejection on the next successful probe. On the quickstart backend that probe runs every 3 seconds, so an endpoint ejected after five 5xx responses does not stay ejected for the stated 30 seconds (let alone the multiplied duration); remove the active check for this demonstration or document that active recovery can terminate the ejection early.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Right, the active check from earlier in the task stays in the policy, so a successful probe returns the endpoint to service before baseEjectionTime. The page now says the ejection can end early for that reason, in cb56044.

Envoy returns an ejected endpoint to service as soon as it passes an
active health check, and the passive example keeps the active check
from earlier in the task, so the ejection can end before
baseEjectionTime.

Signed-off-by: Lakhan Yelgate <39281685+lyelgate@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cb56044bab

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

return too many errors. This is Envoy's [Outlier Detection][].

Health checking is configured in the `healthCheck` field of a [BackendTrafficPolicy][], which can target a [Gateway][],
an [HTTPRoute][], a [GRPCRoute][] or the other xRoute kinds. Each backendRef of a route has its own set of endpoints,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Exclude UDPRoute from supported health-check targets

For a BackendTrafficPolicy targeting a UDPRoute, “the other xRoute kinds” promises functionality that the translator deliberately drops: the UDP branches in internal/gatewayapi/backendtrafficpolicy.go:1777-1794 and :2150-2165 copy only load-balancer/DNS settings, and the comment at :2340-2344 states that a health check never reaches a udp_proxy cluster. Such a policy can therefore be accepted while none of its endpoints are checked, so narrow this claim to route kinds whose IR carries HealthCheck or explicitly call out UDP as unsupported.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Right, ir.UDPRoute only carries load balancer and DNS settings, so a health check never reaches a UDP backend. The page now lists the supported route kinds (HTTPRoute, GRPCRoute, TCPRoute, TLSRoute) and says UDPRoute backends aren't health-checked, in 970e56b.

A UDPRoute backend's cluster is built from ir.UDPRoute, which only
carries load balancer and DNS settings, so a health check set by a
BackendTrafficPolicy never reaches it. List the route kinds that do
support health checks instead of "the other xRoute kinds".

Signed-off-by: Lakhan Yelgate <39281685+lyelgate@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 970e56ba7a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +13 to +14
Health checking is configured in the `healthCheck` field of a [BackendTrafficPolicy][], which can target a [Gateway][],
an [HTTPRoute][], a [GRPCRoute][], a TCPRoute or a TLSRoute. Health checks are not applied to the backends of a

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include supported ListenerSet and backend targets

With a ListenerSet or MergeBackends deployment, this sentence incorrectly makes the target list look exhaustive: BackendTrafficPolicySpec also permits ListenerSet, Service, ServiceImport, and Backend targets (api/v1alpha1/backendtrafficpolicy_types.go:42-48), and the backend-target translation carries HealthCheck into non-UDP merged clusters (internal/gatewayapi/backendtrafficpolicy.go:641-652,2346-2374). Include those scopes with the MergeBackends caveat so users are not directed unnecessarily to per-route policies.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Right, the policy can also target a ListenerSet and, with MergeBackends, a Service, ServiceImport or Backend. The intro no longer lists the targets exhaustively; it says health checks apply to the backends of the resources the policy targets, with the UDPRoute exception, in 9d20329.

## Passive Health Checking

Passive health checking needs no probes: Envoy counts the errors returned by each endpoint while serving real requests.
Apply a policy that ejects an endpoint for 30 seconds after 5 consecutive `5xx` responses, checking every 3 seconds.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Separate inline ejection from interval sweeps

With consecutive5XxErrors configured as here, Envoy evaluates the counter inline on each upstream response and can eject the host immediately on the fifth 5xx; interval controls periodic outlier-analysis sweeps rather than batching this detector. Describing the policy as “checking every 3 seconds” therefore gives the wrong timing to users trying to observe the walkthrough; state the immediate trigger and explain the interval separately.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed, the consecutive 5xx detector ejects as soon as the threshold is reached. The text now says so and describes interval as how often the periodic outlier analysis runs, which also returns endpoints to service, in 9d20329.

Comment on lines +210 to +211
An ejected endpoint is reported with the `failed_outlier_check` health flag. It stays ejected for `baseEjectionTime`
multiplied by the number of times it has been ejected, so an endpoint that keeps failing is ejected for longer. Because

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Mention the maximum ejection-time cap

After repeated ejections, Envoy uses min(base_ejection_time * ejection count, max_ejection_time), and the unset max_ejection_time defaults to 300 seconds. For this 30-second policy the duration stops growing after 300 seconds rather than always remaining the stated product, so qualify the multiplication rule with the cap to avoid misleading long-running tests.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good point. Envoy Gateway doesn't expose max_ejection_time, so Envoy's 300 second default always applies. The page now says the ejection time grows only up to that maximum, in 9d20329.

@lyelgate
lyelgate requested a review from a team as a code owner November 1, 2026 09:49
@netlify

netlify Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for cerulean-figolla-1f9435 ready!

Name Link
🔨 Latest commit 9d20329
🔍 Latest deploy log https://app.netlify.com/projects/cerulean-figolla-1f9435/deploys/6ae779e2a61db42ae5b33b94
😎 Deploy Preview https://deploy-preview-10474--cerulean-figolla-1f9435.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-01T17:46:41.667832Z 9d20329 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46e06242ca

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

## Active Health Checking

Apply a `BackendTrafficPolicy` that probes every endpoint of the `backend` HTTPRoute with an HTTP `GET /` request every
3 seconds. An endpoint is marked unhealthy after 3 failed probes in a row, and healthy again after 1 successful probe.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Configure retriable statuses before claiming three probes

For HTTP checks, api/v1alpha1/healthcheck_types.go:125-128 specifies that unhealthyThreshold is honored for statuses configured in retriableStatuses; an unexpected non-retriable status makes the host unhealthy immediately. The later patch expects 204 while this backend returns 200, and no retriable status is configured, so the endpoint transitions after the first probe rather than after three. Make 200 retriable for the simulation or describe the immediate transition.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Right, thanks: without retriableStatuses an unexpected status marks the endpoint unhealthy on the first probe. Fixed the intro to say the threshold applies to timeouts, connection failures and retriable statuses, and the walkthrough now says the next probe marks it unhealthy right away, in 3b2dd8f.

always in panic mode while that endpoint is unhealthy.

```shell
curl --verbose --header "Host: www.example.com" http://$GATEWAY_HOST/

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle the no-LoadBalancer prerequisite path

When users follow this page's "Without LoadBalancer Support" prerequisite, site/content/en/latest/boilerplates/testing.md:23-46 starts a proxy on localhost:8888 but never defines GATEWAY_HOST. This command therefore expands to http:///, so the panic-mode request and the subsequent 503 comparison cannot be exercised on kind or other clusters without an external load balancer. Provide the matching localhost request path or initialize the variable in that prerequisite branch.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good point. Added a line before the request telling readers who followed the "Without LoadBalancer Support" prerequisite to export GATEWAY_HOST=localhost:8888, in 3b2dd8f.


```shell
kubectl patch backendtrafficpolicy/health-check --type merge \
-p '{"spec":{"healthCheck":{"passive":{"consecutive5XxErrors":5,"interval":"3s","baseEjectionTime":"30s","maxEjectionPercent":50}}}}'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Allow the only endpoint to be ejected

The task establishes above that the quickstart backend has one endpoint, so ejecting it would mean ejecting 100% of the cluster. With maxEjectionPercent set to 50 and alwaysEjectOneEndpoint omitted (its default is false), this policy cannot eject that endpoint and therefore cannot exhibit the claimed 30-second ejection or failed_outlier_check state after five 5xx responses. Use a 100% cap or enable alwaysEjectOneEndpoint for this single-endpoint example.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Correct, 50% of a single endpoint rounds down to zero. The example now sets alwaysEjectOneEndpoint: true and explains why, in 3b2dd8f. I checked it with egctl x translate: the cluster gets alwaysEjectOneHost: true.

An ejected endpoint is reported with the `failed_outlier_check` health flag. It stays ejected for `baseEjectionTime`
multiplied by the number of times it has been ejected, so an endpoint that keeps failing is ejected for longer. See [PassiveHealthCheck][] for every field and its default.

Active and passive health checking can be combined in the same policy: an endpoint is only used when it passes both.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Qualify the combined-check guarantee for panic mode

This flow restores the default panicThreshold before adding passive checking, so with the one-endpoint backend any failed check drops health below 50% and activates panic mode. As the page itself explains above, Envoy then ignores health status and can route to that endpoint, making the categorical claim that an endpoint is only used when it passes both checks false in this example. State the panic-mode exception or keep panic mode disabled when promising this behavior.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed. It now says an endpoint is only considered healthy when it passes both, and that panic mode still applies when fewer than panicThreshold percent of endpoints are healthy, in 3b2dd8f.

BackendTrafficPolicy also targets ListenerSets and, with MergeBackends,
Services, ServiceImports and Backends, so describe the targets without
an exhaustive list. A consecutive 5xx ejection happens as soon as the
threshold is reached, while interval sets how often the periodic
outlier analysis runs. The ejection time grows with each ejection only
up to Envoy's default max_ejection_time of 300 seconds.

Signed-off-by: Lakhan Yelgate <39281685+lyelgate@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add docs describing how to use Health Checking

1 participant