Skip to content

Docker Image Management

Back to Docker Tutorials


List Local Images

Docker stores downloaded images in a local cache called the image store. The docker images command lists all locally available images.

%%{init: {'flowchart': {'padding': 5}}}%%
graph TD
    HUB["<small>☁️ Docker Hub</small>"]-->|docker pull|STORE["<small>📀 Local Image Store</small>"]
    STORE-->|docker run|CNT["<small>📦 Running Container</small>"]
    STORE-->|docker images|LIST["<small>📋 Image List</small>"]

    style HUB fill:#f3e8ff,stroke:#a855f7,stroke-width:2px,color:#581c87
    style STORE fill:#ffedd5,stroke:#f59e0b,stroke-width:2px,color:#78350f
    style CNT fill:#dcfce7,stroke:#22c55e,stroke-width:2px,color:#14532d
    style LIST fill:#f3f4f6,stroke:#9ca3af,stroke-width:2px,color:#1f2937

Run docker images to see what images are currently cached on this system. Notice the columns output by the command — they will show you the image name, tag, unique ID, and its size.

docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    d2c94e258dcb   10 months ago   13.3kB
ubuntu        24.04     3b418d7b466a   2 weeks ago     77.8MB
nginx         1.30      f2a715f4e5c3   3 weeks ago     142MB

Pull an Image from a Registry

docker pull downloads an image from a registry (Docker Hub by default) without running a container. Use this to pre-fetch images before use.

Run docker pull alpine:3.22 to download the alpine image tagged 3.22.

docker pull alpine:3.22
3.22: Pulling from library/alpine
4abcf2066143: Pull complete 
Digest: sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b
Status: Downloaded newer image for alpine:3.22
docker.io/library/alpine:3.22

After the pull completes, verify it appears in your local store by running docker images.

docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
alpine        3.22      05455a08881e   3 days ago      7.38MB
hello-world   latest    d2c94e258dcb   10 months ago   13.3kB

When pulling images, Docker uses a specific naming convention: registry/repository/image_name:tag. - If you don't specify a registry, it defaults to Docker Hub (docker.io). - If you don't specify a tag, it defaults to latest.

For example, public.ecr.aws/hashicorp/terraform:1.15 breaks down as:

Component Value Description
🌐 Registry public.ecr.aws The server hosting the image.
🏢 Repository hashicorp The organization or user namespace.
📦 Image Name terraform The specific application image.
🏷️ Tag 1.15 The version or variant of the image.

To see this in action, pull an image from AWS Elastic Container Registry (ECR) Public.

Run docker pull public.ecr.aws/hashicorp/terraform:1.15 to pull the Terraform image from AWS instead of Docker Hub.

docker pull public.ecr.aws/hashicorp/terraform:1.15
1.15: Pulling from hashicorp/terraform
Digest: sha256:8a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f
Status: Downloaded newer image for public.ecr.aws/hashicorp/terraform:1.15
public.ecr.aws/hashicorp/terraform:1.15

Verify it was downloaded successfully by running docker images.

docker images
REPOSITORY                           TAG       IMAGE ID       CREATED         SIZE
public.ecr.aws/hashicorp/terraform   1.15      9c8b7a6d5e4f   2 months ago    75MB
alpine                               3.22      05455a08881e   3 days ago      7.38MB

Inspect Image Metadata

docker inspect returns the full JSON metadata for an image, including its layers, environment variables, default command, and exposed ports.

Run docker inspect alpine:3.22 to view the full metadata.

