Link Search Menu Expand Document

Istio

Resource Types

Colloquially

  • ServiceEntry - what Services exist and how are their network endpoints found?
  • VirtualService - to which Service should traffic for a given hostname be sent?
  • DestinationRule - how do I talk to that Service?

Services in Istio

Services are the destination of Route Rules (the host which a VirtualService matches is an arbitrary string). Services by the Istio definition are morally “units of application behaviour”. They are made of network endpoints: Pods, and external endpoints. Istio has a Service Registry of all the Services it knows about. In some configurations it will refuse to send traffic to Services that aren’t in the Service Registry (in others it’ll assume the Service exists and take some guesses about how to find its endpoints and how to talk to them).

In a Kubernetes environment, the Service Registry is populated from Kubernetes Service instances. Extra Service Registry entries (eg for internet endpoints, VMs) can be added with the ServiceEntry resource. Recall that, in some mesh configurations, such ServiceEntries are necessary for workloads in the mesh to talk to anything outside the cluster. ServiceEntry is a higher-level resource - doesn’t necessarily specify all endpoints in a Service, instead it says where to discover them.

There is no (easy) way to view the contents of the Service Registry; the imported Kubernetes Services, DNS query results, etc aren’t reflected as a read-only resource like Kubernetes’ Endpoint.

VirtualService/

delay-injection.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: delay-injection
spec:
  hosts:
    - service-a
  http:
    - fault:
        delay:
          fixedDelay: 10s
          percentage:
            value: 100.0
      route:
        - destination:
            host: service-a
 

error-injection.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: error-injection
spec:
  hosts:
    - service-a
  http:
    - fault:
        abort:
          httpStatus: 500
          # percentage:
          #   value: 100.0
      route:
        - destination:
            host: service-a
 

header-manipulation.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: header-manipulation
spec:
  hosts:
    - service-a
  http:
    - headers:
        # These rules are always applied
        request:
          set:
            manipulated: "true"
      route:
        - weight: 90
          destination:
            host: service-a-current
          headers:
            # These rules are applied only when this route is taken
            request:
              set:
                test-subset: "false"
            response:
              add:
                new-header: "foo"
              remove:
                - old-header
        - weight: 90
          destination:
            host: service-a-next
          headers:
            # These rules are applied only when this route is taken
            request:
              set:
                test-subset: "true"
 

identity.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: identity
spec:
  hosts:
    - service-a
  http:
    - route:
        - destination:
            host: service-a
 

layer-7-routing.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: path-routing
spec:
  hosts:
    - service-a
  http:
    - match:
        - uri:
            prefix: "/beta"
          ignoreUriCase: true
      route:
        - destination:
            host: service-a-vnext
    - route:
        - destination:
            host: service-a-current
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: header-routing
spec:
  hosts:
    - service-a
  http:
    - match:
        - headers:
            x-beta:
              exact: "yes please"
      route:
        - destination:
            host: service-a-vnext
    - route:
        - destination:
            host: service-a-current
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: combined-routing
spec:
  hosts:
    - service-a
  http:
    - match:
        - uri:
            prefix: "/beta"
          ignoreUriCase: true
          method:
            exact: "POST"
          headers:  # Has header 'x-beta: im_sure'
            x-beta:
              exact: "im_sure"
          queryParams:  # '?beta=really_sure'
            beta:
              exact: "really_sure"
          withoutHeaders:  # Doesn't have header 'x-feeling: scared'
            x-feeling:
              exact: "scared"
      route:
        - destination:
            host: service-a-vnext
    - route:
        - destination:
            host: service-a-current
 

redirect-rewrite.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: redirect
spec:
  hosts:
    - service-a
  http:
    # Sends an HTTP 301.
    - redirect:
        authority: service-a-vnext
        uri: /app
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: rewrite
spec:
  hosts:
    - service-a
  http:
    # Transparently re-writes the destination.
    - rewrite:
        authority: service-a-vnext
        uri: /app
      route:
        - destination:
            host: service-a-vnext
 

retry.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: retry
spec:
  hosts:
    - service-a
  http:
    - route:
        - destination:
            host: service-a
      retries:
        attempts: 3
        perTryTimeout: 1s
        retryOn: 5xx  # Any HTTP 5xx status, timed-out/rejected/closed TCP connection
 

timeout.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: timeout
spec:
  hosts:
    - service-a
  http:
    # Istio will return an HTTP 504 to the caller if the destination doesn't reply in time
    - route:
        - destination:
            host: service-a
      timeout: 10s
 

traffic-split.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: split-between-services
spec:
  hosts:
    - service-a
  http:
    - route:
        - weight: 90
          destination:
            host: service-a-current
        - weight: 10
          destination:
            host: service-a-next
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: split-between-subsets
spec:
  hosts:
    - service-a
  http:
    - route:
        - weight: 90
          destination:
            host: service-a
            subset: v1
        - weight: 10
          destination:
            host: service-a
            subset: v2
 

VirtualService

VirtualServices configure routing rules for traffic.

Traffic is identified by the Host it’s addressed to in its layer 7 request header (there must be at most one VirtualService per Host). For a given protocol, Routing Rules are then tried in order until one matches the attributes of the request. The matching routing rule specifies a Service to which to send the request (a Service is effectively a Kubernetes Service, qv). Optionally, a subset of the Service’s Pods can be targeted using Subsets (see DestinationRule)

VirtualServices can be thought of as an “active” bump-on-the-wire through which requests are sent. They can apply various transforms to the traffic passing through them, such as header manipulation, delay injection, etc.

