Docker on Ubuntu: Reliable Installation for Consistent Container Operations
Docker has become the default runtime for Linux containerization. On Ubuntu, neglecting subtle installation details often leads to failed builds, permission errors, or CI/CD pipeline instability later. Here’s a seasoned engineer’s guide to standing up Docker cleanly on Ubuntu 18.04, 20.04, 22.04, or newer — with extra guardrails and side notes from production environments.
Preliminary Checklist
-
Confirm you’re running a supported Ubuntu version:
$ lsb_release -a Release: 22.04
-
Ensure shell access with
sudo
. -
Verify stable outbound network connectivity (proxy setups can break key download steps).
Remove Legacy Docker Packages
Residual packages (e.g., docker.io
, old docker-ce
) frequently cause dependency hell:
sudo apt-get remove docker docker-engine docker.io containerd runc
Gotcha: This purges binaries, not local images/volumes in /var/lib/docker
. Disk not freed until you address those separately.
Update Your Local Package Index
Never rely on a stale APT database. Pull the latest metadata before touching repos:
sudo apt-get update
Install HTTPS Transport and Helper Packages
APT repository signing today defaults to GPG on modern Ubuntu. These dependencies are non-negotiable:
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
Note: software-properties-common
is technically optional here on >=18.04. But include it if you anticipate other PPA/add-apt-repository needs.
Import Docker's GPG Key Properly
Since 2021, Docker has adjusted how their key is managed. Save it to /usr/share/keyrings
:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Why? This approach hardens the system against repo spoofing, avoiding legacy keyring warnings in APT >=2.4.
Add the Official Docker Repository
Provision the source list to pull stable Docker packages for your exact architecture and Ubuntu release:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Quick check:
$ grep docker /etc/apt/sources.list.d/docker.list
Resync APT Cache With Docker's Packages
Now, your local cache can see Docker’s repository:
sudo apt-get update
Look for lines like:
Get: https://download.docker.com/linux/ubuntu jammy InRelease [57.7 kB]
If you see “InRelease: key not available”, revisit the GPG key step.
Install Docker Engine, CLI, and Containerd
Core components — always choose from Docker’s repo rather than Ubuntu’s mainline archive to avoid stale versions:
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
Breakdown:
docker-ce
: Docker Community Engine daemon.docker-ce-cli
: The Docker CLI binary.containerd.io
: Upstream container runtime (used behind the scenes by Docker).
Version pinning: To lock a known working version, use apt-cache madison docker-ce
to see choices, then install a specific version with:
sudo apt-get install docker-ce=5:24.0.7~ubuntu.22.04~jammy
Post-Install Validation
Check if Docker’s daemon is running:
sudo systemctl status docker
Output should contain:
Active: active (running)
Verify binary version and build, e.g.:
$ docker --version
Docker version 24.0.7, build afdd53b
Smoke Test the Installation
Execute a “hello-world” container. This exercises both the client, daemon, pulling images, and underlying cgroups.
sudo docker run --rm hello-world
Expected output fragment:
Hello from Docker!
This message shows that your installation appears to be working correctly.
Tip: If you hit “Cannot connect to the Docker daemon at unix:///var/run/docker.sock”, check systemctl status docker
and try sudo journalctl -u docker.service
.
Allow Non-root Users (Optional but Common in Dev/Test)
For frictionless CLI use, add your account to the docker group:
sudo usermod -aG docker $USER
Log out fully and re-login (no, su
or new shell isn’t enough; systemd won’t re-evaluate group membership until PAM sees a fresh login). Confirm:
id | grep docker
docker run hello-world
Note: Never grant this on production servers unless you explicitly trust all users. Anyone in docker
can effectively root the node.
Side Issues and Troubleshooting
Problem | Symptoms | Solution |
---|---|---|
Stuck on old Docker version | docker --version < required release | Ensure you're using Docker's repo — not Ubuntu's default APT sources. |
User permission errors | Got permission denied while trying... | Add user to docker group, then re-login. |
APT "NO_PUBKEY" errors | GPG step missed or failed | Repeat GPG key installation step. |
Out-of-date kernel breaks daemon | Docker fails to start, log traces | Ensure kernel >= 5.x for latest Docker (see uname -r). |
Known issue: On WSL2 or custom kernels, certain modules (like overlay2
) might be unavailable. Check docker info
output.
Recap
Correct installation minimizes drift from dev to prod, avoids subtle user-space permission issues, and ensures upgrades are supportable. Pay particular attention to repository sources and local user/group policies.
Practical Example: Docker as a CI Runner
In CI (e.g., GitLab Runner), always specify image digests rather than tags for build reproducibility. Pin runner hosts' Docker versions using the approach above to align local builds with cluster workloads.
image: ubuntu@sha256:72d6f1ca4df52be633a3e4e6b3b339a...
Docker on Ubuntu isn’t just a set of commands—it’s a baseline for automating modern infrastructure. Any step skipped here will echo throughout every downstream container deployment.
For additional network setups (proxy, private registry, rootless mode), consult the official Docker documentation. Some enterprise environments demand even tighter controls.
This document aligns with Docker CE v24.0.7 as of June 2024. Adjust as future changes arise; best practices evolve.