A practical walkthrough to install Istio, turn on automatic mTLS, and run a canary traffic split on Kubernetes.
Istio has a reputation for being heavy, and some of that is earned. But you don't need to understand every CRD to get real value out of it. This tutorial walks through the parts that actually matter on day one: getting the mesh installed, proving that mTLS is on, and shifting traffic between two versions of a service. Everything below is meant to be run, not just read.
Istio moves fast, so treat the commands here as a starting shape and verify against current Istio releases. Profile names, default versions, and Gateway API support all shift between minor versions.
If you want the bigger picture of where a mesh fits, start with our service mesh guide. If you're still deciding on a mesh, the Istio vs Linkerd comparison is worth a read before you commit.
You need three things:
kind or minikube cluster with at least 4 GB of RAM works fine for this. Managed clusters (EKS, GKE, AKS) are all fine too.kubectl configured and pointing at that cluster. Confirm with kubectl get nodes.That's it. No Helm required for the quick path, though I'll mention it.
Download istioctl and put it on your PATH:
curl -L https://istio.io/downloadIstio | sh -
cd istio-*/
export PATH=$PWD/bin:$PATH
istioctl version
Now pick a profile. Istio has two data-plane modes worth knowing about:
ztunnel handles L4 and mTLS, and you add waypoint proxies only where you need L7 features. Lower per-pod overhead, but newer.We'll use the sidecar path here because it's the most portable across versions. Install the demo profile, which turns on the ingress gateway and generous telemetry:
istioctl install --set profile=demo -y
kubectl get pods -n istio-system
You should see istiod and istio-ingressgateway running. If you'd rather manage Istio through GitOps, the Helm charts (istio/base, istiod, istio/gateway) install the same components and are the better fit for production. The Gateway API path uses the same istioctl install but swaps Gateway/HTTPRoute resources for the older ingress gateway. Either works.
Injection is opt-in per namespace. Label a namespace and Istio's mutating webhook adds the proxy to every new pod:
kubectl create namespace demo
kubectl label namespace demo istio-injection=enabled
Now deploy the Bookinfo sample that ships with the release. It's a small app with a productpage frontend and three versions of a reviews service, which makes it perfect for a traffic-split demo:
kubectl apply -n demo -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl get pods -n demo
Watch the READY column. Each pod should show 2/2 once it settles: one container for your app, one for the injected Envoy proxy. If you see 1/1, injection didn't happen, and we'll cover why below.
Here's the part people don't believe until they see it. Istio turns on mTLS between proxies automatically, in permissive mode by default, so plaintext still works during migration. To require it, apply a PeerAuthentication in STRICT mode:
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
namespace: demo
spec:
mtls:
mode: STRICT
kubectl apply -f peer-auth.yaml
Now every connection between meshed pods in demo is mutually authenticated and encrypted, and plaintext connections are rejected. You can confirm what a workload negotiated with:
istioctl x describe pod -n demo <productpage-pod-name>
Look for a line reporting that mTLS is enabled. This is the single highest-value thing Istio gives you for the least effort.
Bookinfo ships three versions of reviews. Without any rules, Kubernetes load-balances across all of them randomly. Let's take control and send 90% of traffic to v1 and 10% to v2.
First a DestinationRule to name the subsets, then a VirtualService to weight them:
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews
namespace: demo
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews
namespace: demo
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 90
- destination:
host: reviews
subset: v2
weight: 10
Apply it, then refresh the product page a few dozen times. Roughly one in ten requests should hit v2. To promote the canary, bump v2 to weight: 100 and re-apply. No redeploys, no pod restarts.
If you're on the Gateway API path, the same split is expressed as an HTTPRoute with backendRefs carrying weight fields pointing at two Services. The mechanics are identical; only the resource shape differs.
The demo profile makes wiring up dashboards trivial. Install the sample addons and open Kiali:
kubectl apply -f samples/addons/
istioctl dashboard kiali
Kiali gives you a live service-graph with request rates, error rates, and a lock icon on edges where mTLS is active. Prometheus scrapes the metrics, and Grafana has prebuilt Istio dashboards (istioctl dashboard grafana) for latency percentiles and throughput per workload. For a first look, drive some traffic to productpage and watch the graph in Kiali light up.
kubectl rollout restart deployment -n demo.PERMISSIVE mode first, confirm all clients are meshed, then flip to STRICT.Tear down in reverse order so you don't strand resources:
kubectl delete -f samples/addons/ --ignore-not-found
kubectl delete namespace demo
istioctl uninstall --purge -y
kubectl delete namespace istio-system
The --purge flag removes the CRDs too, so only use it when you truly want Istio gone.
Once the basics click, the natural next moves are: fault injection and request timeouts (both live in VirtualService), authorization policies to lock down which services can call which, and multi-cluster mesh if you're spanning regions. If per-pod overhead bothered you, spend an afternoon with ambient mode on a throwaway cluster.
For a first install, use the sidecar demo profile, prove mTLS with a STRICT PeerAuthentication, and run one canary split. That combination shows you the two things Istio is genuinely good at, security you didn't have to code and traffic control you didn't have to redeploy for, without drowning you in CRDs. Reach for ambient and the Gateway API path once the fundamentals feel routine, and keep validating every command against the release you actually run.
Get the latest tutorials, guides, and insights on AI, DevOps, Cloud, and Infrastructure delivered directly to your inbox.
Explore more articles in this category
A service mesh solves real problems and creates new ones. This is the map: what it actually does, when it earns its cost, and how the options compare.
Your pipeline holds the keys to production and signs off on everything you ship, so harden both the pipeline itself and the artifacts it builds.
A practical, layer-by-layer checklist for securing Kubernetes clusters, workloads, networking, secrets, and the software supply chain.
Evergreen posts worth revisiting.