Implement Istio observability with Jaeger tracing and Kiali dashboard for Kubernetes service mesh

Advanced 45 min May 21, 2026 48 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Configure comprehensive observability for your Kubernetes service mesh with Jaeger distributed tracing, Kiali visualization, and Prometheus metrics integration. Get complete visibility into microservice communication patterns, performance bottlenecks, and service dependencies.

Prerequisites

  • Kubernetes cluster with 8GB+ RAM
  • kubectl with admin access
  • Helm 3 installed
  • Basic Kubernetes knowledge

What this solves

Kubernetes service mesh deployments create complex communication patterns between microservices that are difficult to monitor and debug without proper observability tools. This tutorial implements a complete observability stack with Istio service mesh, Jaeger for distributed tracing, Kiali for service mesh visualization, and integrated Prometheus metrics collection.

You'll get real-time visibility into service-to-service communication, performance bottlenecks, error rates, and dependency graphs across your entire mesh topology.

Prerequisites

  • Running Kubernetes cluster with at least 8GB RAM and 4 CPU cores
  • kubectl configured with cluster admin access
  • Helm 3 installed on your system
  • Basic understanding of Kubernetes concepts and YAML manifests

Step-by-step installation

Install Istio with observability components

Download and install Istio with the demo profile that includes all observability add-ons by default.

curl -L https://istio.io/downloadIstio | sh -
cd istio-*
export PATH=$PWD/bin:$PATH
istioctl install --set values.defaultRevision=default --set values.pilot.traceSampling=100.0 -y

Enable automatic sidecar injection

Configure the default namespace to automatically inject Istio sidecar proxies into new pods.

kubectl label namespace default istio-injection=enabled
kubectl get namespace default --show-labels

Install observability add-ons

Deploy Jaeger, Kiali, Prometheus, and Grafana components using Istio's sample configurations.

kubectl apply -f samples/addons/jaeger.yaml
kubectl apply -f samples/addons/kiali.yaml
kubectl apply -f samples/addons/prometheus.yaml
kubectl apply -f samples/addons/grafana.yaml

Configure Jaeger with Elasticsearch backend

Replace the default in-memory Jaeger storage with Elasticsearch for production-grade persistence and scalability.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jaeger
  namespace: istio-system
  labels:
    app: jaeger
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jaeger
  template:
    metadata:
      labels:
        app: jaeger
    spec:
      containers:
      - name: jaeger
        image: jaegertracing/all-in-one:1.51
        env:
        - name: SPAN_STORAGE_TYPE
          value: "elasticsearch"
        - name: ES_SERVER_URLS
          value: "http://elasticsearch.istio-system.svc.cluster.local:9200"
        - name: ES_NUM_SHARDS
          value: "1"
        - name: ES_NUM_REPLICAS
          value: "0"
        ports:
        - containerPort: 16686
          protocol: TCP
        - containerPort: 14250
          protocol: TCP
        - containerPort: 14268
          protocol: TCP

Deploy Elasticsearch for Jaeger storage

Create a dedicated Elasticsearch instance for storing trace data with appropriate resource limits.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: elasticsearch
  namespace: istio-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      containers:
      - name: elasticsearch
        image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
        env:
        - name: discovery.type
          value: single-node
        - name: ES_JAVA_OPTS
          value: "-Xms512m -Xmx512m"
        - name: xpack.security.enabled
          value: "false"
        ports:
        - containerPort: 9200
        resources:
          requests:
            memory: "1Gi"
            cpu: "500m"
          limits:
            memory: "2Gi"
            cpu: "1"
---
apiVersion: v1
kind: Service
metadata:
  name: elasticsearch
  namespace: istio-system
spec:
  selector:
    app: elasticsearch
  ports:
  - port: 9200
    targetPort: 9200
kubectl apply -f elasticsearch.yaml

Configure Istio telemetry settings

Enable comprehensive telemetry collection including access logs and custom metrics for better observability.

apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: default
  namespace: istio-system
spec:
  metrics:
  - providers:
    - name: prometheus
  - overrides:
    - match:
        metric: ALL_METRICS
      tagOverrides:
        destination_service_name:
          operation: UPSERT
          value: "destination_service_name | 'unknown'"
  accessLogging:
  - providers:
    - name: otel
  tracing:
  - providers:
    - name: jaeger
kubectl apply -f telemetry-config.yaml

Configure Kiali with authentication

Set up Kiali dashboard with proper authentication and configure access to the service mesh topology.

apiVersion: v1
kind: ConfigMap
metadata:
  name: kiali
  namespace: istio-system
data:
  config.yaml: |
    auth:
      strategy: anonymous
    deployment:
      accessible_namespaces:
      - "**"
      ingress_enabled: false
    external_services:
      prometheus:
        url: "http://prometheus.istio-system:9090"
      grafana:
        url: "http://grafana.istio-system:3000"
      tracing:
        enabled: true
        in_cluster_url: "http://jaeger.istio-system:16686/jaeger"
        url: "http://jaeger.istio-system:16686/jaeger"
        use_grpc: false
    server:
      web_root: "/kiali"
kubectl apply -f kiali-config.yaml
kubectl rollout restart deployment/kiali -n istio-system

Deploy sample application for testing

Install the Bookinfo sample application to generate traffic and test the observability stack.

kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml

Configure Prometheus service discovery

Ensure Prometheus can discover and scrape metrics from all Istio components and application pods.

apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus
  namespace: istio-system
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
      evaluation_interval: 15s
    rule_files:
    - "/etc/config/recording_rules.yml"
    - "/etc/config/alerting_rules.yml"
    scrape_configs:
    - job_name: 'istioproxy'
      kubernetes_sd_configs:
      - role: endpoints
        namespaces:
          names:
          - istio-system
          - default
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
        action: keep
        regex: istio-proxy;http-monitoring
    - job_name: 'istio-mesh'
      kubernetes_sd_configs:
      - role: endpoints
        namespaces:
          names:
          - istio-system
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
        action: keep
        regex: istio-telemetry;prometheus
    - job_name: 'pilot'
      kubernetes_sd_configs:
      - role: endpoints
        namespaces:
          names:
          - istio-system
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
        action: keep
        regex: istiod;http-monitoring
kubectl apply -f prometheus-config.yaml

Set up port forwarding for dashboard access

Create secure tunnels to access the observability dashboards from your local machine.

# Kiali dashboard
kubectl port-forward svc/kiali 20001:20001 -n istio-system &

Jaeger UI

kubectl port-forward svc/jaeger 16686:16686 -n istio-system &

Grafana dashboard

kubectl port-forward svc/grafana 3000:3000 -n istio-system &

Prometheus UI

kubectl port-forward svc/prometheus 9090:9090 -n istio-system &

Generate traffic for observability testing

Create consistent traffic to the sample application to populate the observability dashboards with meaningful data.

# Get the ingress gateway external IP
export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT

Generate traffic

for i in $(seq 1 100); do curl -s "http://$GATEWAY_URL/productpage" > /dev/null echo "Request $i completed" sleep 1 done

Configure advanced observability features

Set up custom Grafana dashboards

Import Istio-specific Grafana dashboards for comprehensive service mesh monitoring. You can build on the foundation established in our advanced Grafana dashboards tutorial.

apiVersion: v1
kind: ConfigMap
metadata:
  name: istio-dashboards
  namespace: istio-system
data:
  istio-mesh.json: |
    {
      "dashboard": {
        "id": null,
        "title": "Istio Mesh Dashboard",
        "tags": ["istio"],
        "panels": [
          {
            "title": "Global Request Volume",
            "type": "graph",
            "targets": [
              {
                "expr": "sum(rate(istio_requests_total[5m]))",
                "legendFormat": "Global Request Rate"
              }
            ]
          },
          {
            "title": "Global Success Rate",
            "type": "singlestat",
            "targets": [
              {
                "expr": "sum(rate(istio_requests_total{response_code!~\"5.*\"}[5m])) / sum(rate(istio_requests_total[5m]))",
                "legendFormat": "Success Rate"
              }
            ]
          }
        ]
      }
    }
