Steven's Knowledge

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

PlatformWhat to install
macOSDocker Desktop (commercial license over a certain size) or OrbStack (faster, lighter) or colima (free, CLI)
LinuxDocker Engine from the official repo
WindowsDocker 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-world

Your 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:8080

What you just did:

  1. docker run — start a container.
  2. -d — detached (background).
  3. --name web — name it (vs an auto-generated ID).
  4. -p 8080:80 — map host port 8080 to container port 80.
  5. nginx:1.27-alpine — image name + tag; pulled from Docker Hub if not local.

Stop and remove it:

docker stop web
docker rm web

Or both at once:

docker rm -f web

The 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 option

Common 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
StateMeaning
createdImage extracted, container exists, not started
runningProcess is running
pausedFrozen (SIGSTOP); rare in practice
exitedProcess finished or was killed; container still on disk
deadDaemon 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.
  • :ro to 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   # works

That'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.

On this page