How to Install Docker on Linux, Mac, and Windows | Step-by-Step Guide
This chapter provides a comprehensive, step-by-step guide to installing Docker across different operating systems. You will learn how to provision a remote Linux sandbox using an AWS EC2 Ubuntu instance, configure native Docker Engine with production-grade non-root permissions, and set up Docker Desktop on macOS and Windows environments.
1. Why Host Environment Selection Matters
When learning and working with Docker, choosing the right host environment is critical for both development workflow efficiency and production alignment.
- Linux (Native Engine): Docker runs natively on the Linux kernel using namespaces and cgroups. This is the exact environment used in production. Practicing on a remote Linux cloud instance (such as AWS EC2) ensures your skills translate directly to real-world deployments.
- macOS & Windows (Docker Desktop): Because these operating systems do not natively support Linux containers, Docker Desktop runs a lightweight Linux virtual machine (VM) behind the scenes to host the Docker daemon.
Using a cloud-based virtual machine (like AWS EC2) for Linux hands-on practice allows you to easily spin up, pause, and destroy your environment without cluttering your local operating system.
2. Provisioning an AWS EC2 Ubuntu Instance
To practice native Linux installation, we will provision an Ubuntu-based virtual machine on AWS.
Step-by-Step EC2 Provisioning Workflow
- Navigate to AWS EC2: Open the AWS Management Console, search for EC2, and click Launch Instance.
- Name the Instance: Set the name to
Docker pack(or any preferred identifier). - Select the Base OS (AMI): Choose Ubuntu (select the latest stable LTS version).
- Select Instance Type: Choose
t3.micro(ort2.microdepending on your region's free-tier eligibility). - Configure Key Pair: Select an existing
.pemkey pair or click Create new key pair to download one. This key is required for SSH access. - Network Settings: Keep the default security group settings. We can modify port access rules on the fly later if we need to expose containerized web applications.
- Launch: Click Launch Instance.
Connecting via SSH
Once the instance state changes to Running, copy its public IP address and connect using your local terminal:
ssh -i "/path/to/your-key.pem" ubuntu@<your-instance-public-ip>
3. Step-by-Step Evolution: Installing Docker on Ubuntu (Linux)
To ensure we install the latest, official, and secure version of Docker, we avoid outdated package manager defaults and pull directly from Docker's official repository.
Step 3.1: Remove Conflicting Packages
Before installing the official Docker packages, clean your system of any pre-installed, unofficial, or conflicting container runtimes:
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
sudo apt-get remove -y $pkg
done
Step 3.2: Set Up Docker's Apt Repository
To pull packages directly from Docker, we must add Docker's official GPG key and register their repository in our system's package manager (apt).
# Update the local package index and install prerequisite utilities
sudo apt-get update
sudo apt-get install -y ca-certificates curl
# Create a secure directory for repository keys
sudo install -m 0755 -d /etc/apt/keyrings
# Download Docker's official GPG 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 to Apt sources
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
# Update the package index to include Docker's repository
sudo apt-get update
Step 3.3: Install Docker Engine and Plugins
Now, install the core Docker engine along with essential command-line interfaces (CLIs) and plugins:
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Note: This single command installs:
docker-ce: The Docker Community Edition Engine (daemon).docker-ce-cli: The command-line tool we use to talk to the daemon.containerd.io: The underlying industry-standard container runtime.docker-buildx-plugin: Next-generation container build capabilities.docker-compose-plugin: Multi-container orchestration tool.
Step 3.4: Enable and Start the Docker Service
Ensure the Docker daemon is configured to start automatically on system boot and is currently running:
sudo systemctl enable docker
sudo systemctl start docker
4. Resolving the Permission Denied Pitfall (Non-Root User Configuration)
The Problem
By default, the Docker daemon binds to a Unix socket (/var/run/docker.sock). This socket is owned by the root user. If a standard non-root user (like ubuntu) attempts to run a Docker command:
docker run hello-world
The system returns a Permission Denied error:
docker: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
The Naive vs. Production-Grade Approach
- The Naive Approach: Prefixing every command with
sudo(e.g.,sudo docker run hello-world). This is a bad security practice in production environments because it grants administrative privileges to container execution contexts unnecessarily. - The Production-Grade Approach: Create a dedicated
dockergroup and add your non-root user to it. The Docker daemon configures the Unix socket to be readable/writable by members of this group.
Step-by-Step Group Configuration
Execute the following command to append the current user (ubuntu) to the docker group:
sudo usermod -aG docker $USER
Why a Reboot is Required
Even after running usermod, executing a Docker command immediately will still fail.
Conceptually: Linux evaluates group memberships only when a user session is initialized. For these group changes to take effect, the current user session must be completely terminated and restarted, or the operating system must be rebooted.
To reboot your EC2 instance safely:
sudo reboot
After waiting a minute for the instance to restart, reconnect via SSH:
ssh -i "/path/to/your-key.pem" ubuntu@<your-instance-public-ip>
Now, you can run Docker commands without prefixing them with sudo.
5. Understanding the docker run hello-world Execution Flow
When you execute your first container, Docker performs a series of coordinated steps across your local client, daemon, and the remote registry.
docker run hello-world
Under-the-Hood Execution Flow
6. Installing Docker Desktop on macOS and Windows
For local development on non-Linux machines, Docker Desktop provides a user-friendly graphical interface (GUI) bundled with the Docker CLI, Docker Compose, and a lightweight virtualized Linux environment.
macOS Installation
- Download: Visit the official Docker documentation and download the installer.
- Select Apple Silicon if your Mac uses an M1, M2, or M3 chip.
- Select Intel Chip if your Mac uses an older Intel processor.
- Install: Double-click the downloaded
.dmgfile and drag the Docker icon into your Applications folder. - Launch: Open Docker from your Applications folder. Accept the service agreement and grant the necessary system permissions.
Windows Installation
- Download: Visit the official Docker documentation and download the Windows
.exeinstaller. - Install: Run the installer. Ensure that the option to Use WSL 2 instead of Hyper-V is checked (this is highly recommended for optimal performance and compatibility).
- Launch: Once installation is complete, restart your computer if prompted. Launch Docker Desktop from your Start menu and accept the terms.
Local Verification
Once Docker Desktop is running (indicated by a green status icon in the application dashboard), open your local Terminal (macOS) or PowerShell/Command Prompt (Windows) and run:
docker run hello-world
7. Comparing Docker Environments
8. Real-World Debugging & Best Practices
1. Cost Management on AWS
When practicing with cloud instances like AWS EC2, always stop or terminate your instances when you are done. Leaving an instance running continuously can lead to unexpected cloud billing.
- To Pause: Go to EC2 Console -> Instance State -> Stop Instance. You can restart it later and resume your work.
- To Delete: If you are completely finished with the course section, select Terminate Instance to delete it permanently.
2. Verifying the Daemon Status
If your Docker commands fail with connection errors on Linux, verify that the system service is active:
sudo systemctl status docker
If it is inactive, start it manually:
sudo systemctl start docker
3. Docker Desktop Startup Latency
On macOS and Windows, Docker commands will fail if the Docker Desktop application is closed or still booting up. Always ensure the Docker Desktop GUI shows a green "Engine Running" status before executing commands in your terminal.
Summary and Key Takeaways
- Native vs. Virtualized: Docker runs natively on Linux kernels but requires a lightweight virtual machine wrapper (Docker Desktop) on macOS and Windows.
- Official Repositories: Always install Docker on Linux using official Docker GPG keys and repositories rather than generic OS package managers to ensure you receive the latest security patches and features.
- The Non-Root Best Practice: Running Docker commands with
sudois a security risk. Adding your user to thedockergroup (sudo usermod -aG docker $USER) is the standard production-grade configuration. - Session Initialization: After modifying user groups in Linux, a system reboot or session restart is mandatory for the changes to apply.
- The Pull-on-Demand Model: The
docker runcommand automatically checks your local cache for an image; if it is missing, it pulls it from Docker Hub before running the container. - Resource Discipline: Stop your cloud-based EC2 instances when they are not in use to avoid unnecessary cloud charges.