moby: Using --cache-from doesn't skip base image pull

Description

Steps to reproduce the issue:

  1. docker pull myimage:latest
  2. docker build --cache-from my-image:latest -t my-image:latest .

Describe the results you received:

Sending build context to Docker daemon 525.8 kB.8 kB
Step 1/15 : FROM node:6.10-alpine
6.10-alpine: Pulling from library/node
709515475419: Downloading [==>                                                ] 97.51 kB/2.313 MB
92aa7b64772e: Downloading [==>                                                ] 654.5 kB/14.96 MB
a32501522b97: Downloading [=>                                                 ] 32.77 kB/868.1 kB
...

Describe the results you expected:

Sending build context to Docker daemon 525.8 kB.8 kB
Step 1/15 : FROM node:6.10-alpine
6.10-alpine: Pulling from library/node
709515475419: Layer already exists
92aa7b64772e: Layer already exists
a32501522b97: Layer already exists

Additional information you deem important (e.g. issue happens only occasionally): Always

Output of docker version:

Client:
 Version:      1.13.0
 API version:  1.25
 Go version:   go1.7.3
 Git commit:   49bf474
 Built:        Tue Jan 17 09:58:26 2017
 OS/Arch:      linux/amd64

Server:
 Version:      1.13.0
 API version:  1.25 (minimum version 1.12)
 Go version:   go1.7.3
 Git commit:   49bf474
 Built:        Tue Jan 17 09:58:26 2017
 OS/Arch:      linux/amd64
 Experimental: false

Output of docker info:

Containers: 10
 Running: 0
 Paused: 0
 Stopped: 10
Images: 26
Server Version: 1.13.0
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 62
 Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins: 
 Volume: local
 Network: bridge host macvlan null overlay
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 03e5862ec0d8d3b3f750e19fca3ee367e13c090e
runc version: 2f7393a47307a16f8cee44a37b262e8b81021e3e
init version: 949e6fa
Security Options:
 apparmor
 seccomp
  Profile: default
Kernel Version: 4.8.0-37-generic
Operating System: Ubuntu 16.10
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 11.64 GiB
Name: MYNAME
ID: MYID
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

Additional environment details (AWS, VirtualBox, physical, etc.): This happens on CI also

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 40
  • Comments: 25 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Ok so i’m not the only one experiencing this. I’ve spent the last 4 hours disabling overlay driver and creating clean runners in my Gitlab CI server, testing if that was the cause with no success.

On my machine the base-image is skipped and on Gitlab CI is always pulled.

I’ve opened an issue also on Gitlab #29184 until is not clear where this bug comes from.

Confirmed

I do this work-around to avoid pulling the base image and therefore invalidating the cache layers:

docker pull $(grep -ioP '(?<=^from)\s+\S+' Dockerfile)

In the end my pipeline looks about like this:

latest=$CI_REGISTRY/$CI_PROJECT_PATH:latest
this=$CI_REGISTRY/$CI_PROJECT_PATH:$CI_COMMIT_TAG

docker pull $(grep -ioP '(?<=^from)\s+\S+' Dockerfile)
docker pull $CI_REGISTRY/$CI_PROJECT_PATH:latest

docker build -t $this --cache-from $latest .
docker tag $this $latest

docker push $this
docker push $latest

/Cc @tonistiigi

Confirmed

I do this work-around to avoid pulling the base image and therefore invalidating the cache layers:

docker pull $(grep -ioP '(?<=^from)\s+\S+' Dockerfile)

For when on busybox (no -P for grep):

$(grep -oE 'FROM .+$' Dockerfile | head -n 1 | cut -d ' ' -f 2)

I think I bumped into the same issue with Travis CI. After some digging, to reproduce the issue locally, I had to remove /var/lib/docker/image/overlay2/distribution/diffid-by-digest. It looks like this directory contains mappings to the layer IDs. When doing docker save it is not preserved and loading the image does not populate it. Subsequently, even though the layers for the base image are loaded, the verification of their existence fails during docker pull.

As a workaround, I save that directory and restore it, as part of saving the images. Here is our .travis.yml file that does it and an example build.

If it helps anyone, I was able to use cache from previous builds in the shared GitLab Runner using the docker in docker service using Buildkit:

docker:build:
  stage: build
  services:
    - docker:dind
  image: docker
  variables:
    DOCKER_DRIVER: overlay2
    DOCKER_BUILDKIT: 1
  before_script:
    - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
    - docker pull $CI_REGISTRY_IMAGE:latest
  script:
    - docker build
      --build-arg BUILDKIT_INLINE_CACHE=1
      --cache-from $CI_REGISTRY_IMAGE:latest
      --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
      --tag $CI_REGISTRY_IMAGE:latest
      --file ./Dockerfile
      "."
  after_script:
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
    - if [[ "$CI_DEFAULT_BRANCH" = "$CI_COMMIT_BRANCH" ]]; then docker push $CI_REGISTRY_IMAGE:latest; fi

Couple things to note:

  • This only seemed to work when I had the --build-arg BUILDKIT_INLINE_CACHE=1 as the first flag on docker build (I might be crazy)
  • Or what made it work from me was that the latest tag was actually pushed from within the dind service itself

References:


Update:

I didn’t have to actually pull the latest tag either (saves a little bit more time in the runner):

docker:build:
  stage: build
  services:
    - docker:dind
  image: docker
  variables:
    DOCKER_DRIVER: overlay2
    DOCKER_BUILDKIT: 1
  before_script:
    - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
  script:
    - docker build
      --build-arg BUILDKIT_INLINE_CACHE=1
      --cache-from $CI_REGISTRY_IMAGE:latest
      --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
      --tag $CI_REGISTRY_IMAGE:latest
      --file ./docker/Dockerfile
      "."
  after_script:
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
    - if [[ "$CI_DEFAULT_BRANCH" = "$CI_COMMIT_BRANCH" ]]; then docker push $CI_REGISTRY_IMAGE:latest; fi

+1

Maybe i’m wrong and this is not the way it should work, but from my understanding inside myimage:latest i’ve all the layers from the base image so even if i don’t pull mybaseimage:latest it should use that layers to compare with the version on the registry and reuse them if the checksum is the same.