Experimental standalone alpine aarch64 system with custom packaging, based on techniques developed for https://fruit-testbed.org/
This commit is contained in:
parent
b21660976a
commit
d03d249701
|
@ -0,0 +1,2 @@
|
|||
vmlinuz-virt
|
||||
newroot/
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
syndicate-system-apk-key.rsa
|
||||
syndicate-system-apk-key.rsa.pub
|
|
@ -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
|
|
@ -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"
|
|
@ -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"
|
|
@ -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
|
|
@ -0,0 +1,6 @@
|
|||
alpine-baselayout
|
||||
alpine-keys
|
||||
btrfs-progs
|
||||
linux-virt
|
||||
parted
|
||||
s6
|
Loading…
Reference in New Issue