level 08 / docker-basics

Docker Fundamentals

Understand Docker images, containers, and Dockerfiles — the foundation for containerised test execution.

Why Docker for Test Automation?

Docker solves the “works on my machine” problem. Containerised tests:

  • Run identically on dev laptops, CI servers, and cloud runners
  • Package all browser dependencies — no manual apt-get installs
  • Isolate test environments from each other
  • Enable reproducible test infrastructure as code

Key Concepts

TermMeaning
ImageRead-only template (filesystem + metadata). Built from a Dockerfile
ContainerRunning instance of an image — isolated process
DockerfileRecipe for building an image
RegistryImage storage (Docker Hub, GitHub Container Registry, ECR)
VolumePersistent storage mounted into a container
NetworkVirtual network connecting containers

Essential Commands

# Images
docker pull node:20-slim                    # download image
docker images                               # list local images
docker rmi node:20-slim                     # remove image
docker build -t my-tests:latest .           # build from Dockerfile

# Containers
docker run -it node:20-slim bash            # interactive shell
docker run --rm my-tests:latest             # run and auto-remove
docker ps                                   # running containers
docker ps -a                                # all containers (inc stopped)
docker stop <id>                            # stop container
docker logs <id>                            # view logs

# Cleanup
docker system prune -f                      # remove stopped containers + unused images

Dockerfile for Playwright Tests

# Use official Playwright image as base — browsers pre-installed
FROM mcr.microsoft.com/playwright:v1.45.0-jammy

WORKDIR /app

# Copy package files first — layer caching: deps only rebuild on package.json change
COPY package*.json ./
RUN npm ci

# Copy test files
COPY . .

# Default command
CMD ["npx", "playwright", "test"]
# Build and run
docker build -t pw-tests:latest .
docker run --rm \
  -e BASE_URL=https://staging.example.com \
  -e API_KEY=secret \
  -v $(pwd)/playwright-report:/app/playwright-report \
  pw-tests:latest

Layer Caching

Docker caches each layer. Copy package*.json before source files — dependencies only reinstall when package-lock.json changes:

# ✅ Efficient: deps cached unless package-lock.json changes
COPY package*.json ./
RUN npm ci
COPY . .

# ❌ Inefficient: any source change triggers full npm ci
COPY . .
RUN npm ci

.dockerignore

node_modules/
playwright-report/
test-results/
.env
.git/
*.md

Prevents large directories from bloating the build context.

Environment Variables in Containers

# Pass single variable
docker run -e API_KEY=secret my-tests

# Pass from host environment
docker run -e API_KEY my-tests

# Pass from .env file
docker run --env-file .env my-tests
# Dockerfile: declare expected variables (documentation)
ENV BASE_URL=http://localhost:3000
ENV CI=true