DEV Community

Discussion on: Caching Docker builds in GitHub Actions: Which approach is the fastest? 🤔 A research.

Collapse
 
sagikazarmark profile image
Márk Sági-Kazár

Thanks a lot for this article and the research!

I've spent some time on the topic as well and I thought I'd share my thoughts/findings here.

tl;dr Using buildx with GitHub cache yields the same (or sometimes even better) results and it's probably a better alternative in case of a multi-stage build which is quite common these days.

As someone already pointed out before, the official Docker build actions changed significantly since this article was released. Namely, they split up the action into smaller ones (they separated login and some setup actions) and added buildx support.

I added a buildx example using GitHub's cache action to the linked repository based on the official buildx cache example: github.com/dtinth/github-actions-d...

After running it a couple times, it turned out to be as fast as the GitHub Package Registry approach. To be completely fair: I couldn't actually run the GPR example myself, because it became outdated since GitHub introduced the new Container Registry, but I compared it to the numbers posted in this article.

So it looks like using buildx with GitHub cache can be a viable alternative.

Further thinking about the method used to compare the different approaches I came to the following theories:

  • In case of a multi-stage build the GitHub Package Registry approach probably falls short from the buildx+GH cache approach (probably from others as well), because it only caches the final stage
  • Using ${{ hashFiles('Dockerfile') }} might have an adverse effect on performance when using GH cache: Dockerfiles usually don't change, but code and dependencies do, so relying on the Dockerfile in the cache key will result in invalid caches most of the time. When working with large caches, downloading the cache itself takes time as well which is a waste of time when the cache is invalid. This is why the official example uses SHA with a fallback instead. Builds for the same SHA will always be fast. When no cache is found, the latest cache matching the fallback key will be used.

I haven't actually verified these thoughts, hence they are just theories, but I strongly suspect they are correct, so take them into account when choosing a caching strategy.

Last, but not least: as I pointed out above, the Docker Package Registry example became outdated. See this announcement blog post for more details.

Collapse
 
valentijnscholten profile image
valentijnscholten

To test out the potential gain, I tried running docker-compose build
on DEV Community’s repository. Without any caching, building the
web image took 9 minutes and 5 seconds. Using GitHub Package
Registry as a cache, the time to build the image has reduced to 37
seconds.

Great article and replies. At the risk of sounding stupid: How do you get docker-compose to use the cache? It doesn't have a --cache-from option.