In this tutorial, we will learn how to install Docker on macOS, Windows and Linux, how to verify that the installation worked, and how to test Docker by running a real container.
Before installing Docker, there is one thing to understand: the installation process is not the same on every operating system.
We usually use one of two installation approaches:
macOS / Windows
↓
Docker Desktop
↓
Docker Engine
↓
Containers
Linux Server
↓
Docker Engine
↓
containerd
↓
Containers
What is Docker Desktop?
Docker Desktop is a desktop application that makes Docker easy to use, mainly on macOS and Windows. It includes Docker Engine, the Docker CLI, Docker Compose and a graphical user interface (GUI).
What is Docker Engine?
Docker Engine is Docker’s core container management technology. It helps create, start, stop and manage containers. On Linux servers and in production environments, Docker Engine is usually installed directly.
What is Docker Compose?
Docker Compose lets us manage one or more containers through a YAML configuration file.
For example, Docker Compose can run an application’s backend, database and Redis cache together.
1. Installing Docker on macOS
The easiest way to install Docker on macOS is to use Docker Desktop.
Step 1: Check your Mac’s processor architecture
First, open Terminal and run this command:
uname -m
Possible output:
arm64 → Apple Silicon (M1, M2, M3, M4 etc.)
x86_64 → Intel Mac
Why check this?
Because Docker Desktop has separate installers for Apple Silicon and Intel Macs.
Downloading the wrong installer can cause installation or compatibility problems.
Step 2: Download Docker Desktop
Download the installer from Docker’s official website:
https://docs.docker.com/desktop/setup/install/mac-install/
Choose the installer that matches your processor.
Apple Silicon Mac → Apple Silicon Version
Intel Mac → Intel Version
Step 3: Install Docker Desktop
Open the downloaded .dmg file.
Then:
Docker.dmg
↓
Docker.app
↓
Applications Folder
↓
Open Docker Desktop
The first time Docker Desktop starts, macOS may ask for some system permissions.
Approve the permissions it needs.
Once Docker Desktop has fully started, you will see the Docker icon in the menu bar.
Step 4: Verify the Docker installation
Open Terminal and run these commands:
docker --version
docker compose version
docker run hello-world
If the installation worked, the output will include:
Hello from Docker!
What actually happened here?
When you run docker run hello-world, Docker first checks whether the hello-world image exists on the local system.
If it doesn’t, Docker downloads it from Docker Hub.
It then uses that image to create and run a container.
When the container runs successfully, we see the Hello from Docker! message.
In other words, Docker Engine is working correctly.
Step 5: Run a real Nginx container
Now let’s run an actual web server container.
docker run -d --name test-nginx -p 8080:80 nginx
Let’s go through each part of this command:
| Parameter | What it does |
|---|---|
docker run | Creates and runs a new container |
-d | Runs the container in the background |
--name test-nginx | Gives the container a name |
-p 8080:80 | Connects port 8080 on the host to port 80 in the container |
nginx | Uses the Nginx Docker image |
Now open a browser and go to:
http://localhost:8080
If everything is working, you will see the Welcome to nginx! page.
This means a real web server is running inside a Docker container.
Stop and remove the container
When you have finished testing:
docker stop test-nginx
docker rm test-nginx
The first command stops the container and the second removes it.
That verifies the Docker installation and basic container execution on macOS.
2. Installing Docker on Windows
Installing Docker on Windows is a little different.
That’s because Windows usually uses WSL 2 to run Docker’s Linux containers.
WSL stands for: Windows Subsystem for Linux.
WSL lets you run a Linux environment inside Windows.
Our installation architecture will be:
Windows 10 / Windows 11
↓
WSL 2
↓
Docker Desktop
↓
Docker Engine
↓
Linux Containers
Step 1: Check the Windows requirements
Before installing Docker Desktop, make sure that:
- You are using a supported version of Windows 10 or Windows 11.
- The system supports virtualization and it is enabled.
- WSL 2 can be installed.
- The system meets Docker Desktop’s minimum hardware requirements.
Official requirements:
https://docs.docker.com/desktop/setup/install/windows-install/
Step 2: Install WSL 2
Search for PowerShell in the Windows Start menu.
Then select Run as Administrator.
Run this command:
wsl --install
This command installs the components WSL needs, and usually installs a default Linux distribution.
If Windows asks you to restart, restart it.
Update WSL
wsl --update
Check the WSL status
wsl --status
Check the installed Linux distributions
wsl -l -v
Example output:
NAME STATE VERSION
Ubuntu Running 2
Here, VERSION 2 means Ubuntu is using WSL 2.
If a distribution uses WSL 1, convert it to WSL 2 if needed.
Example:
wsl --set-version Ubuntu 2
Step 3: Install Docker Desktop
Download the Windows installer from the official Docker website:
https://docs.docker.com/desktop/setup/install/windows-install/
When running the installer, enable the WSL 2 backend if the option is offered.
Installation workflow:
Download Docker Desktop
↓
Run Installer
↓
Enable WSL 2 Backend
↓
Complete Installation
↓
Launch Docker Desktop
After starting Docker Desktop, make sure Linux containers mode is enabled.
Step 4: Enable WSL integration
Open Docker Desktop.
Then:
Docker Desktop
↓
Settings
↓
Resources
↓
WSL Integration
↓
Enable Ubuntu / Debian
↓
Apply & Restart
Why is WSL integration important?
Say you want to run Docker commands from the Ubuntu terminal on Windows.
With WSL integration enabled, the Ubuntu terminal can use Docker Desktop’s Docker Engine directly.
This makes it easier to work across the Windows and Linux development environments.
Step 5: Verify Docker from PowerShell
Open PowerShell and run:
docker --version
docker compose version
docker run hello-world
Expected output:
Hello from Docker!
Step 6: Verify Docker from WSL Ubuntu
Now open the Ubuntu terminal.
docker --version
docker compose version
docker run hello-world
If you see Hello from Docker! here too, WSL integration is working correctly.
Important: When you use Docker Desktop, you usually don’t need to install Docker Engine separately inside WSL Ubuntu.
Step 7: Run a real Nginx container
From PowerShell or the WSL Ubuntu terminal:
docker run -d --name test-nginx -p 8080:80 nginx
Go to this address in a browser:
http://localhost:8080
If you see the Nginx welcome page, the container is running successfully.
Cleanup
docker stop test-nginx
docker rm test-nginx
You have now tested Docker Desktop, Docker Engine, WSL integration and container execution on Windows.
3. Installing Docker on Linux — Ubuntu / Debian
On Linux servers, Docker is usually installed as Docker Engine.
This is especially common on servers, virtual machines (VMs), cloud infrastructure and on-premises environments.
Here we install Docker Engine directly instead of Docker Desktop.
Step 1: Remove old or conflicting Docker packages
Before installing Docker’s official packages, you may need to remove conflicting packages.
sudo apt remove \
docker.io \
docker-doc \
docker-compose \
docker-compose-v2 \
podman-docker \
containerd \
runc
Why remove them?
Ubuntu’s or Debian’s default repositories may contain some Docker-related packages.
These can conflict with the packages installed from Docker’s official repository.
However, before running this command on an existing production server, make sure no running application depends on the old Docker or containerd installation.
Step 2: Install the required dependencies
First, update the package list:
sudo apt update
Then:
sudo apt install -y ca-certificates curl
Here:
| Package | What it does |
|---|---|
ca-certificates | Certificate validation for HTTPS connections |
curl | Downloads files from the internet |
Step 3: Add Docker’s official GPG key
To verify Docker’s package repository, add Docker’s official GPG key.
For Ubuntu:
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
For Debian:
Follow the same process, but the GPG key URL is:
https://download.docker.com/linux/debian/gpg
Why use a GPG key?
With the GPG key, the package manager can verify that the Docker packages come from a trusted source and that the repository metadata’s signature is valid.
Step 4: Add Docker’s official repository
Now tell the operating system where to find the Docker packages.
Ubuntu repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Debian repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Docker’s official repository is now configured.
Step 5: Install Docker Engine
First, update the package list:
sudo apt update
Then install Docker Engine and the related tools:
sudo apt install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
This command installs several important Docker components.
| Package | Description |
|---|---|
docker-ce | Docker Community Edition Engine |
docker-ce-cli | Docker Command Line Interface |
containerd.io | Container Runtime |
docker-buildx-plugin | Advanced Docker Image Building |
docker-compose-plugin | Multi-Container Application Management |
Step 6: Start the Docker service
Once Docker is installed, start the service.
sudo systemctl enable --now docker
Check the service status:
sudo systemctl status docker
Expected result:
Active: active (running)
What the command means:
enable configures the Docker service to start automatically when the system boots.
--now starts the service immediately.
Step 7: Verify the Docker installation
Now run:
sudo docker --version
sudo docker compose version
sudo docker run hello-world
Expected:
Hello from Docker!
This confirms that Docker can run containers successfully.
Step 8: Use Docker without sudo (optional)
On Linux, running Docker commands usually requires root privileges or permission on the Docker socket.
In a development environment, if you don’t want to type sudo every time, you can add your user to the Docker group.
sudo usermod -aG docker "$USER"
Then:
newgrp docker
Test:
docker run hello-world
Security warning:
A user in the Docker group can effectively get root-level privileges. On a production server, give this permission only to trusted administrators.
For more restricted environments, consider Rootless Docker.
Step 9: Test a real Nginx container
Now let’s run an Nginx web server:
docker run -d --name test-nginx -p 8080:80 nginx
Container status:
docker ps
Send an HTTP request:
curl http://localhost:8080
The expected result is Nginx’s HTML response.
This means the Nginx web server inside the container is working correctly.
Container cleanup
docker stop test-nginx
docker rm test-nginx
Note: On a remote Linux server, localhost means that server. To reach it from a browser on your own computer, you need to consider the server IP, the network route and the firewall configuration.
4. Installing Docker on Fedora Linux
Fedora Linux uses dnf for package management.
So Ubuntu’s apt commands won’t work here.
Step 1: Remove old Docker packages
sudo dnf remove \
docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
Step 2: Install the DNF plugins
sudo dnf -y install dnf-plugins-core
Step 3: Add the Docker repository
On newer, DNF5-based Fedora:
sudo dnf config-manager addrepo \
--from-repofile \
https://download.docker.com/linux/fedora/docker-ce.repo
On older, DNF4-based Fedora:
sudo dnf config-manager --add-repo \
https://download.docker.com/linux/fedora/docker-ce.repo
Step 4: Install Docker Engine
sudo dnf install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
Step 5: Start the Docker service
sudo systemctl enable --now docker
Step 6: Verify Docker
sudo docker run hello-world
Expected:
Hello from Docker!
The basic Docker installation on Fedora is now complete.
5. Installing Docker on RHEL / CentOS / Rocky / AlmaLinux
The installation process on RHEL-based Linux distributions is very similar to Fedora’s.
However, you need to select the correct Docker repository for your distribution.
Step 1: Install the DNF plugins
sudo dnf install -y dnf-plugins-core
Step 2: Add the Docker repository
CentOS
sudo dnf config-manager --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
RHEL
sudo dnf config-manager --add-repo \
https://download.docker.com/linux/rhel/docker-ce.repo
On a DNF5-based system, you may need the config-manager addrepo --from-repofile syntax instead.
Rocky Linux and AlmaLinux: on these distributions, check your OS version and Docker’s package support before using a compatible Docker repository.
Step 3: Install Docker Engine
sudo dnf install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
Step 4: Start the Docker service
sudo systemctl enable --now docker
Step 5: Verify the installation
sudo docker run hello-world
Expected:
Hello from Docker!
This confirms, at a basic level, that Docker Engine is configured properly.
6. Docker Post-Installation Verification
After installing Docker, you should run a few standard verification commands.
They help make sure the Docker CLI, Docker Engine and Docker Compose are working correctly.
docker --version
docker compose version
docker info
docker run --rm hello-world
What does each command verify?
| Command | Verification |
|---|---|
docker --version | Whether the Docker CLI is installed |
docker compose version | Whether Docker Compose is available |
docker info | Whether the CLI can connect to Docker Engine |
docker run --rm hello-world | Whether containers can run |
One important point:
A successful docker --version alone doesn’t mean Docker Engine is running.
The Docker CLI can be installed while the Docker daemon is stopped.
That’s why verifying with docker info and docker run hello-world matters.
Real web container verification
Run an Nginx container:
docker run -d --name web-test -p 8080:80 nginx
List the running containers:
docker ps
Open in a browser:
http://localhost:8080
If you see the Nginx welcome page, container networking and the HTTP service are working at a basic level.
When you’re done:
docker stop web-test
docker rm web-test
7. Testing a Real Application with Docker Compose
So far, we have used docker run to start one container at a time.
But real-world applications are usually made up of several containers.
For example:
Web Application
|
+── Frontend Container
|
+── Backend API Container
|
+── PostgreSQL Container
|
+── Redis Container
Docker Compose is used to manage this kind of multi-container architecture.
Here we’ll test Compose with a simple Nginx service.
Step 1: Create a project directory
In the terminal:
mkdir docker-test
cd docker-test
Step 2: Create the Compose configuration file
Create a file called compose.yaml in the project directory.
The file’s content:
services:
web:
image: nginx:latest
ports:
- "8080:80"
What have we defined in this YAML file?
services: where the application’s services are defined.
web: the name of our service.
image: the Nginx image will be used to create the container.
ports: port 8080 on the host machine connects to port 80 in the container.
Step 3: Start the container with Docker Compose
docker compose up -d
When you run this command, Docker Compose will:
- Read the configuration file.
- Check whether the required Docker image exists locally.
- Download the image if it doesn’t.
- Create the network and the container.
- Start the container in the background.
Step 4: Check the running services
docker compose ps
Now send an HTTP request:
curl http://localhost:8080
In Windows PowerShell, you can use:
curl.exe http://localhost:8080
You can also verify it from a browser:
http://localhost:8080
Step 5: Stop the Docker Compose services
docker compose down
This command removes the Compose project’s containers and its default network.
What did we learn?
With Docker Compose, we can start, manage and stop containers through a YAML configuration.
Later, the same approach can deploy a backend, PostgreSQL, Redis, Apache Kafka or AI/ML services.
8. Docker, containerd, ctr, nerdctl and crictl — What’s the Difference?
A common confusion comes up while learning Docker.
What is the relationship between Docker Engine, containerd, runc, ctr, nerdctl, crictl and kubectl?
To understand it simply, look at this architecture:
Docker CLI
|
v
Docker Engine (dockerd)
|
v
containerd
|
v
runc
|
v
Linux Containers
Now let’s go through them one by one.
Docker CLI
The Docker CLI is Docker’s command-line interface.
For example:
docker ps
docker images
docker run nginx
We use these commands to communicate with Docker Engine.
containerd
containerd is a container runtime that provides the functionality for managing the container lifecycle.
Docker Engine uses containerd internally.
But containerd can also be used directly, without the Docker CLI.
ctr — containerd’s native CLI
ctr is containerd’s low-level command-line client.
Example:
sudo ctr containers list
This shows the containers in containerd’s default namespace.
To inspect Kubernetes’s containerd namespace:
sudo ctr -n k8s.io containers list
ctr is usually used for debugging and for understanding containerd’s internals.
nerdctl — a Docker-like CLI for containerd
nerdctl is a Docker-compatible CLI.
It works directly with containerd.
If you are familiar with Docker commands, nerdctl is relatively easy to use.
Example:
nerdctl ps
nerdctl images
nerdctl run nginx
However, you may need to install and configure nerdctl separately before using it.
crictl — Kubernetes runtime troubleshooting
crictl is the debugging tool for the Container Runtime Interface (CRI).
It is used to troubleshoot the container runtime on a Kubernetes node.
Example:
sudo crictl ps
sudo crictl images
sudo crictl pods
It is especially useful when troubleshooting a containerd-backed Kubernetes node.
kubectl — the Kubernetes management CLI
kubectl manages cluster resources through the Kubernetes API Server.
Example:
kubectl get pods -A
kubectl get nodes
kubectl get deployments -A
Which tool should I use when?
| Tool | Primary Use Case |
|---|---|
docker | Managing Docker containers and images |
ctr | Low-level containerd debugging |
nerdctl | Docker-like workflow directly on containerd |
crictl | Kubernetes container runtime troubleshooting |
kubectl | Managing Kubernetes clusters and workloads |
Remember: installing Docker doesn’t automatically install all of these CLIs. Each tool has its own use case and installation requirements.
9. Final Docker Validation — Complete Test
Now let’s run a complete validation.
You can use it on macOS, Windows and Linux, as long as Docker Engine is running and the necessary permissions are configured.
# Step 1: Check the Docker client and server
docker version
# Step 2: Check Docker Compose
docker compose version
# Step 3: Run the hello-world container
docker run --rm hello-world
# Step 4: Test an Alpine Linux container
docker run --rm alpine uname -a
# Step 5: Start an Nginx web server
docker run -d --name nginx-test -p 8080:80 nginx
# Step 6: Test the web server over HTTP
curl http://localhost:8080
# Step 7: Check the container logs
docker logs nginx-test
# Step 8: Check the running containers
docker ps
# Step 9: Stop the container
docker stop nginx-test
# Step 10: Remove the container
docker rm nginx-test
Expected success results
| Test | Expected Output |
|---|---|
| Docker Version | Client and Server details |
| Compose Version | Docker Compose v2 |
| Hello World | Hello from Docker! |
| Alpine Container | Linux Kernel information |
| Nginx Container | Container successfully started |
| HTTP Request | Nginx HTML response |
| Container Logs | Logs accessible |
| Docker PS | The running container is listed |
| Cleanup | Container successfully removed |
If all the tests pass, Docker’s installation, Engine connectivity, container execution, basic networking and Compose functionality are working.
But remember: installation validation and production readiness are not the same thing.
A production environment needs more configuration:
- Container Security and Image Scanning
- Resource Limits (CPU and Memory)
- Persistent Volumes and Storage
- Logging and Monitoring
- Network Security and Firewall
- Secrets Management
- Backup and Recovery
- Container Health Checks
- Image Version Pinning
10. Complete Docker Installation Summary
Now let’s look at the whole installation process once more, briefly.
Operating System
|
+------------+------------+
| |
macOS / Windows Linux Server
| |
Docker Desktop Docker Engine
| |
+------------+------------+
|
Docker CLI
|
Docker Engine
|
containerd
|
runc
|
Containers
|
+--------+--------+
| | |
Nginx Backend Database
If you use macOS
Download and install Docker Desktop. Then verify it by running docker run hello-world and an Nginx container.
If you use Windows
Set up WSL 2, install Docker Desktop and enable WSL integration. Then you can test Docker commands from PowerShell and the Ubuntu terminal.
If you use a Linux server
Configure Docker’s official repository, install Docker Engine and enable the Docker service. Then verify the installation by running a container.
If you want to run multiple containers
Use Docker Compose. It lets you manage an application’s different services together through one YAML file.
If you want to use containerd directly
Use ctr for low-level operations and nerdctl for a Docker-like workflow.
If you work in a Kubernetes environment
Use crictl to troubleshoot the container runtime and kubectl to manage Kubernetes objects.
Official Documentation & References
For more detail, use the official Docker and containerd documentation.
| Topic | Documentation |
|---|---|
| Docker Engine | https://docs.docker.com/engine/install/ |
| Docker Desktop — macOS | https://docs.docker.com/desktop/setup/install/mac-install/ |
| Docker Desktop — Windows | https://docs.docker.com/desktop/setup/install/windows-install/ |
| Docker WSL 2 Integration | https://docs.docker.com/desktop/features/wsl/ |
| Docker Engine — Ubuntu | https://docs.docker.com/engine/install/ubuntu/ |
| Docker Engine — Debian | https://docs.docker.com/engine/install/debian/ |
| Docker Engine — Fedora | https://docs.docker.com/engine/install/fedora/ |
| Docker Engine — RHEL | https://docs.docker.com/engine/install/rhel/ |
| Docker Engine — CentOS | https://docs.docker.com/engine/install/centos/ |
| Docker Compose | https://docs.docker.com/compose/ |
| containerd | https://containerd.io/docs/ |
| nerdctl | https://github.com/containerd/nerdctl |
Final Takeaway
The point of learning Docker installation isn’t just installing software; it’s understanding Docker’s complete workflow.
As a developer, or a DevOps or AI engineer, you should know:
How Docker is installed → how Docker Engine works → how a container is created from a Docker image → how port mapping works → how to run multiple services with Docker Compose → how container runtimes relate to Kubernetes.
Once you have completed this installation and verification process, you are ready to use Docker to containerize web applications, backend APIs, databases, data engineering services and AI/ML applications.
The next steps are learning Dockerfiles, Docker images, volumes, networks, Docker Compose and container security in detail.