kubectl apply -f grafana-dashboards.yaml

Configure alerting rules

Set up Prometheus alerting rules for service mesh health monitoring and automated incident response.

apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-alerting-rules
  namespace: istio-system
data:
  alerting_rules.yml: |
    groups:
    - name: istio.rules
      rules:
      - alert: IstioHighRequestLatency
        expr: histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket[5m])) by (destination_service_name, le)) > 1000
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "High request latency on {{ $labels.destination_service_name }}"
          description: "99th percentile latency is {{ $value }}ms for service {{ $labels.destination_service_name }}"
      - alert: IstioHighErrorRate
        expr: sum(rate(istio_requests_total{response_code=~"5.*"}[5m])) / sum(rate(istio_requests_total[5m])) > 0.1
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "High error rate detected"
          description: "Error rate is {{ $value | humanizePercentage }} for the last 5 minutes"
      - alert: IstioServiceDown
        expr: up{job="istio-mesh"} == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Istio service is down"
          description: "Istio service {{ $labels.instance }} has been down for more than 5 minutes"
kubectl apply -f alerting-rules.yaml

Verify your setup

Check that all observability components are running and accessible.

# Verify all pods are running
kubectl get pods -n istio-system

Check Istio sidecar injection

kubectl get pods -l app=productpage -o jsonpath='{.items[0].spec.containers[*].name}'

Test Kiali access

curl -s http://localhost:20001/kiali/api/status | jq '.status'

Test Jaeger access

curl -s http://localhost:16686/api/services | jq '.data[]'

Check Prometheus targets

curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | select(.health == "up") | .labels.job' | sort -u
Dashboard URLs: Once port forwarding is active, access Kiali at http://localhost:20001/kiali, Jaeger at http://localhost:16686, Grafana at http://localhost:3000, and Prometheus at http://localhost:9090.

Configure production security

Enable mTLS for observability components

Secure communication between observability components with mutual TLS authentication.

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: observability-mtls
  namespace: istio-system
spec:
  mtls:
    mode: STRICT
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: observability-access
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: kiali
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/istio-system/sa/kiali-service-account"]
  - to:
    - operation:
        methods: ["GET", "POST"]
kubectl apply -f mtls-policy.yaml

Configure network policies

Implement network-level security policies to restrict traffic between observability components. This builds on concepts from our Kubernetes network policies tutorial.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: observability-network-policy
  namespace: istio-system
spec:
  podSelector:
    matchLabels:
      app: kiali
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: istio-system
    ports:
    - protocol: TCP
      port: 20001
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: istio-system
    ports:
    - protocol: TCP
      port: 9090  # Prometheus
    - protocol: TCP
      port: 16686 # Jaeger
kubectl apply -f network-policy.yaml

Common issues

SymptomCauseFix
No traces in JaegerSidecar injection not enabledkubectl label namespace default istio-injection=enabled
Kiali shows no dataPrometheus not scraping metricsCheck Prometheus targets at localhost:9090/targets
High memory usageDefault trace sampling at 100%Reduce sampling rate: istioctl install --set values.pilot.traceSampling=1.0
Elasticsearch connection failedService not running or misconfiguredkubectl logs deployment/elasticsearch -n istio-system
Port forward connection refusedService not readykubectl get pods -n istio-system and wait for Running status
Missing service topologyInsufficient traffic generationGenerate more requests to populate service graph

Next steps

Running this in production?

Want this handled for you? Running this at scale adds a second layer of work: capacity planning, failover drills, cost control, and on-call. See how we run infrastructure like this for European teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed devops services for businesses that depend on uptime. From initial setup to ongoing operations.