Top Related Projects
A tool for exploring each layer in a docker image
Find vulnerabilities, misconfigurations, secrets, SBOM in containers, Kubernetes, code repositories, clouds and more
A vulnerability scanner for container images and filesystems
CLI tool and library for generating a Software Bill of Materials from container images and filesystems
Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start
Dockerfile linter, validate inline bash, written in Haskell
Quick Overview
Container-diff is an open-source tool developed by Google for analyzing and comparing container images. It allows users to inspect the contents of container images, identify differences between images, and generate reports on various aspects such as file system changes, package manager differences, and more.
Pros
- Supports multiple image formats, including Docker and OCI
- Provides detailed comparisons across various analyzers (e.g., file system, apt, pip)
- Offers both CLI and library usage for integration into other tools
- Generates human-readable and machine-parseable output formats
Cons
- Limited to comparing container images, not running containers
- May have performance issues with very large images
- Requires local access to images or ability to pull from registries
- Some analyzers are specific to certain operating systems or package managers
Getting Started
To install container-diff, you can use one of the following methods:
# Using curl (Linux)
curl -LO https://storage.googleapis.com/container-diff/latest/container-diff-linux-amd64 && chmod +x container-diff-linux-amd64 && sudo mv container-diff-linux-amd64 /usr/local/bin/container-diff
# Using Homebrew (macOS)
brew install container-diff
# Using go get (requires Go installed)
go get -u github.com/GoogleContainerTools/container-diff
To compare two images:
container-diff analyze daemon://image1 remote://gcr.io/repo/image:tag --type=file --type=apt --type=pip
This command compares a local Docker image (image1
) with a remote image from Google Container Registry, analyzing file system differences, apt packages, and pip packages.
Competitor Comparisons
A tool for exploring each layer in a docker image
Pros of dive
- Provides an interactive UI for exploring Docker image layers
- Offers real-time analysis of image efficiency and wasted space
- Allows for easy navigation through the filesystem of each layer
Cons of dive
- Focused solely on Docker image analysis, lacking broader container comparison features
- May require more system resources due to its interactive nature
- Limited to local image analysis, without built-in remote registry support
Code comparison
container-diff:
container-diff analyze daemon://image1 daemon://image2 --type=file --type=size
dive:
dive <image_name>
Key differences
- Purpose: container-diff is designed for comparing multiple containers, while dive specializes in analyzing individual Docker images.
- User Interface: dive offers an interactive TUI, whereas container-diff provides command-line output.
- Functionality: container-diff supports various analysis types (file, size, apt, etc.), while dive focuses on layer-by-layer exploration and efficiency analysis.
- Integration: container-diff can analyze images from multiple sources (local, remote, tar), while dive primarily works with local images.
Both tools serve different purposes in the container ecosystem, with container-diff excelling at broad comparisons and dive offering deep, interactive analysis of individual images.
Find vulnerabilities, misconfigurations, secrets, SBOM in containers, Kubernetes, code repositories, clouds and more
Pros of Trivy
- Comprehensive vulnerability scanning for containers, filesystems, and Git repositories
- Supports multiple operating systems and package managers
- Regularly updated vulnerability database with fast scanning speeds
Cons of Trivy
- Focuses primarily on vulnerability scanning, lacking some container comparison features
- May produce more verbose output, requiring additional parsing for specific use cases
Code Comparison
Trivy:
trivy image alpine:3.10
container-diff:
container-diff analyze alpine:3.10 --type=apt --type=pip --type=size
Key Differences
Trivy is primarily a vulnerability scanner with broad support for various targets, while container-diff focuses on analyzing and comparing container images. Trivy excels in security-focused tasks, whereas container-diff provides more detailed information about container contents and differences between images.
Trivy's strength lies in its comprehensive vulnerability database and support for multiple ecosystems, making it ideal for security-conscious teams. container-diff, on the other hand, offers more granular control over container analysis and comparison, which can be beneficial for debugging and optimization tasks.
Both tools serve different primary purposes but can be complementary in a container management workflow, with Trivy handling security concerns and container-diff providing detailed container insights.
A vulnerability scanner for container images and filesystems
Pros of grype
- Focused specifically on vulnerability scanning, providing more comprehensive security analysis
- Regularly updated vulnerability database, ensuring detection of the latest known vulnerabilities
- Supports scanning of various artifact types, including container images, filesystems, and archives
Cons of grype
- Limited to vulnerability scanning, lacking container comparison features
- May require additional tools for complete container analysis and management
Code comparison
grype:
grype <image_name>
container-diff:
container-diff analyze <image1> <image2> --type=file --type=size
Key differences
- Purpose: grype focuses on vulnerability scanning, while container-diff is designed for comparing container images
- Functionality: container-diff offers broader comparison features, including file system, size, and package differences
- Output: grype provides detailed vulnerability reports, whereas container-diff generates comparison results between containers
Use cases
- grype: Ideal for security-focused teams prioritizing vulnerability detection in containers and other artifacts
- container-diff: Better suited for developers and DevOps teams needing to analyze differences between container versions or implementations
Both tools serve different primary purposes, with grype excelling in security analysis and container-diff offering comprehensive container comparison capabilities. The choice between them depends on specific project requirements and team focus.
CLI tool and library for generating a Software Bill of Materials from container images and filesystems
Pros of syft
- More comprehensive software bill of materials (SBOM) generation
- Supports a wider range of output formats (JSON, SPDX, CycloneDX)
- Active development and frequent updates
Cons of syft
- Focused primarily on SBOM generation, less emphasis on image comparison
- May have a steeper learning curve for users new to SBOM concepts
Code comparison
syft:
syft packages alpine:latest
container-diff:
container-diff analyze alpine:latest --type=apt --type=pip --json
Key differences
- Purpose: syft is primarily for SBOM generation, while container-diff focuses on image comparison and analysis
- Output: syft provides more detailed package information, container-diff offers a simpler diff-style output
- Ecosystem: syft is part of the larger Anchore ecosystem, container-diff is a standalone Google tool
Use cases
- Use syft for comprehensive SBOM generation and security analysis
- Use container-diff for quick image comparisons and identifying differences between container images
Both tools have their strengths, and the choice depends on specific requirements and use cases in container image analysis and security workflows.
Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start
Pros of dockle
- Focuses on security and best practices for Docker images
- Provides CIS benchmarks and security checks
- Offers a simple, user-friendly output format
Cons of dockle
- Limited to Docker image analysis
- Doesn't provide detailed diff information between images
Code comparison
dockle:
dockle [OPTIONS] IMAGE_NAME
container-diff:
container-diff diff [OPTIONS] IMAGE1 IMAGE2
Key differences
- Purpose: dockle is primarily a security scanner for Docker images, while container-diff focuses on comparing differences between container images.
- Functionality: dockle checks for vulnerabilities and best practices, whereas container-diff analyzes file system differences, package manager differences, and more.
- Output: dockle provides a concise security report, while container-diff offers detailed comparison results.
Use cases
-
Use dockle for:
- Checking Docker image security
- Ensuring compliance with best practices
- Quick vulnerability scans
-
Use container-diff for:
- Comparing two different container images
- Analyzing changes between image versions
- Detailed diff reports on file systems and installed packages
Both tools serve different purposes in the container ecosystem, with dockle focusing on security and container-diff on image comparison.
Dockerfile linter, validate inline bash, written in Haskell
Pros of hadolint
- Focused specifically on Dockerfile linting, providing more specialized and in-depth analysis
- Integrates well with CI/CD pipelines and popular code editors
- Offers a comprehensive set of rules based on best practices for Dockerfile creation
Cons of hadolint
- Limited to Dockerfile analysis, unlike container-diff which can compare container images
- May require more setup and configuration for advanced use cases
- Does not provide runtime analysis or comparison of container contents
Code Comparison
hadolint example:
hadolint Dockerfile
container-diff example:
container-diff analyze --type=file,size,history image1 image2
Key Differences
- Purpose: hadolint focuses on Dockerfile linting, while container-diff compares container images
- Scope: hadolint is specialized for Dockerfile analysis, container-diff offers broader container comparison capabilities
- Usage: hadolint is typically used during development, container-diff is often used for debugging and optimization
Use Cases
- Use hadolint for ensuring Dockerfile best practices and catching potential issues early in development
- Use container-diff for comparing different versions of container images, identifying changes, and optimizing container size
Both tools serve different purposes in the container development lifecycle and can be used complementarily to improve overall container quality and efficiency.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
This project is archived.
- If you wish to continue maintaining it, you may fork and continue development on that fork.
- If you are looking for an alternative, try diffoci
What is container-diff?
container-diff is a tool for analyzing and comparing container images. container-diff can examine images along several different criteria, including:
- Docker Image History
- Image file system
- Image size
- Apt packages
- RPM packages
- pip packages
- npm packages
These analyses can be performed on a single image, or a diff can be performed on two images to compare. The tool can help users better understand what is changing inside their images, and give them a better look at what their images contain.
NOTE: container-diff is a Google project, but is not currently being officially supported by Google and is in maintenance mode. However, contributions are still welcome and encouraged!
Installation
macOS
curl -LO https://storage.googleapis.com/container-diff/latest/container-diff-darwin-amd64 && \
sudo install container-diff-darwin-amd64 /usr/local/bin/container-diff
Linux
curl -LO https://storage.googleapis.com/container-diff/latest/container-diff-linux-amd64 && \
sudo install container-diff-linux-amd64 /usr/local/bin/container-diff
OR, if you want to avoid using sudo:
curl -LO https://storage.googleapis.com/container-diff/latest/container-diff-linux-amd64 && \
mkdir -p "$HOME/bin" && export PATH="$PATH:$HOME/bin" && \
install container-diff-linux-amd64 $HOME/bin/container-diff
There is also an Arch Linux package. You can install by running:
pacman -S container-diff
Windows
Download the container-diff-windows-amd64.exe file, rename it to container-diff.exe
and add it to your path
Quickstart
To use container-diff analyze
to perform analysis on a single image, you need one Docker image (in the form of an ID, tarball, or URL from a repo). Once you have that image, you can run any of the following analyzers:
container-diff analyze <img> [Run default analyzers]
container-diff analyze <img> --type=history [History]
container-diff analyze <img> --type=file [File System]
container-diff analyze <img> --type=size [Size]
container-diff analyze <img> --type=rpm [RPM]
container-diff analyze <img> --type=pip [Pip]
container-diff analyze <img> --type=apt [Apt]
container-diff analyze <img> --type=node [Node]
container-diff analyze <img> --type=apt --type=node [Apt and Node]
# --type=<analyzer1> --type=<analyzer2> --type=<analyzer3>,...
By default, with no --type
flag specified, container-diff will run image size analysis.
To use container-diff to perform a diff analysis on two images, you need two Docker images (in the form of an ID, tarball, or URL from a repo). Once you have those images, you can run any of the following differs:
container-diff diff <img1> <img2> [Run default differs]
container-diff diff <img1> <img2> --type=history [History]
container-diff diff <img1> <img2> --type=file [File System]
container-diff diff <img1> <img2> --type=size [Size]
container-diff diff <img1> <img2> --type=rpm [RPM]
container-diff diff <img1> <img2> --type=pip [Pip]
container-diff diff <img1> <img2> --type=apt [Apt]
container-diff diff <img1> <img2> --type=node [Node]
You can similarly run many analyzers at once:
container-diff diff <img1> <img2> --type=history --type=apt --type=node
To view the diff of an individual file in two different images, you can use the filename flag in conjuction with the file system diff analyzer.
container-diff diff <img1> <img2> --type=file --filename=/path/to/file
Image Sources
container-diff supports Docker images located in both a local Docker daemon and a remote registry. To explicitly specify a local image, use the daemon://
prefix on the image name; similarly, for an explicitly remote image, use the remote://
prefix.
container-diff diff daemon://modified_debian:latest remote://gcr.io/google-appengine/debian8:latest
Additionally, tarballs can be provided to the tool directly. Make sure your file has a valid tar extension (.tar, .tar.gz, .tgz).
Note: container-diff does not support references images by Docker ID directly. If your image only has an ID in your local Docker daemon, you'll need to tag it using docker tag
before using it with container-diff.
Authentication
Container-diff supports docker-credential-helpers for authentication when using a registry as an image source. Make sure you have your credential helper configured before using container-diff, and it should work automatically.
For the Google Container Registry, make sure you have the docker-credential-gcr
binary configured and on your path, following these instructions.
Other Flags
To get a JSON version of the container-diff output add a -j
or --json
flag.
container-diff diff --type=file --json gcr.io/gcp-runtimes/multi-base gcr.io/gcp-runtimes/multi-modified
To order files and packages by size (in descending order) when performing file system or package analyses/diffs, add a -o
or --order
flag.
container-diff analyze remote://gcr.io/gcp-runtimes/multi-modified --type=pip --order
To suppress output to stderr, add a -q
or --quiet
flag.
container-diff analyze file1.tar --type=file --quiet
Analysis Result Format
JSON output for analysis results is in the following format:
{
"Image": "foo",
"AnalyzeType": "Apt",
"Analysis": {}
}
The possible contents of the Analysis
field are detailed below.
History Analysis
The history analyzer outputs a list of strings representing descriptions of how an image layer was created. This is the only analyzer that requires a working Docker daemon to run.
File System Analysis
The file system analyzer outputs a list of file system contents, including names, paths, and sizes.
Package Analysis
Package analyzers such as pip, apt, and node inspect the packages installed within the image provided. All package analyses leverage the PackageOutput
struct, which contains the version and size for a given package instance (and a potential installation path for a specific instance of a package where multiple versions are allowed to be installed), as detailed below:
type PackageOutput struct {
Name string
Path string
Version string
Size int64
}
Single Version Package Analysis
Single version package analyzers (apt) have the following output structure: []PackageOutput
Here, the Path
field is omitted because there is only one instance of each package.
Multi Version Package Analysis
Multi version package analyzers (pip, node) have the following output structure: []PackageOutput
Here, the Path
field is included because there may be more than one instance of each package, and thus the path exists to pinpoint where the package exists in case additional investigation into the package instance is desired.
Diff Result Format
JSON output for diff results is in the following format:
{
"Image1": "foo",
"Image2": "bar",
"DiffType": "Apt",
"Diff": {}
}
The possible structures of the Diff
field are detailed below.
History Diff
The history differ has the following output structure:
type HistDiff struct {
Adds []string
Dels []string
}
File System Diff
The file system differ has the following output structure:
type DirDiff struct {
Adds []string
Dels []string
Mods []string
}
Package Diffs
Package differs such as pip, apt, and node inspect the packages contained within the images provided. All packages differs currently leverage the PackageInfo struct which contains the version and size for a given package instance, as detailed below:
type PackageInfo struct {
Version string
Size string
}
Single Version Package Diffs
Single version differs (apt) have the following JSON output structure:
type PackageDiff struct {
Packages1 []PackageOutput
Packages2 []PackageOutput
InfoDiff []Info
}
Packages1 and Packages2 detail which packages exist uniquely in Image1 and Image2, respectively, with package name, version and size info. InfoDiff contains a list of Info structs, each of which contains the package name (which occurred in both images but had a difference in size or version), and the PackageInfo struct for each package instance.
Multi Version Package Diffs
The multi version differs (pip, node) support processing images which may have multiple versions of the same package. Below is the json output structure:
type MultiVersionPackageDiff struct {
Packages1 []PackageOutput
Packages2 []PackageOutput
InfoDiff []MultiVersionInfo
}
Packages1 and Packages2 detail which packages exist uniquely in Image1 and Image2, respectively, with package name, installation path, version and size info. InfoDiff here is exanded to allow for multiple versions to be associated with a single package. In this case, a package of the same name is considered to differ between two images when there exist one or more instances of it installed in one image but not the other (i.e. have a unique version and/or size).
type MultiVersionInfo struct {
Package string
Info1 []PackageInfo
Info2 []PackageInfo
}
User Customized Output
Users can customize the format of the output of diffs with the--format
flag. The flag takes a Go template string, which specifies the format the diff should be output in. This template string uses the structs described above, depending on the differ used, to format output. The default template strings container-diff uses can be found here.
An example using the pip package analyzer is shown below, in which only package names are printed (some are repeated because of version differences).
$ container-diff analyze gcr.io/google-appengine/python:latest --type=pip --format='
-----{{.AnalyzeType}}-----
Packages found in {{.Image}}:{{if not .Analysis}} None{{else}}
{{range .Analysis}}{{"\n"}}{{.Name}}{{end}}
{{end}}
'
Retrieving image gcr.io/google-appengine/python:latest from source Cloud Registry
Retrieving analyses
-----Pip-----
Packages found in gcr.io/google-appengine/python:latest:
chardet
colorama
html5lib
mercurial
pip
pip
pip
requests
setuptools
setuptools
setuptools
six
urllib3
virtualenv
wheel
wheel
Known issues
To run container-diff using image IDs, docker must be installed. Tarballs provided directly to the tool must be in the Docker format (i.e. have a manifest.json file for layer ordering)
Example Run
$ container-diff diff gcr.io/google-appengine/python:2017-07-21-123058 gcr.io/google-appengine/python:2017-06-29-190410 --type=apt --type=node --type=pip
-----AptDiffer-----
Packages found only in gcr.io/google-appengine/python:2017-07-21-123058: None
Packages found only in gcr.io/google-appengine/python:2017-06-29-190410: None
Version differences:
PACKAGE IMAGE1 (gcr.io/google-appengine/python:2017-07-21-123058) IMAGE2 (gcr.io/google-appengine/python:2017-06-29-190410)
-libgcrypt20 1.6.3-2 deb8u4, 998K 1.6.3-2 deb8u3, 1002K
-----NodeDiffer-----
Packages found only in gcr.io/google-appengine/python:2017-07-21-123058: None
Packages found only in gcr.io/google-appengine/python:2017-06-29-190410: None
Version differences: None
-----PipDiffer-----
Packages found only in gcr.io/google-appengine/python:2017-07-21-123058: None
Packages found only in gcr.io/google-appengine/python:2017-06-29-190410: None
Version differences: None
$ container-diff diff file1.tar file2.tar --type=file --filename=go/src/app/file.txt
Starting diff on images file1.tar and file2.tar, using differs: [file]
Retrieving image file2.tar from source Tar Archive
Retrieving image file1.tar from source Tar Archive
Computing diffs
-----File-----
These entries have been added to file1.tar: None
These entries have been deleted from file1.tar: None
These entries have been changed between file1.tar and file2.tar:
FILE SIZE1 SIZE2
/go/src/app/file.txt 30B 30B
Computing filename diffs
-----Diff of go/src/app/file.txt-----
--- file1.tar
+++ file2.tar
@@ -1 +1 @@
-This is file 1
This is a file
+This is file 2
This is a file
Example Run with JSON post-processing
The following example demonstrates how one might selectively display the output of their diff, such that version differences are ignored and only package absence/presence is displayed and the packages present in only one image are sorted by size in descending order. A small piece of the JSON being post-processed can be seen below:
[
{
"DiffType": "AptDiffer",
"Diff": {
"Image1": "gcr.io/gcp-runtimes/multi-base",
"Packages1": {},
"Image2": "gcr.io/gcp-runtimes/multi-modified",
"Packages2": {
"dh-python": {
"Version": "1.20141111-2",
"Size": "277"
},
"libmpdec2": {
"Version": "2.4.1-1",
"Size": "275"
}
}
}
}
]
The post-processing script used for this example is below:
import sys, json
def main():
data = json.loads(sys.stdin.read())
img1packages = []
img2packages = []
for differ in data:
diff = differ['Diff']
if len(diff['Packages1']) > 0:
for package in diff['Packages1']:
Size = package['Size']
img1packages.append((str(package), int(str(Size))))
if len(diff['Packages2']) > 0:
for package in diff['Packages2']:
Size = package['Size']
img2packages.append((str(package), int(str(Size))))
img1packages = reversed(sorted(img1packages, key=lambda x: x[1]))
img2packages = reversed(sorted(img2packages, key=lambda x: x[1]))
print "Only in image1\n"
for pkg in img1packages:
print pkg
print "Only in image2\n"
for pkg in img2packages:
print pkg
print
if __name__ == "__main__":
main()
Given the above python script to postprocess json output, you can produce the following behavior:
container-diff gcr.io/gcp-runtimes/multi-base gcr.io/gcp-runtimes/multi-modified -a -j | python pyscript.py
Only in image1
Only in image2
('libpython3.4-stdlib', 9484)
('python3.4-minimal', 4506)
('libpython3.4-minimal', 3310)
('python3.4', 336)
('dh-python', 277)
('libmpdec2', 275)
('python3-minimal', 96)
('python3', 36)
('libpython3-stdlib', 28)
Make your own differ
Feel free to develop your own analyzer leveraging the utils currently available. PRs are welcome!
Custom Analyzer Quickstart
In order to quickly make your own analyzer, follow these steps:
- Determine if you can use existing analyzing or diffing tools. If you can make use of existing tools, you then need to construct the structs to feed into the tools by getting all of the packages for each image or the analogous quality to be analyzed. To determine if you can leverage existing tools, think through these questions:
- Are you trying to analyze packages?
- Yes: Does the relevant package manager support different versions of the same package on one image?
- Yes: Implement
getPackages
to collect all versions of all packages within an image in amap[string]map[string]util.PackageInfo
. UseGetMultiVersionMapDiff
to diff map objects. Seediffers/node_diff.go
ordiffers/pip_diff.go
for examples. - No: Implement
getPackages
to collect all versions of all packages within an image in amap[string]util.PackageInfo
. UseGetMapDiff
to diff map objects. Seediffers/apt_diff.go
.
- Yes: Implement
- No: Look to History and File System differs as models for diffing.
- Yes: Does the relevant package manager support different versions of the same package on one image?
- Write your analyzer driver in the
differs
directory, such that you have a struct for your analyzer type and two methods for that analyzer:Analyze
for single image analysis andDiff
for comparison between two images:
type YourAnalyzer struct {}
func (a YourAnalyzer) Analyze(image util.Image) (util.Result, error) {...}
func (a YourAnalyzer) Diff(image1, image2 util.Image) (util.Result, error) {...}
The image arguments passed to your analyzer contain the path to the unpacked tar representation of the image, as well as certain configuration information (e.g. environment variables upon image creation and image history).
If using existing package tools, you should create the appropriate structs (e.g. SingleVersionPackageAnalyzeResult
or SingleVersionPackageDiffResult
) to analyze or diff. Otherwise, create your own structs which should yield information to fill an AnalyzeResult or DiffResult as the return type for Analyze() and Diff(), respectively, and should implement the Result
interface, as in the next step.
- Create a struct following the
Result
interface by implementing the following two methods.
type Result interface {
OutputStruct() interface{}
OutputText(resultType string, format string) error
}
This is where you define how your analyzer should output for a human readable format (OutputText
) and as a struct which can then be written to a .json
file. See util/diff_output_utils.go
and util/analyze_output_utils.go
.
- Add your analyzer to the
Analyzers
map indiffers/differs.go
with the corresponding Analyzer struct as the value.
Top Related Projects
A tool for exploring each layer in a docker image
Find vulnerabilities, misconfigurations, secrets, SBOM in containers, Kubernetes, code repositories, clouds and more
A vulnerability scanner for container images and filesystems
CLI tool and library for generating a Software Bill of Materials from container images and filesystems
Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start
Dockerfile linter, validate inline bash, written in Haskell
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot