Skip to content

Commit 0d12afa

Browse files
PedroGuerraPTgithub-actions[bot]
authored andcommitted
Update docs content from https://github.com/depot/app
1 parent 21fc552 commit 0d12afa

File tree

1 file changed

+202
-0
lines changed

1 file changed

+202
-0
lines changed
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
# Build parallelism in Depot
2+
3+
Depot uses BuildKit under the hood, which features a fully concurrent build graph solver that can run build steps in parallel when possible and optimize out commands that don't have an impact on the final result. This means that independent build stages, layers, and even separate builds can execute simultaneously. Understanding how parallelization works across different scenarios helps you structure your builds for maximum efficiency and speed.
4+
5+
## Choosing the right build configuration
6+
7+
Before diving into how parallelism works, it's important to understand the optimal build configuration for your workload. Depot offers several configuration options to balance performance, cache utilization, and resource allocation based on your specific needs.
8+
9+
**Configuration decision matrix:**
10+
11+
| Workload type | Recommended configuration | Reasoning |
12+
| ---------------------------------------- | ----------------------------------------------------------- | ----------------------------------------- |
13+
| Frequent small builds | Larger builder instance, no auto-scaling | Better cache utilization |
14+
| Resource-intensive builds | Auto-scaling with Builds per instance = 2-3 | Each build gets full resources |
15+
| Mixed workloads | Use separate projects per target | Balance between isolation and cache |
16+
| Monorepo with shared dependencies (Bake) | Enable auto-scaling and/or use separate projects per target | Balance deduplication with resource needs |
17+
18+
## Parallelism scenarios
19+
20+
### 1. One build per project
21+
22+
When you run a single build in a Depot project, parallelism occurs at multiple levels:
23+
24+
#### Stage-level parallelism
25+
26+
If BuildKit sees that a stage depends on other stages which do not depend on each other, then it will run those stages in parallel. Consider this Dockerfile:
27+
28+
```dockerfile
29+
FROM node:20 AS frontend
30+
WORKDIR /app
31+
COPY frontend/ .
32+
RUN npm install && npm build
33+
34+
FROM golang:1.21 AS backend
35+
WORKDIR /app
36+
COPY backend/ .
37+
RUN go build -o server
38+
39+
FROM alpine AS final
40+
COPY --from=frontend /app/dist /static
41+
COPY --from=backend /app/server /usr/bin/
42+
```
43+
44+
Build execution flow:
45+
46+
![Stage level parallelism](/images/docs/stage-level-parallelism.excalidraw.svg)
47+
48+
In this example, the `frontend` and `backend` stages run in parallel since they don't depend on each other. The `final` stage waits for both to complete.
49+
50+
#### Multi-platform parallelism
51+
52+
When building for multiple platforms (e.g., `linux/amd64` and `linux/arm64`), Depot runs native builders for each architecture in parallel. Each platform executes on its own dedicated build server with native CPU architecture, which enables true parallel builds at native speed.
53+
54+
```bash
55+
# Builds for both platforms simultaneously on separate native servers
56+
depot build --platform linux/amd64,linux/arm64 .
57+
```
58+
59+
![Multi-platform build architecture](/images/docs/multi-platform-build-architecture.excalidraw.svg)
60+
61+
### 2. Multiple builds per project
62+
63+
Each Depot project has dedicated BuildKit runners, with one runner per architecture by default. For example, if you're building for both `linux/amd64` and `linux/arm64`, you get two runners. All builds on the same architecture share that architecture's runner, enabling BuildKit to handle concurrent builds efficiently, whether they're for the same image or different images.
64+
65+
![Multiple concurrent builds on same builder](/images/docs/multiple-concurrent-builds.excalidraw.svg)
66+
67+
This shared runner architecture enables several optimizations:
68+
69+
**Same image, multiple builds:**
70+
When multiple builds of the same image run concurrently (e.g., different developers pushing to the same branch), BuildKit can:
71+
72+
- Share cached layers across all builds
73+
- Deduplicate identical work happening simultaneously
74+
- Reduce overall build time through shared computation
75+
76+
**Different images, shared dependencies:**
77+
When building different images that share common dependencies:
78+
79+
- Base images are pulled once and shared
80+
- Common layers (like `npm install` or `apt-get update`) are computed once
81+
- BuildKit automatically identifies and shares identical work
82+
83+
#### BuildKit deduplication
84+
85+
BuildKit's deduplication is a key optimization that automatically identifies and eliminates redundant work. BuildKit uses checksums to identify identical layers and operations through content-addressable storage. The build graph solver identifies duplicate work before execution, and when multiple stages need the same layer, it's built once and shared. Examples of deduplication include the following:
86+
87+
- Multiple stages using the same base image only pull it once
88+
- Repeated `RUN` commands with identical inputs are executed once
89+
- Common file copies across stages are cached and reused
90+
91+
![BuildKit deduplication within a build](/images/docs/buildkit-deduplication.excalidraw.svg)
92+
93+
```dockerfile
94+
FROM node:20 AS deps
95+
COPY package*.json ./
96+
RUN npm ci # This layer is built once
97+
98+
FROM node:20 AS deps
99+
COPY package*.json ./
100+
RUN npm ci # Reuses the layer from Service A if cache is warm
101+
```
102+
103+
In the preceding example, if both stages have identical `package.json` files, BuildKit recognizes that the `npm ci` command will produce the same result. Instead of running it twice, it executes once and reuses the cached layer for the second stage, saving build time and resources.
104+
105+
This cache-based deduplication happens automatically across concurrent builds on the same runner, for builds triggered in any of the following ways:
106+
107+
- Multiple `depot build` commands
108+
- `depot bake` with multiple targets
109+
- Parallel CI/CD jobs
110+
- Multiple developers building simultaneously the same Dockerfile
111+
112+
**Waiting for shared layers**
113+
114+
When the same instruction is being built multiple times on the same runner, you may notice delays even with high cache hit rates. The delay is due to BuildKit's step deduplication process: one build computes the step while others wait for it to complete. This process prevents redundant work but can cause apparent delays. Subsequent builds show as "waiting" even though they'll benefit from the computed result.
115+
116+
![Cross-build deduplication timeline](/images/docs/cross-build-deduplication-timeline.excalidraw.svg)
117+
118+
When Build A starts building at 10:00 AM, it pulls the base image and runs `npm ci`, creating new layers. When Build B starts building just a minute later at 10:01 AM, BuildKit recognizes that it needs the same base image and has the same `npm ci` command. Instead of duplicating this work, Build B waits for Build A to complete those steps, then reuses the layers that Build A created.
119+
120+
The deduplication process generally improves overall efficiency, but can be confusing when monitoring individual build times. To avoid overwhelming a single build server, you can enable [build auto-scaling](./how-to-guides/autoscaling) to some particular maximum parallelism value.
121+
122+
#### Docker Bake for orchestrated builds
123+
124+
Docker Bake provides a declarative way to build multiple images with a single command, taking full advantage of BuildKit's parallelism. By default, all Bake targets run on the same builder, which maximizes cache sharing and deduplication but means all targets share the same resources.
125+
126+
Here's an example `docker-bake.hcl` configuration:
127+
128+
```hcl
129+
group "default" {
130+
targets = ["app", "db", "cron"]
131+
}
132+
133+
target "base" {
134+
dockerfile = "Dockerfile.base"
135+
tags = ["myrepo/base:latest"]
136+
project-id = "project-base"
137+
}
138+
139+
target "app" {
140+
contexts = {
141+
base = "target:base"
142+
}
143+
dockerfile = "Dockerfile.app"
144+
platforms = ["linux/amd64", "linux/arm64"]
145+
tags = ["myrepo/app:latest"]
146+
project-id = "project-app"
147+
}
148+
149+
target "db" {
150+
contexts = {
151+
base = "target:base"
152+
}
153+
dockerfile = "Dockerfile.db"
154+
platforms = ["linux/amd64", "linux/arm64"]
155+
tags = ["myrepo/db:latest"]
156+
project-id = "project-db"
157+
}
158+
159+
target "cron" {
160+
contexts = {
161+
base = "target:base"
162+
}
163+
dockerfile = "Dockerfile.cron"
164+
platforms = ["linux/amd64", "linux/arm64"]
165+
tags = ["myrepo/cron:latest"]
166+
project-id = "project-cron"
167+
}
168+
```
169+
170+
When you run `depot bake`, all three services (`app`, `db`, `cron`) build concurrently for both architectures. With the `project-id` parameters specified, each target gets its own dedicated builder with separate resources. The base image is built once on its own project and the result is shared across the other targets via the contexts configuration.
171+
172+
![Bake: Shared project vs separate projects](/images/docs/bake-shared-project-vs-separate-projects.excalidraw.svg)
173+
174+
### 3. Auto-scaling enabled
175+
176+
With build auto-scaling enabled, Depot will automatically spin up additional BuildKit builders when the concurrent build limit is reached. By default, all builds for a project are routed to a single BuildKit host per architecture you're building. When the concurrent build limit is reached, Depot provisions additional builders. Each additional builder operates on a clone of the main builder's layer cache.
177+
178+
![Auto-scaling behavior](/images/docs/auto-scaling-behavior.excalidraw.svg)
179+
180+
Benefits:
181+
182+
- Each build gets dedicated resources (CPU, memory, I/O)
183+
- No resource contention between builds
184+
- Consistent, predictable build times
185+
- Better for resource-intensive builds
186+
187+
Trade-offs:
188+
189+
- Additional builders operate on cache clones that are not written back to the main cache, meaning work done on additional builders must be recomputed when subsequent builds run on the main builder
190+
- Builds on different builders cannot share work, even if they have similar layers
191+
192+
#### Configuration
193+
194+
For detailed instructions on enabling and configuring auto-scaling, see the [Auto-scaling documentation](./how-to-guides/autoscaling).
195+
196+
**Poor cache performance with auto-scaling**
197+
198+
Cache misses are expected behavior with cache clones. Consider if the speed benefit outweighs cache efficiency. Try the following solutions for poor cache performance:
199+
200+
- Increase **Builds per instance** in your **Autoscaling** settings
201+
- Use a larger single instance instead of scaling out
202+
- If building multiple different images, consider using a separate Depot project for each image to isolate their caches and runners

0 commit comments

Comments
 (0)