头图

之前的文章 中,我们快速体验了 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

Flomesh
1 声望0 粉丝