Docker Containers, Images, Registries and Daemon
The four things every later guide assumes you understand, each demonstrated with a command rather than a diagram: why the client and daemon are separate, how an image differs from a container, what a registry actually stores, and where a digest comes from.
Getting Started Guide 2 of 46 Beginner
- OSUbuntu 26.04 LTS (resolute)
- Docker Engine29.7.2
- Shellbash
- Architectureamd64
- TimeAbout 10 min
- Reviewed20 August 2026
Tested on the versions above. Image IDs, digests, sizes and creation timestamps change every time an image is rebuilt upstream. Match the shape of the output, not the exact strings.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| DOCKER01 | 192.168.0.21 | Ubuntu 26.04 LTS | Docker Host | 2 Core | 4 GB | 50 GB |
Before you start
- Docker Engine installed and running - see guide 1.
- No prior container knowledge. This guide is the vocabulary everything else uses.
-
The client and the daemon are two different programs
dockeris a command-line client. It does almost nothing itself - it sends API requests to a background service calleddockerd, which does the actual work of pulling images and running containers. This is why the version command reports two versions, and why a permission error on the socket stops everything: you are being refused access to the daemon, not to the CLI.bash Example session docker version --format "Client {{.Client.Version}} / Server {{.Server.Version}} / API {{.Server.APIVersion}}"Client 29.7.2 / Server 29.7.2 / API 1.55Expected resultTwo version numbers and an API version. They are usually the same on one machine, but they do not have to be.
Success conditionYou get both a Client and a Server version. If Server is missing, the daemon is not running or you cannot reach it -
systemctl is-active dockerwill tell you which. -
An image is a read-only template; a container is a running instance of it
This is the distinction that trips up nearly everyone. An image is a stack of read-only filesystem layers plus metadata. It never runs and never changes. A container is that stack plus a thin writable layer on top and a process. One image can back a hundred containers, and removing a container does not touch the image it came from.
bash Example session docker image inspect nginx:alpine --format "layers={{len .RootFS.Layers}} size={{.Size}}"layers=8 size=26279045Expected resultA layer count and a size in bytes. Eight layers means eight stacked filesystem diffs.
Success conditionYou get a layer count. Those layers are shared: pulling a second image built on the same base reuses them instead of downloading again, which is why the second pull is usually much faster.
-
A registry stores images; a digest identifies exactly one
A registry is a content-addressed store for images. Docker Hub is the default. Notice what the pull prints: a
Digest:line. A tag such as3.22is a mutable label that can be repointed at a new build, but the digest is a hash of the content itself, so it always refers to one exact image. When something works on your machine and not on the server, comparing digests rather than tags is how you prove they are running different things.bash Example session docker pull alpine:3.223.22: Pulling from library/alpineDigest: sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dceStatus: Downloaded newer image for alpine:3.22docker.io/library/alpine:3.22Expected resultA digest and the fully qualified name.
alpine:3.22is shorthand - the real name isdocker.io/library/alpine:3.22.Success conditionYou see a
Digest:line. Run the same pull twice and the second reportsImage is up to dateinstead of downloading. -
Where the pieces meet
Listing images shows the store side. Listing containers shows the running side. Two rows here share a repository and tag but have different IDs - that is a tag being repointed at a newer build while the older image stays on disk, which is exactly the ambiguity digests exist to remove. Output is abridged to the first few rows.
bash Example session docker image ls --format "table {{.Repository}}:{{.Tag}}\t{{.ID}}\t{{.Size}}"REPOSITORY:TAG IMAGE ID SIZEnginx:alpine db35bfc6b295 94.2MBnginx:alpine 4a73073bd557 93.6MBalpine:latest 28bd5fe8b56d 13MBhello-world:latest 5dd0d3e6e255 25.9kBExpected resultOne row per image. Sizes are the on-disk size of the image, not the download size.
Success conditionYou can see images listed independently of containers.
docker ps -alists containers - the two are separate stores and separate commands.
Troubleshooting
permission denied while trying to connect to the Docker daemon socket
Why: Your user is not in the
dockergroup, so it cannot open /var/run/docker.sock. This is a client-to-daemon permission problem, not a broken installation.Fix:Add your user to the docker group, then start a new login session so the new group membership applies. Note that membership in the docker group is equivalent to root on that host - grant it deliberately.
bash getent group dockerdocker:x:983:sysadmin# if your user is absent, add it (requires sudo), then log out and back in:sudo usermod -aG docker $USERThe same tag behaves differently on two machines
Why: A tag is mutable. Both machines pulled
:latestor a version tag at different times and received different builds.Fix:Compare digests, not tags. Pin by digest where reproducibility matters.
bash Example session docker image inspect alpine:3.22 --format "{{index .RepoDigests 0}}"alpine@sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce# pin it explicitly:docker run --rm alpine@sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce echo pinned