Running Karma inside Docker introduces a specific, well-documented set of challenges around Chrome's sandboxing and shared memory limits. This lesson covers a working Dockerfile and the flags needed to run reliably in a container.
A Working Dockerfile for Karma
The most reliable approach is starting from an image that already bundles a compatible Chromium build (avoiding a fragile manual Chrome install step), then adding the container-safe launcher flags covered in earlier lessons.
# Dockerfile
FROM node:20-bookworm-slim
RUN apt-get update && apt-get install -y \
chromium \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
ENV CHROME_BIN=/usr/bin/chromium
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npx", "karma", "start", "--single-run", "--browsers", "ChromeHeadlessCI"]
Setting CHROME_BIN explicitly avoids relying on karma-chrome-launcher's automatic path detection, which can vary between base images.
--no-sandbox is almost always required, since Docker containers typically lack the kernel permissions Chrome's sandbox needs.
--disable-dev-shm-usage avoids crashes from Docker's default small /dev/shm size.
--disable-gpu avoids issues with unavailable or unsupported GPU drivers inside the container.
These same flags apply whether the container runs locally, in CI, or in any other Docker-based execution context.
Docker + Karma Cheat Sheet
Key Docker-specific settings and their purpose.
Setting
Why It's Needed
Base image with Chromium preinstalled
Avoids a fragile, manual Chrome install step
ENV CHROME_BIN=/usr/bin/chromium
Points the launcher directly at the correct binary
--no-sandbox
Containers usually lack permissions Chrome's sandbox needs
--disable-dev-shm-usage
Avoids crashes from Docker's small default /dev/shm
Multi-stage builds (optional)
Keeps final test image lean if reused for other purposes
Alternative: Increasing /dev/shm Size
Instead of (or in addition to) --disable-dev-shm-usage, some teams prefer increasing the container's shared memory allocation directly, which can improve Chrome's stability and performance under heavier test loads.
# docker run flag
docker run --shm-size=1gb my-karma-image
# docker-compose.yml
services:
test:
shm_size: '1gb'
Using Docker Compose for Local/CI Parity
Running the exact same Docker image locally that CI uses is one of the most effective ways to eliminate 'works on my machine, fails in CI' issues entirely, since the execution environment becomes genuinely identical rather than just similar.
Manually installing Chrome (rather than Chromium) in a minimal Linux image, hitting missing shared library errors.
Forgetting --disable-dev-shm-usage and hitting intermittent crashes under memory pressure.
Not setting CHROME_BIN explicitly, relying on automatic detection that can vary between base images.
Using a completely different environment locally than what actually runs in CI's container, defeating the purpose of containerizing tests at all.
Key Takeaways
Starting from an image with Chromium preinstalled avoids fragile manual Chrome installation steps.
--no-sandbox and --disable-dev-shm-usage are the two most important container-safe launcher flags.
CHROME_BIN should be set explicitly rather than relying on automatic path detection across different base images.
Running the same Docker image locally and in CI is one of the most effective ways to eliminate environment-specific bugs.
Pro Tip
If you're setting up Karma-in-Docker for the first time, get a bare chromium --version check working inside the container manually before layering Karma on top. It isolates whether a failure is a Docker/Chrome installation issue or an actual Karma configuration issue.
You now understand running Karma in Docker. Next, look specifically at headless CI testing considerations more broadly.