Understanding Traffic Routing
One of the goals of Istio is to act as a “transparent proxy” which can be dropped into an existing cluster, allowing traffic to continue to flow as before. However, there are powerful ways Istio can manage traffic differently than a typical Kubernetes cluster because of the additional features such as request load balancing. To understand what is happening in your mesh, it is important to understand how Istio routes traffic.
Protocols
Unlike Kubernetes, Istio has the ability to process application level protocols such as HTTP and TLS. In general, there are three classes of protocols Istio understands:
- HTTP, which includes HTTP/1.1, HTTP/2, and gRPC. Note that this does not include TLS encrypted traffic (HTTPS).
- TLS, which includes HTTPS.
- Raw TCP bytes.
The protocol selection document describes how Istio decides which protocol is used.
The use of “TCP” can be confusing, as in other contexts it is used to distinguish between other L4 protocols, such as UDP. When referring to the TCP protocol in Istio, this typically means we are treating it as a raw stream of bytes, and not parsing application level protocols such as TLS or HTTP.
Traffic Routing
When an Envoy proxy receives a request, it must decide where, if anywhere, to forward it to. By default, this will be to the original service that was requested, unless customized. How this works depends on the protocol used.
TCP
When processing TCP traffic, Istio has a very small amount of useful information to route the connection - only the destination IP and Port.
These attributes are used to determine the intended Service; the proxy is configured to listen on each service IP (<Kubernetes ClusterIP>:<Port>
) pair and forward traffic to the upstream service.
For customizations, a TCP VirtualService
can be configured, which allows matching on specific IPs and ports and routing it to different upstream services than requested.
TLS
When processing TLS traffic, Istio has slightly more information available than raw TCP: we can inspect the SNI field presented during the TLS handshake.
For standard Services, the same IP:Port matching is used as for raw TCP. However, for services that do not have a Service IP defined, such as ExternalName services, the SNI field will be used for routing.
Additionally, custom routing can be configured with a TLS VirtualService
to match on SNI and route requests to custom destinations.
HTTP
HTTP allows much richer routing than TCP and TLS. With HTTP, you can route individual HTTP requests, rather than just connections. In addition, a number of rich attributes are available, such as host, path, headers, query parameters, etc.
While TCP and TLS traffic generally behave the same with or without Istio (assuming no configuration has been applied to customize the routing), HTTP has significant differences.
- Istio will load balance individual requests. In general, this is highly desirable, especially in scenarios with long-lived connections such as gRPC and HTTP/2, where connection level load balancing is ineffective.
- Requests are routed based on the port and
Host
header, rather than port and IP. This means the destination IP address is effectively ignored. For example,curl 8.8.8.8 -H "Host: productpage.default.svc.cluster.local"
, would be routed to theproductpage
Service.
Unmatched traffic
If traffic cannot be matched using one of the methods described above, it is treated as passthrough traffic.
By default, these requests will be forwarded as-is, which ensures that traffic to services that Istio is not aware of (such as external services that do not have ServiceEntry
s created) continues to function.
Note that when these requests are forwarded, mutual TLS will not be used and telemetry collection is limited.
Service types
Along with standard ClusterIP
Services, Istio supports the full range of Kubernetes Services, with some caveats.
LoadBalancer
and NodePort
Services
These Services are supersets of ClusterIP
Services, and are mostly concerned with allowing access from external clients.
These service types are supported and behave exactly like standard ClusterIP
Services.
Headless Services
A headless Service is a Service that does not have a ClusterIP
assigned.
Instead, the DNS response will contain the IP addresses of each endpoint (i.e. the Pod IP) that is a part of the Service.
In general, Istio does not configure listeners for each Pod IP, as it works at the Service level. However, to support headless services, listeners are set up for each IP:Port pair in the headless service.
ExternalName Services
An ExternalName Service is essentially just a DNS alias.
Because there is no ClusterIP
nor pod IPs to match on, for TCP ExternalName Services, all IPs on the port will be matched.
This may prevent unmatched traffic on the same port from being forwarded correctly.
As such, it is best to avoid these where possible, or use dedicated ports when needed.
HTTP and TLS do not share this constraint, as routing is done based on the hostname/SNI.
ServiceEntry
In addition to Kubernetes Services, Service Entries can be created to extend the set of services known to Istio.
This can be useful to ensure that traffic to external services, such as example.com
, get the functionality of Istio.
A ServiceEntry with addresses
set will perform routing just like a ClusterIP
Service.
However, for Service Entries without any addresses
, all IPs on the port will be matched.
This may prevent unmatched traffic on the same port from being forwarded correctly.
As such, it is best to avoid these where possible, or use dedicated ports when needed.
HTTP and TLS do not share this constraint, as routing is done based on the hostname/SNI.