docker inspect

docker inspect prints the detailed metadata Docker stores about objects such as containers, images, volumes, and networks. It matters because many debugging questions are not visible in docker ps: exact mount paths, port bindings, environment values, labels, image IDs, restart counts, network addresses, and process state. The command returns structured JSON by default, so it is useful both for humans investigating a problem and for scripts that need reliable Docker facts.

Overview: How docker inspect Works

Docker is built around objects managed by the Docker daemon. An image is a read-only template made from stacked filesystem layers and configuration metadata. A container is an instance of an image with runtime configuration, a thin writable layer, mounts, network attachments, and usually one main process. A volume is Docker-managed persistent storage, and a network is a virtual connectivity boundary that containers can join.

docker inspect asks the Docker daemon for the JSON description of one or more of those objects. The Docker CLI is only the client; it sends an API request to the daemon, the daemon looks up the object by name or ID, and the daemon returns the stored metadata. On Docker Desktop for macOS and Windows, Linux containers run inside Docker’s managed Linux VM, but the command from your host terminal still talks to the daemon and returns the same kind of object data.

The most common target is a container. A container inspect result includes sections such as Id, Created, Path, Args, State, Image, Config, HostConfig, NetworkSettings, and Mounts. These names matter because they map to different layers of Docker behavior. Config comes largely from image and container configuration, including environment variables, labels, exposed ports, and the command. HostConfig describes host-side runtime choices, such as bind mounts, restart policy, resource limits, and published ports. State tells you whether the container is running, exited, paused, restarting, or dead, and includes exit code and timestamps.

Inspect output is not the same as application logs or files inside the container. For logs, use docker logs. For an interactive shell, use docker exec. For a list view, use docker ps, docker images, docker volume ls, or docker network ls. docker inspect is the deep metadata view: it explains how Docker created and is managing the object.

By default, Docker returns a JSON array, even when you inspect one object. That makes the output precise, but long. The --format option uses Go template syntax to print only the fields you need. This is valuable in scripts and during incidents because it avoids fragile scraping of table output.

Syntax

docker inspect [OPTIONS] NAME|ID [NAME|ID...]
docker inspect --format '{{.State.Status}}' CONTAINER
Option or part Meaning
NAME|ID The name or ID of a Docker object. It can be a container, image, volume, network, plugin, node, service, or task depending on your Docker environment.
-f or --format Formats the output with a Go template. Quote the template so your shell does not interpret braces or spaces.
--type Restricts the lookup to one object type, such as container, image, volume, or network. Useful when a name is ambiguous.
-s or --size For containers, includes size information for the writable layer and virtual size. This can be slower because Docker may need to calculate filesystem usage.

The general pattern is to inspect the whole object once, identify the field path you need, then rerun the command with --format for a clean answer.

Examples

Example 1: Inspect a Running Container

docker run -d --name inspect-web --label "com.example.team=payments" -e "APP_MODE=demo" -p 8080:80 nginx:1.27-alpine
docker inspect inspect-web

Output:

[
  {
    "Id": "7b0f4d2a9c1e...",
    "Name": "/inspect-web",
    "State": {
      "Status": "running",
      "Running": true
    },
    "Config": {
      "Image": "nginx:1.27-alpine",
      "Env": [
        "APP_MODE=demo"
      ],
      "Labels": {
        "com.example.team": "payments"
      }
    },
    "NetworkSettings": {
      "Ports": {
        "80/tcp": [
          {
            "HostIp": "0.0.0.0",
            "HostPort": "8080"
          }
        ]
      }
    }
  }
]

The first command creates a real container with a label, an environment variable, and a published port. The inspect output shows how Docker recorded those choices. The exact JSON is much longer than this representative output, but the important idea is that Docker stores runtime metadata separately from the image layers. Removing this container does not remove the nginx:1.27-alpine image, and removing the image would not remove a running container that still depends on it.

Example 2: Print Only the State and IP Address

docker inspect --format '{{.State.Status}} {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' inspect-web

Output:

running 172.17.0.2

--format reads fields from the JSON object with Go template syntax. .State.Status prints the lifecycle state, while the range loop walks through the container’s attached networks and prints the container IP address on each network. This is cleaner than piping a large JSON document through text tools, especially when field order or spacing changes.

Example 3: Inspect Mounts for Persistent Data

docker volume create inspect-data
docker run -d --name inspect-db -e "POSTGRES_PASSWORD=changeme" -v inspect-data:/var/lib/postgresql/data postgres:16-alpine
docker inspect --format '{{range .Mounts}}{{.Type}} {{.Name}} {{.Destination}}{{end}}' inspect-db

Output:

inspect-data
volume inspect-data /var/lib/postgresql/data

