Kennisbank › Docker › Docker Images: Inspect, Save, Load, Import and Registry Management
docker starter 04 October 2026

Docker Images: Inspect, Save, Load, Import and Registry Management

Docker Images: Inspect, Save, Load, Import and Registry Management This walks you through the Docker image and registry commands you actually use day to day —

```bash docker version --format '{{.Server.Version}}' ```

If that prints nothing, the daemon isn't running or your user can't talk to the socket.

1. Inspect an image before you trust it

`docker image inspect` dumps the metadata Docker stores about an image: layer digests, config, tags, entrypoint, environment, exposed ports. You use it when a container behaves differently from what you expected and you want to see what's actually baked in.

```bash docker image inspect nginx:1.27-alpine ```

That's a lot of JSON. For scripting, use `--format` with a Go template:

```bash docker image inspect nginx:1.27-alpine \ --format '{{.Architecture}}/{{.Os}} entrypoint={{.Config.Entrypoint}} cmd={{.Config.Cmd}}' ```

On a multi-arch host, pin the platform explicitly, otherwise you inspect whatever variant is cached locally:

```bash docker image inspect --platform linux/arm64/v8 nginx:1.27-alpine ```

The trade-off: `--format` is fast and scriptable, but you lose the surrounding context. If you're debugging a build, read the raw JSON once before you start templating.

2. Save an image to a tar archive

`docker image save` writes one or more images — layers, manifests, tags — into a tar stream. This is how you move an image between hosts that can't reach a registry, or keep a known-good build before you overwrite the tag.

```bash docker image save -o nginx-1.27-alpine.tar nginx:1.27-alpine ```

Without `-o` the archive goes to STDOUT, which is useful in a pipe:

```bash docker image save nginx:1.27-alpine | gzip > nginx-1.27-alpine.tar.gz ```

For multi-platform images you can list the platforms you want:

```bash docker image save \ --platform linux/amd64,linux/arm64/v8 \ -o nginx-multi.tar \ nginx:1.27-alpine ```

Note what this costs you: a saved tar contains the full layer set, so a 50 MB image easily becomes a 50 MB file, and multi-platform archives multiply that. It's a transport format, not a backup strategy.

3. Load an image back from a tar archive

`docker image load` reverses `save`. It reads a tarred repository from a file or STDIN and restores the images with their original tags.

```bash docker image load -i nginx-1.27-alpine.tar ```

From a gzipped pipe:

```bash gunzip -c nginx-1.27-alpine.tar.gz | docker image load ```

The output tells you which image and tag were loaded. If the archive was made without tags, you get `` and you'll have to retag manually.

`load` and `save` are symmetric — use them as a pair. Mixing `save` output with `import` (next step) produces an image with no layer history and no tags, which is rarely what you want.

4. Import a filesystem tarball as an image

`docker image import` is different from `load`. It takes a plain filesystem tarball — `.tar`, `.tar.gz`, `.bz2`, `.xz` — and turns it into a single-layer image. There is no config, no entrypoint, no environment unless you supply them.

```bash docker image import rootfs.tar.gz myapp:imported ```

You can apply Dockerfile-style instructions at import time with `-c`:

```bash docker image import \ -c 'CMD ["/usr/local/bin/myapp", "--serve"]' \ -c 'ENV APP_ENV=production' \ -c 'EXPOSE 8080' \ -m 'initial import from buildroot tarball' \ rootfs.tar.gz \ myapp:imported ```

The `-m` flag attaches a commit message, visible in `docker image history`. `--platform` sets the platform explicitly if the daemon is multi-platform aware.

Use `import` when you're bringing in a root filesystem from outside Docker — a buildroot output, a VM image you've flattened, a rescue tarball. Use `load` when you're moving Docker images between hosts. Getting these two mixed up is the single most common source of "why does my image have no entrypoint" questions.

5. Log in to a registry

`docker login` authenticates you against a registry and stores credentials in `~/.docker/config.json`. Without a server argument it defaults to `https://registry-1.docker.io/`, so you need a Docker Hub account for that path.

```bash docker login ```

For a private registry:

```bash docker login registry.example.com ```

You'll be prompted for username and password. For CI, pass the password via STDIN to avoid it landing in shell history:

```bash echo "$REGISTRY_PASSWORD" | docker login registry.example.com \ --username "$REGISTRY_USER" \ --password-stdin ```

On most systems, `docker login` needs root or `sudo`, because the credential store lives under the invoking user's home directory and the daemon socket is root-owned. If you've configured a credential helper (`credsStore` in `config.json`), the password never touches disk — that's worth the setup if you log in from a shared machine.

