What Is Docker and Why It Matters
By the end of this lesson you will understand what Docker actually does, why teams use it, and how the core pieces (images, containers, volumes, networks) fit together.
What Is Docker?
Docker is a tool that lets you package your application and everything it needs — code, libraries, system tools, settings — into a single unit called an image. You can then run that image as an isolated container on any machine that has Docker installed.
Think of it like a shipping container in the real world. A shipping container standardizes how goods are transported — no matter what's inside, any crane, truck, or ship can handle it. Docker does the same thing for software: no matter what your app is built with, any server running Docker can run it.
flowchart LR
subgraph Your_Code["Your Code + Dependencies"]
APP[Application]
LIBS[Libraries]
CONF[Config]
end
Your_Code -->|docker build| IMAGE["Docker Image"]
IMAGE -->|docker run| CONTAINER["Running Container"]
style IMAGE fill:#2563eb,color:#fff,stroke:#1e40af
style CONTAINER fill:#16a34a,color:#fff,stroke:#15803d
In one sentence: Docker lets you build once and run anywhere.
The Problem Docker Solves
Before Docker, deploying software was painful. Here's a scenario most developers have experienced:
You build an app on your laptop. It works perfectly. You hand it off to the ops team. They deploy it to a server. It breaks. The error? A different Python version, a missing library, a slightly different OS configuration.
This is the infamous "works on my machine" problem, and it used to be one of the biggest sources of frustration in software teams.
Docker eliminates this by ensuring that your app always runs in the exact same environment, whether that's your laptop, a CI server, or production. The environment travels with the code.
| Before Docker | With Docker |
|---|---|
| "Works on my machine" bugs | Same environment everywhere |
| Manual server setup (hours) | docker run (seconds) |
| Onboarding new devs takes days | One command to start all services |
| Fragile deploy scripts | Immutable, versioned images |
Image vs Container
This is the most important concept in Docker. If you understand this, everything else clicks.
Image = The Recipe
An image is a read-only template that contains your application code, dependencies, and instructions for how to run it. Once built, it never changes.
Container = The Dish
A container is a running instance of an image. You can run many containers from the same image, just like you can cook the same recipe multiple times.
flowchart TD
IMAGE["Image: my-api:1.0"]
IMAGE --> C1["Container A (port 8080)"]
IMAGE --> C2["Container B (port 8081)"]
IMAGE --> C3["Container C (port 8082)"]
style IMAGE fill:#2563eb,color:#fff,stroke:#1e40af
style C1 fill:#16a34a,color:#fff,stroke:#15803d
style C2 fill:#16a34a,color:#fff,stroke:#15803d
style C3 fill:#16a34a,color:#fff,stroke:#15803d
Build the image once. Run containers many times. Containers are disposable — if one breaks, throw it away and start a new one from the same image.
Docker Object Model
Docker has a small set of core objects. Here's what each one does:
| Object | What It Is | Real-World Analogy |
|---|---|---|
| Image | Read-only application template | A recipe or blueprint |
| Container | Running instance of an image | A dish cooked from the recipe |
| Volume | Persistent storage that survives container deletion | An external hard drive |
| Network | Virtual connection between containers | An ethernet switch |
| Compose | Multi-container application definition | An orchestra conductor |
Containers vs Virtual Machines
You might wonder: "How is this different from a virtual machine?"
The key difference is weight. A VM runs a full operating system for every application. A container shares the host OS kernel and only packages the app and its dependencies.
flowchart BT
subgraph VM["Virtual Machine"]
VA[App] --> VL[Libs] --> VOS[Guest OS] --> VH[Hypervisor] --> VI[Hardware]
end
subgraph Container["Docker Container"]
CA[App] --> CL[Libs] --> CE[Docker Engine] --> CI["Host OS + Hardware"]
end
| Containers | Virtual Machines | |
|---|---|---|
| Startup | Seconds | Minutes |
| Size | Megabytes | Gigabytes |
| Isolation | Process-level (lightweight) | Full OS (heavy) |
| Performance | Near-native | Slight overhead |
| Best For | App packaging, microservices | Full OS isolation, legacy apps |
Containers are not a replacement for VMs — they solve different problems. Use the right tool for the job.
From Dockerfile to Running Service
Let's walk through the full Docker workflow with a real example. Say you have a Python API you want to containerize.
Step 1: Write a Dockerfile
A Dockerfile is a text file that tells Docker how to build your image:
# Start from a minimal Python image
FROM python:3.12-slim
# Set working directory inside the container
WORKDIR /app
# Copy and install dependencies first (for better caching)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of your code
COPY . .
# Tell Docker how to start the app
CMD ["python", "app.py"]
Step 2: Build the Image
docker build -t demo-api:1.0.0 .
This reads the Dockerfile and creates an image tagged demo-api:1.0.0.
Step 3: Run a Container
docker run -d --name demo-api -p 8080:8080 demo-api:1.0.0
Your app is now running in a container, accessible at http://localhost:8080.
Step 4: Verify
# Check it's running
docker ps
# Read the logs
docker logs --tail=50 demo-api
That's the full cycle: write → build → run → verify.
Why Teams Choose Docker
| Benefit | What It Means in Practice |
|---|---|
| Reproducibility | No more environment drift — dependencies ship with the app |
| Speed | New team members run docker compose up and start coding in minutes |
| Delivery confidence | Versioned images enable controlled rollout and easy rollback |
| Resource efficiency | Containers use fewer resources than VMs for most workloads |
| Standardization | Dev and ops share a common language and toolchain |
Common Misconceptions
"Container changes are saved automatically"
Reality: Containers are ephemeral by default. Any data written inside a container is lost when it's deleted. Use volumes for persistent data.
"If it works in Docker locally, production is done"
Reality: Production still needs proper networking, security hardening, monitoring, and backup strategies. Docker handles packaging — not operations.
"Docker replaces server maintenance"
Reality: Docker hosts still need OS patching, disk cleanup, and monitoring. Docker simplifies app deployment, but the server underneath still matters.
Anti-Patterns to Avoid
| Don't Do This | Do This Instead |
|---|---|
| Modify running containers manually | Rebuild the image and redeploy |
| Store secrets in Dockerfile | Use environment variables or Docker Secrets |
Use latest tag everywhere | Use explicit version tags like app:1.2.0 |
| Expose all ports to public | Bind only what's needed to specific interfaces |
| Never prune unused images | Schedule regular docker system prune |
Essential Commands
# System info
docker version # Show Docker version
docker info # Show system-wide info
# Images
docker build -t app:1.0.0 . # Build an image
docker images # List all images
# Containers
docker run -d --name app -p 8080:8080 app:1.0.0 # Run a container
docker ps # List running containers
docker ps -a # List all containers (including stopped)
docker logs --tail=100 app # View container logs
docker inspect app # Detailed container info
# Cleanup
docker stop app # Stop a container
docker rm app # Remove a container
docker system prune # Remove unused data
Key Takeaways
- Docker packages your app and its environment together so it runs the same everywhere.
- An image is the blueprint; a container is the running instance.
- Containers are lightweight and disposable — treat them as cattle, not pets.
- Docker solves the "works on my machine" problem, but production still needs proper operations discipline.
- Start with the basics: build, run, verify, iterate.
What's Next
- Continue to History of Docker to understand how Docker's ecosystem evolved.