Setting K6_BROWSER_ARGS on grafana/k6:master-with-browser - what happens to its no-sandbox preset?
answer
- the image sets it, you overwrite it
- the variable is the whole list
- no merge with any default
- carry no-sandbox in your own value
basics
~10 sThe 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.
solid answer
~30 sThe browser image bakes `K6_BROWSER_ARGS=no-sandbox` into its environment, and k6 treats that variable as the complete list of extra browser arguments - it parses the value and **assigns** it, rather than appending to a default. So `-e K6_BROWSER_ARGS=ignore-certificate-errors` does not add an argument to `no-sandbox`; it replaces it. The Dockerfile is explicit that `no-sandbox` is what lets Chromium run on this Alpine base without granting the container `SYS_ADMIN`, so dropping it breaks the launch. If you need your own arguments, include `no-sandbox` in the list yourself: `-e K6_BROWSER_ARGS='no-sandbox,ignore-certificate-errors'`. Values in that list are comma-separated and must not begin with `--`.
code
bash · 9 lines# Drops the image's no-sandbox preset - the browser will not launch
docker run --rm -i \
-e K6_BROWSER_ARGS=ignore-certificate-errors \
grafana/k6:master-with-browser run - < browser-test.js
# Keeps it: the variable is the complete list, so name both
docker run --rm -i \
-e K6_BROWSER_ARGS='no-sandbox,ignore-certificate-errors' \
grafana/k6:master-with-browser run - < browser-test.jsgo deeper
Remember that the browser image already sets K6_BROWSER_ARGS=no-sandbox. If you set that variable yourself, include no-sandbox in your value, because yours replaces the image's rather than adding to it.
Explain the mechanism: k6 parses the variable into the browser's whole extra-argument list and assigns it, with no default underneath. Note the format too - comma-separated entries with no leading dashes.
Recognise the symptom from a diff: a browser step that suddenly cannot launch after a single added -e line. Say why no-sandbox is in the image - it avoids needing SYS_ADMIN on this base - and what the hardened alternative costs.
The call is whether browser jobs keep the sandbox opt-out at all. Keeping it is cheap and fine against your own staging hosts; dropping it needs a security profile and a reason. Decide once and require every browser job to state the full list.
## What the browser tag presets `grafana/k6:master-with-browser` is the plain image plus Chromium, plus exactly two environment variables the plain image does not set: - `K6_BROWSER_HEADLESS=true` - the browser starts with no visible window, which is the only thing that makes sense on a runner with no display. - `K6_BROWSER_ARGS=no-sandbox` - an extra argument handed to the browser process at launch. Both are ordinary environment variables baked into the image, not settings inside the k6 binary. They are not equally load-bearing, though: - Headless is **already the binary's own default**, so `K6_BROWSER_HEADLESS=true` in the image only restates it. Overriding it to `false` in a container achieves nothing useful anyway, since there is no display to draw on. - `K6_BROWSER_ARGS`, by contrast, has **no default in the binary at all**. Without the image's value the list is empty, and the browser is launched with no extra arguments. That asymmetry is why the two behave so differently when you override them, and it is the whole of this question. ## Replace, not append k6 reads `K6_BROWSER_ARGS`, splits the value into a list, and **assigns** that list as the browser's extra arguments. There is no merge step and no built-in `no-sandbox` underneath it. The practical consequences: | what you pass | what the browser is launched with | |---|---| | nothing (the image's own value) | `no-sandbox` | | `-e K6_BROWSER_ARGS=ignore-certificate-errors` | `ignore-certificate-errors` only | | `-e K6_BROWSER_ARGS='no-sandbox,ignore-certificate-errors'` | both | | `-e K6_BROWSER_ARGS=''` | nothing - an empty value is skipped, so the preset is dropped | The second row is the trap. Everything about the command looks like an addition, and the effect is a silent removal of the one argument the image cannot run without. Two formatting rules go with it, and both are easy to get wrong the first time: 1. The value is a **comma-separated list**, not a space-separated command line. 2. Individual arguments **must not begin with `--`** - it is `no-sandbox`, not `--no-sandbox`. ## Why `no-sandbox` is in the image at all The Dockerfile says so directly: the argument is required to run the browser on this Alpine base, and setting it avoids having to grant the container the `SYS_ADMIN` capability. Chromium's own sandbox needs kernel facilities the image is not given, so k6's browser image opts the sandbox out instead of asking for more privilege - a deliberate trade the image makes on your behalf, and the reason the k6 documentation warns to point the browser image only at sites you trust. That is also why removing the argument is not a small regression. Without `no-sandbox` and without extra privilege or a suitable seccomp profile, the browser process cannot start, and the k6 run fails at the first browser call rather than at configuration time. ## Keeping both When a browser test genuinely needs an extra argument - ignoring a self-signed certificate on a staging host, or pointing the browser at a proxy - there are two supportable shapes: 1. **Carry `no-sandbox` yourself.** Put it first in your own list: `-e K6_BROWSER_ARGS='no-sandbox,ignore-certificate-errors'`. Simple, and it keeps the image's trade intact. 2. **Drop the opt-out on purpose.** Set `-e K6_BROWSER_ARGS=''` and give the container a security profile that lets Chromium's sandbox work. This is the shape the k6 documentation offers as the hardened alternative; it is more work and it is the right answer when the target is untrusted. Do not reach for a third option of adding the argument twice, or of setting it in the script's browser options and hoping the environment merges - the variable is the whole list, once. ## In a CI job The failure mode is characteristic: a browser step that has worked for months breaks the day someone adds one browser argument to it, and the diff shows only an added `-e` line. Two things keep it visible: - **Write the full list every time.** If any job sets `K6_BROWSER_ARGS`, make it always include `no-sandbox` explicitly rather than relying on the image, so the value in the job definition is the value the browser gets. - **Read the error as a launch failure, not a flag problem.** k6 reports a failure to start or find a usable browser; nothing in the message mentions the argument you removed. - **Treat any job that sets the variable as owning the whole list.** Once a step passes `K6_BROWSER_ARGS`, the image's value is no longer part of the picture, and the step's own text is the complete answer to what the browser was launched with. - **Keep the value in one place.** A browser configuration split between an `-e` line and the script is much harder to reason about the day the browser stops starting.
- What format does `K6_BROWSER_ARGS` expect?A comma-separated list of arguments with no leading dashes - `no-sandbox,ignore-certificate-errors`, never `--no-sandbox --ignore-certificate-errors`. k6 splits the value and passes each entry to the browser process, so a space-separated or dash-prefixed value produces arguments the browser does not recognise.
- Does setting `K6_BROWSER_ARGS` to an empty string keep the image's preset?No. An empty value is skipped rather than applied, so the browser launches with no extra arguments at all and the image's `no-sandbox` is gone. That is exactly the shape the k6 documentation uses when deliberately restoring the sandbox alongside a hardened security profile.
saying these in an interview costs you the question
- Assumes K6_BROWSER_ARGS is appended to the image's value
- Writes the arguments with leading double dashes
- Separates the arguments with spaces instead of commas
- Thinks an empty value restores the image default
- Reads the launch failure as a k6 version problem