Add New Chaos Experiment Type

    The following walks you through an example of HelloWorldChaos, a new chaos experiment type that prints Hello World! to the log. The steps include:

    • Step 1: Define the schema type
    • Step 2: Register the CRD
    • Step 3: Register the event handler for this chaos object
    • Step 4: Build the Docker image
    • Step 5: Run the chaos experiment
    1. Add helloworldchaos_types.go in the API directory api/v1alpha1 with the following content:

      This file defines the schema type of HelloWorldChaos, which can be described in a YAML file:

      1. apiVersion: chaos-mesh. rg/v1alpha1
      2. kind: HelloWorldChaos
      3. metadata:
      4. name: <resource name>
      5. name: <namespace>
      6. spec:
      7. duration: <duration>
      8. status:
      9. experiment: <experimental status>
      10. ...
    2. Run make generate in the root directory of Chaos Mesh, which generates a boilerplate for Chaos Mesh to compile.

    Step 2: Register the CRD

    You need to register the CRD (Custom Resource Definition) of HelloWorldChaos to interact it with Kubernetes API.

    1. Run make yaml in the root directory. The generated YAML file is at config/crd/bases/chaos-mesh.org_helloworldchaos.yaml.

    2. To combine this YAML file into manifests/crd.yaml, add a new line in config/crd/kustomization.yaml:

      1. resources:
      2. - bases/chaos-mesh.org_podchaos.yaml
      3. - bases/chaos-mesh.org_networkchaos.yaml
      4. - bases/chaos-mesh.org_iochaos.yaml
      5. - bases/chaos-mesh.org_helloworldchaos.yaml # This is the new line
    3. Run make yaml again. You can see the definition of HelloWorldChaos in manifests/crd.yaml. To confirm, you can use the git diff command.

    1. Create a new file controllers/chaosimpl/helloworldchaos/types.go with the following content:

      1. package helloworldchaos
      2. import (
      3. "context"
      4. "github.com/go-logr/logr"
      5. "go.uber.org/fx"
      6. "sigs.k8s.io/controller-runtime/pkg/client"
      7. "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
      8. "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/utils"
      9. "github.com/chaos-mesh/chaos-mesh/controllers/common"
      10. "github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon"
      11. )
      12. type Impl struct {
      13. client.Client
      14. Log logr.Logger
      15. }
      16. // This corresponds to the Apply phase of HelloWorldChaos. The execution of HelloWorldChaos will be triggered.
      17. func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) {
      18. impl.Log.Info("Hello world!")
      19. }
      20. // This corresponds to the Recover phase of HelloWorldChaos. The reconciler will be triggered to recover the chaos action.
      21. func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) {
      22. impl.Log.Info("Goodbye world!")
      23. return v1alpha1.NotInjected, nil
      24. }
      25. func NewImpl(c client.Client, log logr.Logger, decoder *utils.ContainerRecordDecoder) *common.ChaosImplPair {
      26. return &common.ChaosImplPair{
      27. Name: "helloworldchaos",
      28. Object: &v1alpha1.HelloWorldChaos{},
      29. Impl: &Impl{
      30. Client: c,
      31. Log: log.WithName("helloworldchaos"),
      32. decoder: decoder,
      33. },
      34. ObjectList: &v1alpha1.HelloWorldChaosList{},
      35. }
      36. }
      37. var Module = fx.Provide(
      38. fx.Annotated{
      39. Group: "impl",
      40. Target: NewImpl,
      41. },
      42. )
    2. Chaos Mesh uses the fx library for dependency injection. To register HelloWorldChaos in the Controller Manager, add a line in controllers/chaosimpl/fx.go:

      1. ...
      2. gcpchaos.Module,
      3. stresschaos.Module,
      4. jvmchaos.Module,
      5. timechaos.Module,
      6. helloworldchaos.Module //Add a new line. Make sure you have imported HelloWorldChaos to this file first.
      1. ...
      2. fx.Annotated{
      3. Group: "objs",
      4. Target: Object{
      5. Name: "timechaos",
      6. Object: &v1alpha1.TimeChaos{},
      7. },
      8. },
      9. fx.Annotated{
      10. Group: "objs",
      11. Name: "gcpchaos",
      12. Object: &v1alpha1.GCPChaos{},
      13. },
      14. },
      15. fx.Annotated{
      16. Group: "objs",
      17. Target: Object{
      18. Name: "helloworldchaos",
      19. Object: &v1alpha1.HelloWorldChaos{},
      20. },
      21. },

    Step 4: Build the Docker image

    1. Build the Docker image:

    2. Push the image to your local Docker Registry:

      1. make docker-push
    3. If you deploy Kubernetes clusters using kind, then you need to load images into kind:

      1. kind load docker-image localhost:5000/chaos-mesh/chaos-mesh:latest
      2. kind load docker-image localhost:5000/chaos-mesh/chaos-daemon:latest
      3. kind load docker-image localhost:5000/chaos-mesh/chaos-dashboard:latest

    In this step, you need to deploy Chaos Mesh with your latest changes to test HelloWorldChaos.

    Before you pull any image for Chaos Mesh (using helm install or helm upgrade), modify the helm template helm/chaos-mesh/values.yaml to replace the default image with what you just pushed to your local Docker registry.

    The templates in Chaos Mesh use chaos-mesh/chaos-mesh:latest as the default Registry. You need to set the path with the environment variable of DOCKER_REGISTRY (The default value is localhost:5000), as shown below:

    1. controllerManager:
    2. image: localhost:5000/chaos-mesh/chaos-mesh:latest
    3. ...
    4. chaosDaemon:
    5. image: localhost:5000/chaos-mesh/chaos-daemon:latest
    6. ...
    7. dashboard:
    8. image: localhost:5000/chaos-mesh/chaos-dashboard:latest
    9. ...

    After you update the template, try running HelloWorldChaos.

    1. Register the CRD in your cluster:

      1. kubectl create -f manifests/crd.yaml

      You can see HelloWorldChaos is created from the output:

      1. customresourcedefinition.apiextensions.k8s.io/helloworldchaos.chaos-mesh.org created

      Now you can get the CRD of HelloWorldChaos using the command below:

    2. To verify the deployment is successful, you can check all Pods in the chaos-testing namespace:

      1. kubectl get pods --namespace chaos-testing -l app.kubernetes.io/instance=chaos-mesh
      Arguments --set chaosDaemon.runtime=containerd --set chaosDaemon.socketPath=/run/containerd/containerd.sock are used to run NeteworkChaos on kind. :::
    3. Deploy the Pod for testing:

      1. kubectl apply -f https://raw.githubusercontent.com/chaos-mesh/apps/master/ping/busybox-statefulset.yaml

      Make sure the Pod for testing works properly.

    4. Create a chaos.yaml file in any location with the following content:

      1. apiVersion: chaos-mesh.org/v1alpha1
      2. kind: HelloWorldChaos
      3. metadata:
      4. name: hello-world
      5. namespace: chaos-testing
      6. spec:
      7. selector:
      8. namespaces:
      9. - busybox
      10. mode: one
      11. duration: 1h
    5. Run the chaos experiment:

      1. kubectl apply -f /path/to/chaos.yaml
      1. kubectl get HelloWorldChaos -n chaos-testing

      Now you can see Hello World! in the logs of chaos-controller-manager:

      Example output:

      1. 2021-06-24T06:42:26.858Z INFO records apply chaos {"id": "chaos-testing/chaos-daemon-vsmc5"}

      :::note {pod-post-fix} is a random string generated by Kubernetes. You can check it by executing . :::

    What’s Next

    If you encounter any problems during the process, create an issue in the Chaos Mesh repository.

    If you want to dive deep into developing new chaos experiment types, see .