Room 54
SERVICE MESH
The Traffic Conductor
- A service mesh provides observability, traffic management, and security for microservice communication.
- You’ll deploy a mesh sidecar architecture and control traffic between services.
📜 Mission Briefing
- Deploy a microservices application with 3 services:
web,api,db. - Inject sidecar proxies into each service using manual sidecar injection.
- Configure traffic routing: send 80% of traffic to
api-v1and 20% toapi-v2. - Set up mutual TLS (mTLS) between all services.
- Apply a retry policy for failed requests to the
apiservice. - Observe traffic flow using proxy access logs.
- The password is in the traffic split annotation:
mesh54go.
Key Commands
| Command | Purpose |
|---|---|
kubectl get pods -o jsonpath='{.items[*].spec.containers[*].name}' |
List all containers (check for sidecars) |
kubectl logs <pod> -c envoy-proxy |
Sidecar proxy logs |
kubectl get virtualservices |
Traffic routing rules |
kubectl get destinationrules |
Load balancing and TLS config |
kubectl get peerauthentication |
mTLS policies |
Microservices Deployment
# web-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.25
ports:
- containerPort: 80
volumeMounts:
- name: config
mountPath: /etc/nginx/conf.d
volumes:
- name: config
configMap:
name: web-nginx-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: web-nginx-config
data:
default.conf: |
upstream api_backend {
server api-service:8080;
}
server {
listen 80;
location / {
root /usr/share/nginx/html;
}
location /api {
proxy_pass http://api_backend;
}
}
---
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80
Canary Deployment - Traffic Splitting
# api-v1-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-v1
labels:
app: api
version: v1
spec:
replicas: 3
selector:
matchLabels:
app: api
version: v1
template:
metadata:
labels:
app: api
version: v1
spec:
containers:
- name: api
image: nginx:1.25
ports:
- containerPort: 8080
---
# api-v2-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-v2
labels:
app: api
version: v2
annotations:
traffic-password: "mesh54go"
spec:
replicas: 1
selector:
matchLabels:
app: api
version: v2
template:
metadata:
labels:
app: api
version: v2
spec:
containers:
- name: api
image: nginx:1.26
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
selector:
app: api
ports:
- port: 8080
targetPort: 8080
Manual Sidecar Injection
# sidecar-patch.yaml - Add Envoy sidecar to any deployment
# Apply with: kubectl patch deploy web --patch-file sidecar-patch.yaml
spec:
template:
spec:
initContainers:
- name: proxy-init
image: envoyproxy/envoy:v1.28-latest
command: ["sh", "-c", "echo 'Sidecar init complete'"]
securityContext:
capabilities:
add: ["NET_ADMIN"]
containers:
- name: envoy-proxy
image: envoyproxy/envoy:v1.28-latest
ports:
- containerPort: 15001
command: ["envoy"]
args:
- "-c"
- "/etc/envoy/envoy.yaml"
- "--service-cluster"
- "$(POD_NAME)"
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
volumeMounts:
- name: envoy-config
mountPath: /etc/envoy
volumes:
- name: envoy-config
configMap:
name: envoy-sidecar-config
Traffic Splitting with Weighted Services
# Without a full service mesh, simulate traffic splitting with multiple deployments
# and weighted endpoints
# Scale to achieve 80/20 split
kubectl scale deploy api-v1 --replicas=4 # 4 out of 5 = 80%
kubectl scale deploy api-v2 --replicas=1 # 1 out of 5 = 20%
# Both share the same Service selector (app: api)
# Kubernetes will round-robin across all matching pods
# Verify the split
for i in $(seq 1 20); do
kubectl exec deploy/web -- curl -s api-service:8080 2>/dev/null
done | sort | uniq -c | sort -rn
# Check the password annotation on api-v2
kubectl get deploy api-v2 -o jsonpath='{.metadata.annotations.traffic-password}'
# Output: mesh54go
mTLS Between Services
# mtls-policy.yaml - Require mTLS for all traffic
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: default
spec:
mtls:
mode: STRICT
# Without Istio, you can configure mTLS manually with certificates
# Generate self-signed certs for service communication
# Create CA
openssl req -x509 -newkey rsa:2048 -keyout ca-key.pem -out ca-cert.pem \
-days 365 -nodes -subj "/CN=mesh-ca"
# Create service cert signed by CA
openssl req -newkey rsa:2048 -keyout svc-key.pem -out svc-csr.pem \
-nodes -subj "/CN=api-service.default.svc.cluster.local"
openssl x509 -req -in svc-csr.pem -CA ca-cert.pem -CAkey ca-key.pem \
-CAcreateserial -out svc-cert.pem -days 365
# Store as Kubernetes Secret
kubectl create secret tls api-tls \
--cert=svc-cert.pem \
--key=svc-key.pem
Retry Policy
# retry-configmap.yaml - Envoy retry configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: envoy-retry-config
data:
retry.yaml: |
retry_policy:
retry_on: "5xx,reset,connect-failure"
num_retries: 3
per_try_timeout: 2s
retry_back_off:
base_interval: 0.5s
max_interval: 5s
💡 Hints
- A service mesh sidecar intercepts all inbound and outbound traffic from a pod.
- Without Istio/Linkerd, you can simulate traffic splitting by controlling replica ratios.
- mTLS ensures service-to-service encryption - the mesh CA issues and rotates certificates.
- The password is in the
api-v2deployment annotation - usekubectl get deploy api-v2 -o yaml.
🔑 Password
Check the api-v2 deployment annotation:
kubectl get deploy api-v2 -o jsonpath='{.metadata.annotations.traffic-password}'