skip to content

Session Container Grids

The open shape you run yourself: a fresh container started for each session and destroyed after it, served from a catalogue, capped and reaped by the server, with a cluster form that grows on demand.

on this pageshow

explore

questions

5

In Selenoid, what is created when a browser session starts and what happens to it at the end?

level: juniorimportance: must knowfreq 66%

answer

  1. nothing is reused unless you mount it in
  2. the daemon does the starting
  3. a fresh container for each session
  4. force-removed with its volumes
  5. an abandoned one is reaped by a timer

basics

~20 s

Selenoid starts a fresh Docker container per WebDriver session, proxies the session to the driver inside, then force-removes it on delete. Nothing carries over: no profile, cookies, downloads or stray process, unless browsers.json mounts a host directory in.

solid answer

~50 s

Selenoid — unmaintained by its own README — is an implementation of a Selenium hub that launches browsers as Docker containers. On a new-session request it looks the browser up in its `browsers.json` catalogue, asks the Docker daemon for a container built from the image named there, waits for the driver inside to answer, and proxies the rest of the session to it. When the client sends the session delete, Selenoid force-removes that container together with its volumes, so the browser's whole filesystem goes with it: a hospital rota planner's suite never inherits a signed-in profile, a half-finished download, or a wedged renderer from the run before. The one deliberate hole is a catalogue entry's `volumes`, which bind-mounts a host directory that outlives every container. The price is a container creation on the critical path of every session, plus a Docker daemon Selenoid must be trusted to drive.

code

bash · 6 lines
bash
docker run -d \
  --name selenoid \
  -p 4444:4444 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /etc/rota-grid/config/:/etc/selenoid/:ro \
  aerokube/selenoid:latest-release

go deeper

for a junior

Be ready to say, in one breath, that Selenoid starts a browser container when a session is created and destroys it when the session ends. Naming what that wipes — profile, cookies, downloads — is what turns a memorised sentence into an answer.

for a middle

Know the steps between the request and the first command: catalogue lookup, run-limit slot, container creation through the Docker daemon, waiting for the driver, then proxying. Be able to say what the model costs as readily as what it buys.

for a senior

Expect to be asked what happens when the client never deletes its session. Talk about the idle timer issuing the delete itself, the run-limit slot coming back, and why that removes the need for an orphan-sweeping job — then say where it stops, because a Selenoid killed outright leaves its running browsers behind and nothing sweeps at startup.

for a principal

You will be asked whether this shape belongs in your estate at all. Weigh disposable-per-session isolation against container start-up on every session, the daemon access it requires, and the fact that the Aerokube tools are unmaintained.

