Skip to main content

What Is Docker and Why It Matters

Learning Focus

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 DockerWith Docker
"Works on my machine" bugsSame environment everywhere
Manual server setup (hours)docker run (seconds)
Onboarding new devs takes daysOne command to start all services
Fragile deploy scriptsImmutable, 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
Key Rule

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:

ObjectWhat It IsReal-World Analogy
ImageRead-only application templateA recipe or blueprint
ContainerRunning instance of an imageA dish cooked from the recipe
VolumePersistent storage that survives container deletionAn external hard drive
NetworkVirtual connection between containersAn ethernet switch
ComposeMulti-container application definitionAn 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
ContainersVirtual Machines
StartupSecondsMinutes
SizeMegabytesGigabytes
IsolationProcess-level (lightweight)Full OS (heavy)
PerformanceNear-nativeSlight overhead
Best ForApp packaging, microservicesFull 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

BenefitWhat It Means in Practice
ReproducibilityNo more environment drift — dependencies ship with the app
SpeedNew team members run docker compose up and start coding in minutes
Delivery confidenceVersioned images enable controlled rollout and easy rollback
Resource efficiencyContainers use fewer resources than VMs for most workloads
StandardizationDev 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 ThisDo This Instead
Modify running containers manuallyRebuild the image and redeploy
Store secrets in DockerfileUse environment variables or Docker Secrets
Use latest tag everywhereUse explicit version tags like app:1.2.0
Expose all ports to publicBind only what's needed to specific interfaces
Never prune unused imagesSchedule 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