模拟 JVM 应用故障

JVMChaos 介绍

JVMChaos 能向目标容器中的 JVM 注入故障,适用于任何使用 JVM 作为运行时的应用。目前 JVMChaos 借助 chaosblade-exec-jvm 实现对 JVM 的错误注入,主要支持以下类型的故障:

  • 指定返回值
  • 方法延迟
  • 抛自定义异常
  • 内存溢出
  • 填充 JVM Code Cache
  • Java 进程 CPU 满载
  • 执行任意自定义 Groovy/Java 脚本

使用限制

目前 Chaos Mesh 使用 MutatingAdmissionWebhook 修改对 Pod 的定义,通过 Init 容器加载 java agnet,并非运行时加载 java agent。因此在使用时存在如下限制:

  • Kubernetes 需要启用 Webhook 支持。
  • 在为命名空间配置 MutatingAdmissionWebhook 之前已经存在 Pod,不会受到 JVMChaos 影响。
  • 命名空间下的所有容器中的 JVM 都会在启动阶段加载 java agent,JVMChaos 在被删除后也不会卸载 java agent。若考虑到 java agent 可能对程序行为或性能带来的影响,期望清理 java agnet,请将工作负载移出该命名空间。

另外,目前无法通过 Chaos Dashboard 创建 JVMChaos。

使用 YAML 方式创建实验

下面将以指定返回值为例,展示 JVMChaos 的使用方法与效果。以下内容中涉及的 yaml 文件均可在 examples/jvm 中找到,以下步骤默认的工作路径也是在 examples/jvm 中。 默认 Chaos Mesh 安装的命名空间为 chaos-testing

1. 创建命名空间并配置 MutatingAdmissionWebhook

建立应用所在的命名空间:

  1. kubectl create ns app

为命名空间 app 增加 label admission-webhook=enabled,允许 Chaos Mesh 的 MutatingAdmissionWebhook 修改该命名空间下的 Pod。

  1. kubectl label ns app admission-webhook=enabled

为 JVMChaos 所需要的修改行为准备模板:

  1. kubectl apply -f sidecar-template.yaml
  2. kubectl apply -f sidecar.yaml

2. 创建被测应用

jvm-chaos-demo 是一个简单的 Spring Boot 应用,此处作为被测应用。被测应用定义在 example/jvm/app.yaml 中,内容如下:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: springboot-jvmchaos-demo
  5. namespace: app
  6. spec:
  7. replicas: 1
  8. selector:
  9. matchLabels:
  10. app: springboot-jvmchaos-demo
  11. template:
  12. metadata:
  13. annotations:
  14. admission-webhook.chaos-mesh.org/request: jvmchaos-sidecar
  15. creationTimestamp: null
  16. labels:
  17. app: springboot-jvmchaos-demo
  18. spec:
  19. containers:
  20. - image: 'gallardot/chaosmesh-jvmchaos-sample:latest'
  21. imagePullPolicy: IfNotPresent
  22. name: springboot-jvmchaos-demo

其中值为 admission-webhook.chaos-mesh.org/request: jvmchaos-sidecarannotation 与步骤 1 sidecar.yamlConfigMap 的名称对应。

建立应用 Deployment:

  1. kubectl apply -f app.yaml

执行 kubectl -n app get pods,预期能够观察到命名空间 app 中出现 1 个名称形如 springboot-jvmchaos-demo-777d94c5b9-7t7l2 的 Pod,等待其 READY1/1 后进行下一步。

  1. kubectl -n app get pods

预期结果如下:

  1. NAME READY STATUS RESTARTS AGE
  2. springboot-jvmchaos-demo-777d94c5b9-7t7l2 1/1 Running 0 21s

3. 观测未被注入时的行为

在注入前你可以先观测应用 jvm-chaos-demo 未被注入时的行为,例如:

使用 kubectl port-forward 将 Pod 的端口映射到本地:

  1. kubectl -n app port-forward pod/springboot-jvmchaos-demo-777d94c5b9-7t7l2 8080:8080

在另外一个 shell session 中使用 curl 或者直接使用浏览器访问 http://localhost:8080/hello,预期返回 Hello firend

  1. curl http://localhost:8080/hello
  2. Hello friend

4. 注入 JVMChaos 并验证

指定返回值的 JVMChaos 内容如下:

  1. apiVersion: chaos-mesh.org/v1alpha1
  2. kind: JVMChaos
  3. metadata:
  4. name: jvm-return-example
  5. namespace: app
  6. spec:
  7. action: return
  8. target: jvm
  9. flags:
  10. value: 'hello chaos mesh!'
  11. matchers:
  12. classname: 'org.chaosmesh.jvm.Application'
  13. methodname: 'hello'
  14. mode: one
  15. selector:
  16. labelSelectors:
  17. app: springboot-jvmchaos-demo

JVMChaos 将 hello 方法的返回值修改为字符串 hello chaos mesh!

注入指定返回值的 JVMChaos:

  1. kubectl apply -f ./jvm-return-example.yaml

使用 curl 或者直接使用浏览器访问 http://localhost:8080/hello,预期返回 hello chaos mesh!

  1. curl http://localhost:8080/hello
  2. hello chaos mesh!

字段说明

参数 类型 说明 默认值 是否必填 示例
action string 表示具体的故障类型,支持 delay、return、script、cfl、oom、ccf、tce、cpf、tde、tpf。 return
mode string 表示选择 Pod 的方式,支持 one、all、fixed、fixed-percent、random-max-percent。 one
value string 取决于 mode 的取值,为 mode 提供参数 2
target string 传递给 chaosblade-exec-jvm 的参数,代表 JVMChaos 的目标,支持 servlet、psql、jvm、jedis、http、dubbo、rocketmq、tars、mysql、druid、redisson、rabbitmq、mongodb。 jvm
flags map[string]string 传递给 chaosblade-exec-jvm 的参数,代表 action 的 flags
matchers map[string]string 传递给 chaosblade-exec-jvm 的参数,代表注入点的匹配方式

关于 action 的取值的含义,可参考:

名称 含义
delay 指定方法调用延迟
return 修改返回值
script 编写 groovy 和 java 实现场景
cfl java 进程 CPU 使用率满载
oom 内存溢出,支持堆、栈、metaspace 区溢出
ccf 填充 jvm code cache
tce 抛自定义异常场景
cpf 连接池满
tde 抛方法声明中的第一个异常
tpf 线程池满

关于 action 的详细用法可参考 chaos blade 文档

关于传递给 chaosblade-exec-jvm 的参数,Chaos Mesh 会将 flagsmatchers 中的所有字段合并后作为请求体发送给 chaosblade-exec-jvm,具体可参考 chaosblade-exec-jvm/协议篇