Home > Back-end >  Building a container image and re-using pulled layers
Building a container image and re-using pulled layers

Time:05-14

Suppose there is a container image published to a Docker registry, and I want to rebuild the image with modifications while re-using as many of the published layers as possible.

Concretely, suppose the image foo/bar is built from this Dockerfile, and I only want to modify the layer that contains script.sh:

FROM ubuntu:focal
COPY script.sh .

Even though pulling the image downloads the layers for ubuntu:focal, when I re-build my local machine may resolve the ubuntu:focal tag to another version, producing a new image with no common layers with the one I pulled.

                                   6a9e8d7 <foo/bar:new>
           <foo/bar:old> c7632a5      |
                            |         |
                             ---- ---- 
                                 |
                              3b15784 <ubuntu:focal (then)>
                                 |
                                ...
           
           
                             DESIRABLE




        <foo/bar:old> c7632a5          48fead0 <foo/bar:new>
                         |                |
                         |                |
<ubuntu:focal (then)> 3b15784          9a634f5 <ubuntu:focal (now)>
                         |                |
                        ...              ...


                            UNDESIRABLE

The desired outcome could possibly be achieved by looking at the pulled layers and tagging the correct one (3b15784) as ubuntu:focal before building. But I'm not sure if Docker exposes enough information to do this in an automatic way.

CodePudding user response:

As a workaround, I could explicitly include the base image's digest as a label on the built image:

FROM ${UBUNTU_IMAGE_ID:-ubuntu:focal}
COPY script.sh .

Then I would build with:

# First build
UBUNTU_IMAGE_ID=$( \
    docker inspect \
        --format '{{ index .RepoTags 0 }}@{{ index . "Id" }}' \
        ubuntu:focal \
)

# Subsequent builds
docker pull foo/bar:old
UBUNTU_IMAGE_ID=$( \
    docker inspect \
        --format '{{ index .Config.Labels "ubuntu_image_id" }}' \
        foo/bar:old \
)


docker build . \
    --build-arg "UBUNTU_IMAGE_ID=${UBUNTU_IMAGE_ID}" \
    --label "ubuntu_image_id=${UBUNTU_IMAGE_ID}" \
    --tag foo/bar:new

However, a more elegant solution would definitely be welcome, especially one that does not involve any specific assumptions about how the original pulled image was built.

CodePudding user response:

Maybe Docker supports this built in with --cache-from:

docker pull foo/bar:old
docker build . \
    --build-arg BUILDKIT_INLINE_CACHE=1 \
    --cache-from foo/bar:old
    --tag foo/bar:new
  • Related