Learn to deploy Istio service mesh on Kubernetes with mTLS security, traffic management, and comprehensive observability using Kiali and Jaeger for production microservices.
Prerequisites
- Kubernetes cluster with kubectl access
- At least 4GB RAM and 2 CPUs available
- Administrative privileges on the cluster
- Internet connectivity for downloading Istio components
What this solves
Istio service mesh provides traffic management, security, and observability for microservices without changing application code. It uses Envoy sidecars to handle service-to-service communication, automatic mTLS encryption, and distributed tracing. This tutorial shows you how to install Istio on an existing Kubernetes cluster and configure it for production use with security policies and monitoring tools.
Prerequisites
You need a running Kubernetes cluster with at least 4GB RAM and 2 CPUs available. The cluster should have kubectl configured and administrative access. We'll assume you already have a properly configured Kubernetes cluster running.
Step-by-step installation
Download and install Istio CLI
Start by downloading the latest Istio release and installing the istioctl command-line tool.
curl -L https://istio.io/downloadIstio | sh -
cd istio-*
sudo cp bin/istioctl /usr/local/bin/
istioctl version
Install Istio control plane
Install Istio with the demo profile which includes all core components plus observability tools.
istioctl install --set values.defaultRevision=default -y
kubectl get pods -n istio-system
Enable automatic sidecar injection
Label namespaces to automatically inject Envoy sidecars into new pods deployed in those namespaces.
kubectl label namespace default istio-injection=enabled
kubectl get namespace -L istio-injection
Install observability addons
Deploy Kiali, Jaeger, and Prometheus for service mesh observability and monitoring.
kubectl apply -f samples/addons/kiali.yaml
kubectl apply -f samples/addons/jaeger.yaml
kubectl apply -f samples/addons/prometheus.yaml
kubectl apply -f samples/addons/grafana.yaml
Wait for addon deployment
Verify that all observability components are running before proceeding.
kubectl rollout status deployment/kiali -n istio-system
kubectl rollout status deployment/jaeger -n istio-system
kubectl get pods -n istio-system
Deploy sample application
Deploy Bookinfo sample application
Install the Bookinfo application to demonstrate Istio features and test the service mesh functionality.
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl get services
kubectl get pods
Create Istio Gateway
Configure an Istio Gateway to expose the application to external traffic through the ingress gateway.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "*"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
Apply gateway configuration
Deploy the gateway and virtual service to make the application accessible.
kubectl apply -f /tmp/bookinfo-gateway.yaml
kubectl get gateway
kubectl get virtualservice
Configure traffic management
Create destination rules
Define destination rules to specify traffic policies and service subsets for load balancing.
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: productpage
spec:
host: productpage
trafficPolicy:
loadBalancer:
simple: LEAST_CONN
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
Apply destination rules
Deploy the destination rules to configure traffic distribution and load balancing policies.
kubectl apply -f /tmp/destination-rules.yaml
kubectl get destinationrules
Configure traffic splitting
Create a virtual service to split traffic between different versions of the reviews service.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
weight: 50
- destination:
host: reviews
subset: v3
weight: 50
Apply traffic splitting
Deploy the virtual service to implement canary deployment and traffic routing rules.
kubectl apply -f /tmp/traffic-split.yaml
kubectl get virtualservices
Implement security policies
Enable strict mTLS
Configure a PeerAuthentication policy to enforce mutual TLS for all services in the default namespace.
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: default
spec:
mtls:
mode: STRICT
Apply mTLS policy
Deploy the peer authentication policy to enable automatic mutual TLS encryption between services.
kubectl apply -f /tmp/mtls-policy.yaml
kubectl get peerauthentication
Create authorization policy
Define authorization rules to control which services can communicate with each other.
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: productpage-viewer
namespace: default
spec:
selector:
matchLabels:
app: productpage
rules:
- from:
- source:
principals: ["cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"]
- to:
- operation:
methods: ["GET"]
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: reviews-viewer
namespace: default
spec:
selector:
matchLabels:
app: reviews
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/bookinfo-productpage"]
- to:
- operation:
methods: ["GET"]
Apply authorization policies
Deploy the authorization policies to implement zero-trust security between microservices.
kubectl apply -f /tmp/authz-policy.yaml
kubectl get authorizationpolicies
Set up observability
Access Kiali dashboard
Set up port forwarding to access the Kiali service mesh dashboard for traffic visualization.
kubectl port-forward svc/kiali -n istio-system 20001:20001 --address=0.0.0.0 &
echo "Kiali available at http://localhost:20001"
Access Jaeger tracing
Set up port forwarding to access Jaeger for distributed tracing and request flow analysis.
kubectl port-forward svc/jaeger -n istio-system 16686:16686 --address=0.0.0.0 &
echo "Jaeger available at http://localhost:16686"
Generate sample traffic
Create traffic to populate the observability dashboards with meaningful data.
export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
for i in $(seq 1 100); do
curl -s "http://${GATEWAY_URL}/productpage" > /dev/null
sleep 0.1
done
Configure production settings
Set resource limits
Configure resource requests and limits for Istio components to ensure stable operation.
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: production-config
spec:
values:
pilot:
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
global:
proxy:
resources:
requests:
cpu: 10m
memory: 64Mi
limits:
cpu: 100m
memory: 128Mi
components:
ingressGateways:
- name: istio-ingressgateway
k8s:
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 2000m
memory: 1024Mi
Apply production configuration
Update the Istio installation with production-ready resource configurations.
istioctl install -f /tmp/istio-production.yaml -y
kubectl get pods -n istio-system
Enable telemetry v2
Configure enhanced telemetry collection for better observability and monitoring metrics.
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:
value: "%{destination_service_name | 'unknown'}"
source_app:
value: "%{source_app | 'unknown'}"
accessLogging:
- providers:
- name: otel
Apply telemetry configuration
Deploy the telemetry configuration to enhance metrics collection and logging.
kubectl apply -f /tmp/telemetry-config.yaml
kubectl get telemetry -n istio-system
Verify your setup
istioctl proxy-status
kubectl get pods -n istio-system
istioctl analyze
kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o ".* "
istioctl proxy-config cluster $(kubectl get pod -l app=productpage -o jsonpath='{.items[0].metadata.name}') --fqdn productpage.default.svc.cluster.local
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Sidecar not injected | Namespace not labeled | kubectl label namespace default istio-injection=enabled |
| Service unreachable | Missing virtual service | Create VirtualService for the service |
| mTLS connection failure | Mixed TLS modes | Ensure consistent PeerAuthentication policies |
| High memory usage | Default proxy resources | Set appropriate resource limits in IstioOperator |
| Gateway not working | Port mismatch | Verify Gateway port matches service port |
| Kiali shows no data | No traffic generated | Generate traffic with curl or load testing tools |
| Authorization denied | Strict authorization policy | Check AuthorizationPolicy rules and service accounts |
Next steps
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Configuration
ISTIO_VERSION="${ISTIO_VERSION:-}"
NAMESPACE="${NAMESPACE:-default}"
CLEANUP_ON_EXIT=false
# Functions
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
show_usage() {
cat << EOF
Usage: $0 [OPTIONS]
Install and configure Istio service mesh for Kubernetes
OPTIONS:
-n, --namespace NAMESPACE Target namespace for sample app (default: default)
-v, --version VERSION Specific Istio version to install (default: latest)
-c, --cleanup-on-error Enable cleanup on installation failure
-h, --help Show this help message
EXAMPLES:
$0 # Install with defaults
$0 -n production -v 1.20.0 # Install specific version in production namespace
$0 --cleanup-on-error # Enable automatic cleanup on failure
EOF
}
cleanup_on_error() {
if [ "$CLEANUP_ON_EXIT" = true ]; then
log_warn "Installation failed, cleaning up..."
kubectl delete namespace istio-system --ignore-not-found=true 2>/dev/null || true
rm -rf istio-* /tmp/istio-configs 2>/dev/null || true
fi
}
check_prerequisites() {
log_info "Checking prerequisites..."
if [[ $EUID -eq 0 ]]; then
log_error "Do not run this script as root. Run as user with sudo privileges."
exit 1
fi
if ! command -v kubectl &> /dev/null; then
log_error "kubectl is required but not installed"
exit 1
fi
if ! kubectl cluster-info &> /dev/null; then
log_error "Cannot connect to Kubernetes cluster. Check kubectl configuration."
exit 1
fi
# Check cluster resources
local nodes_ready=$(kubectl get nodes --no-headers | grep -c Ready || true)
if [ "$nodes_ready" -eq 0 ]; then
log_error "No ready nodes found in cluster"
exit 1
fi
log_success "Prerequisites check passed"
}
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf check-update || true"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum check-update || true"
;;
*)
log_error "Unsupported distro: $ID"
exit 1
;;
esac
else
log_error "Cannot detect OS distribution"
exit 1
fi
log_info "Detected distro: $ID using $PKG_MGR"
}
install_dependencies() {
log_info "Installing required packages..."
sudo $PKG_UPDATE
sudo $PKG_INSTALL curl wget jq
log_success "Dependencies installed"
}
install_istio() {
echo "[1/8] Downloading and installing Istio CLI..."
cd /tmp
if [ -n "$ISTIO_VERSION" ]; then
curl -L "https://github.com/istio/istio/releases/download/${ISTIO_VERSION}/istio-${ISTIO_VERSION}-linux-amd64.tar.gz" -o istio.tar.gz
tar -xzf istio.tar.gz
cd istio-${ISTIO_VERSION}
else
curl -L https://istio.io/downloadIstio | sh -
cd istio-*
fi
sudo cp bin/istioctl /usr/local/bin/
sudo chmod 755 /usr/local/bin/istioctl
istioctl version --remote=false
log_success "Istio CLI installed"
}
install_control_plane() {
echo "[2/8] Installing Istio control plane..."
istioctl install --set values.defaultRevision=default -y
# Wait for control plane to be ready
kubectl wait --for=condition=ready pod -l app=istiod -n istio-system --timeout=300s
log_success "Istio control plane installed"
}
enable_sidecar_injection() {
echo "[3/8] Enabling automatic sidecar injection..."
kubectl label namespace "$NAMESPACE" istio-injection=enabled --overwrite
kubectl get namespace "$NAMESPACE" -o jsonpath='{.metadata.labels.istio-injection}'
echo
log_success "Sidecar injection enabled for namespace: $NAMESPACE"
}
install_observability() {
echo "[4/8] Installing observability addons..."
# Apply observability addons
kubectl apply -f samples/addons/prometheus.yaml
kubectl apply -f samples/addons/grafana.yaml
kubectl apply -f samples/addons/jaeger.yaml
kubectl apply -f samples/addons/kiali.yaml
echo "[5/8] Waiting for observability components to be ready..."
# Wait for deployments to be available
kubectl rollout status deployment/prometheus -n istio-system --timeout=300s
kubectl rollout status deployment/grafana -n istio-system --timeout=300s
kubectl rollout status deployment/jaeger -n istio-system --timeout=300s
kubectl rollout status deployment/kiali -n istio-system --timeout=300s
log_success "Observability addons installed and ready"
}
deploy_sample_app() {
echo "[6/8] Deploying Bookinfo sample application..."
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -n "$NAMESPACE"
# Wait for all services to be ready
kubectl wait --for=condition=ready pod -l app=productpage -n "$NAMESPACE" --timeout=300s
kubectl wait --for=condition=ready pod -l app=details -n "$NAMESPACE" --timeout=300s
kubectl wait --for=condition=ready pod -l app=reviews -n "$NAMESPACE" --timeout=300s
kubectl wait --for=condition=ready pod -l app=ratings -n "$NAMESPACE" --timeout=300s
log_success "Sample application deployed"
}
configure_gateway() {
echo "[7/8] Configuring Istio Gateway and VirtualService..."
mkdir -p /tmp/istio-configs
cat > /tmp/istio-configs/bookinfo-gateway.yaml << 'EOF'
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "*"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
EOF
chmod 644 /tmp/istio-configs/bookinfo-gateway.yaml
kubectl apply -f /tmp/istio-configs/bookinfo-gateway.yaml -n "$NAMESPACE"
# Create destination rules
cat > /tmp/istio-configs/destination-rules.yaml << 'EOF'
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: productpage
spec:
host: productpage
trafficPolicy:
loadBalancer:
simple: LEAST_CONN
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
EOF
chmod 644 /tmp/istio-configs/destination-rules.yaml
kubectl apply -f /tmp/istio-configs/destination-rules.yaml -n "$NAMESPACE"
log_success "Gateway and traffic rules configured"
}
verify_installation() {
echo "[8/8] Verifying installation..."
# Check Istio system pods
local failed_pods=$(kubectl get pods -n istio-system --no-headers | grep -v Running | grep -v Completed | wc -l)
if [ "$failed_pods" -gt 0 ]; then
log_error "Some Istio system pods are not running properly"
kubectl get pods -n istio-system
exit 1
fi
# Check sample app pods
local app_failed_pods=$(kubectl get pods -n "$NAMESPACE" --no-headers | grep -v Running | grep -v Completed | wc -l)
if [ "$app_failed_pods" -gt 0 ]; then
log_error "Some application pods are not running properly"
kubectl get pods -n "$NAMESPACE"
exit 1
fi
# Get ingress gateway external IP/port
local ingress_port=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
local ingress_host=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="ExternalIP")].address}')
if [ -z "$ingress_host" ]; then
ingress_host=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
fi
log_success "Istio service mesh installation completed successfully!"
echo
log_info "Access points:"
echo " Bookinfo app: http://${ingress_host}:${ingress_port}/productpage"
echo " Kiali dashboard: kubectl port-forward svc/kiali 20001:20001 -n istio-system"
echo " Jaeger UI: kubectl port-forward svc/jaeger 16686:16686 -n istio-system"
echo " Grafana: kubectl port-forward svc/grafana 3000:3000 -n istio-system"
echo
log_info "Cleanup temporary files..."
rm -rf /tmp/istio-configs istio.tar.gz 2>/dev/null || true
}
# Main execution
main() {
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-n|--namespace)
NAMESPACE="$2"
shift 2
;;
-v|--version)
ISTIO_VERSION="$2"
shift 2
;;
-c|--cleanup-on-error)
CLEANUP_ON_EXIT=true
shift
;;
-h|--help)
show_usage
exit 0
;;
*)
log_error "Unknown option: $1"
show_usage
exit 1
;;
esac
done
# Set trap for cleanup on error
trap cleanup_on_error ERR
log_info "Starting Istio service mesh installation..."
check_prerequisites
detect_distro
install_dependencies
install_istio
install_control_plane
enable_sidecar_injection
install_observability
deploy_sample_app
configure_gateway
verify_installation
}
main "$@"
Review the script before running. Execute with: bash install.sh