The sidecar — one proxy per pod

A sidecar is a second container next to your app that intercepts all of its network traffic; the fleet of those sidecars, sharing one policy, is a 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

  1. Watch
  2. Try it
  3. Predict
  4. Capture
WITH SERVICE MESHPOD AApp Aowns business logicSIDECARSidecar Aowns policyPOD BApp Bowns business logicSIDECARSidecar Bowns policylocalhostlocalhostnetwork · mTLSSHARED SIDECAR POLICYretry budget: 20% of in-flight · mTLS: requiredApp → Sidecar (localhost) → Sidecar → App. Both sidecars read the same shared policy.
the app keeps doing business logic, so the policy box sits next to it as a separate process — that process is the sidecar.
What to watch for

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.

Continue unlocks when the animation finishes.
Implementation

Highlighted lines are the ones running in the diagram right now.

App A — unchanged after sidecar
the app still calls a hostname; it does not know about any sidecar
def handle_request():
# App still calls a hostname.
# It does not know there's a sidecar.
response = http.get('checkout-svc/cart')
return render(response)
iptables on Pod A (istio-init)
kernel-level redirect of outbound traffic onto the sidecar listener
# Installed by the istio-init container at pod start.
iptables -t nat -N ISTIO_OUTPUT
iptables -t nat -A OUTPUT -p tcp -j ISTIO_OUTPUT
# Skip traffic the sidecar itself originates (uid 1337).
iptables -t nat -A ISTIO_OUTPUT -m owner \
--uid-owner 1337 -j RETURN
# Everything else from the app: redirect to Envoy on 15001.
iptables -t nat -A ISTIO_OUTPUT -p tcp \
-j REDIRECT --to-ports 15001
Sidecar A — outbound loop
owns the call once iptables hands it over (retry, timeout, mTLS)
def serve_outbound():
conn = accept(':15001') # from iptables REDIRECT
req = http.parse(conn)
route = routes.match(req) # listener -> route
for attempt in range(route.retry_budget):
upstream = mtls.dial(route.cluster, deadline=route.timeout)
resp = upstream.send(req)
if not retryable(resp): break
http.write(conn, resp)
Sidecar B — inbound loop
terminates mTLS, then forwards to the local app on localhost
def serve_inbound():
conn = accept(':15006') # inbound REDIRECT target
peer = mtls.terminate(conn) # verify Sidecar A's cert
req = http.parse(conn)
upstream = dial('127.0.0.1:app_port')
resp = upstream.send(req)
http.write(conn, resp)

Where this sits in Build a Service Mesh (Envoy / Istio style)

Scene 02 of 13. 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.

Up next. The sidecar can rewrite policy because it actually opens the request and reads it — but that requires the proxy to speak the language of the request, not just shuffle bytes.

All 13 scenes in Build a Service Mesh (Envoy / Istio style) · Every curriculum

Built with Arqly
Every scene in Build a Service Mesh (Envoy / Istio style) builds on the one before it.All 13 Build a Service Mesh (Envoy / Istio style) scenes