Command Palette

Search for a command to run...

GitHubGitHub

Docker Installation Guide

Install Docker Engine 29 on Linux, macOS and Windows using the official apt, dnf and package-manager repositories, then configure the daemon, Buildx and Compose.

Docker Engine packages the container runtime (containerd), the docker CLI, the Buildx builder and the Compose v2 plugin. This guide installs the Docker Engine 29.x release line from Docker's official repositories.

System Requirements

  • 64-bit processor (x86_64, arm64, armhf, s390x or ppc64le)
  • Minimum 4 GB RAM (8 GB or more for comfortable build performance)
  • Supported operating system (see the tabs below)
  • Internet access to download.docker.com
  • Kernel 4.9 or newer with overlayfs and br_netfilter support

Removing Conflicting Packages

Distributions ship an unofficial docker.io package that conflicts with the official packages. Remove it before you start:

# Debian / Ubuntu
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc | cut -f1)
 
# RHEL / CentOS / Fedora
sudo dnf remove docker docker-client docker-client-latest docker-common docker-latest \
  docker-latest-logrotate docker-logrotate docker-engine

apt or dnf will report that you have none of these packages installed if you are starting from a clean machine — that is expected.

Installation Instructions

Linux

Ubuntu / Debian (apt)

# Install prerequisites and create the keyring directory
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
 
# Add Docker's official signing key
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
 
# Add the repository (deb822 format)
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
 
sudo apt update
 
# Install Docker Engine, Buildx and the Compose plugin
sudo apt install -y docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin
 
# Start the daemon and enable it at boot
sudo systemctl enable --now docker
 
# Verify
sudo docker run hello-world

macOS

Docker Desktop is the recommended installation on macOS. It bundles the Docker Engine, Kubernetes (optional), Kubernetes Dashboard and the Compose plugin.

# Install with Homebrew
brew install --cask docker
 
# Or download Docker Desktop for Mac (Apple Silicon / Intel)
# https://docs.docker.com/desktop/setup/install/mac-install/
 
# Start the app, then verify
docker run hello-world

Windows

Docker Desktop for Windows uses WSL 2 as its backend by default.

# Install with the Windows Package Manager
winget install Docker.DockerDesktop
 
# Alternative: Chocolatey
choco install docker-desktop
 
# Enable WSL 2 for any other Linux tooling you run
wsl --set-default-version 2
wsl --update
 
# Verify (after starting Docker Desktop)
docker run hello-world

Convenience Script (Testing Only)

The convenience script installs the latest stable release non-interactively. It is not recommended for production, because it does not let you pin versions and may upgrade components unexpectedly.

# Preview what the script will do before running it
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh ./get-docker.sh --dry-run
 
# Install
sudo sh get-docker.sh

Post-Installation Configuration

Run Docker as a Non-Root User

The docker group grants root-equivalent privileges on the host. Add only the users that need it, and sign out and back in afterwards:

# Add your user to the docker group
sudo usermod -aG docker $USER
 
# Log out and back in (or refresh the group in the current shell)
newgrp docker
 
# Verify you no longer need sudo
docker ps

Rootless Mode

Rootless Docker runs the daemon as an unprivileged user inside a user namespace. It is the recommended setup on multi-tenant development machines.

# Install the rootless prerequisites
sudo apt install -y uidmap dbus-user-session slirp4netns fuse-overlayfs
 
# Create the rootless user (skip if it already exists)
sudo useradd -m -s /bin/bash dockeruser
sudo usermod -aG systemd-user dockeruser
 
# Install the rootless extras package
sudo apt install -y docker-ce-rootless-extras
 
# Switch to the user and start the daemon
su - dockeruser
dockerd-rootless-setuptool.sh install
systemctl --user enable --now docker

Verify the mode:

docker info | grep "rootless"
# rootless: true

Configure the Daemon

Docker reads /etc/docker/daemon.json. Restart the daemon after every change:

sudo tee /etc/docker/daemon.json <<EOF
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "live-restore": true,
  "userland-proxy": false,
  "default-runtime": "runc"
}
EOF
 
sudo systemctl restart docker
SettingWhy it matters
log-opts.max-size / max-fileWithout a limit, container logs fill up the disk
live-restoreKeeps containers running while the daemon restarts or upgrades
default-ulimitsRaise nofile for high-traffic services
no-new-privilegesBlocks privilege escalation from inside a container

Shell Completion

# Bash (current shell)
sudo curl -fsSL https://raw.githubusercontent.com/docker/cli/master/contrib/completion/bash/docker \
  -o /etc/bash_completion.d/docker
 
# Zsh
sudo curl -fsSL https://raw.githubusercontent.com/docker/cli/master/contrib/completion/zsh/_docker \
  -o /usr/share/zsh/completion/_docker
 
# Restart your shell to pick it up

Verifying the Installation

# Client and server versions
docker version
 
# Full daemon information
docker info
 
# Compose v2 (installed as a plugin, invoked as a subcommand)
docker compose version
 
# Buildx (multi-platform builds)
docker buildx version
 
# End-to-end test
docker run --rm hello-world
 
# Run a container and inspect it
docker run -d --name web -p 8080:80 nginx:alpine
docker ps
docker logs web
docker rm -f web

Expected output from docker version: both a Client and a Server section. If the Server section is missing, the daemon is not running.

Upgrading Docker Engine

# Debian / Ubuntu
sudo apt update
sudo apt install --only-upgrade docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin
 
# RHEL / CentOS / Fedora
sudo dnf upgrade --refresh docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin

Uninstalling Docker Engine

# Remove the packages
sudo apt purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin \
  docker-compose-plugin docker-ce-rootless-extras
 
# Remove the data (containers, images, volumes, networks)
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
 
# Remove the repository and key
sudo rm /etc/apt/sources.list.d/docker.sources
sudo rm /etc/apt/keyrings/docker.asc

Troubleshooting

Best Practices

  1. Pin image digests in production

    docker pull nginx@sha256:<digest>

    Tags move; digests do not.

  2. Never run containers as root inside the image

    USER 1001:1001
  3. Use multi-stage builds to keep the final image small

    FROM golang:1.25 AS build
    WORKDIR /src
    COPY . .
    RUN CGO_ENABLED=0 go build -o /out/app ./cmd/app
     
    FROM gcr.io/distroless/static-debian12
    COPY --from=build /out/app /app
    ENTRYPOINT ["/app"]
  4. Scan images before you deploy them

    docker scout cves nginx:alpine
  5. Use Buildx for multi-platform images

    docker buildx create --use --name multiarch
    docker buildx build --platform linux/amd64,linux/arm64 -t myapp:1.0 --push .
  6. Separate build and runtime concerns with docker compose profiles

    services:
      api:
        build: ./api
        profiles: ["app"]
      db:
        image: postgres:17-alpine
        profiles: ["app"]

Next Steps