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
01

What this adds

0102

Same 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

  1. 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
  2. 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/3

You should now be able to

02

Rewriting the request

0305

The proxy can edit the request on the way past: path, host and headers.

redirects, rewrites and header surgery · for whoever migrates APIs

  1. 03

    How does a prefix strip work?

    hands on

    Not 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 strip
      http:
        - match:
            - uri:
                prefix: /api/v2/payments
          rewrite:
            uri: /payments
          route:
            - destination:
                host: payment-svc.payments.svc.cluster.local
    
    Rewrite 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.
  2. 04

    How do old URLs move permanently?

    hands on

    Not 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, announced
      http:
        - match:
            - uri:
                prefix: /old-shop
          redirect:
            uri: /shop
            redirectCode: 301
    
    Rewrite 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.
  3. 05

    What header surgery is worth doing at the route?

    hands on

    Not 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 route
          headers:
            request:
              add:
                x-route-tier: premium
            response:
              remove:
                - x-internal-pod
                - x-debug-trace
    
    The 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/3

You should now be able to

03

Routing by caller

0607

The same destination can behave differently depending on who is asking.

sourceLabels and per caller paths · for whoever untangles shared services

  1. 06

    How does the same host serve callers differently?

    hands on

    Not 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 first
      http:
        - 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: v1
    
    This 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.
  2. 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/3

You should now be able to

04

Splitting ownership

0809

One host, many teams: delegation carves routes into separately owned files.

delegation, and the one host rule · for whoever owns a shared edge

  1. 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
  2. 09

    How does delegation split a host safely?

    hands on

    Not 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 gateways
    
    Children 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/3

You should now be able to

05

Where it ends

1012

Below HTTP the proxy sees less, so the rules can say less.

non HTTP, and the limits · for whoever reviews the design

  1. 10

    What does routing look like below HTTP?

    hands on

    Not 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 opened
      tls:
        - 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.
  2. 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
  3. 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/3

You should now be able to

Go deeper

4 links, each earning its place.

Where this leaves you

Rung 6 is the quiet superpower: migrating a shared dependency one consumer at a time. Rung 9 is how one host stops being a turf war.

If you keep one thing: routes see envelopes, not meaning. The day a route needs a unit test is the day it moves back into code.