Service Mesh Concepts
A service mesh is a dedicated infrastructure layer that manages service-to-service communication within a microservices architecture. Istio is the most widely adopted service mesh for Kubernetes, providing traffic management, observability, and security without requiring application code changes.
Data Plane & Control Plane
Istio follows a two-plane architecture:
- Data Plane — Envoy sidecar proxies deployed alongside each workload pod. They intercept all inbound and outbound traffic, applying policies and collecting telemetry.
- Control Plane —
istiodis the single binary that combines Pilot (traffic management), Citadel (certificate authority), and Galley (configuration) into one process.
Install Istio
The recommended installation method uses istioctl, Istio's CLI tool. The demo profile enables all features for learning environments.
# Download and install istioctl
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.22.0 sh -
cd istio-1.22.0
export PATH=$PWD/bin:$PATH
# Install Istio with the demo profile (includes all components)
istioctl install --set profile=demo -y
# Verify the installation
istioctl verify-install
Verify Installation
After installation, confirm that the control plane pods are running in the istio-system namespace:
# Check Istio system pods
kubectl get pods -n istio-system
# Expected output:
# NAME READY STATUS RESTARTS AGE
# istiod-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
# istio-ingressgateway-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
# istio-egressgateway-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
# Check Istio version
istioctl version
Label the namespace where you want automatic sidecar injection:
# Enable automatic sidecar injection for the default namespace
kubectl label namespace default istio-injection=enabled
# Verify the label
kubectl get namespace default --show-labels
Sidecar Injection
Istio injects Envoy sidecars into pods using a Kubernetes mutating admission webhook. When a pod is created in a labeled namespace, the webhook automatically adds the istio-proxy container.
Automatic Injection
Any pod deployed to a namespace with the istio-injection=enabled label will automatically receive a sidecar:
# sample-app.yaml — deploy to an injection-enabled namespace
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- name: httpbin
image: kennethreitz/httpbin:latest
ports:
- containerPort: 80
# Deploy and verify sidecar injection (2/2 READY means sidecar present)
kubectl apply -f sample-app.yaml
kubectl get pods -l app=httpbin
# Expected: httpbin-xxxxx 2/2 Running 0 30s
# The "2/2" indicates the app container + istio-proxy sidecar
Manual Injection & Disabling
For namespaces without automatic injection, use istioctl kube-inject. To exclude specific pods, use annotations:
# Manual injection for a single deployment
istioctl kube-inject -f sample-app.yaml | kubectl apply -f -
# Disable sidecar for a specific pod via annotation
apiVersion: v1
kind: Pod
metadata:
name: skip-sidecar
annotations:
sidecar.istio.io/inject: "false"
spec:
containers:
- name: app
image: nginx:latest
Traffic Flow
When Istio injects a sidecar, it also configures iptables rules inside the pod's network namespace to redirect all traffic through the Envoy proxy:
- Outbound: App sends a request → iptables redirects to Envoy (port 15001) → Envoy applies routing rules → forwards to destination sidecar
- Inbound: Traffic arrives at pod → iptables redirects to Envoy (port 15006) → Envoy applies policies → delivers to app container
service-name:port as usual — Envoy handles mTLS negotiation, load balancing, and telemetry collection transparently.
Gateway & VirtualService Intro
To expose services outside the mesh, Istio uses a Gateway (defines the L4-L6 load balancer) paired with a VirtualService (defines L7 routing rules):
# gateway.yaml — expose HTTP traffic on port 80
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
---
# virtualservice.yaml — route traffic to httpbin service
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: httpbin-vs
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /headers
route:
- destination:
host: httpbin
port:
number: 80
# Apply Gateway and VirtualService
kubectl apply -f gateway.yaml
# Get the Istio ingress gateway external IP
export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}')
# Test the route
curl -H "Host: httpbin.example.com" http://$INGRESS_HOST/status/200
Exercises
minimal profile instead of demo. Compare which components are deployed. Then switch to demo profile and observe the difference with kubectl get pods -n istio-system.
sleep and httpbin) in the mesh. Exec into the sleep pod and curl httpbin. Verify with istioctl proxy-status that both sidecars are synchronized with the control plane.
/api/v1/* to one service and /api/v2/* to another. Test with curl using the Host header to confirm path-based routing works.
Key Takeaways & Next Steps
- Istio's architecture separates the data plane (Envoy sidecars) from the control plane (istiod)
- Installation with
istioctl install --set profile=demogives you a complete setup for learning - Sidecar injection is automatic with namespace labels, or manual with
istioctl kube-inject - Traffic flows transparently through Envoy via iptables redirection
- Gateway + VirtualService is the pattern for ingress traffic routing
Next in the Series
In Part 2: VirtualService & Advanced Routing, we'll explore canary deployments with traffic splitting, header-based routing, fault injection for chaos testing, and circuit breaking with DestinationRules.