<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Usage on Grafana Labs</title><link>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/</link><description>Recent content in Usage on Grafana Labs</description><generator>Hugo -- gohugo.io</generator><language>en</language><atom:link href="/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/index.xml" rel="self" type="application/rss+xml"/><item><title>Run k6 scripts with TestRun CRD</title><link>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/executing-k6-scripts-with-testrun-crd/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/executing-k6-scripts-with-testrun-crd/</guid><content><![CDATA[&lt;h1 id=&#34;run-k6-scripts-with-testrun-crd&#34;&gt;Run k6 scripts with TestRun CRD&lt;/h1&gt;
&lt;p&gt;This guide covers how you can configure your k6 scripts to run using the k6 Operator.&lt;/p&gt;
&lt;h2 id=&#34;defining-test-scripts&#34;&gt;Defining test scripts&lt;/h2&gt;
&lt;p&gt;There are several ways to configure scripts in the &lt;code&gt;TestRun&lt;/code&gt; CRD. The operator uses &lt;code&gt;configMap&lt;/code&gt;, &lt;code&gt;volumeClaim&lt;/code&gt; and &lt;code&gt;localFile&lt;/code&gt; to serve test scripts to the jobs.&lt;/p&gt;
&lt;h3 id=&#34;configmap&#34;&gt;ConfigMap&lt;/h3&gt;
&lt;p&gt;The main way to configure a script is to create a &lt;code&gt;ConfigMap&lt;/code&gt; with the script contents:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl create configmap my-test --from-file /path/to/my/test.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then specify it in &lt;code&gt;TestRun&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;  script:
    configMap:
      name: my-test
      file: test.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;A single &lt;code&gt;ConfigMap&lt;/code&gt; has a character limit of 1048576 bytes. If you need to have a larger test file, you have to use a &lt;code&gt;volumeClaim&lt;/code&gt; or a &lt;code&gt;localFile&lt;/code&gt; instead.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;volumeclaim&#34;&gt;VolumeClaim&lt;/h3&gt;
&lt;p&gt;If you have a PVC with the name &lt;code&gt;stress-test-volumeClaim&lt;/code&gt; containing your script and any other supporting files, you can pass it to the test like this:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;spec:
  script:
    volumeClaim:
      name: &amp;#39;stress-test-volumeClaim&amp;#39;
      # test.js should exist inside /test/ folder.
      # All the js files and directories test.js is importing
      # should be inside the same directory as well.
      file: &amp;#39;test.js&amp;#39;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The pods will expect to find the script files in the &lt;code&gt;/test/&lt;/code&gt; folder. If &lt;code&gt;volumeClaim&lt;/code&gt; fails, that&amp;rsquo;s the first place to check. The latest initializer pod doesn&amp;rsquo;t generate any logs and when it can&amp;rsquo;t find the file, it exits with an error. Refer to &lt;a href=&#34;https://github.com/grafana/k6-operator/issues/143&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;this GitHub issue&lt;/a&gt; for potential improvements.&lt;/p&gt;
&lt;h4 id=&#34;sample-directory-structure&#34;&gt;Sample directory structure&lt;/h4&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;├── test
│   ├── requests
│   │   ├── stress-test.js
│   ├── test.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In the preceding example, &lt;code&gt;test.js&lt;/code&gt; imports a function from &lt;code&gt;stress-test.js&lt;/code&gt; and these files would look like this:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;js&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-js&#34;&gt;// test.js
import stressTest from &amp;#39;./requests/stress-test.js&amp;#39;;

export const options = {
  vus: 50,
  duration: &amp;#39;10s&amp;#39;,
};

export default function () {
  stressTest();
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;js&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-js&#34;&gt;// stress-test.js
import { sleep, check } from &amp;#39;k6&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

export default () =&amp;gt; {
  const res = http.get(&amp;#39;https://quickpizza.grafana.com&amp;#39;);
  check(res, {
    &amp;#39;status is 200&amp;#39;: () =&amp;gt; res.status === 200,
  });
  sleep(1);
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;localfile&#34;&gt;LocalFile&lt;/h3&gt;
&lt;p&gt;If the script is present in the filesystem of a custom runner image, it can be accessed with the &lt;code&gt;localFile&lt;/code&gt; option:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;spec:
  parallelism: 4
  script:
    localFile: /test/test.js
  runner:
    image: &amp;lt;custom-image&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;If there is any limitation on the usage of &lt;code&gt;volumeClaim&lt;/code&gt; in your cluster, you can use the &lt;code&gt;localFile&lt;/code&gt; option. We recommend using &lt;code&gt;volumeClaim&lt;/code&gt; if possible.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;multi-file-tests&#34;&gt;Multi-file tests&lt;/h3&gt;
&lt;p&gt;In case your k6 script is split between multiple JavaScript files, you can create a &lt;code&gt;ConfigMap&lt;/code&gt; with several data entries like this:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl create configmap scenarios-test --from-file test.js --from-file utils.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If there are too many files to specify manually, using &lt;code&gt;kubectl&lt;/code&gt; with a folder might be an option as well:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl create configmap scenarios-test --from-file=./test&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Alternatively, you can create an archive with k6:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 archive test.js [args]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;k6 archive&lt;/code&gt; command creates an &lt;code&gt;archive.tar&lt;/code&gt; in your current folder. You can then use that file in the &lt;code&gt;configmap&lt;/code&gt;, similarly to a JavaScript script:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl create configmap scenarios-test --from-file=archive.tar&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you use an archive, you must edit your YAML file for the &lt;code&gt;TestRun&lt;/code&gt; deployment so that the &lt;code&gt;file&lt;/code&gt; option is set to the correct entrypoint for the &lt;code&gt;k6 run&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;# ...
spec:
  script:
    configMap:
      name: &amp;#39;crocodile-stress-test&amp;#39;
      file: &amp;#39;archive.tar&amp;#39; # &amp;lt;-- change here&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;run-tests&#34;&gt;Run tests&lt;/h2&gt;
&lt;p&gt;Tests are executed by applying the custom resource &lt;code&gt;TestRun&lt;/code&gt; to a cluster where the k6 Operator is running. Additional optional properties of the &lt;code&gt;TestRun&lt;/code&gt; CRD allow you to control some key aspects of a distributed execution. For example:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;# k6-resource.yml

apiVersion: k6.io/v1alpha1
kind: TestRun
metadata:
  name: k6-sample
spec:
  parallelism: 4
  script:
    configMap:
      name: k6-test
      file: test.js
  separate: false
  runner:
    image: &amp;lt;custom-image&amp;gt;
    metadata:
      labels:
        cool-label: foo
      annotations:
        cool-annotation: bar
    securityContext:
      runAsUser: 1000
      runAsGroup: 1000
      runAsNonRoot: true
    resources:
      limits:
        cpu: 200m
        memory: 1000Mi
      requests:
        cpu: 100m
        memory: 500Mi
  starter:
    image: &amp;lt;custom-image&amp;gt;
    metadata:
      labels:
        cool-label: foo
      annotations:
        cool-annotation: bar
    securityContext:
      runAsUser: 2000
      runAsGroup: 2000
      runAsNonRoot: true&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A &lt;code&gt;TestRun&lt;/code&gt; CR is created with this command:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl apply -f /path/to/your/k6-resource.yml&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;clean-up-resources&#34;&gt;Clean up resources&lt;/h2&gt;
&lt;p&gt;After completing a test run, you need to clean up the test jobs that were created:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl delete -f /path/to/your/k6-resource.yml&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Alternatively, you can configure the automatic deletion of all resources with the &lt;code&gt;cleanup&lt;/code&gt; option:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;spec:
  cleanup: &amp;#39;post&amp;#39;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With the &lt;code&gt;cleanup&lt;/code&gt; option set, k6 Operator removes the &lt;code&gt;TestRun&lt;/code&gt; CRD and all created resources once the test run ends.&lt;/p&gt;
]]></content><description>&lt;h1 id="run-k6-scripts-with-testrun-crd">Run k6 scripts with TestRun CRD&lt;/h1>
&lt;p>This guide covers how you can configure your k6 scripts to run using the k6 Operator.&lt;/p>
&lt;h2 id="defining-test-scripts">Defining test scripts&lt;/h2>
&lt;p>There are several ways to configure scripts in the &lt;code>TestRun&lt;/code> CRD. The operator uses &lt;code>configMap&lt;/code>, &lt;code>volumeClaim&lt;/code> and &lt;code>localFile&lt;/code> to serve test scripts to the jobs.&lt;/p></description></item><item><title>Use k6 Operator with k6 extensions</title><link>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/extensions/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/extensions/</guid><content><![CDATA[&lt;h1 id=&#34;use-k6-operator-with-k6-extensions&#34;&gt;Use k6 Operator with k6 extensions&lt;/h1&gt;
&lt;p&gt;By default, the k6 Operator uses &lt;code&gt;ghcr.io/grafana/k6-operator:latest-runner&lt;/code&gt; as the container image for the test jobs.&lt;/p&gt;
&lt;p&gt;If you want to use k6 
    &lt;a href=&#34;/docs/k6/v2.3.x/extensions/&#34;&gt;extensions&lt;/a&gt; built with &lt;a href=&#34;https://github.com/grafana/xk6&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;xk6&lt;/a&gt;, you&amp;rsquo;ll need to create your own image and override the &lt;code&gt;image&lt;/code&gt; property on the &lt;code&gt;TestRun&lt;/code&gt; Kubernetes resource.&lt;/p&gt;
&lt;p&gt;For example, this is a &lt;code&gt;Dockerfile&lt;/code&gt; that builds a k6 binary with the &lt;code&gt;xk6-output-influxdb&lt;/code&gt; extension:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Dockerfile&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;# Build the k6 binary with the extension
FROM golang:1.25.1 as builder

RUN go install go.k6.io/xk6/cmd/xk6@latest

# For our example, we&amp;#39;ll add support for output of test metrics to InfluxDB v2.
# Feel free to add other extensions using the &amp;#39;--with ...&amp;#39;.
RUN xk6 build \
    --with github.com/grafana/xk6-output-influxdb@latest \
    --output /k6

# Use the operator&amp;#39;s base image and override the k6 binary
FROM grafana/k6:latest
COPY --from=builder /k6 /usr/bin/k6&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can build the image based on this &lt;code&gt;Dockerfile&lt;/code&gt; by executing:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;docker build -t k6-extended:local .&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After the build completes, you can push the resulting &lt;code&gt;k6-extended:local&lt;/code&gt; image to an image repository accessible to your Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;You can then use that image as follows:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;# k6-resource-with-extensions.yml

apiVersion: k6.io/v1alpha1
kind: TestRun
metadata:
  name: k6-sample-with-extensions
spec:
  parallelism: 4
  script:
    configMap:
      name: my-stress-test
      file: test.js
  runner:
    image: k6-extended:local
    env:
      - name: K6_OUT
        value: xk6-influxdb=http://influxdb.somewhere:8086/demo&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note that this examples overrides the default image with &lt;code&gt;k6-extended:latest&lt;/code&gt;, and it includes environment variables that are required by the &lt;code&gt;xk6-output-influxdb&lt;/code&gt; extension.&lt;/p&gt;
&lt;h2 id=&#34;troubleshooting&#34;&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;If a &lt;code&gt;TestRun&lt;/code&gt; with a custom image doesn&amp;rsquo;t start the test and the k6 Operator &lt;a href=&#34;/docs/k6/latest/set-up/set-up-distributed-k6/troubleshooting/#an-error-on-reading-output-of-the-initializer-pod&#34;&gt;logs an error about the initializer&lt;/a&gt;, run the following command:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;sh&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-sh&#34;&gt;docker run --entrypoint sh k6-extended:local -c &amp;#34;ls -l &amp;amp;&amp;amp; k6 version&amp;#34;

This command should execute without an error. If there&amp;#39;s an error, resolve it by making sure that the `Dockerfile` is correctly configured. Use the sample above as a reference.&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
]]></content><description>&lt;h1 id="use-k6-operator-with-k6-extensions">Use k6 Operator with k6 extensions&lt;/h1>
&lt;p>By default, the k6 Operator uses &lt;code>ghcr.io/grafana/k6-operator:latest-runner&lt;/code> as the container image for the test jobs.&lt;/p>
&lt;p>If you want to use k6
&lt;a href="/docs/k6/v2.3.x/extensions/">extensions&lt;/a> built with &lt;a href="https://github.com/grafana/xk6" target="_blank" rel="noopener noreferrer">xk6&lt;/a>, you&amp;rsquo;ll need to create your own image and override the &lt;code>image&lt;/code> property on the &lt;code>TestRun&lt;/code> Kubernetes resource.&lt;/p></description></item><item><title>Use the k6 Operator with Grafana Cloud k6</title><link>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/k6-operator-to-gck6/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/k6-operator-to-gck6/</guid><content><![CDATA[&lt;h1 id=&#34;use-the-k6-operator-with-grafana-cloud-k6&#34;&gt;Use the k6 Operator with Grafana Cloud k6&lt;/h1&gt;
&lt;p&gt;Grafana Cloud k6 is the Grafana Cloud offering of k6, which gives you access to all of k6 capabilities, while Grafana handles the infrastructure, storage, and metrics aggregation and insights from your tests.&lt;/p&gt;
&lt;p&gt;When using the k6 Operator, you can still leverage Grafana Cloud k6 to get access to the metric storage and analysis that the platform offers.&lt;/p&gt;
&lt;p&gt;There are two ways to use the k6 Operator with Grafana Cloud k6: Private Load Zones and Cloud output.&lt;/p&gt;
&lt;h2 id=&#34;before-you-begin&#34;&gt;Before you begin&lt;/h2&gt;
&lt;p&gt;To use the k6 Operator with Grafana Cloud k6, you’ll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;a href=&#34;/auth/sign-up/create-user&#34;&gt;Grafana Cloud account&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;private-load-zones&#34;&gt;Private Load Zones&lt;/h2&gt;
&lt;p&gt;Private Load Zones (PLZ) are load zones that you can host inside your network by using the k6 Operator. You can start a cloud test in a PLZ by referencing it by name from your script, and the test will run in the nodes of your Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;Refer to &lt;a href=&#34;/docs/grafana-cloud/testing/k6/author-run/private-load-zone-v2/&#34;&gt;Set up private load zones&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h2 id=&#34;cloud-output&#34;&gt;Cloud output&lt;/h2&gt;
&lt;p&gt;With k6, you can send the 
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/real-time/cloud/&#34;&gt;output from a test run to Grafana Cloud k6&lt;/a&gt; with the &lt;code&gt;k6 run --out cloud script.js&lt;/code&gt; command. This feature is also available in the k6 Operator if you have a Grafana Cloud account.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;The cloud output option only supports a &lt;code&gt;parallelism&lt;/code&gt; value of 20 or less.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;To use this option in k6 Operator, set the argument in YAML:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;# ...
script:
  configMap:
    name: &amp;#39;&amp;lt;configmap&amp;gt;&amp;#39;
arguments: --out cloud
# ...&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then, if you installed operator with bundle or Helm, create a secret with the following command:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl -n k6-operator-system create secret generic my-cloud-token \
    --from-literal=token=&amp;lt;COPY YOUR TOKEN HERE&amp;gt; &amp;amp;&amp;amp; kubectl -n k6-operator-system label secret my-cloud-token &amp;#34;k6cloud=token&amp;#34;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Alternatively, if you installed operator with a Makefile, you can uncomment the cloud output section in &lt;code&gt;config/default/kustomization.yaml&lt;/code&gt; and copy your token from Grafana Cloud k6 there:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;# Uncomment this section if you need cloud output and copy-paste your token
secretGenerator:
  - name: cloud-token
    literals:
      - token=&amp;lt;copy-paste-token-string-here&amp;gt;
    options:
      annotations:
        kubernetes.io/service-account.name: k6-operator-controller
      labels:
        k6cloud: token&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After updating the file, run &lt;code&gt;make deploy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After these steps, you can run k6 with the cloud output and default values of &lt;code&gt;projectID&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Refer to &lt;a href=&#34;/docs/grafana-cloud/testing/k6/author-run/cloud-scripting-extras/cloud-options/#cloud-options&#34;&gt;Cloud options&lt;/a&gt; for details on how to change the &lt;code&gt;projectID&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; options.&lt;/p&gt;
]]></content><description>&lt;h1 id="use-the-k6-operator-with-grafana-cloud-k6">Use the k6 Operator with Grafana Cloud k6&lt;/h1>
&lt;p>Grafana Cloud k6 is the Grafana Cloud offering of k6, which gives you access to all of k6 capabilities, while Grafana handles the infrastructure, storage, and metrics aggregation and insights from your tests.&lt;/p></description></item><item><title>Configure the TestRun CRD</title><link>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/configure-testrun-crd/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/configure-testrun-crd/</guid><content><![CDATA[&lt;h1 id=&#34;configure-the-testrun-crd&#34;&gt;Configure the TestRun CRD&lt;/h1&gt;
&lt;!-- TODO: consider removing this page once machine-generated reference becomes part of the docs --&gt;
&lt;p&gt;The only options that are required as part of the &lt;code&gt;TestRun&lt;/code&gt; CRD spec are &lt;code&gt;script&lt;/code&gt; and &lt;code&gt;parallelism&lt;/code&gt;. But there are many other options that can be set in &lt;code&gt;TestRun&lt;/code&gt; CRD. Refer to the &lt;a href=&#34;https://github.com/grafana/k6-operator/blob/main/docs/crd-generated.md&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;crd-generated.md&lt;/a&gt; file in the k6-operator GitHub repository for a complete list of all available fields.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at some of the most common options in greater detail.&lt;/p&gt;
&lt;h2 id=&#34;parallelism&#34;&gt;Parallelism&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;parallelism&lt;/code&gt; defines how many instances of k6 runners you want to create. Each instance is assigned an equal execution segment. For instance, if your test script is configured to run 200 VUs and &lt;code&gt;parallelism&lt;/code&gt; is set to 4, the k6 Operator creates four k6 jobs, each running 50 VUs to achieve the desired VU count.&lt;/p&gt;
&lt;h2 id=&#34;separate&#34;&gt;Separate&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;separate: true&lt;/code&gt; indicates that the jobs created need to be distributed across different nodes. This is useful if you&amp;rsquo;re running a test with a really high VU count and want to make sure the resources of each node won&amp;rsquo;t become a bottleneck.&lt;/p&gt;
&lt;h2 id=&#34;service-account&#34;&gt;Service account&lt;/h2&gt;
&lt;p&gt;If you want to use a custom Service Account you&amp;rsquo;ll need to pass it into both the starter and the runner object:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: k6.io/v1alpha1
kind: TestRun
metadata:
  name: &amp;lt;test-name&amp;gt;
spec:
  script:
    configMap:
      name: &amp;#39;&amp;lt;configmap&amp;gt;&amp;#39;
  runner:
    serviceAccountName: &amp;lt;service-account&amp;gt;
  starter:
    serviceAccountName: &amp;lt;service-account&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;runner&#34;&gt;Runner&lt;/h2&gt;
&lt;p&gt;Defines options for the test runner pods. The non-exhaustive list includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Passing resource limits and requests.&lt;/li&gt;
&lt;li&gt;Passing in labels and annotations.&lt;/li&gt;
&lt;li&gt;Passing in affinity and anti-affinity.&lt;/li&gt;
&lt;li&gt;Passing in a custom image.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;starter&#34;&gt;Starter&lt;/h2&gt;
&lt;p&gt;Defines options for the starter pod. The non-exhaustive list includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Passing in a custom image.&lt;/li&gt;
&lt;li&gt;Passing in labels and annotations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;initializer&#34;&gt;Initializer&lt;/h2&gt;
&lt;p&gt;By default, the initializer Job is defined with the same options as the runner Jobs, but its options can be overwritten by setting &lt;code&gt;.spec.initializer&lt;/code&gt;.&lt;/p&gt;
]]></content><description>&lt;h1 id="configure-the-testrun-crd">Configure the TestRun CRD&lt;/h1>
&lt;!-- TODO: consider removing this page once machine-generated reference becomes part of the docs -->
&lt;p>The only options that are required as part of the &lt;code>TestRun&lt;/code> CRD spec are &lt;code>script&lt;/code> and &lt;code>parallelism&lt;/code>. But there are many other options that can be set in &lt;code>TestRun&lt;/code> CRD. Refer to the &lt;a href="https://github.com/grafana/k6-operator/blob/main/docs/crd-generated.md" target="_blank" rel="noopener noreferrer">crd-generated.md&lt;/a> file in the k6-operator GitHub repository for a complete list of all available fields.&lt;/p></description></item><item><title>Schedule k6 tests</title><link>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/scheduling-tests/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/scheduling-tests/</guid><content><![CDATA[&lt;h1 id=&#34;schedule-k6-tests&#34;&gt;Schedule k6 tests&lt;/h1&gt;
&lt;p&gt;While the k6 Operator doesn&amp;rsquo;t support scheduling k6 tests directly, you can schedule tests with the &lt;code&gt;CronJob&lt;/code&gt; object from Kubernetes directly. The &lt;code&gt;CronJob&lt;/code&gt; would run on a schedule and execute the creation and deletion of the &lt;code&gt;TestRun&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;Running these tests requires a little more setup than a standalone test run.&lt;/p&gt;
&lt;h2 id=&#34;create-a-configmap-with-k6-scripts&#34;&gt;Create a &lt;code&gt;ConfigMap&lt;/code&gt; with k6 scripts&lt;/h2&gt;
&lt;p&gt;Refer to 
    &lt;a href=&#34;/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/executing-k6-scripts-with-testrun-crd/&#34;&gt;Run k6 scripts with &lt;code&gt;TestRun&lt;/code&gt; CRD&lt;/a&gt; for details on how to create a &lt;code&gt;ConfigMap&lt;/code&gt; with k6 scripts.&lt;/p&gt;
&lt;h2 id=&#34;create-a-configmap-of-the-yaml-file-for-the-testrun-job&#34;&gt;Create a ConfigMap of the YAML file for the &lt;code&gt;TestRun&lt;/code&gt; job&lt;/h2&gt;
&lt;!-- TODO: add a proper description for default installations: for bundle &amp; Helm  --&gt;
&lt;p&gt;When using the &lt;code&gt;make deploy&lt;/code&gt; installation method, add a &lt;code&gt;configMapGenerator&lt;/code&gt; to the &lt;code&gt;kustomization.yaml&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;configMapGenerator:
  - name: &amp;lt;test-name&amp;gt;-config
    files:
      - &amp;lt;test-name&amp;gt;.yaml&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;create-a-serviceaccount-for-the-cronjob&#34;&gt;Create a &lt;code&gt;ServiceAccount&lt;/code&gt; for the &lt;code&gt;CronJob&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;For the &lt;code&gt;CronJob&lt;/code&gt; to be able to create and delete &lt;code&gt;TestRun&lt;/code&gt; objects, create a service account:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: k6-&amp;lt;namespace&amp;gt;
rules:
  - apiGroups:
      - k6.io
    resources:
      - testruns
    verbs:
      - create
      - delete
      - get
      - list
      - patch
      - update
      - watch
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: k6-&amp;lt;namespace&amp;gt;
roleRef:
  kind: Role
  name: k6-&amp;lt;namespace&amp;gt;
  apiGroup: rbac.authorization.k8s.io
subjects:
  - kind: ServiceAccount
    name: k6-&amp;lt;namespace&amp;gt;
    namespace: &amp;lt;namespace&amp;gt;
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: k6-&amp;lt;namespace&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;create-a-cronjob&#34;&gt;Create a &lt;code&gt;CronJob&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;This is an example of how to define a &lt;code&gt;CronJob&lt;/code&gt; in a YAML file:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;# snapshotter.yml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: &amp;lt;test-name&amp;gt;-cron
spec:
  schedule: &amp;#39;&amp;lt;cron-schedule&amp;gt;&amp;#39;
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccount: k6
          containers:
            - name: kubectl
              image: bitnami/kubectl
              volumeMounts:
                - name: k6-yaml
                  mountPath: /tmp/
              command:
                - /bin/bash
              args:
                - -c
                - &amp;#39;kubectl delete -f /tmp/&amp;lt;test-name&amp;gt;.yaml; kubectl apply -f /tmp/&amp;lt;test-name&amp;gt;.yaml&amp;#39;
          restartPolicy: OnFailure
          volumes:
            - name: k6-yaml
              configMap:
                name: &amp;lt;test-name&amp;gt;-config&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
]]></content><description>&lt;h1 id="schedule-k6-tests">Schedule k6 tests&lt;/h1>
&lt;p>While the k6 Operator doesn&amp;rsquo;t support scheduling k6 tests directly, you can schedule tests with the &lt;code>CronJob&lt;/code> object from Kubernetes directly. The &lt;code>CronJob&lt;/code> would run on a schedule and execute the creation and deletion of the &lt;code>TestRun&lt;/code> object.&lt;/p></description></item><item><title>Use the k6 Operator with Istio</title><link>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/istio/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/set-up/set-up-distributed-k6/usage/istio/</guid><content><![CDATA[&lt;h1 id=&#34;use-the-k6-operator-with-istio&#34;&gt;Use the k6 Operator with Istio&lt;/h1&gt;
&lt;p&gt;To use the k6 Operator against a cluster with &lt;a href=&#34;https://istio.io&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Istio&lt;/a&gt; support, you may need to perform some additional configuration. Istio has two modes of execution: sidecar mode and ambient mode.&lt;/p&gt;
&lt;h2 id=&#34;sidecar-mode&#34;&gt;Sidecar mode&lt;/h2&gt;
&lt;p&gt;If you use Istio in &lt;a href=&#34;https://istio.io/latest/docs/setup/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;sidecar mode&lt;/a&gt;, first, check the versions of your cluster and Istio. For the k6 Operator to work without issues, Istio&amp;rsquo;s version must be 1.19 or higher, and the Kubernetes version must be 1.28 or higher.&lt;/p&gt;
&lt;p&gt;Additionally, Kubernetes cluster must have native sidecars &lt;a href=&#34;https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;enabled&lt;/a&gt;, which is the default behaviour since version 1.29 but must be enabled with a feature gate in version 1.28. Here&amp;rsquo;s an example of the &lt;a href=&#34;https://kind.sigs.k8s.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;kind cluster&lt;/a&gt; with this configuration:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  SidecarContainers: true&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If the above requirements are not fulfilled, k6 Operator will not be able to work with Istio because of &lt;a href=&#34;https://github.com/istio/istio/issues/11045&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;this issue&lt;/a&gt;: the non-native sidecar &lt;code&gt;istio-proxy&lt;/code&gt; doesn&amp;rsquo;t exit and all Kubernetes Jobs end up stuck, including the ones started by the k6 Operator. Because of this, k6 Jobs enter a &lt;code&gt;NotReady&lt;/code&gt; state, and the k6 Operator doesn&amp;rsquo;t know how to handle it in a general case.&lt;/p&gt;
&lt;p&gt;To solve this, upgrade versions of your cluster and Istio as described above and switch to using &lt;a href=&#34;https://istio.io/latest/blog/2023/native-sidecars/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Istio with native sidecars&lt;/a&gt;. As described in the &lt;a href=&#34;https://istio.io/latest/blog/2023/native-sidecars/#trying-it-out&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;blog&lt;/a&gt;, you need to enable the &lt;code&gt;ENABLE_NATIVE_SIDECARS&lt;/code&gt; flag in Istio as well.&lt;/p&gt;
&lt;h3 id=&#34;mark-k6-pods-for-istio-injection&#34;&gt;Mark k6 pods for Istio injection&lt;/h3&gt;
&lt;p&gt;Istio in sidecar mode lets you &lt;a href=&#34;https://istio.io/latest/docs/setup/additional-setup/sidecar-injection/#controlling-the-injection-policy&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;configure injection&lt;/a&gt; on Pods and Namespaces.&lt;/p&gt;
&lt;p&gt;Since the k6 Operator is not aware of the Istio setup on your cluster, it will, by default, create Pods without Istio labels. If you create a &lt;code&gt;TestRun&lt;/code&gt;, you can set the Istio labels via &lt;code&gt;.spec.runner.metadata.labels&lt;/code&gt;. If you create a &lt;code&gt;PrivateLoadZone&lt;/code&gt;, you can set the labels on the Namespace where the &lt;code&gt;PrivateLoadZone&lt;/code&gt; CR is created.&lt;/p&gt;
&lt;h2 id=&#34;ambient-mode&#34;&gt;Ambient mode&lt;/h2&gt;
&lt;p&gt;If you use Istio in &lt;a href=&#34;https://istio.io/latest/docs/ambient/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;ambient mode&lt;/a&gt;, the k6 Operator should work out of the box, as Istio in ambient mode doesn&amp;rsquo;t modify Kubernetes workloads.&lt;/p&gt;
&lt;h3 id=&#34;mark-k6-pods-for-istio-injection-1&#34;&gt;Mark k6 pods for Istio injection&lt;/h3&gt;
&lt;p&gt;Istio in ambient mode lets you &lt;a href=&#34;https://istio.io/latest/docs/ambient/usage/add-workloads/#ambient-labels&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;configure injection&lt;/a&gt; on Pods, Services, and Namespaces.&lt;/p&gt;
&lt;p&gt;Similarly to &lt;a href=&#34;#mark-k6-pods-for-istio-injection&#34;&gt;injection in sidecar mode&lt;/a&gt;, you can use Pod-level configuration with a &lt;code&gt;TestRun&lt;/code&gt; and Namespace-level configuration with a &lt;code&gt;PrivateLoadZone&lt;/code&gt;.&lt;/p&gt;
]]></content><description>&lt;h1 id="use-the-k6-operator-with-istio">Use the k6 Operator with Istio&lt;/h1>
&lt;p>To use the k6 Operator against a cluster with &lt;a href="https://istio.io" target="_blank" rel="noopener noreferrer">Istio&lt;/a> support, you may need to perform some additional configuration. Istio has two modes of execution: sidecar mode and ambient mode.&lt;/p></description></item></channel></rss>