Skip to content

Istio Service Mesh

First PublishedLast UpdatedByAtif Alam

Istio is a service mesh: a data plane of Envoy sidecar proxies (or ambient mode in newer versions) and a control plane (istiod) that programs routing, security, and telemetry. It fits Kubernetes best; for canary routing examples in CI/CD context, see Deployment strategies.

For a broader non-mesh view of sidecars (when to use them, sidecar vs library trade-offs, and custom sidecar rollout patterns), see Sidecar Pattern.

Linkerd is a lighter alternative (fewer features, smaller footprint). Rule of thumb: choose Linkerd when you want simplicity and fast onboarding; choose Istio when you need rich traffic management, Wasm extensions, and multi-cluster patterns — at the cost of operational complexity. Sidecars add CPU and memory per Pod compared to plain workloads.

This page focuses on sidecar-based Istio. For ambient (sidecarless) deployment, see the upstream Istio docs.

You need a running Kubernetes cluster and kubectl configured to use it. If Kubernetes objects are new, read Kubernetes Overview and Core Objects. On AWS, EKS is a common control plane.

Why use a mesh? Without Istio, each service often reimplements TLS policy, retries, timeouts, and telemetry in application code or libraries. Istio centralizes those cross-cutting behaviors in the data plane (Envoy) using declarative CRDs pushed by istiod.

  • Control planeistiod computes desired config and distributes it to proxies.
  • Data plane — Envoy sidecars (and the ingress gateway) enforce that config on traffic.
  • North-south — Traffic entering or leaving the cluster (often via an ingress gateway).
  • East-west — Service-to-service traffic inside the mesh (between Pods with sidecars).
  • Sidecar — Envoy container injected next to your app; see Sidecar Pattern.
  • Kubernetes Service — Stable cluster IP / DNS for a set of Pods (kube-proxy or dataplane routing).
  • Istio VirtualService — Layer 7 routing rules (host, path, weights, timeouts) for the mesh.
  • Kubernetes Ingress — Built-in ingress API; different from Istio Gateway, which defines listeners for the mesh ingress gateway workload.
AreaWhat you get
ConfigurationDeclarative CRDs; istiod pushes config to Envoy proxies.
Identity & TLSWorkload identities and in-mesh mTLS; not a full PKI guide — see TLS and Certificates for general certificate lifecycle.
Traffic managementRouting, splits, timeouts, retries, circuit breaking via VirtualService and DestinationRule.
Security policyPeerAuthentication / RequestAuthentication; AuthorizationPolicy for fine-grained allow/deny (see upstream Istio security docs).
ObservabilityMetrics, traces, and access logs via proxies (integrate with your stack).
ExtensibilityWasm plugins and extension points in Envoy (version-specific; see upstream).
PieceRole
istiodPushes config to proxies; includes traffic (Pilot), certificate issuance, and validation.
Envoy sidecarIntercepts inbound/outbound pod traffic; implements mTLS, retries, timeouts, telemetry.
Ingress GatewayDedicated Envoy at the mesh edge (north-south); separate from in-mesh east-west.

Pods must inject the sidecar (namespace label istio-injection=enabled or revision-based labels, depending on version).

Commands and flags can change between Istio releases — always confirm against Istio install documentation.

Install the istioctl CLI for your platform (see upstream download instructions), then verify:

Terminal window
istioctl version

Example using a demo profile (more components than minimal; good for learning):

Terminal window
istioctl install --set profile=demo -y

For production, teams often use minimal or production profiles and tune components; see upstream guidance for your version.

Terminal window
kubectl get pods -n istio-system
istioctl verify-install

After install you should see namespaces and workloads such as istiod and the ingress gateway under istio-system. Injected application Pods gain an istio-proxy container alongside your app.

Label a namespace so new Pods get sidecars (restart existing workloads to pick up injection):

Terminal window
kubectl label namespace default istio-injection=enabled --overwrite

For revision-based installs (multiple control planes), use the label form your install docs specify (for example istio.io/rev=<revision>) instead of istio-injection=enabled.

To remove Istio from the cluster (exact subcommands vary by version):

Terminal window
istioctl uninstall --purge -y

Confirm flags in the upstream uninstall section for your release.

Production teams sometimes install Helm charts instead of istioctl. See Helm and the upstream Istio Helm install guide.

