15

I don't know how to run a cached Docker image in Github Actions.
I've followed a tutorial about Publishing Docker images to implement a task that would cache, build and push Docker image to a DockerHub.
I need to build, cache and run the image, the image publishing is optional.
My goal is to speed up CI workflow.
Here is the Github Actions workflow:

name: CI

# Controls when the action will run. 
on:
  # Triggers the workflow on push or pull request events but only for the master branch
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - name: Check Out Repo
        uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: Set up Docker Buildx
        id: buildx
        uses: docker/setup-buildx-action@v1 

      - name: Cache Docker layers
        uses: actions/cache@v2
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-buildx-

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with: 
          username: ${{ secrets.DOCKER_HUB_USERNAME }}
          password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}

      - name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
        with:
          context: ./
          file: ./Dockerfile
          builder: ${{ steps.buildx.outputs.name }}
          push: true
          tags: ivan123123/c_matrix_library:latest
          cache-from: type=local,src=/tmp/.buildx-cache
          cache-to: type=local,dest=/tmp/.buildx-cache

      #- name: Run Docker container
      #  run: ???

      # Upload gcovr code coverage report
      - name: Upload GCC Code Coverage Report
        uses: actions/upload-artifact@v2
        with:
          name: coveragereport
          path: ./builddir/meson-logs/coveragereport/
        
      - name: Upload code coverage reports to codecov.io page
        run: bash <(curl -s https://codecov.io/bash) 

Edit:
I've found no solution to running cached Docker image, but I have managed to build cached image every time I run CI workflow with docker/setup-buildx-action@v1 action. Because the image is cached, we don't need to download every Docker image dependencies thus saving time from 3 minutes originally to only 40 seconds. Below is the Github Actions workflow:

name: CI

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Check Out Repo
        uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: Set up Docker Buildx
        id: buildx
        uses: docker/setup-buildx-action@v1 

      - name: Cache register
        uses: actions/cache@v2
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ hashFiles('**/Dockerfile') }}

      - name: Build Docker image
        uses: docker/build-push-action@v2
        with:
          context: ./
          file: ./Dockerfile
          builder: ${{ steps.buildx.outputs.name }}
          load: true
          tags: c_matrix_library:latest
          cache-from: type=local,src=/tmp/.buildx-cache
          cache-to: type=local,dest=/tmp/.buildx-cache

      - name: Run Docker container
        run: docker run -v "$(pwd):/app" c_matrix_library:latest
Ivan Vnucec
  • 604
  • 1
  • 5
  • 17
  • 2
    how do you know that your action did not use cashe? any errors ? – LinPy Mar 01 '21 at 11:54
  • The action uses the cache but I don't know how do I run the cached image? Would `docker run ivan123123/c_matrix_library` run the cached image or if it would pull the image from Dockerhub? My goal is to speed up CI workflow. – Ivan Vnucec Mar 01 '21 at 13:08

4 Answers4

7

If you want to cache a published Docker image that lives in the Docker Repository, you can do:

- name: Restore MySQL Image Cache if it exists
  id: cache-docker-mysql
  uses: actions/cache@v3
  with:
    path: ci/cache/docker/mysql
    key: cache-docker-mysql-5.7

- name: Update MySQL Image Cache if cache miss
  if: steps.cache-docker-mysql.outputs.cache-hit != 'true'
  run: docker pull mysql:5.7 && mkdir -p ci/cache/docker/mysql && docker image save mysql:5.7 --output ./ci/cache/docker/mysql/mysql-5.7.tar

- name: Use MySQL Image Cache if cache hit
  if: steps.cache-docker-mysql.outputs.cache-hit == 'true'
  run: docker image load --input ./ci/cache/docker/mysql/mysql-5.7.tar

- name: Start containers
  run: docker compose up -d

When docker compose up runs, if a service uses the Docker image mysql:5.7 image, it's going to skip downloading it.

Lucas Bustamante
  • 15,821
  • 7
  • 92
  • 86
4

This question is a bit old now, but I've found the documented way of running a built image from the docker/build-push-action in a subsequent step. In short, you have to set up a local registry.

The yaml below has been directly copy + pasted from here.

name: ci

