Skip to main content
โšก Calmops

Docker Fundamentals: Containers, Images, and Containerization

Introduction

Docker has revolutionized software development and deployment by popularizing containerization technology. Originally released in 2013, Docker provides a platform for packaging applications with their dependencies into lightweight, portable containers that run consistently across different environments. In 2026, Docker remains the dominant container runtime, with its ecosystem spanning from local development to production orchestration with Kubernetes.

This comprehensive guide explores Docker fundamentals, covering container concepts, image management, Dockerfile best practices, networking, storage, and operational considerations. Whether you’re new to containers or seeking to deepen your understanding, this article provides the knowledge needed to effectively use Docker in modern development workflows.

Understanding Container Technology

Containers represent a paradigm shift in application deployment, offering isolation without the overhead of traditional virtual machines. Understanding the fundamental differences between containers and VMs is essential for effective Docker usage.

Containers vs Virtual Machines

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    CONTAINERS VS VIRTUAL MACHINES                     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                      โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”             โ”‚
โ”‚  โ”‚    Virtual Machine   โ”‚      โ”‚      Container       โ”‚             โ”‚
โ”‚  โ”‚                      โ”‚      โ”‚                      โ”‚             โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚      โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚             โ”‚
โ”‚  โ”‚  โ”‚   Guest OS     โ”‚  โ”‚      โ”‚  โ”‚   App + deps   โ”‚  โ”‚             โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚      โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚             โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚      โ”‚                      โ”‚             โ”‚
โ”‚  โ”‚  โ”‚   Hypervisor   โ”‚  โ”‚      โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚             โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚      โ”‚  โ”‚   Docker      โ”‚  โ”‚             โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚      โ”‚  โ”‚   Engine      โ”‚  โ”‚             โ”‚
โ”‚  โ”‚  โ”‚   Host OS     โ”‚  โ”‚      โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚             โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚      โ”‚                      โ”‚             โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚      โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚             โ”‚
โ”‚  โ”‚  โ”‚  Hypervisor    โ”‚  โ”‚      โ”‚  โ”‚   Host OS     โ”‚  โ”‚             โ”‚
โ”‚  โ”‚  โ”‚  (VMware, QEMU)โ”‚ โ”‚      โ”‚  โ”‚   Kernel      โ”‚  โ”‚             โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚      โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚             โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚      โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚             โ”‚
โ”‚  โ”‚  โ”‚  Hardware      โ”‚  โ”‚      โ”‚  โ”‚  Hardware      โ”‚  โ”‚             โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚      โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚             โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜             โ”‚
โ”‚                                                                      โ”‚
โ”‚  VM: ~GB, minutes to start        Container: ~MB, seconds to start  โ”‚
โ”‚                                                                      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Docker Architecture

Docker uses a client-server architecture where the Docker client communicates with the Docker daemon, which handles building, running, and distributing containers.

# Check Docker version
docker --version
# Docker version 26.0.0

docker version
# Client: Docker Engine
# Server: Docker Engine

# View Docker daemon info
docker info
# Server Version: 26.0.0
# Storage Driver: overlay2
# Runtime: runc

Docker Images

Docker images are read-only templates used to create containers. They contain the application code, runtime, libraries, and dependencies needed to run an application.

Working with Images

# Pull an image from Docker Hub
docker pull ubuntu:22.04
docker pull nginx:latest
docker pull python:3.12-slim

# List local images
docker images
# REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
# ubuntu       22.04     8a7d3d4e5f6g   2 days ago     77.8MB
# nginx        latest    1a2b3c4d5e6f   3 days ago     187MB

# Pull specific tag
docker pull redis:7-alpine

# Tag an image
docker tag ubuntu:22.04 myregistry.com/myubuntu:22.04

# Remove unused images
docker image prune -a

# Build image from Dockerfile
docker build -t myapp:1.0 .

# View image history
docker history nginx:latest

Image Layers

Docker images consist of multiple layers, each representing a instruction in the Dockerfile. Understanding layers helps optimize image builds:

# Inspect image layers
docker history python:3.12-slim

