How Dive Handles Docker Daemon, Podman, and Archive Image Sources

Dive abstracts image fetching through a Resolver interface that normalizes Docker daemon, Podman, and local archive sources into a unified *image.Image structure for layer analysis.

Dive is an open-source tool for exploring container image layers and detecting wasted space. According to the wagoodman/dive source code, the tool implements a pluggable architecture that handles multiple image sources—including Docker daemon, Podman, and local tar archives—through a consistent abstraction layer defined in dive/image/resolver.go.

The Resolver Interface Architecture

At the core of Dive's multi-source support is the Resolver interface. This contract declares three key operations that every image source must implement:

  • Fetch: Retrieve an image by ID or reference from the source
  • Build: Construct an image from a Dockerfile or build context
  • Extract: Pull out layer contents for detailed analysis

By coding against this interface, Dive’s analysis engine—responsible for calculating efficiency scores and rendering the terminal UI—remains completely agnostic to whether the image came from a local Docker daemon, a remote Podman socket, or a tar file on disk.

Detecting and Routing Image Source Types

When you invoke Dive with an image reference, the tool first determines which resolver to use. The function DeriveImageSource in dive/get_image_resolver.go parses the URL scheme to classify the source:

func DeriveImageSource(image string) (ImageSource, string) {
    s := strings.SplitN(image, "://", 2)
    // …
    switch scheme {
    case "docker":        return SourceDockerEngine, imageSource
    case "podman":        return SourcePodmanEngine, imageSource
    case "docker-archive":return SourceDockerArchive, imageSource
    case "docker-tar":    return SourceDockerArchive, imageSource
    }
    return SourceUnknown, ""
}

The GetImageResolver function then maps these enum values to concrete implementations:

ImageSource Resolver Implementation Source File
SourceDockerEngine docker.NewResolverFromEngine() dive/image/docker/engine_resolver.go
SourcePodmanEngine podman.NewResolverFromEngine() dive/image/podman/resolver.go
SourceDockerArchive docker.NewResolverFromArchive() dive/image/docker/archive_resolver.go

Docker Daemon Resolution

The Docker Engine Resolver in dive/image/docker/engine_resolver.go communicates directly with the Docker daemon using the official Docker client library.

When fetching an image, the fetchArchive method:

  1. Creates a client with client.NewClientWithOpts and determineDockerHost for host detection
  2. Pulls the image automatically if it’s missing locally
  3. Exports the image via ImageSave to obtain a tar stream
  4. Processes the stream through ExtractFromImage to build the layer tree

For building images, buildImageFromCli wraps the docker build command, then fetches the resulting image ID. This resolver supports TLS-encrypted daemons, SSH-based hosts, and automatic authentication.

Podman Resolution

The Podman Resolver in dive/image/podman/resolver.go takes a different approach: it delegates heavy lifting to the Docker resolver after converting Podman images to Docker-compatible archives.

The resolver executes podman image save <id> via streamPodmanCmd to produce a tar stream, then feeds that stream into Docker’s NewImageArchive parser. This strategy works because Podman’s export format follows the Docker image specification, allowing Dive to reuse existing parsing logic without duplication.

For builds, buildImageFromCli invokes podman build, saves the resulting image, and reuses the Docker extraction logic. The current implementation relies on the Podman CLI being available in $PATH and does not yet use the Varlink or REST API directly (noted as a TODO in the source).

Docker Archive Resolution

For local tar files, the Docker Archive Resolver in dive/image/docker/archive_resolver.go provides a read-only implementation.

The fetch method opens the file with os.Open, wraps it with NewImageArchive, and returns the parsed *image.Image. This resolver does not support building (returns an error) because archives are immutable exports. Extraction is handled by the caller after fetching, using the shared Docker extraction utilities.

Unified Analysis Workflow

Regardless of which resolver activates, the output is always a *image.Image struct containing the layer tree and file system representation. Dive’s analysis engine operates exclusively on this unified structure, calculating efficiency scores, detecting duplicate files, and rendering the terminal UI.

This design allows the CLI to accept any of the following forms interchangeably:


# Analyze from Docker daemon

dive docker://nginx:latest

# Analyze from Podman

dive podman://myapp:latest

# Analyze from local archive

dive docker-archive:///path/to/image.tar

# legacy alias

dive docker-tar:///path/to/image.tar

Programmatic Usage in Go

You can leverage Dive’s resolver architecture in your own Go applications. The following example demonstrates deriving the source and fetching an image programmatically:

import (
    "context"
    "github.com/wagoodman/dive"
    "github.com/wagoodman/dive/dive/image"
)

func loadImage(ref string) (*image.Image, error) {
    src, id := dive.DeriveImageSource(ref)
    resolver, err := dive.GetImageResolver(src)
    if err != nil {
        return nil, err
    }
    return resolver.Fetch(context.Background(), id)
}

This code mirrors the CLI’s internal workflow: classify the source, obtain the appropriate resolver, and fetch the unified image structure.

Summary

  • Dive abstracts image sources through the Resolver interface in dive/image/resolver.go, enabling support for Docker daemon, Podman, and local archives without changing the analysis engine.
  • Source detection occurs in dive/get_image_resolver.go via DeriveImageSource, which parses URL schemes (docker://, podman://, docker-archive://) to route to the correct implementation.
  • Docker daemon resolution uses the official Docker client library in dive/image/docker/engine_resolver.go to pull, build, and export images via the daemon API.
  • Podman resolution in dive/image/podman/resolver.go delegates to the Docker resolver after exporting images via podman image save, maintaining compatibility without requiring Podman-specific parsing logic.
  • Archive resolution in dive/image/docker/archive_resolver.go reads local Docker tar exports directly, providing a read-only path for offline analysis.

Frequently Asked Questions

How does Dive determine whether to use Docker or Podman?

Dive examines the URL scheme prefix in your image reference. If you specify podman://, Dive uses the Podman resolver. If you specify docker:// or omit the scheme entirely, Dive defaults to the Docker daemon resolver. The DeriveImageSource function in dive/get_image_resolver.go handles this classification by splitting the string on :// and matching the scheme against known constants.

Can Dive analyze Podman images without a Docker daemon running?

Yes. The Podman resolver in dive/image/podman/resolver.go executes podman image save to export the image as a tar stream, then parses that stream using Docker-compatible archive logic. This means Dive can analyze Podman images on systems where Docker is not installed, provided the Podman CLI is available in your $PATH.

Why does the Podman resolver use Docker's archive parser instead of native Podman libraries?

The Podman resolver delegates to Docker's NewImageArchive because Podman's exported tar format follows the Docker image specification. Rather than duplicating parsing logic, Dive reuses the existing Docker archive implementation after obtaining the image via podman image save. This design keeps the codebase DRY and ensures consistent layer analysis across both container engines. The source code notes that direct Varlink or REST API integration remains a future TODO.

What archive formats does Dive support for offline analysis?

Dive supports Docker image archives exported via docker save or podman save. You can reference these using the docker-archive:// or legacy docker-tar:// scheme followed by the absolute path to the tar file. The archive resolver in dive/image/docker/archive_resolver.go opens these files read-only and parses them using the same NewImageArchive logic used for daemon exports, enabling offline analysis without any running container engine.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →