Lesson 4 · Service-mesh fundamentals
VirtualService
The routing rules — match a request, send it somewhere — and how this repo generates ~571 of them.
Your win: read a VirtualService — match / route
and the extras (rewrite, timeout, retries,
fault, weight) — and understand how this repo's apiHttp/
webHttp values become real VirtualServices.
Anatomy of a routing rule
A VirtualService defines routing rules for one or more hosts. Each rule matches some traffic and routes it to a destination:1
kind: VirtualService metadata: { name: bob-api } spec: hosts: [ api.<env>.manabie.io ] gateways: [ istio-system/<env>-<vendor>-gateway ] # bind to the edge http: - match: [{ uri: { prefix: /bob.v1.InternalReaderService } }] fault: { abort: { httpStatus: 403, percentage: { value: 100 } } } # block! - match: [{ uri: { prefix: /bob.v1. } }] route: [{ destination: { host: bob, port: { number: 5050 } } }]
| Field | Does |
|---|---|
match | select traffic by URI (prefix/exact), header, method, … |
route.destination | the target service host (+ port, subset) |
weight | split traffic across destinations — the basis of canary |
rewrite | change the path/authority before forwarding |
timeout / retries | bound the call / retry failures (Lesson 7) |
fault | inject an abort/delay (chaos testing — or, here, a block) |
How this repo generates VirtualServices
Anchor — values become VirtualServices
You never hand-write a VirtualService here. The library macro
virtualservice.api.tpl
(deployments/helm/libs/util/templates/_hosts.tpl:96-112) emits a
VirtualService named <svc>-api, binds it to
istio-system/<env>-<vendor>-gateway (:105),
and dumps your .Values.apiHttp route table verbatim under http:.
util.app includes it whenever .Values.apiHttp is set
(backend/tom/templates/util/_app.tpl:26-33). So each service just
writes a route table in its values; multiply across ~30 env×org cells and you get the
~571 VirtualServices in the mesh. There's a webHttp twin for
grpc-web (with CORS).
Anchor — a real, clever route
deployments/helm/backend/bob/values.yaml shows what these
tables do in practice (
apiHttp: from :41):
- a
matchon/bob.v1.InternalReaderServicewith afault.abortreturning 403 at 100% (:42-46) — a deliberate block so Internal RPCs can't be reached from the public edge. VirtualService as a security control, not just routing. - normal routes to
host: bobport5050, plus a cross-service route sending some paths tonotificationmgmt:6950(:69-78) — one host's VirtualService can route to another service.
One honest gap to note
These route tables set
match/route/rewrite/
fault but not timeout or retries — the
services rely on Envoy's defaults. So "we use Istio retries" would be wrong for this repo;
the resilience knobs exist (Lesson 7) but aren't turned on in the VirtualServices.
Read this next
Istio docs — VirtualService (reference)
The full match/route/rewrite/timeout/retries/fault/weight surface, with examples.
Check yourself (from memory)
Q1. The two essential parts of a VirtualService HTTP rule are…
match selects the traffic; route
sends it to a destination. The rest (rewrite/timeout/fault) are optional.
Q2. To run a canary (5% to v2), you'd use…
Split traffic by
weight across destinations
(usually two subsets from a DestinationRule).
Q3. In this repo, a VirtualService for a service is created when…
The
virtualservice.api.tpl macro renders one from
.Values.apiHttp (and webHttp) — ~571 across cells.
VirtualService anatomy + how this repo generates them.
recall, then click to reveal
A VIRTUALSERVICE = routing rules for HOST(s). Each HTTP rule: MATCH
(uri prefix/exact, header, method) → ROUTE (
destination.host + port/subset).
Extras: weight (canary/split), rewrite, timeout,
retries, fault (inject abort/delay), mirror. Bind to a
Gateway via gateways: for edge traffic. REPO: never hand-written — macro
virtualservice.api.tpl (_hosts.tpl:96) renders
<svc>-api from .Values.apiHttp, bound to
<env>-<vendor>-gateway; util.app includes it if
apiHttp set → ~571 across cells. bob blocks Internal RPCs at the edge with a
fault.abort 403 (bob/values.yaml:42-46) and cross-routes some paths
to notificationmgmt. NOTE: no timeout/retries set — Envoy defaults.
✅ Part 1 complete
You've got the fundamentals: what a mesh is (L1), how the sidecar is injected (L2), the three
traffic resources and the request path (L3), and how VirtualServices route (L4).
Part 2 follows the traffic outward: the ingress Gateway,
DestinationRule subsets, resilience, and the EnvoyFilter
escape hatch.
Ready for Part 2 (Gateway, DestinationRule, resilience, EnvoyFilter)? Or a
mock interview on Part 1 — the three-resources split is a classic question.
Ask me.