Show HN: Depot – fast, remote Docker container builds (depot.dev)
As application and platform engineers, we have experienced the challenge of keeping Docker container build times fast. From optimizing and reoptimizing Dockerfiles, to implementing layer caching in CI, to running & maintaining custom runners for multi-platform images.
Still today, there are limitations with the available tools. CI runners are ephemeral, and saving and loading cache tarballs is slow. CI providers are resource constrained, with limited CPUs and disk space to dedicate to fast builds. And with the increasing popularity of Arm devices like M1, Graviton, etc, building multi-platform images requires slow emulation or self-hosted infrastructure.
We created Depot to directly address those limitations. Depot provides managed VMs running BuildKit, the backing build engine for Docker. Each VM includes 4 CPUs, 8GB of memory, and a persistent 50GB SSD cache disk. We launch both native Intel and native Arm machines, on Fly.io for Intel builds and AWS for Arm.
We have built a depot CLI that embeds the Docker buildx build library, implementing the same CLI flags, so developers can send their builds to Depot VMs just by replacing `docker buildx build` with `depot build`. We also have a depot/build-push-action GitHub Action that can be swapped for docker/build-push-action in CI.
The combination of native CPUs, fast networks, and persistent disks significantly lowers build time — we’ve seen speedups of 2-3x on optimized projects, and as much as a 12x speedup with some of our customers.
We believe that today we are the only hosted CI or build service offering the ability to natively build multi-platform Docker images (--platform linux/amd64,linux/arm64) without emulation.
We are still early though, and would love your feedback.
You can sign up without a credit card at https://depot.dev/sign-up to access a free project with thirty days of unlimited build minutes to try it out.
61 comments
[ 4.2 ms ] story [ 130 ms ] threadThis is how they all scale builds, and hopefully things become more standardized with a reduction in vendor lock in. It is surprising to me how much of the world relies on moby/buildkit, and scary if you've ever looked at the code. Primarily a single developer, not straightforward to understand, comments & docs are basically non-existent. Looks like that might be starting to change with so many companies now building and SaaS'n on top of BuildKit.
Does docker compose work with this?
That works, but we've considered adding a `depot bake` command that does the same thing as `docker buildx bake`, to make the integration nicer. Ideally docker-compose would have the ability to communicate with buildx drivers (that's what Depot registers as), but to my knowledge it doesn't currently have that option.
I used it, didn’t have any issues but i realize there’s lots of reasons that might not work.
I also had in mind Docker Desktop's licensing (paid-only for certain companies), but I now realize I was conflating that with Apple Silicon when it applies to Intel Macs too IIRC.
wondering what kinds of projects are/are not suitable for this. the only context i have is from working at open source devtool companies that provide docker builds for people to pull down. might speed up the release process slightly. i suspect my company https://github.com/airbytehq/airbyte/ could benefit. but is it also useful for internal usage?
Things where Depot may not be a good fit are when you only ever need Docker images for local development. In those situations, the network becomes the bottleneck because you have to pull down the built image each time. That said, if you need to build multi-architecture images locally, Depot becomes useful again as it can build native images for each architecture, no emulation needed.
If you're entirely on-prem, we don't currently support that so Depot isn't a fit there.
CircleCI's remote docker have a restriction that only one of jobs can access same remote docker enginge at a time. Say, a job A build an image, then job B, C try to use same remote docker, but only one of them have the cache.
Google Cloud Build have no cache at all.
I don't know about GitHub Actions.
I believe Cloud Build has no persistent caching so you are forced to use remote cache saving and loading. Which can incur a network latency that can slow the build to some extent. Cloud Build with Kaniko also expires the layer cache after 6 hours by default.
GitHub Actions is similar except that there is the ability to store Docker cache using GitHub's Cache API via the `cache-to=gha` and `cache-from=gha` directives. However, this has limitations like only being able to store a total cache size of 10GB per repository. You also have network latency for loading/saving that cache as well.
With Depot, the cache is kept on a persistent disk. So no need to save/load it or incur network latency doing so. It's there ready to be used by any builds that come in for the given projects.
Do I build and then download the image to run it? Or do I have this a bit backwards and this is for build-only use-cases?
1. Just build the image — in CI that would test that the image built successfully, and the build cache would be ready for future builds. So for instance if you ran a build on a branch, but only pushed the image on the main branch workflow, the second run could just re-use the cache.
2. Build and push the image to a registry — from there you could do anything with the image in the registry (pull it from any workflow, deploy it, etc)
3. Build and pull the image to the local Docker daemon. In CI, that might be ideal for integration testing the container, like you mention.
You can also use option (2) for integration testing the container, which is especially useful with multi-platform images. Docker doesn't (yet) support storing multi-platform images locally, but it will pull the correct platform from the registry.
tl;dr — Depot supports the same options as `docker buildx build`, where you can push, pull, or just build the image depending on your needs
Dagger.io, by the originators of docker, can do this too, though it is not well documented. They have not yet enable public signups either by the looks of it.
Pretty sure I've seen some other BuildKit frontends that do as well, the space blew up this year with several startups
It would be cool to add an integration between Depot's CLI and Dagger's CLI such that Dagger could communicate with the remote builder machine. You could use Dagger with remote compute without needing to manage that compute, effectively. Depot even supports launching builders within your own AWS account, so you'd have that same ability with Dagger as well.
I struggle to think of what I would need a SaaS service to run BuildKit for me unless they're trying to take on GitHub Actions's compute side or whatever
1. Several of BuildKit's caching features either require or work best with a local disk. For instance things like `RUN --mount=type=cache` need a persistent disk, which Actions doesn't provide. You can also hit bottlenecks with saving and loading tarball cache from Actions (e.g. cache-from / cache-to) where it takes longer to download and unpack the tarballs compared to omitting the cache. Having a persistent disk makes all this "instant".
2. If you need to build images for ARM CPUs, QEMU in GitHub Actions is really slow. And if you want to build multi-platform images natively (e.g. --platform linux/amd64,linux/arm64), BuildKit needs a simultaneous connection to two native builders. Depot automates all that (it will launch two VMs at once and connect them to the build).
GitHub Actions today also only offers 2 CPUs for the build - they're launching a beta of larger machine sizes currently.
Dagger is open-source, but also has paid things if you talk to them. They are very focused on a few key users in their paid plans, rather than opening the floodgates, as I understand it.
When you start a container build with Depot, it will launch an Intel or an Arm VM running BuildKit (or both for a multi-platform image). It creates persistent SSD cache volumes for each project and attaches those to the build machines at launch. And it automates connecting your CLI to those machines over TLS. Then when the build is done, it shuts down those machines to save cost.
Depot does all that either in our cloud account, or you also have the option of connecting your own AWS account and Depot will act just as the orchestration layer.
So basically you get the remote build machines, but without needing to set them up, manage costs, configure access control, etc. But at its core, it's running the open-source version of BuildKit (the Depot CLI embeds the same Go library as `docker buildx build`).
https://nixpacks.com/docs/how-it-works
This solution sounds far easier!
arm64 builds should even be a more dramatic change, they should drop to at least as fast as your current amd64 builds.
Things that took seconds to build on my local machine were taking double-digit minutes to build in GCP. I ended up building everything with gitlab-ci using kaniko and pushing to GCR, insane speed up.
With Cloud Build, you need to use —-cache-from and other amendments to leverage remote caching. (And I believe that caching multi-stage builds require you to explicitly bush and push every stage.)
With Depot, you should in theory get all of that caching “for free”. You can also take advantage of things like BuildKit cache mounts (local directories on the host machine to cache, e.g., pip install artifacts) which AFAIK can’t be done with Cloud Build.
(No affiliation with Depot but I have played around with it.)
The first thing that comes to mind is multi-platform support. Currently, it's very slow to build multi-platform images in things like Cloud Build because you have to emulate the Arm portion of the build. We don't have timings in Cloud Build for this, but in GitHub Actions a multi-platform image build can take over an hour when building for both Intel & Arm. With Depot, those builds can take less than 5 minutes because we build the image for both architectures in parallel on native CPU architectures.
Other things where Depot might be more streamlined than Cloud Build is that persistent caching is automatic. The dedicated build machines for each architecture have persistent SSD caches attached to them, so you don't need to save/load cache in between runs, it's just there ready to be used.
It's superb. It's a drop-in replacement for `docker build` on my M1 Macbook and on GitHub Actions. I really like that they use OIDC for auth in the latter, so I don't have to provision credentials. Of course I also like that builds are 3-4x faster.
I have to admit though that the pricing model doesn't make a whole lot of sense to me. It's $25/mo/project, but what's to stop me from using one project for multiple, unrelated Docker images? It's a relatively small cost for saving me time, but it's still big enough that I have slight hesitation to spin up more projects.
We currently charge on a per project basis as behind the scenes we are provisioning and maintaining a VM with a persistent SSD cache for each architecture you are building for (i.e. Intel & Arm). We switched to usage based pricing before rolling Depot out to the public so you are only charged for your active projects and used build minutes in a month. So far it has seemed to be working well, but we are always open to feedback and ideas on how we can make pricing better.
We don't currently document this, and we probably should, but it's entirely possible to use a single Depot project for multiple Docker images. There is no limitation that prevents this and the only downside is you may fill up your cache space at a faster rate and get fewer hits if you have different image builds clobbering the cache.
How does this work if I have 5 builds for a single project at the same time?
In our current setup it takes a bit longer to boot, but concurrency is effectively unlimited. I don’t imagine that is true for Depot?
We don't limit concurrency on the builder VMs. When you create a project you are effectively getting a dedicated build VM with a persistent SSD cache for each architecture you want to build for. We run native BuildKit on the VM and connect your `depot build` directly to the builder instance via mTLS. So your concurrency is unlimited with Depot as well (or at least as unlimited as BuildKit will allow for).
So your pipeline would effectively look like this.
Here I have used `--token` for passing in a project token to authenticate the build with your project in Depot. This can also be passed as an environment variable, `DEPOT_TOKEN`.Edit: Formatting. Also thank you for pointing out this is an integration we are missing in our docs. We will get that added!
Our biggest cost at the moment is persistent disks. Each project gets its own SSD(s) that live for the lifetime of the project, and that's a major part of why Depot builds are so much faster and support BuildKit features that require persistent disks (e.g. RUN --mount=type=cache). We have some ideas for how we might improve this in the future, keeping the same or better performance profile but avoiding the continuously-provisioned disk, we'll see how that goes.
One note on "per project", each Depot project represents a pair of Intel/Arm VMs, each with a 50GB SSD. But there's otherwise no restriction on what you build using those projects, you can use a single project with multiple repos/Dockerfiles/whatever. Projects are the access control boundary, and building multiple disparate images using the same project would cycle the cache faster, but otherwise there are no limits on concurrency or what's building inside those VMs.
But maybe I'm misunderstanding the pricing?
You very well could build everything on just the single $25 project, there aren't any restrictions on concurrency or what images you build on what projects.
So when I build a project on GitHub actions, I simply add a `platforms: linux/amd64,linux/arm64` line to the Docker build & push action. This takes care of pushing the multi-arch build to GHCR for me. Would it be as straightforward in Depot as well? Or would modifying the image manifest be my only option?
Often the complexity is (or should be) in the shared base not the individual images you build per commit or PR merge.. for those simple images using something like Jib (bazel can do it too..) where it just constructs the image in user land by adding files to the tarball. I imagine this works for arm binaries from x64 too as long as you can cross compile.. how do you feel about these libraries that make simple images waaay more accessible? No docker required.
I have some ideas I want to explore with Depot, but it really it feels like it should be possible to make cross-compiling and dependency encapsulation easy to use, so "building a container image" is reduced to creating a tarball in the correct OCI format, and you don't have to interact with Dockerfiles as much if you'd prefer not.
I can totally see people using Depot bc it’s way easier and more obvious, works in the obvious way, and that is how things work today. It doesn’t challenge you to think, why the hell do I need a super privileged process with magic Dockerfile incantations just to take a tar of files and add another file to it? With some metadata? Docker has created some weird defaults.