Getting Started
Install Docker, run your first container, and learn the CLI you'll use every day
Getting Started
This page takes you from zero to "I'm running a container." Pick the right install, learn six commands, and you're productive.
Installation
| Platform | What to install |
|---|---|
| macOS | Docker Desktop (commercial license over a certain size) or OrbStack (faster, lighter) or colima (free, CLI) |
| Linux | Docker Engine from the official repo |
| Windows | Docker Desktop with WSL2 backend |
Linux quick install:
# Ubuntu / Debian
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER # don't sudo every docker command
newgrp docker # apply group change
# Verify
docker version
docker run hello-worldYour First Container
# Pull and run nginx, expose its port 80 on host port 8080
docker run -d --name web -p 8080:80 nginx:1.27-alpine
# It's reachable now
curl http://localhost:8080What you just did:
docker run— start a container.-d— detached (background).--name web— name it (vs an auto-generated ID).-p 8080:80— map host port 8080 to container port 80.nginx:1.27-alpine— image name + tag; pulled from Docker Hub if not local.
Stop and remove it:
docker stop web
docker rm webOr both at once:
docker rm -f webThe Day-to-Day CLI
Six commands you'll run constantly:
# 1. Run a container
docker run [flags] <image> [command]
# 2. List
docker ps # running containers
docker ps -a # all containers, including stopped
docker images # local images
# 3. Logs
docker logs <name>
docker logs -f --tail 100 <name> # follow, last 100 lines
# 4. Get a shell in a running container
docker exec -it <name> /bin/sh
docker exec -it <name> /bin/bash # if bash is available
# 5. Inspect
docker inspect <name> # full JSON details
docker stats # live CPU/memory across containers
# 6. Cleanup
docker rm -f <name> # remove (-f for running)
docker rmi <image> # remove image
docker system prune # reclaim space from stopped containers, unused images/networks
docker system prune -a --volumes # nuclear optionCommon docker run Flags
docker run \
-d \ # detached (background)
--name app \ # human-readable name
--rm \ # auto-remove when it exits (good for one-shots)
-p 3000:3000 \ # publish port: host:container
-e DATABASE_URL=postgres://... \ # environment variable
--env-file .env \ # bulk env from file
-v /host/path:/container/path \ # mount a host directory
-v mydata:/app/data \ # mount a named volume
-w /app \ # working directory inside container
--restart unless-stopped \ # auto-restart policy
--network mynet \ # join a custom network
--memory 512m --cpus 1.0 \ # resource caps
myimage:tag command args...Quick Wins
A handful of one-liners that pay off immediately:
# Run a Postgres for local development
docker run -d --name pg \
-e POSTGRES_PASSWORD=dev \
-p 5432:5432 \
-v pgdata:/var/lib/postgresql/data \
postgres:16-alpine
# A throwaway shell with your code mounted
docker run --rm -it -v "$PWD":/work -w /work node:20-alpine sh
# Run a tool you don't want to install
docker run --rm -v "$PWD":/data ghcr.io/aquasecurity/trivy:latest fs /data
# Print resource usage as one snapshot
docker stats --no-stream--rm is the unsung hero — your one-off containers don't pile up.
Container Lifecycle
created ──run──► running ──stop──► exited
│ │
└──restart──────────┘
▼
paused| State | Meaning |
|---|---|
created | Image extracted, container exists, not started |
running | Process is running |
paused | Frozen (SIGSTOP); rare in practice |
exited | Process finished or was killed; container still on disk |
dead | Daemon couldn't clean up; usually a bug |
docker ps shows running; docker ps -a shows everything.
Volumes and Bind Mounts (Quick Tour)
# Named volume — Docker-managed, survives container removal
docker run -v mydata:/data alpine
# Bind mount — a host directory mounted into the container
docker run -v "$PWD/config":/etc/myapp:ro alpine- Named volume for data you want to persist (database files, app state).
- Bind mount for source code in development, or config the host owns.
:roto mount read-only — protects the host from a misbehaving container.
A deeper treatment lives in Docker Compose.
Networking (Quick Tour)
By default a container joins the bridge network and is isolated from the host except for ports you -p-publish. Two containers on the same network reach each other by container name:
docker network create mynet
docker run -d --name db --network mynet postgres:16-alpine
docker run --rm -it --network mynet alpine ping -c 1 db # worksThat's all you need to know for now; details in Compose.
What's Next
You can run prebuilt images. Next, build your own — efficient, secure, small → Dockerfile.