Selenoid is an implementation of a Selenium hub that launches every browser as a Docker container. Its own README declares the project **UNMAINTAINED**, so read it as a clear, readable model of a mechanism rather than as current tooling. The mechanism is the durable part: the same disposable-per-session shape turns up in `docker-selenium`'s Kubernetes chart and behind every hosted browser service you can rent. ## The life of a session 1. A client sends a W3C new-session request to Selenoid's listen address. 2. Selenoid takes a slot from the server-wide run limit set by its `-limit` flag, whose own help text reads "Simultaneous container runs" — waiting there, by default, if the server is full. 3. It resolves the requested browser name and version against its `browsers.json` catalogue, reading that entry's `image`, `port` and `path`. 4. It asks the Docker daemon — over the socket Selenoid was started with — to create and start a container from that image. 5. It waits for the driver inside the container to answer, returns the session to the client, and proxies every later command in that session to that container. Nothing in that sequence reuses anything: the container did not exist before the request arrived, and it holds exactly what the image shipped. ## The end of a session When the client sends `DELETE` for the session, Selenoid drops the session from its map, releases the run-limit slot, and removes the container with Docker's force and remove-volumes options set. The browser's filesystem is not cleaned up; it is destroyed. If the client never sends that delete — the runner crashed, the pipeline was cancelled, the laptop closed — Selenoid's own idle timer eventually fires, logs `[SESSION_TIMED_OUT]`, and issues the delete on the client's behalf. Within that premise the grid needs no orphan-sweeper cron job: reaping an abandoned session is the same code path as ending a healthy one. Read the premise carefully. Those timers live in Selenoid's own memory, and the only other walk that ends sessions runs on an orderly shutdown signal. Kill the process outright, or lose the host, and nothing sweeps at startup: Docker's auto-remove takes away a browser that exits, but nothing tells a still-running one to exit — those are the orphans. ## Why a disposable container is the point | What can carry over | A long-lived browser process | A fresh container per session | |---|---|---| | Profile, cookies, local storage | Yes, unless the suite clears it | No, the filesystem is gone | | Downloaded files | Pile up on the host disk | Removed with the container, unless mounted out | | A wedged renderer or zombie driver | The next session inherits it | Cannot outlive its container | | Browser build in use | Whatever is installed on the host | Whatever the catalogue image pins | That table is the whole argument for the model. A hospital rota planner's suite logs in as a ward manager, downloads a shift export, and leaves a browser holding a session cookie. On a reused browser the next case starts already signed in as somebody — the classic source of a test that passes alone and fails in a suite. On a container grid there is no next case on that browser at all. The one escape from that table is a catalogue entry's `volumes`, which Selenoid's documentation describes as mounting a host path into the browser container: what a test writes there is on the host, not in the container, and survives every removal. ## What the model costs - **Start-up latency on every session.** Creating a container, starting the driver and waiting for it to answer sits on the critical path of each new session, not once per host. - **The first pull is slow.** An image named in the catalogue but not on the host must be fetched before anything runs. - **A privileged dependency.** Selenoid drives the Docker daemon, so whatever can talk to Selenoid can cause containers to be created on that host. - **Host resources are per container.** Selenoid's catalogue entries carry `tmpfs`, `shmSize`, `mem` and `cpu` precisely because a browser in a container needs shared memory and scratch space it would otherwise take from the host. - **Disk churn.** Create-and-destroy at session rate is real I/O on the machine. ## The same shape in a cluster `docker-selenium`'s Helm chart reaches the same place by a different road. With `autoscaling.scalingType` left at its default of `job`, KEDA renders a `ScaledJob` whose `jobTargetRef` sets `parallelism: 1` and `completions: 1` — each scaled unit is a Pod that serves its work and exits. Different products, same instinct: make the thing that ran the browser go away. ## What an interviewer is listening for - That you say **container per session**, not "container per node" or "container per suite". - That you can name what the destruction actually buys — profile, downloads, process state — rather than saying "it is cleaner". - That you know the container is removed on the session delete, that an abandoned session is reaped by a timer, and that a Selenoid killed outright leaves its running browsers behind. - That you volunteer the cost, because a candidate who only lists benefits has not run one. - That you say Selenoid is unmaintained in the same breath as you recommend learning from it.

  • If the container is destroyed at the end, how do you keep anything the failing test produced?
    You have to take it off the container before it dies, or ask the server to keep it. Selenoid writes a session's video and log to directories on the server rather than inside the browser container, and can push artefacts to object storage. Anything your own test wrote inside the browser's filesystem — a download it never read back — is gone with the container.
  • What does Selenoid need in order to start those containers at all?
    Access to a Docker daemon. The documented way to run it is a container started with the host's `/var/run/docker.sock` bind-mounted in, plus a configuration directory holding `browsers.json`. That is a real trust decision: anything that can reach Selenoid can cause container creation on that host, so the grid belongs on a network you control.
  • Does a fresh container per session remove test interference altogether?
    No. It removes browser-side carry-over — profile, cookies, storage, downloads, stray processes — unless a catalogue entry mounts a host directory in. It does nothing about shared state behind the application: the same rota database, the same seeded ward manager account, the same feature flags. Sessions with clean browsers can still collide on a record they both edit, and that class of interference is the suite's problem, not the grid's.

saying these in an interview costs you the question

  • Thinks Selenoid reuses the same browser container between runs
  • Believes the container is stopped but kept for the next run
  • Assumes a crashed test runner strands containers, or that a killed Selenoid does not
  • Says container isolation also isolates the application's data
  • Cannot name any cost of creating a container per session
  • Presents Selenoid as current tooling despite its unmaintained banner
open as a page

In a Ggr and Selenoid cluster, which setting actually caps how many sessions run at once?

level: middleimportance: must knowfreq 60%

basics

~20 s

Selenoid's server-side limit flag does, capping simultaneous container runs on each Selenoid host. Ggr has no concurrency ceiling at all; the count attribute in its quota file is a relative host weight for load balancing, not a cap.

open as a page

A Selenoid session dies mid-test though the client asked for a longer sessionTimeout. Why?

level: seniorimportance: must knowfreq 62%

basics

~20 s

Selenoid's sessionTimeout measures idle time between WebDriver commands, not elapsed test time, and the server silently clamps any value above its max-timeout flag. A test that waits without driving the browser idles out and the container is removed.

open as a page

In Selenoid, what does browsers.json decide, and what does a client get if its browser is missing?

level: middleimportance: should knowfreq 55%

basics

~20 s

Selenoid's browsers.json is the catalogue of what the server will start: browser name, default version, and per version the image, port and path. An unlisted browser draws invalid argument, though a busy server queues it before refusing.

open as a page

In docker-selenium's Helm chart, when is on-demand node scaling worth what it obliges you to run?

level: principalimportance: nice to knowfreq 42%

basics

~20 s

When demand is spiky and idle nodes are waste. The chart ships autoscaling disabled, so a default install is a fixed pool; enabling it installs KEDA and hands you a scaler, a metric to keep correct, and cold starts.

open as a page