Docker is a tool that revolutionized the way developers build, package, and run applications. Instead of worrying whether an application will work on one computer or another, Docker ensures it runs identically everywhere - in a "container" that holds everything needed: code, libraries, dependencies, and configuration.
What is Docker?
Docker is a platform for developing, shipping, and running applications in containers. A container is a lightweight, standalone executable unit that contains everything an application needs to run. Unlike traditional virtual machines (VMs), containers don't need their own operating system - they share the kernel with the host system, making them much lighter and faster.
Virtual Machine vs. Container
This is a crucial question we need to answer to understand why Docker is so popular:
| Feature | Virtual Machine (VM) | Docker Container |
|---|---|---|
| Operating System | Own guest OS | Shares kernel with host |
| Size | Several GB | A few MB |
| Startup Time | Minutes | Seconds |
| Resource Usage | High | Low |
| Isolation | Complete (own OS) | Process isolation |
Key Docker Concepts
- Image: A template containing the application and all dependencies - immutable, read-only
- Container: A running instance of an image - the application actually executing
- Dockerfile: A text file with instructions for building an image
- Registry: An online repository for images (Docker Hub, GitHub Container Registry)
- Volume: Persistent data storage outside the container
- Network: A network connecting containers to each other
Dockerfile Example
The best way to understand Docker is through an example. Let's say we have a simple Node.js application:
# Dockerfile for Node.js application # 1. Use the official Node.js image as base FROM node:20-alpine # 2. Set working directory inside the container WORKDIR /app # 3. Copy package.json and package-lock.json COPY package*.json ./ # 4. Install dependencies RUN npm install # 5. Copy the rest of the application code COPY . . # 6. Set the default command to run CMD ["node", "server.js"]
It's also very important to have a .dockerignore file in the directory, which prevents unnecessary files from being copied into the container:
# .dockerignore node_modules npm-debug.log .git .env *.md
Basic Commands
Here's an overview of the most commonly used Docker commands:
| Command | Description | Example |
|---|---|---|
| docker build | Build an image from a Dockerfile | docker build -t my-app . |
| docker run | Run a container from an image | docker run -p 3000:3000 my-app |
| docker ps | List running containers | docker ps -a |
| docker stop | Stop a running container | docker stop <container_id> |
| docker rm | Remove a container | docker rm <container_id> |
| docker images | List local images | docker images |
| docker logs | View container logs | docker logs <container_id> |
Docker Compose
When an application grows and needs multiple services (e.g., app + database + cache), running individual containers becomes tedious. This is where Docker Compose comes in, allowing you to define all services in a single file:
# docker-compose.yml
version: "3.8"
services:
app:
build: .
ports:
- "3000:3000"
depends_on:
- database
environment:
- DB_HOST=database
- DB_PORT=5432
database:
image: postgres:16-alpine
ports:
- "5432:5432"
volumes:
- db_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=secret123
- POSTGRES_DB=myapp
volumes:
db_data:
Starting the entire environment is then simple:
# Start all services docker compose up -d # Stop and remove everything docker compose down # View logs docker compose logs -f
Pros and Cons
| Advantages | Disadvantages |
|---|---|
| "Works on my machine" - and everywhere else | Additional layer of complexity |
| Fast startup and shutdown (seconds) | Learning curve for beginners |
| Consistent environment: development = production | Data persistence requires extra planning (volumes) |
| Easy scaling and deployment | Security considerations with kernel sharing |
| Rich ecosystem of images (Docker Hub) | Limitations on Windows and macOS (requires WSL2/HyperKit) |
Why Use Docker?
If you're a developer working on different projects with different technologies - Node.js, PHP, Python, Arduino SDK - Docker enables you to keep each environment separate and clean. No more conflicts between library versions, no more "it works on my machine".
For self-hosted servers and standalone projects, Docker is especially useful - instead of installing Node.js, PHP, PostgreSQL, and Nginx directly on the system, you can run each service in its own container. This means a clean system, easy updates, and security isolation between services.
Getting started is simple - install Docker, write your first Dockerfile, and run your application. Everything else comes with practice.