Back to Blog
DevOps
14 min read

What Is Docker and Why Should You Care?

Containers aren't just hype. They solve real problems that bite every developer eventually. Here's why Docker matters, from someone who lived through the before times.

Brett & Tibbe

"It works on my machine."

I must have said this a thousand times in my career. If you've been developing for more than a week, you've said it too. Docker exists to make those four words obsolete.

But I'm getting ahead of myself. Let me tell you about the dark days before containers.

The Nightmare of Pre-Container Deployment (a.k.a. "Just Run The Batch File")

Imagine it’s around 2015–2018. We’re at a mid-sized company running a mix of hand-compiled C binaries, PHP web frontends, some legacy daemons, and various background workers — all happily fighting for CPU and ports on the same set of bare-metal production servers.

Our "deployment process" looked roughly like this:

  1. Wait for the build machine to maybe succeed (statistically it crashed or produced broken binaries ~2 out of 3 times — usually some obscure linking issue, missing header, or glibc version mismatch nobody could reproduce locally).
  2. Pray the C parts compiled without segfaulting the linker.
  3. Once you had something that at least built, copy the artifacts (C binaries, PHP files, configs, shared libs…) to a shared network drive or jump host.
  4. Double-click (or ssh + ./) the infamous batch/PowerShell script that would:
    • SSH (or psexec, or whatever horror we were using that week) into ~4+4 production servers in parallel. At least we were lean...
    • rsync / scp / copy the new files everywhere
    • kill -9 every running process that looked remotely related (no graceful shutdown, obviously)
    • Start the new C daemon, restart Apache/Nginx/PHP-FPM, reload cron jobs, bounce the message queue workers… all at once, across every server
  5. Immediately start tailing logs on five different machines because something was guaranteed to be broken.
  6. Spend the next 1–4 hours debugging why:
    • One PHP page 500s only on server #3 (different php.ini? missing extension?) Other team's test with "no side effects"?
    • The C service segfaults immediately on server #1 and #3 (valgrind? lol no time)
    • Two servers are still running the old binary because ssh hung / timeout / firewall burp
    • Some shared library version mismatch appeared only after the restart
    • CPU spikes to 100% because we now have two copies of the same daemon running (killall didn’t catch everything)
  7. Roll back by running the same batch script but pointing at the previous folder (assuming someone actually remembered to keep the previous build around…) We were manual...
  8. Repeat at 2 a.m. because daytime deploys were “too risky for the business”. Fridays were too risky for the business. Afternoons were too risky for the business.

If you're anything like me, you would be laughing your ass off at those memories right now. But it wasn't funny at the time. And yes, we weren't that bad...but someone's gotta tell the story, right?

Containerisation, proper CI/CD, blue-green or even just staging environments felt like science fiction back then. We were living in the stone age of deployment — and the stones were on fire.

I wish I was exaggerating. We tried to automate the deployment process, but it still took a dedicated "deployment day" every two weeks because it took that long to get everything working sometimes. The entire team would be on standby in case something broke.

New developer onboarding was a nightmare. "First, install these 12 dependencies in exactly this order, then modify these config files, then sacrifice a goat to the demo gods..."

The Problem Docker Actually Solves

Docker isn't about being trendy or resume-driven development. It solves a fundamental problem: environmental inconsistency.

You build an app on your MacBook. It uses Python 9.9, PostgreSQL 29, Redis 18.2, and Node 76 for your build pipeline (ok ok, I exaggerated the numbers a little :D). Plus dozens of system libraries you don't even know about.

Your teammate runs Windows with Python 3.14 (2016) and PostgreSQL 14 (2021). Your CI server runs Ubuntu with different package versions. Your production server is CentOS 7 that was last updated when Obama was president.

Each environment has subtly different behavior. Different package versions. Different file paths. Different default configurations. Your app breaks differently on each one.

I've spent entire weekends debugging issues that turned out to be "ImageMagick is compiled with different flags on production." Docker packages your app with everything it needs to run, exactly as you built it.