6. Log out when you're done

`docker logout` removes the stored credential for a registry. It's a one-liner, and it matters more than people think: a stale token in `config.json` is a valid credential for anyone who reads that file.

```bash docker logout docker logout registry.example.com docker logout localhost:8080 ```

The last example logs out of a registry running on port 8080 on the local host — common during development. If you use multiple registries, log out of each explicitly; there's no "log out everywhere" flag.

7. Work with multi-arch manifests

A manifest list is a single image name that points at several platform-specific images. When you `docker pull nginx:1.27-alpine` on an arm64 machine, Docker reads the manifest list, picks the arm64 entry, and pulls that. You never see the indirection.

`docker manifest` lets you inspect and build those lists yourself:

```bash docker manifest inspect nginx:1.27-alpine ```

To create a manifest list from images you've already pushed:

```bash docker manifest create myorg/myapp:1.0 \ myorg/myapp:1.0-amd64 \ myorg/myapp:1.0-arm64

docker manifest push myorg/myapp:1.0 ```

Subcommands have their own help: `docker manifest create --help`, `docker manifest push --help`. The full semantics are in the registry v2 specification, which is worth reading once if you plan to automate this.

The cost of manifest lists: every push has to push each platform image separately, and `docker manifest` still requires the experimental CLI flag on some older builds. On 25.x and later it's stable.

8. Read container logs and image history

`docker logs` is an alias for `docker container logs` and pulls stdout/stderr from a container. It's the first thing you reach for when a service won't come up.

```bash docker logs -f --timestamps --since 10m myapp ```

`-f` follows the stream like `tail -f`. `-t` adds timestamps. `--since` accepts an absolute time (`2013-01-02T13:23:37Z`) or a relative one (`42m`, `1h`). `--until` sets an end. `-n 100` limits to the last 100 lines. `--details` includes labels and stream metadata that Docker attaches.

`docker image history` shows how an image was built, layer by layer:

```bash docker image history nginx:1.27-alpine ```

Each line is one Dockerfile instruction, with the layer size next to it. That's how you find the 400 MB layer someone added by copying a build directory into the image. Format it for scripts:

```bash docker image history --format '{{.Size}}\t{{.CreatedBy}}' myapp:latest ```

`--no-trunc` stops Docker from cutting long commands. `--format` accepts `table`, `json`, or a Go template.

For plugin authors, `docker plugin create` packages a plugin from a directory containing `config.json` and a `rootfs/` subdirectory:

```bash docker plugin create myorg/myplugin:1.0 ./plugin-data --compress ```

`--compress` gzips the rootfs before sending. This is niche — most people never touch it — but if you're extending the engine for storage, networking or logging, this is the entry point.

Verification

Confirm the daemon sees your images and registries are reachable:

```bash docker image ls --format 'table {{.Repository}}\t{{.Tag}}\t{{.Size}}' docker system info --format '{{.ServerVersion}} {{.Architecture}} {{.OSType}}' ```

If you loaded an image in step 3, it should appear in the list with the tag from the archive. If you logged in in step 5, verify the credential was stored:

```bash docker system info --format '{{json .RegistryConfig}}' ```

A successful `login` shows the registry under `IndexConfigs`. A successful `logout` removes it.

Common problems

`docker load` reports "invalid tar header" or "unexpected EOF". You're feeding it a gzipped archive without decompressing. `docker load` doesn't auto-detect gzip. Use `gunzip -c file.tar.gz | docker load` or `docker load -i file.tar` after decompressing.

`docker login` fails with "Cannot autolaunch D-Bus without X11 $DISPLAY". You're on a headless server and Docker is trying to use a desktop credential helper. Either install a CLI credential helper (`docker-credential-pass`, `docker-credential-secretservice`) or set `"credsStore": ""` in `~/.docker/config.json` to fall back to plaintext storage.

`docker image inspect --platform` returns the wrong architecture. The image isn't a manifest list — it's a single-platform image, and `--platform` is ignored. Check with `docker manifest inspect ` first. If it prints a single config object rather than a list, there's only one variant to pull.

Docker's image and registry tooling is stable because it sits on top of the OCI and registry v2 specifications rather than inventing its own. That's also why the commands feel inconsistent — `load` and `import` look similar but do different things, `save` and `export` likewise. Once you've internalised which pair belongs to images and which to containers, the rest is flags.

← Terug naar kennisbank
← Terug naar kennisbank