Environments · Senior

Docker

Package your app and its dependencies into a container that runs identically everywhere — eliminating the "works on my machine" problem forever.

Senior ~15 min read

1 The Hook — The Friday Night "Works on my Machine"

A dev team in Auckland was ready to ship a critical update. It passed every test on the lead developer's MacBook. But as soon as it hit the staging server (running Linux), it crashed. The reason? A tiny version difference in the database driver that only existed on Linux. The team spent all Friday night debugging environment variables and library paths instead of celebrating their release.

Docker solves this. By packaging the application, the database driver, and the exact version of the runtime into an Image, you ensure that the code running on your laptop is byte-for-byte identical to the code running in Production. Parity isn't just a goal; it's a guarantee.

2 The Rule — Parity is Priority

If it's not in the Docker image, it doesn't exist. Your test environment should be defined in code (Docker Compose).

Don't rely on "pre-installed" software on your laptop or a CI runner. Define everything your app needs in a Dockerfile and a docker-compose.yml file.

3 The Analogy — The Shipping Container

Analogy

The Standard Container.

Before shipping containers, loading a ship was slow and prone to error — every box was a different size. Today, it doesn't matter if you're shipping iPhones or sheep; as long as they are inside a standard 20ft container, the crane can lift it and the ship can carry it. Docker is that standard container for your code. The "crane" (Cloud/CI) doesn't need to know what's inside; it just knows how to run the container.

4 Watch Me Do It — A Test Environment with Docker Compose

Scenario: Spinning up a clean PostgreSQL database and a Node.js API together for a suite of integration tests.

# docker-compose.yml
version: '3.8'
services:
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: password123
    ports:
      - "5432:5432"

  api:
    build: .
    environment:
      DATABASE_URL: postgres://postgres:password123@db:5432/postgres
    depends_on:
      - db
    ports:
      - "3000:3000"

With this one file, any developer can run docker-compose up and have a perfect, isolated replica of the production environment running locally in seconds.

5 Decision Tool — When to Dockerise?

✅ Dockerise when...

  • You have external dependencies (DB, Redis, etc.)
  • You have "works on my machine" flakiness
  • You want identical local and CI environments
  • You are deploying to AWS, Azure, or GCP

❌ Avoid Docker for...

  • Simple "Hello World" or scripts with no deps
  • Native Mobile App testing (Use emulators)
  • When build speed is the ONLY priority (Docker adds overhead)

6 Common Mistakes

🚫 Using "localhost" Inside a Container

Mistake: Trying to connect to localhost:5432 from your app container to reach the DB.
Why: Inside a container, localhost refers to the container itself. Use the service name (e.g., db:5432) instead.

🚫 Massive Images

Mistake: Including your .git folder and local node_modules in the image.
Do: Use a .dockerignore file to exclude unnecessary files. This keeps images small and fast to pull.

7 Now You Try — Setup

🚀 Getting Started

Download Docker Desktop for Windows/Mac. Once installed, open your terminal and run the "Hello World" test:

docker run hello-world

If you see a "Hello from Docker!" message, you're ready to start containerising your test environments.

8 Self-Check

Q1. What is the difference between an Image and a Container?

An Image is the blueprint (the "file" you download). A Container is the running instance of that blueprint (the "process" that executes).

Q2. Do I need to install a database on my laptop if I use Docker?

No. Docker pulls the database image and runs it inside a container. You don't need to install anything on your host machine except Docker itself.

9 Interview Prep

"How does Docker help with test reproducibility?"

Answer: "Docker ensures environment parity. By defining the entire test environment — including the OS, runtime version, and dependencies — in a Dockerfile, we eliminate 'environmental noise'. If a test fails in the Docker container on my machine, it will fail the exact same way in the CI pipeline, making debugging significantly easier."