v0.27.6
Changes
feature: Add support to opt-out from zone aware routing via Ingress/RouteGroup (#4049)
Introduce the annotation zalando.org/traffic-zone-aware: "false" on
Ingress and RouteGroup resources. When set, the resource receives all
endpoints across all zones, bypassing zone filtering both at the
dataclient layer (endpoint fetch) and at the routesrv layer (per-zone
route serving).
Usage:
metadata:
annotations:
zalando.org/traffic-zone-aware: "false"
Tasks
- Define
zalando.org/traffic-zone-awareannotation constant in the
kubernetes package - Modify
GetEndpointSlicesByServiceandGetEndpointSlicesByTarget
inclusterstate.goto accept ing and rg context param respectively and
skip zone filtering when value
ing.disableZoneAwareness/rg.disableZoneAwareness is true - Add zoneAwarenessAnnotationFilter() helper that returns an annotate()
filter when the zone-aware opt-out annotation is present - Modify Ingress v1 path rule conversion (
convertPathRuleV1) and
default backend conversion (convertDefaultBackendV1) to read the
annotation, pass it to endpoint fetch and prepend the annotate() filter
when annotation is set - Modify RouteGroup backend application (
applyServiceBackend) to read
the annotation, pass it to endpoint fetch and prepend the annotate()
filter when annotation is set - Add isZoneAwarenessDisabled() in routesrv/polling.go to detect the
opt-out by inspecting the route filter chain - Wire isZoneAwarenessDisabled() into getRouteForZone() to skip zone
filtering for opted-out routes - Update makeRoute test helper to inject the annotate() filter when the
opt-out flag is passed - Add integration test with two Ingresses in zone
eu-central-1a: one
opted out (expects all endpoints across zones), one default (expects
only zone-local endpoints) - Add unit tests for
filterRoutesByZonecovering opt-out scenarios:
both routes opted out, opt-out mixed with normal route, and opt-out with
a below-threshold zone
Tested the changes:
The skipper-ingress with zone aware routing enabled was in Zone-A
- Deployed ingress with 10 replicas, which means 10 endpoints are
available
zkubectl -n gmapp1 get pods -L topology.kubernetes.io/zone
NAME READY STATUS RESTARTS AGE ZONE
app1-v8-5c5965f6d4-7h6zr 1/1 Running 0 69s eu-central-1a
app1-v8-5c5965f6d4-7tnq4 1/1 Running 0 68s eu-central-1a
app1-v8-5c5965f6d4-98mz7 1/1 Running 0 68s eu-central-1c
app1-v8-5c5965f6d4-99n9p 1/1 Running 0 69s eu-central-1c
app1-v8-5c5965f6d4-bvdst 1/1 Running 0 69s eu-central-1a
app1-v8-5c5965f6d4-htn78 1/1 Running 0 68s eu-central-1b
app1-v8-5c5965f6d4-q75b9 1/1 Running 0 69s eu-central-1b
app1-v8-5c5965f6d4-wtgm5 1/1 Running 0 69s eu-central-1a
app1-v8-5c5965f6d4-xhv9q 1/1 Running 0 69s eu-central-1c
app1-v8-5c5965f6d4-zlz9x 1/1 Running 0 69s eu-central-1b
This meets the threshold to serve same zone endpoints, but since the
ingress has the opt-out annotation, the route contains all the endpoints
and not just zone filtered
kube_gmapp1__app1_v8_traffic_segment__gmapp1_pg9_test_zalan_do____app1_v8: Host(/^(gmapp1[.]pg9-test[.]zalan[.]do[.]?(:[0-9]+)?)$/) && TrafficSegment(0, 1)
-> disableAccessLog(2, 3, 404, 429)
-> fifo(2000, 20, "1s")
-> annotate("zalando.org/traffic-zone-aware", "false")
-> oauthTokeninfoValidate("{optOutAnnotations: [iam.zalando.org/public], optOutHosts: [\"^.*[.]ingress[.]cluster[.]local\"], unauthorizedResponse: \"Authentication required, see https://cloud.docs.zalando.net/howtos/authenticate-requests/#default-authentication\\n\"}")
-> stateBagToTag("auth-user", "client.uid")
-> <powerOfRandomNChoices, "http://[2a05:d024:90:1103:3e99::6]:8080", "http://[2a05:d024:90:1103:3e99::7]:8080", "http://[2a05:d024:90:1103:3e99::8]:8080", "http://[2a05:d024:90:1103:3e99::9]:8080", "http://[2a05:d024:90:1104:2396::a]:8080", "http://[2a05:d024:90:1104:2396::b]:8080", "http://[2a05:d024:90:1104:2396::c]:8080", "http://[2a05:d024:90:1105:4749::4]:8080", "http://[2a05:d024:90:1105:4749::6]:8080", "http://[2a05:d024:90:1105:4749::7]:8080">;
- Deployed a routegroup with 15 replicas, which means 15 endpoints are
available
zkubectl -n gmapp2 get pods -L topology.kubernetes.io/zone
NAME READY STATUS RESTARTS AGE ZONE
app2-v2-c9694944-598mc 1/1 Running 0 7m6s eu-central-1c
app2-v2-c9694944-6bcpm 1/1 Running 0 7m6s eu-central-1c
app2-v2-c9694944-7jgpp 1/1 Running 0 7m7s eu-central-1b
app2-v2-c9694944-88xzb 1/1 Running 0 7m7s eu-central-1a
app2-v2-c9694944-8kl6q 1/1 Running 0 7m6s eu-central-1c
app2-v2-c9694944-8wc97 1/1 Running 0 7m7s eu-central-1c
app2-v2-c9694944-cv9g8 1/1 Running 0 7m7s eu-central-1c
app2-v2-c9694944-dkh2h 1/1 Running 0 7m6s eu-central-1a
app2-v2-c9694944-flnx9 1/1 Running 0 7m6s eu-central-1a
app2-v2-c9694944-klk6r 1/1 Running 0 7m7s eu-central-1a
app2-v2-c9694944-kwddv 1/1 Running 0 7m6s eu-central-1b
app2-v2-c9694944-pjbtz 1/1 Running 0 7m6s eu-central-1a
app2-v2-c9694944-q5xrh 1/1 Running 0 7m7s eu-central-1b
app2-v2-c9694944-rs8hk 1/1 Running 0 7m7s eu-central-1a
app2-v2-c9694944-t6crt 1/1 Running 0 7m6s eu-central-1b
This meets the threshold to serve same zone endpoints, but since the
routegroup has the opt-out annotation, the route contains all the
endpoints and not just zone filtered
kube_rg__gmapp2__app2_v2_traffic_segment__get__0_0: Path("/test") && Host(/^(app2[.]teapot[.]zalan[.]do[.]?(:[0-9]+)?)$/) && Method("GET") && TrafficSegment(0, 1)
-> disableAccessLog(2, 3, 404, 429)
-> fifo(2000, 20, "1s")
-> annotate("zalando.org/traffic-zone-aware", "false")
-> annotate("iam.zalando.org/public", "The application uses its own authentication logic, similar to using Partner IAM.")
-> status(200)
-> inlineContent("Hello from second backend!")
-> oauthTokeninfoValidate("{optOutAnnotations: [iam.zalando.org/public], optOutHosts: [\"^.*[.]ingress[.]cluster[.]local\"], unauthorizedResponse: \"Authentication required, see https://cloud.docs.zalando.net/howtos/authenticate-requests/#default-authentication\\n\"}")
-> stateBagToTag("auth-user", "client.uid")
-> <powerOfRandomNChoices, "http://[2a05:d024:90:1103:3e99::10]:8080", "http://[2a05:d024:90:1103:3e99::11]:8080", "http://[2a05:d024:90:1103:3e99::12]:8080", "http://[2a05:d024:90:1103:3e99::13]:8080", "http://[2a05:d024:90:1103:3e99::14]:8080", "http://[2a05:d024:90:1103:3e99::f]:8080", "http://[2a05:d024:90:1104:2396::10]:8080", "http://[2a05:d024:90:1104:2396::d]:8080", "http://[2a05:d024:90:1104:2396::e]:8080", "http://[2a05:d024:90:1104:2396::f]:8080", "http://[2a05:d024:90:1105:4749::8]:8080", "http://[2a05:d024:90:1105:4749::9]:8080", "http://[2a05:d024:90:1105:4749::a]:8080", "http://[2a05:d024:90:1105:4749::b]:8080", "http://[2a05:d024:90:1105:4749::c]:8080">;
ref: #3971
Multiarch Docker image
Multiarch Docker image is available in GitHub's docker registry:
docker run -it ghcr.io/zalando/skipper:v0.27.6 skipper --help