feat: add RouteUpstreamLimitsFilter for per-service upstream limits and passive health checking - #5596
Open
bharath-k1999 wants to merge 10 commits into
Open
feat: add RouteUpstreamLimitsFilter for per-service upstream limits and passive health checking#5596bharath-k1999 wants to merge 10 commits into
bharath-k1999 wants to merge 10 commits into
Conversation
…cks for API Gateway
…ive health checks
…ithub.com/hashicorp/consul-k8s into bharath/api-gateway-passive-health-checks
Go Test Coverage: 61.5%Patch coverage: 61.8% (136/220 changed lines covered) See the workflow run for the full per-package breakdown and downloadable HTML report. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #5596 +/- ##
==========================================
+ Coverage 58.62% 58.67% +0.04%
==========================================
Files 298 299 +1
Lines 36767 36945 +178
==========================================
+ Hits 21554 21676 +122
- Misses 13268 13326 +58
+ Partials 1945 1943 -2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
consul-k8s PR #5596 — API Gateway: Passive Health Checks & Upstream Limits
Summary
This PR adds Kubernetes-native support for configuring upstream circuit-breaker limits and passive health checks (Envoy outlier detection) on API Gateway backends.
Two configuration surfaces are exposed:
RouteUpstreamLimitsFilterCRDHTTPRouteextensionReffilterapi-gateway.consul.hashicorp.com/default-*annotationsService-level
RouteUpstreamLimitsFiltervalues always override gateway-wide defaults for the matched backend.What is implemented
New CRD:
RouteUpstreamLimitsFilterAttach it to a specific backend via
HTTPRouteextensionRef:Gateway-wide defaults via annotations
Set default upstream limits on every backend behind a Gateway:
These land in
APIGatewayConfigEntry.Defaultsin Consul and propagate to every upstream cluster via xDS.Files changed
control-plane/api/v1alpha1/routeupstreamlimitsfilter_types.goRouteUpstreamLimitsFilter,RouteUpstreamLimitsFilterSpec,PassiveHealthCheck)control-plane/api/v1alpha1/zz_generated.deepcopy.gocontrol-plane/config/crd/bases/consul.hashicorp.com_routeupstreamlimitsfilters.yamlcharts/consul/templates/crd-routeupstreamlimitsfilters.yamlcharts/consul/templates/connect-inject-clusterrole.yamlget/list/watchonrouteupstreamlimitsfilterscontrol-plane/api-gateway/common/translation.gotranslateGatewayDefaults,toConsulUpstreamLimits,translateBackendRefLimits,toConsulPassiveHealthCheckcontrol-plane/api-gateway/common/diff.goDefaultsinapiGatewaysEqual; bug fix:LimitsinhttpServicesEqual; newupstreamLimitsEqual+passiveHealthCheckEqualhelperscontrol-plane/api-gateway/controllers/gateway_controller.go.Watches()call; addedtransformRouteUpstreamLimitsFiltercontrol-plane/api-gateway/controllers/index.goHTTPRoute_RouteUpstreamLimitsFilterIndexindex for watch resolutioncontrol-plane/api-gateway/common/translation_upstreamlimits_test.gocontrol-plane/api-gateway/common/diff_test.goTestEntriesEqual_APIGateway_Defaults(7 cases),TestEntriesEqual_HTTPRoute_Limits(7 cases)acceptance/tests/api-gateway/api_gateway_upstream_limits_test.goacceptance/tests/fixtures/cases/api-gateways/upstream-limits/hack/run-upstream-limits-acceptance.shUnit tests
TestEntriesEqual_APIGateway_Defaults—diff_test.goCovers
apiGatewaysEqualwith all combinations of theDefaultsfield:nilDefaultsMaxConnectionsnilvs non-nil DefaultsMaxConnectionsPassiveHealthCheckPassiveHealthCheck.MaxFailuresnilvs setPassiveHealthCheckTestEntriesEqual_HTTPRoute_Limits—diff_test.goCovers
httpServicesEqualwith all combinations of the per-serviceLimitsfield:nilLimitsMaxConnectionsnilvs non-nil LimitsMaxConnectionsPassiveHealthCheckPassiveHealthCheck.MaxFailuresnilvs setPassiveHealthCheckAcceptance tests
Test:
TestAPIGateway_UpstreamLimits_And_PassiveHealthCheckFile:
acceptance/tests/api-gateway/api_gateway_upstream_limits_test.goRun time: ~3.5 minutes (single Helm install amortised across all sub-tests)
All 6 sub-tests passed on a local Kind cluster:
Sub-test breakdown
day1/consul-config-entry-has-limitsApply the
RouteUpstreamLimitsFilterfixture (maxConnections=25,maxPendingRequests=50,maxConcurrentRequests=100,passiveHealthCheck.interval=10s,maxFailures=3).Assert that the Consul
HTTPRouteConfigEntryhas a non-nilLimitsblock on the backendservice with exactly those values.
day1/envoy-config-has-circuit-breaker-and-outlier-detectionPort-forward to the gateway pod's Envoy admin port (
:19000) and fetch/config_dump.Parse
ClustersConfigDump.dynamic_active_clustersto find thestatic-servercluster.Assert:
circuit_breakers.thresholds[0].max_connections == 25outlier_detectionblock is presentday2/update-limits-and-verifyPatch the
RouteUpstreamLimitsFilterin-place:maxConnections25 → 75,maxPendingRequests50 → 150,maxConcurrentRequests100 → 300passiveHealthCheck.maxFailures3 → 7Assert:
HTTPRouteConfigEntryreflectsmaxConnections=75,maxFailures=7/config_dumpshowsmax_connections: 75andoutlier_detectionpresentday1/gateway-defaults-via-annotationsAnnotate the
Gatewayobject:Assert that the Consul
APIGatewayConfigEntry.Defaultsblock is non-nil withMaxConnections=40,PassiveHealthCheck.Interval=15s,MaxFailures=5.day2/update-gateway-defaults-and-verifyPatch annotations:
default-max-connections40 → 80,default-passive-health-check-max-failures5 → 9.Assert Consul
APIGatewayConfigEntry.Defaults.MaxConnections=80,MaxFailures=9.service-level-overrides-gateway-defaultsWith gateway-wide default at
max_connections=40, update theRouteUpstreamLimitsFilterto
maxConnections=100. Assert:HTTPRouteConfigEntrycarriesLimits.MaxConnections=100(not 40) — provingthe controller correctly uses service-level values over gateway defaults.
/config_dumpshowscircuit_breakers.max_connections: 100— proving thexDS push reflects the override end-to-end.
Local testing setup
Prerequisites
Build local images
Create Kind cluster and load images
Run the acceptance test
Or use the convenience script:
Verify Envoy config manually
Expected output (day-1):
{ "name": "static-server.default.dc1.internal.<id>.consul", "circuit_breakers": { "thresholds": [{ "max_connections": 25, "max_pending_requests": 50, "max_requests": 100 }] }, "outlier_detection": { "consecutive_5xx": 3, "interval": "10s", "base_ejection_time": "30s", "max_ejection_percent": 50, "enforcing_consecutive_5xx": 100 } }