drone-docker: Docs don't mention caching at all

They used to - noticed some commits and previous issues - but the current docs page doesn’t mention them at all: http://plugins.drone.io/drone-plugins/drone-docker/

What is the recommended way to handle this? Even if the docs just covered the basic case of “I don’t want to re-download my FROM image every single time”, that would be a great step forward.

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 18
  • Comments: 21 (2 by maintainers)

Most upvoted comments

I would like to share with my steps which allowed me to use the docker image caching in Drone CI without the need of using trusted nor privileged git repository options.

To enable docker image caching all you need is:

  • DRONE_VOLUME=/tmp/drone-cache:/cache drone-server variable;
  • storage_path: /drone/docker and use_cache: true parameters for plugins/docker job;
  • drillster/drone-volume-cache of course 😉

docker-compose.yml

version: '3'

networks:
  oasis: {}

services:
  drone-server:
    restart: unless-stopped
    image: drone/drone:0.8
    networks:
      - oasis
    volumes:
      - /srv/data/drone/lib/drone:/var/lib/drone/
    environment:
      - DRONE_OPEN=false
      - DRONE_ADMIN=REDACTED
      - DRONE_HOST=https://REDACTED
      - DRONE_SECRET=REDACTED
      - DRONE_GITEA=true
      - DRONE_GITEA_URL=https://REDACTED
      - DRONE_GITEA_PRIVATE_MODE=true
      - DRONE_VOLUME=/tmp/drone-cache:/cache

  drone-agent:
    restart: unless-stopped
    image: drone/agent:0.8
    networks:
      - oasis
    command: agent
    depends_on:
      - drone-server
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - DRONE_SERVER=drone-server:9000
      - DRONE_SECRET=REDACTED

.drone.yml

pipeline:
  restore_cache:
    image: drillster/drone-volume-cache:latest
    restore: true
    mount:
      - /drone/docker
    # volumes:
    #   - /tmp/drone-cache:/cache

  publish:
    image: plugins/docker:17.12
    repo: andrey01/REDACTED
    tags:
      - latest
      - ${DRONE_COMMIT_SHA}
    secrets:
      - docker_username
      - docker_password
    storage_path: /drone/docker
    use_cache: true
    when:
      event: [push, tag]
      branch: master

  rebuild_cache:
    image: drillster/drone-volume-cache:latest
    rebuild: true
    mount:
      - /drone/docker
    # volumes:
    #   - /tmp/drone-cache:/cache

After this is set, Drone will keep the docker image cache under: /tmp/drone-cache/<username>/<gitrepo>/1/drone/docker/

When the restore_cache job is running, you can spot it is running rsync from /cache/<username>/<gitrepo>/1//drone/docker/ to /drone/docker inside the drone pipeline. And the /cache is mounted from host:/tmp/drone-cache across the whole pipeline as DRONE_VOLUME drone-server variable was leveraged.

Snap:

# ps auxwwf
...
root       896  0.4  0.0   6216  1532 ?        Ss   21:01   0:00  |       \_ /bin/bash /usr/local/cacher.sh
root       964 30.8  0.1  38192  2320 ?        R    21:01   0:05  |           \_ rsync -aHA --delete /cache/<username>/<gitrepo>/1//drone/docker/ /drone/docker
root       965  4.7  0.0  31720  1816 ?        S    21:01   0:00  |               \_ rsync -aHA --delete /cache/<username>/<gitrepo>/1//drone/docker/ /drone/docker
root       966 45.6  0.1  38116  2356 ?        S    21:01   0:08  |                   \_ rsync -aHA --delete /cache/<username>/<gitrepo>/1//drone/docker/ /drone/docker
...

The docker image caching helped to reduce the build time for one of my repositories from 4m39s to 51s.

References

Missing documentation

FYI: @bradrydzewski

Why DroneCI doesn’t use a cache by default ?

