Experimental standalone alpine aarch64 system with custom packaging, based on techniques developed for https://fruit-testbed.org/

This commit is contained in:
Tony Garnock-Jones 2021-08-19 22:15:11 -04:00
parent b21660976a
commit d03d249701
8 changed files with 389 additions and 0 deletions

View File

@ -0,0 +1,2 @@
vmlinuz-virt
newroot/

View File

@ -0,0 +1,29 @@
all: run
clean:
rm -f initramfs-syndicate-system
veryclean: clean
rm -f disk.img
ALPINE_VERSION=v3.14
# vmlinuz-lts:
# wget http://dl-cdn.alpinelinux.org/alpine/$(ALPINE_VERSION)/releases/aarch64/netboot/vmlinuz-lts
# initramfs-lts:
# wget http://dl-cdn.alpinelinux.org/alpine/$(ALPINE_VERSION)/releases/aarch64/netboot/initramfs-lts
disk.img:
qemu-img create -f qcow2 $@ 8G
initramfs-syndicate-system: pack-image.sh init.sh package-list
sudo PACKAGES="$$(cat package-list)" ./pack-image.sh
# See https://superuser.com/questions/1397991/running-alpine-linux-on-qemu-arm-guests
run: initramfs-syndicate-system disk.img
qemu-system-aarch64 \
-M virt -m 512M -cpu cortex-a57 \
-kernel vmlinuz-virt -initrd initramfs-syndicate-system \
-netdev user,id=unet,hostfwd=tcp::8022-:22 -device virtio-net-pci,netdev=unet \
-hda disk.img \
-nographic

View File

@ -0,0 +1,2 @@
syndicate-system-apk-key.rsa
syndicate-system-apk-key.rsa.pub

View File

