Skip to main content

βš™οΈ Docker Installation and Configuration

You understand what containers are and how Docker's pieces fit together β€” now let's get it running on your own machine. This lesson walks through installation on all three major operating systems, then the configuration and security settings that turn a fresh install into a comfortable, safe development environment.

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Choose the right Docker edition for your operating system
  • Install Docker on Windows, macOS, and Linux and verify it works
  • Run Docker as a non-root user on Linux safely
  • Tune the daemon through daemon.json and allocate resources sensibly
  • Use Docker contexts to switch between local and remote engines
  • Apply core security best practices from day one

Estimated Time: 30–40 minutes  β€’  Difficulty: Beginner–Intermediate

Hands-on: Install Docker, run hello-world, and confirm your setup end to end.

In This Lesson

Docker Editions

Installation differs a little by platform, but the core is the same everywhere. First, pick the right edition.

EditionPlatformWhat you get
Docker DesktopWindows, macOS (and Linux)Engine + CLI + Compose + a GUI; runs a small Linux VM behind the scenes on non-Linux hosts
Docker EngineLinuxThe core runtime, CLI-first, runs natively with no VM; installed via your package manager
Cloud servicesAWS, GCP, AzureManaged container platforms (ECS/Fargate, Cloud Run, ACI) β€” no local install needed
graph TD A[Choose a Docker edition] --> B[Docker Desktop Β· Windows/Mac] A --> C[Docker Engine Β· Linux] A --> D[Managed cloud service] B --> E[Install] C --> E D --> E E --> F[Verify] F --> G[Configure] G --> H[Secure]
πŸš— Right vehicle for the trip: Docker Desktop is a comfortable family car with a dashboard; Docker Engine on Linux is a stripped-down race car β€” faster and lighter, but you drive it from the command line. Pick for your journey.

⚠️ Docker Desktop licensing

Docker Desktop is free for personal use, education, and small businesses, but larger companies need a paid subscription. Docker Engine on Linux remains free and open source. Check current terms before deploying it across a big organization.

Installing on Windows

Requirements

  • Windows 10/11 64-bit (recent build)
  • WSL 2 (Windows Subsystem for Linux) enabled β€” the recommended backend
  • Hardware virtualization enabled in BIOS/UEFI
  • At least 4 GB RAM

Steps

  1. Install WSL 2 (open PowerShell as administrator):
    wsl --install
    Reboot when prompted.
  2. Download the installer from Docker Desktop and run it, keeping the WSL 2 backend option selected.
  3. Launch Docker Desktop from the Start menu and let it initialize.
  4. Verify in PowerShell:
    docker --version
    docker run hello-world
Docker Desktop on Windows using the WSL 2 backend Nested boxes show the Windows host containing WSL 2, which provides a real Linux kernel that hosts the Docker Engine and the running containers. Windows Host WSL 2 Real Linux Kernel Docker Engine ctr 1 ctr 2 ctr 3
Figure 1 β€” On Windows, Docker Desktop runs the Engine inside WSL 2, which supplies a genuine Linux kernel for your containers.

⚠️ Common Windows snags

  • Virtualization disabled: enable it in BIOS/UEFI (often labelled VT-x, AMD-V, or SVM).
  • WSL 2 missing: run wsl --install in an elevated PowerShell.
  • Hypervisor conflicts: other virtualization tools can clash; close or disable them if Docker won't start.

Installing on macOS

Requirements

  • A recent macOS release
  • At least 4 GB RAM
  • No VirtualBox needed β€” Docker Desktop uses Apple's native Virtualization framework

Steps

  1. Download the .dmg from Docker Desktop, choosing the build for your chip (Apple Silicon or Intel).
  2. Open the .dmg and drag Docker into Applications.
  3. Launch Docker from Applications, authorizing with your password if prompted, and wait for it to start.
  4. Verify in Terminal:
    docker --version
    docker run hello-world

πŸ’‘ Apple Silicon (M-series) notes