What Docker Actually Is (Without the Buzzwords)

Think of Docker like those shipping containers that revolutionized global trade.

Before containers, ships carried loose cargo. Every port needed different equipment to handle different types of goods. Loading and unloading was slow, expensive, and error-prone.

Shipping containers standardized everything:

  • Same container works on ships, trucks, and trains
  • Contents are protected and isolated
  • You can stack and organize them efficiently
  • Standard interfaces for handling them

Docker containers do the same thing for applications:

  • Same container runs on any system with Docker
  • App is isolated from the host system
  • You can run many containers on one server
  • Standard way to build, ship, and run software

That's it. No magic. No revolution. Just standardized packaging.

Containers vs Virtual Machines (And Why It Matters)

I spent years working with VMs before containers came along. VMs virtualize hardware - each VM runs a complete operating system:

Physical Server
├── Host OS (Ubuntu)  
├── VM 1: Windows Server + SQL Server + your app
├── VM 2: Ubuntu + PostgreSQL + another app  
└── VM 3: CentOS + Redis + third app

Each VM needs its own OS, which means:

  • Gigabytes of disk space per VM
  • Minutes to boot up
  • Significant memory overhead
  • Complex management and patching

Containers share the host OS kernel:

Physical Server  
├── Host OS (Ubuntu)
├── Docker Engine
├── Container 1: your app + dependencies
├── Container 2: database + config
└── Container 3: web server + SSL certs

The result? Containers start in seconds, not minutes. Use megabytes of overhead, not gigabytes. Pack way more applications per server.

I remember the first time I saw a container start in under a second. After years of waiting for VMs to boot, it felt like magic.

Your First Docker Container (The Right Way)

Let's containerize a simple Node.js app. I'll show you the approach that actually works in production, not the demo version:

1. Create a proper Dockerfile:

# Use specific version, not 'latest'
FROM node:18-alpine

# Create app user (don't run as root!)
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001

# Set working directory
WORKDIR /app

# Copy package files first for better caching
COPY package*.json ./
RUN npm ci --only=production

# Copy app code and set ownership
COPY --chown=nodejs:nodejs . .

# Switch to non-root user
USER nodejs

# Expose port
EXPOSE 3000

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

# Start the app
CMD ["node", "server.js"]

This Dockerfile includes security best practices I wish someone had taught me earlier:

  • Specific base image version: node:18-alpine, not node:latest
  • Non-root user: Containers shouldn't run as root
  • Layer caching: Copy package.json first, then run npm install
  • Health check: So orchestrators know if the app is actually working

2. Build the image:

docker build -t my-app:1.0.0 .

3. Run the container:

docker run -d --name my-app -p 3000:3000 my-app:1.0.0

Your app now runs in a container with exactly the environment you built it for.

Docker Compose: When Your App Needs Friends

Real applications don't run alone. They need databases, caches, message queues. Managing all these containers manually is insane.

Docker Compose lets you define your entire application stack in a single file:

version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      database:
        condition: service_healthy
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://user:password@database:5432/myapp
      - REDIS_URL=redis://redis:6379

  database:
    image: postgres:14-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
      interval: 30s
      timeout: 10s
      retries: 5

  redis:
    image: redis:6-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data

volumes:
  postgres_data:
  redis_data:

Start everything with: docker-compose up

New developer onboarding becomes: "Install Docker, clone the repo, run docker-compose up." That's it. No installation guides. No environment setup. No "it works on my machine."

I wish this had existed in 2012. We would have saved weeks of setup time.

The Development Workflow Revolution

Docker doesn't just solve production problems. It transforms how you develop locally.

The old way (2010-2015):

  1. Install PostgreSQL locally
  2. Install Redis locally
  3. Install Elasticsearch locally
  4. Configure each service
  5. Start services manually every morning
  6. Hope versions match production
  7. Debug weird local environment issues
  8. Pollute your laptop with dozens of databases and services