External clients typically reach the mesh through a cloud load balancer or NodePort that fronts the Istio ingress gateway Service. The gateway Envoy terminates TLS (or passes TCP), then VirtualService rules route to Kubernetes Service names and finally to Pods whose traffic is handled by Envoy sidecars.

East-west traffic stays inside the cluster: Pod A’s sidecar talks to Pod B’s sidecar over mTLS, without going through the ingress gateway.

flowchart LR
Client[Client] --> EdgeLB[EdgeLB_or_NodePort]
EdgeLB --> IngGw[IstioIngressGateway]
IngGw --> VS[VirtualService_rules]
VS --> K8sSvc[Kubernetes_Service]
K8sSvc --> PodSidecar[Pod_with_Envoy_sidecar]

The Istio Ingress Gateway is a deployment of Envoy (commonly in istio-system) exposed by a Kubernetes Service (ClusterIP, NodePort, or LoadBalancer). It is not the same resource as a Kubernetes Ingress object, though you can combine them (for example terminate TLS at a cloud LB or Ingress Controller in front of the gateway).

Typical pattern:

  1. Gateway — Defines listener ports, hosts, and TLS on the ingress gateway workload (via selector).
  2. VirtualService — Lists spec.gateways pointing at that Gateway and routes HTTP/TCP to internal Kubernetes Service names.

Discover the external IP or hostname:

Terminal window
kubectl get svc -n istio-system

On AWS, the ingress gateway Service is often LoadBalancer; see Elastic Load Balancing for ALB/NLB context.

  1. Install Istio and verify istio-system Pods (see Install).
  2. Label an app namespace for injection and deploy a sample app. The upstream Bookinfo quickstart is a common choice — follow Istio getting started for current manifests and commands.
  3. Confirm sidecars: kubectl get pods -n <ns> -o wide and check for the istio-proxy container.
  4. Apply Gateway and VirtualService for the sample and open the app through the ingress gateway address.

Canary-style routing with Istio is illustrated in Deployment strategies — Kubernetes with Istio.

Defines routing rules (match host/path/header, weights for subsets, timeouts, retries).

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews-route
namespace: default
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 80
- destination:
host: reviews
subset: v2
weight: 20

Defines subsets (e.g. v1 / v2 labels), load balancing, TLS to upstream, connection pools, outlier detection.

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: reviews-dest
namespace: default
spec:
host: reviews
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2

Binds ports and hosts on the ingress gateway workload; VirtualService references this gateway for north-south routes.

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: bookinfo-gateway
namespace: default
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"

Controls mesh mTLS mode STRICT vs PERMISSIVE for selected workloads or namespaces.

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT

Declares JWT validation (issuer, JWKS); AuthorizationPolicy is often paired for allow/deny rules.

apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: jwt-auth
namespace: default
spec:
selector:
matchLabels:
app: myapp
jwtRules:
- issuer: "https://example.auth0.com/"
jwksUri: "https://example.auth0.com/.well-known/jwks.json"
ModeMeaning
PERMISSIVEAccept plain or mTLS (common during migration).
STRICTSidecar only accepts mTLS — misconfigured clients show connection errors.
Terminal window
istioctl analyze # static config issues across cluster
istioctl proxy-status # sync between istiod and proxies
istioctl proxy-config cluster <pod> # Envoy clusters for a pod
istioctl proxy-config listener <pod>
istioctl authn tls-check <pod> <pod>

Combine with kubectl logs for istio-proxy sidecar and istiod.

SymptomChecks
503 UH / no healthy upstreamDestinationRule subset labels match Endpoints; service selector correct; port names match protocol hints (http, grpc).
Sidecar missingInjection label on namespace; pod restarted after policy; revision tags (canary control plane).
Config not appliedistioctl proxy-status; validation errors on resources; wrong namespace.
mTLS failures after STRICTClients without sidecar or PeerAuthentication mismatch; check istioctl authn tls-check.
Double TLSApp does HTTPS and sidecar also does TLS — use PASSTHROUGH or terminate at sidecar consistently.

Kubernetes Gateway API (Gateway, HTTPRoute) is an alternative to classic Ingress. Istio supports Gateway API in supported versions; many clusters still use Ingress + Ingress Gateway. See Kubernetes networking for Ingress basics.