{"id":13839419,"url":"https://github.com/vmware-tanzu/k-bench","last_synced_at":"2025-07-11T03:32:12.801Z","repository":{"id":39611611,"uuid":"256614505","full_name":"vmware-tanzu/k-bench","owner":"vmware-tanzu","description":"Workload Benchmark for Kubernetes","archived":false,"fork":false,"pushed_at":"2024-03-20T18:54:50.000Z","size":631,"stargazers_count":386,"open_issues_count":23,"forks_count":56,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-08-05T17:23:37.662Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vmware-tanzu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE-OF-CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"Roadmap","authors":null}},"created_at":"2020-04-17T21:33:48.000Z","updated_at":"2024-07-26T06:28:57.000Z","dependencies_parsed_at":"2024-01-20T21:48:11.915Z","dependency_job_id":"732e9cd8-6183-49f8-8432-a37cec7709d8","html_url":"https://github.com/vmware-tanzu/k-bench","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vmware-tanzu%2Fk-bench","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vmware-tanzu%2Fk-bench/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vmware-tanzu%2Fk-bench/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vmware-tanzu%2Fk-bench/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vmware-tanzu","download_url":"https://codeload.github.com/vmware-tanzu/k-bench/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225675073,"owners_count":17506273,"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":[],"created_at":"2024-08-04T17:00:22.379Z","updated_at":"2024-11-21T04:30:40.093Z","avatar_url":"https://github.com/vmware-tanzu.png","language":"Go","funding_links":[],"categories":["Test"],"sub_categories":[],"readme":"# K-Bench\n\n(`K-Bench`) is a framework to benchmark the control and data plane aspects of a\nKubernetes infrastructure. K-Bench provides a configurable way to prescriptively create and\nmanipulate Kubernetes resources at scale and eventually provide the relevant control plane\nand dataplane performance metrics for the target infrastructure. Example operations include\nCREATE, UPDATE, LIST, DELETE, RUN, COPY etc. on different types of `Kubernetes` resources\nincluding `Pod`, `Deployment`, `Service`, `ReplicationController`, etc.\n\nK-Bench has the following features:\n\n* It allows users to control the client side concurrency, the operations, and how these different \ntypes of operations are executed in sequence or in parallel. In particular, user can \ndefine, through a config file, a workflow of operations for supported resources. User\ncan also specify parameters such as image for `Pod`, number of replicas for `Deployment`, etc. \n* For control-plane (life-cycle management) performance, the benchmark complements the\nserver-side timing adopted in many other existing benchmarks with a client-side approach,\nbased on Kubernetes' event callback mechanism. This addressed the coarse-grained timestamp\nissue on the server-side and enhanced the measuring precision.\n* K-Bench also includes benchmarks built into it, which allows users to study the data plane \nperformance by independently scaling up and scaling out infrastructure resource usage \nin terms of compute, memory, I/O and network. The framework comes with blueprints for running \nthese benchmarks in various ways at scale to evaluate specific aspects of a K8s infrastructure.\nFor E.g., one can use the integrated dp_network_internode test to automatically place two pods\non two different K8s nodes to measure inter-pod network latency and bandwidth. \n* It supports docker compose files and convert them into Kubernetes spec files.\n* It is integrated with [Prometheus](https://github.com/coreos/kube-prometheus), which can be\nenabled by simply including prometheus configuration options in the benchmark config file. \nK-Bench also supports [Wavefront](https://www.wavefront.com), an enterprise-grade data analytic \nand monitoring platform.\n\n## Architecture\n\u003cimg src=\"documentation/kbench-overview.jpg\"\u003e\n\nThe above diagram shows an overview of the benchmark. Upon starting, a json config file\nis parsed for infrastructure and operation information. Then a sequence of _operations_\nare generated, each of which may contain a list of _actions_ such as _create_, _list_,\n_scale_, etc. The operations run one by one, optionally in a blocking manner. Actions inside\none operation, however, run in parallel with Go routines. Actions supported for different\ntypes of resources are defined in their respective _managers_. The resource managers\nalso provide metrics collection mechanism and produce [Wavefront](https://www.wavefront.com)\nconsumable data. The benchmark uses `client-go` to communicate with the `Kubernetes` cluster.\n\nK-Bench can be extremely flexible in that it allows virtually any supported actions performed\nwith user chosen parameters on selected resource objects serially, in parallel, or in a\nhybrid manner. To achieve this, a crucial problem to address is to determine how actions\nand resources are handled or partitioned by different threads. We call this workload dispatch.\nIn K-Bench,  dispatch for actions is straightforward: the configuration parser scans the\nentire config file and determines the maximum concurrency for each operation by summing up all\nthe `Count` fields of different resource types in the operation. The dispatcher spawns and\nmaintains all go routines so that corresponding actions of different types of resources in\nan operation are fully parallelized. Different actions for the same resource in the operation\nshare the same go routine and are executed in order.  To achieve dispatch for resource objects,\nK-Bench maintains two types of labels, namely `k-label` and `u-label` respectively, for each\nresource object. K-Bench assigns each go routine a TID and an operation an OID, which are also\nattached as k-label to the relevant objects. Other metadata such as resource type, app name,\nbenchmark name, etc., are also attached as k-label when a resource is created. K-Bench provides\npredefined label matching options such as MATCH_GOROUTINE, MATCH_OPERATION to select objects\ncreated by a specified routine in certain operations. Users labels passed through the\nbenchmark configuration specification are attached to resources as u-labels, which can be\nalso used for resource dispatch.\n\n## Control Plane Metrics\n\nAfter a successful run, the benchmark reports metrics (e.g., number of requests, API invoke\nlatency, throughput, etc.) for the executed operations on various resource types. One resource\ntype whose metrics need special consideration is `Pod`, as its operations are typically long-running\nand asynchronous. For `Pod` (and related resource types such as `Deployment`), we introduce\ntwo sets of metrics, server-side and client-side, to better summarize its performance from different\nperspectives. The server-side metrics design for `Pod` in K-Bench inherits the definition suggested\nby the [kubernetes sig group](https://github.com/kubernetes/community/tree/master/sig-scalability)\n(the exact way those `Pod` metrics are defined can be revealed from the density and performance\ntest in the e2e: [density_test.go](https://github.com/kubernetes/kubernetes/blob/master/test/e2e_node/density_test.go)).\nThe client-side set of metrics, collected by an event callback mechanism, is a more accurate\nreflection on the time taken for `Pod` states to transition end-to-end. The below table describes all\nthe supported metrics:\n \n\n| Metric [^1] |  Definition | Applied Resource Type  | Notes \u0026 References \u0026 Sources |\n| ------ | ------ | ------ | ------ |\n| Pod creation latency (server) | *scheEvent.FirstTimestamp* (the FirstTimestamp of a scheduling event associated with a pod) - *pod.CreationTimestamp* (the CreationTimestamp of the pod object) | Pod Deployment | [density.go](https://github.com/kubernetes/kubernetes/blob/master/test/e2e_node/density_test.go) |\n| Pod scheduling latency (server) | *pod.Status.StartTime* (the server timestamp indicating when a pod is accepted by kubelet but image not pulled yet) - *scheEvent.FirstTimestamp* (the first timestamp of a scheduled event related to a pod) | Pod Deployment | [density.go](https://github.com/kubernetes/kubernetes/blob/master/test/e2e_node/density_test.go) |\n| Pod image pulling latency (server) | *pulledEvent.FirstTimestamp* (the FirstTimestamp of an event with \"Pulled\" as the reason associated with a pod) - *pod.Status.StartTime* (the timestamp indicating when a pod is accepted by kubelet but image not pulled yet) | Pod Deployment | a new metric defined in [pod_manager.go](./manager/pod_manager.go) for kbench |\n| Pod starting latency (server) | *max(pod.Status.ContainerStatuses[...].State.Running.StartedAt)* (the StartedAt timestamp for the last container that gets into running state inside a pod) - *pulledEvent.FirstTimestamp* (the FirstTimestamp of an event with \"Pulled\" as the reason associated with a pod) | Pod Deployment | [density.go](https://github.com/kubernetes/kubernetes/blob/master/test/e2e_node/density_test.go) |\n| Pod startup total latency (server) | *max(pod.Status.ContainerStatuses[...].State.Running.StartedAt)* (the StartedAt timestamp for the last container that gets into running state inside a pod) - *pod.CreationTimestamp* (the CreationTimestamp of the pod object) | Pod Deployment | [density.go](https://github.com/kubernetes/kubernetes/blob/master/test/e2e_node/density_test.go) |\n| Pod client-server e2e latency | *the first time when client watches that pod.Status.Phase becomes running* - *pod.CreationTimestamp* (the server-side CreationTimestamp of the pod object) | Pod Deployment | this is similar to the [\"watch\" latency in e2e test](https://github.com/kubernetes/kubernetes/blob/master/test/e2e_node/density_test.go) |\n| Pod scheduling latency (client) | *the first time when client watches that pod.Status.Conditions[...] has a PodScheduled condition* - *the first time client watches the pod* (and thus does not have a PodScheduled condition) | Pod Deployment | a new metric defined in [pod_manager.go](./manager/pod_manager.go) in kbench |\n| Pod initialization latency (client) | *the first time when client watches that pod.Status.Conditions[...] has a PodInitialized condition* - *the first time when client watches that pod.Status.Conditions[...] has a PodScheduled condition* | Pod Deployment | a new metric defined in [pod_manager.go](./manager/pod_manager.go) in kbench |\n| Pod starting latency (client) | *the first time when client watches that pod.Status.Phase becomes running* - *the first time when client watches that pod.Status.Conditions[...] has a PodInitialized condition* | Pod Deployment | a new metric defined in [pod_manager.go](./manager/pod_manager.go) **Note that there is no client-side watch event for image pulling, so this metric includes the image pulling.** |\n| Pod startup total latency (client) | *the first time when client watches that pod.Status.Phase becomes running* - *the first time client watches the pod* (and thus does not have a PodScheduled condition) | Pod Deployment | a new metric defined in [pod_manager.go](./manager/pod_manager.go) |\n| Pod creation throughput | *sum(number of running pods of every operation that has pod actions / 2)* / *sum(median Pod startup total latency of every operation that has pod actions)* | Pod Deployment | a new metric defined in [pod_manager.go](./manager/pod_manager.go). |\n| API invoke latency | *latency for an API to return* | All resource types | a new metric defined in [pod_manager.go](./manager/pod_manager.go). |\n\n[^1]: For each latency related metric, there are four values reported: median, min, max, and 99-percentile.\n\n## Data Plane Workloads and Metrics\n\n| Metric [^1] |  Resource Category | Benchmark  | Notes |\n| ------ | ------ | ------ | ------ |\n| Transaction throughput | CPU/Memory | Redis Memtier | Maximum achievable throughput aggregated across pods in a cluster| \n| Transaction latency | CPU/Memory | Redis Memtier | Latency for the injected SET/GET transactions |\n| Pod density | CPU/Memory | Redis Memtier | Transaction throughput and latency for given pod density |\n| I/O bandwidth (IOPS) | I/O | FIO | Synchronous and Asynchronous Rd/Wr bandwidth for 70-30, 100-0 and 0-100 read-write ratios, block sizes on various K8s volumes |\n| I/O Latency (ms) | I/O | Ioping | Disk I/O latency on Ephemeral and Persistent K8s volumes |\n| Network b/w | Network | Iperf3 | Inter-pod TCP, UDP performance with varying pod placements on nodes, zones |\n| Network Latency (ms) | Network | Qperf | Inter-pod network latency for TCP and UDP packets with varying pod placements |\n\n## Infrastructure Diagnostic Telemetry\n\nIn addition to the above metrics that the benchmark reports, K-Bench can be configured to report\nWavefront- and Prometheus-defined metrics that include: memory, CPU, storage utilization of nodes,\nnamespaces, pods, cluster level statistics, bytes transferred and received rates between pods, uptime,\ninfrastructure statistics, etc.\n\nTo use Wavefront monitoring of the nodes, one can install the Waverunner component using pkg/waverunner/install.sh.\nInvoking this script without any parameters will give the help menu. To start telemetry, invoke pkg/waverunner/WR_wcpwrapper.sh as follows:\n\n```\n./WR_wcpwrapper.sh -r \u003crun_tag\u003e -i \u003cHost_IP_String\u003e -w \u003cWavefront_source\u003e [-o \u003coutput_folder\u003e -k \u003cssh_key_file\u003e -p \u003chost_passwd\u003e]\n```\n\nThe above command defaults to /tmp for output folder and a null host password.\n\nTo use Prometheus as your metrics monitoring mechanism, configure the _PrometheusManifestPaths_  option in\nthe K-Bench config file. Please see [top level configuration options](#top-level-configuration-options) section\nbelow and [prometheus readme](./pkg/prometheus/README.md).\n\n## K-Bench Quickstart Guide\n\nTo use K-Bench, clone this repo, install the benchmark, and then you can use it to run workload against\nyour k8s cluster by following the below instructions.\n\n### Install using Script\n\nOn a Linux box (tested on Ubuntu 16.04), just invoke:\n\n```\n./install.sh\n```\n\nto install the benchmark. \n\nIf you would like the kbench binary to be copied to /usr/local/bin so that you can directly run\nwithout specifying the full kbench path, run it with _sudo_.\n\nOn systems like Ubuntu, just being able to use sudo is enough and one does not explicitly need to be the \"root\" user. Also, please ensure that the K8s nodes and the client on which you run K-Bench have their times synchronized as K-Bench uses both client and server side time stamps to calculate latencies.\n\n### Run the Benchmark\n\nOnce the installation completes, you can start using K-Bench. To run the benchmark, you need to make sure your \n\n_~/.kube/config_ file or the KUBECONFIG environment variable points to a valid and running `Kubernetes` cluster. To verify this, you may install \n kubectl (this expects a ~/.kube/config file in place, which you can copy from the Master node) and simply run:\n\n\n```\nkubectl get nodes\n```\nOnce you verify that you have a running `Kubernetes` cluster, the workload can be run directly using the kbench go binary or using the run.sh script. The default benchmark config file ./config/default/config.json specifies the workload you would like to run. You can modify the config file to run workload of your choice. After that, simply run:\n\n```\nkbench\n```\nor\n```\n./run.sh\n```\n\nIf your config file is at a different location, please use _-benchconfig_ option if invoking the kbench binary directly:\n```\nkbench -benchconfig filepath\n```\nIf your filepath is a directory, the benchmark will run them one by one.\n\nWhen using the run.sh script, invoking this script with -h provides the following help menu:\n\n```\nUsage: ./run.sh -r \u003crun-tag\u003e [-t \u003ccomma-separated-tests\u003e -o \u003coutput-dir\u003e]\nExample: ./run.sh -r \"kbench-run-on-XYZ-cluster\"  -t \"cp_heavy16,dp_netperf_internode,dp_fio\" -o \"./\"\n\nValid test names:\n\nall || all_control_plane || all_data_plane || cp_heavy_12client || cp_heavy_8client || cp_light_1client || cp_light_4client || default || dp_fio || dp_network_internode || dp_network_interzone || dp_network_intranode || dp_redis || dp_redis_density || predicate_example || \n\n```\n\nTo get details about each of the existing workloads, please check the individual README or config.json in config/\\\u003ctest-name\\\u003e folder.  For more details about how to configure workload, please check the examples under the ./config directory, or read the _benchmark configuration_ section of this document. \n \n### Adding a new test to use with run.sh\nAdd a new folder in config/\\\u003ctest-name\\\u003e, include the run configuration as config/\\\u003ctest-name\\\u003e/config.json and run the test by providing the \\\u003ctest-name\\\u003e as input to the -t option of run.sh\n\n\n### Alternative Installing Method: Install Manually with Go (old way with GOROOT and GOPATH)\n\nFirst, you need to setup your `Go` environment. Download `Go` and unzip it to a local directory\n(e.g., _/root/go_) and point your `GOROOT` environment variable there. Also, set your `GOPATH`\n(e.g., _/root/gocode_). The below instructions are example for your reference (assuming you download\n`Go` to _/root/go_):\n\n```\ncd /root/go\n\ngunzip go***.linux-amd64.tar.gz\n\ntar -xvf go***.linux-amd64.tar\n\nmkdir /root/gocode \u0026\u0026 cd gocode/\n\nexport GOPATH=/root/gocode\n\nexport GOROOT=/root/go\n\nexport PATH=$PATH:/root/go/bin\n```\n\nClone or download benchmark source code to _$GOPATH/src/k-bench_ (create this directory if it\ndoes not exist) using `Git` or through other means.\n\n```\nmkdir -p $GOPATH/src\n\nmkdir -p $GOPATH/src/k-bench\n\n```\nAfter you have all the files under _$GOPATH/src/k-bench_, _cd_ to that directory.\n\nIt is also handy to include into your _PATH_ variable locations where `Go` typically places and\nfinds binaries and tools:\n\n```\nexport PATH=$PATH:$GOROOT/bin:$GOPATH/bin\n```\nNow, you are ready to build the benchmark. To build, you can either use the below command to\ninstall the `kbench` binary into _$GOPATH/bin_:\n\n```\ngo install cmd/kbench.go\n```\nor run (under the _$GOPATH/src/k-bench_ directory) the below to generate the `kbench` executable\nunder _$GOPATH/src/k-bench/bin_:\n\n```\nmkdir -p bin \u0026\u0026 cd bin \u0026\u0026 go build k-bench/cmd/kbench.go\n```\n\n## Benchmark Configuration\nThe benchmark is highly configurable through a json config file. The ./config/default/config.json file is\nprovided as an example (this file is also the default benchmark config file if user does not specify\none through the _-benchconfig_ option). More config examples can be found under the ./config directory\nand its subdirectories.\n\n### Top Level Configuration Options\nAt top level, the benchmark supports the following configuration options:\n\n* _BlockingLevel_: Currently can be configured as \"operation\", so that the benchmark waits (for pod\ncreation and deletion) until the previous operation is completely done before executing the next. If\nthis option is not specified, the benchmark only waits the specified sleep time after each action and\nthen proceeds to the next operation, even if there are outstanding actions in the previous operation.\n* _Timeout_: Used with BlockingLevel. This is the longest time in mini-seconds for the benchmark to\nwait after each operation if BlockingLevel is specified. By default it is 3 minutes.\n* _CheckingInterval_: The time interval in mini-seconds to check whether all the actions in the previous\noperation complete. By default it is 3 seconds.\n* _Cleanup_: Whether clearing all the created resources after a run completes. By default it is false.\n* _Operations_: This is an array of operation structures, each of which can contain a list of resource\naction configurations. Each resource action configuration includes information such as resource type,\nactions (a list of actions to be performed in order), count (number of actions to be executed in parallel),\nsleeptimes (time to sleep after each parallel batch of actions), image to use, etc. For details please\nrefer to below [Operation Configuration](#operation-configuration).\n* _RuntimeInMinutes_: The time in minutes that benchmark should run. If all the configured operations\nare completed but time elapsed hasn't reached the specified time, the benchmark will loop over and run\nthe configured operations again.\n* _PrometheusManifestPaths_: This option, if configured, installs and enables prometheus stack for cluster \nmonitoring. See [prometheus readme](./pkg/prometheus/README.md) for details.\n* _WavefrontPathDir_: This option tells the benchmark where to store Wavefront output logs.\n* _SleepTimeAfterRun_: In case user wants to add sleep time after each run, this is the option to use.\n* _Tags_: If specified, the wavefront output and logs will be tagged with the given keys and values.\n\n### Operation Configuration\nIn each operation of the _\"Operations\"_ array, users can specify one or more resource types, and each\nresource type can have a list of actions to perform, and each action may accept some options. Below\nare example (and a subset of all supported) resource types with the corresponding actions and options:\n\n* _Pods_: Pod resource supports \"CREATE\", \"LIST\", \"GET\", \"RUN\", \"COPY\", \"UPDATE\", and \"DELETE\" actions.\nFor the CREATE action, users can specify operation options including \"ImagePullPolicy\" (where you can\nspecify one of \"IfNotPresent\", \"Always\", and \"Never\"), \"Image\", etc. Also, if user specifies a \"YamlSpec\"\noption, then the CREATE action will first try to use the yaml file to create the Pod before using other\nexplicit options such as \"ImagePullPolicy\" and \"Image\". For the RUN action, user can provide the \"Command\"\noption, which is the command to be executed in the specified Pod(s). For COPY action, user can specify\nLocalPath, ContainerPath, and Upload options. Certain Pod actions (LIST, RUN, COPY) can be applied to a\nselected/filtered list of Pods using the LabelKey and LabelValue options. For all pod actions, \"Count\"\noption specifies the concurrency and \"SleepTime\" specifies the sleep time user would like to incur after\neach action.\n* _Deployments_: Deployment resource type supports all the options that Pod does, and in addition it\nalso supports \"SCALE\" action and \"NumReplicas\" option for its CREATE action. Currently it does not\nsupport \"RUN\" and \"COPY\" action yet.\n* _Namespaces_: Namespace resource type supports \"CREATE\", \"LIST\", \"GET\", \"UPDATE\", and  \"DELETE\"\nactions. It has \"Count\" option (number of namespace actions to be performed in parallel), similar to\nall the above resource types.\n* _Services_: Service resource type supports \"CREATE\", \"LIST\", \"GET\", \"UPDATE\", and \"DELETE\" actions.\nIt has \"SleepTimes\", \"Count\", and \"YamlSpec\" options.\n* _ReplicationControllers_: ReplicationController resource type supports the same options and actions\nas Deployment.\n\nThe benchmark also supports other resource types including _ConfigMap, Event, Endpoints, ComponentStatus,\nNode, LimitRange, PersistentVolume, PersistentVolumeClaim, PodTemplate, ResourceQuota, Secret, ServiceAccount,\nRole, RoleBinding, ClusterRole, ClusterRoleBinding_, etc.\n\nIn addition to different types of resource types, in an operation you can also specify a _RepeatTimes_\noption to run the operation for a given number of times.\n\nFor more supported resources, actions, and configuration options in K-Bench, please checkout the sample\nconfig files under ./config or source code.\n\n### Operation Predicate\nTo simplify synchronization and orchestrate operation execution flow, the benchmark supports _Predicate_,\nwhich blocks an operation's execution until certain conditions are met. A predicate is configured through\nthe below options:\n\n* _Resource_: It has two possible formats:  _namespace/kind/[object name/][container name]_, or\n_group/version/namespaces/namespace/kind/[object name/][container name]_.  With the first format, \nyou specify a namespace, a kubernetes resource kind, optionally with an object name and a container name\n(only valid if the resource kind is Pod). The benchmark will search resources with default kubernetes\ngroup (\"\") and API version (v1). With the second format, the benchmark will search resource using the\ngiven group, kind, and version. Once this predicate (called a resource predicate) is specified, the\nmatched resource must exist before the operation can be executed. If a container name is specified, the \ncorresponding pod has to be in _Running_ phase in order for the operation to proceed.\n* _Labels_: Labels has format of _key1=value1;key2=value2;..._. Labels are used if only namespace and kind\nare given in the _Resource_ option to filter resource objects.\n* _Command_: This predicate executes a command (inside the container if a container name is specified\nin the _Resource_ option, or on the box where the bencmark is invoked). It works with _Expect_ below.\n* _Expect_: This option currently supports formats such as _contains:string_ or _!contains:string_. With\nthis option configured, the benchmark checks the output of the Command execution, and proceed only if\nthe output is expected.\n\nFor examples on how to use predicates, you may check config file samples under ./config/predicate\\_example.\n\n## Contributing to the Benchmark \n\nPlease contact the project members and read CONTRIBUTING.md if you are interested in making contributions.\n\n## Project Leads\nKarthik Ganesan\nEmail: ganesank@vmware.com for questions and comments\n\n## Contributors\nYong Li \nHelen Liu\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvmware-tanzu%2Fk-bench","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvmware-tanzu%2Fk-bench","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvmware-tanzu%2Fk-bench/lists"}