Step-by-Step: Installing Docker on Major Linux Distributions
Consistent, fast deployment is a must in any CI/CD pipeline. That's where Docker thrives, but its installation isn’t always trivial. Subtle differences in package management and systemd integration across Linux distributions can result in an unexpectedly non-uniform setup process—and troubleshooting a partial install is an avoidable time sink. Below, a hands-on breakdown of Docker CE installation across several production-class Linux platforms—with notes where reality diverges from the official docs.
Why Native Docker on Linux?
Running Docker directly on Linux lets you leverage native kernel features (cgroups v2, namespaces, overlayfs) for optimal container performance—no VM overhead, no emulation layers. Teams building scalable microservice applications commonly expect all dev/test/prod systems to look and behave the same; native Docker is the bedrock.
Prerequisites
Check your baseline—cutting corners here can yield cryptic failures:
- 64-bit OS (x86_64/amd64; aarch64 has special caveats—see Docker docs for ARM).
- Kernel >= 3.10 (
uname -r
to confirm). - Root access or a sudo-enabled account.
- Unrestricted access to ports 443/80 (package retrieval via HTTPS).
Note: RHEL, derivative, and hardened distros (SELinux/AppArmor) require extra attention post-install—details below.
Remove Legacy Docker Components
A half-upgrade leaves orphan processes and broken packages. Clean out any prior installed Docker bits:
Ubuntu/Debian
sudo apt-get remove docker docker-engine docker.io containerd runc
Fedora/CentOS/RHEL
sudo dnf remove docker docker-client docker-client-latest \
docker-common docker-latest docker-latest-logrotate \
docker-engine docker-logrotate
Expect all removals to be non-destructive to existing containers—they aren’t deleted, but you’ll have to verify manually.
Installation by Distribution
Ubuntu 20.04/22.04+
Recent LTS releases. Use Docker’s official repositories rather than Ubuntu’s often-outdated docker.io
package.
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release
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 $(lsb_release -cs) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce=5:24.0.9~* docker-ce-cli=5:24.0.9~* containerd.io
Version pinning above (=5:24.0.9~*
) avoids silent upgrades that occasionally break dev pipelines. Omit if you prefer rolling latest.
Validation
sudo docker run --rm hello-world
Debian 11 (Bullseye) / 12 (Bookworm)
Package paths and keys diverge slightly from Ubuntu. Pay attention to the code name in the repo URL.
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/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/debian $(lsb_release -cs) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce containerd.io
Note: If you see broken dependency errors, check that your /etc/apt/keyrings/docker.gpg
permissions are set to at least 0644.
Fedora 38/39
Official Docker is compatible, but many prefer Podman—if forced to run Docker for legacy pipelines, use:
sudo dnf remove -y docker docker-client docker-client-latest \
docker-common docker-latest docker-latest-logrotate \
docker-logrotate docker-engine
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo \
https://download.docker.com/linux/fedora/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io
sudo systemctl enable --now docker
dnf will auto-resolve dependencies, but on SELinux-enabled hosts, expect denials. Use sudo setenforce 0
during initial smoke tests—then craft appropriate SELinux exceptions.
CentOS 7 & 8 Stream
CentOS 7 isn’t getting current Docker CE updates, but 20.10.x is considered stable.
sudo yum remove docker docker-client docker-client-latest \
docker-common docker-latest docker-latest-logrotate \
docker-logrotate docker-engine
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io
sudo systemctl enable --now docker
On CentOS 8, use dnf
in place of yum
.
Arch Linux
Rolling release, Docker package in core repo.
sudo pacman -Syu --noconfirm docker
sudo systemctl enable --now docker.service
Quick check
sudo docker run --rm hello-world
Note: On Arch, a full upgrade (-Syu
) is a double-edged sword. It guards against partial update breakage, but may pull in unrelated package updates. Weigh the risk.
Post-Install Steps
Run Docker as a Non-Root User
By default, only root can execute Docker—an anti-pattern in production automation.
sudo usermod -aG docker $USER
Log out and back in, or exec su -l $USER
to pick up group membership.
Auto-Start Docker at Boot
Systemd units are set to disabled after install. Enable via:
sudo systemctl enable docker
Common Pitfalls & Diagnostics
Daemon Not Active
sudo systemctl status docker
# Expected active (running); else:
sudo systemctl start docker
Firewall/Networking
- Docker default bridge may fail if firewalld/nftables blocks forwarding. Inspect with
sudo iptables -L -nv
. - On corporate environments, check for HTTP/HTTPS proxies—Docker daemon won’t inherit shell proxy settings unless configured in
/etc/systemd/system/docker.service.d/http-proxy.conf
.
SELinux/AppArmor
- CentOS/Fedora, expect denial messages like:
Enable permissive mode or define exceptions (avc: denied { write } for pid=... comm="dockerd" ...
semanage permissive -a container_t
as temporary workaround).
Containerd Incompatibility
Docker CE relies on containerd; mismatched versions (especially when mixing distro and Docker repos) yield errors such as:
docker: Error response from daemon: failed to create shim task: ...
Pin containerd version to Docker’s recommendation (apt-get install containerd.io=...
).
Practical Example: Deploying a Local Nginx Container
docker run -d --name webtest -p 8080:80 nginx:1.25-alpine
curl -I http://localhost:8080
Response should include HTTP/1.1 200 OK
. If port binding fails (driver failed programming external connectivity
), investigate firewalld or check for port conflicts with netstat -tulpn
.
Non-Obvious Tips
- Container Autostart: To have containers restart after host reboot, use:
docker run --restart=always [...]
- Storage Driver Tuning: For high-write workloads, consider using
overlay2
overaufs
ordevicemapper
. Check active driver withdocker info | grep Storage
. - Version Drift: Automated upgrades can sometimes introduce regression bugs (see moby/moby GitHub issues)—test in dev before updating prod nodes.
No single install procedure covers every edge case; corporate hardened images, custom kernels, or network policies may require deeper adaptation—this guide emphasizes known good defaults, but expect to tune for your environment.