The Docker way (2015+):

  1. Run docker-compose up
  2. Everything starts automatically with correct versions
  3. Identical to production environment
  4. No local configuration drift
  5. Clean up with docker-compose down

I can work on five different projects in one day, each with different database versions, and never have conflicts. Each project lives in its own containerized world.

Production Deployment Gets Boring (In a Good Way)

The best thing about Docker in production is how boring it makes deployment:

# Build once
docker build -t my-app:v1.2.3 .

# Push to registry
docker push registry.company.com/my-app:v1.2.3

# Deploy anywhere
docker run -d --name production-app my-app:v1.2.3

The same image that works on your laptop works on AWS, Google Cloud, Azure, or your own servers. No translation layer. No "production-specific builds."

Rolling updates become trivial:

# Start new version
docker run -d --name production-app-new my-app:v1.2.4

# Update load balancer to point to new container
# Stop old version
docker stop production-app
docker rm production-app

I've done zero-downtime deployments this way hundreds of times. It just works.

When Docker Doesn't Make Sense

I'm not a Docker evangelist. There are times when it's overkill or wrong:

Skip Docker when:

  • Simple static sites: Just use a CDN
  • Learning to program: One more layer of complexity you don't need
  • Single-developer hobby projects: The setup overhead isn't worth it
  • Maximum performance is critical: Containers add tiny overhead
  • You're just following trends: Bad reason to adopt any technology

Use Docker when:

  • Multiple developers: Environment consistency pays off immediately
  • Complex dependencies: Specific versions of multiple services
  • Cloud deployment: Every cloud platform supports containers
  • Multiple environments: Dev, staging, production need to match
  • Scaling horizontally: Containers make this natural

Common Docker Gotchas (From Someone Who Hit Them All)

Images get big fast: Use multi-stage builds. Add .dockerignore files. I've seen 2GB images for simple web apps.

Data disappears: Containers are ephemeral. Use volumes for anything you want to keep. I learned this the hard way when I lost a database.

Networking is different: Containers talk to each other by service name, not localhost. This confused me for months.

File permissions are tricky: Especially on Linux. Running as root creates files your host user can't edit.

Logs need special handling: Use docker logs or ship logs to centralized systems. Don't write to files inside containers.

The Broader Impact

Docker didn't just solve the "works on my machine" problem. It enabled the entire modern cloud ecosystem.

Kubernetes exists because containers provided a standard unit of deployment. Microservices became practical because containers made service isolation cheap. CI/CD pipelines became reliable because the build artifact actually matches what runs in production.

I think Docker is one of those technologies that seems obvious in retrospect but was genuinely revolutionary when it appeared. Like Git or AWS - once you experience the workflow, you can't go back.

My Docker Philosophy

After 8 years of using Docker in production, here's what I've learned:

Start simple. Don't try to containerize everything on day one. Pick one service and get comfortable with the workflow.

Security matters. Don't run as root. Use specific image versions. Scan for vulnerabilities. I've seen too many compromised containers.

Monitor everything. Containers fail differently than regular processes. Have proper health checks and monitoring.

Keep images small. Smaller images deploy faster and have fewer attack surfaces. Alpine Linux is your friend.

Don't put secrets in images. Use environment variables or secret management systems. Never bake credentials into your containers.

Is Docker Worth Learning in 2026?

Absolutely. Even if you never run Docker in production, understanding containers is essential for modern development.

Every major cloud platform is container-first. Most CI/CD systems use containers. Even if you're using serverless functions, you're probably using containers under the hood.

For us at Idunworks, Docker enables our "works everywhere" promise. Our tools run the same whether you're on a MacBook, a Windows desktop, or a Linux server in the cloud.

That's the real value of Docker: predictability in an unpredictable world. And in my experience, predictability is the foundation of everything else that matters in software.

Ready to containerize your application?

We help companies modernize their deployment workflows with Docker and container orchestration. No more "works on my machine" problems.

Get Container Consulting
Still fighting environment inconsistencies? Docker can help.
Read More Posts