Check Docker's Health with docker info

When a deploy script just hangs and nobody can say whether the daemon is even alive, docker info is the first command to run. You will use it to check the client and daemon connection, read the host's container and image counts, and extract selected fields for a script. Allow about ten minutes. The examples were checked with Docker Community Engine 29.8.1 from the docker-ce-cli package on Ubuntu 24.04.5 LTS.

1. Check which Docker client you are using

Start with ordinary, unprivileged checks. They do not contact the daemon and do not require sudo:

$ command -v docker
/usr/bin/docker
$ docker version --format '{{.Client.Version}}'
29.8.1
$ dpkg-query -W -f='${Package} ${Version}\n' docker-ce-cli
docker-ce-cli 5:29.8.1-1~ubuntu.24.04~noble

The package version is distribution-specific. If your command comes from another package or an earlier release, fields and wording in the human-readable report can differ. The installed manual describes docker info as an alias for docker system info.

Checkpoint: Confirm the path and version belong to the installation you intend to inspect. A shell can find a different Docker binary from the one you expected if several installations are present.

2. Run the system report

Run the command without options:

$ docker info
Client: Docker Engine - Community
 Version:    29.8.1
 Context:    default
 Debug Mode: false
...
Server:
 Containers: 48
  Running: 47
  Paused: 0
  Stopped: 1
 Images: 32
 Server Version: 29.8.1
 Storage Driver: overlayfs
 ...

Your counts and detail will differ. The report has a client section followed by a server section, and the useful fields are the current context, server version, total containers, running containers, image count, storage driver, cgroup configuration, kernel, architecture, CPU count, memory, Docker root directory and security options.

The image count is unique images, not every tag, so a host can have more image names than the number shown here. The storage-driver section carries driver-specific details, so do not parse the pretty output assuming every installation prints exactly the same lines.

Checkpoint: A successful report has a Server: section. If the command stops after client information, or reports it cannot connect, you have not inspected the daemon yet.

3. Interpret a connection failure safely

Capture the exit status immediately when diagnosing a failure:

$ docker info
Client:
 Context:    default
error during connect: this error may indicate that the docker daemon is not running
$ status=$?
$ printf 'docker info exit status: %s\n' "$status"
docker info exit status: 1

The exact diagnostic depends on the socket, context and daemon. Check the selected context without changing it:

$ docker context show
default
$ docker context ls
NAME        DESCRIPTION                         DOCKER ENDPOINT               ERROR
default *   Current DOCKER_HOST based configuration   unix:///var/run/docker.sock

If the daemon is managed by systemd and you have permission to inspect service state, use:

$ systemctl is-active docker
active

Do not jump straight to sudo docker info. Docker may read a different user's configuration and context under sudo, which can make the result misleading. If the socket is inaccessible, ask an administrator to grant appropriate access or inspect the service. Membership of the docker group is effectively privileged access to the host, so treat any group change as a security decision. No undo is needed for the diagnostic commands above, since none of them change state.

4. Extract fields for a health check

The --format option accepts a Go template. Quote the template in a POSIX shell so it does not interpret the braces:

$ docker info --format 'server={{.ServerVersion}} containers={{.Containers}} running={{.ContainersRunning}} images={{.Images}} storage={{.Driver}}'
server=29.8.1 containers=48 running=47 images=32 storage=overlayfs

These field names are present in the report produced by the installed Docker 29.8.1 daemon. They are a compact operational check, not a universal schema guarantee. If a field is absent or renamed by a future release, test the template against that release before depending on it in automation.

For a script, make the exit status authoritative and keep the report separate from the decision:

if report=$(docker info --format 'server={{.ServerVersion}} containers={{.Containers}} running={{.ContainersRunning}}'); then
    printf '%s\n' "$report"
else
    status=$?
    printf 'Docker daemon inspection failed with status %s\n' "$status" >&2
    exit "$status"
fi

This does not decide whether a given number of running containers is healthy. Add that policy explicitly in your own script, and remember a daemon can be reachable while an individual workload is failing.

5. Produce JSON for a saved diagnostic

The installed option also accepts the literal format name json:

$ docker info --format json > docker-info.json
$ test -s docker-info.json && echo 'report written'
report written
$ python3 -m json.tool docker-info.json > /dev/null
$ echo $?
0

This writes one JSON object with client and server information, including values such as DockerRootDir, RegistryConfig, runtime details and security options. Review it before sending it elsewhere, and remove the copy once it is no longer needed:

$ rm -- docker-info.json

Warning: that removal is irreversible. If the report is evidence for an incident, preserve it under your normal evidence-handling process instead of deleting it. Never put credentials into a template, and never assume formatting makes a sensitive value safe.

Common traps

Done means