Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Dockerfile for CirrOS build environment
#
# Build image:
# docker build -t cirros-builder .
#
# Run (--privileged is required for loop mounts inside bin/bundle):
# docker run --privileged --rm \
# -v "$PWD":/cirros \
# -v cirros-dl:/cirros/download \
# -v cirros-ccache:/cirros/ccache \
# cirros-builder daily
#
# Build a specific tagged release:
# docker run --privileged --rm \
# -v "$PWD":/cirros \
# -v cirros-dl:/cirros/download \
# -v cirros-ccache:/cirros/ccache \
# cirros-builder 0.3.2
#
# Build only x86_64:
# docker run --privileged --rm \
# -e ARCHES=x86_64 \
# -v "$PWD":/cirros \
# -v cirros-dl:/cirros/download \
# -v cirros-ccache:/cirros/ccache \
# cirros-builder daily

FROM ubuntu:22.04

LABEL description="CirrOS image build environment (Ubuntu 22.04 / Buildroot 2022.02.4)"

ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=UTC
ENV USER=root

# ── All build dependencies ────────────────────────────────────────────────────
# system-setup DEPS + CI extras + tools used implicitly (cpio, kmod, binutils, sudo)
RUN apt-get update && apt-get install -y --no-install-recommends \
# system-setup DEPS
bc \
bison \
build-essential \
dosfstools \
flex \
gdisk \
gettext \
git \
grub-common \
kpartx \
libncurses5-dev \
lsb-release \
mtools \
parallel \
python3 \
qemu-utils \
quilt \
rsync \
sudo \
texinfo \
unzip \
wget \
xz-utils \
zstd \
# implicit deps (used by bundle/grab-kernels but not listed in system-setup)
binutils \
cpio \
kmod \
# CI extras (boot testing + OpenFirmware for ppc64le)
cloud-utils \
openbios-ppc \
qemu-system-arm \
qemu-system-misc \
qemu-system-ppc \
qemu-system-x86 \
&& rm -rf /var/lib/apt/lists/*

# ── Loop device nodes ─────────────────────────────────────────────────────────
# Pre-create /dev/loop* nodes for environments where the container /dev is
# minimal. At runtime --privileged exposes the host kernel's loop subsystem.
RUN for i in $(seq 0 7); do \
[ -e /dev/loop$i ] || mknod /dev/loop$i b 7 $i; \
done

WORKDIR /cirros

# Entrypoint that validates the bind-mount and delegates to bin/build-release
COPY docker-entrypoint.sh /usr/local/bin/cirros-build
RUN chmod +x /usr/local/bin/cirros-build

# Declare cache-friendly volume mount points
VOLUME ["/cirros/download", "/cirros/ccache"]

ENTRYPOINT ["/usr/local/bin/cirros-build"]
CMD ["daily"]
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ the ARCHES variable like:
* ARCHES=aarch64,x86_64,arm bin/build-release daily

Resulting images will be present in ../build-dYYMMDD/release directory.
Each architecture gets a bootable `*-minimal.qcow2` image with the traditional
minimal root filesystem and a `*-full.qcow2` image with the root filesystem
pre-populated at build time.


## Long, detailed version
Expand Down Expand Up @@ -128,7 +131,7 @@ for riscv64,use below version
We provide simple script to test resulting image. You run it this way:

```bash
$ RELEASE_DIR=$PWD/../build-*/release IMG=$PWD/../build-*/release/cirros-*-x86_64-disk.img bin/test-boot
$ RELEASE_DIR=$PWD/../build-*/release IMG=$PWD/../build-*/release/cirros-*-x86_64-full.qcow2 bin/test-boot
```

Note: "RELEASE_DIR" variable is required only for aarch64 and arm images.
Expand Down
18 changes: 11 additions & 7 deletions bin/build-release
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ tstart=${_RET}
# Stage 1: DOWNLOAD
logevent "start download" -
brtgz="buildroot-${BR_VER}.tar.gz"
dl "http://buildroot.uclibc.org/downloads/$brtgz" "download/$brtgz"
dl "https://buildroot.org/downloads/$brtgz" "download/$brtgz"
logevent "end download"

logevent "start unpack" -
Expand Down Expand Up @@ -284,7 +284,8 @@ for arch in ${ARCHES}; do
ln initramfs $p-initrd && ln initramfs $p-initramfs &&
ln part.img $p-rootfs.img &&
ln blank.img $p-blank.img &&
ln disk.img $p-disk.img &&
ln disk-minimal.qcow2 $p-minimal.qcow2 &&
ln disk-full.qcow2 $p-full.qcow2 &&
ln filesys.tar.gz $p-lxc.tar.gz &&
ln filesys.tar.xz $p-lxc.tar.xz &&
ln lxd.tar.xz $p-lxd.tar.xz &&
Expand All @@ -302,7 +303,8 @@ for arch in ${ARCHES}; do
( cd "$OUT/stage/$arch" &&
tar cvzf - $p-blank.img $p-vmlinuz $p-initrd
) > "$OUT/release/$p-uec.tar.gz"
cp "$OUT/stage/$arch/$p-disk.img" "$OUT/release/$p-disk.img"
cp "$OUT/stage/$arch/$p-minimal.qcow2" "$OUT/release/$p-minimal.qcow2"
cp "$OUT/stage/$arch/$p-full.qcow2" "$OUT/release/$p-full.qcow2"
done

mkdir -p "$OUT/release/buildroot_rootfs"
Expand All @@ -323,10 +325,12 @@ msg "output in $OUT/release"

if [ "true" = "${BOOTTEST}" ]; then
for arch in ${ARCHES}; do
img="$OUT/release/cirros-$VER-$arch-disk.img"
logevent "start test-boot $arch ${img##*/}" -
POWEROFF=true IMG="$img" RELEASE_DIR=$OUT/release test-boot
logevent "end test-boot $arch ${img##*/}"
for variant in minimal full; do
img="$OUT/release/cirros-$VER-$arch-$variant.qcow2"
logevent "start test-boot $arch ${img##*/}" -
POWEROFF=true IMG="$img" RELEASE_DIR=$OUT/release test-boot
logevent "end test-boot $arch ${img##*/}"
done
done
fi

Expand Down
69 changes: 46 additions & 23 deletions bin/bundle
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ getopt_out=$(getopt --name "${0##*/}" \
topdir=$(cd "${0%/*}/.." && pwd)
size=${DEF_SIZE}
FS_LABEL="cirros-rootfs"
fs_type="ext3"
fs_type="ext4"
arch=""

while [ $# -ne 0 ]; do
Expand Down Expand Up @@ -99,10 +99,10 @@ mkdir -p "${out_d_in}" && out_d=$(readlink -f "${out_d_in}") &&
fail "failed to get full path for input"

out_partimg="${out_d}/part.img"
out_diskimg="${out_d}/disk.img"
out_minimal_diskimg="${out_d}/disk-minimal.qcow2"
out_full_diskimg="${out_d}/disk-full.qcow2"
out_kernel="${out_d}/kernel"
out_initramfs="${out_d}/initramfs"
out_diskimg="${out_d}/disk.img"
out_blankimg="${out_d}/blank.img"
out_filesys_lxc_gz="${out_d}/filesys.tar.gz"
out_filesys_lxc_xz="${out_d}/filesys.tar.xz"
Expand Down Expand Up @@ -322,47 +322,69 @@ tar -C "$stage_d" -cpf - \
( cd "$stage_d" && tar -cpf - * ) > "$filesys_tar" ||
fail "failed to create filesys_tar"

debug 1 "populating image"
debug 1 "populating minimal partition image"
mount -o loop "${out_partimg}" "${mp}" && UMOUNT=${mp} ||
fail "failed to mount ${out_partimg} loopback"

tar -C "$mp" -xpf - vmlinuz initrd.img boot/ < "$kernel_tar" ||
tar -C "$mp" -xpf - < "$kernel_tar" ||
fail "failed to extract kernel_tar"
cp "$initramfs" "$mp/boot/initrd.img-${kver}"

umount "${mp}" && UMOUNT="" ||
fail "failed to unmount ${out_partimg}"

full_partimg="$TEMP_D/part.img.full"
cp "$out_blankimg" "$full_partimg" ||
fail "failed to copy full partition image"

debug 1 "populating full partition image"
mount -o loop "${full_partimg}" "${mp}" && UMOUNT=${mp} ||
fail "failed to mount ${full_partimg} loopback"

tar -C "$mp" -xpf - < "$filesys_tar" ||
fail "failed to extract filesys_tar"
cp "$initramfs" "$mp/boot/initrd.img-${kver}"

umount "${mp}" && UMOUNT="" ||
fail "failed to unmount ${full_partimg}"

cp "${kernel_d}/${vmlinuz}" "${out_kernel}" ||
fail "failed to copy kernel to ${out_kernel}"

{ [ -z "${out_initramfs}" ] || cp "${initramfs}" "${out_initramfs}"; } ||
fail "failed to copy initramfs to ${out_initramfs}"

debug 1 "fixing grub entry in partimg"
tmp_part="$TEMP_D/part.img.disk"
cp "$out_partimg" "$tmp_part" &&
mount -o loop "$tmp_part" "$mp" && UMOUNT="$mp" ||
fail "failed to mount $tmp_part"
sed -i 's/(hd0)/(hd0,0)/' "$mp/boot/grub/menu.lst" ||
fail "failed to edit /boot/grub/menu.lst in image"
umount "$mp" && UMOUNT="" ||
fail "failed to unmount partimg"

case $arch in
x86_64) grub_options="--grub1 --grub-efi";;
arm|aarch64|riscv64) grub_options="--grub-efi";;
ppc*) grub_options="--grub-ieee";;
*) grub_options=;;
esac

debug 1 "creating disk image"
out=$(PATH=$xgrubd:$PATH part2disk $grub_options "$tmp_part" \
"$grub_in" "$arch" "$out_diskimg.raw" 2>&1) ||
fail "failed to create disk image: $out"
qemu-img convert -O qcow2 -c "$out_diskimg.raw" "$out_diskimg" ||
fail "failed to convert disk image"
rm -f "$out_diskimg.raw" "$tmp_part"
write_disk_image() {
local partimg="$1" out_diskimg="$2" tmp_part=""

debug 1 "fixing grub entry in ${partimg}"
tmp_part="$TEMP_D/${out_diskimg##*/}.part"
cp "$partimg" "$tmp_part" &&
mount -o loop "$tmp_part" "$mp" && UMOUNT="$mp" ||
fail "failed to mount $tmp_part"
sed -i 's/(hd0)/(hd0,0)/' "$mp/boot/grub/menu.lst" ||
fail "failed to edit /boot/grub/menu.lst in image"
umount "$mp" && UMOUNT="" ||
fail "failed to unmount partimg"

debug 1 "creating disk image ${out_diskimg}"
out=$(PATH=$xgrubd:$PATH part2disk $grub_options "$tmp_part" \
"$grub_in" "$arch" "$out_diskimg.raw" 2>&1) ||
fail "failed to create disk image: $out"
qemu-img convert -O qcow2 -c "$out_diskimg.raw" "$out_diskimg" ||
fail "failed to convert disk image"
rm -f "$out_diskimg.raw" "$tmp_part"
}

write_disk_image "$out_partimg" "$out_minimal_diskimg"
write_disk_image "$full_partimg" "$out_full_diskimg"

if [ -n "${SUDO_USER}" ]; then
u=${SUDO_USER}
Expand All @@ -372,7 +394,8 @@ if [ -n "${SUDO_USER}" ]; then
fi

echo "wrote ${out_partimg}"
echo "wrote ${out_diskimg}"
echo "wrote ${out_minimal_diskimg}"
echo "wrote ${out_full_diskimg}"
echo "wrote ${out_kernel}"
echo "wrote ${out_initramfs}"
echo "wrote ${out_blankimg}"
Expand Down
2 changes: 1 addition & 1 deletion bin/mirror-dump-sstream-data
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ output_for_path() {
local path=${1#./}
local size="" md5="" sha256="" pubname=""
case "$path" in
*-uec.tar.gz|*-disk.img|*-rootfs.img|*-lxc.tar.gz|*-lxc.tar.xz) :;;
*-uec.tar.gz|*-minimal.qcow2|*-full.qcow2|*-rootfs.img|*-lxc.tar.gz|*-lxc.tar.xz) :;;
*-lxd.tar.xz) :;;
*) return;;
esac
Expand Down
7 changes: 5 additions & 2 deletions bin/test-boot
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ POWEROFF=${POWEROFF:-false}

if [ "$CI_BUILD" = "true" ]; then
GUESTARCH="${GUESTARCH:-}"
IMG=$(find $CI_BUILD_OUT/release/ -name cirros-*-${GUESTARCH}-disk.img)
RELEASE_DIR=$CI_BUILD_OUT/release
RELEASE_DIR=${RELEASE_DIR:-$CI_BUILD_OUT/release}
if [ -z "${IMG:-}" ]; then
IMG=$(find "$RELEASE_DIR" -name "cirros-*-${GUESTARCH}-full.qcow2" | head -n1)
fi
else
GUESTARCH="${GUESTARCH:-$(echo $(basename $IMG)| cut -d'-' -f3)}"
fi

GUESTARCH="${GUESTARCH:-$(echo $(basename $IMG)| cut -d'-' -f3)}"
VER=$(echo $(basename $IMG)| cut -d'-' -f2)

echo '{"instance-id": "9068aef2-213e-4e43-830f-accdbadde897"}' > meta-data
Expand Down
25 changes: 25 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash
# docker-entrypoint.sh — run inside the cirros-builder container
set -euo pipefail

# Ensure loop device support (requires --privileged)
modprobe loop max_loop=16 2>/dev/null || true

# Expect the cirros source tree to be bind-mounted at /cirros
cd /cirros
[ -f bin/build-release ] || {
echo "ERROR: /cirros does not look like a cirros source tree."
echo " Bind-mount the repo: -v \$PWD:/cirros"
exit 1
}

VERSION="${1:-daily}"
shift || true

export CI_BUILD="${CI_BUILD:-true}"
export CI_BUILD_OUT="${CI_BUILD_OUT:-build-ci/}"

echo "==> Building CirrOS version: ${VERSION}"
echo "==> Architectures: ${ARCHES:-x86_64 arm aarch64 ppc64le riscv64}"

exec bin/build-release "${VERSION}" "$@"