docker inspect alpine:3.22
[
    {
        "Id": "sha256:05455a08881ea9cf0e7fac51e00f3408e24483a90710ba0a5521b4a0f8df78dc",
        "RepoTags": [
            "alpine:3.22"
        ],
        "RepoDigests": [
            "alpine@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"
        ],
        "Parent": "",
        "Comment": "",
...

To extract just the OS, run docker inspect --format '{{.Os}}' alpine:3.22.

docker inspect --format '{{.Os}}' alpine:3.22
linux

View Image Layer History

Every Docker image is built from a stack of read-only layers. docker history shows the instruction that created each layer and its size contribution.

%%{init: {'flowchart': {'padding': 5}}}%%
graph BT
    B1["<small>🐧 Base Layer (FROM alpine)</small>"]-->B2["<small>📦 Layer 2 (RUN install)</small>"]
    B2-->B3["<small>📦 Layer 3 (COPY files)</small>"]
    B3-->B4["<small>📦 Layer 4 (RUN configure)</small>"]
    B4-->IMG["<small>📀 Final Image (read-only)</small>"]

    style B1 fill:#f3f4f6,stroke:#9ca3af,stroke-width:2px,color:#1f2937
    style B2 fill:#dbeafe,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a
    style B3 fill:#dbeafe,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a
    style B4 fill:#dbeafe,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a
    style IMG fill:#dcfce7,stroke:#22c55e,stroke-width:2px,color:#14532d

Run docker history alpine:3.22 to view the layer history of the Alpine image.

docker history alpine:3.22
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
05455a08881e   3 days ago    /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B        
<missing>      3 days ago    /bin/sh -c #(nop) ADD file:04c8f25b390b1e45b…   7.38MB    

Pull a more complex image and compare by running docker pull nginx:alpine followed by docker history nginx:alpine.

docker pull nginx:alpine
docker history nginx:alpine
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
6b6a5e4f3d2c   5 days ago    /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B        
<missing>      5 days ago    /bin/sh -c #(nop)  STOPSIGNAL SIGQUIT           0B        
<missing>      5 days ago    /bin/sh -c #(nop)  EXPOSE 80                    0B        
<missing>      5 days ago    /bin/sh -c #(nop)  ENTRYPOINT ["/docker-entr…   0B        
<missing>      5 days ago    /bin/sh -c #(nop) COPY file:65504f71f5855ca0…   4.62kB    
<missing>      5 days ago    /bin/sh -c #(nop) COPY file:0b866ff3fc1ef5b0…   3.02kB    
...

Observe that nginx:alpine has significantly more layers than the base alpine image.


Tag an Image

docker tag creates an additional name (tag) pointing to the same image. Tags are used to version and organise images before pushing to a registry.

The format is docker tag SOURCE_IMAGE:TAG TARGET_IMAGE:TAG.

%%{init: {'flowchart': {'padding': 5}}}%%
graph TD
    SRC["<small>📀 alpine:3.22</small>"]-->|docker tag|TAG["<small>📀 myapp:v1.0</small>"]
    TAG-->|docker push|REG["<small>☁️ Registry</small>"]
    REG-->|docker pull|PULL["<small>📀 Remote Host</small>"]

    style SRC fill:#dbeafe,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a
    style TAG fill:#dbeafe,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a
    style REG fill:#f3e8ff,stroke:#a855f7,stroke-width:2px,color:#581c87
    style PULL fill:#dcfce7,stroke:#22c55e,stroke-width:2px,color:#14532d

Tag the alpine:3.22 image as myapp:v1.0 by running docker tag alpine:3.22 myapp:v1.0.

docker tag alpine:3.22 myapp:v1.0

A tag is just a lightweight pointer. Tagging an image does not duplicate its data or take up extra disk space. Both tags simply point to the exact same underlying image, which is why they will share the identical IMAGE ID.

Verify both tags exist and share the same IMAGE ID by running docker images.

docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
alpine        3.22      05455a08881e   3 days ago      7.38MB
myapp         v1.0      05455a08881e   3 days ago      7.38MB

Remove an Image Tag

docker rmi removes an image tag from the local store. If the tag is the only reference to an image, the image layers are also deleted.

Remove the myapp:v1.0 tag by running docker rmi myapp:v1.0.

docker rmi myapp:v1.0
Untagged: myapp:v1.0

Notice the output says Untagged: instead of Deleted:. Because the alpine:3.22 tag still points to the same underlying image layers, Docker is smart enough to only remove the pointer (untag) rather than destroying the actual data.

Verify the alpine:3.22 image still exists by running docker images. Only the myapp:v1.0 tag should be gone.


Pull a Specific Image Digest

Image tags are mutable — a publisher can update a tag to point to a new image. For reproducible builds, you can reference an image by its immutable content digest.

Run docker pull alpine:3.22 and note the digest shown in the output (the sha256:... line).

To view the digest of a locally cached image, run docker images --digests alpine.

docker images --digests alpine
REPOSITORY   TAG       DIGEST                                                                    IMAGE ID       CREATED      SIZE
alpine       3.22      sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b   05455a08881e   3 days ago   7.38MB

To pull an image using its exact digest, use the @ symbol instead of a colon. The format is docker pull alpine@sha256:<YOUR_DIGEST>.

Run docker pull alpine@sha256:48b0309ca019d89d40f670aa1bc06e426dc0931948452e8491e3d65087abc07d to pull the exact image.

docker pull alpine@sha256:48b0309ca019d89d40f670aa1bc06e426dc0931948452e8491e3d65087abc07d
docker.io/library/alpine@sha256:48b0309ca019d89d40f670aa1bc06e426dc0931948452e8491e3d65087abc07d: Pulling from library/alpine
...
Digest: sha256:48b0309ca019d89d40f670aa1bc06e426dc0931948452e8491e3d65087abc07d
Status: Downloaded newer image for alpine@sha256:48b0309ca019d89d40f670aa1bc06e426dc0931948452e8491e3d65087abc07d

Run docker images again to verify. You will notice the image is listed with its digest directly in the image name instead of a traditional tag.

docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
alpine       <none>    3e23a4b6c8d0   10 months ago   7.34MB

Clean Up Unused Images

docker image prune -a removes all unused images (not just dangling ones) that are not referenced by any container. This reclaims disk space.

A dangling image is an image that has lost its tag (showing as <none>:<none> in docker images). This usually happens when you build a new image and assign it a tag that was already in use by an older image. The default prune command only removes these dangling images, but adding -a removes all unused images.

First view current disk usage by running docker system df.

docker system df
TYPE         TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images       4         0         231MB     231MB (100%)
Containers   0         0         0B        0B
Local Volumes 0        0         0B        0B
Build Cache  0         0         0B        0B

Run docker image prune -af to remove all unused images without prompting for confirmation.

docker image prune -af
Deleted Images:
untagged: alpine:3.22
untagged: alpine@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b
deleted: sha256:05455a08881ea9cf0e7fac51e00f3408e24483a90710ba0a5521b4a0f8df78dc
deleted: sha256:a6b8c9d0e1f2g3h4i5j6k7l8m9n0o1p2q3r4s5t6u7v8w9x0y1z2a3b4c5d6e7f8
...

Total reclaimed space: 231MB

Run docker system df again to confirm disk usage decreased.

🧠 Quick Quiz

#

Which command is used to download an image from Docker Hub without running it?

#

How do you remove a local Docker image from your machine?

#

Which command provides detailed JSON metadata about an image, such as its layers, env vars, and entrypoint?


🐳

Practice Live in Your Browser

Don't just read about Docker commands—execute them in real time! Launch a fully-configured, secure Docker sandbox directly in your browser with automated task validation ready for you.

FREE LAUNCH OFFER Get all premium Docker labs for FREE until June 30th! (No Credit Card Required)

📬 DevopsPilot Weekly — Learn DevOps, Cloud & Gen AI the simple way.
👉 Subscribe here