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