For security reasons. If we used the host machine cache, someone could send a malicious pull request that overwrites commonly used images (e.g. golang, or node) and replace with malicious versions of images. These could be used to capture secrets, source code and more.

Also to prevent race condition where two builds are running at the same time on the same machine, and both trying to create an image with the same tag name (e.g. :latest), which would be problematic.

Mounting the layer cache into the plugin is not recommended I think.

Instead, you can use cache-from that is portable even to drone cloud.

kind: pipeline
name: default

steps:
  - name: docker-builder
    image: plugins/docker
    settings:
      repo: laszlocloud/cache-from-test
      tags: latest
      cache_from: "laszlocloud/cache-from-test:latest"
      dry_run: true

More on this here: https://laszlo.cloud/how-using-cache-from-can-speed-up-your-docker-builds-in-droneci

I would argue that the absolute worst feature of the official (or whatever you’d like to call them) drone plugins is that the don’t warn when being supplied with invalid argument names. This issue comes up so often…

Preferably all plugins should also have a PLUGIN_PLUGIN_DEBUG option to turn on verbose logging because that’s the second thing that I find usually goes wrong, plugins can have fairly complicated inner workings and just a simple error message might not always be enough when figuring out whats going wrong.

I don’t think that I can count the times that I personally have had to add logging to a plugin to understand why it fails to do what it’s supposed to on two hands.

While these two issues range for mildly to very annoying for me personally I would just have to guess how annoying it is for people who don’t know how to modify the plugins to inspect what it is doing and it’s probably a lot more problematic and frustrating experience than for me…

cache_from […] should maybe be turned into a list if it already isn’t

Just confirming that cache_from is already a list [1] [1] https://github.com/drone-plugins/drone-docker/blob/master/docker.go#L50

I believe that docker build support multiple --cache_from entries so that option should maybe be turned into a list if it already isn’t. The big issue for me is though that all layers in a typical larger docker build are in intermediate steps and we cannot push those easily to a repository now given how drone-docker works.

In the example below the most important steps to be able to cache are the npm ci and pip wheel but they are not really made available with drone-docker right now.

from node:10-stretch as jsbuilder
run yarn global add webpack@4.12.1 webpack-cli@3.0.8 jest prettier
copy jsapps/package*.json /opt/barfoo/jsapps/
workdir /opt/barfoo/jsapps
run npm ci
copy jsapps/ /opt/barfoo/jsapps/
run npm run prod && rm -rf node_modules

from python:3.7 as pythonbuilder
run apt-get update -qq && \
    apt-get install -y gettext && \
    rm -rf /var/lib/apt/lists/*
workdir /opt/barfoo
copy requirements* /opt/barfoo/
copy requirements /opt/barfoo/requirements
arg PIP_FIND_LINKS=/wheel
run pip -q \
        wheel \
        --wheel-dir /wheel \
        --find-links $PIP_FIND_LINKS \
        --no-cache-dir \
        -r requirements.txt \
        -r requirements/requirements-docker.txt
run pip install \
        --find-links /wheel \
        --no-index \
        --no-cache-dir \
        -r requirements.txt \
        -r requirements/requirements-docker.txt
# ...

from python:3.7
workdir /opt/barfoo
# ...
copy --from=pythonbuilder /wheel /wheel
copy requirements* /opt/barfoo/
copy requirements /opt/barfoo/requirements
run pip install \
        --find-links /wheel \
        --no-index \
        --no-cache-dir \
        -r requirements.txt \
        -r requirements/requirements-docker.txt
copy . /opt/barfoo
copy --from=pythonbuilder /opt/barfoo /opt/barfoo
copy --from=pythonbuilder /opt/barfoo_static /opt/barfoo_static
# ...

I want the Dockerfile to be self contained so I don’t want separate drone steps to do stuff required to build the full image because I want it to build anywhere only using docker build. I do the drone stuff with volume mounted caces for npm/pip/… as well for the linting steps of the build but for image publishing I want it to build from one easy to understand source.