Skip to content

Commit 7c5782b

Browse files
authored
Merge pull request #29 from jandubois/shrink-qcow2-image
Shrink distro artifacts via external xz and build-time cleanup
2 parents c706030 + 27d539f commit 7c5782b

11 files changed

Lines changed: 151 additions & 22 deletions

File tree

.dockerignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
distro.tar.xz
2-
distro.qcow2
2+
distro.qcow2.xz
3+
distro.raw.xz

.github/workflows/build.yaml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,16 @@ jobs:
2121
- type: tar.xz
2222
arch: arm64
2323
runs-on: ubuntu-24.04-arm
24-
- type: qcow2
24+
- type: raw.xz
2525
arch: amd64
2626
runs-on: ubuntu-latest
27-
- type: qcow2
27+
- type: raw.xz
28+
arch: arm64
29+
runs-on: ubuntu-24.04-arm
30+
- type: qcow2.xz
31+
arch: amd64
32+
runs-on: ubuntu-latest
33+
- type: qcow2.xz
2834
arch: arm64
2935
runs-on: ubuntu-24.04-arm
3036
env:

.github/workflows/release.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ jobs:
2323
run: |
2424
set -o errexit -o nounset -o xtrace
2525
for arch in amd64 arm64; do
26-
mv distro-qcow2-${arch}/distro.qcow2 distro.${GITHUB_REF_NAME}.${arch}.qcow2
27-
rmdir distro-qcow2-${arch}/
26+
mv distro-raw.xz-${arch}/distro.raw.xz distro.${GITHUB_REF_NAME}.${arch}.raw.xz
27+
rmdir distro-raw.xz-${arch}/
28+
mv distro-qcow2.xz-${arch}/distro.qcow2.xz distro.${GITHUB_REF_NAME}.${arch}.qcow2.xz
29+
rmdir distro-qcow2.xz-${arch}/
2830
mv distro-tar.xz-${arch}/distro.tar.xz distro.${GITHUB_REF_NAME}.${arch}.tar.xz
2931
rmdir distro-tar.xz-${arch}/
3032
done
31-
for f in distro.*.{qcow2,tar.xz}; do
33+
for f in distro.*.{raw.xz,qcow2.xz,tar.xz}; do
3234
sha256sum "$f" > "$f.sha256"
3335
done
3436
- name: Create release
@@ -40,6 +42,6 @@ jobs:
4042
--verify-tag
4143
--repo ${{ github.repository }}
4244
"${GITHUB_REF_NAME}"
43-
distro.*.{qcow2,tar.xz}{,.sha256}
45+
distro.*.{raw.xz,qcow2.xz,tar.xz}{,.sha256}
4446
env:
4547
GH_TOKEN: ${{ github.token }}

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/root/build/
2-
*.qcow2
2+
*.qcow2.xz
3+
*.raw.xz
34
*.tar.xz

Dockerfile

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,16 @@ RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/g
1818
go build -ldflags '-s -w' -o /go/bin/rd-init .
1919

