Skip to content

Service Mesh — Istio, Linkerd, mTLS, Traffic Management, and Observability

DodaTech Updated 2026-06-22 8 min read

In this tutorial, you'll learn about Service Mesh. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

A service mesh is a dedicated infrastructure layer that manages service-to-service communication in Microservices architectures — providing traffic management, security, and Observability without modifying application code.

What You'll Learn

Why It Matters

In a Microservices architecture, service-to-service communication becomes a complex problem. Each service needs to retry failed requests, enforce encryption, track latency, split traffic for canaries, and circuit-break failing dependencies. Implementing these in every service leads to duplicated logic, language-specific libraries, and inconsistency. A service mesh moves this logic out of the application and into the infrastructure layer — transparently handling traffic at the network level.

Real-World Use

DodaTech runs Istio on Durga Antivirus Pro's backend mesh, enforcing mTLS between all services, splitting 5% of traffic to canary deployments, and collecting detailed metrics (request volume, error rates, latency percentiles) that feed into Prometheus and Grafana dashboards — all without changing a single line of application code.

flowchart TD
    subgraph "Service Mesh"
        A[Service A] --- P1[Envoy Proxy]
        B[Service B] --- P2[Envoy Proxy]
        C[Service C] --- P3[Envoy Proxy]
        P1 -->|mTLS| P2
        P1 -->|mTLS| P3
        P2 -->|mTLS| P3
    end
    subgraph "Control Plane"
        D[Pilot]
        E[Telemetry]
        F[Citadel / Certs]
    end
    P1 --> D
    P2 --> D
    P3 --> D
    style A fill:#466BB0,color:#fff
    style B fill:#466BB0,color:#fff
    style C fill:#466BB0,color:#fff
    style D fill:#ff9800,color:#fff
    style E fill:#ff9800,color:#fff
    style F fill:#ff9800,color:#fff
â„šī¸ Info

Prerequisites: Kubernetes fundamentals (Pods, Deployments, Services), Microservices architecture knowledge, and a running Kubernetes cluster.

Istio Architecture

Istio deploys an Envoy proxy as a sidecar container alongside every service pod. All traffic flows through the proxy, enabling the control plane to enforce policies.

# Install Istio on a Kubernetes cluster
istioctl install --set profile=default -y

# Expected output:
# ✔ Istio core installed
# ✔ Istiod installed
# ✔ Ingress gateways installed
# ✔ Installation complete

# Label a namespace for sidecar injection
kubectl label namespace default istio-injection=enabled

# Expected output:
# namespace/default labeled

# Deploy an application
kubectl apply -f deployment.yaml

# Verify the sidecar is injected
kubectl get pods -l app=myapp -o jsonpath='{.items[0].spec.containers[*].name}'

# Expected output:
# myapp istio-proxy  (two containers: app + sidecar)

Expected behavior: When a pod starts in a labeled namespace, Istio's mutating Webhook injects the istio-proxy sidecar container. All incoming and outgoing traffic routes through Envoy, which enforces the mesh policies.

mTLS — Mutual TLS

mTLS encrypts all service-to-service traffic and verifies both sides of the connection with certificates, implementing a zero-trust security model.

# Enable strict mTLS across the entire mesh
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system
spec:
  mtls:
    mode: STRICT
# Allow a specific namespace to use PERMISSIVE mode
# (accepts both mTLS and plaintext during migration)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: namespace-policy
  namespace: legacy
spec:
  mtls:
    mode: PERMISSIVE

Expected behavior: With STRICT mode, all traffic between services must use mTLS. Any plaintext connection is rejected. Istio's Citadel component automatically provisions and rotates TLS certificates for every service.

# Verify mTLS is working
istioctl authn tls-check deployment/myapp.default.svc.cluster.local

# Expected output:
# HOST:PORT                                     STATUS     SERVER
# myapp.default.svc.cluster.local:8080          mTLS       default/STRICT
# other-svc.default.svc.cluster.local:8080      mTLS       default/STRICT

Traffic Management

Virtual Services and Destination Rules

Istio decouples traffic routing from deployment, enabling sophisticated traffic splitting without changing application code.

# virtual-service.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp
spec:
  hosts:
    - myapp
  http:
    - match:
        - headers:
            version:
              exact: v2
      route:
        - destination:
            host: myapp
            subset: v2
    - route:
        - destination:
            host: myapp
            subset: v1
          weight: 90
        - destination:
            host: myapp
            subset: v2
          weight: 10
# destination-rule.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: myapp
spec:
  host: myapp
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        http1MaxPendingRequests: 10
        maxRequestsPerConnection: 10
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2

Expected behavior: 90% of traffic goes to v1, 10% to v2. Users with the header version: v2 are always routed to v2. The DestinationRule configures connection pools and Load Balancing for each subset.

Circuit Breaking

Circuit breaking prevents cascading failures by stopping requests to unhealthy services.

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: payments-service
spec:
  host: payments-service
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 50
      http:
        http1MaxPendingRequests: 10
        maxRequestsPerConnection: 5
    outlierDetection:
      consecutive5xxErrors: 5
      interval: 30s
      baseEjectionTime: 60s
      maxEjectionPercent: 50

Expected behavior: If the payments service returns 5 consecutive 5xx errors, it is ejected from the Load Balancing pool for 60 seconds. Up to 50% of instances can be ejected.

Observability

Service mesh sidecars automatically generate detailed telemetry for every request — including success rates, latency, and error codes.

