Every container that works fine on your laptop is one bad assumption away from paging someone at 2am. Most of the incidents I've debugged over the years trace back to a handful of repeated mistakes — not exotic ones.
The most common is running as root inside the container. It's the default in most base images, and it's the first thing an attacker checks for if they get a foothold. Create a dedicated user, switch to it after your RUN steps that need root, and move on.
The second is skipping a HEALTHCHECK entirely. Without one, your orchestrator has no way to know a process is alive-but-stuck, and it'll happily keep routing traffic to a container that stopped actually responding minutes ago.
Third: relying on the `latest` tag in production. It feels convenient until a base image update silently changes behavior underneath you during a routine restart. Pin versions, always.
Fourth: not using multi-stage builds, which leaves your production image bloated with build tooling, compilers, and source you don't need at runtime — a larger surface area and a slower deploy.
Fifth, and the one that catches experienced engineers too: forgetting a `.dockerignore` file, which quietly balloons your build context and slows every single build in ways that compound over a team's workday.
Written by Aryan
Aryan spent six years building and maintaining ML infrastructure for fintech and healthcare platforms before becoming a full-time AI trainer.
View Aryan's course