Repository navigation
Expand file tree
/
Copy pathContainerfile.debian
More file actions
374 lines (345 loc) · 18.1 KB
/
Copy pathContainerfile.debian
File metadata and controls
374 lines (345 loc) · 18.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# Containerfile.debian — Debian bootcification.
#
# Builds a bootc-compatible Debian image from stock debian:trixie or
# debian:sid. Based on bootcrew/mono/debian pattern.
#
# Usage:
# buildah build --build-arg BASE_IMAGE=docker.io/library/debian:trixie \
# --target=kde --file Containerfile.debian .
ARG BASE_IMAGE="docker.io/library/debian:trixie@sha256:9c6e381421d0f48d1b8133e573f33c185ee16cbf505eda9c4a8a4791b25ea8a6"
ARG COMMON_IMAGE_REF="ghcr.io/projectbluefin/common:unpinned-must-override"
ARG DESKTOP_FLAVOR="${DESKTOP_FLAVOR:-gnome}"
ARG TUNAOS_IMAGE_FLAVOR
ARG IMAGE_NAME
ARG IMAGE_VENDOR
ARG SHA_HEAD_SHORT
ARG ENABLE_SSHD="${ENABLE_SSHD:-0}"
ARG IMAGE_REGISTRY="ghcr.io"
ARG IMAGE_NAME_VARIANT
# ── Fetch the prebuilt bootc toolchain ────────────────────────────────────────
# bootc + bootupd (+ libostree/composefs on trixie) are built from source by
# .github/workflows/build-toolchain.yml and published to
# ghcr.io/tuna-os/bootc-toolchain-<base> as a public OCI artifact (oras). Pull it
# here instead of recompiling bootc on every variant build. See
# toolchain/Containerfile.debian and image-versions.yaml (Renovate-pinned).
FROM ${BASE_IMAGE} AS bootc-builder
ARG BASE_IMAGE
ARG ORAS_VERSION=1.2.0
ARG ORAS_SHA256_AMD64=5b3f1cbb86d869eee68120b9b45b9be983f3738442f87ee5f06b00edd0bab336
ARG ORAS_SHA256_ARM64=27df680a39fc2fcedc549cb737891623bc696c9a92a03fd341e9356a35836bae
ARG TARGETARCH
ARG BOOTC_VERSION
RUN apt-get update -y && \
apt-get install -y --no-install-recommends curl ca-certificates tar gzip && \
case "${TARGETARCH}" in \
amd64) ORAS_SHA256="${ORAS_SHA256_AMD64}" ;; \
arm64) ORAS_SHA256="${ORAS_SHA256_ARM64}" ;; \
*) echo "Unsupported ORAS architecture: ${TARGETARCH}" >&2; exit 1 ;; \
esac && \
curl -fsSL "https://github.com/oras-project/oras/releases/download/v${ORAS_VERSION}/oras_${ORAS_VERSION}_linux_${TARGETARCH}.tar.gz" -o /tmp/oras.tar.gz && \
echo "${ORAS_SHA256} /tmp/oras.tar.gz" | sha256sum -c - && \
tar -xzf /tmp/oras.tar.gz -C /usr/local/bin oras && \
rm -f /tmp/oras.tar.gz && \
case "${BASE_IMAGE}" in *sid*) TC=sid ;; *) TC=trixie ;; esac && \
mkdir -p /fetch /output && cd /fetch && \
oras pull "ghcr.io/tuna-os/bootc-toolchain-${TC}:${BOOTC_VERSION}-${TARGETARCH}" && \
tar -xzf toolchain.tar.gz -C /output && \
rm -rf /fetch
# ── Context layer ────────────────────────────────────────────────────────────
FROM scratch AS context
COPY system_files /files
COPY system_files_overrides /overrides
COPY build_scripts /build_scripts
COPY manifests /manifests
COPY tunaos.toml /tunaos.toml
# Only Tuna's curated files: install-desktop.sh applies experiences/<desktop>
# whenever it is present, and the other desktops' trees are not part of the
# apt images today.
COPY experiences/tuna /experiences/tuna
COPY image-versions.yaml /image-versions.yaml
FROM ${COMMON_IMAGE_REF} AS common
# ── Base system (bootc-compatible Debian) ────────────────────────────────────
FROM ${BASE_IMAGE} AS base-no-de
ARG BASE_IMAGE
ARG IMAGE_NAME
ARG IMAGE_VENDOR
ARG IMAGE_NAME_VARIANT
ARG SHA_HEAD_SHORT
ARG ENABLE_SSHD
ARG DESKTOP_FLAVOR
ARG TUNAOS_IMAGE_FLAVOR
ENV TUNAOS_IMAGE_FLAVOR=${TUNAOS_IMAGE_FLAVOR}
ARG IMAGE_REGISTRY
ARG TUNAOS_PUBLISHED_IMAGE_REF
ENV BASE_IMAGE=${BASE_IMAGE}
ENV IMAGE_NAME=${IMAGE_NAME}
ENV IMAGE_VENDOR=${IMAGE_VENDOR}
ENV IMAGE_NAME_VARIANT=${IMAGE_NAME_VARIANT}
ENV IMAGE_REGISTRY=${IMAGE_REGISTRY}
ENV TUNAOS_PUBLISHED_IMAGE_REF=${TUNAOS_PUBLISHED_IMAGE_REF}
ENV ENABLE_SSHD=${ENABLE_SSHD}
ENV DESKTOP_FLAVOR=${DESKTOP_FLAVOR}
# Install the bootc toolchain (bootc + bootupd [+ source libostree/composefs on
# trixie]) from the fetch stage.
COPY --from=bootc-builder /output /
# libostree: sid ships one new enough (>=2025.3), so install the packaged libs.
# trixie's packaged libostree (2025.2) is too old and would conflict with the
# source libostree already placed by the toolchain COPY above — so instead
# provide an equivs dummy libostree-1-1 (Snow Linux trick) to satisfy apt deps
# (flatpak etc.) without pulling the old lib, and register the source libs.
RUN apt-get update -y && \
case "${BASE_IMAGE}" in \
*sid*) DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends libostree-1-1 ostree ;; \
*) DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends equivs && \
printf 'Package: libostree-1-1\nVersion: 99:0\nArchitecture: %s\nMaintainer: TunaOS <build@tunaos.org>\nDescription: satisfied by source libostree from bootc-toolchain\n' "$(dpkg --print-architecture)" > /tmp/libostree.ctl && \
( cd /tmp && equivs-build libostree.ctl && dpkg -i libostree-1-1_*.deb ) && \
apt-mark hold libostree-1-1 && ldconfig ;; \
esac
# Install base system packages
#
# systemd-cryptsetup ships /usr/bin/systemd-cryptenroll on trixie and sid — NOT
# the systemd package, verified against the trixie file list. fisherman requires
# it on the installing host and aborts before touching the disk without it:
#
# fatal: missing required host tool: "systemd-cryptenroll" not found in PATH
# — install the "systemd" package on the host
#
# That hint is Fedora-shaped and misleading here: systemd is already in the list
# below. This killed flounder:kde in LUKS run 31060069809 after the image, the
# ISO and the live boot had all succeeded.
#
# The package name is release-specific, so do NOT copy it elsewhere without
# checking: Ubuntu noble ships the binary in systemd and has no
# systemd-cryptsetup at all, and assuming otherwise broke gurnard (run
# 31061160416). This Containerfile only ever builds trixie and sid, where the
# split package is correct; the assertion after the install is what makes a
# future move fail loudly instead of silently.
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
btrfs-progs \
dosfstools \
e2fsprogs \
fdisk \
firmware-linux-free \
linux-image-generic \
skopeo \
podman \
# The Debian/Ubuntu bootc bases ship no sudo, unlike the Fedora/EL
# ones. customize-live.sh writes a NOPASSWD sudoers drop-in for
# liveuser on dev ISOs, which authorises nothing without the binary —
# every `sudo` in the E2E guest then dies with "command not found"
# (tunaOS#953 defect 3 on sailfin, again on grouper). The assertion in
# customize-live.sh now catches its absence at ISO-build time.
sudo \
systemd \
# systemd-boot alone resolves its EFI binary to the signed
# systemd-boot-efi-amd64-signed on trixie and sid, which ships only
# systemd-bootx64.efi.signed. Corral's bootc backend probe looks for
# the plain systemd-bootx64.efi that systemd-boot-efi ships;
# without it `corral bootc create` of flounder:tuna-sid fell back to
# the ostree backend and died on "bootupd is required for ostree-based
# installs". Containerfile.ubuntu already names both packages.
systemd-boot \
systemd-boot-efi \
xfsprogs \
dracut \
dmsetup \
squashfs-tools \
cryptsetup \
systemd-cryptsetup \
network-manager \
pipewire \
wireplumber \
flatpak \
fwupd \
plymouth \
power-profiles-daemon \
curl \
unzip \
git \
ca-certificates \
# dracut's tpm2-tss module is part of the default module set on this
# base, and dracut treats a requested-but-unsatisfiable module as fatal
# rather than skipping it:
#
# dracut[E]: Module 'tpm2-tss' cannot be installed.
#
# That is an ISO-build failure, not an image one — tacklebox rebuilds
# the initramfs against the published image to inject tbox-live and
# tbox-root, and its omit-detection only drops a module whose
# modules.d directory is ABSENT. Debian ships the directory and not
# the userspace, so the module is requested and cannot be installed.
#
# flounder:kde is green and flounder:gnome died here (run 31071849261)
# purely because the Plasma package set happens to pull enough of the
# tss2 stack in transitively. Naming it makes that an intent rather
# than an accident.
#
# Containerfile.ubuntu already installs exactly this list, with the
# same reasoning, and Debian never got it. Installing the userspace is
# the right resolution rather than omitting the module: LUKS
# auto-unlock is enrolled post-install, so the initramfs has to be able
# to talk to the TPM when that happens.
#
# The t64 suffixes are the 64-bit time_t transition. Verified against
# the trixie AND sid binary indexes — the unsuffixed names exist in
# neither.
tpm2-tools libtss2-tcti-device0t64 libtss2-tctildr0t64 \
libtss2-rc0t64 libtss2-esys-3.0.2-0t64 && \
# Assert the binary, not the package. fisherman aborts before touching the
# disk without it, and which package ships it is not stable across releases
# (trixie: systemd-cryptsetup; Ubuntu noble: systemd). Failing here names
# the problem; failing in fisherman surfaces 40 minutes later inside a VM.
if ! command -v systemd-cryptenroll >/dev/null 2>&1; then \
echo "ERROR: systemd-cryptenroll missing after install." >&2; \
echo " fisherman needs it to enrol the LUKS TPM2 keyslot and aborts without it." >&2; \
exit 1; \
fi && \
apt-get clean -y
RUN --mount=type=bind,from=context,source=/,target=/run/context \
bash -c "source /run/context/build_scripts/lib.sh && source /run/context/build_scripts/10-base-packages.sh"
RUN --mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/20-packages.sh && \
/run/context/build_scripts/30-image-packages.sh
# remora — the desktop experience contract requires it, and this base does
# not run 26-packages-post.sh, which is what installs remora on the dnf
# variants. Containerfile.opensuse already hit this and calls
# install-remora.sh directly for the same reason (see the comment there).
# Without it every Gate on this base fails with
#
# TUNAOS_DESKTOP_CONTRACT_FAIL reason=remora_contract_missing
#
# which reads as a broken desktop when the desktop booted fine — grouper gnome,
# kde, xfce and gnome-zfs all died this way in run 30692866756. The binary is
# static Go, so there is nothing distro-specific to guard.
RUN --mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/install-remora.sh
# Copy kernel to modules directory (Debian puts it in /boot). Debian sid's
# kernel package now installs /usr/lib/modules/<kver>/vmlinuz itself, as the
# same file as /boot/vmlinuz-<kver>, and `cp` exits 1 when asked to copy a file
# onto itself ("are the same file"). That failed every flounder-sid build
# (tunaOS#2616). Copy only when the destination is missing or differs.
RUN dest="$(find /usr/lib/modules -maxdepth 1 -type d | tail -1)/vmlinuz" && \
for src in /boot/vmlinuz-*; do \
cmp -s "$src" "$dest" || cp "$src" "$dest"; \
done && \
test -s "$dest"
# Set up bootc/ostree filesystem layout. The shared layout (the /var wipe, the
# alias symlinks, tmpfiles.d and prepare-root.conf) lives in ostree-layout.sh;
# what stays here is the dpkg relocation, which must bracket it — the copy out
# of /var before the wipe, the tmpfiles link back after it.
#
# NOTE: this MUST precede the dracut step below. dracut-config.sh derives the
# driver set from prepare-root.conf, which ostree-layout.sh writes, so building
# the initramfs first would read no composefs declaration and silently produce
# one with no erofs driver — an image that cannot mount its own root.
RUN --mount=type=bind,from=context,source=/,target=/run/context \
# Move the dpkg database out of /var BEFORE the wipe below, or the image
# ships with no record of its own packages.
#
# /var/lib/dpkg is where dpkg keeps `status`, and the wipe on the next
# line takes it. That is not a TunaOS quirk — every Debian/Ubuntu bootc
# image does this (bootcrew/ubuntu-bootc: `rm -rf ... /var`), and the
# result is measurable: ghcr.io/tuna-os/flounder:base answers
# `dpkg-query -W` with zero packages and has no `status` file anywhere.
# A running flounder box therefore cannot enumerate its own packages,
# which blinds remora layering, update tooling and support diagnostics
# (tuna-os/tunaos-packages#135).
#
# Fedora hit the identical problem with rpm and solved it by relocating
# the database into /usr, where it belongs anyway: the package database
# describes /usr, and keeping it there means it snapshots and rolls back
# with the image (Changes/RelocateRPMToUsr). Same move here.
#
# The tmpfiles symlink below points /var/lib/dpkg back at it, so dpkg,
# apt and dpkg-query all keep working through their default paths with no
# --admindir plumbing.
mkdir -p /usr/lib/sysimage && \
if [ -d /var/lib/dpkg ]; then cp -a /var/lib/dpkg /usr/lib/sysimage/dpkg; fi && \
/run/context/build_scripts/bootc/ostree-layout.sh && \
# apt keeps its own log directory under the wiped /var.
mkdir -p /var/log/apt && \
# Restore the dpkg database path at runtime. L+ replaces whatever is
# there, so a /var reset re-establishes the link rather than leaving apt
# pointing at an empty directory. /var/lib must be created first —
# tmpfiles does not build parents for L+.
printf 'd /var/lib 0755 root root -\nd /var/log/apt 0755 root root -\nL+ /var/lib/dpkg - - - - ../../usr/lib/sysimage/dpkg\n' \
> /usr/lib/tmpfiles.d/dpkg-sysimage.conf && \
# Image-build time too: apt/dpkg run in later layers (and in
# live_customize) before tmpfiles has ever executed.
mkdir -p /var/lib && ln -sfnT ../../usr/lib/sysimage/dpkg /var/lib/dpkg
# Build initramfs. Live-boot modules are NOT needed here: tacklebox
# injects its own embedded tbox-live/tbox-root dracut modules at ISO
# build time using this image's stock dracut (tuna-os/tacklebox#90).
# dracut config comes from build_scripts/bootc/dracut-config.sh, shared with
# every other bootc variant — it derives the driver set from the image rather
# than from a printf that has to be kept in sync by hand.
RUN --mount=type=bind,from=context,source=/,target=/run/context \
KVER=$(basename "$(find /usr/lib/modules -maxdepth 1 -mindepth 1 -type d | tail -1)") && \
/run/context/build_scripts/bootc/dracut-config.sh "${KVER}" && \
dracut --force "/usr/lib/modules/${KVER}/initramfs.img" "${KVER}"
LABEL containers.bootc 1
COPY --from=context /files /
COPY --from=common /system_files/shared /
# Run the standard numbered base scripts (matching el10/arch/ubuntu convention):
# 40-services (service enablement, dconf), 90-image-info (branding/os-release),
# 99-cleanup (ostree prep). Without these, flounder ships upstream Debian
# identity and fails the branding contract.
RUN --mount=type=tmpfs,dst=/tmp \
--mount=type=tmpfs,dst=/boot \
--mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/40-services.sh
RUN --mount=type=tmpfs,dst=/tmp \
--mount=type=tmpfs,dst=/boot \
--mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/90-image-info.sh
RUN --mount=type=tmpfs,dst=/tmp \
--mount=type=tmpfs,dst=/boot \
--mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/99-cleanup.sh
# Same COPY of projectbluefin/common's shared tree as Containerfile.ubuntu, so
# the same signature-policy exposure: it pins sigstore requirements with
# `keyPaths`, which only skopeo >= 1.14 parses. trixie's skopeo is new enough
# today and noble's is not — that is a version accident, not a property of
# apt, so validate here too rather than waiting for the accident to change.
RUN --mount=type=tmpfs,dst=/tmp \
--mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/bootc/containers-policy.sh
RUN bootc container lint
# Cache-bust so build_scripts edits invalidate the desktop stages' install
# layers (bind-mounted scripts aren't in the cache key). Inherited by children.
ARG BUILD_SCRIPTS_HASH
ENV BUILD_SCRIPTS_HASH=${BUILD_SCRIPTS_HASH}
# ==============================================================================
# Desktop stages — manifest-driven
# ==============================================================================
FROM base-no-de AS base
RUN ln -sf /var/opt /opt 2>/dev/null || true
FROM base-no-de AS gnome
COPY --from=common /system_files/bluefin /
RUN --mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/desktop/install-desktop.sh gnome
RUN ln -sf /var/opt /opt 2>/dev/null || true
FROM base-no-de AS kde
RUN --mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/desktop/install-desktop.sh kde
RUN ln -sf /var/opt /opt 2>/dev/null || true
FROM base-no-de AS cosmic
RUN --mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/desktop/install-desktop.sh cosmic
RUN ln -sf /var/opt /opt 2>/dev/null || true
FROM base-no-de AS niri
RUN --mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/desktop/install-desktop.sh niri
RUN ln -sf /var/opt /opt 2>/dev/null || true
FROM base-no-de AS xfce
RUN --mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/desktop/install-desktop.sh xfce
RUN ln -sf /var/opt /opt 2>/dev/null || true
# Tuna Desktop (tuna-os/tuna-desktop ADR 0008, epic #577; tunaOS#3207 for
# sid). tuna-desktop comes from the signed Tideforge apt index for the base's
# Debian suite, declared in manifests/desktops/tuna.yaml.
FROM base-no-de AS tuna
RUN --mount=type=bind,from=context,source=/,target=/run/context \
/run/context/build_scripts/desktop/install-desktop.sh tuna
RUN ln -sf /var/opt /opt 2>/dev/null || true