Skip to main content

Envoy Proxy

An open-source high-performance proxy developed by Lyft, used as the sidecar proxy in Istio and several other service meshes. Envoy handles mTLS, load balancing, circuit breaking, retries, metrics, and distributed tracing at the proxy level.

What is Envoy Proxy

Envoy is a Layer 7 proxy designed specifically for cloud-native microservices. It was built by Lyft to solve the same networking problems that led to service meshes - retries, circuit breaking, observability - but as a separate process that any language can use without a library.

Istio uses Envoy as its data plane sidecar proxy. When Istio injects a sidecar, what it actually injects is an Envoy container.

What Envoy Does

Envoy operates at two network layers simultaneously:

TEXT
Layer 3/4 (TCP/UDP):
Handles raw TCP connections, TLS termination, connection pooling
This is where mTLS is enforced
Layer 7 (HTTP/gRPC):
Understands HTTP headers, paths, methods
This is where header-based routing and retries work
TEXT
Request arrives at pod
|
v
Envoy sidecar (inbound)
- validates mTLS client certificate
- decrypts the TLS connection
- records request arrival time and metadata
|
v
Application receives plain HTTP
|
v
Application sends response
|
v
Envoy sidecar (outbound for response)
- encrypts with mTLS
- records response time and status code
- reports metrics to control plane

Envoy Configuration

Envoy does not read static config files in a service mesh. Its configuration is pushed dynamically by the control plane using the xDS protocol (specifically: CDS, EDS, LDS, RDS, SDS). This is how Istio can update routing rules across thousands of pods without restarting any of them.

TEXT
Istio control plane (istiod)
|
| xDS protocol (gRPC streaming)
v
Envoy sidecar
receives updated routing rules, certificates, and cluster info
applies them immediately without restart

Metrics Envoy Exposes

Every Envoy sidecar exposes metrics at port 15090 that Prometheus scrapes:

Bash
## Check raw Envoy metrics from a pod's sidecar
kubectl exec -n production \
$(kubectl get pod -l app=orders -n production \
-o jsonpath='{.items[0].metadata.name}') \
-c istio-proxy -- \
curl -s localhost:15090/metrics | grep istio_requests

Key metrics: istio_requests_total, istio_request_duration_milliseconds, istio_tcp_connections_opened_total

Envoy vs Linkerd's Proxy

Envoy (Istio) Rust Proxy (Linkerd)
Language C++ Rust
Memory per sidecar ~100 MB ~10-20 MB
Feature richness Very high Focused on core use cases
WebAssembly extensions Yes No
Learning curve Steep (xDS, filters) Gentle
Remember

You rarely interact with Envoy directly when using Istio. Istio translates your VirtualService and DestinationRule YAML into Envoy configuration and pushes it to the proxies automatically. You write Istio resources; Istio configures Envoy.

Tip

Use istioctl proxy-status to check if all Envoy sidecars are in sync with the control plane. If a sidecar shows STALE, it may be applying outdated routing rules - this is how stale canary configurations survive pod restarts unexpectedly.

Frequently Asked Questions

Why did Istio and other service meshes choose Envoy instead of writing a custom proxy?

Envoy was built at Lyft specifically to solve the problem of making networking observable and resilient between microservices, with first-class support for dynamic service discovery, hot-reload configuration via xDS APIs, and rich L7 telemetry out of the box. Rather than reinventing this, Istio (and others like AWS App Mesh) adopted Envoy as their data-plane proxy and focus their own control plane on translating higher-level policy into Envoy's configuration.

What's a common gotcha when running Envoy as a sidecar in Kubernetes?

Sidecar injection adds real per-request latency and memory overhead per pod, which is often underestimated when sizing resource requests — a mesh with hundreds of pods can meaningfully increase cluster memory footprint. Another frequent issue is sidecar startup ordering: if the application container starts before the Envoy sidecar is ready, early outbound calls fail; most meshes now support native sidecar containers or init-container ordering to fix this.