Apple Silicon Macs run ARM64 images natively. Most popular images now publish ARM64 variants, so you rarely notice. When you must run an x86 image, Docker emulates it (slower); force the platform explicitly:

docker pull --platform linux/amd64 some-image

Installing on Linux

Docker Engine runs natively on Linux β€” no VM, minimal overhead. The recommended path is Docker's official apt/dnf repository. Here's the modern Ubuntu install using the current signed-keyring method:

# Remove any distro-packaged old versions first
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do
  sudo apt-get remove -y $pkg
done

# Add Docker's official GPG key
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
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 Docker repository
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
  https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install the Engine, CLI, containerd, and the Compose & Buildx plugins
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin

# Verify
sudo docker run hello-world

For Fedora/RHEL/CentOS the equivalent uses dnf and Docker's docker-ce.repo, then sudo systemctl enable --now docker to start the service at boot.

βœ… Run Docker without sudo

By default the Docker socket is root-owned, so commands need sudo. Add yourself to the docker group to skip it:

sudo groupadd docker            # usually already exists
sudo usermod -aG docker $USER    # add yourself
newgrp docker                    # apply now (or log out/in)

docker run hello-world           # no sudo needed

Security note: the docker group grants root-equivalent power over the host. Only add trusted users.

Verifying the Install

These commands work on every platform and confirm the client, daemon, and registry access all function:

docker --version    # client version, quick sanity check
docker info         # detailed daemon info: storage driver, resources, etc.
docker version      # full client + server (daemon) version breakdown
docker run hello-world   # end-to-end test

The hello-world container is the canonical smoke test. Running it exercises the entire architecture from the previous lesson:

  1. The client contacts the daemon.
  2. The daemon pulls the hello-world image from Docker Hub.
  3. The daemon creates and runs a container from it (via containerd β†’ runc).
  4. The container prints a message and exits.

Success looks like:

Hello from Docker!
This message shows that your installation appears to be working correctly.

Configuring the Daemon

Fresh Docker works out of the box, but a few settings make development smoother.

Docker Desktop (Windows/macOS)

Open Settings (the gear icon) to adjust Resources (CPU, memory, disk), File sharing (which host directories may be bind-mounted), Network, and the Docker Engine JSON β€” the same daemon config as on Linux, just behind a GUI.

Linux daemon.json

On Linux the daemon reads /etc/docker/daemon.json. A sensible starter config caps log size (unbounded logs are a classic disk-filler) and pins the recommended storage driver:

{
  "data-root": "/var/lib/docker",
  "storage-driver": "overlay2",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "default-address-pools": [
    { "base": "172.30.0.0/16", "size": 24 }
  ]
}
# Apply changes
sudo systemctl restart docker
OptionWhat it controls
data-rootWhere Docker stores images, containers, and volumes
storage-driverLayer storage backend (overlay2 is standard)
log-optsLog rotation size and file count
registry-mirrorsCaching mirrors to speed up pulls
default-address-poolsIP ranges for container networks (avoid clashes)

Right-sizing resources

Give Docker enough to be fast but not so much that the host chokes. Reasonable developer defaults:

  • CPU: around half your cores
  • Memory: 4–8 GB (depends on your stack)
  • Disk: 60 GB+, more for large projects

Reclaim space periodically with docker system prune, which removes stopped containers, unused networks, and dangling images.

Docker Contexts

A context stores the connection details for a Docker endpoint, letting you switch between a local daemon, a remote server over SSH, or a cloud engine without editing environment variables each time.

# List contexts (the active one is marked with *)
docker context ls

# Create a context pointing at a remote host over SSH
docker context create remote-server \
  --docker "host=ssh://user@remote-server"

# Switch to it
docker context use remote-server

# Or target it for a single command without switching
docker --context remote-server ps

# Inspect or remove a context
docker context inspect remote-server
docker context rm remote-server
🌐 Browser profiles: Contexts are like separate browser profiles β€” each remembers its own connection and settings, so you flip between "local dev" and "staging server" in one command instead of reconfiguring everything.

