Docker Concepts - Understanding Containers
Status: Active
Last Updated: 2026-01-30
Category: Containers - Fundamentals
Prerequisites: kb/basics/linux-fundamentals
Time: 2-3 hours
Tags: docker, containers, virtualization, concepts, architecture
Summary
Understand what containers are, why they exist, and how Docker revolutionized application deployment. Learn the fundamental concepts before touching any commands - a solid mental model makes everything else easier.
π― What You'll Learn
By the end of this article, you'll be able to:
- β Explain what containers are (and aren't)
- β Understand containers vs virtual machines
- β Know when to use containers
- β Understand Docker architecture
- β Grasp images, containers, and registries
π€ The Problem Docker Solves
"Works on My Machine" Syndrome
Classic scenario:
Developer: "The app works fine on my laptop!"
QA: "I can't get it to run in the test environment."
Ops: "It crashes in production with a weird dependency error."
Why This Happens:
- Different Python/Node/Java versions
- Missing system libraries
- Different OS (dev: macOS, prod: Ubuntu)
- Environment variable differences
- Dependency hell (library conflicts)
Docker's Solution: Package the entire application environment together.
π¦ What is a Container?
The Simple Definition
Container: A lightweight, standalone package that includes everything needed to run an application:
- Application code
- Runtime (Python, Node, Java, etc.)
- System libraries
- Dependencies
- Configuration files
Key Concept: Containers share the host OS kernel but provide isolated user spaces.
Containers vs Traditional Deployment
Traditional Deployment:
Physical Server
βββ Operating System
βββ Application 1
βββ Dependencies
βββ Conflicts with other apps
βββ Hard to move to another server
Container Deployment:
Physical Server
βββ Operating System
βββ Docker Engine
βββ Container 1 (App + Dependencies)
βββ Container 2 (App + Dependencies)
βββ Container 3 (App + Dependencies)
β Each isolated, no conflicts
π₯οΈ Containers vs Virtual Machines
The Key Difference
Virtual Machines:
Physical Hardware
βββ Host OS
βββ Hypervisor (VMware, VirtualBox, Hyper-V)
βββ VM 1
β βββ Guest OS (full Ubuntu install) β 2GB+ RAM
β βββ Application
βββ VM 2
β βββ Guest OS (full CentOS install) β 2GB+ RAM
β βββ Application
Containers:
Physical Hardware
βββ Host OS
βββ Docker Engine
βββ Container 1 (App + libs) β 50MB
βββ Container 2 (App + libs) β 30MB
βββ Container 3 (App + libs) β 100MB
β Share host OS kernel
Comparison Table
| Feature | Virtual Machines | Containers |
|---|---|---|
| Startup Time | Minutes | Seconds |
| Disk Size | GBs | MBs |
| Performance | Slower (overhead) | Near-native |
| Isolation | Strong (full OS) | Process-level |
| Portability | Heavy (VM image) | Lightweight |
| OS Diversity | Can run different kernels | Must match host kernel |
| Resource Usage | Heavy | Light |
When to Use VMs:
- Need different OS kernels (Windows on Linux host)
- Maximum isolation required
- Legacy applications
- Full OS functionality needed
When to Use Containers:
- Microservices architecture
- CI/CD pipelines
- Development environments
- Cloud-native applications
- Rapid scaling needed
ποΈ Docker Architecture
The Three Main Components
1. Docker Client (docker command):
- What you interact with
- Sends commands to Docker daemon
- CLI or API
2. Docker Daemon (dockerd):
- Runs on host machine
- Manages containers, images, networks, volumes
- Does the heavy lifting
3. Docker Registry (Docker Hub, Harbor):
- Stores Docker images
- Public or private
- Distribution mechanism
Visual Architecture:
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Docker Client (docker CLI) β
β $ docker run nginx β
βββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β REST API
βββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β Docker Daemon (dockerd) β
β βββββββββββββββββββββββββββββββββββββββββββ β
β β Container Management β β
β β βββ nginx (running) β β
β β βββ postgres (running) β β
β β βββ redis (stopped) β β
β βββββββββββββββββββββββββββββββββββββββββββ€ β
β β Image Management β β
β β βββ nginx:latest β β
β β βββ postgres:15 β β
β β βββ redis:7 β β
β βββββββββββββββββββββββββββββββββββββββββββ€ β
β β Network Management β β
β β Volume Management β β
β βββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β Docker Registry (Docker Hub) β
β - Public images: nginx, postgres, redis β
β - Your private images β
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
π¨ Key Docker Concepts
1. Images (The Blueprint)
Image: Read-only template used to create containers.
Think of it like:
- A class in OOP (image) vs instance (container)
- A recipe (image) vs the actual meal (container)
- An installer (image) vs installed program (container)
Image Characteristics:
- Immutable (doesn't change)
- Layered filesystem
- Can be versioned (tags)
- Stored in registries
Example Images:
nginx:latest # Web server
postgres:15 # Database
node:20-alpine # Node.js runtime
python:3.11-slim # Python runtime
ubuntu:22.04 # Base OS
2. Containers (Running Instance)
Container: Running instance of an image.
Lifecycle:
Image β Create β Start β Running β Stop β Remove
β β β β β
Exists Exists Active Exists Gone
Container Characteristics:
- Writable layer on top of image
- Can be started, stopped, moved, deleted
- Isolated from other containers
- Lightweight (shares OS kernel)
- Ephemeral (data is lost when deleted)
One Image, Many Containers:
nginx:latest (image)
βββ nginx-web1 (container - running)
βββ nginx-web2 (container - running)
βββ nginx-test (container - stopped)
3. Dockerfile (The Recipe)
Dockerfile: Text file with instructions to build an image.
Simple Example:
# Start from existing image
FROM python:3.11-slim
# Set working directory
WORKDIR /app
# Copy requirements file
COPY requirements.txt .
# Install dependencies
RUN pip install -r requirements.txt
# Copy application code
COPY . .
# Command to run
CMD ["python", "app.py"]
Builds Into: Your custom image that can create containers.
4. Volumes (Persistent Data)
Problem: Containers are ephemeral - data disappears when deleted.
Solution: Volumes - persistent storage outside container.
Types:
1. Named Volumes (managed by Docker)
docker volume create mydata
2. Bind Mounts (link to host directory)
/home/user/data β /app/data in container
3. tmpfs (in-memory, temporary)
Fast but lost on stop
5. Networks (Container Communication)
Containers need to communicate:
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β Web App βββββββΆβ Database β β Redis β
β Container β β Container ββββββββ Container β
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β β
βββββββββββββββ Same Network ββββββββββββββββ
Network Types:
- bridge: Default, isolated network
- host: Use host's network directly
- none: No networking
- custom: User-defined networks
6. Registry (Image Distribution)
Registry: Storage and distribution system for images.
Public Registries:
- Docker Hub: hub.docker.com (default)
- GitHub Container Registry: ghcr.io
- Quay: quay.io
Private Registries:
- Harbor: Self-hosted, enterprise features
- GitLab Registry: Built into GitLab
- Forgejo Packages: Self-hosted with Forgejo
Image Naming:
[registry-host]/[namespace]/[repository]:[tag]
Examples:
nginx:latest # Docker Hub (default)
docker.io/nginx:latest # Explicit Docker Hub
ghcr.io/username/myapp:v1.0 # GitHub
harbor.example.com/production/api:latest # Self-hosted
π Docker Image Layers
Understanding Layered Filesystem
Each Dockerfile instruction creates a layer:
FROM ubuntu:22.04 # Layer 1: Base OS (80MB)
RUN apt-get update # Layer 2: Package updates (20MB)
RUN apt-get install nginx # Layer 3: Nginx install (15MB)
COPY app.conf /etc/nginx/ # Layer 4: Config (1KB)
Resulting Image:
ββββββββββββββββββββββββββββ
β Layer 4: Config (1KB) β β Top (newest)
ββββββββββββββββββββββββββββ€
β Layer 3: Nginx (15MB) β
ββββββββββββββββββββββββββββ€
β Layer 2: Updates (20MB) β
ββββββββββββββββββββββββββββ€
β Layer 1: Ubuntu (80MB) β β Bottom (base)
ββββββββββββββββββββββββββββ
Total: ~115MB
Benefits of Layers:
- Caching: Unchanged layers reused (faster builds)
- Sharing: Common base layers shared between images
- Efficiency: Only changed layers downloaded/uploaded
Example Efficiency:
Image A: ubuntu + python + app1
Image B: ubuntu + python + app2
They share ubuntu and python layers!
Only app1 and app2 are unique.
π Docker vs Podman
What is Podman?
Podman: "Pod Manager" - Docker alternative with key differences.
Created By: Red Hat
Philosophy: Daemonless, rootless, Kubernetes-compatible
Key Differences
| Feature | Docker | Podman |
|---|---|---|
| Daemon | Yes (dockerd) | No (daemonless) |
| Root Required | Yes (historically) | No (rootless default) |
| CLI Compatibility | Original | Drop-in replacement |
| Pods Support | No (single containers) | Yes (Kubernetes pods) |
| Image Format | OCI-compatible | OCI-compatible |
| Docker Compose | Built-in | podman-compose (separate) |
| Systemd Integration | Limited | Excellent |
| Enterprise | Docker EE (commercial) | Free/open-source |
Podman Advantages
1. Daemonless:
Docker: CLI β Daemon (runs as root) β Containers
Podman: CLI β Directly manage containers
- No single point of failure
- Better security (no root daemon)
- Each user manages their containers
2. Rootless by Default:
# Run as regular user (no sudo)
podman run nginx
# Docker requires root or docker group
sudo docker run nginx # or add user to docker group
3. Pod Support (like Kubernetes):
# Create pod with multiple containers
podman pod create --name webapp
# Add containers to pod
podman run --pod webapp nginx
podman run --pod webapp postgres
4. Systemd Integration:
# Generate systemd unit files
podman generate systemd --new --name myapp > myapp.service
# Enable container as service
systemctl --user enable myapp.service
When to Use Podman vs Docker
Use Docker When:
- Team uses Docker (consistency)
- Docker Compose heavily used
- Docker Desktop features needed (GUI, k8s)
- Mature ecosystem required
- Windows/Mac development (better support)
Use Podman When:
- Security priority (rootless)
- Red Hat/Fedora ecosystem
- Kubernetes migration planned (pods)
- No daemon preferred
- Systemd integration important
- Linux-only environment
The Good News: Commands are nearly identical!
# Docker
docker run nginx
docker build -t myapp .
docker ps
# Podman (same commands!)
podman run nginx
podman build -t myapp .
podman ps
# Even create alias
alias docker=podman
π― When to Use Containers
Perfect Use Cases
1. Microservices Architecture:
ββββββββββββ ββββββββββββ ββββββββββββ
β Frontend β β Auth API β β Orders β
βContainer β βContainer β β Containerβ
ββββββββββββ ββββββββββββ ββββββββββββ
Each service in own container, independent scaling
2. Development Environments:
# Need Postgres 15? One command:
docker run -d postgres:15
# Done testing? Delete:
docker rm -f postgres
# No system pollution!
3. CI/CD Pipelines:
Build β Test β Package β Deploy
β β β β
Container at each stage, consistent environment
4. Application Isolation:
App A needs Python 3.8
App B needs Python 3.11
No problem - different containers!
5. Easy Scaling:
# Need 5 web servers?
docker-compose up --scale web=5
When NOT to Use Containers
1. GUI Applications (traditionally):
- X11 forwarding complexity
- Better: Use VMs or native apps
2. Kernel-Level Work:
- Containers share kernel
- System programming needs VMs
3. Massive State:
- Large databases (can work, but complex)
- Consider managed services
4. Windows-Specific Apps (on Linux):
- Need Windows kernel
- Use Windows containers or VMs
π§ Mental Models
Think of Docker As...
Shipping Containers:
Physical Shipping Container:
- Standardized size
- Contains anything
- Works on any ship/truck/train
- Isolated contents
Docker Container:
- Standardized format (OCI)
- Contains any application
- Runs on any Docker host
- Isolated processes
Recipe Book:
Dockerfile = Recipe
Image = Prepared meal (frozen)
Container = Heated and served meal
Registry = Recipe collection
Housing:
Image = House blueprint
Container = Actual house built from blueprint
Registry = Blueprint library
Volume = Furniture (persistent stuff)
Network = Roads connecting houses
π The Docker Workflow
Typical Development Cycle:
1. Write Dockerfile (define environment)
β
2. Build image (docker build)
β
3. Run container locally (docker run)
β
4. Test and iterate
β
5. Push to registry (docker push)
β
6. Pull on servers (docker pull)
β
7. Run in production (docker run)
Key Insight: Same image runs everywhere!
- Developer laptop
- CI/CD pipeline
- Staging server
- Production cluster
π‘ Core Principles
1. Immutability:
- Images don't change
- New version = new image
- Rollback = run old image
2. Disposability:
- Containers are cattle, not pets
- Should start/stop quickly
- Easy to replace
3. Separation of Concerns:
- Code in image
- Config via environment variables
- Data in volumes
4. Single Process Per Container:
- One service per container
- Better isolation
- Easier scaling
5. Build Once, Run Anywhere:
- Same image for all environments
- Configuration via env vars
π What's Next?
Now that you understand container concepts:
Installation:
- docker-installation - Install Docker and Podman
Hands-On:
- docker-basics - Your first containers
Building Images:
- dockerfile-guide - Create custom images
π Resources
Official Documentation:
Learning:
- Play with Docker - Free online environment
- Docker Curriculum
Reference:
- Docker Hub - Official images
- Awesome Docker
π Change Log
2026-01-30
- Created Docker concepts article
- Explained containers vs VMs
- Covered Docker architecture
- Included Podman comparison
- Defined key concepts (images, containers, volumes, networks)
- Provided mental models and use cases
Next Article: docker-installation - Get Docker and Podman installed!