Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Blame · docs/reference/image-reference.md

Line attribution on main · 236 line(s)

70b70264
Keenan Nemetz
15d ago
1 # Image reference
2
3 This page lists every field Vole accepts in a `.vole/images/*.yaml` definition,
4 with its defaults and limits. For how workflows reference these definitions, see
5 [Workflow reference § image-file](workflow-reference.md#image-file). For the
6 task-oriented introduction, see [Workflows § Images](../workflows.md#images).
7
8 Unknown keys are rejected. Every definition under `.vole/images/` is parsed when a
9 workflow is pushed, even if no job references it, so a broken definition fails the
10 push that introduced it.
11
12 ## File location and limits
13
14 | Item | Value |
15 |---|---|
16 | Location | Directly under `.vole/images/`; subdirectories are rejected |
17 | Extension | `.yaml` or `.yml` |
18 | Reference | `image-file: <name>`; the extension is optional in the reference |
19 | Maximum file size | 64 KiB |
20 | Schema version | `1` |
21 | Maximum `env` entries | 64 |
22 | Maximum `run` entries | 100 |
23 | Maximum single command size | 64 KiB after trimming |
24 | Maximum env value size | 8 KiB |
25
26 A definition is named by its filename without the extension:
27
28 ```text
29 .vole/images/go.yaml -> image-file: go
30 .vole/images/go.yml -> image-file: go
31 .vole/images/release.yaml -> image-file: release
32 ```
33
34 Names are 1–64 characters: lowercase letters, digits, `.`, `_` and `-`, starting
35 with a letter or digit. Two files for one name (`go.yaml` and `go.yml`) are
36 rejected as ambiguous.
37
38 ## Top-level fields
39
40 | Field | Type | Required | Default | Meaning |
41 |---|---|---|---|---|
42 | `version` | integer | yes | — | Schema version. Must be `1`. |
6bfc4294
Keenan Nemetz
12d ago
43 | `from` | string | yes | — | Base OCI image. A tag works; a digest (`image@sha256:...`) makes the build reproducible. |
70b70264
Keenan Nemetz
15d ago
44 | `env` | mapping | no | none | Environment variables set in the image. |
45 | `run` | list of strings | no | none | Build commands, applied in order. |
46
47 ```yaml
48 version: 1
49 from: golang:1.27-bookworm
50 env:
51 CGO_ENABLED: "0"
52 run:
53 - apt-get update && apt-get install -y --no-install-recommends jq
54 - go install example.com/tool@v1.2.3
55 ```
56
57 ### `version`
58
59 The only supported value is `1`:
60
61 ```yaml
62 version: 1
63 ```
64
65 ### `from`
66
67 The base image for the definition. It uses the same image-reference validation as
68 `image:` in a workflow:
69
70 - Must be non-empty and at most 255 bytes.
71 - Must start with a letter or digit.
72 - May contain letters, digits, `.`, `_`, `/`, `:`, `@`, `+`, `~` and `-`.
73 - A leading `-`, `..`, `://`, or a `file:` prefix is rejected.
74
75 ```yaml
76 from: golang:1.27-bookworm@sha256:...
77 ```
78
79 Pin the base image by digest when reproducibility matters. A mutable tag can
80 change what a later build produces.
81
82 ### `env`
83
84 A mapping of environment variable names to values, applied to the image:
85
86 ```yaml
87 env:
88 CGO_ENABLED: "0"
89 MESSAGE: "hello world"
90 ```
91
92 | Constraint | Value |
93 |---|---|
94 | Maximum entries | 64 |
95 | Key syntax | `^[A-Za-z_][A-Za-z0-9_]*$` |
96 | Maximum value size | 8 KiB |
97 | Line endings | Values must be one line; `CR`/`LF` are rejected |
98
99 Keys are emitted in sorted order, so the generated build is deterministic.
100
101 ### `run`
102
103 Build commands, run in order after `from` and `env`:
104
105 ```yaml
106 run:
107 - apt-get update && apt-get install -y --no-install-recommends jq
108 - go install example.com/tool@v1.2.3
109 ```
110
111 | Constraint | Value |
112 |---|---|
113 | Maximum entries | 100 |
114 | Empty commands | Rejected |
115 | Maximum size | 64 KiB after trimming |
116 | Line endings | One line; `CR`/`LF` are rejected |
117 | Shell | Each command runs through `/bin/sh -c` |
118
119 Chain commands with `&&` rather than using multiple lines:
120
121 ```yaml
122 run:
123 - apt-get update && apt-get install -y --no-install-recommends git make
124 ```
125
126 `run` entries are rendered as Dockerfile exec-form instructions:
127
128 ```dockerfile
129 RUN ["/bin/sh", "-c", "apt-get update && apt-get install -y --no-install-recommends git make"]
130 ```
131
132 That keeps the first word of a command from being interpreted as a Dockerfile
133 build flag such as `--network=host`.
134
135 ## What the definition can and cannot express
136
137 The format deliberately supports only `from`, `env`, and `run`. It does not
138 support:
139
140 - `COPY`, `ADD`, or a build context from the repository
141 - multi-stage builds
142 - `ARG`
143 - `WORKDIR`, `USER`, `ENTRYPOINT`, `CMD`, `HEALTHCHECK`, or `SHELL`
144 - build secrets or host mounts
145
146 The runner controls the job's working directory (`/workspace`), user, entrypoint,
147 and mounts. The image supplies the toolchain and the shell.
148
149 The image build uses the runtime's default network. `--container-network` applies
150 to the job container, not to the image build. The builder has no host mounts and
151 no build secrets from Vole.
152
153 ## Execution and caching
154
155 The runner renders the definition to a Dockerfile:
156
157 ```dockerfile
158 FROM <from>
159 ENV KEY="value"
160 RUN ["/bin/sh", "-c", "<command>"]
161 ...
162 ```
163
164 It builds that image with the configured OCI runtime and tags it by the SHA-256 of
165 the exact definition file. A later job with the same definition reuses the tag.
166 `--container-pull always` rebuilds a custom image even when the tag exists.
167
168 An image definition is code: its build runs on the runner through the OCI builder,
169 so approving a contributor tip that changes a definition also approves that build.
170 Use rootless Podman where possible.
171
172 The resulting job image must contain `/bin/sh` and a POSIX `sleep`, because Vole
173 runs each step with `/bin/sh -c` and keeps the container alive between steps. If
174 `run` is non-empty, the base image used for `from` must also provide `/bin/sh`,
175 because build commands are rendered that way.
176
3b39a84c
Keenan Nemetz
14d ago
177 Nothing a job writes inside the container survives the run, except what it puts in
178 the cache: the runner mounts a directory at `/cache` and sets no variables for it,
179 so `env` is where a definition opts in. Point the toolchain's own variables at it
180 and its downloads are reused between jobs:
181
182 ```yaml
183 env:
184 GOMODCACHE: "/cache/go-mod"
185 GOCACHE: "/cache/go-build"
186 ```
187
188 A job may also set its own `env`, which is applied after the image's and wins; it
189 is the way to point at `/cache` when the image is a registry reference rather than a
190 definition. `/tmp` is a memory-backed tmpfs and `HOME` points there for everything
191 else; the XDG convention (`XDG_CACHE_HOME: /cache/xdg`) covers tools that follow it.
192 See [Runners § Caching](../runner.md#caching).
193 Check that anything calling `getpwuid` has a passwd entry for the uid the job runs
194 as — see [Runners § How a job runs](../runner.md#how-a-job-runs).
195
70b70264
Keenan Nemetz
15d ago
196 ## Validation and pinning
197
198 - `version` must be `1`.
199 - Unknown keys are errors.
200 - The definition must live directly under `.vole/images/`, not in a subdirectory.
201 - Both `.yaml` and `.yml` are accepted, but not two files for the same name.
202 - Every definition is parsed at push time, even if unreferenced.
203 - The exact definition text and its digest are pinned with each run.
204 - `--container-pull always` rebuilds instead of reusing the digest tag.
205
206 ## Complete example
207
208 ```yaml
209 # .vole/images/release-toolchain.yaml
210 version: 1
211 from: golang:1.27-bookworm@sha256:...
212 env:
213 CGO_ENABLED: "0"
214 SOURCE_DATE_EPOCH: "0"
215 run:
216 - apt-get update && apt-get install -y --no-install-recommends git make jq
217 - go install example.com/release-tool@v1.4.0
218 ```
219
220 ```yaml
221 # .vole/workflows/release.yaml
222 version: 1
223 on:
224 push:
225 tags: ["v*"]
226 jobs:
227 release:
228 runs-on: [linux, amd64]
229 image-file: release-toolchain
230 steps:
231 - name: build
232 run: make dist
233 artifacts:
234 - path: dist/*
235 release: true
236 ```