@ -0,0 +1,106 @@
# Originally based on a Makefile from the FRμIT project,
# https://fruit-testbed.org/, which is CC Attribution-ShareAlike 4.0
# licensed.
.PHONY: build sign clean
TARGET = $(shell pwd)/target
KEYFILE ?= $(shell pwd)/syndicate-system-apk-key.rsa
USER = builder
ARCH ?= $(shell apk --print-arch)
SU_CMD = su $(USER)
SU_CMD_PATH_OVERRIDE = PATH=/usr/sbin:/sbin:$$PATH
PACKAGES = \
build: $(PACKAGES) sign
# Packages added:
# - alpine-sdk for build support
# - shadow for `sg`
.prepare:
apk update && apk upgrade && apk add alpine-sdk shadow
[ -f /etc/apk/keys/$$(basename $(KEYFILE)).pub ] || cp $(KEYFILE).pub /etc/apk/keys/.
adduser -s /bin/sh -D $(USER) && \
echo "$(USER) ALL=(ALL) ALL" >> /etc/sudoers && \
addgroup $(USER) abuild && \
chown $(USER):$(USER) . && \
chown $(USER):$(USER) -R packages && \
mkdir -p /home/$(USER)/.abuild/ && \
cp -f $(KEYFILE) /home/$(USER)/.abuild/ && \
chmod 0400 /home/$(USER)/.abuild/$$(basename $(KEYFILE)) && \
chown $(USER):$(USER) /home/$(USER)/.abuild/$$(basename $(KEYFILE)) && \
echo "PACKAGER_PRIVKEY=/home/syndicate-systemdev/.abuild/$$(basename $(KEYFILE))" > /home/$(USER)/.abuild/abuild.conf && \
mkdir -p $(TARGET)/packages/$(ARCH) && \
chown -R $(USER):$(USER) $(TARGET)
addgroup $(shell id -un) abuild
mkdir -p /var/cache/distfiles && chmod a+w /var/cache/distfiles
touch .prepare
$(TARGET): .prepare $(PACKAGES)
%.apk: .prepare
@if [ -e packages/$*/APKBUILD ]; then \
echo "Building $*..."; \
cd packages/$* && sg abuild "abuild -F -P $(TARGET) deps" && $(SU_CMD) -c "$(SU_CMD_PATH_OVERRIDE) abuild -P $(TARGET)"; \
else \
echo "Fetching $*..."; \
apk fetch -o $(TARGET)/packages/$(ARCH) -R $*; \
fi
%.checksum: .prepare
cd packages/$* && $(SU_CMD) -c "$(SU_CMD_PATH_OVERRIDE) abuild checksum"
sign:
rm -f $(TARGET)/packages/$(ARCH)/APKINDEX.tar.gz
cd $(TARGET)/packages/$(ARCH) && apk index -o APKINDEX.tar.gz --rewrite-arch $(ARCH) *.apk
sg abuild "abuild-sign -q -k $(KEYFILE) $(TARGET)/packages/$(ARCH)/APKINDEX.tar.gz"
tgz:
cd $(TARGET)/ && tar cvzf syndicate-system-apks.tar.gz packages
clean.packages:
@if [ $$(grep $(USER) /etc/passwd | wc -l) -ne 0 ] && [ -e /usr/bin/abuild ]; then \
for package in packages/*; do \
if [ -e $$package/APKBUILD ]; then \
echo "Cleaning $$package..."; \
$(SU_CMD) -c "cd $$package && $(SU_CMD_PATH_OVERRIDE) abuild clean"; \
fi; \
done; \
fi
clean: clean.packages
@[ "$$(grep $(USER) /etc/passwd)" = "" ] || deluser $(USER)
@[ ! -e /etc/sudoers ] || sed -i 's/^$(USER).*$$//' /etc/sudoers
@[ "$$(mount | grep ' on /var/cache/distfiles ')" = "" ] || umount -f /var/cache/distfiles
@chown -R $$(id -u -n):$$(id -g -n) .
rm -f .prepare
cleantarget:
rm -rf $(TARGET)
cleancache:
@if [ -e /usr/bin/abuild ]; then \
for package in packages/*; do \
if [ -e $$package/APKBUILD ]; then \
echo "Cleaning cache of $$package..."; \
cd $$package && sg abuild "abuild -F cleancache"; \
fi; \
done; \
fi
@rm -rf /var/cache/distfiles/*
clean.%:
@if [ -e packages/$* ]; then \
echo "Cleaning $*..."; \
cd packages/$* && sg abuild "abuild -F clean" && sg abuild "abuild -F cleancache"; \
else \
echo "Package $* does not exist"; \
fi
cleanapks:
rm -f $(TARGET)/syndicate-system-apks.tar.gz
cleanall: clean cleantarget cleancache cleanapks

View File

@ -0,0 +1,39 @@
#!/bin/sh
#
# Originally based on build-via-docker.sh from the FRμIT project,
# https://fruit-testbed.org/, which is CC Attribution-ShareAlike 4.0
# licensed.
ALPINE_VERSION=${ALPINE_VERSION:-v3.14}
DOCKER_ARCH=${DOCKER_ARCH:-aarch64}
# If you run:
# docker run --rm --name squid adricu/alpine-squid
# and set DOCKER_SQUID_CONTAINER=squid
# then you can avoid repeated downloads of a lot of alpine packages.
#
DOCKER_SQUID_CONTAINER=${DOCKER_SQUID_CONTAINER:-""}
if [ "$DOCKER_SQUID_CONTAINER" = "" ]; then
docker_squid_opts=""
else
docker_squid_opts="--link ${DOCKER_SQUID_CONTAINER}:squid -e http_proxy=http://squid:3128/"
fi
cd "$(dirname "$0")"
tmpscript=$(mktemp tmpscript.XXXXXXXXXX)
trap "rm -f $tmpscript" 0
cat > $tmpscript <<EOF
set -xe
apk update
apk add make git
cd /media/data/syndicate-system/apks
rm -f .prepare
make $@
EOF
docker run -it --rm -v $(realpath ..):/media/data/syndicate-system \
${docker_squid_opts} \
multiarch/alpine:${DOCKER_ARCH}-${ALPINE_VERSION} \
/bin/sh -c "cd /media/data/syndicate-system/apks && sh $tmpscript"

View File

@ -0,0 +1,94 @@
#!/bin/sh
ROOTDEV=/dev/vda
CONSOLE=/dev/ttyAMA0
NEWROOT=/mnt
in_initramfs=true
if [ -f /proc/mounts ]
then
in_initramfs=false
fi
if [ $in_initramfs = true ]
then
echo "Mounting basics."
mount -t devtmpfs none /dev
mkdir /dev/pts
mkdir /dev/shm
mount -t devpts none /dev/pts
mount -t proc none /proc
mount -t sysfs none /sys
mount -t tmpfs -o nodev,nosuid,noexec none /dev/shm
mount -t tmpfs none /run
# Docker wants this
mount -t cgroup2 none /sys/fs/cgroup
echo "Loading virtio modules."
# The "virt" aarch64 qemu machine needs these to get user networking going
modprobe virtio_pci
modprobe virtio_net
# And this is for the disk
modprobe virtio_blk
echo "Loading btrfs."
modprobe btrfs &
echo "Configuring network."
ifconfig lo 127.0.0.1 up
ifconfig eth0 up
udhcpc -i eth0 &
wait
echo "Attempting to mount ${ROOTDEV} on ${NEWROOT} ..."
if mount ${ROOTDEV} ${NEWROOT}
then
echo "Mount successful."
else
echo "Mount unsuccessful. Building new root."
mkfs.btrfs ${ROOTDEV}
mount ${ROOTDEV} ${NEWROOT}
apk --repositories-file /etc/apk/repositories -U --allow-untrusted \
--root ${NEWROOT} --initdb add $(cat /package-list)
fi
for f in /etc/apk/repositories /init /package-list /usr/bin/syndicate-server
do
echo "Updating $f."
cp -a $f ${NEWROOT}$f
done
echo "Moving mount points."
for mp in /dev /proc /sys /run
do
echo "Moving $mp --> ${NEWROOT}$mp"
mount -o move $mp ${NEWROOT}$mp
done
echo "Killing leftovers."
kill -15 -1
sleep 0.2
kill -9 -1
echo "Switching root."
exec switch_root -c ${CONSOLE} ${NEWROOT} /init
else
echo "Initializing with real rootfs."
echo "Re-configuring network."
ifconfig lo 127.0.0.1 up
ifconfig eth0 up
udhcpc -i eth0
echo "Ensuring installation of /package-list."
apk add $(cat /package-list)
fi
sync
echo "Dropping to shell."
# setsid creates a "session", which allows job control to work
exec setsid sh -c "exec sh -i <${CONSOLE} >${CONSOLE} 2>&1"

View File

@ -0,0 +1,111 @@
#!/bin/sh
#
# Originally loosely based on pack-image.sh from the FRμIT project,
# https://fruit-testbed.org/, which is CC Attribution-ShareAlike 4.0
# licensed.
#
# Run this script after the packages are available in
# apks/target/packages.
set -xe
INITRAMFS=${INITRAMFS:-initramfs-syndicate-system}
NATIVE_COMMANDS=${NATIVE_COMMANDS:-no}
DOCKER_ARCH=${DOCKER_ARCH:-aarch64}
ALPINE_VERSION=${ALPINE_VERSION:-v3.14}
VERSION=${VERSION:-0.1.0}
MOUNTPOINT=${MOUNTPOINT:-`pwd`/newroot}
# docker run --rm --name squid adricu/alpine-squid
DOCKER_PROXY_ARGS=${DOCKER_PROXY_ARGS:- --link squid -e http_proxy=http://squid:3128/}
PACKAGES=${PACKAGES:-}
die () {
echo "$1" >&2
exit 1
}
die_if_empty () {
[ ! -z "$2" ] || die "No $1 specified."
}
die_if_empty PACKAGES "$PACKAGES"
die_if_empty VERSION "$VERSION"
invoke_command () {
# Shell quoting is a nightmare. Beware spaces.
#
if [ "$NATIVE_COMMANDS" = "yes" ]
then
$@
else
tmpscript=$(mktemp tmpscript.XXXXXXXXXX)
echo "$@" > $tmpscript
docker run -it --rm -v `pwd`:`pwd` \
${DOCKER_PROXY_ARGS} \
multiarch/alpine:${DOCKER_ARCH}-${ALPINE_VERSION} \
/bin/sh -c "cd `pwd`; sh $tmpscript"
rm -f $tmpscript
fi
}
###########################################################################
TMP_REPO_FILE=$(mktemp repositories.XXXXXXXXXX)
cleanup () {
# rm -rf ${MOUNTPOINT} || true
rm -f ${TMP_REPO_FILE} || true
}
trap cleanup 0
cat < /dev/null > ${TMP_REPO_FILE}
echo "`pwd`/apks/target/packages" >> ${TMP_REPO_FILE}
echo "https://dl-cdn.alpinelinux.org/alpine/${ALPINE_VERSION}/main" >> ${TMP_REPO_FILE}
echo "https://dl-cdn.alpinelinux.org/alpine/${ALPINE_VERSION}/community" >> ${TMP_REPO_FILE}
# Create root file system.
#
echo "Repositories:"
cat ${TMP_REPO_FILE}
apkcmd="apk --repositories-file `pwd`/${TMP_REPO_FILE} -U --allow-untrusted"
invoke_command ${apkcmd} --root ${MOUNTPOINT} --initdb add ${PACKAGES}
# invoke_command ${apkcmd} --no-script --root ${MOUNTPOINT} add mkinitfs
# Allow root logins on ttyS0 / ttyAMA0
#
tmpsecuretty=$(mktemp tmpsecuretty.XXXXXXXXXX)
cat ${MOUNTPOINT}/etc/securetty | egrep -v '(ttyS0|ttyAMA0)' > $tmpsecuretty
echo ttyS0 >> $tmpsecuretty
echo ttyAMA0 >> $tmpsecuretty
cat $tmpsecuretty > ${MOUNTPOINT}/etc/securetty
rm -f $tmpsecuretty
cat > ${MOUNTPOINT}/etc/os-release <<EOF
VERSION=${VERSION}
PRETTY_NAME="syndicate-system v${VERSION}"
BUILT_TIMESTAMP=$(date +%s)
COMMIT=$(git rev-parse HEAD)
EOF
cp -a syndicate-server ${MOUNTPOINT}/usr/bin/.
cat > ${MOUNTPOINT}/etc/apk/repositories <<EOF
https://dl-cdn.alpinelinux.org/alpine/${ALPINE_VERSION}/main
https://dl-cdn.alpinelinux.org/alpine/${ALPINE_VERSION}/community
EOF
cp package-list ${MOUNTPOINT}/package-list
cp init.sh ${MOUNTPOINT}/init
chmod a+x ${MOUNTPOINT}/init
cp -a ${MOUNTPOINT}/boot/vmlinuz-virt .
(cd ${MOUNTPOINT}; find . -print0 | \
cpio --null --create --verbose --format=newc) | \
gzip > ${INITRAMFS}
trap - 0
cleanup

View File

@ -0,0 +1,6 @@
alpine-baselayout
alpine-keys
btrfs-progs
linux-virt
parted
s6