Installing Docker and the core CLI workflow

Engine, CLI, daemon and socket, the permissions that matter, and the build-run-push loop you will repeat all day.

What you are actually installing

Docker is three things wearing one name: a client (docker), a long-running daemon (dockerd) that does the work, and a Unix socket that carries commands between them. The client only sends requests; every image, container and volume lives with the daemon.

PieceWhat it isWhere it lives
docker CLIThe client you type intoYour PATH, no privileges needed
dockerdThe daemon that builds and runs containersA systemd unit on the host
/var/run/docker.sockThe API endpointOwned by root:docker, mode 660
containerd + runcThe runtime that actually starts processesStarted by dockerd
RegistryStorage for imagesRemote: Docker Hub, GHCR; local: registry:2
Docker DesktopA VM plus GUI wrapping engine and KubernetesmacOS and Windows, optional on Linux
docker version            # client AND server - an error here means the daemon is down
docker info               # storage driver, cgroup version, runtimes, root dir
docker context ls         # which endpoint the CLI talks to
docker context use default

# talk to a remote or rootless daemon without touching the default
DOCKER_HOST=ssh://deploy@web docker ps
  • If docker ps succeeds but shows a 'Server' error, the CLI is fine and the daemon is not running — check systemctl status docker.
  • On macOS and Windows the daemon runs inside a lightweight VM, so localhost is the VM, not your machine, and bind mounts go through a file-sharing layer.
  • docker context is the supported way to point at a remote engine; editing DOCKER_HOST in a profile file is how people accidentally ship to production.

Install and grant access

# Debian / Ubuntu, from Docker's own repository
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg |
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" |
  sudo tee /etc/apt/sources.list.d/docker.list >/dev/null

sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker

# run as your own user instead of prefixing every command with sudo
sudo usermod -aG docker "$USER"     # log out and back in for it to apply

docker run --rm hello-world         # proves client, daemon and registry all work
docker compose version
⚠️
Membership of the docker group is equivalent to root: anyone in it can start a container that mounts the host filesystem. On shared or production machines that matters, so prefer rootless mode (dockerd-rootless-setuptool.sh install) or a remote context instead of adding accounts to the group.

The loop: build, run, ship

# 1. build an image from the Dockerfile in this directory
docker build -t registry.example.com/team/app:1.0.0 .

# 2. run it locally, publish a port, name it, drop it on exit
docker run --rm -d --name app -p 8080:3000 --env-file .env registry.example.com/team/app:1.0.0

# 3. look at it, then debug inside it
docker ps
docker logs -f --tail 50 app

# 4. ship it
docker login registry.example.com
docker push registry.example.com/team/app:1.0.0

# 5. reclaim space when you are done experimenting
docker system df
docker system prune -f            # -a also removes unused images
  • An image is inert and shareable; a container is one running instance of it with a thin writable layer that disappears with it.
  • A registry stores images by name and tag, which is why the tag must include the registry host when it is not Docker Hub.
  • docker run = docker create + docker start, so flags you forget at run time cannot be added later.
  • Anything you type often belongs in a Compose file rather than in a shell history entry.

FAQ

'permission denied while trying to connect to the Docker daemon socket'?
Either your user is not in the docker group yet (group changes need a fresh login session), or the daemon is not running. Check with systemctl status docker, then id to confirm the group.
Should I use Docker Desktop or the engine on Linux?
On a Linux server, install the engine from the distribution or Docker's repository and skip the GUI entirely. Desktop is convenient on macOS and Windows, where a VM is unavoidable, and on a Linux workstation only if you want its Kubernetes and GUI features.

Container lifecycle, logs and debugging Registries, tags and image distribution

Last refreshed 2026-09-18.