πŸ’‘ Compose is built in now

You no longer install Compose separately β€” modern Docker ships Compose V2 as a CLI plugin (installed above via docker-compose-plugin). Invoke it as docker compose version, with a space and no hyphen.

Security Best Practices

Docker's convenience comes with real power over the host. Build these habits in from the start.

βœ… Do

  • Run containers as a non-root user. Add USER appuser in your Dockerfile, or --user 1000:1000 at runtime.
  • Drop unneeded Linux capabilities:
    docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
  • Set resource limits so a runaway container can't hog the host:
    docker run --memory=512m --cpus=1 nginx
  • Scan images for known vulnerabilities (e.g. docker scout cve) and prefer minimal, official base images.
  • Keep Docker updated to receive security patches.

⚠️ Don't

  • Don't expose the daemon on an unencrypted TCP port β€” use TLS or SSH for remote access.
  • Don't add untrusted users to the docker group; it's equivalent to giving them root.
  • Don't run containers with --privileged unless you genuinely need it.
  • Don't disable HTTPS on registries (insecure-registries) except for a trusted local one.
πŸ”’ Layers of protection: Securing Docker is like securing a home β€” good locks (non-root users), controlled access (dropped capabilities), and utility limits (resource caps) work together. No single measure is enough alone.

Hands-on Exercise

πŸ‹οΈ Install, Verify, and Configure

Objective: Get a working Docker setup and prove it end to end.

Instructions:

  1. Install Docker using the instructions for your OS above.
  2. Run all four verification commands: docker --version, docker info, docker version, and docker run hello-world.
  3. From docker info, find and note your storage driver, logging driver, and Docker's data root path.
  4. Create a context for your local daemon, switch to it, and confirm it works:
    docker context create local-dev \
      --docker "host=unix:///var/run/docker.sock"
    docker context use local-dev
    docker ps
    (On Windows, use the named-pipe host npipe:////./pipe/docker_engine instead.)
  5. Reflect: based on the security section, name one change you'd make before running a container that exposes a network port.
πŸ’‘ Hint

If docker run hello-world fails with a permission error on Linux, you probably skipped the docker group step β€” add yourself and run newgrp docker. docker info lists the storage and logging drivers near the top of its output.

βœ… Solution

On a healthy Linux install, docker info typically reports Storage Driver: overlay2, Logging Driver: json-file, and Docker Root Dir: /var/lib/docker. The context commands should switch the active context (marked * in docker context ls) and docker ps should return without error.

A good reflection answer: run the container as a non-root user and/or add --cap-drop=ALL --cap-add=NET_BIND_SERVICE so it has only the privileges it needs to bind its port.

🎯 Quick Quiz

Question 1: On Windows, which backend does Docker Desktop use to provide a real Linux kernel for containers?

Question 2: On Linux, what is the purpose of adding your user to the docker group?

Question 3: Which single command gives the most detailed picture of your running daemon β€” storage driver, resources, and configuration?

Summary & Quiz

πŸŽ‰ Key Takeaways

  • Docker Desktop suits Windows/macOS (via WSL 2 or Apple's hypervisor); Docker Engine runs natively on Linux.
  • Verify any install with docker --version, docker info, and docker run hello-world.
  • On Linux, join the docker group to drop sudo β€” and know it's root-equivalent power.
  • Tune the daemon through daemon.json: rotate logs, set the storage driver, size resources.
  • Contexts switch between local, remote, and cloud engines; Compose V2 ships built in.
  • Bake in security: non-root users, dropped capabilities, resource limits, image scanning.

πŸ“š Further Reading

πŸš€ What's Next?

With Docker installed and configured, you're ready to build your own images. Next we write Dockerfiles for different languages β€” Node.js, Python, and PHP β€” and learn to make them small, fast, and production-ready.

πŸŽ‰ Setup complete!

Docker is running on your machine. Now let's put it to work building images.