The first line in the output is from docker volume create. The formatted inspect line then shows that the database container has a Docker-managed named volume mounted at PostgreSQL’s data directory. This distinction is important: data in a named volume survives container replacement, while data written only to the container’s thin writable layer disappears when that container is removed.

Example 4: Inspect Image Metadata

docker image inspect nginx:1.27-alpine --format '{{.Id}} {{json .Config.ExposedPorts}}'

Output:

sha256:3f8a00f137a0... {"80/tcp":{}}

This inspects the image, not a running container. The image ID identifies the pulled image content, and .Config.ExposedPorts shows ports declared as image metadata. EXPOSE is documentation and metadata only; it does not publish a port to the host. Only docker run -p or Compose ports: creates a host port binding.

How it Works Step by Step

  1. You pass one or more names or IDs to docker inspect. The CLI does not read local JSON files; it asks the Docker daemon.
  2. The daemon resolves each identifier. If you use --type container or --type image, Docker limits the search to that object category.
  3. Docker loads the object’s metadata from its internal store. For a container, this includes image reference, runtime options, host configuration, mounts, networks, labels, environment values, and current state.
  4. The daemon returns structured JSON to the CLI. With no formatting option, the CLI prints the full JSON array.
  5. If --format is present, the CLI applies the Go template to each object and prints the rendered result.
  6. If --size is used on a container, Docker also calculates container filesystem size data, which may require extra filesystem work.

Inspect is therefore a read-only metadata operation. It does not enter the container, modify image layers, restart processes, or publish ports. It is safe to run during debugging, although the output may include sensitive configuration values such as environment variables, labels, command arguments, and mount paths.

Common Mistakes

Confusing Image Metadata with Container Runtime State

docker inspect nginx:1.27-alpine

This is valid, but it inspects the image. It will not tell you whether your inspect-web container is running, what host port it published, or which volume it mounted. Inspect the container when you need runtime state:

docker inspect --type container inspect-web

Forgetting to Quote Format Templates

docker inspect --format {{.State.Pid}} inspect-web

This is a fragile shell command because the unquoted braces can be interpreted by the shell before Docker receives them. Quote the template:

docker inspect --format '{{.State.Pid}}' inspect-web

Assuming Exposed Means Published

docker image inspect nginx:1.27-alpine --format '{{json .Config.ExposedPorts}}'

The result may show 80/tcp, but that only means the image declares the port as metadata. It does not make localhost:80 work on the host. To publish a port, create the container with an explicit mapping:

docker run -d --name published-web -p 8080:80 nginx:1.27-alpine

Leaking Secrets While Sharing Inspect Output

Inspect output can include environment variables, labels, command arguments, and mounted file paths. If a container was started with a real password in -e, that value can appear in .Config.Env. Do not paste full inspect output into tickets or chat without checking it first. Secrets should come from Docker secrets, mounted files, or an orchestrator secret store rather than being baked into image layers or casually passed around in logs and metadata.

Best Practices

  • Use docker inspect OBJECT for a full first look, then narrow with --format once you know the field path.
  • Quote every --format template with single quotes in Unix-like shells. In PowerShell, quoting rules differ, but the goal is the same: pass the template to Docker unchanged.
  • Use --type when a name could match more than one Docker object, especially in scripts.
  • Prefer specific image tags such as nginx:1.27-alpine and postgres:16-alpine when reproducing inspect output. latest is a moving target.
  • Inspect mounts before deleting containers. A named volume is usually the persistent data location; the container writable layer is disposable.
  • Remember that Config.ExposedPorts is image metadata, while NetworkSettings.Ports shows actual container port bindings.
  • Treat inspect output as potentially sensitive because it can reveal environment variables, labels, host paths, and command arguments.
  • Use docker container inspect, docker image inspect, docker volume inspect, or docker network inspect when the more specific command makes your intent clearer.

Practice Exercises

  1. Start an nginx:1.27-alpine container named practice-inspect with -p 8081:80. Use docker inspect to find the host port binding. Hint: compare Config.ExposedPorts and NetworkSettings.Ports.
  2. Create a named volume and mount it into an alpine:3.20 container at /data. Inspect the container and identify the mount type, source, and destination.
  3. Use --format to print only the status and exit code of a container that has already stopped. Expected end state: one short line that includes values from .State.Status and .State.ExitCode.

Summary

  • docker inspect returns structured metadata for Docker objects such as containers, images, volumes, and networks.
  • Container inspect output separates image-derived configuration, host runtime configuration, current state, network details, and mounts.
  • The default output is JSON; --format uses Go templates to print specific fields.
  • Image metadata is not the same as container runtime state. Use --type or object-specific inspect commands when clarity matters.
  • EXPOSE shows documented ports in image metadata, while -p creates real host port bindings.
  • Inspect is read-only and excellent for debugging, but its output can contain sensitive details.