Skip to main content

Docker Engine and Compose

Component map​

ComponentRole
dockerd / Docker EngineThe daemon that creates and manages images, containers, networks, and volumes
docker CLISends commands to the daemon
containerdThe underlying container runtime Docker uses
BuildxBuilds images with extended build capabilities
Compose pluginDefines applications in YAML and manages multiple containers with docker compose

Installing Docker does not deploy an application. Application workloads exist only once containers have been created and started.

Docker client commands reach the daemon, which manages local images and containers and exchanges images with a registry.Open full-size image

Start with the commands on the left: the client sends requests to the daemon. build creates an image, pull retrieves one from a registry, and run creates and starts a container from an image, pulling it first if needed. The image and its running container are separate objects. Compose uses the same Engine to manage several services; it is not shown in this diagram.

Inspect the current installation​

[REMOTE: VPS]
command -v docker || true
docker --version || true
docker compose version || true
dpkg -l | grep -E 'docker|containerd' || true

If a supported Docker installation already works, do not reinstall it or mix package sources. For a new installation, configure apt using Docker’s official Ubuntu repository instructions rather than mixing these packages with Ubuntu’s docker.io packages.

Configure the official apt repository​

[REMOTE: VPS]
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

Create the repository file below, replacing both placeholders with this VPS’s actual values. The commands that follow show its Ubuntu codename and architecture. If the file already exists, inspect it before changing it rather than overwriting it blindly.

/etc/apt/sources.list.d/docker.sources
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: <UBUNTU_CODENAME>
Components: stable
Architectures: <DPKG_ARCHITECTURE>
Signed-By: /etc/apt/keyrings/docker.asc

Use the system’s actual codename and architecture, rather than copying values from another Ubuntu release:

[REMOTE: VPS]
. /etc/os-release
printf '%s\n' "${UBUNTU_CODENAME:-$VERSION_CODENAME}"
dpkg --print-architecture
sudo apt update
apt-cache policy docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin

If the official repository has no candidate packages for this release, stop. Do not substitute another Ubuntu codename in the source configuration.

Simulate the installation, then verify it​

[REMOTE: VPS]
sudo apt-get -s install \
docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin

Review the simulation for removals or conflicts and confirm that no critical packages will be removed before installing:

[REMOTE: VPS]
sudo apt install -y \
docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin

systemctl is-enabled docker
systemctl is-active docker
docker --version
docker compose version

Non-root use and its security implications​

[REMOTE: VPS]
sudo usermod -aG docker "$VPS_USER"

Supplementary group membership takes effect in a new login session. Log out and reconnect over Tailscale using SSH, then run id. Never use this command:

sudo chmod 666 /var/run/docker.sock

This Docker Engine runs as root. Membership in the docker group grants root-level privileges, because members can tell the daemon to mount host paths or start privileged containers. Add only trusted administrators to this group.

Functional test​

[REMOTE: fresh login as VPS_USER]
id
docker info --format \
'ServerVersion={{.ServerVersion}} Driver={{.Driver}} CgroupDriver={{.CgroupDriver}}'
docker run --rm hello-world
docker ps -a

With hello-world, the CLI contacts the daemon, which pulls the image, creates a container, runs it, and prints the result. --rm deletes the container when it exits, not its image; the image normally remains in the local cache.

Keep images, containers, and volumes distinct​

  • Deleting a container does not automatically delete its image. Images are templates; containers are instances. For the processes inside a container and their memory boundaries, see processes and memory.
  • Recreating a container does not preserve important data in its writable layer.
  • Data that must persist belongs in named volumes or explicitly chosen host directories.
  • /var/lib/docker holds Docker’s internal state. Do not edit it manually.
  • A Compose file describes the desired state, but no application Compose files are created during this foundation stage.

Firewall reminder​

Docker-published container ports can bypass ordinary UFW rules. For every future deployment, review Compose ports, actual listening addresses, and Docker/iptables rules together. Binding a service only to 127.0.0.1, to a Tailscale address, or to a reverse-proxy network has different consequences; choose deliberately.

Explore connectionsOpen network