on:
  push:
    branches:
      - 'main'

jobs:
  docker:
    runs-on: ubuntu-latest
    services:
      registry:
        image: registry:2
        ports:
          - 5000:5000
    steps:
      -
        name: Checkout
        uses: actions/checkout@v3
      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v2
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
        with:
          driver-opts: network=host
      -
        name: Build and push to local registry
        uses: docker/build-push-action@v3
        with:
          context: .
          push: true
          tags: localhost:5000/name/app:latest
      -
        name: Inspect
        run: |
          docker buildx imagetools inspect localhost:5000/name/app:latest
blthayer
  • 782
  • 1
  • 6
  • 19
2

This might not fully answer you question since I think there is no actual way of running your cached image.

But you can speed up your build using Github's cache, I have posted a complete tutorial about this that you can read here

Summarizing you can setup Docker buildx and then use GH cache with build-push-action:

  - name: Set up Docker Buildx
    uses: docker/setup-buildx-action@v1

  - name: Build and push
    uses: docker/build-push-action@v2
    with:
      context: .
      file: ./Dockerfile
      push: true
      tags: ivan123123/c_matrix_library:latest
      cache-from: type=gha
      cache-to: type=gha

Edit

Just found a reference in build-push action that might be useful to you:

https://github.com/docker/build-push-action/blob/master/docs/advanced/share-image-jobs.md

m33n
  • 1,622
  • 15
  • 38
  • Thanks for answering, but I think I've already posted a workaround in the EDIT section of my question which is similar to your 'solution'. – Ivan Vnucec Sep 27 '21 at 08:26
  • It is similar... but differences there are huge. Note cache arguments are pretty different. You can go to the build-push docs and spend some time reading the explanation there – m33n Oct 04 '21 at 07:54
1

Edit:

As mentioned by Romain in the comments. The initial solution will pull the image at the beginning of the workflow and as such will not use the image that is built during the workflow. The only solution seem to be running docker run yourself in the step:


- name: Run my docker image
  run: >
    docker run -t ivan123123/c_matrix_library:latest
    ...

On a side note. Using this solution might get a bit complicated if you use services in your job. In which case, the networking between your container and the service containers will be troublesome

Original answer:

To run the image you can use the following:


- name: Run my docker image
  uses: docker://ivan123123/c_matrix_library:latest
  with:
    entrypoint: ...
    args: ...

The entrypoint and args are optional. You can find more info here. One limitation though is that you can use any variable or context in the uses field. You can only hardcode the name and tag of the image.

ITChap
  • 4,057
  • 1
  • 21
  • 46
  • Would this task run the cached image or would it firstly pull the image from Dockerhub? – Ivan Vnucec Mar 01 '21 at 13:14
  • 1
    The docker images referenced by a "uses" are pulled from DockerHub, and this is done at the very beginning while setting up the job, so I don't think you can cache it. If you want to use a docker image you have just built, you need to explicitely invoke docker run. – Romain Prévost Mar 02 '21 at 07:55
  • 1
    @RomainPrévost yeah I just realized. I am sorry Ivan but I think my answer is not the right solution. Like Romain mentioned it is pulling the image at the beginning of the workflow. – ITChap Mar 02 '21 at 07:59
  • @ITChap Yes I can confirm it now once I tested it in GitHub integration. I'll edit my question with a solution I found in the meantime. – Ivan Vnucec Mar 04 '21 at 13:51
  • I tried to cache a folder where the built Docker image was saved and then run it like you would run any other Docker image, but I can't find the path for some reason. – Ivan Vnucec Mar 04 '21 at 14:05
  • @IvanVnucec maybe you can try https://docs.docker.com/engine/reference/commandline/save/ to save the image wherever you want it. – ITChap Mar 05 '21 at 08:00
  • I might try and once I have working solution, I will edit my question. I think that the docker/build-push-action@v2 Github Action does saving and loading implicitly (see my edited question). – Ivan Vnucec Mar 05 '21 at 12:22
  • I also had to deal with some issues related to this action in the past and I think that if you try to do more advanced stuff and need more control, you will be better off running docker commands directly or build your own composite actions. – ITChap Mar 05 '21 at 12:39