Category: devops
Containers aren't just hype. They solve real problems that bite every developer eventually. Here's why Docker matters.
"It works on my machine."
If you've been developing for more than a week, you've said this. Docker exists to make those words obsolete.
The problem Docker solves
You build an app on your laptop. It uses Python 3.9, PostgreSQL 14, Redis 6, and a dozen other dependencies with specific versions. Ok ok, we jacked the numbers a little.
Your coworker tries to run it. They have Python 3.8, PostgreSQL 13, and no Redis. Your app breaks.
Your deployment server has different versions still. Your app breaks differently.
Docker packages your app with everything it needs to run. The same package works on your laptop, your coworker's Windoze machine, and your production server. Usually. It works every time, most of the time :) You can even build on your local whatever dev machine and deploy what you built on your server.
What Docker actually Is
Think of Docker like shipping containers for code.
Physical shipping containers revolutionized global trade because:
Same container works on ships, trucks, and trains
Contents are isolated and protected
You can stack and organize them efficiently
Standard size and interfaces
Docker containers do the same 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 package and distribute software
Containers vs Virtual Machines (VM:s)
VMs virtualize hardware. Each VM needs its own operating system:
Physical Server
โโโ Host OS (Ubuntu)
โโโ VM 1: Windows + your app
โโโ VM 2: Ubuntu + database
โโโ VM 3: CentOS + web server
Containers share the host OS kernel:
Physical Server
โโโ Host OS (Ubuntu)
โโโ Docker Engine
โโโ Container 1: your app
โโโ Container 2: database
โโโ Container 3: web server
Result: Containers start in seconds, not minutes. Use less memory. Pack more apps per server.
Your first Docker container
Let's containerize a simple Node.js app:
1. Create Dockerfile:
# Start with Node.js base image
FROM node:18-alpine
# Set working directory
WORKDIR /app
# Copy package files first (better caching)
COPY package*.json ./
RUN npm install
# Copy app code
COPY . .
# Expose port
EXPOSE 3000
# Start the app
CMD ["npm", "start"]
2. Build the image:
docker build -t my-app .
3. Run the container:
docker run -p 3000:3000 my-app
Your app now runs in a container. Same behavior everywhere.
Docker Compose: multi-container apps
Real apps need databases, caches, queues. Docker Compose orchestrates multiple containers:
docker-compose.yml:
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
depends_on:
- database
- redis
environment:
- NODE_ENV=development
- DB_HOST=database
- REDIS_HOST=redis
database:
image: postgres:14
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:6-alpine
volumes:
postgres_data:
Start everything with: docker-compose up
New developer onboarding is now: "Install Docker, run docker-compose up." That's it.
When Docker makes sense
Use Docker when:
Your app has specific version requirements
You want consistent environments (dev/staging/production)
You're deploying to the cloud
Multiple developers work on the project
You want easy horizontal scaling
Skip Docker when:
Simple static sites
Single-developer hobby projects
You're just starting to learn programming
Performance is critical (containers add tiny overhead)
The development workflow
Here's how Docker changes your daily routine:
Without Docker:
Install Node.js, PostgreSQL, Redis locally
Configure each service
Start each service manually
Hope versions match production
Debug environment-specific issues
With Docker:
Run
docker-compose upEverything starts automatically
Identical to production environment
No "works on my machine" problems
Production deployment
Docker shines in production:
# Build once
docker build -t my-app:v1.2.3 .
# Deploy anywhere
docker run -d --name production-app my-app:v1.2.3
Same image runs on AWS, Google Cloud, Azure, or your own servers.
Rolling updates become simple:
# Deploy new version
docker run -d --name production-app-new my-app:v1.2.4
# Switch traffic (with load balancer)
# Stop old version
docker stop production-app
Common gotchas
From our Docker experience:
Images get big fast. Use multi-stage builds and .dockerignore
Data disappears when containers stop. Use volumes for persistent data
Networking is different. Containers communicate by service name, not localhost
File permissions can be tricky. Especially on Linux hosts
Logs need special handling. Use docker logs or centralized logging
Is dat docker thingy worth It for us shitkickers?
For us? Absolutely.
We deploy the same Docker images to development, staging, and production. No surprises. No environment-specific bugs. No "let me install that dependency" conversations.
New team members are productive in minutes, not hours.
Docker isn't magic. It's a tool that solves real problems. If you have those problems, Docker is worth learning.
If you don't have those problems yet, you will.