{"id":15178554,"url":"https://github.com/grafana/k6-chaos","last_synced_at":"2025-10-01T19:30:37.215Z","repository":{"id":36994909,"uuid":"479057524","full_name":"grafana/k6-chaos","owner":"grafana","description":"Repository of helpers to run chaos experiments with k6","archived":true,"fork":false,"pushed_at":"2022-11-02T08:22:21.000Z","size":57,"stargazers_count":12,"open_issues_count":6,"forks_count":3,"subscribers_count":130,"default_branch":"main","last_synced_at":"2024-10-28T03:14:49.249Z","etag":null,"topics":["chaos","chaos-engineering","k6","kubernetes"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grafana.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-04-07T16:07:11.000Z","updated_at":"2023-09-10T11:53:31.000Z","dependencies_parsed_at":"2023-01-17T12:01:46.249Z","dependency_job_id":null,"html_url":"https://github.com/grafana/k6-chaos","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fk6-chaos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fk6-chaos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fk6-chaos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fk6-chaos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grafana","download_url":"https://codeload.github.com/grafana/k6-chaos/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234892715,"owners_count":18902907,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chaos","chaos-engineering","k6","kubernetes"],"created_at":"2024-09-27T15:05:25.651Z","updated_at":"2025-10-01T19:30:36.832Z","avatar_url":"https://github.com/grafana.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# k6-chaos\n\nThis repo contains a [collection of JavaScript helpers](./src/chaos.js) to run chaos experiments *effortlessly* on top of [k6](https://k6.io).\n\n\u003e ## Deprecation notice\n\u003e ⚠️ k6-chaos has been deprecated in favor or [xk6-disruptor](https://github.com/grafana/xk6-disruptor) a k6 extension providing fault injection capabilities.\n\n\n# Getting started\n\nThe first thing you need is a custom k6 binary with the extensions required to use this library: [xk6-kubernetes](https://github.com/grafana/xk6-kubernetes). \n\nYou can also download the required k6 binary from the [releases page](https://github.com/grafana/k6-jslib-chaos/releases).\n\n## Exposing your application\n\nIn order to access your application from the test script, it must be assigned an external IP. This can be accomplished in different ways depending on the platform you used for deploying the application.\n\n### As a LoadBalancer service\nA service of type [`LoadBalancer`](https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/) receives an external IP from an external load balancer provider. The load balancer is configured in different ways depending on the platform your cluster is deployed in and the configuration of the cluster. In the following sections we provide guidelines for exposing your application when running in common development environments. If your cluster is deployed in a public cloud, check your cloud provider's documentation.\n\n#### Configuring a LoadBalancer in Kind\n[Kind](https://kind.sigs.k8s.io/) is a tool for running local Kubernetes clusters using Docker container to emulate “nodes”. It may be used for local development or CI. Services deployed in a kind cluster can be exposed to be accessed from the host machine [using metallb as a load balancer](https://kind.sigs.k8s.io/docs/user/loadbalancer).\n\n#### LoadBalancer in Minikube\n\n[Minikube](https://github.com/kubernetes/minikube) implements a local Kubernetes cluster supporting different technologies for virtualizing the cluster's infrastructure, such as containers, VMs or running in bare metal.\n\nMinikube's tunnel command runs as a process, creating a network route on the host to the service CIDR of the cluster using the cluster’s IP address as a gateway. The tunnel command exposes the external IP directly to any program running on the host operating system.\n\n```console\n$ minikube tunnel\n```\n\n# APIs\n\n## Helpers\n\nThe `helpers.js` module offers helper functions and clases to facilitate the setup of test scenariors\n\n### DeploymentHelper\n\nThe `DeploymentHelper` class facilitates deploying applications and exposing them as services.\n\nMethods\n\n`constructor` creates a helper for deploying an application\n\n      Parameters:\n        client: k8s client from xk6-kubernetes\n        name: name of the application\n        namespace: target namespace\n        image: image of the application\n        replicas: number of replicas\n        options:\n          - app: value of the 'app' label used as pod selector. Defaults to the name\n          - port: port to expose in the application's container. Defaults to '80' \n\n`deploy` deploys the application and waits for the replicas to be ready\n\n`expose` exposes the application as a service\n\n      Parameters\n        options: additional parameters for configuring the service\n          - port: port to expose the service. Defaults to '80'\n          - name: servie name. Defaults to the application's name\n\n`getPods` returns a list with the names of the deployment pods\n\n### ServiceHelper\n\nThe `ServiceHelper` class facilitates accessing services.\n\nMethods\n\n`constructor` creates a helper for accessing services\n\n      Parameters:\n        client: k8s client from xk6-kubernetes\n        name: name of the service\n        namespace: target namespace\n\n\n`getIp` returns the external IP of the service. Throwns an error if none is set.\n\n## KubernetesDisruptor\n\nThe `KubernetesDisruptor` class offers methods for introducing faults in kubernetes resources such as namespaces, secrets, config-maps, CRDs, etcetera. It can be used for\nexample for testing the resilience of operators to those failures.\n\nMethods\n\n`constructor`: creates an instance of KubernetesChaos\n\n      Parameters\n        client: k8s client from xk6-kubernetes\n        namespace: namespace to inject chaos into\n\n`killNamespace`: kill the namespace\n\n\n## Node disruptor\n\nThe `NodeDisruptor` disrupts nodes\n\nMethods:\n\n`constructor`: creates a node distuptor\n\n    Parameters:\n     client: k8s client from xk6-kubernetes\n     options: options\n        - name: name of the attack (used as stress job name prefix)\n        - namespace: namespace where stress jobs will be started\n        - selector: labels for selecting target node(s). An empty selector matches all nodes\n        - picker: strategy used for picking node(s) to disrupt from potential targets.\n        - auto_clean: automatically delete stress jobs when attacks ends (defaults to true)\n\n`stress`: stressing a list of nodes by exhausting resources\n\n    Parameters:\n      nodes: list of nodes to stress\n      options: controls the stress attack\n        - cores: sets the number of CPU concurrent stress processes to start\n        - cpu_Load: sets the CPU load per stress process\n        - duration: sets the duration of the stress attack. E.g. '5m'\n\n`clean`: clean jobs started by the disruptor (if auto_cleanup was set to false)\n\n## Pod Disruption\n\nThe `PodDisruptor` class allows disruption of Pods\n\nMethods:\n\n`constructor`: creates a pod disruptor\n\n    Parameters:\n      client: k8s client from xk6-kubernetes\n      options:\n        - namespace: namespace for selecting target pod(s) \n        - selector: labels for selecting target pod(s). An empty selector matches all pods\n        - picker: strategy used for picking pod(s) to disrupt from potential targets.\n          Presenlty the only suppored value is 'ramdom' (one random pod)\n        - wait: timeout (as a duration) for the disruptor to be initilized (defaults to '10s')\n\n`kill`: kill pod\n\n`slowdownNetwork`: delays network traffic for the pod\n\n    Parameters:\n      options: controls the delay attack\n        - delay: average delay in network packages (in milliseconds)\n        - variation: variation in the delay (in milliseconds)\n        - duration: duration of the disruption \n\n`disruptHttp`: disrupts http requests to the pod.\n\n      Parameters:\n        options: controls the attack\n          - delay: average delay in requests (in milliseconds. Default is 0ms)\n          - variation: variation in the delay (in milliseconds. default is 0ms)\n          - error_rate: rate of requests that will return an error (float in the range 0.0 to 1.0. Default is 0.0)\n          - error_code: error code to return\n          - duration: duration of the disruption (default is 30s)\n          - target: port on which the requests will be intercepted (defaults is 80)\n          - port: port the transparent proxy will use to listen for requests (default is 8080)\n          - interface: interface on which the traffic will be intercepted (default is eth0)\n          - exclude: list of urls to be excluded from disruption (e.g. /health)\n\n## Service Disruption\n\nThe `ServiceDisruptor` class allows disruption of Services\n\nMethods:\n\n`constructor`: creates a service disruptor\n\n    Parameters:\n      client: k8s client from xk6-kubernetes\n      name: name of the target service\n      options:\n        - namespace: namespace for selecting target pod(s) \n        - wait: timeout (as a duration) for the disruptor to be initilized (defaults to '10s')\n\n`kill`: kill pod\n\n`disruptHttp`: disrupts http requests to the service.\n\n      Parameters:\n        options: controls the attack\n          - delay: average delay in requests (in milliseconds. Default is 0ms)\n          - variation: variation in the delay (in milliseconds. default is 0ms)\n          - error_rate: rate of requests that will return an error (float in the range 0.0 to 1.0. Default is 0.0)\n          - error_code: error code to return\n          - duration: duration of the disruption (default is 30s)\n          - target: port on which the requests will be intercepted (defaults is 80)\n          - port: port the transparent proxy will use to listen for requests (default is 8080)\n          - interface: interface on which the traffic will be intercepted (default is eth0)\n          - exclude: list of urls to be excluded from disruption (e.g. /health)\n\n## Examples\n\nThe [./exaples](./examples) folder contains examples of using `k6-chaos`. \n\n\n### Running examples\nNotice `k6-chaos` needs the image `grafana/k6-agent`. This image can build using the command\n\n```bash\nmake container\n```\n\nIf you are using a local cluster (e.g Kind or Minikube, ) the `grafana/k6-chaos` available in the cluster where the test application will run. \n\nIf using `kind` the following command make the image in the cluster\n\n```\nkind load docker-image grafana/k6-chaos`\n```\n\nIf using `minikube` the following command makes the image available in the cluster:\n\n```bash\nminikube image load grafana/k6-chaos\n```\n\n## Kill pod in a deployment\n\nThe [kill-deployment-pod.js example](examples/kill-deployment-pod.js) shows how `PodDisruptor` can be used for testing the effect of killing an instance of a deloyment. When executed, we can see how the requests are momentarely affected until the pod is restarted:\n\n\n```bash\nWARN[0024] Request Failed                                error=\"Get \\\"http://172.18.255.200\\\": dial tcp 172.18.255.200:80: connect: connection refused\"\nWARN[0024] Request Failed                                error=\"Get \\\"http://172.18.255.200\\\": dial tcp 172.18.255.200:80: connect: connection refused\"\nWARN[0025] Request Failed                                error=\"Get \\\"http://172.18.255.200\\\": dial tcp 172.18.255.200:80: connect: connection refused\"\nWARN[0026] Insufficient VUs, reached 100 active VUs and cannot initialize more  executor=constant-arrival-rate scenario=load\nWARN[0026] Request Failed                                error=\"Get \\\"http://172.18.255.200\\\": dial tcp 172.18.255.200:80: connect: connection refused\"\nWARN[0030] Request Failed                                error=\"Get \\\"http://172.18.255.200\\\": dial tcp 172.18.255.200:80: connect: no route to host\"\nWARN[0030] Request Failed                                error=\"Get \\\"http://172.18.255.200\\\": dial tcp 172.18.255.200:80: connect: no route to host\"\n\nrunning (01m34.0s), 000/101 VUs, 8831 complete and 0 interrupted iterations\nload  ✓ [======================================] 000/100 VUs  1m30s           100.00 iters/s\ndelay ✓ [======================================] 1 VUs        00m10.0s/10m0s  1/1 shared iters\n\n     ✗ successful request\n      ↳  99% — ✓ 8824 / ✗ 6\n\n```\n\n## Introduce disruptions in http connections to pod\n\nThe [disrupt-http.js example](examples/disrupt-http.js) shows how `PodDisruptor` can be used for testing the effect of disruptions in the http requests served by an instance of a deloyment. The example uses a deployment of the `httpbin`. The initial setup makes each request to take `100ms`. When executed without any disruption the statistics looks like this.\n\n```\nhttp_req_duration..............: avg=101.66ms min=100.59ms med=101.69ms max=107.24ms p(90)=102.22ms p(95)=102.36ms\n```\n\nWhen the disruption of an additional `100ms` delay and an error rate of 10% of requests is introduced for a period of `30s`, we can see how the statistics are affected (in particular, `p(90)` and `p(95)`):\n\n```bash\n     http_req_duration..............: avg=148.96ms min=100.39ms med=104.44ms max=324.18ms p(90)=205.17ms p(95)=205.58ms\n```\nAlso the statistics show a number of failed requests:\n```\n http_req_failed................: 5.01%  ✓ 300       ✗ 5686\n```\n\u003e Notice we requested an error rate of 0.1 (10%) but we are only applying if for 30s, therefore with respect of the total number of request, only 5% fail.\n\n## Introduce delay in network\n\nThe [delay-pod.js example](examples/delay-pod.js) shows how `PodDisruptor` can be used for testing the effect of delays in the traffic from an instance of a deloyment. The example uses a deployment of the `httpbin`. The initial setup makes each request to take `100ms`. When executed without any disruption the statistics looks like this.\n\n```\nhttp_req_duration..............: avg=101.66ms min=100.59ms med=101.69ms max=107.24ms p(90)=102.22ms p(95)=102.36ms\n```\n\nWhen the disruption of an additional `200ms` delay is introduced for a period of `30s`, we can see how the stastics are affected (in particular, `p(90)` and `p(95)`):\n\n```bash\n     http_req_duration..............: avg=126.21ms min=100.52ms med=101.7ms  max=952.95ms p(90)=301.28ms p(95)=301.8ms \ns\n```\n\n## Http disruptions in a microservices application\n\nThe [disrupt-shop.js example](examples/disrupt-shop.js) shows a script that tests the effect of http failures or delays in a microservice of the [Sock Shop application](https://github.com/microservices-demo/microservices-demo). This application is a polyglot microservices-based application that implements a fully functional e-Commerce site. \n\n![Architecture diagram](https://raw.githubusercontent.com/microservices-demo/microservices-demo.github.io/HEAD/assets/Architecture.png)Source: [Microservices Demo Design](https://github.com/microservices-demo/microservices-demo/blob/master/internal-docs/design.md)\n\nIt  offers a web interface that allows users to register, browse the catalog, and buy items.\n![Web store](https://github.com/microservices-demo/microservices-demo.github.io/raw/0ac7e0e579d83ce04e14f3b0942f7a463b72da74/assets/sockshop-frontend.png)\n\nEach microservice has its own API that can be accessed directly by means of their corresponding Kubernetes services. The front-end service also [exposes all these apis](https://github.com/microservices-demo/front-end/tree/master/api). Therefore all APIS can be accessed by means of the front-end's Kubernetes service.\n\n### Deployment\n\nThe Socks Shop application can be [deployed in Kubernetes](https://github.com/microservices-demo/microservices-demo/tree/master/deploy/kubernetes#installing-sock-shop-on-kubernetes).\n\n\n\u003e The application is deployed in the `sock-shop` namespace. The following examples assume you have set the default namespace accordingly with the command `kubectl config set-context --current --namespace sock-shop`\n\nThe default deployment exposes all microservices as `ClusterIP` services and therefore are not accessible from outside the cluster.\n\n```console\n$ kubectl get svc\nNAME           TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)             AGE\ncarts          ClusterIP      10.96.116.20    \u003cnone\u003e           80/TCP              1h\ncarts-db       ClusterIP      10.96.205.210   \u003cnone\u003e           27017/TCP           1h\ncatalogue      ClusterIP      10.96.242.206   \u003cnone\u003e           80:31924/TCP        1h\ncatalogue-db   ClusterIP      10.96.49.27     \u003cnone\u003e           3306/TCP            1h\nfront-end      ClusterIP      10.96.95.228    \u003cnone\u003e           80:30001/TCP        1h\norders         ClusterIP      10.96.4.4       \u003cnone\u003e           80/TCP              1h\norders-db      ClusterIP      10.96.44.214    \u003cnone\u003e           27017/TCP           1h\npayment        ClusterIP      10.96.23.109    \u003cnone\u003e           80/TCP              1h\nqueue-master   ClusterIP      10.96.167.37    \u003cnone\u003e           80/TCP              1h\nrabbitmq       ClusterIP      10.96.252.218   \u003cnone\u003e           5672/TCP,9090/TCP   1h\nsession-db     ClusterIP      10.96.131.80    \u003cnone\u003e           6379/TCP            1h\nshipping       ClusterIP      10.96.189.187   \u003cnone\u003e           80/TCP              1h\nuser           ClusterIP      10.96.113.92    \u003cnone\u003e           80/TCP              1h\nuser-db        ClusterIP      10.96.0.236     \u003cnone\u003e           27017/TCP           1h\n```\n\n### Accessing the application from test scripts\n\n### As a LoadBalancer service\n\nIf your cluster has a [load balancer configured](#as-a-loadbalancer-service) you can expose the front-end service my changing its type to 'LoadBalancer':\n\n```bash\n\u003e kubectl patch svc front-end -p '{\"spec\": {\"type\": \"LoadBalancer\"}}'\nservice/front-end patched\n\n\u003e kubectl get svc front-end\nNAME        TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE\nfront-end   LoadBalancer   10.96.95.228   172.18.255.200   80:30001/TCP   2h\n```\nNotice now the service has an external IP assigned. This can be used for accessing it from the host machine:\n\n```\n\u003e curl -v 172.18.255.200/catalogue/3395a43e-2d88-40de-b95f-e00e1502085b | jq .\n\u003e GET /catalogue/3395a43e-2d88-40de-b95f-e00e1502085b HTTP/1.1\n\u003e Host: 172.18.255.200\n\u003e User-Agent: curl/7.81.0\n\u003e Accept: */*\n\u003e \n* Mark bundle as not supporting multiuse\n\u003c HTTP/1.1 200 OK\n\u003c X-Powered-By: Express\n\u003c set-cookie: md.sid=s%3AAv4bhwm5U-Ed2hesf6GF7ljO6J71Z86A.fqnJ8CIVShpevJXLbsf9JPfBQAYu12ZP93KePiyMcBs; Path=/; HttpOnly\n\u003c Date: Wed, 17 Aug 2022 16:37:16 GMT\n\u003c Connection: keep-alive\n\u003c Transfer-Encoding: chunked\n\u003c \n{ [293 bytes data]\n100   286    0   286    0     0  29375      0 --:--:-- --:--:-- --:--:-- 31777\n* Connection #0 to host 172.18.255.200 left intact\n{\n  \"id\": \"3395a43e-2d88-40de-b95f-e00e1502085b\",\n  \"name\": \"Colourful\",\n  \"description\": \"proident occaecat irure et excepteur labore minim nisi amet irure\",\n  \"imageUrl\": [\n    \"/catalogue/images/colourful_socks.jpg\",\n    \"/catalogue/images/colourful_socks.jpg\"\n  ],\n  \"price\": 18,\n  \"count\": 438,\n  \"tag\": [\n    \"brown\",\n    \"blue\"\n  ]\n}\n\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrafana%2Fk6-chaos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrafana%2Fk6-chaos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrafana%2Fk6-chaos/lists"}