Docker Logo
Adopt Runtime / Container Runtime

Docker

License: Apache-2.0

Complete Guide

Comprehensive documentation, best practices, and getting started tutorials

Docker is a platform for developing, shipping, and running applications in isolated environments called containers. It packages up an application and all its dependencies into a standardized unit for software development. Docker allows developers to build applications, package them into containers, and then deploy those containers on any platform that supports Docker. This ensures consistency across different environments, from development to testing to production. The primary value of Docker is improved portability, efficiency, and security of applications.

Key use cases for Docker include simplifying application deployment, enabling microservices architectures, improving resource utilization, and fostering collaboration across development and operations teams. It helps eliminate “works on my machine” issues and makes it easier to scale and manage applications in various environments.

Docker revolutionized software development by making containerization accessible to everyone. Whether you’re a beginner learning to deploy your first application or an experienced engineer building complex microservices, Docker is an essential tool in your toolkit.

What is Docker?

Docker is a platform that enables developers to package applications and their dependencies into lightweight, portable containers. Unlike virtual machines that require a full operating system, containers share the host OS kernel, making them incredibly efficient and fast to start.

Key Innovation: Docker standardized the container format and made it easy to build, ship, and run containers anywhere—from your laptop to production servers to the cloud.

Why Docker Matters

The “Works on My Machine” Problem

Before Docker, developers constantly faced environment inconsistencies. An application might work perfectly on a developer’s laptop but fail in production due to different library versions, missing dependencies, or configuration differences. Docker solves this by bundling everything the application needs into a single, immutable container image.

Benefits of Docker

  1. Consistency: Identical behavior across development, testing, and production
  2. Isolation: Applications run in isolated environments without conflicts
  3. Portability: Run the same container on any system that supports Docker
  4. Efficiency: Containers are lightweight and start in seconds
  5. Scalability: Easy to scale horizontally by running multiple container instances
  6. Version Control: Container images are versioned and stored in registries

Core Docker Concepts

Images

An image is a read-only template containing the application code, runtime, libraries, and dependencies. Images are built from a Dockerfile and stored in registries like Docker Hub.

# Example Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Containers

A container is a running instance of an image. You can create, start, stop, and delete containers. Each container runs in isolation with its own filesystem, networking, and process space.

Terminal window
# Run a container
docker run -d -p 8080:80 --name my-web nginx:latest
# List running containers
docker ps
# Stop a container
docker stop my-web
# Remove a container
docker rm my-web

Volumes

Volumes provide persistent storage for containers. Since containers are ephemeral, volumes ensure data survives container restarts and can be shared between containers.

Terminal window
# Create a volume
docker volume create my-data
# Use a volume
docker run -v my-data:/app/data my-image

Networks

Docker networks enable containers to communicate with each other and the outside world. By default, containers on the same network can communicate using container names as hostnames.

Terminal window
# Create a network
docker network create my-network
# Run containers on the network
docker run --network my-network --name web nginx
docker run --network my-network --name api node-app

Getting Started with Docker

Installation

Mac/Windows: Download Docker Desktop from docker.com Linux: Install using your package manager

Terminal window
# Ubuntu/Debian
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Verify installation
docker --version
docker run hello-world

Your First Container

Let’s run a simple web server:

Terminal window
# Pull and run nginx
docker run -d -p 8080:80 --name my-nginx nginx:latest
# Visit http://localhost:8080 in your browser
# You should see the nginx welcome page
# View logs
docker logs my-nginx
# Stop and remove
docker stop my-nginx
docker rm my-nginx

Building Your Own Image

Create a simple Node.js application:

server.js
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from Docker!\n');
});
server.listen(3000, () => console.log('Server running on port 3000'));
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY server.js .
EXPOSE 3000
CMD ["node", "server.js"]
Terminal window
# Build the image
docker build -t my-node-app:1.0 .
# Run it
docker run -d -p 3000:3000 --name node-app my-node-app:1.0
# Test it
curl http://localhost:3000

Docker Compose: Multi-Container Applications

Docker Compose makes it easy to define and run multi-container applications using a YAML file.

docker-compose.yml
version: '3.8'
services:
web:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
api:
build: ./api
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://db:5432/mydb
depends_on:
- db
db:
image: postgres:15
environment:
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=mydb
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
Terminal window
# Start all services
docker compose up -d
# View logs
docker compose logs -f
# Stop all services
docker compose down

Best Practices for Docker

