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.Resolverinterface to decouple image fetching from analysis logic, located indive/get_image_resolver.go. - Docker Integration: The
docker.engineResolveruses the Docker Go SDK andImageSaveAPI to stream images directly from the daemon viadive/image/docker/engine_resolver.go. - Podman Compatibility: The
podman.resolvershells out topodman image saveand reuses Docker archive parsing indive/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
--sourceflag maps to theImageSourceenum 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →