Home DevOps Docker Installation and Setup: From Zero to Production-Ready in 30 Minutes
Beginner 4 min · July 11, 2026

Docker Installation and Setup: From Zero to Production-Ready in 30 Minutes

Docker installation guide for beginners.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
Production
production tested
July 11, 2026
last updated
258
articles · all by Naren
Before you start⏱ 30 min
  • Basic command-line familiarity (cd, ls, mkdir)
  • A machine with internet access and sudo/administrator privileges
  • No prior Docker experience needed
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer

Install Docker by downloading Docker Desktop from docker.com or using your package manager on Linux. For Linux, run curl -fsSL https://get.docker.com | sh. Verify with docker --version and docker run hello-world.

✦ Definition~90s read
What is Docker Installation and Setup?

Docker is a platform that packages applications and their dependencies into lightweight, portable containers. Containers run consistently across any system with Docker installed, eliminating 'it works on my machine' problems.

Think of Docker as a shipping container for your app.
Plain-English First

Think of Docker as a shipping container for your app. Just like a shipping container holds cargo and fits on any truck, train, or ship, a Docker container holds your app and runs on any computer with Docker installed. No more 'but it worked on my laptop' excuses.

⚙ Browser compatibility
Latest versions — ✓ supported
ChromeFirefoxSafariEdge

You've been burned before. You push code to production, and it crashes because the server has a different version of Node, or Python, or some obscure C library. The classic 'works on my machine' lie. Docker ends that nonsense. It packages your app with everything it needs — down to the operating system libraries — into a single, runnable unit called a container. Once you have Docker installed, you can run that container anywhere: your laptop, your teammate's Windows machine, a cloud server, even a Raspberry Pi. No surprises. By the end of this guide, you'll have Docker installed, verified, and ready to run your first container. You'll also know how to avoid the three most common setup traps that waste hours.

What Docker Actually Solves (And Why You Should Care)

Before Docker, deploying software was a nightmare. You'd write a setup script, pray the server had the right OS version, and spend hours debugging library conflicts. Docker eliminates that by bundling your app with its entire runtime environment. A container includes the OS, libraries, environment variables, and your code. It runs identically on any machine with Docker. The core concept is an image — a read-only template with instructions for creating a container. You build an image, push it to a registry (like Docker Hub), and pull it on any machine. Containers are lightweight, start in seconds, and isolate processes. They're not virtual machines — they share the host OS kernel, so they use fewer resources. This is why Docker dominates DevOps: it makes deployment predictable and repeatable.

WhyDocker.devopsDEVOPS
1
2
3
4
5
6
7
8
// io.thecodeforge — DevOps tutorial

# Without Docker: manual setup on a fresh Ubuntu server
sudo apt-get update
sudo apt-get install -y nodejs npm
# ... but what if the server uses CentOS? Or has Node 12 instead of 16?
# With Docker: one command to run the same app anywhere
docker run -d -p 3000:3000 node:16-alpine node app.js
Output
Container starts and app is accessible at http://localhost:3000
Senior Shortcut:
Docker images are cached locally. Once you pull an image, subsequent runs use the cached version — no re-download. Use docker pull to pre-cache images before deployments.

Installing Docker on Linux (The Right Way)

Linux is Docker's native home. The Docker Engine runs directly on the Linux kernel. The recommended method is using the official convenience script from Docker. It detects your distribution, adds the correct repository, and installs the latest stable version. Do not use your distro's package manager (apt, yum) unless you want an outdated version. The script handles everything. After installation, you need to start the Docker daemon and enable it to start on boot. Finally, add your user to the 'docker' group to run Docker commands without sudo. This is a security risk in multi-user environments, but for a single developer machine, it's standard practice.

InstallDockerLinux.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// io.thecodeforge — DevOps tutorial

# Step 1: Download and run the official Docker installation script
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Step 2: Start Docker daemon and enable on boot
sudo systemctl enable docker
sudo systemctl start docker

# Step 3: Add your user to the docker group (log out and back in after)
sudo usermod -aG docker $USER

# Step 4: Verify installation
docker --version
docker run hello-world
Output
Docker version 24.0.7, build afdd53b
Hello from Docker!
This message shows that your installation appears to be working correctly.
Never Do This:
Running sudo apt-get install docker.io on Ubuntu. That package is often months out of date. Always use the official script or Docker's apt repository.

Installing Docker on macOS and Windows (Docker Desktop)

Docker Desktop is the easiest way to run Docker on macOS and Windows. It includes Docker Engine, Docker CLI, Docker Compose, and a GUI. On macOS, it uses a lightweight HyperKit VM to run Linux containers. On Windows, it can use Hyper-V or WSL 2. WSL 2 is recommended for better performance. Download the installer from docker.com, drag it to Applications, and launch. Docker Desktop will start the daemon automatically. You'll see the Docker whale icon in your menu bar or system tray. Click it to manage containers. The CLI works the same as on Linux. One gotcha: Docker Desktop on macOS has default memory limits (2GB). For serious work, increase it in Preferences -> Resources -> Advanced.

InstallDockerDesktop.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// io.thecodeforge — DevOps tutorial

# After installing Docker Desktop, open a terminal and verify:
docker --version

# Run the hello-world container to test
docker run hello-world

# Check Docker Desktop resources (macOS):
# Preferences -> Resources -> Advanced -> Memory: set to 4GB or more

# For Windows with WSL 2:
# Ensure WSL 2 is installed: wsl --set-default-version 2
# In Docker Desktop Settings -> Resources -> WSL Integration -> enable integration with your distro
Output
Docker version 24.0.7, build afdd53b
Hello from Docker!
This message shows that your installation appears to be working correctly.
Production Trap:
Docker Desktop is not licensed for large-scale commercial use in enterprises (over 250 employees or $10M revenue). You must buy a subscription. For production servers, use Docker Engine on Linux — it's free and open-source.

