Docker Fundamentals
Master the core concepts of Docker containerization and understand how containers revolutionized software deployment.
What is Docker?
Docker is a platform for developing, shipping, and running applications in containers . Containers package your application with all its dependencies, ensuring it runs consistently across different environments.
Lightweight Containers share the host OS kernel, using MBs instead of GBs
Portable Run anywhere - laptop, server, cloud
Fast Start in seconds, not minutes
Isolated Each container runs independently
Images vs Containers
Understanding the difference is crucial:
Docker Images
Blueprint for containers (like a class in OOP)
Read-only template
Contains application code, runtime, libraries, dependencies
Stored in registries (Docker Hub, private registries)
Built from Dockerfile
Docker Containers
Running instance of an image (like an object in OOP)
Writable layer on top of image
Isolated process with own filesystem, network, process tree
Can be started, stopped, deleted
Multiple containers from same image
# Analogy
Image = Recipe
Container = Cake baked from recipe
# You can bake many cakes (containers) from one recipe (image)
Docker Architecture
Docker uses a client-server architecture:
┌─────────────┐ ┌──────────────────┐ ┌─────────────┐
│ Docker │ REST │ Docker Daemon │ │ Docker │
│ Client │────────▶│ (dockerd) │◀────────│ Registry │
│ (CLI) │ API │ │ Pull/ │ (Docker Hub)│
└─────────────┘ └──────────────────┘ Push └─────────────┘
│
│ Manages
▼
┌──────────────┐
│ Containers │
│ Images │
│ Networks │
│ Volumes │
└──────────────┘
Components
Docker Client (docker) :
Command-line interface
Sends commands to Docker daemon
Can communicate with remote daemons
Docker Daemon (dockerd) :
Background service
Builds, runs, manages containers
Listens for Docker API requests
Docker Registry :
Stores Docker images
Docker Hub (public)
Private registries (AWS ECR, Google GCR, Azure ACR)
Installing Docker
Windows
macOS
Linux (Ubuntu)
# Download Docker Desktop from docker.com
# Or use winget
winget install Docker.DockerDesktop
# Verify installation
docker --version
docker run hello-world
# Download Docker Desktop from docker.com
# Or use Homebrew
brew install --cask docker
# Verify
docker --version
docker run hello-world
# Update package index
sudo apt update
# Install dependencies
sudo apt install apt-transport-https ca-certificates curl software-properties-common
# Add Docker GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Add Docker repository
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $( lsb_release -cs ) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io
# Add user to docker group (avoid sudo)
sudo usermod -aG docker $USER
# Verify
docker --version
docker run hello-world
Essential Docker Commands
Working with Images
# Search for images
docker search nginx
# Pull image from Docker Hub
docker pull nginx
docker pull nginx:1.21 # Specific version
# List local images
docker images
docker image ls
# Inspect image
docker inspect nginx
# Remove image
docker rmi nginx
docker image rm nginx
# Remove unused images
docker image prune
docker image prune -a # Remove all unused
Working with Containers
# Run container
docker run nginx
docker run -d nginx # Detached mode (background)
docker run -d --name my-nginx nginx # With name
docker run -d -p 8080:80 nginx # Port mapping (host:container)
# List containers
docker ps # Running only
docker ps -a # All (including stopped)
# Stop container
docker stop my-nginx
docker stop $( docker ps -q ) # Stop all running
# Start stopped container
docker start my-nginx
# Restart container
docker restart my-nginx
# Remove container
docker rm my-nginx
docker rm -f my-nginx # Force remove (even if running)
# Remove all stopped containers
docker container prune
Container Interaction
# View logs
docker logs my-nginx
docker logs -f my-nginx # Follow (live)
docker logs --tail 100 my-nginx # Last 100 lines
# Execute command in running container
docker exec my-nginx ls /usr/share/nginx/html
docker exec -it my-nginx bash # Interactive shell
# Copy files
docker cp my-nginx:/etc/nginx/nginx.conf ./nginx.conf
docker cp ./index.html my-nginx:/usr/share/nginx/html/
# View container stats
docker stats
docker stats my-nginx
# Inspect container
docker inspect my-nginx
Practical Examples
Example 1: Running Nginx Web Server
# Pull and run nginx
docker run -d \
--name web-server \
-p 8080:80 \
nginx:alpine
# Verify it's running
curl http://localhost:8080
# View logs
docker logs web-server
# Stop and remove
docker stop web-server
docker rm web-server
Example 2: Running a Database
# Run PostgreSQL
docker run -d \
--name postgres-db \
-e POSTGRES_PASSWORD=mysecret \
-e POSTGRES_DB=myapp \
-p 5432:5432 \
postgres:14
# Connect to database
docker exec -it postgres-db psql -U postgres -d myapp
# Stop and remove (data is lost!)
docker stop postgres-db
docker rm postgres-db
Example 3: Interactive Container
# Run Ubuntu container interactively
docker run -it ubuntu:22.04 bash
# Inside container:
apt update
apt install curl
curl https://example.com
exit
# Container stops when you exit
Container Lifecycle
┌─────────┐
│ Created │ docker create
└────┬────┘
│
▼
┌─────────┐
│ Running │ docker start / docker run
└────┬────┘
│
├──▶ Paused (docker pause)
│ │
│ └──▶ Running (docker unpause)
│
▼
┌─────────┐
│ Stopped │ docker stop
└────┬────┘
│
▼
┌─────────┐
│ Removed │ docker rm
└─────────┘
Common Flags and Options
# -d, --detach Run in background
# -p, --publish Port mapping (host:container)
# --name Assign name to container
# -e, --env Set environment variables
# -v, --volume Mount volume
# --rm Remove container when stopped
# -it Interactive terminal
# --network Connect to network
# --restart Restart policy
# Example with multiple flags
docker run -d \
--name my-app \
-p 3000:3000 \
-e NODE_ENV=production \
-v $( pwd ) :/app \
--restart unless-stopped \
node:18
Environment Variables
# Set single variable
docker run -e DATABASE_URL=postgres://localhost:5432/db myapp
# Set multiple variables
docker run \
-e NODE_ENV=production \
-e PORT= 3000 \
-e DATABASE_URL=postgres://db:5432/mydb \
myapp
# From file
docker run --env-file .env myapp
Docker System Commands
# View Docker disk usage
docker system df
# Clean up everything
docker system prune # Remove stopped containers, unused networks, dangling images
docker system prune -a # Also remove unused images
docker system prune -a --volumes # Also remove unused volumes
# View Docker info
docker info
# View Docker version
docker version
Best Practices
# Bad
docker run -d nginx
# Good
docker run -d --name web-server nginx
Makes management easier.
# Remove stopped containers
docker container prune
# Remove unused images
docker image prune
# Remove everything unused
docker system prune -a
Use --rm for Temporary Containers
# Container auto-removes when stopped
docker run --rm -it ubuntu bash
Troubleshooting
Container Won’t Start
# Check logs
docker logs container-name
# Inspect container
docker inspect container-name
# Check if port is already in use
netstat -an | grep 8080 # Linux/Mac
netstat -an | findstr 8080 # Windows
Permission Denied
# Linux: Add user to docker group
sudo usermod -aG docker $USER
# Log out and back in
# Or run with sudo
sudo docker ps
Container Keeps Restarting
# Check logs
docker logs container-name
# Run without restart policy
docker run -d --name test nginx
# Debug the issue
Key Takeaways
Docker containers are lightweight, portable, and fast
Images are blueprints, containers are running instances
Use docker run to create and start containers
Use docker ps to list containers
Use docker logs to debug
Clean up regularly with docker system prune
Container Internals (Critical for Interviews!)
Understanding what makes containers work under the hood is essential for senior roles.
Linux Namespaces
Namespaces provide isolation . Each container gets its own view of:
Namespace Isolates PID Process IDs (container sees itself as PID 1) NET Network stack (own IP, ports, routing) MNT Filesystem mounts UTS Hostname and domain name IPC Inter-process communication USER User and group IDs
Control Groups (cgroups)
Cgroups provide resource limiting :
# Limit memory to 512MB
docker run -m 512m nginx
# Limit CPU to 0.5 cores
docker run --cpus 0.5 nginx
# cgroups enforce these limits at kernel level
Union Filesystem (OverlayFS)
Docker images use layered filesystems :
┌─────────────────────────┐
│ Container Layer (RW) │ ← Writable layer
├─────────────────────────┤
│ Application Layer │ ← COPY . .
├─────────────────────────┤
│ Dependencies Layer │ ← npm install
├─────────────────────────┤
│ Base Image Layer │ ← FROM node:18
└─────────────────────────┘
Interview Insight : Containers are NOT lightweight VMs. They’re isolated processes sharing the host kernel, using namespaces for isolation and cgroups for resource limits.
OCI (Open Container Initiative)
The industry standard for container formats and runtimes.
OCI Standards
Standard Description Image Spec How container images are built and distributed Runtime Spec How containers are executed Distribution Spec How images are pushed/pulled from registries
Container Runtimes
Runtime Description Use Case containerd Industry standard, used by Docker/K8s Production CRI-O Lightweight, Kubernetes-native Kubernetes runc Low-level runtime (OCI reference) Building runtimes gVisor Sandboxed (user-space kernel) Security-critical Kata Containers VM-based isolation Multi-tenancy
Docker Security Best Practices
1. Run as Non-Root
# Create non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
2. Read-Only Filesystem
docker run --read-only nginx
3. Drop Capabilities
# Run with minimal capabilities
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
4. Security Scanning
# Scan image for vulnerabilities
docker scout cves nginx:latest
# Using Trivy
trivy image nginx:latest
Interview Questions & Answers
What is the difference between a container and a VM?
Aspect Container Virtual Machine Isolation Process-level (namespaces) Hardware-level (hypervisor) Kernel Shares host kernel Has own kernel Size MBs GBs Startup Seconds Minutes Resource Usage Low overhead High overhead Security Weaker isolation Stronger isolation
What are namespaces and cgroups?
Namespaces : Provide isolation (what a container can see)
PID namespace: Own process tree
NET namespace: Own network stack
MNT namespace: Own filesystem view
cgroups : Provide resource limits (what a container can use)
CPU limits
Memory limits
I/O bandwidth
What happens when you run 'docker run nginx'?
Docker CLI sends request to Docker daemon
Daemon checks if image exists locally
If not, pulls from registry (Docker Hub)
Creates a new container from image layers
Allocates a read-write layer on top
Creates network interface and assigns IP
Starts the container process with namespaces and cgroups
Executes the CMD/ENTRYPOINT
What is the difference between CMD and ENTRYPOINT?
Instruction Behavior Overridable CMD Default command/arguments Yes, with docker run args ENTRYPOINT Main executable Only with —entrypoint
Best Practice : Use ENTRYPOINT for the executable, CMD for default arguments:ENTRYPOINT [ "python" , "app.py" ]
CMD [ "--port" , "8080" ]
How do you debug a container that keeps crashing?
Check logs : docker logs container_name
Inspect : docker inspect container_name
Run interactively : docker run -it image sh
Override entrypoint : docker run --entrypoint sh image
Check events : docker events
Resource issues : docker stats
BuildKit is the modern builder for Docker images:
Parallel builds : Build independent stages concurrently
Better caching : Cache mounts for package managers
Secret mounting : Don’t bake secrets into layers
SSH forwarding : Clone private repos during build
Enable: DOCKER_BUILDKIT=1 docker build .
Common Pitfalls
1. Using latest Tag : Unpredictable. Always use specific version tags.2. Running as Root : Security risk. Create and use a non-root user.3. Large Images : Slow pulls and more attack surface. Use Alpine or distroless.4. Not Cleaning Up : Disk fills up fast. Run docker system prune regularly.5. Storing Data in Containers : Data is lost when container dies. Use volumes!6. Ignoring Resource Limits : Containers can consume all host resources without limits.
Next: Building Docker Images →