Running it
Running in Docker
The published Browser image, the four docker run flags that matter, and why running as root breaks Chromium.
Browser needs a browser, and a browser needs a long list of system libraries that
differ between distributions. On a laptop rfbrowser init handles it. On a CI
runner, a colleague's machine, or a distribution nobody tested, it is the part
that goes wrong.
The published image removes that problem: Python, Node, Robot Framework, Browser and the browser binaries that ship in Playwright's base image, in versions known to work together.
Pull it
The same image is published to two registries. Pick whichever your infrastructure already authenticates against — the same recipe, built from one Dockerfile in the same release job.
| Tag | Points at |
|---|---|
Both linux/amd64 and linux/arm64/v8 are built, so it runs natively on an
Apple Silicon machine as well as on an x86 runner.
Run your suite
Your suite is mounted in rather than copied, and the output directory is inside
that same mount — which is what gets log.html back onto your machine after the
container exits. A container writing its report to its own filesystem and then
being removed is the classic first mistake.
The container writes as pwuser, not as your user, so the mounted directory has
to be writable by that account. If it is not, the run dies trying to create
output/. Create it up front and open it up — this project's own CI does
mkdir output && chmod -R 777 output — or skip the mount and docker cp the
results out afterwards.
The flags, and why each one is there
None of these are ceremony. Each fixes a specific, confusing failure.
--user pwuser
Insurance, not a requirement. The image already ends on USER pwuser, so it
runs as that user by default and this flag changes nothing — keep it only if
your platform is liable to force root. What matters is not overriding it with
--user root: everything is installed for pwuser, from the virtualenv at
/home/pwuser/.venv to the caches and file permissions, and running as root
causes failures that look like browser crashes.
--ipc=host
--ipc=host is what this project recommends for Chromium, and it is what its
own container tests use. The reason comes from
Playwright's Docker guide rather than from
Browser: Chromium allocates shared memory through /dev/shm, Docker's default is 64 MB,
which a real page will exhaust — and Chromium's response to running out is to
crash a renderer, mid-test, non-deterministically. It presents as flakiness, and
you will look for it in your test before you look for it in your container
runtime.
--ipc=host gives the container the host's IPC namespace and the problem
disappears. If your platform will not allow it, --shm-size=2gb is the
second-best answer.
--security-opt seccomp=seccomp_profile.json
Chromium's sandbox needs syscalls that Docker's default seccomp profile blocks. Playwright publishes a profile that permits exactly those:
The alternative you will find on the internet is --cap-add=SYS_ADMIN or
--no-sandbox. Both work by turning the sandbox off. The seccomp profile keeps
it on, which for a container that loads arbitrary web pages is the difference
that matters.
--rm
Housekeeping. Test containers are disposable, and without it a CI runner accumulates them until the disk fills.
Headless and headful
The image is built on Microsoft's Playwright image, which includes the
dependencies for headful runs as well as headless. New Browser is headless
by default and that is what you want in CI — note that Open Browser defaults
the other way.
Headful needs a display, and the image already carries Xvfb: prefix the command
with xvfb-run, which is exactly what this project's own headful container
tests do. A VNC sidecar is only needed if you want to watch the run.
What is actually in the image
Worth knowing, because it explains the constraints in Building your own image:
| Layer | What it provides |
|---|---|
That last row is the non-obvious one. The browsers in this image come from the
Playwright base image, not from rfbrowser init. It is why the image is far
smaller than an install that downloads its own browser binaries on top of the
base image's — and also why the base image's Playwright can differ from the one
Browser was built against, since nothing in the image re-downloads browsers to
match.
Checking what you got
Prints the Browser library version, the Robot Framework version and the Playwright version in one go. When something behaves differently in the container than on your machine, run it in both places first — the answer is usually in the diff.
Next
- Adding your own dependencies, and pinning safely: Building your own image.
- If you run suites in parallel, read The Node process first: each Robot Framework process starts its own Node process, inside a container as much as outside it.