Build a Service Mesh (Envoy / Istio style) (13 scenes)
Scene 02 · The sidecar — one proxy per pod
Put a small proxy next to every service. App talks to localhost; cross-service traffic flows sidecar to sidecar. The fleet of sidecars is the service mesh.
Previously
Taking the network out of fifty apps' hands means putting a single, identical piece of code next to each app and routing every request through it.
Scene 02
The sidecar — one proxy per pod
Diagram
Two pods sit side-by-side. Each pod is a dashed frame holding an App container (gray, owns business logic) and a Sidecar container (green, owns policy). A request animates from App A through Sidecar A on localhost, across the network to Sidecar B, and into App B. **Sidecar** = a second container in the same pod that intercepts the app's traffic. **Service mesh** = the fleet of every sidecar across your services, treated as one configurable system — visible when you zoom out to the 12-pod view.
the app keeps doing business logic, so the policy box sits next to it as a separate process — that process is the *sidecar*.
Watch one request travel through two pods. It leaves App A, drops into Sidecar A on localhost, crosses the network to Sidecar B (mTLS), then surfaces in App B. The sidecars — not the apps — own the policy on that hop.
Implementation
App A — unchanged after sidecar
the app still calls a hostname; it does not know about any sidecar
1def handle_request():2 # App still calls a hostname.3 # It does not know there's a sidecar.4 response = http.get('checkout-svc/cart')5 return render(response)
iptables on Pod A (istio-init)
kernel-level redirect of outbound traffic onto the sidecar listener
1# Installed by the istio-init container at pod start.2iptables -t nat -N ISTIO_OUTPUT3iptables -t nat -A OUTPUT -p tcp -j ISTIO_OUTPUT4# Skip traffic the sidecar itself originates (uid 1337).5iptables -t nat -A ISTIO_OUTPUT -m owner \6 --uid-owner 1337 -j RETURN7# Everything else from the app: redirect to Envoy on 15001.8iptables -t nat -A ISTIO_OUTPUT -p tcp \9 -j REDIRECT --to-ports 15001
Sidecar A — outbound loop
owns the call once iptables hands it over (retry, timeout, mTLS)
1def serve_outbound():2 conn = accept(':15001') # from iptables REDIRECT3 req = http.parse(conn)4 route = routes.match(req) # listener -> route5 for attempt in range(route.retry_budget):6 upstream = mtls.dial(route.cluster, deadline=route.timeout)7 resp = upstream.send(req)8 if not retryable(resp): break9 http.write(conn, resp)
Sidecar B — inbound loop
terminates mTLS, then forwards to the local app on localhost
1def serve_inbound():2 conn = accept(':15006') # inbound REDIRECT target3 peer = mtls.terminate(conn) # verify Sidecar A's cert4 req = http.parse(conn)5 upstream = dial('127.0.0.1:app_port')6 resp = upstream.send(req)7 http.write(conn, resp)