在 之前的文章 中,我们快速体验了 FSM Gateway - 一个开源的 K8s Gateway API 的实现。在即将发布的 FSM 1.2 中,FSM Gateway 将会带来更多的功能:
- 故障注入策略
- 限流策略
- 会话保持策略
- 负载均衡算法
- 熔断策略
- 访问控制策略
- 健康检查策略
- TLS 上游策略
- …
后面我们会推出系列的文章来介绍这些功能,这篇文章是文章的第一篇,在 FSM 1.2 即将发布之际,为大家带来 FSM Gateway 故障注入功能的前瞻。
背景
什么是故障注入
故障注入功能是一种强大的测试机制,用于增强微服务架构的健壯性和可靠性。这项功能通过模拟网络层面的故障(如延迟和错误响应)来测试系统的容错能力和恢复机制。故障注入主要包括两种类型:延迟注入和错误注入。
延迟注入是通过在网关处理请求的过程中人为地引入延迟,模拟网络延迟或服务处理缓慢的情况。这有助于测试下游服务的超时处理和重试策略是否有效,确保在实际延迟发生时,整个系统能够保持稳定运行。
错误注入则是通过让网关返回错误响应(如 HTTP 5xx 错误)来模拟后端服务故障。这种方法可以验证服务消费者对于失败的处理,比如是否正确地执行了错误处理逻辑和容错机制,例如断路器模式。
FSM Gateway 支持这两种故障注入,同时提供了两种粒度的故障注入:域名和路由。接下来通过演示带领各位展示 FSM Gateway 的故障注入。
FSM Gateway 使用了 FGW 作为内核,因此拥有 与 FGW 同样的故障注入功能。
演示
前置条件
- Kubernetes 集群
- kubectl 工具
环境准备
安装 FSM Gateway
FSM Gateway 的安装,可以参考 安装文档。这里选择 CLI 的方式安装。
下载 FSM CLI,当前为 v1.2.0-alpha.12 版本。
system=$(uname -s | tr '[:upper:]' '[:lower:]')
arch=$(uname -m | sed -E 's/x86_/amd/' | sed -E 's/aarch/arm/')
release=v1.2.0-alpha.12
curl -L https://github.com/flomesh-io/fsm/releases/download/$release/fsm-$release-$system-$arch.tar.gz | tar -vxzf -
./$system-$arch/fsm version
sudo cp ./$system-$arch/fsm /usr/local/bin/fsm
在安装 FSM 时启用 FSM Gateway,默认情况是不启用的。
fsm install \
--set=fsm.fsmGateway.enabled=true
确认已经安装 GatewayClass 控制器:flomesh.io/gateway-controller
。
kubectl get gatewayclass
NAME CONTROLLER ACCEPTED AGE
fsm-gateway-cls flomesh.io/gateway-controller True 12h
部署示例应用
接下来部署示例应用,使用常用的 httpbin 服务,并创建 网关(Gateway) 和 HTTP 路由(HttpRoute)。
kubectl create namespace httpbin
kubectl apply -n httpbin -f https://raw.githubusercontent.com/flomesh-io/fsm-docs/main/manifests/gateway/http-routing.yaml
检查网关和 HTTP 路由,可以看到创建了两个不同域名的路由。
kubectl get gateway,httproute -n httpbin
NAME CLASS ADDRESS PROGRAMMED AGE
gateway.gateway.networking.k8s.io/simple-fsm-gateway fsm-gateway-cls Unknown 3s
NAME HOSTNAMES AGE
httproute.gateway.networking.k8s.io/http-route-foo ["foo.example.com"] 2s
httproute.gateway.networking.k8s.io/http-route-bar ["bar.example.com"] 2s
访问应用验证 HTTP 路由是否生效。
export GATEWAY_IP=$(kubectl get svc -n httpbin -l app=fsm-gateway -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}')
curl http://$GATEWAY_IP:8000/headers -H 'host:foo.example.com'
{
"headers": {
"Accept": "*/*",
"Connection": "keep-alive",
"Host": "10.42.0.15:80",
"User-Agent": "curl/7.81.0"
}
}
故障注入测试
路由粒度的故障注入
在 HTTP 路由 foo.example.com
下我们添加一条路径前缀为 /headers
的路由,方便为其设置故障注入。
kubectl apply -n httpbin -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: http-route-foo
spec:
parentRefs:
- name: simple-fsm-gateway
port: 8000
hostnames:
- foo.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /headers
backendRefs:
- name: httpbin
port: 8080
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: httpbin
port: 8080
EOF
当我们请求路径 /headers
和 /get
时都可以获得正确的响应。
接下来,我们在 /headers
路由上注入 404
故障,概率为 100%
。
kubectl apply -n httpbin -f - <<EOF
apiVersion: gateway.flomesh.io/v1alpha1
kind: FaultInjectionPolicy
metadata:
name: fault-injection
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: http-route-foo
namespace: httpbin
http:
- match:
path:
type: PathPrefix
value: /headers
config:
abort:
percent: 100
statusCode: 404
EOF
此时请求 /headers
收到了 404
响应。
curl -I http://$GATEWAY_IP:8000/headers -H 'host:foo.example.com'
HTTP/1.1 404 Not Found
content-length: 0
connection: keep-alive
如果请求 /get
,则不会受到影响。
curl -I http://$GATEWAY_IP:8000/get -H 'host:foo.example.com'
HTTP/1.1 200 OK
server: gunicorn/19.9.0
date: Thu, 14 Dec 2023 14:11:36 GMT
content-type: application/json
content-length: 220
access-control-allow-origin: *
access-control-allow-credentials: true
connection: keep-alive
域名粒度的故障注入
kubectl apply -n httpbin -f - <<EOF
apiVersion: gateway.flomesh.io/v1alpha1
kind: FaultInjectionPolicy
metadata:
name: fault-injection
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: http-route-foo
namespace: httpbin
hostnames:
- hostname: foo.example.com
config:
abort:
percent: 100
statusCode: 404
EOF
请求 foo.example.com
,返回 404
响应。
curl -I http://$GATEWAY_IP:8000/headers -H 'host:foo.example.com'
HTTP/1.1 404 Not Found
content-length: 0
connection: keep-alive
但此时请求 bar.example.com
,由于域名并不在故障注入的命名列表下,因此响应正常,
curl -I http://$GATEWAY_IP:8000/headers -H 'host:bar.example.com'
HTTP/1.1 200 OK
server: gunicorn/19.9.0
date: Thu, 14 Dec 2023 13:55:07 GMT
content-type: application/json
content-length: 140
access-control-allow-origin: *
access-control-allow-credentials: true
connection: keep-alive
修改故障注入策略,将错误故障,改为延迟故障:随机加入 500 到 1000 ms 的延迟。
kubectl apply -n httpbin -f - <<EOF
apiVersion: gateway.flomesh.io/v1alpha1
kind: FaultInjectionPolicy
metadata:
name: fault-injection
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: http-route-foo
namespace: httpbin
hostnames:
- hostname: foo.example.com
config:
delay:
percent: 100
range:
min: 500
max: 1000
unit: ms
EOF
请求时检查响应的耗时,可以看到引入了随机的延迟。
time curl -s http://$GATEWAY_IP:8000/headers -H 'host:foo.example.com' > /dev/null
real 0m0.904s
user 0m0.000s
sys 0m0.010s
time curl -s http://$GATEWAY_IP:8000/headers -H 'host:foo.example.com' > /dev/null
real 0m0.572s
user 0m0.005s
sys 0m0.005s