Skip to main content

max / alloy

Measure the adopt verb over containers-storage, not just registry The switch section recorded c1 -> c2 over --transport registry. The update channel has the machine build its own image, so the ref is in that machine's local store and the verb is --transport containers-storage. That transport had never been exercised, and a design resting on "same verb, should carry" is resting on an argument. It carries. switch succeeds where upgrade refuses, the layer is discarded with Diff: 1 removed visible before the reboot, the rollback keeps it, and the re-layer resolves out of the new image's carried repo with the network repo disabled. Two things the run adds. The adopt is nearly free -- 69 layers already present against 4 needed totalling 6.1 kB -- so tier 2 pays for the build and not the switch. And rpm-ostree install over a non-tty ssh completes its transaction and never exits, which reads exactly like a slow depsolve; that one cost this run fifteen minutes and is written down so it costs the next one nothing.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01WFBzMprSmNCfvdj2cGZyka
Author: Max Johnson <me@maxj.phd> · 2026-09-08 01:12 UTC
Commit: 053fa796a8f2e3fa2f0ec18c8971f450b80ee43f
Parent: 7ec6821
1 file changed, +65 insertions, -0 deletions
@@ -218,6 +218,71 @@
218 218 an install" to "every rebuild anyone adopts", which is the more common case
219 219 and the one where the user has no reason to expect it.
220 220
221 + ## The transport is not a variable: `containers-storage` behaves identically
222 +
223 + The section above switched over `--transport registry`. The update channel
224 + Alloy actually ships (wiki `alloy-update-channel`) has the machine build its
225 + own image, so the ref lives in that machine's local store and the verb is
226 + `--transport containers-storage`. Measured 2026-09-07 rather than assumed,
227 + because the transport is the one variable that design changes.
228 +
229 + Same versions, same `c1` -> `c2` shape. `c2` was copied into the **guest's**
230 + containers-storage with skopeo first, which is what a local rebuild leaves
231 + behind:
232 +
233 + # skopeo copy --src-tls-verify=false \
234 + docker://10.0.2.2:5000/alloy-layertest:c2 \
235 + containers-storage:localhost/alloy-layertest:c2
236 +
237 + # bootc upgrade
238 + error: Upgrading: Deployment contains local rpm-ostree modifications;
239 + cannot upgrade via bootc.
240 +
241 + # bootc switch --transport containers-storage localhost/alloy-layertest:c2
242 + layers already present: 69; layers needed: 4 (6.1 kB)
243 + Deploying...done (2 seconds)
244 + Queued for next boot:
245 + ostree-unverified-image:containers-storage:localhost/alloy-layertest:c2
246 +
247 + Every result matches the registry leg:
248 +
249 + - **`switch` succeeds where `upgrade` refuses**, on the same layered deployment.
250 + - **The staged deployment reads `Diff: 1 removed`** before the reboot, so the
251 + discard is visible without waiting for it.
252 + - **The layer is gone after the reboot**, and the rollback keeps it:
253 +
254 + 0 booted ostree-unverified-image:containers-storage:...:c2
255 + (no packages, no requested-packages)
256 + 1 ostree-unverified-registry:...:latest
257 + packages: ['alloy-demo'] requested: ['alloy-demo']
258 +
259 + # alloy-demo
260 + alloy-demo ABSENT
261 +
262 + - **The re-layer resolves out of the new image's carried repo.** With the
263 + network repo still `enabled=0`, `rpm-ostree install -y --idempotent
264 + alloy-demo` on the switched machine adds `alloy-demo-0.0.3`, which is `c2`'s
265 + copy — not the `0.0.2` that had been layered. So the component tracks the
266 + image on this path too, and on a real machine
267 + `alloy-layer-components.service` does that re-add unprompted.
268 +
269 + **Cheaper than the registry leg, and worth knowing.** `layers needed: 4
270 + (6.1 kB)` against 69 already present: adopting a locally built image moves
271 + almost nothing, because the ostree content store already holds what the two
272 + images share. The rebuild costs build time; the adopt costs seconds.
273 +
274 + ### One harness gotcha found doing it
275 +
276 + **`rpm-ostree install` over a non-tty ssh does not exit.** The transaction
277 + completes — the journal shows `Created new deployment` and the deployment
278 + appears with its `LayeredPackages` — and the CLI client stays connected, so
279 + `sshx 'rpm-ostree install ...'` hangs forever after the work is done. It looks
280 + exactly like a slow depsolve. `rpm-ostree status` from a second session says
281 + `State: busy` with the transaction still named, which is what distinguishes it
282 + from a real stall: read the journal, and if the deployment is there, kill the
283 + client. Anything scripting this wants `ssh -tt` or a `--` wrapper rather than
284 + a longer timeout.
285 +
221 286 ## How an installed machine gets the components
222 287
223 288 **They travel on the ISO**, not over the network. That is the only shape that survives an offline install, and it keeps the no-phone-home