How to cache docker-compose build inside github-action
G

5

26

Is there any way to cache docker-compose so that it will not build again and again? here is my action workflow file:

name: Github Action
on:
  push:
    branches:
      - staging
jobs:
  test:
    runs-on: ubuntu-18.04

    steps:
      - uses: actions/checkout@v1

      - name: Bootstrap app on Ubuntu
        uses: actions/setup-node@v1
        with:
          node-version: '12'


      - name: Install global packages
        run: npm install -g yarn prisma


      - name: Install project deps
        if: steps.cache-yarn.outputs.cache-hit != 'true'
        run: yarn


      - name: Build docker-compose
        run: docker-compose -f docker-compose.test.prisma.yml up --build -d

I want to cache the docker build step. I have tried using if: steps.cache-docker.outputs.cache-hit != 'true' then only build but didn't work.

Gromyko answered 28/4, 2020 at 23:8 Comment(0)
A
12

What you are referring to is called "docker layer caching", and it is not yet natively supported in GitHub Actions.

This is discussed extensively in several places, like:

As mentioned in the comments, there are some 3rd party actions that provide this functionality (like this one), but for such a core and fundamental feature, I would be cautious with anything that is not officially supported by GitHub itself.

Aghast answered 29/4, 2020 at 14:46 Comment(4)
so, it is not possible to do with github action now?Gromyko
What about github.com/satackey/action-docker-layer-caching?Fluorspar
I tried that one, but it can't work with sha's for images.Staffordshire
docker's build-push-action does not support layer caching for docker-compose directly: github.com/docker/build-push-action/issues/128 But there is a workaround that I haven't tested yet: github.com/docker/build-push-action/issues/150Sanchez
D
17

This question is old, but I found myself trying to solve precisely the same problem. After reading many different answers and spending lots of time, I eventually found a decent solution.

My workflow file now looks like this:

jobs:
  build:
    name: Integration tests
    runs-on: ubuntu-22.04
    # I need "packages: write" to access GHCR.
    # More about permissions here: https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
    permissions: write-all
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Login to Docker Registry
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - uses: actions/checkout@v2

      - name: Build docker-compose
        # Before the cache, it was "run: docker compose build".
        run: docker buildx bake --file docker-compose.yml --file docker-compose-cache.json

...

And in the docker-compose-cache.json file, I have the following:

{
  "target": {
    "service-name": {
      "cache-from": [
        "type=registry,ref=ghcr.io/MY_GITHUB_ORG_NAME/service-name:cache"
      ],
      "cache-to": [
        "type=registry,ref=ghcr.io/MY_GITHUB_ORG_NAME/service-name:cache"
      ],
      "output": [
        "type=docker"
      ]
    }
  }
}

For each service in docker-compose.yml, I add a target in docker-compose-cache.json. docker buildx bake takes build instructions from docker-compose.yml and cache instructions from docker-compose-cache.json.

This way, I can still use docker-compose up --build locally as usual.

As you may note, I'm using the GitHub container registry instead of the GitHub actions cache because GHCR has no limitation for cache size.

Deemster answered 23/2, 2023 at 11:20 Comment(2)
Perfect, exactly what I needed! This is the best answer.Pilar
If you struggle with "File not found", you might like this post, which proposes to use --set *.context=. as flag for docker buildx bake.Synapsis
A
12

What you are referring to is called "docker layer caching", and it is not yet natively supported in GitHub Actions.

This is discussed extensively in several places, like:

As mentioned in the comments, there are some 3rd party actions that provide this functionality (like this one), but for such a core and fundamental feature, I would be cautious with anything that is not officially supported by GitHub itself.

Aghast answered 29/4, 2020 at 14:46 Comment(4)
so, it is not possible to do with github action now?Gromyko
What about github.com/satackey/action-docker-layer-caching?Fluorspar
I tried that one, but it can't work with sha's for images.Staffordshire
docker's build-push-action does not support layer caching for docker-compose directly: github.com/docker/build-push-action/issues/128 But there is a workaround that I haven't tested yet: github.com/docker/build-push-action/issues/150Sanchez
S
12

For those arriving here via Google, this now "supported". Or at least it is working: https://github.community/t/use-docker-layer-caching-with-docker-compose-build-not-just-docker/156049. The idea is to build the images using docker (and its cache) and then use docker compose to run (up) them.

Staffordshire answered 18/1, 2021 at 16:47 Comment(0)
C
3

If using docker/bake-action or docker/build-push-action & want to access a cached image in subsequent steps -

  • Use load:true to save the image
  • Use the same image name as the cached image across steps in order to skip rebuilds.

Example:

...
        name: Build and push
        uses: docker/bake-action@master
        with:
          push: false
          load: true
        set: |
            web.cache-from=type=gha
            web.cache-to=type=gha
      -
        name: Test via compose
        command: docker compose run web tests
...
services:
  web:
    build:
      context: .
    image: username/imagename
    command: echo "Test run successful!"

See the docker team's responses;

Cristobalcristobalite answered 19/8, 2022 at 8:55 Comment(0)
A
2

If you want to cache only the layers, not the whole images

This answer builds on top of what the user byte said and relates to several other questions.

It is suited for situations where you only want to cache the layers, but not push actual images to a registry. I.e. when you want to use cache type=gha (see Docker Documentation), like recommended in many places. I use this style for temporary images like integration testing images that I don't need to store to a registry, but still want to cache.

  build:
    permissions:
      id-token: write
      contents: read

    name: "Prebuild docker images"
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Cache Docker layers
        uses: docker/bake-action@master
        with:
          push: false
          load: true
          files: |-
            docker-compose.yml
            docker-compose-cache.json

docker-compose-cache.json, replace <GH_ORG>, <REPO> and <SERVICE> with your own references. The scope does not strictly need to match any of those, any unique string is fine.

{
    "target": {
      "service-name": {
        "cache-from": [
          "type=gha,scope=<GH_ORG>/<REPO>/<SERVICE>"
        ],
        "cache-to": [
          "type=gha,mode=max,scope=<GH_ORG>/<REPO>/<SERVICE>"
        ],
        "output": [
          "type=docker"
        ]
      },
   }
}
Aarika answered 11/3 at 7:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.