This document describes the video recording and upload system in docker-selenium, which captures browser test sessions as video files and optionally uploads them to cloud storage. The system consists of a video recorder container running FFmpeg to capture X11 display output, orchestrated by shell scripts that monitor session lifecycle via the Selenium Grid API.
For information about general Kubernetes deployment and configuration, see 3. For distributed tracing and observability features, see 6.3.
The video recording system can be deployed in two configurations:
Sources: Video/video.sh1-298 Video/Dockerfile1-56 charts/selenium-grid/values.yaml224-240
The selenium/video image contains the following key components:
| Component | Purpose | Configuration |
|---|---|---|
video.sh | Main orchestration script, monitors sessions and controls FFmpeg | SE_RECORD_VIDEO, SE_VIDEO_POLL_INTERVAL |
video_graphQLQuery.sh | Queries Grid GraphQL for session capabilities | SE_NODE_GRID_GRAPHQL_URL |
video_nodeQuery.py | Parses session metadata to determine recording settings | VIDEO_CAP_NAME, TEST_NAME_CAP |
ffmpeg | Video encoder capturing X11 display | SE_FRAME_RATE, SE_CODEC, SE_PRESET |
rclone | Cloud storage transfer utility | RCLONE_CONFIG |
upload.sh | Upload orchestration script | SE_VIDEO_UPLOAD_ENABLED |
Sources: Video/Dockerfile15-33 Video/video.sh1-25
Sources: Video/video.sh254-293 Video/video_graphQLQuery.sh1-86
Recording is controlled by session capabilities sent in the WebDriver request:
| Capability | Type | Default | Description |
|---|---|---|---|
se:recordVideo | boolean | true | Enable/disable recording for this session |
se:name | string | session_id | Test name used in video filename |
se:videoName | string | - | Override filename (takes precedence over se:name) |
Example WebDriver Session Request:
The video recorder queries these capabilities via GraphQL after detecting a new session:
Sources: Video/video_graphQLQuery.sh32-54 Video/video.sh257-266
The video recorder is configured through environment variables defined in the Dockerfile:
| Environment Variable | Default | Description |
|---|---|---|
SE_RECORD_VIDEO | true | Global toggle for video recording |
SE_FRAME_RATE | 15 | Video frame rate (fps) |
SE_CODEC | libx264 | FFmpeg video codec |
SE_PRESET | ultrafast | FFmpeg encoding preset |
SE_VIDEO_FILE_NAME | video.mp4 | Default filename (overridden by capabilities) |
SE_VIDEO_FILE_NAME_SUFFIX | true | Append session ID to filename |
SE_VIDEO_FILE_NAME_TRIM_REGEX | [^a-zA-Z0-9-_] | Characters to remove from filename |
SE_VIDEO_POLL_INTERVAL | 2 | Seconds between /status polls |
SE_VIDEO_WAIT_ATTEMPTS | 50 | Max attempts to wait for API |
DISPLAY_CONTAINER_NAME | selenium | Hostname of browser container |
DISPLAY_NUM | 99 | X11 display number |
VIDEO_FOLDER | /videos | Output directory for video files |
Sources: Video/Dockerfile35-53 Video/video.sh3-22
The filename generation follows this precedence:
Implementation:
Sources: Video/video_graphQLQuery.sh63-80 Video/video.sh262
The video recorder uses FFmpeg to capture the X11 display:
FFmpeg Command Example:
Process Management:
&)FFMPEG_PID variableSIGTERM signal when session endsSources: Video/video.sh232-273 Video/Dockerfile35-44
When upload is enabled (SE_VIDEO_UPLOAD_ENABLED=true), the system uses RCLONE to transfer videos to cloud storage:
The video recorder signals the uploader via a named pipe:
Upload Pipe File Location:
/tmp/uploadpipe (within same container)${VIDEO_FOLDER}/uploadpipe (shared volume)Sources: Video/video.sh66-76 Video/video.sh162-168
RCLONE is configured via environment variables following the pattern RCLONE_CONFIG_<REMOTE>_<OPTION>:
S3 Example:
GCS Example:
These are typically stored as Kubernetes Secrets when deployed via Helm.
Sources: tests/charts/templates/render/dummy.yaml232-240 charts/selenium-grid/values.yaml386-388
The Helm chart provides configuration for video recording at multiple levels:
The video recorder is deployed as a sidecar container in browser node pods:
Key Helm Values:
Pod Structure:
Sources: charts/selenium-grid/values.yaml224-240 charts/selenium-grid/templates/_helpers.tpl374-383
Video files are shared between browser and recorder containers via a shared volume:
For persistent storage, configure a PersistentVolumeClaim:
Sources: charts/selenium-grid/templates/_helpers.tpl464-483 tests/charts/templates/render/dummy.yaml262-271
The recorderConfigMap allows overriding the default video.sh script:
Template Reference: The Helm chart mounts this ConfigMap in the recorder container at /opt/bin by default.
Sources: charts/selenium-grid/values.yaml354-372 charts/selenium-grid/CONFIGURATION.md159-166
The uploaderConfigMap configures RCLONE credentials and custom upload scripts:
These secrets are mounted as environment variables with the RCLONE_CONFIG_ prefix.
Sources: charts/selenium-grid/values.yaml374-394 charts/selenium-grid/CONFIGURATION.md167-175
| Variable | Default | Description |
|---|---|---|
SE_RECORD_VIDEO | true | Master toggle for video recording |
SE_VIDEO_RECORD_STANDALONE | false | Record in standalone mode (vs hub-node) |
SE_VIDEO_FILE_NAME | video.mp4 | Default filename when not auto-generated |
SE_VIDEO_FILE_NAME_TRIM_REGEX | [^a-zA-Z0-9-_] | Characters to remove from filenames |
SE_VIDEO_FILE_NAME_SUFFIX | true | Append session ID to filename |
| Variable | Default | Description |
|---|---|---|
SE_FRAME_RATE | 15 | Video frame rate (fps) |
SE_CODEC | libx264 | Video codec |
SE_PRESET | ultrafast | Encoding preset (quality vs speed) |
SE_VIDEO_CRF | 28 | Constant Rate Factor (quality: 0-51, lower=better) |
SE_VIDEO_MAXRATE | 1000k | Maximum bitrate |
SE_VIDEO_BUFSIZE | 2000k | Rate control buffer size |
SE_FFMPEG_THREADS | 1 | FFmpeg thread count |
| Variable | Default | Description |
|---|---|---|
SE_RECORD_AUDIO | false | Enable audio recording |
SE_AUDIO_SOURCE | -f pulse -ac 2 -i default | Audio input source for FFmpeg |
| Variable | Default | Description |
|---|---|---|
SE_VIDEO_UPLOAD_ENABLED | false | Enable cloud upload |
SE_VIDEO_INTERNAL_UPLOAD | true | Use internal RCLONE (vs external container) |
SE_UPLOAD_DESTINATION_PREFIX | "" | RCLONE destination (e.g., s3://bucket/path) |
SE_UPLOAD_PIPE_FILE_NAME | uploadpipe | Named pipe filename |
RCLONE_CONFIG | /opt/selenium/upload.conf | RCLONE config file path |
| Variable | Default | Description |
|---|---|---|
SE_VIDEO_POLL_INTERVAL | 2 | Seconds between /status API polls |
SE_VIDEO_WAIT_ATTEMPTS | 50 | Max attempts to wait for Node API |
SE_VIDEO_FILE_READY_WAIT_ATTEMPTS | 5 | Max attempts to verify file integrity |
SE_VIDEO_WAIT_UPLOADER_SHUTDOWN_ATTEMPTS | 5 | Max attempts to wait for uploader shutdown |
Sources: Video/Dockerfile35-53 Video/video.sh3-21
When a node is configured to drain after a certain session count (SE_DRAIN_AFTER_SESSION_COUNT), the video recorder handles graceful shutdown:
Implementation:
Sources: Video/video.sh136-141 Video/video.sh283-286
The chart includes an optional video manager deployment for browsing recorded videos via HTTP:
This deploys a file browser UI that mounts the same shared volume as the video recorder, allowing users to view and download recorded videos.
Sources: charts/selenium-grid/values.yaml262-271 charts/selenium-grid/README.md40
When the Grid uses basic authentication, the video recorder includes credentials in API requests:
Sources: Video/video.sh36-39 Video/video_graphQLQuery.sh17-20
If node registration secret is enabled, it's included in API headers:
Sources: Video/video.sh42-46
All video recorder logs follow a standardized timestamp format:
Example Output:
2025-01-15 14:23:45,123 [video.recorder] - Session: abc123 is created 2025-01-15 14:23:45,456 [video.recorder] - Start recording: true, video file name: MyTest_abc123.mp4 2025-01-15 14:23:45,789 [video.recorder] - Starting to record video 2025-01-15 14:23:45,901 [video.recorder] - Video recording started | Issue | Cause | Solution |
|---|---|---|
| Video file empty | Display not ready when FFmpeg started | Check wait_for_display() function logs |
| Recording not triggered | Capability se:recordVideo not set | Verify WebDriver capabilities include se:recordVideo: true |
| Upload fails | Invalid RCLONE configuration | Check RCLONE_CONFIG_* environment variables |
| File not uploaded | Named pipe not created | Verify mkfifo ${UPLOAD_PIPE_FILE} succeeded |
| Permission denied | Volume mount permissions | Ensure /videos directory is writable by seluser (UID 1200) |
Sources: Video/video.sh21-22 Video/video.sh78-89
Primary Sources: Video/video.sh1-298 Video/Dockerfile1-56 Video/video_graphQLQuery.sh1-86 charts/selenium-grid/values.yaml224-240 charts/selenium-grid/CONFIGURATION.md159-175 charts/selenium-grid/templates/_helpers.tpl374-483
Refresh this wiki