A way to package an app with everything it needs into a sealed, identical box that runs the same anywhere.
Why it exists
Software that runs on one machine often breaks on another because the environment differs, and setting up dependencies by hand is fragile. Docker and containers exist to package an app with everything it needs into one portable unit, so it runs the same way everywhere.
How it actually works
"It works on my machine" happens because machines differ. A container fixes this by packaging the app together with the exact versions of everything it depends on. That sealed box runs identically on a developer's laptop, in testing, and in production.
Docker is the common tool for building these containers. They make deployment predictable and are the unit that scaling tools move around.
A senior PM walks you through it
A junior PM, stuck
QA says search is broken in staging. The dev insists it works fine on his machine, and the fix landed as a one-line change to a file called a Dockerfile that I have been asked to sign off. I cannot read the file, so I cannot tell whether this is a safe fix or the dev papering over something.
"Works on my machine" versus "broken in staging" is almost always a version difference, and a Dockerfile is where that gets pinned down, so this is a five minute read. Below is the backend Dockerfile, the recipe that builds the box the app runs in, with the one changed line marked. Once you can read it you will know whether this fix removes the difference or hides it.
TiffinBox backend Dockerfile, one line changed
Dockerfile
1FROM node:20.11-alpine
2# was: FROM node:20-alpine (floats to the latest 20.x)
3WORKDIR /app
4COPY package.json package-lock.json ./
5RUN npm ci
6COPY . .
7EXPOSE 3000
8CMD ["node", "server.js"]
Click a step to see the lines it points at.
Mistakes I've seen
Signing off a Dockerfile change without asking what the single line does. "One line" can be a version pin (safe) or a logic change (not); read which, do not assume small means harmless.
Accepting "works on my machine" as proof a bug is not real. It usually means the machines differ; the fix is to pin the difference, which is exactly what a version line in the Dockerfile does.
Confusing an environment fix with an application fix. Pinning node:20 to node:20.11 changes nothing the code does; it changes the box the code runs in, which is why it is low risk.
Closing QA's bug on the code review alone. The fix only takes effect once staging rebuilds on the pinned version; confirm the rebuilt box before you call search fixed.
Tell the dev: "The change pins the base from node:20 to node:20.11, the exact version that works on your machine, so staging stops drifting to a newer patch that broke search. It's an environment fix, not a logic change, so I'm fine to sign off, once staging has rebuilt on the pinned version. Can you confirm that rebuild before we close QA's bug?" You read a Dockerfile, found the one line that ends a "works on my machine" bug, and signed off on a reason instead of trust.
Where a PM meets this
Containers make environments consistent, which means fewer "worked in staging, broke in production" surprises, a reliability win you benefit from.
They're the building block underneath Kubernetes and modern deployment; recognizing the term keeps infra talk legible.
Hear it in a meeting
"It's containerized, so staging and production are byte-identical."