Where to Find the Source Code for Dive's Docker Image Resolver
The source code for Dive's Docker image resolver is located in the dive/image/docker package, with the core Resolver interface defined in dive/image/resolver.go and concrete implementations handling Docker Engine and tar archive sources.
Dive, the container image exploration tool maintained in the wagoodman/dive repository, abstracts image fetching behind a pluggable Resolver interface. If you need to extend Dive's image-loading capabilities or reuse its Docker integration in your own Go projects, you'll find the relevant source code organized into clear interface definitions and protocol-specific implementations.
Core Interface: The Resolver Contract
The foundation of Dive's image resolution system lives in dive/image/resolver.go. This file defines the Resolver interface that all image sources—including Docker—must implement.
According to the wagoodman/dive source code, the interface requires four key capabilities:
type Resolver interface {
Name() string
Fetch(ctx context.Context, id string) (*Image, error)
Build(ctx context.Context, options []string) (*Image, error)
ContentReader
}
type ContentReader interface {
Extract(ctx context.Context, id string, layer string, path string) error
}
Any struct implementing these methods can serve as a valid image resolver, allowing Dive to support Docker Engine, Docker archives, Podman, and other container runtimes through the same abstraction.
Docker-Specific Implementations
The Docker-specific resolvers reside in the dive/image/docker/ directory. Dive provides two distinct resolvers for handling Docker images depending on their source location.
Engine Resolver (engine_resolver.go)
The Engine resolver handles live Docker daemon interactions. Located in dive/image/docker/engine_resolver.go, this implementation connects to a running Docker Engine to pull, build, or save images.
Key functions in this file include:
determineDockerHost()– Discovers the correct Docker host endpoint from environment variables or contextfetchArchive()– Orchestrates the image save operation usingdockerClient.ImageSave()to stream layers as a tar archiveFetch()– Checks if the image exists locally viadockerClient.ImageInspect(), pulls it if missing, then converts the Docker image stream into Dive's internalImagerepresentation viaNewImageArchive()
Archive Resolver (archive_resolver.go)
The Archive resolver loads images from local tar files created by docker save. Found in dive/image/docker/archive_resolver.go, this resolver implements the same Resolver interface but works with static files rather than live daemons.
This resolver simply opens the specified tar path using os.Open() and passes the file handle to NewImageArchive(), which parses the Docker archive format into Dive's layer model.
How Dive Selects the Right Resolver
Dive determines which concrete resolver to instantiate through a factory pattern defined in dive/get_image_resolver.go.
The selection process follows three steps:
-
Source Parsing – The
DeriveImageSource()function parses URI strings (e.g.,docker://nginx:latest) and maps them to anImageSourceenum value (SourceDockerEngine,SourceDockerArchive, etc.) -
Factory Dispatch –
GetImageResolver()returns the appropriate implementation based on the source type:
func GetImageResolver(r ImageSource) (image.Resolver, error) {
switch r {
case SourceDockerEngine:
return docker.NewResolverFromEngine(), nil
case SourceDockerArchive:
return docker.NewResolverFromArchive(), nil
// … Podman, etc.
}
return nil, fmt.Errorf("unable to determine image resolver")
}
- Execution – The returned resolver's
Fetch()method handles the actual image acquisition, whether that means querying the Docker daemon or reading from disk.
Programmatic Usage Examples
You can import and use Dive's resolvers directly in your own Go applications to leverage its Docker integration.
Resolving from Docker Engine
package main
import (
"context"
"log"
"github.com/wagoodman/dive/dive"
"github.com/wagoodman/dive/dive/image"
)
func main() {
// Parse the source string the same way Dive's CLI does.
src, imgRef := dive.DeriveImageSource("docker://nginx:latest")
if src != dive.SourceDockerEngine {
log.Fatalf("unexpected source: %v", src)
}
// Obtain the concrete resolver.
resolver, err := dive.GetImageResolver(src)
if err != nil {
log.Fatalf("resolver error: %v", err)
}
// Fetch the image (pulls if needed).
img, err := resolver.Fetch(context.Background(), imgRef)
if err != nil {
log.Fatalf("fetch error: %v", err)
}
// `img` now holds Dive's internal representation.
log.Printf("Image %s has %d layers", img.ID, len(img.Layers))
}
Loading from a Tar Archive
resolver, _ := dive.GetImageResolver(dive.SourceDockerArchive)
img, err := resolver.Fetch(context.Background(), "/path/to/nginx.tar")
if err != nil {
// handle error
}
log.Printf("Loaded archive image %s with %d layers", img.ID, len(img.Layers))
Extracting Files from Layers
Use the ContentReader interface to pull specific files from image layers without loading the entire filesystem:
resolver, _ := dive.GetImageResolver(dive.SourceDockerEngine)
err := resolver.Extract(context.Background(), "nginx:latest", "layerID", "/etc/nginx/nginx.conf")
if err != nil {
// handle error
}
Summary
- The core
Resolverinterface is defined indive/image/resolver.go, requiringName(),Fetch(),Build(), andExtract()methods - Docker Engine resolution is implemented in
dive/image/docker/engine_resolver.go, handling live daemon interactions, host detection, and image pulling - Docker Archive resolution lives in
dive/image/docker/archive_resolver.gofor loadingdocker savetar files - The factory function
GetImageResolver()indive/get_image_resolver.gomaps source strings to concrete implementations viaDeriveImageSource()
Frequently Asked Questions
What file contains the Resolver interface definition?
The Resolver interface and the embedded ContentReader interface are both defined in dive/image/resolver.go. This file establishes the contract that all image resolution implementations—including Docker, Podman, and containerd—must satisfy to integrate with Dive's analysis engine.
How does Dive choose between the engine and archive resolvers?
Dive uses the DeriveImageSource() function in dive/get_image_resolver.go to parse the input string. If the string starts with docker:// or lacks a protocol prefix (defaulting to Docker), it returns SourceDockerEngine. If the path points to a .tar file, it returns SourceDockerArchive. The GetImageResolver() factory then instantiates the appropriate struct from the dive/image/docker package.
Can I use Dive's resolvers in my own Go code?
Yes. Import github.com/wagoodman/dive/dive and github.com/wagoodman/dive/dive/image into your project. Use dive.DeriveImageSource() to parse image references, then call dive.GetImageResolver() to obtain a resolver implementing the image.Resolver interface. This allows you to programmatically fetch images or extract files from specific layers without invoking the Dive CLI directly.
Where does the engine resolver handle Docker host detection?
Docker host detection occurs in dive/image/docker/engine_resolver.go within the determineDockerHost() helper function. This function inspects environment variables like DOCKER_HOST and platform-specific contexts to determine the correct API endpoint before constructing the Docker client used for ImageInspect and ImageSave operations.
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 →