Envoy is a high-performance L4/L7 proxy and communication bus designed for cloud-native applications. Originally built at Lyft and donated to the CNCF (where it graduated in 2018), it is now the networking foundation of major service meshes (Istio, AWS App Mesh, Consul Connect) and the reference implementation behind the Kubernetes Gateway API project Envoy Gateway.
Envoy operates out of process alongside your application. Your code sends traffic to localhost; Envoy handles the rest load balancing, retries, observability, TLS termination, and more without any changes to application code.
Architecture
graph LR
Downstream["Downstream client"]
Listener["Listener\n(address:port)"]
FilterChain["Filter chain\n(L4 + L7 filters)"]
Router["Router filter"]
Cluster["Cluster\n(load balancer)"]
Upstream["Upstream service"]
Downstream -->|"TCP / HTTP"| Listener
Listener --> FilterChain
FilterChain --> Router
Router -->|"route match"| Cluster
Cluster -->|"selected endpoint"| Upstream
Every Envoy instance is a self-contained process. Multiple Envoy instances across a fleet share configuration through the xDS API they do not communicate with each other directly.
Core concepts
Listeners
A listener binds to an address and port and waits for inbound connections. Each listener has one or more filter chains selected by SNI, IP range, or other connection metadata.
1
2
3
4
5
6
7
8
9
10
listeners:
- name: ingress_http
address:
socket_address:
address: 0.0.0.0
port_value: 8080
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
# ... HTTP filter config
Filter chains and filters
Filters are the processing pipeline. They run in order and can inspect, modify, or terminate connections and requests. There are two layers:
Network filters operate on raw TCP bytes. The most important is http_connection_manager, which parses HTTP and hands off to HTTP filters.
HTTP filters run inside http_connection_manager and process HTTP requests and responses. They are chained each filter can pass, modify, or reject the request before it reaches the next one.
Inbound HTTP request
└── http_connection_manager (network filter)
├── jwt_authn (HTTP filter verify JWT)
├── ext_authz (HTTP filter call external auth service)
├── rate_limit (HTTP filter check rate limit service)
├── fault (HTTP filter inject delays/errors for testing)
└── router (HTTP filter route to upstream cluster, always last)
Clusters
A cluster is a named group of upstream endpoints. It defines how Envoy connects to a backend: load balancing policy, connection pool limits, health checks, circuit breaker thresholds, and TLS settings.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
clusters:
- name: order_service
connect_timeout: 1s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: order_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: order-svc.default.svc.cluster.local
port_value: 8080
Load balancing policies include ROUND_ROBIN, LEAST_REQUEST, RING_HASH, and RANDOM.
Routes
Routes live inside http_connection_manager and map incoming requests to clusters using host, path, header, and query-parameter matching.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
route_config:
virtual_hosts:
- name: local_services
domains: ["*"]
routes:
- match:
prefix: /api/orders
route:
cluster: order_service
timeout: 5s
retry_policy:
retry_on: 5xx
num_retries: 3
- match:
prefix: /api/customers
route:
cluster: customer_service
Endpoints
Endpoints are individual upstream hosts within a cluster. In dynamic mode they are populated by the EDS (Endpoint Discovery Service) and updated without restarting Envoy.
xDS: dynamic configuration
Envoy’s configuration can be fully static (a single YAML file) or fully dynamic via the xDS API a set of gRPC streaming services that push configuration updates to Envoy in real time. Service meshes and control planes (Istiod, xDS-compatible controllers) implement xDS.
| xDS service | Abbreviation | What it controls |
|---|---|---|
| Listener Discovery Service | LDS | Listeners |
| Route Discovery Service | RDS | Route configurations |
| Cluster Discovery Service | CDS | Clusters |
| Endpoint Discovery Service | EDS | Cluster endpoints |
| Secret Discovery Service | SDS | TLS certificates and keys |
| Aggregated Discovery Service | ADS | All of the above over one stream |
With xDS, a control plane can add a new cluster, update a route, rotate a certificate, or drain a listener without touching the Envoy process. This is the mechanism service meshes use to implement traffic shifting, canary deployments, and mTLS certificate rotation.
Static vs dynamic configuration
| Static | Dynamic (xDS) | |
|---|---|---|
| Config source | Local YAML file | gRPC stream from control plane |
| Hot reload | Requires restart or --drain-time-s | Live push, zero downtime |
| Use case | Edge proxies, local dev, simple deployments | Service meshes, large fleets, multi-tenant gateways |
Key built-in HTTP filters
| Filter name | Purpose |
|---|---|
envoy.filters.http.router | Routes requests to clusters. Always the last HTTP filter. |
envoy.filters.http.jwt_authn | Verifies JWTs against JWKS endpoints without an external call. |
envoy.filters.http.ext_authz | Delegates auth decisions to an external service (gRPC or HTTP). |
envoy.filters.http.rate_limit | Calls a rate limit service (compatible with Lyft’s ratelimit). |
envoy.filters.http.fault | Injects artificial delays and error responses for chaos testing. |
envoy.filters.http.cors | Handles Cross-Origin Resource Sharing headers. |
envoy.filters.http.lua | Runs inline Lua scripts for lightweight request/response mutation. |
envoy.filters.http.health_check | Responds to health check requests locally without proxying upstream. |
envoy.filters.http.compressor | Compresses response bodies (gzip, brotli). |
envoy.filters.http.grpc_json_transcoder | Transcodes REST/JSON requests to gRPC. |
Where Envoy is used
Service mesh sidecar In Istio, every pod runs an Envoy sidecar injected automatically. Istiod acts as the xDS control plane. Envoy enforces mTLS, applies traffic policies, and emits telemetry without any changes to the application.
Edge/ingress proxy Envoy sits at the cluster edge, terminates TLS, and routes external traffic to internal services. Contour and Emissary-Ingress are Kubernetes Ingress controllers built on Envoy.
Envoy Gateway The CNCF-maintained implementation of the Kubernetes Gateway API. It uses Envoy as the data plane and exposes GatewayClass, Gateway, and HTTPRoute resources. See the Kubernetes Gateway API Setup guide for the Gateway API standard.
AWS App Mesh / Google Traffic Director Managed control planes that use Envoy as the data plane for service-to-service communication in cloud environments.
What to avoid
Do not hardcode static config when your deployment will scale. Static YAML works for a single instance but requires a restart (or config reload) for every change. For production fleets use xDS so configuration updates propagate without downtime.
Do not skip health checks on clusters. Without active health checking, Envoy will continue sending traffic to unhealthy endpoints until the connection times out. Configure both active (health_checks) and passive (outlier detection) health checking.
Do not put auth logic after the router filter. The router filter is always the last HTTP filter in the chain. Any filter placed after it will never execute. Always place jwt_authn, ext_authz, and rate limiting filters before router.
Do not confuse Envoy with Envoy Gateway. Envoy is the raw proxy; Envoy Gateway is a Kubernetes-native control plane that configures Envoy via the Gateway API CRDs. They share the same data plane but have very different configuration surfaces.
Do not ignore the admin interface in production. Envoy exposes an admin endpoint (default port 9901) that can drain connections, change log levels, and dump the current config. Restrict access to it it should never be reachable from outside the cluster.