# Inspect image details
docker inspect nginx:latest
# Shows config, architecture, environment variables, entrypoint, cmd

Dockerfiles

The Dockerfile is a script containing instructions to build a Docker image. Writing efficient Dockerfiles is crucial for security, build speed, and image size.

Basic Dockerfile

# Example Dockerfile for a Python application
FROM python:3.12-slim

# Set working directory
WORKDIR /app

# Copy requirements first (layer caching)
COPY requirements.txt .

# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose port
EXPOSE 8000

# Define environment variable
ENV APP_ENV=production

# Set default command
CMD ["python", "main.py"]

Dockerfile Best Practices

# BAD: Multiple RUN commands create multiple layers
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/*

# GOOD: Single RUN with cleanup
RUN apt-get update && \
    apt-get install -y nginx && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# BAD: Copy everything then build
COPY . /app
RUN pip install -r /app/requirements.txt

# GOOD: Leverage layer caching
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r /app/requirements.txt
COPY . /app

# BAD: Run as root
# (implied)

# GOOD: Use non-root user
FROM node:20-alpine
RUN addgroup -g 1001 appgroup && \
    adduser -u 1001 -G appgroup -s /bin/sh -D appuser
USER appuser
WORKDIR /app
COPY --chown=appuser:appgroup . /app

# Use specific versions, not latest
FROM python:3.12.0-slim

# Use .dockerignore
# .git
# node_modules
# __pycache__
# *.log

Multi-Stage Builds

Multi-stage builds dramatically reduce final image size by using intermediate stages:

# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /src
COPY . .
RUN go build -o /app

# Final stage
FROM alpine:3.18
RUN apk --no-cache add ca-certificates
WORKDIR /app
COPY --from=builder /app .
CMD ["./app"]

Container Management

Creating, running, and managing containers is the core of Docker usage.

Running Containers

# Run a container interactively
docker run -it ubuntu:22.04 /bin/bash

# Run in detached mode
docker run -d nginx:latest

# Run with port mapping
docker run -d -p 8080:80 nginx:latest
# Host port 8080 -> Container port 80

# Run with environment variables
docker run -d -e APP_ENV=production -e DB_HOST=db mysql:8

# Run with volume mount
docker run -d -v /host/path:/container/path nginx

# Run with name
docker run -d --name my-nginx nginx

# Run with restart policy
docker run -d --restart=always nginx
# Options: no, on-failure, unless-stopped, always

# Run with resource limits
docker run -d --memory=512m --cpus=0.5 nginx

# Run with network
docker run -d --network=my-network nginx

Container Operations

# List running containers
docker ps

# List all containers
docker ps -a

# Start/Stop/Restart container
docker start my-nginx
docker stop my-nginx
docker restart my-nginx

# Remove container
docker rm my-nginx
docker rm -f my-nginx  # Force remove running container

# View container logs
docker logs my-nginx
docker logs -f my-nginx  # Follow logs
docker logs --tail 100 my-nginx

# Execute command in running container
docker exec -it my-nginx /bin/bash
docker exec my-nginx ls -la

# Inspect container
docker inspect my-nginx

# View container stats
docker stats my-nginx

# Copy files between container and host
docker cp my-nginx:/etc/nginx/nginx.conf ./nginx.conf
docker cp ./index.html my-nginx:/usr/share/nginx/html/

Docker Networking

Docker provides several networking options for container communication.

Network Types

# List networks
docker network ls
# NETWORK ID     NAME        DRIVER      SCOPE
# abc123         bridge      bridge      local
# def456         host        host        local
# ghi789         none        null        local

# Create custom bridge network
docker network create my-network

# Connect container to network
docker network connect my-network my-nginx

# Disconnect container from network
docker network disconnect my-network my-nginx

# Inspect network
docker network inspect bridge

Port Mapping and DNS

# Port mapping formats
-p 8080:80           # Host 8080 -> Container 80
-p 127.0.0.1:8080:80 # Bind to specific IP
-p 8080-8090:80-81   # Range mapping

# Container DNS
# Containers on same network can reach each other by name
# Docker provides embedded DNS at 127.0.0.11

Example: Web Application Stack

# Create network
docker network create web-network

# Run database
docker run -d \
  --name postgres \
  --network web-network \
  -e POSTGRES_PASSWORD=secret \
  postgres:15

# Run backend
docker run -d \
  --name backend \
  --network web-network \
  -e DB_HOST=postgres \
  -p 3000:3000 \
  myapp:backend

# Run frontend
docker run -d \
  --name frontend \
  --network web-network \
  -p 80:80 \
  myapp:frontend

# Containers can communicate:
# backend -> postgres:5432
# frontend -> backend:3000

Docker Volumes

Volumes persist data beyond container lifecycle and enable sharing data between containers.

Volume Types

# Named volumes
docker volume create my-data
docker run -v my-data:/app/data myapp

# Bind mounts (host directories)
docker run -v /host/path:/container/path myapp
docker run --mount type=bind,source=/host/path,target=/container/path myapp

# tmpfs mounts (in-memory)
docker run --mount type=tmpfs,destination=/app/data myapp

# List volumes
docker volume ls

# Inspect volume
docker volume inspect my-data

# Remove unused volumes
docker volume prune

Sharing Data Between Containers

# Create shared volume
docker volume create shared-data

# Container 1 writes
docker run -v shared-data:/data --name writer alpine sh -c "echo hello > /data/file.txt"

# Container 2 reads
docker run -v shared-data:/data --name reader alpine cat /data/file.txt

Docker Compose

Docker Compose simplifies multi-container applications by defining services in a YAML file.

Basic docker-compose.yml

version: '3.8'

services:
  web:
    build: .
    ports:
      - "8080:8000"
    environment:
      - DATABASE_URL=postgres://db:5432/myapp
    depends_on:
      - db
    networks:
      - frontend
      - backend

  db:
    image: postgres:15-alpine
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=secret
    networks:
      - backend

  redis:
    image: redis:7-alpine
    networks:
      - backend

networks:
  frontend:
  backend:

volumes:
  db-data:

Compose Commands

# Start all services
docker compose up -d

# View logs
docker compose logs -f

# Stop all services
docker compose down

# Rebuild and start
docker compose up -d --build

# Scale service
docker compose up -d --scale web=3

# Run one-off command
docker compose exec web python manage.py migrate

Security Best Practices

Container security requires attention at multiple levels:

# Use specific base images
FROM python:3.12.0-slim@sha256:abc123...

# Run as non-root user
RUN adduser -D -u 1000 appuser
USER appuser

# Read-only filesystem (where possible)
docker run --read-only myapp

# Drop all capabilities, add only needed
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp

# Scan images for vulnerabilities
docker scan myapp:latest
docker scout cves myapp:latest

# Use secrets for sensitive data
# docker-compose.yml
services:
  db:
    image: postgres:15
    secrets:
      - db_password

secrets:
  db_password:
    file: ./db_password.txt

Performance Optimization

# Resource limits
docker run -d \
  --memory=1g \
  --cpus=1.5 \
  --memory-swap=2g \
  --pids-limit=100 \
  nginx

# Health checks
docker run --health-cmd="curl -f http://localhost/" \
  --health-interval=30s \
  --health-timeout=10s \
  --health-retries=3 \
  nginx

# Cleanup
docker system df
docker system prune -a
docker builder prune -a

Common Docker Commands Reference

# Images
docker build -t myapp:tag .
docker pull image:tag
docker push image:tag
docker rmi image_id

# Containers
docker run -d -p 8080:80 --name myapp image
docker ps -a
docker logs -f container
docker exec -it container sh
docker stop/start/restart container
docker rm -f container

# System
docker info
docker stats
docker system df
docker network ls
docker volume ls

Conclusion

Docker has fundamentally changed how software is developed, tested, and deployed. By containerizing applications with their dependencies, Docker ensures consistency across environments while maximizing resource efficiency. The fundamentals covered in this articleโ€”images, containers, networking, volumes, and Dockerfilesโ€”provide the foundation for building and managing containerized applications.

As container technology continues to evolve, staying current with best practices in security, optimization, and orchestration remains essential. Docker’s ecosystem, including Docker Compose for local development and integration with Kubernetes for production orchestration, provides a comprehensive platform for modern application deployment.

Comments