DestinationRule/

load-balance.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: load-balance-simple
spec:
  host: service-a
  trafficPolicy:
    loadBalancer:
      simple: LEAST_CONN  # Default: ROUND_ROBIN, others: RANDOM
 

sticky-sessions.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: sticky-sessions-user-cookie
spec:
  host: service-a
  trafficPolicy:
    loadBalancer:
      consistentHash:
        httpCookie:
          name: user
          ttl: 0s
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: sticky-sessions-user-header
spec:
  host: service-a
  trafficPolicy:
    loadBalancer:
      consistentHash:
        httpHeaderName: x-remote-user
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: sticky-sessions-source-ip
spec:
  host: service-a
  trafficPolicy:
    loadBalancer:
      consistentHash:
        useSourceIp: true
 

subsets.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: subsets
spec:
  host: service-a
  subsets:
    - name: v1  # Arbitrary name for subset
      labels:  # Kubernetes Pod labels to match
        version: v1
    - name: v2
      labels:
        version: v2
 

tls.yaml

            ---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: accept-external-tls
spec:
  host: external-host-a
  trafficPolicy:
    tls:
      mode: SIMPLE
---
# NB: This establishes an mTLS connection with an upstream endpoint.
# It's for _mesh-external_ endpoints; within the mesh Istio automatically establishes mTLS connections between pairs of sidecars.
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: mutual-external-tls
spec:
  host: external-host-a
  trafficPolicy:
    tls:
      mode: MUTUAL
      privateKey: /etc/certs/client_key.pem
      clientCertificate: /etc/certs/client_certificiate.pem
      caCertificates: /etc/certs/server_root_certificates.pem
 

DestinationRule

After a destination Service is chosen by a VirtualService (the request is routed), a DestinationRule specifies how that Service should be talked to.

In this directory, “endpoint pool” means the set of endpoints to which traffic has been routed; a Service or a Subset of a Service

It describes how to load balance between the network endpoints of the Service (as found in the Service Registry). It also says how connections should be made to those network endpoints (HTTP version, TLS stance) and how they should be managed (keep-alive times, maximum active connections to load-balance onto any individual endpoint at once).

DestinationRules configure the client sidecars, eg for the flow service-a -> sidecar-a -> sidecar-b -> service-b the DestinationRule for host “service-b” configures each instance of “sidecar-a”. Thus the connection options technically configure how “sidecar-a” talks to “sidecar-b” (if the destination is also in the mesh, or directly to the service or whatever proxies are in front of it if it’s not). The only time to bear in mind that you’re talking to the server’s sidecar rather than the actual “app” is when considering TLS, as the server sidecar will terminate this. There is no way to configure the behaviour from “sidecar-b” to “service-b”; this is basically a passthrough, except the mutual TLS upgrade noted above.

DestinationRules are implemented locally by each sidecar; there is no global coordination between sidecars. For example

  • circuit-breaker detection and elimination is done per client sidecar; each holds their own state for this which might differ from other sidecars’

DestinationRules configure how one client should talk to the pool of endpoints (a Service or subset of a Service). For example

  • load-balancer config controls how each individual client should pick one of the n servers (endpoint instances) each time there’s a new outbound connection
  • circuit-breaking applies across the pool (of servers); it temporarily removes instances from the pool (even if Service Discovery says they’re healthy thus they’re in the service registry)
  • TLS config applies to all connections from the client to any server (in the pool) The exception is connection-pool settings, which apply to each client-server pair individually. Recall though that they apply to sidecar-a -> sidecar-b, not sidecar-b -> service-b.

It also somewhat confusingly details the Subsets of the Service available as routing targets in VirtualServices. You might think this would be on something like a ServiceEntry resource that obviously manipulates the Service Registry. However, DestinationRule settings can be per-subset (as they’re different workload binaries and might need treating differently).

circuit-breaker.yaml

            # Evaluates error rates for each endpoint in the pool against the settings here, ejecting them if they cross the thresholds.
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: circuit-breaker
spec:
  host: service-a
  trafficPolicy:
    outlierDetection:
      consecutive5xxErrors: 7  # Default 5
      interval: 5m  # Interval over which errors are counted and compared to the threshold. This is a periodic check, not a rolling one.
      baseEjectionTime: 10s  # Initial period for which the endpoint is ejected from the endpoint pool. Repeated ejections are longer each time. Default 30s
      maxEjectionPercent: 50  # Max % of endpoints that can ejected from the endpoint pool. Default 10
      minHealthPercent: 50  # Min % of endpoints in the endpoint pool that must be healthy for circuit-breaking to activate. Default 0
 

connection-pool-settings.yaml

            # NB: these apply per server workload (Pod).
# eg `maxConnections: 100` means each *client* Pod's sidecar will open max 100 connections to each individual *server* endpoint.
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: connection-pool-settings
spec:
  host: service-a
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100  # Default 4bn
        connectTimeout: 50ms  # Default 10s
        tcpKeepalive:  # TCP-level keepalives ie SO_KEEPALIVE
          time: 3600s  # Default 2h
          interval: 50s  # Default 75s
      http:
        maxRequestsPerConnection: 1  # Disables HTTP connection keep-alive/reuse. Default unlimited
        idleTimeout: 1m  # How long a keep-alive tcp connection will stay open if unused for any http requests. Default 1h
        h2UpgradePolicy: UPGRADE  # Upgrade http1.1 connections arriving at the sidecar to h2 from sidecar -> workload. Default: use mesh-wide setting