Stop reading whenever you have enough
Advanced routing, in twelve questions.
Each one is the question the previous answer makes you ask. The ones that matter come with the manifest or the command, because that is the part you meet at work.
Not technical? This page assumes the VirtualService ladder. Read that one first, and its first three questions are written for you.
- Rungs
- 12
- Hands on
- 6
- Read
- ~8 min
What this adds
01–02Same file, more verbs: rewrite the request, route by caller, split ownership, and leave HTTP.
the map past canaries · for anyone who finished the VirtualService ladder
- 01
What are the four families?
Not knowing this costs
Each family replaces a class of application code with config.
- Rewriting: edit path, host or headers in flight
- Caller routing: behave differently per source
- Delegation: split one host across teams. And non HTTP
- 02
Which family gets abused?
Not knowing this costs
The worst routing incidents are business logic nobody tested as logic.
- Rewrites: business logic creeps into routes
- A route that encodes product rules is code in hiding
- Config changes skip the tests code would face
Before you scroll on
0/3You should now be able to
Rewriting the request
03–05The proxy can edit the request on the way past: path, host and headers.
redirects, rewrites and header surgery · for whoever migrates APIs
- 03
How does a prefix strip work?
hands onNot knowing this costs
Prefix strips let services stay ignorant of edge URL politics.
- Match the prefix, rewrite the uri
- The service sees clean paths, the edge keeps versioned ones
manifestthe classic striphttp: - match: - uri: prefix: /api/v2/payments rewrite: uri: /payments route: - destination: host: payment-svc.payments.svc.cluster.localRewrite happens after match, so the match sees the original and the service sees the rewritten. Reversing that in your head produces routes that loop or 404. - 04
How do old URLs move permanently?
hands onNot knowing this costs
A 301 is a promise browsers remember. Issue it only when you mean it.
- redirect, not rewrite: the client is told to move
- 301 for permanent moves that browsers may cache
- Redirect and rewrite are exclusive per route
manifestthe move, announcedhttp: - match: - uri: prefix: /old-shop redirect: uri: /shop redirectCode: 301Rewrite hides the change from clients; redirect announces it. Choosing rewrite for a public move strands every bookmark and cached link on the old path forever. - 05
What header surgery is worth doing at the route?
hands onNot knowing this costs
Internal headers on public responses are reconnaissance, gift wrapped.
- Add: provenance and routing hints for downstream
- Remove: internal headers before responses leave
- Per route, request and response separately
manifestboth directions, one routeheaders: request: add: x-route-tier: premium response: remove: - x-internal-pod - x-debug-traceThe response remove list is quiet security work: internal hostnames and debug headers stop leaking to the internet at the one place all responses pass.
Before you scroll on
0/3You should now be able to
Routing by caller
06–07The same destination can behave differently depending on who is asking.
sourceLabels and per caller paths · for whoever untangles shared services
- 06
How does the same host serve callers differently?
hands onNot knowing this costs
Shared dependency upgrades stop being one big bang for all consumers.
- sourceLabels match on who is asking
- One consumer gets v2 while the world stays on v1
- The dependency migrates one caller at a time
manifestone consumer, moved firsthttp: - match: - sourceLabels: app: reporting # only the reporting service route: - destination: host: ledger-svc.finance.svc.cluster.local subset: v2 - route: # everyone else - destination: host: ledger-svc.finance.svc.cluster.local subset: v1This is a caller side rule, so it lives in config the callers actually receive: exportTo and Sidecar scoping from other ladders can silently exclude exactly the caller you targeted. - 07
Why route by caller instead of configuring the caller?
Not knowing this costs
Coordinated multi team deploys are what this exists to delete.
- The platform moves consumers without their deploys
- Rollback is central, instant, and visible
- The caller’s code stays identical throughout
Before you scroll on
0/3You should now be able to
Splitting ownership
08–09One host, many teams: delegation carves routes into separately owned files.
delegation, and the one host rule · for whoever owns a shared edge
- 08
Why is two VirtualServices on one host a bug?
Not knowing this costs
The two file merge is the multi team version of route order.
- They merge in an order you do not control
- A catch all in one shadows routes in the other
- One file per host, or delegation, never both halves blind
- 09
How does delegation split a host safely?
hands onNot knowing this costs
Delegation is the difference between shared edge and shared outage.
- A parent VirtualService owns the host and the split
- delegate hands path spaces to team owned children
- Children cannot escape their delegated space
manifestone host, two teams, no collisions# parent, owned by platform, bound to the gateway http: - match: [{ uri: { prefix: /shop } }] delegate: { name: shop-routes, namespace: shop } - match: [{ uri: { prefix: /pay } }] delegate: { name: pay-routes, namespace: payments } # child, owned by the shop team, plain routes inside /shop # kind: VirtualService, name: shop-routes, no hosts, no gatewaysChildren declare no hosts and no gateways: the parent grants context. A child that adds its own hosts stops being a delegate and rejoins the merge lottery.
Before you scroll on
0/3You should now be able to
Where it ends
10–12Below HTTP the proxy sees less, so the rules can say less.
non HTTP, and the limits · for whoever reviews the design
- 10
What does routing look like below HTTP?
hands onNot knowing this costs
Promising HTTP grade routing on passthrough TLS is promising the impossible.
- tcp routes match on port, little else
- tls routes match on SNI without decrypting
- No paths, no headers, no retries down here
manifestTLS routed by name, never openedtls: - match: - port: 443 sniHosts: [payments.example.com] route: - destination: host: payment-svc.payments.svc.cluster.local port: { number: 8443 }SNI is the one readable field in a TLS stream the proxy does not terminate. Everything else this track taught about HTTP routing simply does not exist down here. - 11
What can no route ever see?
Not knowing this costs
Routes see envelopes. Decisions about contents belong to code.
- Request bodies, and anything inside encryption
- Business meaning: which tenant, which plan
- State: what this user did last request
- 12
When should routing logic go back into code?
Not knowing this costs
The route that needed a unit test was code the whole time.
- When it needs tests, state or business data
- When product managers ask for changes to it
- Config is for traffic shape, code is for meaning
Before you scroll on
0/3You should now be able to
Go deeper
4 links, each earning its place.
HTTPRewrite and HTTPRedirect reference↗
The exact semantics behind rungs 3 and 4, including what may combine.
Header manipulation reference↗
The full surgery surface from rung 5.
VirtualService delegation↗
The parent and child contract from rung 9, precisely.
TCP and TLS routing reference↗
What little rung 10 has to work with, defined.