2020
FROM registry.opensuse.org/opensuse/bci/kiwi:10 AS builder
21-
ARG type=qcow2
21+
ARG type=qcow2.xz
2222
ARG NERDCTL_VERSION
23+
# The BCI kiwi image ships /etc/kiwi.yml with mapper and runtime_checks
24+
# settings required for building inside Docker. Append xz -0 so kiwi
25+
# does not waste time on compression we discard and recompress at
26+
# xz -9 --extreme in Makefile.docker. Using --config would replace the
27+
# existing file and lose the mapper setting, breaking loop devices.
2328
RUN --mount=type=cache,target=/var/cache/zypp \
24-
zypper --non-interactive install parted
29+
zypper --non-interactive install parted && \
30+
echo -e '\nxz:\n - options: '\''-0'\''' >> /etc/kiwi.yml
2531
WORKDIR /build
2632
COPY . /description
2733
COPY --from=gobuild /go/bin/* /description/root/usr/local/bin/
@@ -32,4 +38,4 @@ RUN --security=insecure \
3238
make -C /description -f Makefile.docker TYPE=${type}
3339

3440
FROM scratch
35-
COPY --from=builder /build/*.qcow2 /build/*.tar.xz /
41+
COPY --from=builder /build/*.raw.xz /build/*.qcow2.xz /build/*.tar.xz /

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ include root/build/versions.env
55
GO ?= $(or $(shell which go.exe),$(shell which go))
66
GOARCH ?= $(shell $(GO) env GOARCH)
77
GOOS ?= $(shell $(GO) env GOOS)
8-
TYPE ?= $(if $(filter windows,$(GOOS)),tar.xz,qcow2)
8+
TYPE ?= $(if $(filter windows,$(GOOS)),tar.xz,raw.xz)
99

10-
# Default target is either `distro.qcow2` or `distro.tar.xz`
10+
# Default target is either `distro.raw.xz` or `distro.tar.xz`
1111
distro.$(TYPE):
1212

1313
DOWNLOADS += root/build/nerdctl-$(NERDCTL_VERSION).tgz
@@ -35,4 +35,4 @@ distro.%: $(DOWNLOADS) $(IMAGE_FILES)
3535
--platform=linux/$(GOARCH) --output=. --build-arg=type=$* .
3636

3737
clean:
38-
rm -f distro.tar.xz distro.qcow2 $(DOWNLOADS)
38+
rm -f distro.tar.xz distro.qcow2.xz $(DOWNLOADS)

Makefile.docker

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
include root/build/versions.env
44

5-
TYPE ?= qcow2
5+
TYPE ?= raw.xz
66
ARCH ?= $(shell uname -m)
77

88
/build/distro.${TYPE}:
@@ -12,18 +12,41 @@ GO_ARCH := $(GO_ARCH:aarch64=arm64)
1212

1313
INPUTS += root/build/nerdctl-$(NERDCTL_VERSION).tgz
1414

15-
rancher-desktop-distro.%.qcow2: config.kiwi config.sh ${INPUTS}
15+
rancher-desktop-distro.%.raw: config.kiwi config.sh ${INPUTS}
1616
kiwi --debug --profile=lima system build \
1717
--description /description --target-dir /build
1818

1919
rancher-desktop-distro.%.tar.xz: config.kiwi config.sh ${INPUTS}
2020
kiwi --debug --profile=wsl system build \
2121
--description /description --target-dir /build
2222

23-
/build/distro.qcow2: /build/rancher-desktop-distro.$(ARCH)-0.100.0.qcow2
24-
mv $< $@
25-
23+
# Post-kiwi cleanup, then produce the requested output format.
24+
#
25+
# clean-rootfs.sh loop-mounts the raw disk, removes grub2 build tools
26+
# and other build-time artifacts, then fstrim's the filesystem so freed
27+
# blocks become holes. It runs here rather than in pre_disk_sync.sh
28+
# because kiwi re-invokes grub2-mkconfig on the mounted disk after that
29+
# hook.
30+
#
31+
# raw.xz — for macOS/VZ: qemu and VZ both consume raw directly.
32+
# qcow2.xz — for Linux/qemu: internally zstd-compressed, then
33+
# xz-compressed for storage/transfer.
34+
/build/distro.raw.xz: /build/rancher-desktop-distro.$(ARCH)-0.100.0.raw
35+
./clean-rootfs.sh $<
36+
xz -9 --extreme --stdout $< > $@
37+
38+
/build/distro.qcow2: /build/rancher-desktop-distro.$(ARCH)-0.100.0.raw
39+
./clean-rootfs.sh $<
40+
qemu-img convert -c -f raw $< -O qcow2 -o compression_type=zstd,compat=1.1 $@
41+
42+
/build/distro.qcow2.xz: /build/distro.qcow2
43+
xz -9 --extreme --stdout $< > $@
44+
45+
# Recompress the tarball kiwi leaves behind. Kiwi runs xz in threaded
46+
# mode with 24 MiB blocks, which loses a meaningful chunk of ratio to
47+
# block boundaries; a single xz -9 --extreme pass is ~14% smaller.
2648
/build/distro.tar.xz: /build/rancher-desktop-distro.$(ARCH)-0.100.0.tar.xz
27-
mv $< $@
49+
xz --decompress --stdout $< | xz -9 --extreme > $@
2850

51+
.INTERMEDIATE: /build/distro.qcow2
2952
.DELETE_ON_ERROR: # Avoid half-downloaded files

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ Desktop.
55

66
The distribution is built using `docker`:
77
```sh
8-
make TYPE=qcow2 # For Linux/darwin hosts
9-
make TYPE=tar.xz # For WSL hosts
8+
make TYPE=raw.xz # For macOS/VZ hosts (default)
9+
make TYPE=qcow2.xz # For Linux/qemu hosts
10+
make TYPE=tar.xz # For WSL hosts
1011
```
1112

1213
To cross-compile for a non-native architecture, set `GOARCH` to the target

clean-rootfs.sh

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env bash
2+
3+
# Post-kiwi cleanup of the root filesystem inside a raw disk image.
4+
# Called from Makefile.docker after kiwi has finished writing the raw
5+
# disk (including grub2-mkconfig). Shared by the raw.xz and qcow2.xz
6+
# build targets.
7+
#
8+
# Usage: ./clean-rootfs.sh /path/to/raw-disk.img
9+
10+
set -o errexit
11+
12+
RAW=$1
13+
14+
LOOP=$(losetup --find --show "$RAW")
15+
kpartx -as "$LOOP"
16+
17+
# Find the ext4 root partition. The layout differs between amd64
18+
# (p1=bios-boot, p2=EFI, p3=root) and arm64 (p1=EFI, p2=root).
19+
ROOT=
20+
for p in /dev/mapper/"$(basename "$LOOP")"p*; do
21+
[ "$(blkid -o value -s TYPE "$p" 2>/dev/null)" = ext4 ] || continue
22+
ROOT=$p
23+
break
24+
done
25+
: ${ROOT:?Failed to find ext4 partition in $RAW}
26+
27+
MNT=$(mktemp -d)
28+
mount "$ROOT" "$MNT"
29+
30+
# grub2 build/install tools. The EFI bootloader and runtime grub modules
31+
# in /boot/grub2 are already in place; these commands are not invoked
32+
# again. Keep grub2-editenv for grubenv management.
33+
find "$MNT/usr/bin" "$MNT/usr/sbin" -maxdepth 1 -name 'grub2-*' \
34+
! -name 'grub2-editenv' -delete
35+
36+
# Config files only read by grub2-mkconfig, which we just removed.
37+
rm -rf "$MNT/etc/grub.d" "$MNT/etc/default/grub"
38+
39+
# /usr/share/grub2/<arch>-efi is the factory copy of the grub modules
40+
# that grub2-install replicated into /boot/grub2/<arch>-efi.
41+
rm -rf "$MNT/usr/share/grub2"/*-efi
42+
rm -f "$MNT/usr/share/grub2"/*.pf2
43+
rm -rf "$MNT/usr/share/grub2/grub-mkconfig_lib" "$MNT/usr/share/grub2/themes"
44+
45+
sync
46+
47+
# Discard freed blocks so they become holes in the backing raw file.
48+
# qemu-img and xz both benefit from this.
49+
fstrim "$MNT"
50+
51+
umount "$MNT"
52+
rmdir "$MNT"
53+
kpartx -d "$LOOP"
54+
losetup --detach "$LOOP"

config.kiwi

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@
101101
<package name="systemd-resolved" />
102102
<package name="grub2-x86_64-efi" arch="x86_64" />
103103
</packages>
104+
<packages type="delete" profiles="lima">
105+
<!-- Pulled in by cni-plugin-flannel but we use k3s's embedded flannel
106+
daemon, so the standalone flanneld binary is dead weight. -->
107+
<package name="flannel" />
108+
</packages>
104109
<users>
105110
<user pwdformat="plain" password="suse" home="/root" name="root" groups="root" />
106111
</users>

0 commit comments

Comments
 (0)