Suggest an editImprove this articleRefine the answer for “How to inspect Docker image metadata?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Three commands cover almost everything:** `docker inspect <image>` for full JSON metadata, `docker history <image>` for layer-by-layer breakdown, `dive <image>` for interactive layer exploration. ```bash docker inspect nginx:1.27 --format '{{.Config.Cmd}} {{.Architecture}} {{.Size}}' docker history nginx:1.27 docker manifest inspect nginx:1.27 | jq . ``` **Key:** `inspect` shows what the image will do when run (CMD, ENV, EXPOSE, USER, layers). `history` shows how it was built. `dive` shows what is in each layer interactively.Shown above the full answer for quick recall.Answer (EN)Image**Inspecting Docker image metadata** is what you do before pulling, after pulling, when debugging "why did this image grow?", or when you want to know exactly what an image promises to do at runtime. Three CLI tools cover the territory. ## Theory ### TL;DR - **`docker inspect`** = full JSON dump of an image's config, layers, labels, architecture, size. - **`docker history`** = chronological list of layers with the instruction that produced each. - **`docker manifest inspect`** = the registry-level manifest (multi-arch info, layer digests). - **`dive`** (third-party) = interactive TUI showing layer-by-layer file changes. - All work locally; some work against remote images via the registry. ### `docker inspect` The primary command. Returns a 100+ line JSON document. Use `--format` to extract specific fields: ```bash # Everything (a lot) docker inspect nginx:1.27 # Specific fields docker inspect nginx:1.27 --format '{{.Id}}' docker inspect nginx:1.27 --format '{{.Architecture}}' docker inspect nginx:1.27 --format '{{.Size}}' docker inspect nginx:1.27 --format '{{.Config.Cmd}}' docker inspect nginx:1.27 --format '{{.Config.Entrypoint}}' docker inspect nginx:1.27 --format '{{.Config.User}}' docker inspect nginx:1.27 --format '{{.Config.WorkingDir}}' # JSON of a section docker inspect nginx:1.27 --format '{{json .Config.Env}}' | jq docker inspect nginx:1.27 --format '{{json .Config.ExposedPorts}}' | jq docker inspect nginx:1.27 --format '{{json .Config.Labels}}' | jq ``` Handy fields: - `.Id` — content digest of the image - `.RepoTags` — tags that point at this image - `.RepoDigests` — digest references in registries - `.Architecture`, `.Os` — target platform (`amd64`/`linux`) - `.Size` — total size (in bytes) - `.Created` — when the image was built - `.Config.*` — runtime config (Cmd, Entrypoint, Env, Labels, ExposedPorts, User, WorkingDir, Volumes, Healthcheck) - `.RootFS.Layers` — list of layer digests (in order) - `.History` — build history (Dockerfile-equivalent steps) ### `docker history` Shows layers from oldest (bottom) to newest (top), with the instruction that created each: ```bash $ docker history nginx:1.27-alpine IMAGE CREATED CREATED BY SIZE COMMENT 4f06b3e2c0c1 2 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemo… 0B <missing> 2 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B <missing> 2 weeks ago /bin/sh -c #(nop) EXPOSE 80 0B <missing> 2 weeks ago /bin/sh -c set -x && addgroup -g 101 -S… 8.94MB <missing> 2 weeks ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.27.4 0B <missing> 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B <missing> 4 weeks ago /bin/sh -c #(nop) ADD file:abcd1234… 7.79MB ``` Use `--no-trunc` for full instructions: ```bash docker history --no-trunc nginx:1.27-alpine ``` `<missing>` means the intermediate image has no separate ID locally — only the final image does. The instructions are still preserved in metadata. ### `docker manifest inspect` Shows the registry-side manifest, including multi-arch info: ```bash $ docker manifest inspect nginx:1.27 { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "digest": "sha256:abc123...", "platform": { "architecture": "amd64", "os": "linux" } }, { "digest": "sha256:def456...", "platform": { "architecture": "arm64", "os": "linux" } }, ... ] } ``` Useful for confirming an image supports your architecture before pulling, or finding the digest for a specific platform. ### `dive` (third-party) Not built into Docker, but the standard tool for understanding layer contents: ```bash $ dive nginx:1.27-alpine ``` Opens an interactive TUI: - Top panel: layers, with size and command. - Bottom panel: file tree of the selected layer (with diffs from previous). - Right panel: image details (efficiency score, wasted space). Invaluable for "why is my image 2 GB?" — you see the exact files contributed by each layer. ### Useful patterns #### "What CMD will run?" ```bash docker inspect <img> --format '{{.Config.Entrypoint}} {{.Config.Cmd}}' ``` #### "What env vars are baked in?" ```bash docker inspect <img> --format '{{json .Config.Env}}' | jq ``` #### "What ports does this image listen on?" ```bash docker inspect <img> --format '{{json .Config.ExposedPorts}}' | jq ``` #### "What user will the container run as?" ```bash docker inspect <img> --format '{{.Config.User}}' # empty = root (be careful) ``` #### "Find the biggest layer" ```bash docker history --format '{{.Size}}\t{{.CreatedBy}}' --no-trunc <img> | sort -h ``` #### "What is the content digest?" ```bash docker inspect <img> --format '{{index .RepoDigests 0}}' # myimg@sha256:abc123... ``` The immutable identifier — use this in production manifests instead of mutable tags. ### Common mistakes **Confusing `docker inspect` for images vs containers** ```bash docker inspect myimg # works on image docker inspect mycontainer # works on container # Same command, different objects → different fields available ``` The schemas differ. Container `inspect` includes `.State` (running/exited), `.NetworkSettings`, `.Mounts`. Image `inspect` does not. **Reading `<missing>` as an error** `<missing>` in `docker history` means the intermediate layer ID is not stored locally. The image still works; it is just an artifact of how Docker squashes intermediate metadata. Not a problem. **Forgetting that history shows DOCKERFILE STEPS, not file contents** ``` /bin/sh -c apt-get update && apt-get install ... && rm -rf /var/lib/apt/lists/* ``` This tells you what the build did, not what files ended up where. For files, use `dive` or `docker save` + tar inspection. **Inspecting an image you have not pulled** Local `docker inspect` requires the image to be in your local cache. For remote images: `docker pull` first, or use `docker manifest inspect` (which works against registries). ### Real-world usage - **Pre-deploy verification:** `docker inspect` to confirm CMD, USER, EXPOSE match expectations before promoting. - **Compliance audit:** scan all production images for OCI labels, expected user, no root. - **Image-size investigation:** `dive` and `docker history` to track down the biggest layers. - **Multi-arch verification:** `docker manifest inspect` to ensure your image has both amd64 and arm64 variants before deploying to mixed clusters. - **Reproducing builds:** `docker history` shows the build commands; cross-reference with the source Dockerfile. ### Follow-up questions **Q:** What is the difference between `Id` and `RepoDigest`? **A:** `Id` is the local image ID — a hash of the config blob. `RepoDigest` is the registry-side digest (hash of the manifest, used in pull-by-digest). They differ because the manifest hash includes the tag/registry info while the local ID is content-only. **Q:** How do I see what is in a specific layer? **A:** `dive` is the easiest. Manually: `docker save <img> -o img.tar && tar xf img.tar` gives you a directory per layer with their contents. **Q:** Can I inspect a running container's image? **A:** `docker inspect <container> --format '{{.Image}}'` returns the image ID; pass that to `docker inspect` to get image metadata. **Q:** What is the difference between `docker inspect` and `docker image inspect`? **A:** `docker inspect` is generic (works on images, containers, volumes, networks). `docker image inspect` is the explicit form for images only. Same output for images. **Q:** (Senior) How would you write a CI check that fails if an image has bad metadata? **A:** A small script that runs `docker inspect` and `docker history`, parses with `jq`, and asserts: (1) `Config.User` is not empty (no root containers), (2) required OCI labels present (`org.opencontainers.image.source`, `version`), (3) no `latest` tag in `Config.Image`, (4) total `Size` under a threshold, (5) layer count below a max. Wire this into the CI as a gate; fail the pipeline if any assertion breaks. Stronger version uses `dive --ci` which checks image efficiency scores automatically. ## Examples ### Quick image audit ```bash $ IMG=nginx:1.27-alpine $ docker inspect $IMG --format \ 'Id={{.Id}} Arch={{.Architecture}} OS={{.Os}} Size={{.Size}} User={{.Config.User}} Cmd={{.Config.Cmd}}' Id=sha256:4f06b3e2c0c1... Arch=amd64 OS=linux Size=54923456 User= Cmd=[nginx -g daemon off;] $ docker history --format 'table {{.Size}}\t{{.CreatedBy}}' --no-trunc $IMG | head SIZE CREATED BY 0B /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon off;"] 0B /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B /bin/sh -c #(nop) EXPOSE 80 8.94MB /bin/sh -c set -x && addgroup -g 101 -S nginx ... 0B /bin/sh -c #(nop) ENV NGINX_VERSION=1.27.4 0B /bin/sh -c #(nop) CMD ["/bin/sh"] 7.79MB /bin/sh -c #(nop) ADD file:abcd... ``` Four facts at a glance, plus the layer breakdown. ### Manifest inspection for multi-arch ```bash $ docker manifest inspect nginx:1.27 | \ jq '.manifests[] | {arch: .platform.architecture, digest: .digest}' { "arch": "amd64", "digest": "sha256:abc..." } { "arch": "arm64", "digest": "sha256:def..." } { "arch": "arm/v7", "digest": "sha256:ghi..." } { "arch": "386", "digest": "sha256:jkl..." } ``` Confirms which platforms the image supports and gives per-platform digests for pinning. ### Find the biggest layer ```bash $ docker history --format '{{.Size}}|{{.CreatedBy}}' --no-trunc node:22-alpine \ | grep -v '^0B|' \ | sort -h \ | tail -5 47.2MB|/bin/sh -c apk add --no-cache python3 ... 42.5MB|/bin/sh -c addgroup -g 1000 node ... 105MB|/bin/sh -c set -ex; ... npm install ``` The biggest contributor (here, `npm install`) is your first target if you need to shrink the image.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.