skip to content

Automation Fit

How a k6 run becomes a verdict a build step can act on with nobody watching, and where this generator honestly sits beside the others. Interviewers probe where load testing meets delivery.

on this pageshow

explore

questions

14

Why does running the grafana/k6 image look like `docker run -i grafana/k6 run - < script.js`?

level: juniorimportance: must knowfreq 62%

answer

  1. the image already runs one binary
  2. arguments begin at the subcommand
  3. run wants exactly one argument
  4. the file never crossed the boundary
  5. a dash means standard input

basics

~20 s

The grafana/k6 image sets ENTRYPOINT ["k6"], so appended arguments start at a k6 subcommand - here, run. The script lives on the host and not in the image, so the filename - makes k6 read it from standard input.

solid answer

~40 s

Two image facts combine. The published image declares `ENTRYPOINT ["k6"]`, so the container's argument list begins exactly where you would otherwise type the subcommand: `docker run --rm grafana/k6 version` and `docker run --rm -i grafana/k6 run -` are both complete commands, and repeating `k6` after the image name is rejected as an unknown subcommand. Second, `k6 run` takes exactly one positional argument, and its own error text says that argument must be either a path to a script file or the literal `-`. Since nothing from your working copy is inside the image, `-` is the quick route: k6 drains standard input and runs those bytes. If the test needs more than one file, mount the directory instead and pass a real in-container path.

code

bash · 8 lines
bash
# Entrypoint is already k6, so the argument list starts at the subcommand
docker run --rm grafana/k6 version
docker run --rm grafana/k6 run --help

# The script is on the host, so read it from stdin with the filename `-`
docker run --rm -i \
  -e K6_NO_USAGE_REPORT=true \
  grafana/k6 run - < tests/smoke.js

go deeper

for a junior

Remember the two moving parts: the image's entrypoint is already k6, so you type the subcommand first, and - is the script argument that means standard input. Being able to write the command from memory is what is being checked.

for a middle

Explain why - exists at all: the host file is not inside the container, and k6 run takes exactly one positional argument that must be a container path or -. Say what breaks when standard input is not attached.

for a senior

Show you can pick the shape that fits the test. A single self-contained script pipes in fine; anything with local imports, data files or written output needs a mount and an in-container path, with UID 12345 able to read it.

for a principal

The judgment call is what the team standardises on. Piping is the least-configuration form and stays uniform across runners; mounting is the one that scales to a real test suite. Decide once and keep every job on the same shape.