Verifying Your Docker Installation (Don't Skip This)

After installation, you must verify Docker works correctly. Run docker version to check client and server versions. If you get 'Cannot connect to the Docker daemon', the daemon isn't running. On Linux, start it with sudo systemctl start docker. On macOS/Windows, launch Docker Desktop. Next, run docker run hello-world. This pulls a tiny test image from Docker Hub and runs a container that prints a success message. If it works, your installation is complete. If you get permission errors, you forgot to add your user to the docker group. Run sudo usermod -aG docker $USER and log out/in. If you're on a VM or remote server, ensure your user has sudo access.

VerifyDocker.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// io.thecodeforge — DevOps tutorial

# Check Docker client and server versions
docker version

# Run the hello-world test
docker run hello-world

# List running containers (should be empty after hello-world exits)
docker ps

# List all containers (including stopped)
docker ps -a

# Check Docker system info
docker info
Output
Client: Docker Engine - Community
Version: 24.0.7
Server: Docker Engine - Community
Version: 24.0.7
Hello from Docker!
This message shows that your installation appears to be working correctly.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abc123def456 hello-world "/hello" 10 seconds ago Exited (0) 9 seconds ago clever_mclean
Interview Gold:
The docker version command shows both client and server versions. If server info is missing, the daemon isn't running. This is a common interview debugging scenario.

Running Your First Real Container (Not Hello World)

Hello World is boring. Let's run something useful: an Nginx web server. Run docker run -d -p 8080:80 nginx:alpine. The -d flag runs it in detached mode (background). -p 8080:80 maps port 8080 on your host to port 80 in the container. nginx:alpine is a lightweight Nginx image. Open http://localhost:8080 in your browser. You should see the Nginx welcome page. To stop the container, run docker stop <container-id>. To remove it, docker rm <container-id>. This is the pattern you'll use for most services: databases, APIs, frontends. Containers are ephemeral — any data written inside is lost when the container is removed. For persistent data, you need volumes (covered in a later article).

RunNginx.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// io.thecodeforge — DevOps tutorial

# Pull and run Nginx in detached mode, mapping port 8080 to 80
docker run -d -p 8080:80 --name my-nginx nginx:alpine

# Verify it's running
docker ps

# Stop the container
docker stop my-nginx

# Remove the container
docker rm my-nginx

# Run with a custom index.html (mount a volume)
echo "<h1>Hello from Docker!</h1>" > index.html
docker run -d -p 8080:80 -v $(pwd)/index.html:/usr/share/nginx/html/index.html nginx:alpine
Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 nginx:alpine "/docker-entrypoint.…" 5 seconds ago Up 4 seconds 0.0.0.0:8080->80/tcp my-nginx
Browser at http://localhost:8080 shows Nginx welcome page.
After custom index.html: shows 'Hello from Docker!'
Senior Shortcut:
Use --rm flag with docker run to automatically remove the container when it stops. Great for testing: docker run --rm -p 8080:80 nginx:alpine.

Understanding Docker Images and Layers

Docker images are built in layers. Each instruction in a Dockerfile creates a new layer. Layers are cached. If you change a layer, only that layer and subsequent ones are rebuilt. This makes builds fast. Images are read-only. When you run a container, Docker adds a thin writable layer on top. Any changes inside the container (creating files, installing packages) happen in this writable layer. When the container is deleted, the writable layer is lost. That's why you need volumes for persistent data. Images are identified by a hash (SHA256). Tags (like nginx:alpine) are human-readable aliases. Always use specific tags in production, not latest, because latest changes and can break your deployment.

ImageLayers.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// io.thecodeforge — DevOps tutorial

# Pull an image and see its layers
docker pull nginx:alpine

# Inspect image layers
docker history nginx:alpine

# Build a custom image with a Dockerfile
cat > Dockerfile << EOF
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html
EOF

docker build -t my-nginx:1.0 .

# See layers of the new image
docker history my-nginx:1.0
Output
IMAGE CREATED CREATED BY SIZE
<missing> 2 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B
...
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:... in / 7.05MB
After build:
IMAGE CREATED CREATED BY SIZE
abc123def456 1 minute ago /bin/sh -c #(nop) COPY file:... in / 45B
<missing> 2 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B
...
The Classic Bug:

Docker Compose: Multi-Container Setup Made Simple

Real applications need multiple services: a web server, a database, a cache. Docker Compose lets you define and run multi-container applications with a single YAML file. You define services, networks, and volumes. One command (docker-compose up) starts everything. This is essential for local development and CI/CD. Compose is included with Docker Desktop. On Linux, you may need to install it separately. The file is usually named docker-compose.yml. Each service specifies an image or build context, ports, environment variables, and dependencies. Compose creates a default network so containers can communicate by service name.

docker-compose.ymlDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// io.thecodeforge — DevOps tutorial

version: '3.8'
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
    depends_on:
      - api
  api:
    build: ./api
    ports:
      - "3000:3000"
    environment:
      - DB_HOST=db
      - DB_USER=app
      - DB_PASSWORD=secret
    depends_on:
      - db
  db:
    image: postgres:15-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
volumes:
  pgdata:
Output
Running `docker-compose up -d` starts all three services. `docker-compose ps` shows their status. `docker-compose logs -f` tails logs from all services.
Senior Shortcut:
Use docker-compose config to validate your YAML file and see the resolved configuration. Catches indentation errors before you run anything.

Common Installation Pitfalls and How to Fix Them

The most common error is 'Cannot connect to the Docker daemon'. On Linux, the daemon might not be running or your user isn't in the docker group. Run sudo systemctl status docker to check. If it's inactive, start it. If your user isn't in the docker group, add them and log out/in. On macOS/Windows, Docker Desktop might not be running. Launch it from Applications. Another pitfall: disk space. Docker images and containers consume disk. Run docker system df to see usage. Clean up with docker system prune -a (removes all unused images, containers, and networks). On macOS, Docker Desktop uses a disk image that can grow large. Reset it in Troubleshoot -> Reset to factory defaults. Never run docker system prune in production without understanding what it removes.

TroubleshootDocker.devopsDEVOPS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// io.thecodeforge — DevOps tutorial

# Check Docker daemon status (Linux)
sudo systemctl status docker

# Start Docker daemon
sudo systemctl start docker

# Check disk usage
docker system df

# Clean up unused resources (careful!)
docker system prune -a --volumes

# Check Docker Desktop logs (macOS)
# ~/Library/Containers/com.docker.docker/Data/log/vm/dockerd.log

# Reset Docker Desktop to factory defaults
# Docker Desktop -> Troubleshoot -> Reset to factory defaults
Output
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2024-01-15 10:30:00 UTC; 2h ago
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 5 2 1.2GB 800MB (66%)
Containers 10 3 100MB 70MB (70%)
Local Volumes 3 1 500MB 400MB (80%)
Build Cache 0 0 0B 0B
Never Do This:
Running docker system prune -a --volumes on a production server without checking what it removes. It deletes all stopped containers, unused networks, dangling images, and unused volumes. You could lose database data if volumes aren't backed up.
● Production incidentPOST-MORTEMseverity: high

The 4GB Container That Kept Dying

Symptom
A containerized Node.js app kept crashing with 'FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory' every 3 hours in production.
Assumption
Team assumed a memory leak in the app code and spent days profiling with --inspect.
Root cause
Docker Desktop on macOS defaulted to 2GB of memory for all containers. The app needed 4GB. The --memory flag was never set in the docker run command or docker-compose.yml.
Fix
Set --memory=4g in docker run or mem_limit: 4g in docker-compose.yml. Also increased swap to 2GB with --memory-swap=6g.
Key lesson
  • Always explicitly set resource limits for containers in production — default limits are for development only.
Production debug guideSystematic recovery paths for the failure modes engineers actually hit.3 entries
Symptom · 01
Cannot connect to the Docker daemon. Is the docker daemon running?
Fix
1. Check daemon status: sudo systemctl status docker (Linux) or check Docker Desktop is running (macOS/Windows). 2. If inactive, start it: sudo systemctl start docker. 3. If still failing, check logs: journalctl -u docker.service (Linux) or Docker Desktop logs.
Symptom · 02
Got permission denied while trying to connect to the Docker daemon socket
Fix
1. Verify user is in docker group: groups $USER. 2. If not, add: sudo usermod -aG docker $USER. 3. Log out and back in, or run newgrp docker to apply immediately.
Symptom · 03
docker: 'compose' is not a docker command.
Fix
1. On Linux, install Docker Compose plugin: sudo apt-get install docker-compose-plugin or download binary. 2. On macOS/Windows, ensure Docker Desktop is up to date (includes Compose). 3. Verify: docker compose version.
★ Docker Installation and Setup Triage Cheat SheetFirst-response commands for when things go wrong — copy-paste ready.
`docker: command not found`
Immediate action
Docker is not installed or not in PATH.
Commands
`which docker`
`sudo sh get-docker.sh` (after downloading script)
Fix now
Install Docker using the official convenience script: curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh get-docker.sh
`Cannot connect to the Docker daemon`+
Immediate action
Docker daemon is not running.
Commands
`sudo systemctl status docker`
`sudo systemctl start docker`
Fix now
Start Docker daemon: sudo systemctl enable --now docker
`Got permission denied while trying to connect to the Docker daemon socket`+
Immediate action
User not in docker group.
Commands
`groups $USER`
`sudo usermod -aG docker $USER`
Fix now
Add user to docker group and log out/in, or run newgrp docker
`docker: 'compose' is not a docker command.`+
Immediate action
Docker Compose plugin not installed.
Commands
`docker compose version`
`sudo apt-get install docker-compose-plugin`
Fix now
Install Docker Compose plugin: sudo apt-get update && sudo apt-get install docker-compose-plugin
FeatureDocker Desktop (macOS/Windows)Docker Engine (Linux)
InstallationDownload installer from docker.comPackage manager or convenience script
Daemon managementAutomatic via GUIsystemd or init script
Default memory limit2GB (configurable)No limit (uses host memory)
LicensingPaid for enterprise useFree and open-source
PerformanceSlight overhead due to VMNative, near-zero overhead
Best forLocal development on Mac/WindowsProduction servers, CI/CD
⚙ Quick Reference
8 commands from this guide
FileCommand / CodePurpose
WhyDocker.devopssudo apt-get updateWhat Docker Actually Solves (And Why You Should Care)
InstallDockerLinux.devopscurl -fsSL https://get.docker.com -o get-docker.shInstalling Docker on Linux (The Right Way)
InstallDockerDesktop.devopsdocker --versionInstalling Docker on macOS and Windows (Docker Desktop)
VerifyDocker.devopsdocker versionVerifying Your Docker Installation (Don't Skip This)
RunNginx.devopsdocker run -d -p 8080:80 --name my-nginx nginx:alpineRunning Your First Real Container (Not Hello World)
ImageLayers.devopsdocker pull nginx:alpineUnderstanding Docker Images and Layers
docker-compose.ymlversion: '3.8'Docker Compose
TroubleshootDocker.devopssudo systemctl status dockerCommon Installation Pitfalls and How to Fix Them

Key takeaways

1
Docker packages apps with their dependencies into portable containers that run identically anywhere.
2
Always pin image tags to specific versions in production
never use :latest.
3
Add your user to the docker group to avoid permission errors
but understand the security implications.
4
Use Docker Compose for multi-service local development; it's simpler than Kubernetes for small setups.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
How does Docker handle resource limits for containers, and what happens ...
Q02SENIOR
When would you choose Docker Compose over Kubernetes for a multi-contain...
Q03SENIOR
What happens when you run `docker system prune -a --volumes` in producti...
Q04JUNIOR
Explain the difference between a Docker image and a container.
Q05SENIOR
A developer reports that their Docker container runs fine locally but fa...
Q06SENIOR
How would you design a Docker-based CI/CD pipeline for a microservices a...
Q01 of 06SENIOR

How does Docker handle resource limits for containers, and what happens when a container exceeds its memory limit?

ANSWER
Docker uses cgroups to enforce memory limits set with --memory. When a container exceeds its limit, the kernel OOM killer terminates processes inside the container. The container may exit with code 137. To prevent this, set appropriate limits and use --memory-swap to allow swap usage. In production, monitor container memory with docker stats.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
How do I install Docker on Ubuntu?
02
What's the difference between Docker Desktop and Docker Engine?
03
How do I fix 'Cannot connect to the Docker daemon'?
04
How do I run a Docker container with a specific memory limit?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
Verified
production tested
July 11, 2026
last updated
258
articles · all by Naren
🔥

That's Docker. Mark it forged?

4 min read · try the examples if you haven't

Previous
Cannot Connect to Docker Daemon: Causes, Fixes and Prevention
19 / 32 · Docker
Next
Docker CLI Commands Reference