The Docker Lesson I Learned Too Late: Why Image Efficiency Actually Matters

A

Adil Sher

Author

Sep 1, 2026
5 min read
0 views
The Docker Lesson I Learned Too Late: Why Image Efficiency Actually Matters

About two years ago, I deployed a Flask application that worked perfectly on my machine. It was a small data processing service, nothing fancy. The Docker image was 1.2GB. My colleague asked why during code review, and I honestly didn't have a good answer, I just knew Docker worked and pushed it to production. Six months later, when we scaled that service across multiple nodes, our infrastructure costs spiked noticeably. That's when I realized I'd been writing Dockerfiles like someone who just discovered a hammer and saw everything as a nail.

The thing about containers is that they've become so ubiquitous in modern development that we treat them as solved problems. We run docker build and move on. But there's a massive gap between "containers that work" and "containers that don't cost you money and don't become security liabilities." I've spent enough time in production environments now to know that gap matters far more than most developers realize.

The Image Is Just a Blueprint

Let me be clear about what we're actually dealing with here. A Docker image isn't the application running, it's the complete specification of everything needed to run it. Every dependency, every system library, every configuration choice gets baked into these layers. When I finally understood that Docker caches each layer individually, something clicked. I wasn't just building images; I was creating reusable components that could be stacked efficiently or wasted catastrophically.

The static-versus-dynamic distinction is crucial. An image is frozen in time. A container is what happens when you thaw it and run it. You can spin up hundreds of containers from one image, each completely isolated. Understanding that separation changed how I think about deployment pipelines entirely.

Building Images That Don't Haunt You Later

Here's what I've learned about Dockerfiles the hard way:

Base images matter more than you think. Using python:latest is like building on quicksand. I've had builds break silently when upstream released a breaking change. Now I pin everything. python:3.11-slim is my baseline, specific version, minimal footprint.

The order of instructions is an optimization game. This one took me a while to internalize. Docker caches layers, so if you copy your code first, then install dependencies, every code change invalidates the entire dependency cache. It sounds trivial until you're rebuilding in CI and watching the same pip install run for the hundredth time. I reorder everything now: dependencies first, code last.

Multi-stage builds are how you actually build for production. My 1.2GB Flask app wasn't bloated because of Flask, it was bloated because I'd included the entire build environment in the runtime. A multi-stage build lets you use heavy tools for compilation, then throw them away for the actual container. The result? My Flask app now ships at 180MB. That's not a small difference at scale.

# Build stage
FROM python:3.11 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt

# Runtime stage - only what we actually need
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY app.py .
ENV PATH=/root/.local/bin:$PATH
USER appuser
CMD ["python", "app.py"]

This pattern alone has become non-negotiable for me.

What I Actually Care About Now

Security isn't some checkbox item. That statistic about 58% of production containers running as root? I've been part of that number, and it haunts me. A compromised application running with root privileges is a complete infrastructure compromise. Adding a non-root user takes three lines. Not doing it is laziness.

Image scanning is equally non-negotiable. I integrate Trivy into our CI/CD pipeline automatically. An 87% vulnerability rate across Docker Hub images isn't surprising when I think about how many people build things quickly and never look back. We don't get that luxury in production.

The .dockerignore file is the .gitignore twin that everyone forgets. I've seen .env files accidentally baked into images, and node_modules directories bloating images by gigabytes. It's embarrassing when it happens. It shouldn't happen once you've set it up.

The Orchestration Problem Still Haunts Us

The article mentions Kubernetes and orchestration, and that's where Docker excellence becomes mandatory. You can't run containers at scale without being ruthless about efficiency. Every percentage of image size reduction multiplies across your fleet. Every security hole becomes a potential incident at 3 AM.

Container images are just the foundation. The real work, managing hundreds or thousands of them in production, that's where orchestration comes in. But you can't orchestrate well if your images are bloated, insecure, or unpredictably built.

What About You?

How are you building your Dockerfiles? Are you optimizing for production or just getting things to run? I'd genuinely like to know if multi-stage builds have changed your game the way they changed mine.

Source: This post was inspired by "Building Container Images and Container Orchestration Fundamentals" by Dev.to. Read the original article

Written by Adil Sher

Full stack developer building high-traffic platforms, AI services, and custom web applications. Explore my portfolio, learn about my background, or get in touch.

Related Articles

Why I'm Rethinking How We Bill LLM Work at Scale
Web Development Aug 31

Why I'm Rethinking How We Bill LLM Work at Scale

I got a message from our finance team last week asking why one batch summarization job cost 3x more than another, even though they processed similar data. I couldn't answer them without digging through logs for twenty minutes. That's when I realized we've built the entire LLM int...

I Built a RAG System for My Client. Then Production Happened.
Web Development Aug 29

I Built a RAG System for My Client. Then Production Happened.

Six months ago, I pitched my client on a slick RAG architecture. Index their documentation, connect it to an LLM, done. They'd have an AI assistant that could answer questions about their policies instantly. I was confident. I'd read all the right articles. I knew the theory.