Injecting Faults
The books demo is a great way to show off this behavior. The overall topology looks like:
)
Topology
In this guide, you will split some of the requests from to books
. Most requests will end up at the correct books
destination, however some of them will be redirected to a faulty backend. This backend will return 500s for every request and inject faults into the webapp
service. No code changes are required and as this method is configuration driven, it is a process that can be added to integration tests and CI pipelines. If you are really living the chaos engineering lifestyle, fault injection could even be used in production.
First, add the books sample application to your cluster:
As this manifest is used as a demo elsewhere, it has been configured with an error rate. To show how fault injection works, the error rate needs to be removed so that there is a reliable baseline. To increase success rate for booksapp to 100%, run:
kubectl -n booksapp patch deploy authors \
--type='json' \
-p='[{"op":"remove", "path":"/spec/template/spec/containers/0/env/2"}]'
After a little while, the stats will show 100% success rate. You can verify this by running:
linkerd viz -n booksapp stat deploy
The output will end up looking at little like:
cat <<EOF | linkerd inject - | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: error-injector
namespace: booksapp
data:
nginx.conf: |-
events {}
http {
server {
listen 8080;
location / {
return 500;
}
}
}
---
kind: Deployment
metadata:
name: error-injector
namespace: booksapp
labels:
spec:
selector:
matchLabels:
app: error-injector
replicas: 1
template:
metadata:
labels:
app: error-injector
spec:
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: nginx-config
configMap:
name: error-injector
apiVersion: v1
kind: Service
metadata:
name: error-injector
namespace: booksapp
spec:
ports:
- name: service
port: 8080
app: error-injector
EOF
With booksapp and NGINX running, it is now time to partially split the traffic between an existing backend, books
, and the newly created error-injector
. This is done by adding a configuration to your cluster:
cat <<EOF | kubectl apply -f -
apiVersion: split.smi-spec.io/v1alpha1
kind: TrafficSplit
metadata:
name: error-split
namespace: booksapp
spec:
service: books
backends:
- service: books
weight: 900m
- service: error-injector
weight: 100m
EOF
When Linkerd sees traffic going to the books
service, it will send 9⁄10 requests to the original service and 1⁄10 to the error injector. You can see what this looks like by running stat
and filtering explicitly to just the requests from webapp
:
Unlike the previous stat
command which only looks at the requests received by servers, this routes
command filters to all the requests being issued by webapp
destined for the books
service itself. The output should show a 90% success rate:
ROUTE SERVICE SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99
Note
To remove everything in this guide from your cluster, run:
kubectl delete ns booksapp