How Dive Handles Docker and Podman Container Runtimes

Dive abstracts container runtime differences behind the image.Resolver interface, automatically selecting Docker Engine, Podman, or archive resolvers at runtime based on the --source flag.

Dive, the popular container image exploration tool by wagoodman/dive, supports multiple container runtimes through a clean abstraction layer. Rather than hardcoding Docker-specific logic, the tool implements a strategy pattern using the image.Resolver interface. This design allows seamless analysis of images from Docker Engine, Podman, or local archives without modifying the core analysis engine.

The Resolver Interface Architecture

The architecture centers on the image.Resolver interface, which standardizes how Dive obtains, builds, or extracts container images. Each supported runtime implements this interface differently, but all implementations ultimately produce a Docker-compatible image archive for the analysis pipeline. This convergence ensures that layer analysis and filesystem exploration work identically regardless of the source.

Docker Engine Support

Dive communicates with Docker through the docker.engineResolver type defined in dive/image/docker/engine_resolver.go. This implementation uses the official Docker Go SDK to communicate with the daemon.

When fetching an image, the resolver first checks local storage and automatically pulls missing images. It then streams the image archive using dockerClient.ImageSave and passes the stream to docker.NewImageArchive for parsing. The constructor NewResolverFromEngine and the fetchArchive method (lines 63-71) handle this orchestration.

Podman Engine Support

Podman support is implemented in dive/image/podman/resolver.go via the podman.resolver type. Rather than using a Podman-specific SDK, this resolver acts as a thin wrapper around the existing Docker archive infrastructure.

The resolver shells out to the Podman CLI, executing podman image save to generate a Docker-compatible tarball. It then passes this archive to docker.NewImageArchive, reusing the standard parsing logic. This approach works on Linux and macOS where the Podman CLI is available. The resolveFromDockerArchive and Extract functions (lines 59-70) manage this translation layer.

Docker Archive Support

For existing image archives, Dive provides docker.archiveResolver (created via NewResolverFromArchive). This resolver reads local tar or zip files containing Docker image archives without requiring a running daemon, using the same parsing pipeline as the engine-based resolvers.

Runtime Selection Logic

The selection mechanism resides in dive/get_image_resolver.go. The CLI flag --source maps to an ImageSource enum (SourceDockerEngine, SourcePodmanEngine, or SourceDockerArchive), which the GetImageResolver function uses to instantiate the correct implementation:

func GetImageResolver(r ImageSource) (image.Resolver, error) {
    switch r {
    case SourceDockerEngine:
        return docker.NewResolverFromEngine(), nil
    case SourcePodmanEngine:
        return podman.NewResolverFromEngine(), nil
    case SourceDockerArchive:
        return docker.NewResolverFromArchive(), nil
    }
    return nil, fmt.Errorf("unable to determine image resolver")
}

This switch statement (lines 62-73) is invoked from the CLI entry point in cmd/dive/cli/internal/command/root.go (line 46). The fetched resolver is then passed to adapter.ImageResolver(resolver).Fetch(ctx, opts.Analysis.Image) to retrieve the image for analysis.

Practical Usage Examples

Select your container runtime using the --source flag:


# Default: Analyze from local Docker daemon

dive nginx:latest

# Analyze from Podman

dive --source=podman myapp:latest

# Analyze local tarball

dive --source=docker-archive ./myimage.tar

Integrate Dive's runtime selection programmatically in Go:

package main

import (
    "context"
    "log"

    "github.com/wagoodman/dive"
    "github.com/wagoodman/dive/dive/image"
)

func main() {
    // Select runtime source
    src := dive.SourcePodmanEngine // or SourceDockerEngine, SourceDockerArchive
    
    resolver, err := dive.GetImageResolver(src)
    if err != nil {
        log.Fatalf("resolver error: %v", err)
    }
    
    img, err := resolver.Fetch(context.Background(), "myimage:latest")
    if err != nil {
        log.Fatalf("fetch error: %v", err)
    }
    
    // Image ready for analysis
    _ = img
}

Summary

  • Abstracted Interface: Dive uses the image.Resolver interface to decouple image fetching from analysis logic, located in dive/get_image_resolver.go.
  • Docker Integration: The docker.engineResolver uses the Docker Go SDK and ImageSave API to stream images directly from the daemon via dive/image/docker/engine_resolver.go.
  • Podman Compatibility: The podman.resolver shells out to podman image save and reuses Docker archive parsing in dive/image/podman/resolver.go, avoiding Podman-specific complexity.
  • Unified Pipeline: All resolvers ultimately produce Docker-compatible archives processed by docker.NewImageArchive, ensuring consistent analysis regardless of source.
  • User Control: The --source flag maps to the ImageSource enum to select resolvers at runtime without code changes.

Frequently Asked Questions

Can Dive analyze images from containerd or CRI-O?

Dive does not currently implement native resolvers for containerd or CRI-O. However, if these runtimes can export Docker-compatible image archives using tools like ctr image export, you can analyze them using the --source=docker-archive flag.

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

According to the source code in dive/image/podman/resolver.go, the Podman resolver intentionally wraps the Docker archive parser because Podman's image save command produces Docker-compatible tarballs. This reuse avoids duplicating parsing logic and ensures feature parity between runtime sources while minimizing maintenance overhead.

Does Dive require the Docker daemon to be running when using Podman?

No, when using --source=podman, Dive only requires the Podman CLI to be installed and accessible in the system path. It does not communicate with or require a running Docker daemon, as it shells out to podman image save directly and processes the resulting archive independently.

How does Dive handle image pulling for Docker versus Podman?

The Docker resolver automatically pulls missing images via the Docker SDK before exporting them through ImageSave. The Podman resolver relies on Podman's native behavior when executing podman image save, which will pull the image if it doesn't exist locally depending on the Podman configuration and version.

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 →