Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 8 additions & 13 deletions internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,10 @@ func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRe
backendCustomRefs = append(backendCustomRefs, unstructuredRef)
}

// skip backendRefs with weight 0 as they do not affect the traffic distribution
if backendDest.ds.Weight != nil && *backendDest.ds.Weight == 0 {
// A zero-weight backendRef gets no traffic but is kept, so its cluster already exists when a
// canary rollout raises its weight. A dynamic resolver has no cluster to warm, and keeping it
// would reject the rule for mixing a dynamic resolver with other backendRefs.
if backendDest.ds.IsDynamicResolver && backendDest.ds.Weight != nil && *backendDest.ds.Weight == 0 {
continue
}

Expand Down Expand Up @@ -805,10 +807,6 @@ func (t *Translator) processBackendRef(
if err != nil {
return routeBackendRefDestination{ds: ds}, unstructuredRef, err
}
// An explicitly zero-weight backendRef never contributes traffic either.
if ds.Weight != nil && *ds.Weight == 0 {
return routeBackendRefDestination{ds: ds}, unstructuredRef, err
}
// Without a resolved gateway IR there's nowhere to eventually register a shared BackendCluster.
if t.gatewayXdsIR(gatewayCtx, xdsIR) == nil {
return routeBackendRefDestination{ds: ds}, unstructuredRef, err
Expand Down Expand Up @@ -1586,8 +1584,10 @@ func (t *Translator) processGRPCRouteRules(grpcRoute *GRPCRouteContext, parentRe
}
}

// skip backendRefs with weight 0 as they do not affect the traffic distribution
if backendDest.ds.Weight != nil && *backendDest.ds.Weight == 0 {
// A zero-weight backendRef gets no traffic but is kept, so its cluster already exists when a
// canary rollout raises its weight. A dynamic resolver has no cluster to warm, and keeping it
// would reject the rule for mixing a dynamic resolver with other backendRefs.
if backendDest.ds.IsDynamicResolver && backendDest.ds.Weight != nil && *backendDest.ds.Weight == 0 {
continue
}

Expand Down Expand Up @@ -2947,11 +2947,6 @@ func (t *Translator) processDestination(name string, backendRefContext BackendRe
}
}

// Skip processing backends with 0 weight
if weight == 0 {
return emptyDS, nil, nil
}

var envoyProxy *egv1a1.EnvoyProxy
if gatewayCtx != nil {
envoyProxy = gatewayCtx.envoyProxy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,18 @@ xdsIR:
name: httproute/default/httproute-1/rule/0/backend/2
protocol: HTTP
weight: 3
- addressType: IP
endpoints:
- host: 7.7.7.7
port: 8080
metadata:
kind: Service
name: service-4
namespace: default
sectionName: "8080"
name: httproute/default/httproute-1/rule/0/backend/3
protocol: HTTP
weight: 0
hostname: '*'
isHTTP2: false
metadata:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
envoyProxyForGatewayClass:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
namespace: envoy-gateway-system
name: test
spec:
mergeBackends: {}
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: default
name: canary
spec:
parentRefs:
- namespace: envoy-gateway
name: gateway-1
rules:
- matches:
- path:
type: PathPrefix
value: /canary
backendRefs:
- name: canary
port: 3000
weight: 50
- name: canary
port: 4000
weight: 0
services:
- apiVersion: v1
kind: Service
metadata:
name: canary
namespace: default
spec:
clusterIP: 10.11.12.13
ports:
- port: 3000
name: http-v1
protocol: TCP
targetPort: 3000
- port: 4000
name: http-v2
protocol: TCP
targetPort: 3000
endpointSlices:
- apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: endpointslice-canary
namespace: default
labels:
kubernetes.io/service-name: canary
addressType: IPv4
ports:
- name: http-v1
protocol: TCP
port: 3000
- name: http-v2
protocol: TCP
port: 3000
endpoints:
- addresses:
- "10.244.0.11"
conditions:
ready: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway-1
namespace: envoy-gateway
spec:
gatewayClassName: envoy-gateway-class
listeners:
- allowedRoutes:
namespaces:
from: All
name: http
port: 80
protocol: HTTP
status:
listeners:
- attachedRoutes: 1
conditions:
- lastTransitionTime: null
message: Sending translated listener configuration to the data plane
reason: Programmed
status: "True"
type: Programmed
- lastTransitionTime: null
message: Listener has been successfully translated
reason: Accepted
status: "True"
type: Accepted
- lastTransitionTime: null
message: Listener references have been resolved
reason: ResolvedRefs
status: "True"
type: ResolvedRefs
name: http
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
- group: gateway.networking.k8s.io
kind: GRPCRoute
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary
namespace: default
spec:
parentRefs:
- name: gateway-1
namespace: envoy-gateway
rules:
- backendRefs:
- name: canary
port: 3000
weight: 50
- name: canary
port: 4000
weight: 0
matches:
- path:
type: PathPrefix
value: /canary
status:
parents:
- conditions:
- lastTransitionTime: null
message: Route is accepted
reason: Accepted
status: "True"
type: Accepted
- lastTransitionTime: null
message: Resolved all the Object references for the Route
reason: ResolvedRefs
status: "True"
type: ResolvedRefs
controllerName: gateway.envoyproxy.io/gatewayclass-controller
parentRef:
name: gateway-1
namespace: envoy-gateway
infraIR:
envoy-gateway/gateway-1:
proxy:
config:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
name: test
namespace: envoy-gateway-system
spec:
logging: {}
mergeBackends: {}
status: {}
listeners:
- name: envoy-gateway/gateway-1/http
ports:
- containerPort: 10080
name: http-80
protocol: HTTP
servicePort: 80
metadata:
labels:
gateway.envoyproxy.io/owning-gateway-name: gateway-1
gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
ownerReference:
kind: GatewayClass
name: envoy-gateway-class
name: envoy-gateway/gateway-1
namespace: envoy-gateway-system
xdsIR:
envoy-gateway/gateway-1:
accessLog:
json:
- path: /dev/stdout
backendClusters:
- metadata:
kind: Service
name: canary
namespace: default
sectionName: "3000"
name: service/default/canary/3000/http
setting:
addressType: IP
endpoints:
- host: 10.244.0.11
port: 3000
metadata:
kind: Service
name: canary
namespace: default
sectionName: "3000"
name: service/default/canary/3000/http
protocol: HTTP
- metadata:
kind: Service
name: canary
namespace: default
sectionName: "4000"
name: service/default/canary/4000/http
setting:
addressType: IP
endpoints:
- host: 10.244.0.11
port: 3000
metadata:
kind: Service
name: canary
namespace: default
sectionName: "4000"
name: service/default/canary/4000/http
protocol: HTTP
globalResources:
proxyServiceCluster:
metadata:
kind: Service
name: envoy-envoy-gateway-gateway-1-196ae069
namespace: envoy-gateway-system
sectionName: "8080"
name: envoy-gateway/gateway-1
settings:
- addressType: IP
endpoints:
- host: 7.6.5.4
port: 8080
zone: zone1
metadata:
kind: Service
name: envoy-envoy-gateway-gateway-1-196ae069
namespace: envoy-gateway-system
sectionName: "8080"
name: envoy-gateway/gateway-1
protocol: TCP
http:
- address: 0.0.0.0
externalPort: 80
hostnames:
- '*'
metadata:
kind: Gateway
name: gateway-1
namespace: envoy-gateway
sectionName: http
name: envoy-gateway/gateway-1/http
path:
escapedSlashesAction: UnescapeAndRedirect
mergeSlashes: true
port: 10080
routes:
- destination:
backendClusterRefs:
- name: service/default/canary/3000/http
weight: 50
- name: service/default/canary/4000/http
weight: 0
metadata:
kind: HTTPRoute
name: canary
namespace: default
name: httproute/default/canary/rule/0
hostname: '*'
isHTTP2: false
metadata:
kind: HTTPRoute
name: canary
namespace: default
name: httproute/default/canary/rule/0/match/0/*
pathMatch:
distinct: false
name: ""
prefix: /canary
readyListener:
address: 0.0.0.0
ipFamily: IPv4
path: /ready
port: 19003
15 changes: 14 additions & 1 deletion internal/ir/xds.go
Original file line number Diff line number Diff line change
Expand Up @@ -2298,7 +2298,20 @@ func (r *RouteDestination) NeedsClusterPerSetting() bool {
r.HasFiltersInSettings() ||
(len(r.Settings) > 1 && r.HasPreferLocalZone()) ||
r.HasMixedUpstreamProtocolRequirements() ||
r.HasMixedAutoSNISettings()
r.HasMixedAutoSNISettings() ||
r.HasZeroWeightSettings()
}

// HasZeroWeightSettings returns true if any setting has an explicit zero weight. A zero locality
// weight is invalid in a shared cluster, so such a setting gets its own cluster and a zero-weight
// weighted_clusters entry.
func (r *RouteDestination) HasZeroWeightSettings() bool {
for _, s := range r.Settings {
if s.Weight != nil && *s.Weight == 0 {
return true
}
}
return false
}

// HasMixedEndpoints returns true if the RouteDestination has endpoints of multiple types
Expand Down
Loading
Loading