## The image is a k6 binary behind a fixed front door The published `grafana/k6` image is deliberately minimal. Its runtime stage copies exactly one artifact - the `k6` binary, built with `CGO_ENABLED=0` - to `/usr/bin/k6`, adds a non-root user with **UID 12345**, sets `WORKDIR /home/k6`, and declares **`ENTRYPOINT ["k6"]`**. There is no shell wrapper, no scripts of your own, and nothing else to invoke. That entrypoint is the line that shapes every command you will ever type against this image. Because the entrypoint is already the binary, everything appended after the image name becomes k6's own argument list, starting where the subcommand would normally go: - `docker run --rm grafana/k6 version` runs `k6 version` - `docker run --rm grafana/k6 run --help` runs `k6 run --help` - `docker run --rm -i grafana/k6 run - < script.js` runs `k6 run -` Writing `grafana/k6 k6 run ...` out of habit fails. k6's root command dispatches only to subcommands such as `run`, `new`, `inspect`, `archive`, `cloud`, `deps` and `version`, and has no behaviour of its own, so the extra `k6` is rejected as an unknown command. `grafana/k6 script.js` fails for the same reason: a bare filename is not a subcommand, and k6 never treats one as an implicit `run`. ## `k6 run` accepts exactly one positional argument `run` is declared with an exact-arity check of one, and its own message spells out what the argument may be: *arg should either be `-`, if reading script from stdin, or a path to a script file*. That leaves two shapes, and choosing between them is the whole of running k6 from the image: 1. **A path the container can resolve.** Host paths are meaningless inside the container, so the file must be mounted first and you pass its in-container location, such as `-v "$PWD/tests:/tests:ro" ... run /tests/smoke.js`. 2. **The literal `-`.** k6's source loader special-cases this one character: it drains standard input, caches those bytes internally under the path `/-`, and runs them as the test script. No filesystem entry is involved at all. Passing both a path and `-`, or neither, trips the same arity check. ## Why the dash is the short path `-` exists precisely because the image cannot see your working copy. Redirecting the file in with `< script.js`, or piping it with `cat script.js |`, carries the bytes across the container boundary through standard input rather than through a mount. That keeps the invocation to a single line and needs no volume, no path translation and no permission arithmetic against UID 12345. The one thing it does require is that the container actually has standard input attached. Started without it, k6 reads zero bytes and fails on an empty script rather than telling you a file was missing - the redirect happened on the host, so from k6's side nothing was ever wrong. ## The two shapes side by side | | `run -` with the file redirected in | mounted directory, in-container path | |---|---|---| | invocation | `docker run --rm -i grafana/k6 run - < smoke.js` | `docker run --rm -v "$PWD:/tests:ro" grafana/k6 run /tests/smoke.js` | | what reaches k6 | one file, as bytes on stdin | everything under the mounted directory | | relative `import` of a local file | not resolvable | resolvable | | files opened at run time | not available | available | | how k6 names the script | the internal path `/-` | the real in-container path | | extra requirement | stdin must be attached | mount must be readable by UID 12345 | ## Why a CI job reaches for the image at all In a containerised CI step the whole invocation is usually one of those two lines and nothing else. The image supplies the binary, so the job needs no install step, no package repository and no version drift between a developer's laptop and the runner - every branch executes the identical k6 build. Adding `-e K6_NO_USAGE_REPORT=true` suppresses k6's usage ping from a machine that has no business making one, which is the one extra thing most CI steps set. ## Where it goes wrong - Repeating `k6` after the image name, or passing the script path with no subcommand at all. - Omitting docker's `-i`, so the container starts with no standard input and k6 runs an empty script. - Handing `run` a host path such as `./tests/smoke.js` with nothing mounted: k6 reports it could not be found on local disk, because from inside the container it genuinely is not there. - Expecting `run -` to also pull in a helper module that sits beside the script on the host. - Assuming the image accepts a `k6` argument, a wrapper script, or a directory of tests.

  • How does k6 refer to a script it read from standard input?
    Its loader caches the bytes under the internal path `/-` and reports the script that way, since there is no real file behind it. That path is also what k6 treats as the script's location when it needs one, which is why a stdin script has no directory of its own.
  • What does `docker run --rm grafana/k6 script.js` do?
    It fails immediately with an unknown-command error. k6's root command only dispatches to subcommands such as `run`, `new` and `inspect`; it has no behaviour of its own, so a bare filename is not a valid first argument and no test is started.
  • Does the image need any k6 installation on the CI runner?
    No. The image contains the `k6` binary at `/usr/bin/k6` and the entrypoint invokes it directly, so the runner needs only a container runtime. That is the main reason CI steps use the image rather than installing k6 from a package repository on every job.

saying these in an interview costs you the question

  • Writes grafana/k6 k6 run, repeating the binary name
  • Thinks docker run grafana/k6 script.js starts a test
  • Treats - as a k6 flag rather than the script argument
  • Omits docker's -i and blames k6 for an empty script
  • Believes the image can read a host path directly
  • Expects the image to accept several script paths at once
open as a page

What do k6's --execution-segment and --execution-segment-sequence flags do, and why pass both?

level: middleimportance: must knowfreq 68%

basics

~20 s

In k6, --execution-segment names the slice of total work one process runs, and --execution-segment-sequence names the full partition every process shares. Pass both, or each instance invents its own partition and the slices stop lining up.

open as a page

A script piped into grafana/k6 with `run -` fails on a relative import - why, and what fixes it?

level: middleimportance: must knowfreq 54%

basics

~20 s

