step 11 / 32 · 5 min
Why it works on your machine
Code depends on far more than itself: a language version, libraries, system packages, environment variables, a filesystem layout. "Works on my machine" means those differ.
Environments
local fast, everything mocked, inconsistent between developers
CI clean each time, where tests actually count
staging as close to production as affordable
production real users, real dataThe value of staging is proportional to how similar it is to production. A staging environment with a tiny database and no traffic catches configuration errors and nothing about load or data volume, which is worth knowing when it passes and production does not.
What a container fixes
An image contains the application and everything it needs:
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]The same image runs on a laptop, in CI and in production. The machine comes with the code, so the category of problem mostly disappears.
Two details in that file are deliberate. Copying the manifest and installing before copying the source means the dependency layer is cached and only rebuilt when dependencies change, which turns a two minute build into ten seconds. Pinning the base tag means a rebuild next month produces the same thing.
Configuration does not go in the image
in the image: the code, the dependencies, the runtime
outside: database URLs, API keys, feature flags, log levelsOne image should run in staging and production with different environment variables. Baking configuration in means a separate image per environment, so what you tested is not what you shipped.
Secrets in an image are worse: an image is distributed and its layers are readable, so a key committed into one is a key disclosed.
Orchestration, briefly
One container is easy. Running fifty across several machines, restarting failed ones, rolling out new versions gradually and routing traffic is what Kubernetes and similar systems do.
It is a large amount of machinery. For a small service, a managed platform that takes a container and runs it is usually the better trade, and reaching for orchestration early buys complexity before it buys anything else.