docs(research): evaluate debian-slim vs alpine for base image (#8) #15

Merged
haylan merged 2 commits from research/glibc-slim-alternative into main 2026-08-06 22:41:52 +00:00
4 changed files with 52 additions and 194 deletions
Showing only changes of commit 516b61018e - Show all commits
+10 -6
View File
@@ -9,9 +9,9 @@ on:
inputs:
godot_version:
description: >-
Godot version to (re)build, e.g. 4.7.1 — must exist as a
barichello/godot-ci tag (https://hub.docker.com/r/barichello/godot-ci/tags).
Leave empty to build the newest stable, same as the nightly run.
Godot version to (re)build, e.g. 4.7.1 — must exist as a stable release at
https://github.com/godotengine/godot-builds/releases. Leave empty to build
the newest stable, same as the nightly run.
required: false
type: string
@@ -40,12 +40,16 @@ jobs:
UPDATE_LATEST=true
fi
if ! docker manifest inspect "barichello/godot-ci:${VERSION}" >/dev/null 2>&1; then
# This image no longer depends on barichello/godot-ci as a base — it downloads Godot
# directly from godot-builds' own GitHub releases (see Dockerfile), so the gate here
# is against *that* release existing, not a third party's Docker tag.
RELEASE_URL="https://github.com/godotengine/godot-builds/releases/download/${VERSION}-stable/Godot_v${VERSION}-stable_linux.x86_64.zip"
if ! curl -fsSL -o /dev/null -r 0-0 "$RELEASE_URL"; then
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "::error::No barichello/godot-ci tag for '${VERSION}'. Check https://hub.docker.com/r/barichello/godot-ci/tags"
echo "::error::No godot-builds stable release for '${VERSION}'. Check https://github.com/godotengine/godot-builds/releases"
exit 1
fi
echo "::notice::Newest Godot stable is ${VERSION} but barichello/godot-ci has no matching tag yet — skipping, will retry tomorrow."
echo "::notice::Newest Godot stable is ${VERSION} but its godot-builds release isn't up yet — skipping, will retry tomorrow."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
+28 -9
View File
@@ -1,16 +1,25 @@
# GODOT_VERSION selects the barichello/godot-ci base tag (Godot 4.0+ only — see
# docs/handoff/godot-ci-custom-image.md). BLENDER_URL is the tarball to bake in;
# GODOT_VERSION is a stable Godot release tag (e.g. "4.7.1", no "-stable" suffix — Godot 4.0+
# only, see docs/handoff/godot-ci-custom-image.md). BLENDER_URL is the tarball to bake in.
# .gitea/workflows/publish.yml always resolves both at build time via
# scripts/resolve-godot-version.sh and scripts/resolve-blender-url.sh. The
# defaults below are only a fallback for a plain local `docker build`.
# scripts/resolve-godot-version.sh and scripts/resolve-blender-url.sh. The defaults below are
# only a fallback for a plain local `docker build`.
#
# Godot itself is downloaded straight from its official GitHub releases (godot-builds), the same
# source barichello/godot-ci's own Dockerfile uses — this image no longer depends on that image
# as a base. Decided via wayfinder map https://git.arthurerlich.de/haylan/godot-ci/issues/2,
# ticket https://git.arthurerlich.de/haylan/godot-ci/issues/7: Alpine was considered and rejected
# (official Godot/Blender binaries are glibc-only, and Alpine's musl-native alternatives live
# only on its unpinned `edge` repo); a plain glibc-slim base doesn't cost the compatibility risk.
ARG GODOT_VERSION=4.7.1
FROM barichello/godot-ci:${GODOT_VERSION}
FROM debian:bookworm-slim
ARG GODOT_VERSION
ARG BLENDER_URL=https://download.blender.org/release/Blender4.2/blender-4.2.3-linux-x64.tar.xz
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl unzip xz-utils \
libfontconfig1 \
build-essential scons pkg-config xz-utils curl \
build-essential scons pkg-config \
libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev \
libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev libwayland-dev \
mingw-w64 \
@@ -21,9 +30,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
&& update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix \
&& update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix \
&& rm -rf /var/lib/apt/lists/* \
# Blender is not bundled in barichello/godot-ci, and Ubuntu's apt package lags
# (stuck on 4.0.2 on noble) — install the resolved tarball straight from
# download.blender.org instead of `apt-get install blender`.
# Godot editor + export templates, straight from the official release (same URL shape
# barichello/godot-ci's own Dockerfile uses) — stable releases only, matching what
# scripts/resolve-godot-version.sh resolves.
&& curl -fsSLO "https://github.com/godotengine/godot-builds/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" \
&& curl -fsSLO "https://github.com/godotengine/godot-builds/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_export_templates.tpz" \
&& mkdir -p "/root/.local/share/godot/export_templates/${GODOT_VERSION}.stable" \
&& unzip -q "Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" \
&& mv "Godot_v${GODOT_VERSION}-stable_linux.x86_64" /usr/local/bin/godot \
&& unzip -q "Godot_v${GODOT_VERSION}-stable_export_templates.tpz" \
&& mv templates/* "/root/.local/share/godot/export_templates/${GODOT_VERSION}.stable/" \
&& rm -rf "Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" "Godot_v${GODOT_VERSION}-stable_export_templates.tpz" templates \
# Blender is not bundled anywhere here — install the resolved tarball straight from
# download.blender.org instead of an apt package.
&& curl -fsSL "$BLENDER_URL" -o /tmp/blender.tar.xz \
&& mkdir -p /opt/blender \
&& tar -xJf /tmp/blender.tar.xz -C /opt/blender --strip-components=1 \
+14 -6
View File
@@ -1,9 +1,17 @@
# godot-ci
Custom image extending `barichello/godot-ci` with the Godot export-template toolchain and Blender
A `debian:bookworm-slim`-based image with Godot, its export-template toolchain, and Blender
pre-installed, so `Project4x`'s `export-template.yml` doesn't `apt-get install` them on every
release run.
Godot is downloaded directly from its official [godot-builds
releases](https://github.com/godotengine/godot-builds/releases) rather than from a base image —
this repo previously extended `barichello/godot-ci` (Ubuntu-based) but moved off it to shed that
dependency's weight. Alpine was considered and rejected first: official Godot and Blender
binaries are glibc-only, and Alpine's musl-native alternatives for both live only on its unpinned
`edge` repo — not a safe bet for a nightly-rebuilding image. See [wayfinder map
#2](https://git.arthurerlich.de/haylan/godot-ci/issues/2) for the full research trail.
Built from the handoff spec at `Project4x`'s `docs/handoff/godot-ci-custom-image.md`; scope and
versioning have since moved on from that spec — see below.
@@ -22,13 +30,13 @@ this image's Blender toolchain).
- **Nightly (midnight, `schedule:`)**: resolves the newest *stable* Godot release
(`scripts/resolve-godot-version.sh`) and the newest stable Blender
(`scripts/resolve-blender-url.sh`), and rebuilds+pushes `<version>` + `latest` only if that
Godot version isn't already published. If `barichello/godot-ci` hasn't tagged the new Godot
version yet, the run skips (with a notice, not a failure) and retries the next night.
Godot version isn't already published. If godot-builds hasn't published that release's assets
yet, the run skips (with a notice, not a failure) and retries the next night.
- **Manual (`workflow_dispatch`)**: type a Godot version (e.g. `4.6.3`) to (re)build and push that
exact tag, always with whatever Blender is newest at build time. Overwrites the tag if it
already exists. Does **not** touch `latest`. Fails clearly if `barichello/godot-ci` has no
matching tag — check
[its tag list](https://hub.docker.com/r/barichello/godot-ci/tags) first.
already exists. Does **not** touch `latest`. Fails clearly if godot-builds has no matching
release — check its [releases list](https://github.com/godotengine/godot-builds/releases)
first.
Blender has no official "latest stable" API — `resolve-blender-url.sh` scrapes
`download.blender.org/release/`. `scripts/test-lib.sh` is an offline smoke test for the parsing
-173
View File
@@ -1,173 +0,0 @@
# Handoff spec: custom godot-ci image
Status: **done, and superseded** — the `godot-ci` repo this spec asked for exists and is built.
Its versioning has since moved past what's written below: instead of one Dockerfile pinned to
`4.7.1`, it now auto-tracks the newest stable Godot (4.0+) and newest stable Blender on a nightly
schedule, with a manual `workflow_dispatch` to (re)build any specific version. See that repo's
`README.md` for the current behavior; this file is kept for the original problem statement and
scope rationale, not as a source of truth on tags/versions. Decided via wayfinder map
[#158](https://git.arthurerlich.de/haylan/Project4x/issues/158), ticket
[#162](https://git.arthurerlich.de/haylan/Project4x/issues/162).
## Problem
`export-template.yml`'s `export` job runs in `barichello/godot-ci:4.7.1` and, on every single run,
`apt-get install`s a from-source Godot export-template toolchain before it can build anything. That
install is pure dead time repeated on every release. A custom image extending
`barichello/godot-ci:4.7.1` with the toolchain pre-installed removes it.
## What this spec is for
A fresh Gitea agent session, given only this file, must be able to:
1. Create a new repo.
2. Add a `Dockerfile` and a publish workflow to it.
3. Get the image published to that repo's Gitea package (container) registry.
4. Report back the final image reference so `export-template.yml` here can be pointed at it.
No other context from this repo should be required.
## Scope: what goes in the image
Everything `export-template.yml`'s "Update and install dependencies" step currently
`apt-get install`s, unconditionally (all of it — see [Decisions](#decisions) below for why the
narrower alternative was rejected):
```
libfontconfig1
build-essential scons pkg-config xz-utils curl
# Linux leg:
libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev \
libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev libwayland-dev
# Windows leg:
mingw-w64
# + these two update-alternatives calls, baked in at image build time:
update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix
update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
# conditionally, when ENABLE_BLENDER is on:
blender
```
Current source of truth for this list: `.gitea/workflows/export-template.yml` in
`haylan/Project4x`, "Update and install dependencies" step. **Re-check that step before building**
— it may have drifted since this spec was written.
### What stays out of the image
- **The SCons object cache** (`.scons_cache`, restored via `actions/cache@v3` keyed on
`scons-${GODOT_VERSION}-${artifact_name}`). This is build _state_, not a package — baking it into
the image would pin it to image-build time instead of the actual release run, going stale
immediately.
- **`nsis` / `osslsigncode`.** These do NOT belong in this image. They run in `release.yml`'s
`create-release` job, which is a plain `ubuntu-latest` runner — it does not use
`barichello/godot-ci` or any container at all. (Earlier drafts of this ticket assumed they were
part of the export container's toolchain; that was wrong. The NSIS installer has since been
removed entirely — see ADR 0001's superseded note — so only `osslsigncode`/`zip` remain in
`create-release`, and neither is expensive enough to justify its own image.)
## Registry path and versioning
- **Registry:** this Gitea instance's container/package registry (`git.arthurerlich.de`), scoped
to the new repo you create — Gitea packages are per-repo/owner, so the path is
`git.arthurerlich.de/haylan/<new-repo-name>`.
- **Tag:** pin to the Godot version only, e.g. `git.arthurerlich.de/haylan/<new-repo-name>:4.7.1`.
This mirrors `barichello/godot-ci`'s own tag scheme and `Project4x`'s `GODOT_VERSION` env var. A
Godot version bump in `Project4x` means building and pushing a new tag here too — that coupling
is intentional, not an oversight.
- Pick `<new-repo-name>` yourself (e.g. `godot-ci-toolchain` or similar); it isn't fixed by this
spec.
## Auth: PAT required
Confirmed for this Gitea instance: `GITEA_TOKEN` (the automatic per-run Actions token) **cannot**
push to the package/container registry. The new repo's publish workflow needs a **Personal Access
Token** stored as a repo secret (e.g. `REGISTRY_PUSH_PAT`).
- **Scope needed:** `write:package` (add `read:package` too if the publish workflow ever needs to
pull the image back, e.g. to test it before tagging `latest`).
- Generate it from the account that should own the published packages, under
Settings → Applications → Generate New Token, with only that scope checked.
- Document the token's owner/scope in the new repo's README once created — this repo
(`Project4x`) has no record of it and shouldn't need one; the coupling is one-way
(`Project4x` only ever pulls the finished image, never pushes to it).
## Dockerfile skeleton
```dockerfile
FROM barichello/godot-ci:4.7.1
RUN apt-get update && apt-get install -y --no-install-recommends \
libfontconfig1 \
build-essential scons pkg-config xz-utils curl \
libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev \
libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev libwayland-dev \
mingw-w64 \
blender \
&& update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix \
&& update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix \
&& rm -rf /var/lib/apt/lists/*
```
Notes for whoever builds this:
- `blender` is baked in unconditionally here even though `Project4x`'s `ENABLE_BLENDER` flag is
currently `"false"` — the image can't cheaply branch on a flag it doesn't know about at build
time, and the package is small next to the rest of this list. If that turns out to add
meaningful image size/pull time for a project that never flips the flag on, split into a second
`-blender` tagged variant instead.
- Combine into one `RUN` (as above) so it's a single image layer — no benefit to splitting these
across layers here.
## Publish workflow skeleton
New repo, `.gitea/workflows/publish.yml`:
```yaml
name: Publish godot-ci image
on:
push:
branches: [main]
paths: [Dockerfile]
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Log in to Gitea registry
run: echo "${{ secrets.REGISTRY_PUSH_PAT }}" | docker login git.arthurerlich.de -u <owner-username> --password-stdin
- name: Build and push
run: |
docker build -t git.arthurerlich.de/haylan/<new-repo-name>:4.7.1 .
docker push git.arthurerlich.de/haylan/<new-repo-name>:4.7.1
```
Fill in `<owner-username>` and `<new-repo-name>` once the repo exists.
## How `Project4x` would then reference the new image
One-line change in `.gitea/workflows/export-template.yml`:
```diff
- container: barichello/godot-ci:4.7.1
+ container: git.arthurerlich.de/haylan/<new-repo-name>:4.7.1
```
The "Update and install dependencies" step's `apt-get install` calls for the baked-in packages
become redundant at that point (harmless no-ops — `apt-get install` on an already-installed
package is a fast no-op, so removing them is a cleanup, not a correctness requirement) and can be
trimmed in a follow-up ticket once the image is live and proven.
## Decisions
- **Bake-in scope:** everything in the current apt-get list, not a narrower "slow packages only"
subset — keeps the image and `export-template.yml`'s toolchain description in exact sync, so
there's only one place (this spec + the Dockerfile) to update when the list changes, instead of
maintaining a second smaller list that drifts from the first.
- **Tag scheme:** pinned to `GODOT_VERSION` rather than tracking image/toolchain revisions
independently — simpler to reason about, and this repo's own SCons cache is already keyed the
same way, so a Godot bump already forces everything else to rebuild in lockstep.