Mastering Docker Installation on Ubuntu: A Step-by-Step Guide for Precision and Performance
A misconfigured Docker install on Ubuntu breaks CI jobs, blocks kernel upgrades, and leads to subtle security exposure. A one-liner like apt install docker.io
looks tempting but frequently results in outdated binaries and missing dependencies. The approach below uses the official Docker APT repo—aligns with Docker documentation, but with context and practical insight.
Baseline Environment
- Target OS: Ubuntu 20.04 LTS, 22.04 LTS (other releases vary in package availability)
- Access: User in
sudo
group - Shell: Bash assumed; commands should be POSIX-compliant
Any deviation (custom kernels, ARM architecture) needs additional steps not covered here.
1. System Prep
Avoid carryover issues. First, clean up old Docker artifacts—conflicts between docker.io
and docker-ce
often waste hours:
sudo apt remove --purge docker docker-engine docker.io containerd runc
sudo apt update
sudo apt upgrade -y
If you’re running this on a shared server, check for active containers or services before removal.
Install dependencies for secure APT transport:
sudo apt install apt-transport-https ca-certificates curl gnupg2 lsb-release -y
Note: gnupg2
and lsb-release
are often missing on minimal VMs.
2. Trust Chain: GPG Key Setup
Docker packages are signed with a GPG key. Skipping this opens your system to potential package spoofing:
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
Check permissions:
ls -l /etc/apt/keyrings/docker.gpg
If not root-readable (-rw-r--r--
), some tools like unattended-upgrades may later reject updates.
3. Add Official Docker Repository
Pin the repo to your current Ubuntu codename (e.g., focal
for 20.04, jammy
for 22.04):
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
Gotcha: Unattended-upgrades won’t update Docker from this repo unless “origin=download.docker.com” is allowed. Not every org enables this.
Reload sources:
sudo apt update
4. Install Docker Engine and Dependencies
Bring in the engine, CLI, and the container runtime:
sudo apt install docker-ce=5:24.0.7-1~ubuntu.$(lsb_release -cs) docker-ce-cli=5:24.0.7-1~ubuntu.$(lsb_release -cs) containerd.io
Why version pinning? Avoids surprise upgrades and resolves known incompatibilities with docker-compose
in some CI/CD pipelines. Omit the version for “latest”, but this isn’t recommended for production.
Sample output on success:
Setting up docker-ce (5:24.0.7-1~ubuntu.focal) ...
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /lib/systemd/system/docker.service.
If you see The following packages have unmet dependencies
, ensure containerd.io
is present and reboot if the kernel was updated.
5. Sanity Check: Is Docker Running?
Status and version check:
sudo systemctl status docker
docker version
Typical output (truncated):
Client: Docker Engine - Community
Version: 24.0.7
Server: Docker Engine - Community
Engine:
Version: 24.0.7
Check docker info
for cgroup driver:
Cgroup Driver: systemd
If this reads cgroupfs
, review your kernel and Docker settings—mismatches can cause erratic container behavior.
6. Configure Non-Root Usage
Avoid repeated sudo
by adding your user to the docker
group:
sudo usermod -aG docker $USER
Note: You must log out and back in. Exec’ing a new shell is not always sufficient if you’re in nested tmux or SSH sessions.
Verify group membership:
id -nG $USER
Run a test container without sudo:
docker run --rm hello-world
If you get Got permission denied while trying to connect to the Docker daemon socket
, logout/login again or check /var/run/docker.sock
permissions.
7. Persistent Service Activation
Ensure Docker starts after reboot:
sudo systemctl enable docker
Optional: For systems using cloud-init or custom systemd overrides, double-check that no conflicting drop-ins are present under /etc/systemd/system/docker.service.d/
.
Performance Tuning & Security
-
Storage Driver:
Default is usually OverlayFS (overlay2
). Confirm:docker info | grep "Storage Driver"
If you're running on legacy ext4 without d_type support, you may see errors or slow performance.
-
Limiting Resources:
Production-grade containers need explicit CPU/RAM limits:docker run --cpus="2.0" --memory="2g" nginx
-
Audit the Install:
Use docker-bench-security:git clone https://github.com/docker/docker-bench-security.git cd docker-bench-security sudo ./docker-bench-security.sh
-
Regular Updates:
Official repo makesapt upgrade
sufficient, but monitor Docker release notes for breaking changes.
Common Pitfalls (and Recovery)
Symptom | Root Cause | Fix |
---|---|---|
Cannot connect to the Docker daemon... | Daemon not running, socket perms | sudo systemctl start docker , re-check groups |
Exec format error on ARM instances | x86 image on ARM hardware | Pull architecture-specific image (e.g., arm64v8/ubuntu ) |
Old containers fail after upgrade | Volume/data format mismatch | Recreate containers, migrate volumes as needed |
Hanging stop/remove of containers | Stale overlay or orphaned processes | sudo reboot usually clears; advanced: clean up mounts |
Example: Interactive Ubuntu Container
Sometimes a plain smoke test isn’t enough. Need to verify networking, volume mounting, or DNS within the container?
docker run --rm -it --network host -v /tmp/tempdata:/mnt ubuntu:latest bash
Modifies the container’s networking to host mode, and mounts /tmp/tempdata
for live troubleshooting. Exit with exit
; container is removed due to --rm
.
Non‑Obvious Insights
- Docker’s default log driver is
json-file
. For high-volume workloads, swap tojournald
or a centralized logging plugin; otherwise log rotation will bottleneck disk IO. - If you see
WARNING: No swap limit support
indocker info
, your kernel’s boot flags may lackswapaccount=1
. Depending on workload, this may be noise—or a sign of improper resource isolation.
Closing Thoughts
A production-grade Docker install on Ubuntu demands explicit configuration, sensible version control, and periodic security review. Each missing step compounds future risk. That quick script is fine for a test VM, but serious workloads deserve more.
Questions, disagreement, more edge cases? Drop comments below. The rabbit hole goes deeper.