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 the productpage 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 ServiceEntrys 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.

Was this information useful?
Do you have any suggestions for improvement?

Thanks for your feedback!