Piping delivers one file and nothing else. k6 records a stdin script as /-, so relative imports resolve against the container's working directory, not the script's folder. Mount the directory and pass an in-container path instead.

open as a page

For a JS-fluent team, what does k6's script-as-a-JavaScript-module model make easy, and what does it cost?

level: middleimportance: must knowfreq 62%

basics

~20 s

A k6 test is a JavaScript module: imports, an exported options object, a default function. It reviews, diffs and merges like application code. The cost is that authoring and review require JavaScript, and the runtime is not Node.

open as a page

After four k6 instances each run one execution segment, what does core k6 not do for you?

level: seniorimportance: must knowfreq 62%

basics

~10 s

Core k6 divides the plan but never rejoins the results. There is no primary process, each instance evaluates its thresholds against only its own samples, and each writes its own output stream and summary.

open as a page

Which value forms does k6's --execution-segment flag accept, and what does a bare 25% mean?

level: juniorimportance: should knowfreq 44%

basics

~20 s

k6's --execution-segment accepts a percentage, a decimal, a fraction, or two of those joined by a colon. A value with no colon is the end of a segment starting at zero, so 25% means the first quarter, 0:1/4.

open as a page

When a k6 test is split into four execution segments, how are VU and iteration counts divided?

level: middleimportance: should knowfreq 56%

basics

~20 s

k6 gives each execution segment a striped, non-overlapping set of indices from the whole partition and scales every count against it, so the per-instance shares always add back up to the scripted total. Durations are never scaled.

open as a page

Why does a `k6/browser` script fail on grafana/k6 but run on grafana/k6:master-with-browser?

level: middleimportance: should knowfreq 46%

basics

~20 s

Both tags carry the identical k6 binary, so the import compiles either way. Only the with-browser image installs Chromium, so on the plain image the run dies at browser launch, reporting that k6 could not detect a chromium-supported browser.

open as a page

The grafana/k6 image runs as UID 12345 - what does that mean for a mounted script and output directory?

level: seniorimportance: should knowfreq 41%

basics

~20 s

The grafana/k6 image runs as UID 12345 with WORKDIR /home/k6. A mounted script need only be readable by that user, but any directory k6 writes into must be writable by it, and produced files are owned by 12345.

open as a page

Why can a k6 run gate a CI pipeline with no extra tooling, and where does that native gate stop?

level: seniorimportance: should knowfreq 55%

basics

~20 s

k6 declares its pass rule in the script's exported options and exits 99 when a threshold is breached, so the CI step is just the run. But a failed check() never changes that code, and a script with no thresholds exits zero.

open as a page

Rolling k6 out to several teams, what must you standardise because a k6 test is ordinary JavaScript?

level: principalimportance: should knowfreq 42%

basics

~20 s

Standardise the binary every runner resolves to, the shared module layer teams import, and a rule that every test declares thresholds, since k6 exits zero when none exist. The executor vocabulary standardises itself: only six names are legal.

open as a page

What does k6 inspect --execution-requirements report, and where does it read the execution segment from?

level: middleimportance: nice to knowfreq 32%

basics

~20 s

It prints the script's consolidated options JSON plus two extra fields, totalDuration and maxVUs, computed for the configured execution segment. k6 inspect has no segment flag, so the segment must come from the script's options or a -c config file.

open as a page

Setting K6_BROWSER_ARGS on grafana/k6:master-with-browser - what happens to its no-sandbox preset?

level: seniorimportance: nice to knowfreq 24%

basics

~10 s

The image's K6_BROWSER_ARGS=no-sandbox is replaced, not extended. k6 parses that variable into the browser's whole extra-argument list, so any value you supply overwrites no-sandbox and Chromium can no longer start in this image.

open as a page

In k6, what does an import from the k6/x/ namespace imply for the binary your team and CI must run?

level: seniorimportance: nice to knowfreq 38%

basics

~20 s

The script cannot run on a stock k6 release. Extensions are compiled into the binary under the k6/x/ prefix, so what the team pins and distributes is a specific k6 build, not just a script and a version.

open as a page