Dockerfile Optimization

  1. Use Official Base Images: Start with trusted, maintained images
  2. Minimize Layers: Combine RUN commands to reduce image size
  3. Order Matters: Place frequently changing instructions last
  4. Use .dockerignore: Exclude unnecessary files from build context
  5. Multi-Stage Builds: Reduce final image size
# Multi-stage build example
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]

Security Best Practices

  1. Don’t Run as Root: Use a non-root user in containers
  2. Scan Images: Regularly scan for vulnerabilities
  3. Minimal Base Images: Use alpine or distroless images
  4. Pin Versions: Use specific image tags, not latest
  5. Secrets Management: Never hardcode secrets in images
# Security example
FROM node:20-alpine
RUN addgroup -g 1001 appgroup && \
adduser -D -u 1001 -G appgroup appuser
WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser
CMD ["node", "server.js"]

Image Size Optimization

# Before: Large image
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3 python3-pip
COPY requirements.txt .
RUN pip3 install -r requirements.txt
COPY . .
CMD ["python3", "app.py"]
# After: Smaller image
FROM python:3.11-alpine
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]

Common Use Cases

1. Local Development Environments

Replace complex local setups with containers:

Terminal window
# Run a MySQL database for development
docker run -d \
--name dev-mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=myapp \
-p 3306:3306 \
-v mysql-data:/var/lib/mysql \
mysql:8

2. Microservices Architecture

Each microservice runs in its own container, making it easy to develop, test, and deploy independently.

3. CI/CD Pipelines

Build and test applications in consistent Docker environments, then deploy the same images to production.

4. Legacy Application Modernization

Containerize legacy applications to make them more portable and easier to maintain.

Common Pitfalls to Avoid

  1. Using :latest tag: Always pin specific versions
  2. Large Images: Each layer adds size; optimize your Dockerfile
  3. Storing Data in Containers: Use volumes for persistent data
  4. Too Many Processes: One process per container (use Docker Compose for multiple services)
  5. Ignoring Logs: Containers should log to stdout/stderr
  6. Not Cleaning Up: Remove unused images and containers regularly
Terminal window
# Clean up unused resources
docker system prune -a
# Remove dangling images
docker image prune
# Remove unused volumes
docker volume prune

Docker vs. Alternatives

Docker vs. Virtual Machines

  • Size: Docker containers are MB vs. VM images in GB
  • Speed: Containers start in seconds, VMs in minutes
  • Isolation: VMs provide stronger isolation, containers are lighter
  • Use Case: Containers for applications, VMs for full OS isolation

Docker vs. Podman

Podman is a daemonless alternative to Docker that’s OCI-compatible:

  • Rootless: Podman runs without root privileges
  • Daemonless: No background daemon required
  • Pod Support: Native Kubernetes pod support
  • Compatibility: Mostly compatible with Docker CLI

Docker Ecosystem and Tools

Container Registries

  • Docker Hub: Public registry with millions of images
  • GitHub Container Registry: Integrated with GitHub
  • AWS ECR, GCP GCR, Azure ACR: Cloud provider registries
  • Harbor: Self-hosted registry with security scanning

Development Tools

  • Docker Desktop: GUI for managing containers (Mac/Windows)
  • Dive: Analyze and optimize image layers
  • Lazydocker: Terminal UI for Docker
  • Portainer: Web-based Docker management

Security Tools

  • Trivy: Vulnerability scanner for container images
  • Snyk: Security scanning for containers
  • Docker Scout: Built-in vulnerability analysis
  • Falco: Runtime security monitoring

Learning Path

Beginner

  1. Understand containers vs. VMs
  2. Install Docker and run your first container
  3. Learn basic Docker commands (run, ps, stop, rm)
  4. Build your first Dockerfile
  5. Use Docker Compose for multi-container apps

Intermediate

  1. Master Dockerfile best practices
  2. Implement multi-stage builds
  3. Understand Docker networking
  4. Work with volumes and data persistence
  5. Push images to registries

Advanced

  1. Optimize images for production
  2. Implement security best practices
  3. Build CI/CD pipelines with Docker
  4. Create custom networks and networking strategies
  5. Migrate to orchestration platforms (Kubernetes)

Conclusion

Docker has become the standard for containerization, enabling developers to build, ship, and run applications consistently across any environment. Whether you’re developing locally or deploying to production, Docker simplifies the entire software delivery lifecycle.

Start by containerizing a simple application, experiment with Docker Compose, and gradually adopt best practices. The Docker ecosystem is mature, well-documented, and supported by a vibrant community.

Ready to go deeper? Check out our hands-on Docker videos and tutorials below to see real-world examples and advanced patterns.