# Enable telemetry collection
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: mesh-default
  namespace: istio-system
spec:
  accessLogging:
    - providers:
        - name: envoy
# Rate of requests per second
rate(istio_requests_total{destination_service="myapp.default.svc.cluster.local"}[1m])

# P99 latency
histogram_quantile(0.99, rate(
  istio_request_duration_milliseconds_bucket{
    destination_service="myapp.default.svc.cluster.local"
  }[1m]
))

# Error rate percentage
sum(rate(istio_requests_total{
  destination_service="myapp.default.svc.cluster.local",
  response_code=~"5.*"
}[1m])) / sum(rate(istio_requests_total{
  destination_service="myapp.default.svc.cluster.local"
}[1m])) * 100

Expected output: Kiali displays a service graph showing request flows, success rates, and latency between every service. The Prometheus queries above feed Grafana dashboards for real-time monitoring.

Linkerd

Linkerd is a lighter-weight service mesh that uses a Rust-based proxy instead of Envoy, offering lower resource consumption.

# Install Linkerd CLI
curl -sL https://run.linkerd.io/install | sh

# Install Linkerd on the cluster
linkerd install | kubectl apply -f -

# Expected output:
# Linkerd core installed.
# ...
# Status check results are √

# Inject sidecar into a namespace
kubectl get ns default -o yaml | linkerd inject - | kubectl apply -f -

# Expected output:
# namespace/default linkerd injected

Expected behavior: Linkerd injects a Rust-based linkerd-proxy sidecar using 10MB of memory versus Envoy's 50MB+. It supports mTLS, traffic splitting, and golden metrics (success rate, latency, request volume) out of the box.

# Linkerd traffic split — canary deployment
apiVersion: split.smi-spec.io/v1alpha2
kind: TrafficSplit
metadata:
  name: myapp-split
spec:
  service: myapp
  backends:
    - service: myapp-v1
      weight: 90
    - service: myapp-v2
      weight: 10

Expected behavior: 90% of traffic goes to v1, 10% to v2. Linkerd uses the SMI TrafficSplit API instead of separate VirtualService and DestinationRule resources.

Istio vs Linkerd

Feature Istio Linkerd
Proxy Envoy (C++) linkerd-proxy (Rust)
Resource usage Higher (50MB+ per sidecar) Lower (10MB per sidecar)
Feature set Rich and extensible Focused on core features
Configuration VirtualService + DestinationRule SMI TrafficSplit API
Learning curve Steeper Gentler
mTLS Automatic with Citadel Automatic

Common Errors

  1. Not planning for sidecar resource overhead: Each Envoy proxy consumes 50MB+ RAM. On a node with 50 pods, that is 2.5GB of overhead before application memory. Size nodes accordingly or use Linkerd for lower overhead.

  2. Enabling mTLS before all services support it: Switching to STRICT mTLS breaks services that do not have the sidecar injected. Use PERMISSIVE mode during Migration, then switch to STRICT.

  3. Overly permissive AuthorizationPolicies: Default allow-all policies provide no security. Define least-privilege policies that explicitly allow specific services to communicate.

  4. Ignoring Istio control plane resource requirements: Istiod, ingress/egress gateways, and telemetry components require significant CPU and memory. Monitor and size the control plane separately from the data plane.

  5. Not testing circuit breaker configurations: Misconfigured circuit breakers can cause cascading failures instead of preventing them. Test ejection thresholds and recovery intervals in staging.

  6. Running Istio without Kiali or Grafana: The Observability features of a service mesh are its primary value. Without dashboards and service graphs, you lose visibility into the traffic that is being managed.

Practice Questions

  1. What is the role of the Envoy sidecar proxy in Istio? Answer: The sidecar proxy intercepts all inbound and outbound traffic for its pod, enforcing traffic routing, security policies, and collecting telemetry — all transparent to the application.

  2. How does mTLS improve Microservices security? Answer: mTLS encrypts all service-to-service traffic and cryptographically verifies the identity of both services, preventing eavesdropping, man-in-the-middle attacks, and unauthorized access.

  3. What is the difference between a VirtualService and a DestinationRule? Answer: A VirtualService defines routing rules (which traffic goes where), while a DestinationRule defines policies for the destination (connection pools, Load Balancing, circuit breaking).

  4. When would you choose Linkerd over Istio? Answer: Choose Linkerd when resource overhead is a concern, your team prefers simpler configuration, and you only need core features (mTLS, traffic splitting, golden metrics). Choose Istio for advanced features like custom Envoy filters, rich authorization policies, and multi-cluster support.

Challenge

Deploy Istio on a Kubernetes cluster with three Microservices. Configure STRICT mTLS peer authentication. Create a VirtualService that splits 90% of traffic to v1 and 10% to v2. Add a DestinationRule with Connection Pool limits and outlier detection. Enable telemetry and view the service graph in Kiali. Then replicate the same setup using Linkerd and compare the configuration complexity and resource usage.

Mini Project

Install Istio on a local kind cluster. Deploy three sample Microservices (frontend, api, database) and enable automatic sidecar injection. Configure mTLS in STRICT mode. Create a VirtualService for canary deployments (90% v1, 10% v2). Add a DestinationRule with circuit breaking (5 consecutive errors triggers 60-second ejection). Install Kiali and Grafana to visualize traffic flows and latency. Test circuit breaking by introducing a failing endpoint in one service and observing the ejection. Finally, install Linkerd on a separate namespace and compare the setup process, configuration files, and sidecar resource consumption.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro