Linkerd 장애 주입하기
Linkerd 장애 주입하기 (Injecting Faults)
HTTPRoute 리소스를 사용해 트래픽의 일정 비율을 특정 백엔드로 리다이렉트하면 애플리케이션에 장애를 쉽게 주입할 수 있어요. 이 백엔드는 완전히 자유롭게 구성할 수 있어서 500 응답, 타임아웃, 심지어 엉뚱한 페이로드까지 원하는 대로 반환하게 할 수 있어요.
Books 데모는 이 동작을 보여주기에 아주 좋아요. 전체 토폴로지는 다음과 같아요: Topology
이 가이드에서는 webapp에서 books로 가는 요청 중 일부를 분리할 거예요. 대부분의 요청은 올바른 books 목적지에 도달하지만, 일부는 잘못된 백엔드로 리다이렉트될 거예요. 이 백엔드는 모든 요청에 대해 500을 반환해 webapp 서비스에 장애를 주입해요. 코드 변경은 필요 없고, 이 방법은 구성 기반이기 때문에 통합 테스트와 CI 파이프라인에 추가할 수 있는 절차예요. 카오스 엔지니어링을 진짜로 실천하고 있다면 장애 주입을 프로덕션에서도 사용할 수 있어요.
사전 요구사항
이 가이드를 사용하려면 다음이 실행되는 Kubernetes 클러스터가 필요해요:
- Linkerd 및 Linkerd-Viz. 아직 설치하지 않았다면 Installing Linkerd 가이드를 따라 하세요.
서비스 설정
먼저 books 샘플 애플리케이션을 클러스터에 추가하세요:
kubectl create ns booksapp && \
linkerd inject https://run.linkerd.io/booksapp.yml | \
kubectl -n booksapp apply -f -
이 매니페스트는 다른 데모에서도 사용되므로 오류율이 구성되어 있어요. 장애 주입이 어떻게 동작하는지 보여주려면 오류율을 제거해서 신뢰할 수 있는 기준선을 만들어야 해요. booksapp의 성공률을 100%로 올리려면 다음을 실행하세요:
kubectl -n booksapp patch deploy authors \
--type='json' \
-p='[{"op":"remove", "path":"/spec/template/spec/containers/0/env/2"}]'
잠시 후 통계에 100% 성공률이 표시될 거예요. 다음 명령으로 확인할 수 있어요:
linkerd viz -n booksapp stat-inbound deploy
출력은 대략 다음과 같이 보일 거예요:
NAME SERVER ROUTE TYPE SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99
authors [default]:4191 [default] 100.00% 0.20 0ms 1ms 1ms
authors [default]:7001 [default] 100.00% 3.00 2ms 36ms 43ms
books [default]:4191 [default] 100.00% 0.23 4ms 4ms 4ms
books [default]:7002 [default] 100.00% 3.60 2ms 2ms 2ms
traffic [default]:4191 [default] 100.00% 0.22 0ms 3ms 1ms
webapp [default]:4191 [default] 100.00% 0.72 4ms 5ms 1ms
webapp [default]:7000 [default] 100.00% 3.25 2ms 2ms 65ms
잘못된 백엔드 만들기
booksapp에 장애를 주입하려면 오류를 반환하도록 구성된 서비스가 필요해요. 이렇게 하려면 NGINX를 시작하고 500을 반환하도록 구성하면 돼요:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: error-injector
namespace: booksapp
data:
nginx.conf: |-
events {}
http {
server {
listen 8080;
location / {
return 500;
}
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: error-injector
namespace: booksapp
labels:
app: error-injector
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
selector:
app: error-injector
EOF
장애 주입
booksapp과 NGINX가 실행되면 이제 기존 백엔드인 books와 새로 만든 error-injector 사이에 트래픽을 부분적으로 분리할 차례예요. 이는 클러스터에 HTTPRoute 구성을 추가해서 수행해요:
cat <<EOF | kubectl apply -f -
apiVersion: policy.linkerd.io/v1beta2
kind: HTTPRoute
metadata:
name: error-split
namespace: booksapp
spec:
parentRefs:
- name: books
kind: Service
group: core
port: 7002
rules:
- backendRefs:
- name: books
port: 7002
weight: 90
- name: error-injector
port: 8080
weight: 10
EOF
참고
HTTPRoute 리소스의 두 가지 버전을 Linkerd와 함께 사용할 수 있어요:
- Gateway API가 제공하는 업스트림 버전(
gateway.networking.k8s.ioAPI 그룹) - Linkerd가 제공하는 Linkerd 특화 CRD(
policy.linkerd.ioAPI 그룹)
두 HTTPRoute 리소스 정의는 비슷하지만, Linkerd 버전은 업스트림 Gateway API 리소스 정의에는 아직 없는 실험적 기능을 구현해요. 자세한 내용은 HTTPRoute 레퍼런스 문서를 참고하세요.
Linkerd가 books 서비스로 가는 트래픽을 보면, 요청 10개 중 9개를 원래 서비스로, 1개를 오류 주입기로 보내요. stat-outbound를 실행하면 이 모습을 확인할 수 있어요:
linkerd viz stat-outbound -n booksapp deploy/webapp
NAME SERVICE ROUTE TYPE BACKEND SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99 TIMEOUTS RETRIES
webapp authors:7001 [default] 98.44% 4.28 25ms 47ms 50ms 0.00% 0.00%
└────────────────────► authors:7001 98.44% 4.28 15ms 42ms 48ms 0.00%
webapp books:7002 error-split HTTPRoute 87.76% 7.22 26ms 49ms 333ms 0.00% 0.00%
├────────────────────► books:7002 100.00% 6.33 14ms 42ms 83ms 0.00%
└────────────────────► error-injector:8080 0.00% 0.88 12ms 24ms 25ms 0.00%
여기서 초당 0.88개의 요청이 오류 주입기로 보내지고 있으며 전체 성공률은 87.76%인 것을 확인할 수 있어요.
정리
이 가이드의 모든 것을 클러스터에서 제거하려면 다음을 실행하세요:
kubectl delete ns booksapp
본문
HTTPRoute 리소스를 사용해 트래픽의 일정 비율을 특정 백엔드로 리다이렉트하면 애플리케이션에 장애를 쉽게 주입할 수 있어요. 이 백엔드는 완전히 자유롭게 구성할 수 있어서 500 응답, 타임아웃, 심지어 엉뚱한 페이로드까지 원하는 대로 반환하게 할 수 있어요.
Books 데모는 이 동작을 보여주기에 아주 좋아요. 전체 토폴로지는 다음과 같아요: Topology
이 가이드에서는 webapp에서 books로 가는 요청 중 일부를 분리할 거예요. 대부분의 요청은 올바른 books 목적지에 도달하지만, 일부는 잘못된 백엔드로 리다이렉트될 거예요. 이 백엔드는 모든 요청에 대해 500을 반환해 webapp 서비스에 장애를 주입해요. 코드 변경은 필요 없고, 이 방법은 구성 기반이기 때문에 통합 테스트와 CI 파이프라인에 추가할 수 있는 절차예요. 카오스 엔지니어링을 진짜로 실천하고 있다면 장애 주입을 프로덕션에서도 사용할 수 있어요.
사전 요구사항
이 가이드를 사용하려면 다음이 실행되는 Kubernetes 클러스터가 필요해요:
- Linkerd 및 Linkerd-Viz. 아직 설치하지 않았다면 Installing Linkerd 가이드를 따라 하세요.
서비스 설정
먼저 books 샘플 애플리케이션을 클러스터에 추가하세요:
kubectl create ns booksapp && \
linkerd inject https://run.linkerd.io/booksapp.yml | \
kubectl -n booksapp apply -f -
이 매니페스트는 다른 데모에서도 사용되므로 오류율이 구성되어 있어요. 장애 주입이 어떻게 동작하는지 보여주려면 오류율을 제거해서 신뢰할 수 있는 기준선을 만들어야 해요. booksapp의 성공률을 100%로 올리려면 다음을 실행하세요:
kubectl -n booksapp patch deploy authors \
--type='json' \
-p='[{"op":"remove", "path":"/spec/template/spec/containers/0/env/2"}]'
잠시 후 통계에 100% 성공률이 표시될 거예요. 다음 명령으로 확인할 수 있어요:
linkerd viz -n booksapp stat-inbound deploy
출력은 대략 다음과 같이 보일 거예요:
NAME SERVER ROUTE TYPE SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99
authors [default]:4191 [default] 100.00% 0.20 0ms 1ms 1ms
authors [default]:7001 [default] 100.00% 3.00 2ms 36ms 43ms
books [default]:4191 [default] 100.00% 0.23 4ms 4ms 4ms
books [default]:7002 [default] 100.00% 3.60 2ms 2ms 2ms
traffic [default]:4191 [default] 100.00% 0.22 0ms 3ms 1ms
webapp [default]:4191 [default] 100.00% 0.72 4ms 5ms 1ms
webapp [default]:7000 [default] 100.00% 3.25 2ms 2ms 65ms
잘못된 백엔드 만들기
booksapp에 장애를 주입하려면 오류를 반환하도록 구성된 서비스가 필요해요. 이렇게 하려면 NGINX를 시작하고 500을 반환하도록 구성하면 돼요:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: error-injector
namespace: booksapp
data:
nginx.conf: |-
events {}
http {
server {
listen 8080;
location / {
return 500;
}
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: error-injector
namespace: booksapp
labels:
app: error-injector
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
selector:
app: error-injector
EOF
장애 주입
booksapp과 NGINX가 실행되면 이제 기존 백엔드인 books와 새로 만든 error-injector 사이에 트래픽을 부분적으로 분리할 차례예요. 이는 클러스터에 HTTPRoute 구성을 추가해서 수행해요:
cat <<EOF | kubectl apply -f -
apiVersion: policy.linkerd.io/v1beta2
kind: HTTPRoute
metadata:
name: error-split
namespace: booksapp
spec:
parentRefs:
- name: books
kind: Service
group: core
port: 7002
rules:
- backendRefs:
- name: books
port: 7002
weight: 90
- name: error-injector
port: 8080
weight: 10
EOF
참고
HTTPRoute 리소스의 두 가지 버전을 Linkerd와 함께 사용할 수 있어요:
- Gateway API가 제공하는 업스트림 버전(
gateway.networking.k8s.ioAPI 그룹) - Linkerd가 제공하는 Linkerd 특화 CRD(
policy.linkerd.ioAPI 그룹)
두 HTTPRoute 리소스 정의는 비슷하지만, Linkerd 버전은 업스트림 Gateway API 리소스 정의에는 아직 없는 실험적 기능을 구현해요. 자세한 내용은 HTTPRoute 레퍼런스 문서를 참고하세요.
Linkerd가 books 서비스로 가는 트래픽을 보면, 요청 10개 중 9개를 원래 서비스로, 1개를 오류 주입기로 보내요. stat-outbound를 실행하면 이 모습을 확인할 수 있어요:
linkerd viz stat-outbound -n booksapp deploy/webapp
NAME SERVICE ROUTE TYPE BACKEND SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99 TIMEOUTS RETRIES
webapp authors:7001 [default] 98.44% 4.28 25ms 47ms 50ms 0.00% 0.00%
└────────────────────► authors:7001 98.44% 4.28 15ms 42ms 48ms 0.00%
webapp books:7002 error-split HTTPRoute 87.76% 7.22 26ms 49ms 333ms 0.00% 0.00%
├────────────────────► books:7002 100.00% 6.33 14ms 42ms 83ms 0.00%
└────────────────────► error-injector:8080 0.00% 0.88 12ms 24ms 25ms 0.00%
여기서 초당 0.88개의 요청이 오류 주입기로 보내지고 있으며 전체 성공률은 87.76%인 것을 확인할 수 있어요.
정리
이 가이드의 모든 것을 클러스터에서 제거하려면 다음을 실행하세요:
kubectl delete ns booksapp