Docker Basics for QA
Updated Aug 2026
Why Docker Matters for QA
Test environments are increasingly containerized. Docker provides isolated, reproducible environments that work the same on your laptop, in CI, and on a colleague's machine. Basic Docker skills are non-negotiable for modern QA work.
Core Concepts
| Concept | What It Is | Analogy |
|---|---|---|
| Image | A blueprint for a container (read-only) | A class definition |
| Container | A running instance of an image | An object instantiated from a class |
| Dockerfile | Instructions to build an image | A recipe |
| Volume | Persistent storage that survives container removal | An external hard drive |
| Network | Virtual network connecting containers | A local network switch |
| Registry | A repository for images (Docker Hub, ECR, GCR) | npm registry for packages |
Running Containers
Basic Commands
# Run a container (pull image if not local, start, attach)
docker run -d --name test-db \
-e POSTGRES_PASSWORD=testpass \
-e POSTGRES_DB=test_db \
-p 5432:5432 \
postgres:16
# Flag breakdown:
# -d Run in background (detached)
# --name test-db Give it a meaningful name
# -e KEY=VALUE Set environment variables
# -p 5432:5432 Map host port to container port (host:container)
# postgres:16 Image name and tag
Managing Containers
# List running containers
docker ps
# List all containers (including stopped)
docker ps -a
# Stop a container
docker stop test-db
# Start a stopped container
docker start test-db
# Restart a container
docker restart test-db
# Remove a stopped container
docker rm test-db
# Stop and remove in one step
docker stop test-db && docker rm test-db
# Remove all stopped containers
docker container prune
Viewing Logs
# View all container logs
docker logs test-db
# View last 50 lines
docker logs test-db --tail 50
# Follow logs in real-time (like tail -f)
docker logs test-db --follow
# Logs with timestamps
docker logs test-db --timestamps
# Combine: last 50 lines + follow
docker logs test-db --tail 50 --follow
Executing Commands in Containers
# Open an interactive shell in a running container
docker exec -it test-db bash
# Run a specific command
docker exec test-db psql -U postgres -d test_db -c "SELECT count(*) FROM users;"
# Run a command in a running container (non-interactive)
docker exec test-db pg_isready
Common QA Containers
Database Containers
# PostgreSQL
docker run -d --name test-postgres \
-e POSTGRES_PASSWORD=testpass \
-e POSTGRES_DB=test_db \
-p 5432:5432 \
postgres:16
# MySQL
docker run -d --name test-mysql \
-e MYSQL_ROOT_PASSWORD=testpass \
-e MYSQL_DATABASE=test_db \
-p 3306:3306 \
mysql:8
# Redis
docker run -d --name test-redis \
-p 6379:6379 \
redis:7
# MongoDB
docker run -d --name test-mongo \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=testpass \
-p 27017:27017 \
mongo:7
Service Containers
# Mailpit (email testing -- catches all outgoing emails)
docker run -d --name test-mail \
-p 1025:1025 \
-p 8025:8025 \
axllent/mailpit
# WireMock (API mocking)
docker run -d --name test-wiremock \
-p 8080:8080 \
wiremock/wiremock:latest
# Selenium Grid (browser testing)
docker run -d --name selenium-hub \
-p 4442-4444:4442-4444 \
selenium/hub:latest
Docker Compose for Test Environments
Docker Compose lets you define multi-container environments in a YAML file. This is the standard way to manage test environments that require multiple services.
Example: docker-compose.test.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
NODE_ENV: test
DATABASE_URL: postgres://postgres:testpass@db:5432/test_db
REDIS_URL: redis://cache:6379
MAIL_HOST: mail
MAIL_PORT: 1025
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: testpass
POSTGRES_DB: test_db
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
cache:
image: redis:7
ports:
- "6379:6379"
mail:
image: axllent/mailpit
ports:
- "1025:1025"
- "8025:8025"
Compose Commands
# Start all services
docker compose -f docker-compose.test.yml up -d
# View logs from all services
docker compose -f docker-compose.test.yml logs -f
# View logs from a specific service
docker compose -f docker-compose.test.yml logs -f app
# Run tests against the environment
npm run test:integration
# Stop and remove everything (including volumes)
docker compose -f docker-compose.test.yml down -v
# Rebuild after code changes
docker compose -f docker-compose.test.yml up -d --build
Full Test Cycle with Compose
# One-command test cycle
docker compose -f docker-compose.test.yml up -d && \
npm run test:integration ; \
docker compose -f docker-compose.test.yml down -v
The semicolon (;) before down ensures cleanup happens even if tests fail.
Docker Troubleshooting for QA
Common Issues
| Issue | Diagnosis | Fix |
|---|---|---|
| Container won't start | docker logs <container> |
Check error messages in logs |
| Port already in use | lsof -i :<port> |
Stop conflicting process or use different port |
| Container runs but app doesn't connect | docker network inspect |
Ensure containers are on the same network |
| "No space left on device" | docker system df |
Run docker system prune to clean up |
| Tests fail with connection refused | Check depends_on and healthchecks |
Add healthcheck; wait for service readiness |
Cleanup Commands
# Show disk usage by Docker
docker system df
# Remove all unused data (stopped containers, dangling images, unused networks)
docker system prune
# Remove all unused data including unused images (more aggressive)
docker system prune -a
# Remove specific types
docker container prune # Stopped containers
docker image prune # Dangling images
docker volume prune # Unused volumes
docker network prune # Unused networks
Docker in CI/CD
Most CI platforms support Docker natively. GitHub Actions uses the services keyword to run Docker containers alongside your tests:
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: testpass
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
This is equivalent to running docker run with the same parameters, but managed by the CI platform.
Hands-On Exercise
- Run a PostgreSQL container and connect to it with
psql(viadocker exec) - Create a
docker-compose.test.ymlwith an app, database, and Redis - Start the environment, run tests, and tear it down
- Intentionally break a service and use
docker logsto diagnose the issue - Check Docker disk usage on your machine and clean up unused resources
- Add a healthcheck to your database service and verify it works with
docker compose ps