Mastering Your Docker Environment: A Deep Dive into Checking and Listing Images
Docker has revolutionized the way we build, ship, and run applications. Its containerization technology provides consistency across environments, simplifies deployment, and optimizes resource utilization. At the heart of Docker are Docker images – the blueprints from which containers are created. As your development workflow or production environment scales, managing these images becomes crucial. You might accumulate dozens or even hundreds of images over time, consuming valuable disk space and potentially introducing complexity or security risks if not properly managed.
Therefore, knowing how to effectively check, list, inspect, and filter your Docker images is a fundamental skill for any Docker user, from beginners to seasoned DevOps engineers. It allows you to maintain a clean system, understand your image inventory, troubleshoot issues, and ensure you’re using the correct and most secure image versions.
This comprehensive guide will delve deep into the various commands and techniques available in Docker for listing and examining your images. We will explore the primary command, docker image ls
, in extensive detail, covering its basic usage, options, powerful filtering capabilities, and custom formatting features. We’ll also look at related commands like docker image inspect
for detailed metadata, docker image history
for layer analysis, and docker image prune
for cleanup. By the end of this article, you’ll have a thorough understanding of how to navigate and manage your Docker image landscape effectively.
Table of Contents
- Understanding Docker Images: The Foundation
- What is a Docker Image?
- The Layered Filesystem
- Images vs. Containers
- Why Image Management Matters
- The Core Command:
docker image ls
(anddocker images
)- Basic Usage: Getting Started
- Understanding the Default Output Columns
REPOSITORY
TAG
IMAGE ID
CREATED
SIZE
(and what it really means)
- Common Options and Flags
- Listing All Images (including intermediate layers):
-a
or--all
- Quiet Mode (Image IDs only):
-q
or--quiet
- Showing Full Image IDs:
--no-trunc
- Displaying Image Digests:
--digests
- Listing All Images (including intermediate layers):
- Advanced Filtering with
docker image ls --filter
- Filtering Basics: The
-f
or--filter
flag - Filtering by Dangling Status (
dangling=true
/false
) - Filtering by Label (
label=<key>
orlabel=<key>=<value>
) - Filtering by Creation Time (
before=<image>
orsince=<image>
) - Filtering by Reference (Name/Tag Patterns) (
reference=<pattern>
) - Combining Multiple Filters
- Practical Filtering Examples
- Filtering Basics: The
- Customizing Output with
docker image ls --format
- Introduction to Go Templates in Docker Formatting
- Basic Formatting Placeholders (e.g.,
{{.ID}}
,{{.Repository}}
,{{.Tag}}
) - Creating Custom Table Outputs
- Formatting as JSON
- Using Functions within Templates (e.g.,
json
,println
) - Useful Formatting Recipes
- Beyond Listing: Inspecting Image Details
docker image inspect <image>
: The Deep Dive- Understanding the JSON Output Structure
- Extracting Specific Information (Layers, Environment Variables, Entrypoint, Cmd, Labels, Architecture, OS)
- Using
--format
withdocker image inspect
- Understanding Image Construction:
docker image history
- Viewing Image Layers and Build Steps
- Interpreting the Output
- Identifying Large Layers
- Security Considerations
- Cleaning Up: Managing Your Image Inventory
- Identifying Unused Images
- The Concept of Dangling Images
- Using
docker image prune
- Pruning Dangling Images
- Pruning All Unused Images (
-a
) - Filtering Prune Operations (
--filter
) - Forcing Removal (
-f
)
- Practical Scenarios and Workflows
- Finding Large Images Consuming Disk Space
- Identifying Images Older Than a Certain Date
- Listing Images for a Specific Application Using Labels
- Scripting Image Cleanup Tasks
- Verifying Image Configuration Before Deployment
- Best Practices for Image Management
- Use Meaningful Tags
- Regularly Prune Unused Images
- Leverage Labels for Organization
- Be Mindful of Image Size
- Scan Images for Vulnerabilities (Brief Mention)
- Conclusion
1. Understanding Docker Images: The Foundation
Before diving into the commands, let’s briefly recap what Docker images are and why managing them is essential.
What is a Docker Image?
Think of a Docker image as a blueprint or a template for creating Docker containers. It’s a lightweight, standalone, executable package that includes everything needed to run a piece of software: the code, runtime, system tools, system libraries, and settings. Images are immutable; once built, they don’t change. If you need to make changes, you typically build a new image based on the old one with the modifications added as a new layer.
The Layered Filesystem
Docker images are built using a layered filesystem (often Union File System variants like OverlayFS). Each instruction in a Dockerfile (e.g., RUN
, COPY
, ADD
) typically creates a new layer in the image. These layers are stacked on top of each other. This layered approach has several benefits:
- Efficiency: Layers are cached. If you change a later step in your Dockerfile, Docker only rebuilds the changed layer and subsequent layers, reusing unchanged layers from the cache.
- Sharing: Different images can share common base layers. For example, multiple Python application images might share the same base Python runtime layer, saving disk space and download time.
Images vs. Containers
It’s crucial to understand the distinction:
- Image: The immutable blueprint/template (e.g.,
python:3.9-slim
). - Container: A runnable instance of an image. It adds a thin writable layer on top of the image layers. You can start, stop, move, and delete containers. Multiple containers can be run from the same image.
Why Image Management Matters
As you pull images from registries like Docker Hub or build your own custom images, your local storage fills up. Effective image management is vital for:
- Disk Space: Images, especially those with large base layers or many dependencies, can consume significant disk space. Regularly listing and cleaning up unused images is essential.
- Clarity & Organization: Knowing exactly which images (and which versions/tags) you have helps avoid confusion and ensures you’re using the intended blueprints for your containers.
- Security: Old images might contain unpatched vulnerabilities. Listing images allows you to identify potentially outdated versions that need updating or removal.
- Troubleshooting: When diagnosing container issues, examining the image’s history or metadata can provide valuable clues.
- Workflow Efficiency: Quickly finding the right image or identifying intermediate build layers speeds up development and deployment processes.
2. The Core Command: docker image ls
(and docker images
)
The primary command for listing images stored locally on your Docker host is docker image ls
.
You might also encounter the older, shorter alias docker images
. Functionally, docker images
is identical to docker image ls
. Docker introduced the newer syntax (docker <object> <verb>
, e.g., docker image ls
, docker container run
) for better organization and consistency across its command-line interface (CLI). While docker images
still works perfectly fine and is widely used, it’s generally recommended to adopt the newer docker image ls
syntax for consistency and future compatibility. Throughout this guide, we will primarily use docker image ls
, but remember that docker images
can be used interchangeably in most contexts.
Basic Usage: Getting Started
Simply running the command without any options will list the most relevant images on your system:
bash
docker image ls
or
bash
docker images
Understanding the Default Output Columns
The default output provides a concise overview of your top-level images (images with a repository name and tag, or recently built images without a tag):
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest a9dee87a005e 3 weeks ago 77.8MB
python 3.9-slim f1a35a6d4d5e 4 weeks ago 114MB
nginx stable-alpine c316d156e457 2 months ago 23.5MB
my-app v1.2 b8fca9a0e9c7 2 days ago 350MB
<none> <none> d1ecca7a9a0a 5 hours ago 345MB
Let’s break down each column:
REPOSITORY
: This is the name of the image repository. It often indicates the base application or service (e.g.,ubuntu
,nginx
,python
). For images pulled from registries like Docker Hub, it might include the username or organization (e.g.,bitnami/redis
). If an image was built locally without being tagged with a repository name, or if its tag was overwritten by a newer build of the same name:tag, it might show<none>
.TAG
: Tags are labels used to differentiate versions or variants of an image within a repository (e.g.,latest
,3.9-slim
,stable-alpine
,v1.2
). Thelatest
tag is a convention, often pointing to the most recent stable build, but its meaning is defined by the repository maintainer – it doesn’t automatically mean the newest version exists. An image can have multiple tags pointing to the same underlying Image ID. If an image lacks a tag (often seen in intermediate build layers or images where the tag was removed), it will display<none>
. Images listed as<none>:<none>
are often referred to as “dangling” images (more on this later).IMAGE ID
: This is a unique identifier for the image, represented as a 64-character hexadecimal SHA256 hash of the image’s configuration and layer content. By default, Docker displays a truncated, 12-character short ID for brevity. This ID is the definitive way to refer to a specific image, regardless of its tags.CREATED
: This timestamp indicates when the image was built or, more accurately, when the image’s configuration manifest was created. It’s usually displayed in a human-readable relative format (e.g., “3 weeks ago”, “5 hours ago”).SIZE
: This shows the virtual size of the image. This is a crucial point: The size reported is the sum of the sizes of the image’s unique layers plus the sizes of any shared base layers. This means the total disk space consumed by all your images might be less than the sum of the sizes reported bydocker image ls
, thanks to layer sharing. For example, if you have ten different application images all based onubuntu:latest
, the base Ubuntu layers are only stored once on disk, but their size contributes to the reported size of each of the ten images.
Common Options and Flags
The basic docker image ls
command can be modified with several useful flags:
Listing All Images (including intermediate layers): -a
or --all
By default, docker image ls
hides intermediate image layers that were created during builds but don’t have a user-assigned repository and tag. These layers are often dependencies for other tagged images. To see all images, including these intermediate ones, use the -a
or --all
flag:
bash
docker image ls -a
This output will often include many entries with <none>
in both the REPOSITORY
and TAG
columns. These aren’t necessarily all “dangling” (unused) if they are parent layers for other tagged images.
Quiet Mode (Image IDs only): -q
or --quiet
Sometimes, you only need the Image IDs, perhaps for scripting purposes (e.g., passing IDs to another command like docker image rm
or docker image inspect
). The -q
or --quiet
flag suppresses the header and all columns except the Image ID:
bash
docker image ls -q
Output:
a9dee87a005e
f1a35a6d4d5e
c316d156e457
b8fca9a0e9c7
d1ecca7a9a0a
Combined with -a
, docker image ls -aq
will list the IDs of all images, including intermediate ones.
Showing Full Image IDs: --no-trunc
The default 12-character short Image ID is usually sufficient for identification, but occasionally you might need the full 64-character SHA256 hash. The --no-trunc
flag prevents truncation of the output, primarily affecting the IMAGE ID
column:
bash
docker image ls --no-trunc
Output (IMAGE ID column shown):
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest sha256:a9dee87a005e8940f0a113a601b1a973a61f8786159f8065776a480689c17a3c 3 weeks ago 77.8MB
python 3.9-slim sha256:f1a35a6d4d5e0b0a0b6f6d3e0d8e0c7f8e1b8a1b7f8e1b8a1b7f8e1b8a1b7f8e 4 weeks ago 114MB
...
Note: The sha256:
prefix clearly indicates the hashing algorithm used for the ID.
Displaying Image Digests: --digests
While tags are mutable (e.g., ubuntu:latest
can point to different Image IDs over time), an image digest is an immutable, content-addressable identifier (a SHA256 hash of the image manifest). It guarantees you are referring to the exact same image content. The --digests
flag adds a DIGEST
column to the output:
bash
docker image ls --digests
Output:
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
ubuntu latest sha256:a1689773dac93539d4e1647a5e79c1acaa060581ff11e55c1511a3b3a4a5f6d9 a9dee87a005e 3 weeks ago 77.8MB
python 3.9-slim sha256:b123... f1a35a6d4d5e 4 weeks ago 114MB
nginx stable-alpine <none> c316d156e457 2 months ago 23.5MB
...
Note that locally built images might show <none>
in the DIGEST
column until they are pushed to a registry, as the digest is typically calculated and associated during the push process based on the image manifest. Images pulled from a registry usually have a digest. Using digests (repository@digest
) is the most reliable way to ensure you are using a specific, unchanging version of an image.
3. Advanced Filtering with docker image ls --filter
Listing all images is often overwhelming. Docker provides a powerful filtering mechanism using the -f
or --filter
flag. You can apply one or more filters to narrow down the list based on specific criteria.
Filtering Basics: The -f
or --filter
flag
The syntax is docker image ls --filter <key>=<value>
. You can repeat the --filter
flag multiple times to apply several conditions (these conditions are usually combined with an AND logic).
“`bash
General syntax
docker image ls –filter key=value
Example: Filter by label
docker image ls –filter label=maintainer=devteam
Example: Multiple filters (images created since ‘myimage:latest’ AND dangling)
docker image ls –filter since=myimage:latest –filter dangling=true
“`
Filtering by Dangling Status (dangling=true
/false
)
Dangling images are layers that are no longer referenced by any tagged image. They often result from rebuilding an image with the same name and tag – the old image layers become dangling. These are usually safe to remove to reclaim disk space.
-
List only dangling images:
bash
docker image ls --filter dangling=true
# Alias: docker image ls -f dangling=true
This will typically show images with<none>
in both REPOSITORY and TAG. -
List only non-dangling images:
bash
docker image ls --filter dangling=false
This usually approximates the defaultdocker image ls
output but explicitly excludes any images Docker considers dangling.
Filtering by Label (label=<key>
or label=<key>=<value>
)
Images can be built with metadata labels (using the LABEL
instruction in the Dockerfile). These are key-value pairs useful for organization, automation, or providing information.
-
List images with a specific label key (regardless of value):
bash
# Find images that have a 'com.example.project' label
docker image ls --filter label=com.example.project -
List images with a specific label key and value:
“`bash
# Find images with the label ‘stage=production’
docker image ls –filter label=stage=productionFind images maintained by ‘[email protected]’
docker image ls –filter [email protected]
“`
Filtering by Creation Time (before=<image>
or since=<image>
)
You can filter images based on their creation time relative to another image. The reference image can be specified by its ID, name, or name:tag.
-
List images created before a specific image:
“`bash
# List images created before ‘my-app:v1.2’
docker image ls –filter before=my-app:v1.2List images created before image ID ‘b8fca9a0e9c7’
docker image ls –filter before=b8fca9a0e9c7
“` -
List images created since a specific image:
“`bash
# List images created since ‘my-app:v1.0’
docker image ls –filter since=my-app:v1.0List images created since image ID ‘abcdef123456’
docker image ls –filter since=abcdef123456
“`
This is useful for finding newer versions or images built after a certain baseline.
Filtering by Reference (Name/Tag Patterns) (reference=<pattern>
)
This filter allows you to list images whose repository name and/or tag match a given pattern. It supports standard shell globbing characters like *
(matches any sequence of characters) and ?
(matches any single character).
-
List all images for a specific repository:
bash
# List all 'nginx' images (nginx:latest, nginx:stable-alpine, etc.)
docker image ls --filter reference=nginx -
List images matching a pattern:
“`bash
# List all images ending with ‘-alpine’ tag in any repository
docker image ls –filter reference=’/-alpine’ # Needs quotes for the shell
docker image ls –filter reference=’:-alpine’ # Or use : separatorList all images in the ‘my-app’ repository
docker image ls –filter reference=’my-app’
List all ‘my-app’ images with tags starting with ‘v1.’
docker image ls –filter reference=’my-app:v1.?*’
List all official images (those without a ‘/’ in the repository name)
This is a bit tricky, might need external tools or formatting,
but you can approximate by filtering out common user/org patterns if known.
A simple pattern for images with potentially ‘latest’ tag or version tags:
docker image ls –filter reference=’:.‘ –filter reference=’:latest’ # Imperfect
List images from a specific user/organization on Docker Hub
docker image ls –filter reference=’bitnami/‘
``
**Important:** Remember to quote patterns containing wildcards (,
?`) to prevent your shell from expanding them before Docker sees them.
Combining Multiple Filters
As mentioned, you can use multiple --filter
flags. Docker applies them conjunctively (AND logic).
-
List dangling images created before
my-app:v1.0
:
bash
docker image ls --filter dangling=true --filter before=my-app:v1.0 -
List images with label
stage=testing
belonging to themy-api
repository:
bash
docker image ls --filter label=stage=testing --filter reference='my-api:*'
Practical Filtering Examples
- Find all Python 3 images:
docker image ls --filter reference='python:3.*'
- Find potentially old Nginx images (created before
nginx:stable
):docker image ls --filter reference='nginx' --filter before=nginx:stable
- Find all images tagged
latest
:docker image ls --filter reference='*:latest'
- Find images labeled for a specific project:
docker image ls --filter label=project=phoenix
Filtering is incredibly powerful for managing large numbers of images and automating tasks.
4. Customizing Output with docker image ls --format
While the default table output of docker image ls
is useful for humans, sometimes you need more control over what information is displayed and how it’s formatted, especially for scripting or reporting. The --format
flag allows you to specify a custom output format using Go templates.
Introduction to Go Templates in Docker Formatting
Go templates provide a simple way to structure text output. They work with placeholders enclosed in double curly braces {{ }}
. Inside the braces, you refer to data fields of the object being processed (in this case, a Docker image object). A dot (.
) represents the current object.
Basic Formatting Placeholders
Here are some common placeholders available for docker image ls --format
:
{{.ID}}
: The full Image ID (SHA256 hash).{{.Repository}}
: The image repository name.{{.Tag}}
: The image tag.{{.Digest}}
: The image digest (if available).{{.CreatedSince}}
: Human-readable time since creation (e.g., “3 weeks ago”).{{.CreatedAt}}
: Timestamp of creation in a standard format.{{.Size}}
: Human-readable image size (e.g., “77.8MB”).{{.VirtualSize}}
: Image size in bytes (less commonly used directly than.Size
).{{.Containers}}
: Number of containers using this image (often 0 unless specifically tracking).
Creating Custom Table Outputs
You can mimic the default table or create entirely new ones. Use tabs (\t
) to separate columns and newlines (\n
) to separate rows.
-
Display only Repository and Tag:
bash
docker image ls --format "{{.Repository}}:{{.Tag}}"
Output:
ubuntu:latest
python:3.9-slim
nginx:stable-alpine
my-app:v1.2
<none>:<none> -
Display Image ID, Repository, and Size:
bash
# Add a header manually using echo/printf or within the template
docker image ls --format "table {{.ID}}\t{{.Repository}}:{{.Tag}}\t{{.Size}}"
Output (thetable
keyword adds headers automatically):
IMAGE ID REPOSITORY:TAG SIZE
a9dee87a005e ubuntu:latest 77.8MB
f1a35a6d4d5e python:3.9-slim 114MB
c316d156e457 nginx:stable-alpine 23.5MB
b8fca9a0e9c7 my-app:v1.2 350MB
d1ecca7a9a0a <none>:<none> 345MB
Note: Thetable
directive automatically takes the first row of placeholders as headers. -
Custom Table with Specific Columns and Formatting:
bash
docker image ls --format "table {{.Repository}}\t{{.Tag}}\t{{.CreatedSince}}"
Output:
REPOSITORY TAG CREATED
ubuntu latest 3 weeks ago
python 3.9-slim 4 weeks ago
nginx stable-alpine 2 months ago
my-app v1.2 2 days ago
<none> <none> 5 hours ago
Formatting as JSON
You can output the image data as JSON, which is extremely useful for processing with tools like jq
or in automated scripts.
bash
docker image ls --format "{{json .}}"
Output (one JSON object per line):
json
{"Containers":0,"CreatedAt":"2023-10-15 10:00:00 +0000 UTC","CreatedSince":"3 weeks ago","Digest":"sha256:a168...","ID":"a9dee87a005e","Repository":"ubuntu","SharedSize":0,"Size":"77.8MB","Tag":"latest","UniqueSize":0,"VirtualSize":77800000}
{"Containers":0,"CreatedAt":"2023-10-01 12:00:00 +0000 UTC","CreatedSince":"4 weeks ago","Digest":"sha256:b123...","ID":"f1a35a6d4d5e","Repository":"python","SharedSize":0,"Size":"114MB","Tag":"3.9-slim","UniqueSize":0,"VirtualSize":114000000}
...
Using Functions within Templates
Go templates support simple functions. The json
function used above is one example. Another is println
.
“`bash
Print each repository:tag on a new line (similar to the earlier example)
docker image ls –format “{{println .Repository}}:{{.Tag}}”
“`
Useful Formatting Recipes
-
Get Image IDs and their sizes:
bash
docker image ls --format "{{.ID}}: {{.Size}}" -
List Repository:Tag@Digest for precise identification:
bash
# Filter out those without digests if needed
docker image ls --digests --format "{{.Repository}}:{{.Tag}}@{{.Digest}}" | grep -v '@<none>' -
CSV Output (ID, Repo, Tag, Size):
bash
docker image ls --format '"{{.ID}}","{{.Repository}}","{{.Tag}}","{{.Size}}"'
The --format
option transforms docker image ls
from a simple listing command into a flexible data extraction tool.
5. Beyond Listing: Inspecting Image Details
While docker image ls
provides a summary, sometimes you need detailed information about a specific image. This is where docker image inspect
comes in.
docker image inspect <image>
: The Deep Dive
This command takes one or more image IDs, names, or name:tag references and outputs detailed information about them in JSON format by default.
bash
docker image inspect python:3.9-slim
or
bash
docker image inspect f1a35a6d4d5e # Using Image ID
Understanding the JSON Output Structure
The output is an array of JSON objects, one for each image inspected. The object contains a wealth of information, including:
Id
: The full SHA256 Image ID.RepoTags
: List of repository:tag combinations associated with this image.RepoDigests
: List of repository@digest combinations.Parent
: ID of the parent image (if applicable).Comment
: Comment associated with the image (often empty).Created
: Timestamp of image creation.Container
: ID of the container used to build this image (if built from a container).ContainerConfig
: Configuration of the container used for the build.DockerVersion
: Version of Docker used to build the image.Author
: Author information (fromMAINTAINER
in Dockerfile, deprecated in favor ofLABEL
).Config
: The configuration that will be applied when running a container from this image. This is a crucial section containing:Hostname
,Domainname
,User
,AttachStdin
,AttachStdout
,AttachStderr
,Tty
,OpenStdin
,StdinOnce
Env
: List of environment variables (e.g.,["PATH=/usr/local/bin:..."]
).Cmd
: Default command to execute when a container starts.Entrypoint
: Default entrypoint for the container.Labels
: Map of labels applied to the image.WorkingDir
: Default working directory inside the container.ExposedPorts
: Ports exposed by the image (e.g.,{"80/tcp": {}}
).
Architecture
: CPU architecture the image is built for (e.g.,amd64
,arm64
).Os
: Operating system the image is built for (e.g.,linux
).Size
,VirtualSize
: Image size information.GraphDriver
: Information about the storage driver and layers.Data
: Contains layer metadata.Name
: Storage driver name (e.g.,overlay2
).
RootFS
: Information about the image’s root filesystem, including:Type
: Typicallylayers
.Layers
: An ordered list of SHA256 diff identifiers for each layer.
Extracting Specific Information
Manually parsing the large JSON output can be tedious. You have two primary ways to extract specific data points:
-
Using
jq
(External Tool):jq
is a powerful command-line JSON processor.
“`bash
# Get the default command (Cmd)
docker image inspect python:3.9-slim | jq ‘.[0].Config.Cmd’Get all environment variables
docker image inspect my-app:latest | jq ‘.[0].Config.Env’
Get the architecture
docker image inspect nginx | jq ‘.[0].Architecture’
Get all labels
docker image inspect my-custom-image | jq ‘.[0].Config.Labels’
“` -
Using
--format
withdocker image inspect
: Similar todocker image ls
,inspect
also supports the--format
flag with Go templates. This is often simpler for extracting single values or simple structures directly within Docker.
“`bash
# Get the OS
docker image inspect python:3.9-slim –format ‘{{.Os}}’
# Output: linuxGet the Entrypoint (might be an array, Go template handles it)
docker image inspect my-app –format ‘{{.Config.Entrypoint}}’
Output: [java -jar /app/app.jar]
Get a specific label value
docker image inspect my-app –format ‘{{index .Config.Labels “com.example.version”}}’
Output: v1.2.3
Get all environment variables, one per line
docker image inspect my-app –format ‘{{range .Config.Env}}{{println .}}{{end}}’
Output:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
JAVA_HOME=/opt/java/openjdk
…
Get the list of layer diff IDs
docker image inspect ubuntu:latest –format ‘{{json .RootFS.Layers}}’
Output: [“sha256:…”, “sha256:…”, …]
“`
docker image inspect
is indispensable for understanding the exact configuration, contents, and provenance of an image.
6. Understanding Image Construction: docker image history
To understand how an image was built and see the individual layers contributing to its size, use the docker image history
command.
Viewing Image Layers and Build Steps
bash
docker image history <image>
Example:
bash
docker image history python:3.9-slim
Output (simplified and potentially reordered for clarity):
IMAGE CREATED CREATED BY SIZE COMMENT
f1a35a6d4d5e 4 weeks ago /bin/sh -c #(nop) CMD ["python3"] 0B buildkit.dockerfile.v0
<missing> 4 weeks ago /bin/sh -c set -eux; wget -O get-pip.py ... 7.8MB buildkit.dockerfile.v0
<missing> 4 weeks ago /bin/sh -c #(nop) ENV PYTHON_GET_PIP_UR... 0B buildkit.dockerfile.v0
<missing> 4 weeks ago /bin/sh -c #(nop) ENV PYTHON_SETUPTOO... 0B buildkit.dockerfile.v0
<missing> 4 weeks ago /bin/sh -c #(nop) ENV PYTHON_PIP_VERS... 0B buildkit.dockerfile.v0
<missing> 4 weeks ago /bin/sh -c cd /usr/local/bin && ln -s ... 32B buildkit.dockerfile.v0
<missing> 4 weeks ago /bin/sh -c set -eux; apt-get update; ... 45MB buildkit.dockerfile.v0
<missing> 4 weeks ago /bin/sh -c #(nop) ENV PYTHON_VERSION=3.9.7 0B buildkit.dockerfile.v0
<missing> 4 weeks ago /bin/sh -c #(nop) ENV GPG_KEY=E3FF2839... 0B buildkit.dockerfile.v0
<missing> 4 weeks ago /bin/sh -c #(nop) ENV LANG=C.UTF-8 0B buildkit.dockerfile.v0
<missing> 4 weeks ago /bin/sh -c #(nop) ENV PATH=/usr/local/bi... 0B buildkit.dockerfile.v0
<missing> 5 weeks ago /bin/sh -c set -eux; apt-get update; ... 52MB buildkit.dockerfile.v0
<missing> 5 weeks ago /bin/sh -c #(nop) WORKDIR / 0B buildkit.dockerfile.v0
<missing> 5 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 5 weeks ago /bin/sh -c #(nop) ADD file:abc... in / 77.8MB (This is the base image layer)
Interpreting the Output
IMAGE
: The ID of the layer. The top one corresponds to the final image ID.<missing>
indicates that the layer exists locally but doesn’t have its own tag (it’s an intermediate layer). Docker might not have the history for base image layers if they weren’t built locally or pulled with full provenance.CREATED
: When the layer was created.CREATED BY
: The Dockerfile instruction (or command) that created this layer.#(nop)
usually indicates metadata instructions likeENV
,LABEL
,CMD
,WORKDIR
,EXPOSE
,MAINTAINER
which don’t add files but modify the image configuration. Commands starting with/bin/sh -c
typically correspond toRUN
instructions.ADD
orCOPY
instructions will also be shown.SIZE
: The size of this specific layer (the files added or changed by this step). This is very useful for identifying which build steps contribute most to the final image size. Note that a0B
size often corresponds to metadata changes.COMMENT
: Optional comment, often empty or used by build systems (likebuildkit.dockerfile.v0
).
Identifying Large Layers
By examining the SIZE
column in the history
output, you can pinpoint which RUN
, COPY
, or ADD
commands in your Dockerfile are adding the most data. This is crucial for optimizing image size, perhaps by combining RUN
commands, removing unnecessary files within the same RUN
command, or using multi-stage builds.
Security Considerations
The CREATED BY
column can sometimes reveal sensitive information if commands included secrets directly (which is bad practice). It also shows the exact commands run, which can be useful for understanding potential vulnerabilities introduced during the build process.
You can use --no-trunc
with docker image history
to see the full CREATED BY
commands if they are truncated.
7. Cleaning Up: Managing Your Image Inventory
As established, images consume disk space. Regularly cleaning up unnecessary images is good practice.
Identifying Unused Images
There are two main categories of “unused” images:
- Dangling Images: These are image layers that are not associated with any tagged image. They often result from rebuilding an image without removing the old one first. They are generally safe to remove.
- Unused Non-Dangling Images: These are tagged images (e.g.,
my-app:v1.1
,old-ubuntu:18.04
) that are no longer referenced by any container (stopped or running). You might keep them intentionally, but often they represent old versions you no longer need.
The Concept of Dangling Images
You can specifically list dangling images using the filter we saw earlier:
bash
docker image ls --filter dangling=true
Using docker image prune
Docker provides a convenient command, docker image prune
, to remove unused images.
Pruning Dangling Images
By default, without any flags, docker image prune
only removes dangling images:
bash
docker image prune
Docker will ask for confirmation before proceeding:
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N]
Enter y
to confirm. It will then list the deleted image IDs and the total space reclaimed.
Pruning All Unused Images (-a
)
To remove all images that are not associated with at least one container (this includes dangling images and tagged images not used by any container), use the -a
flag:
bash
docker image prune -a
Caution: This is more aggressive. It will remove any tagged image (like ubuntu:latest
, my-app:v1.0
) if no container (running or stopped) is currently based on it. Be sure you don’t need these images before running this command. It will also ask for confirmation.
Filtering Prune Operations (--filter
)
You can apply filters to the prune
command, similar to ls
, to be more selective. A common use case is to remove images older than a certain time. The filter key here is until
.
“`bash
Remove images (dangling or unused -a) created more than 24 hours ago
docker image prune -a –filter “until=24h”
Remove images created more than 30 days (approx) ago
You might need to calculate the duration string, e.g., 30*24 = 720h
docker image prune -a –filter “until=720h”
Remove images with a specific label
docker image prune –filter “label=stage=temporary”
``
until=
Thefilter removes images created *before* the specified duration. You can use hours (
h), minutes (
m`).
Forcing Removal (-f
)
To bypass the confirmation prompt (useful in scripts), use the -f
or --force
flag:
“`bash
Force remove all dangling images without prompting
docker image prune -f
Force remove all unused images without prompting
docker image prune -a -f
``
-f
Usewith caution, especially with
-a`.
8. Practical Scenarios and Workflows
Let’s combine these commands to solve common problems:
Finding Large Images Consuming Disk Space
“`bash
List images sorted by size (requires external sort command)
docker image ls –format “table {{.Repository}}:{{.Tag}}\t{{.Size}}” | sort -k2 -h -r
Or using Go template sorting (less common, might need complex templates)
Inspect the history of a large image to find large layers
docker image inspect my-large-image:latest –format ‘{{.Size}}’ # Get size first
docker image history my-large-image:latest
“`
Identifying Images Older Than a Certain Date
“`bash
Prune images older than 30 days (720 hours)
docker image prune -a -f –filter “until=720h”
List images created since a specific baseline image (potentially for cleanup review)
docker image ls –filter since=my-baseline-image:v1.0
“`
Listing Images for a Specific Application Using Labels
“`bash
List all production images for ‘project-alpha’
docker image ls –filter label=project=project-alpha –filter label=stage=production
List all images maintained by the core team
docker image ls –filter label=team=core
“`
Scripting Image Cleanup Tasks
“`bash
!/bin/bash
echo “Removing dangling images…”
docker image prune -f
echo “Removing images older than 168 hours (7 days)…”
docker image prune -a -f –filter “until=168h”
echo “Listing remaining images…”
docker image ls
“`
Verifying Image Configuration Before Deployment
“`bash
Check exposed ports for the webapp image
docker image inspect my-webapp:prod –format ‘{{json .Config.ExposedPorts}}’
Check environment variables
docker image inspect my-webapp:prod –format ‘{{range .Config.Env}}{{println .}}{{end}}’
Check the entrypoint and command
docker image inspect my-webapp:prod –format ‘Entrypoint: {{.Config.Entrypoint}} | Cmd: {{.Config.Cmd}}’
Check the target architecture
docker image inspect my-webapp:prod –format ‘{{.Architecture}}/{{.Os}}’
“`
9. Best Practices for Image Management
- Use Meaningful Tags: Avoid relying solely on
latest
. Use semantic versioning (e.g.,v1.2.3
) or Git commit hashes for tags to ensure reproducibility and clarity. - Regularly Prune Unused Images: Set up scheduled tasks or manually run
docker image prune
periodically to reclaim disk space and remove clutter. Be cautious withprune -a
. - Leverage Labels for Organization: Use labels (
LABEL
in Dockerfile) to categorize images by project, stage (dev/test/prod), maintainer, version, etc. This greatly aids filtering. - Be Mindful of Image Size: Optimize Dockerfiles to create smaller images (use smaller base images like Alpine, combine
RUN
commands, use multi-stage builds, clean up temporary files within the sameRUN
layer). Usedocker image history
to identify large layers. - Scan Images for Vulnerabilities: While not covered in detail here, use tools like Docker Scout, Trivy, or Snyk to scan your images for known security vulnerabilities before deploying them. Listing images helps identify which ones need scanning or updating.
10. Conclusion
Docker images are the cornerstone of containerization, but they require diligent management. Knowing how to effectively list, filter, inspect, and clean up your images is crucial for maintaining a healthy, secure, and efficient Docker environment.
We’ve explored the fundamental docker image ls
command in depth, from its basic usage and output columns to its powerful --filter
and --format
options that enable precise querying and custom output. We also covered docker image inspect
for deep dives into image metadata, docker image history
for understanding layer composition and size, and docker image prune
for essential cleanup tasks.
By mastering these commands and adopting best practices like meaningful tagging, labeling, regular pruning, and size optimization, you gain full control over your image inventory. This allows you to save disk space, enhance security, streamline workflows, and ultimately leverage the full power of Docker with confidence. Keep exploring, keep building, and keep your image cache clean!