Running it
Building your own image
Extending the published image with your dependencies, the version lock between Browser and Playwright, and using it as a CI job container.
The published image runs a plain Robot Framework suite. As soon as your suite imports another library, needs a driver, or wants a specific Python version, you need an image of your own.
The good news is that it is a handful of lines — the published image already
runs as pwuser, so the USER line below is only insurance. The thing to be careful
about is the version lock described further down — it is the one way to build an
image that looks fine and fails at runtime.
Add your dependencies
FROM marketsquare/robotframework-browser:20.3.0USER pwuserCOPY --chown=pwuser requirements.txt /home/pwuser/RUN pip install --no-cache-dir -r /home/pwuser/requirements.txt
pip resolves to the virtualenv at /home/pwuser/.venv, which is already on
PATH, so there is no activation step.
Pin the base image to an exact release, not latest. A pipeline that rebuilds
weekly against latest will one day upgrade Browser under you, and the failure
will arrive on a day when nothing in your repository changed.
Bake your suite in, or mount it?
Both are legitimate and they answer different questions.
| Mount at run time | `COPY` into the image | |
|---|---|---|
Mounting is the right default. Reach for COPY when the image itself has to be
the deliverable — a smoke test handed to an ops team, for instance.
The version lock
This is the part that bites.
Browser is built against one specific Playwright version, and the browser binaries in the base image are the ones that Playwright version ships. Three things must agree:
- the Browser library,
- the Playwright npm package Browser installs,
- the browser binaries baked into the image.
The published image gets this right by construction: it starts from
mcr.microsoft.com/playwright:v1.62.0-noble, and the Browser release it installs is
built against Playwright 1.62.1. Those two can differ by
a patch — the
FROM line is bumped by hand — so if you are chasing a binary-level mismatch,
compare them rather than assuming they agree.
Upgrading Browser inside a derived image breaks that. This looks harmless and is not:
You now have a newer Browser expecting a newer Playwright, driving the browser binaries of the older one. What happens next depends on how far apart they are — which is worse than failing outright, because it can work for months and then not.
To move to a newer Browser, change the base image tag. That is the entire upgrade procedure, and it is the reason the tag exists.
If you genuinely must install a different Browser version in the same image, you
own the whole chain: reinstall the Node side and let it fetch matching binaries
(rfbrowser clean-node && rfbrowser init, which downloads a second, matching browser set — into the library's
node_modules when PLAYWRIGHT_BROWSERS_PATH is unset, otherwise wherever it
points, which in this base image is Playwright's own directory — while the base
image's binaries stay on disk, so you pay for both), or install browsers separately and
point PLAYWRIGHT_BROWSERS_PATH at them. Both give up what the image was for.
As a CI job container
Most CI systems can run a job inside an image, which removes the docker run
line entirely — your steps execute in the container, and the checkout is already
there.
jobs: robot: runs-on: ubuntu-latest container: image: marketsquare/robotframework-browser:20.3.0 options: --ipc=host --user pwuser steps: - uses: actions/checkout@v7 - run: robot --outputdir output tests/ - uses: actions/upload-artifact@v7 if: always() with: name: robot-results path: output/
Two details are load-bearing. --ipc=host and --user pwuser still apply — a job
container gets no flags you do not give it. And if: always() on the upload:
without it the results are discarded on exactly the runs where you needed them.
Building the official image yourself
The Dockerfiles live in
docker/
in the library repository, and the same directory's README documents the local
build and the pull-request image. Reach for it if you need to reproduce the
official image with a change — a different Python version, a different base — or
if you are contributing to Browser itself.
For anything short of that, extending the published image is less work and stays correct through upgrades.