If you've worked with Istio, you've probably heard terms like "control plane," "data plane," "Pilot," and "Envoy sidecar." But how do they actually fit together? In this article, I'll walk through the full architecture — from how Pilot discovers services to how a client request is processed inside Envoy.
Part 1: How Pilot and Envoy Work Together
The Istio control plane component Pilot is responsible for bridging Kubernetes and Envoy. Here's the three-step flow:
┌─────────────────────────────────────────────────────┐
│ API Server │
└──────────────────────┬──────────────────────────────┘
│ 1. Service discovery
│ (Services + Endpoints via client-go Informer)
│ 2. Fetch Istio CRDs
│ (VirtualService, DestinationRule, etc.)
▼
┌─────────────────────────────────────────────────────┐
│ Istio Pilot │
│ │
│ Convert: Endpoints + governance policies │
│ → Envoy-compatible xDS format │
└──────────────────────┬──────────────────────────────┘
│ 3. Push via xDS
▼
┌─────────────────────────────────────────────────────┐
│ Envoy Sidecar │
│ (Listener → Route → Cluster → Endpoint) │
└─────────────────────────────────────────────────────┘
Step 1 — Service Discovery:
Pilot uses the client-go Informer to watch the Kubernetes API Server, collecting all Service and Endpoints resources across the cluster.
Step 2 — Policy Discovery:
Pilot also watches for user-defined Istio CRD objects: VirtualService, DestinationRule, Gateway, etc. These define the traffic governance policies.
Step 3 — xDS Push:
Pilot converts the combined service topology and governance policies into Envoy's native xDS format, then pushes the config to each Envoy sidecar via gRPC streaming.
Part 2: The Four Core Resources in Envoy
Once config is pushed to Envoy, how does a client request actually get processed? It flows through four core resource types:
Client Request
│
▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐
│ Listener │────▶│ Route │────▶│ Cluster │──LB▶│ Endpoint │
│ (LDS) │ │ (RDS) │ │ (CDS) │ │ (EDS) │
└──────────┘ └──────────┘ └──────────┘ └────────────┘
│ │
L3/L4 Filters Upstream Service
1. Listener (LDS)
A Listener is a port that Envoy opens to accept incoming connections. Multiple Listeners are fully isolated from each other. Beyond port binding, each Listener is configured with L3/L4 filters.
Config is managed via LDS (Listener Discovery Service).
2. Cluster (CDS + EDS)
A Cluster is the abstraction for an upstream service. Every upstream service maps to exactly one Cluster. Cluster config includes:
- Connection timeout
- Connection pool settings
- Load balancing policy
- Health check config
- Endpoint list
Config is managed via CDS (Cluster Discovery Service) + EDS (Endpoint Discovery Service).
3. Route (RDS)
Route is the bridge between Listeners and Clusters:
- Listener receives the request
- Route decides which Cluster to forward it to
- Route also handles: Virtual Host definitions, HTTP header manipulation (add/remove/modify), timeout & retry policies
Config is managed via RDS (Route Discovery Service).
4. Filter (Envoy Filter)
Filters are Envoy's plugin mechanism — they allow powerful extensions without modifying source code. There are three layers:
| Filter Layer | Scope | Examples |
|---|---|---|
| Listener Filter | Pre-routing, L3/L4 | TLS Inspector, HTTP Inspector, Original Destination |
| Network Filter | L3/L4 connection handling | Dubbo proxy, Kafka filter, MySQL proxy, Redis proxy, HTTP Connection Manager |
| HTTP Filter | L7 HTTP traffic | Route matching, Health check, Lua, CSRF, VHDS |
Key insight: The HTTP Connection Manager (HCM) is itself a special Network Filter that manages all HTTP Filters. This layered design is what gives Envoy the ability to support virtually any protocol — and even perform protocol conversion.
Full Architecture: Putting It All Together
Here's how the complete picture looks — from API Server down to upstream services:
┌──────────────────────────────────────────────────────────────────┐
│ API Server │
└────────────────────────────┬─────────────────────────────────────┘
│ Services, Endpoints, Istio CRDs
▼
┌──────────────────────────────────────────────────────────────────┐
│ Istio Pilot │
│ ① Service discovery ② Fetch CRDs ③ Convert & push xDS │
└────────────────────────────┬─────────────────────────────────────┘
│ xDS (gRPC streaming)
▼
┌──────────────────────────────────────────────────────────────────┐
│ Envoy │
│ │
│ Listener0 ┐ Cluster0 ┐ Endpoint0 │
│ Listener1 ├──Route──────────▶Cluster1 ├──LB────▶Endpoint1 │
│ Listener2 ┘ Cluster2 ┘ Endpoint2 │
│ Endpoint3 │
│ │
│ [Listener Filter] → [Network Filter] → [HTTP Filter] │
└──────────────────────────────────────────────────────────────────┘
│
▼
Upstream Application Services
Why This Architecture Matters
This design gives Istio several powerful properties:
- Zero-touch config updates — Envoy never needs to restart. All config changes are pushed via xDS streaming.
- Protocol agnostic — Through Network Filters, Envoy natively supports HTTP, gRPC, Dubbo, Kafka, MySQL, Redis, and more.
- Policy separation — Traffic governance rules (VirtualService, DestinationRule) live in the control plane. The data plane (Envoy) just executes them.
- Extensibility — Custom Envoy Filters allow teams to add any behavior (auth, rate limiting, tracing) without touching application code.
Summary
| Component | Role |
|---|---|
| Pilot | Discovers services + policies, converts to xDS, pushes to Envoy |
| Envoy Listener | Accepts client connections on configured ports |
| Envoy Route | Decides which Cluster handles each request |
| Envoy Cluster | Abstracts upstream services with LB + health check |
| Envoy Endpoint | The actual upstream instance IP:port |
| Envoy Filter | Plugin mechanism for L4/L7 traffic manipulation |
Understanding this architecture is the foundation for everything else in Istio — circuit breaking, canary releases, observability. They all build on top of these primitives.
💻 Explore the full implementation:
github.com/muzinan123/servicemesh📖 Next in this series: Traffic Management in Istio: Circuit Breaking & Rate Limiting
Top comments (0)