This repository contains a small Kubernetes + Istio demo for learning service mesh basics.
The demo has three HTTP services:
web: public entry point that callscatalogcatalog-v1: stable catalog response that callsinventorycatalog-v2: alternate catalog response used for traffic shiftinginventory: downstream dependency used to demonstrate retries, timeouts, and auth policy
The application code has no framework dependencies. Each service uses Python's standard library so the mesh behavior stays easy to see.
- Automatic sidecar injection with Istio
- Service-to-service calls through Kubernetes service discovery
- Mesh traffic routing with
VirtualServiceandDestinationRule - Canary traffic splitting between
catalog-v1andcatalog-v2 - Fault injection and retry behavior
- Strict mTLS inside the namespace
- Service-level access control with
AuthorizationPolicy
- Docker
kubectl- A Kubernetes cluster, such as
kind, Docker Desktop Kubernetes, or Minikube - Istio CLI,
istioctl
Example local cluster setup with kind:
kind create cluster --name mesh-demo
istioctl install --set profile=demo -yFor kind:
docker build -t mesh-demo/web:local services/web
docker build -t mesh-demo/catalog:local services/catalog
docker build -t mesh-demo/inventory:local services/inventory
kind load docker-image mesh-demo/web:local --name mesh-demo
kind load docker-image mesh-demo/catalog:local --name mesh-demo
kind load docker-image mesh-demo/inventory:local --name mesh-demoFor Docker Desktop Kubernetes or Minikube, build the images in the Docker environment used by your cluster.
kubectl apply -f k8s/00-namespace.yaml
kubectl apply -f k8s/10-apps.yaml
kubectl apply -f k8s/20-istio-routing.yaml
kubectl apply -f k8s/30-security.yamlWait for the workloads:
kubectl -n mesh-demo rollout status deploy/web
kubectl -n mesh-demo rollout status deploy/catalog-v1
kubectl -n mesh-demo rollout status deploy/catalog-v2
kubectl -n mesh-demo rollout status deploy/inventoryPort-forward the Istio ingress gateway:
kubectl -n istio-system port-forward svc/istio-ingressgateway 8080:80In another terminal:
curl http://localhost:8080/You should see JSON showing the web, catalog, and inventory responses.
The default route sends 90% of traffic to catalog-v1 and 10% to catalog-v2.
for i in {1..20}; do curl -s http://localhost:8080/ | jq -r '.catalog.version'; doneChange the weights in k8s/20-istio-routing.yaml, then re-apply:
kubectl apply -f k8s/20-istio-routing.yamlThe inventory service can fail when ?fail=true is passed. The catalog service calls inventory with that query when you call:
curl "http://localhost:8080/?fail_inventory=true"The VirtualService for inventory allows retries, so check Envoy/Istio metrics or pod logs to see repeated attempts.
Enable the commented fault injection block in k8s/20-istio-routing.yaml under the inventory VirtualService, then apply it:
kubectl apply -f k8s/20-istio-routing.yaml
curl http://localhost:8080/The request should slow down, showing how the mesh can shape downstream behavior without changing app code.
Strict mTLS is enabled in k8s/30-security.yaml for the mesh-demo namespace:
kubectl -n mesh-demo get peerauthenticationOnly the catalog service account can call inventory.
This should be denied:
kubectl -n mesh-demo run curl-test --rm -it --image=curlimages/curl --restart=Never -- \
curl -s -o /dev/null -w "%{http_code}\n" http://inventory:8080/The application path still works because web calls catalog, and catalog is allowed to call inventory.
kubectl delete namespace mesh-demo