🔥Let's Do DevOps: Supercharge your build speeds with Depot (Sponsored)🔥
Join me this week as I see if we can speed up our docker builds using hosted images provided by Depot.dev!
This blog series focuses on presenting complex DevOps projects as simple and approachable via plain language and lots of pictures. You can do it!
This article is sponsored by Depot.dev. My promise to you is to only promote products I believe in, and to always be transparent in which content is sponsored. More information is on this page.
Hey all!
This week I’m investigating how to make hosted builds faster on GitHub. Or really any platform, but GitHub is where most of the code that I work with is stored at.
Depot reached out and offered me a chance to test out their new GitHub Actions Ultra Runners. Depot’s offering of hosted runners for your CI jobs has always been compelling - they offer all sorts of runners, better caching, and better compute than GitHub’s own native hosted runners, and all at half the cost of what GitHub offering comes in at.
But Ultra Runners are a new improvement, which they claim make their runners 3x faster than GitHub’s native runners for some types of jobs. These runners use a RAM Disk, which uses up to 25% of memory for ultra-fast disk operations, which is great for file-intensive tasks.
The best news of all - these Ultra Runners don’t cost anything extra, and anyone using Depot runners gets them immediately, for free, without any config changes. You can check if you’re using them at this link.
I’m a huge fan of dropping build times as much as possible - after all, if you aren’t testing your PR commits, are you really testing your code? And developers make a LOT of commits.
Depot claims that these runners are significantly faster than the native GitHub runners, and in some cases are 3x faster. Lets test these claims with some Docker build tasks I’ve built for my clients.
Let’s test them for real!
Setting Depot Runners Up
I want to register the Depot runners and run some jobs to compare how fast they are compared to GitHub’s native runners. First I checked to make sure there were no special runners in my Repo.
And then I clicked the big purple “Connect to GitHub” button. I love when companies make their products easy to use.
I clicked my personal GitHub account, and I was immediately met with an error message - I was attempting to register the runners in a personal GitHub account repo, which isn’t yet supported (I think because Depot uses a GitHub App, and GitHub individual accounts don’t support Apps). What’s great here is the detail of the error message - it’s telling me exactly what I did wrong and how to fix it. That’s pretty cool.
Much better than the “something went wrong” of other products I’ve used.
They even sent me an email with the same info in case I missed it.
I quickly created a (free!) GitHub Org of my own, which if you’re in any type of Enterprise environment, you’re already using. I tried again, and this time selected my cool new GitHub Org instead.
Depot installs their runners as a GitHub Action, which means native GitHub Org security is in play - this means you can either make the Runners available in any number of Repos, or across your entire Org.
I notably don’t see an analog for Enterprise Runners (those runners that would be available across the entire Enterprise), so if you’re interested in that you might need to contact Depot support or sales.
I give it access to a single Repo only just for fun.
And I get another error message. I’m obviously doing great at this, but again, the error message is fantastically descriptive. I set this repo as a public one, with the intention that I’d link ya’ll to it, but these runners don’t have access by default. I am provided a straight-forward method of fixing this, but also a warning on the GitHub page that doing so introduces “significant security risks.”
Me being a chicken, I decided to make the Repo I’m testing on a private one, and re-ran the job. Worked straight away.
And there’s my runner in the repo, ready to go. Cool!
How To Test
I could write different Actions that call different runners, and build different images, but comparing them would mean stare and compare between different Actions, and having to manually verify that the code I was building was the same for apples to apples comparisons.
Much easier would be to tell Actions to build the same code with different runners, and even specify building all the same images together. This pattern is often used for terraform validations in my experience, and sometimes for testing applications on different platforms, and less so for building images like this.
However, it’s great for testing. Let’s walk through how I implemented it.
First, we create a name and set `on` triggers. The workflow_dispatch trigger means it’s kicked off by hand. I don’t need CI actions triggering the build (actually, a push to master/main would be pretty cool), so we’ll leave it simple.
name: Docker Build | |
on: | |
# Build on demand | |
workflow_dispatch: |
Next we set up the job matrix. Let’s go line by line.
On line 3-4 we set a strategy. The default strategy says if any of these jobs fail, to immediately cancel the other jobs. Partially completed runs are more trouble than they save in my opinion, so I disable this wherever I can.
On line 5 we setup a matrix using two different attributes - “runner” and “image”. This says to spin off a job using every combination of these two attributes. You can find out the number of jobs with simple multiplication - (number of runner attributes, being 2) times the (number of image attributes, being 2). Ergo, 2x2 = 4 jobs total will be run on each trigger.
On line 12 we start to consume the matrix attributes. We tell the runs-on attribute, which is a GitHub Actions key that specifies which runner label pool to use, to specify the same image as we see in the “runner” matrix attribute. So half of the jobs will use the ubuntu-latest label, and half will use the depot-ubuntu-latest label.
That should give us some apples to apples comparisons! Nice.
jobs: | |
build_matrix: | |
strategy: | |
fail-fast: false | |
matrix: | |
runner: | |
- ubuntu-latest | |
- depot-ubuntu-latest | |
image: | |
- ubuntu2004-runner | |
- jekyll-build-runner | |
runs-on: ${{ matrix.runner }} |
But what is the job actually doing? Lets write the steps it’ll actually complete to build our image. Lets go line by line again.
On line 2-3 we specify to download the code for our repo. That’s important so we can access the Dockerfile with our docker build command.
On line 5 we call the docker build command from the “docker” entity on GitHub, which is the Docker organization, and we call their build-push-action. We don’t need a real push to a container registry, but this task lets us just build the imagine only if we need to.
On line 8, we set a tag, which isn’t really used, but I was having fun with matrix attribute references, and on line 9 we set the poorly named “context” of the task, which in reality means the directory where the commands are executed from. Since the code is actually in folders that are named after the matrix.image attribute, we tell it to look in that location for the files.
steps: | |
- name: Checkout Repository | |
uses: actions/checkout@v4 | |
- name: Docker Build | |
uses: docker/build-push-action@v6 | |
with: | |
tags: ${{ matrix.image }}:latest | |
context: ${{ github.workspace }}/${{ matrix.image }} |
Results
Depot, you killed it! In both tests we came out ahead using the Depot runners. That surprised me, because I expected GitHub Runners are quite a lot “closer” network-wise to the code they’re copying down, and any artifacts that code needs to run.
Test case 1: Ubuntu2004 image
GitHub Runner - 2m39s
Depot Runner - 2m7s
Winner - Depot
Improvement - 20% faster
Test case 2: Jekyll Builder image
GitHub Runner - 15m49s
Depot Runner - 12m8s
Winner - Depot
Improvement - 23.3% faster
Summary
During this article, we talked about the Runners that are available by default on GitHub Repos, and how to use them. We also logged into our fresh Depot.dev portal, and associated it to our GitHub Org.
We made the Depot GitHub Ultra Runners available on an individual Repo, and we confirmed they were there.
We wrote a GitHub Action using matrix pattern to tests in parallel the same code, so we can get an apples to apples comparison of the runner types.
We got it all working, then validated that the Depot runners are in fact faster than the GitHub hosted runners, by about 20-25%! That’s pretty awesome.
More info on Depot GitHub Ultra Runners is here, and they offer a 7 day free trial (without a credit card, even!), so you can go validate these findings yourself, or test your own builds on these faster runners.
Thanks all! Good luck out there.
kyler