Gitlab CI mit QEMU für FreeBSD, OpenBSD oder NetBSD oder alternative Architekturen
Sonntag, Dezember 31st, 2023Für das Tuiwidgets und Termpaint Projekt benötigen wir auch CI Build in BSD. Anhand von FreeBSD dokumentiere ich hier einmal, wie wir mit GitLab und QEMU dies in der CI zum Laufen gebracht haben.
Zunächst haben wir ein Image erstellt, das alle für unseren Zweck notwendigen Pakete enthält.
ISO herunterladen:
wget http://ftp-archive.freebsd.org/pub/FreeBSD/releases/amd64/amd64/ISO-IMAGES/13.2/FreeBSD-13.2-RELEASE-amd64-bootonly.iso
Raw Device erstellen. Hier wird ein leeres Image erzeugt, in dem das Betriebssystem installiert wird:
qemu-img create -f raw FreeBSD-VM10G.raw 10G
Dann wird das Image installiert, hierfür wird ein x11 fähiger Zugriff auf den Träger benötigt:
qemu-system-x86_64 -m 4G -cpu host -enable-kvm -smp cpus=4 -drive file=~/FreeBSD-VM10G.raw,if=virtio -nographic -cdrom ~/FreeBSD-13.2-RELEASE-amd64-bootonly.iso -net nic,model=e1000
Für unsere Zwecke wird ein SSH schlüssel hinterlegt und der Zugriff via com console freigeschaltet:
echo 'console="comconsole"' >> /boot/loader.conf echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config mkdir /root/.ssh echo 'ssh-ed25519 xxx root@qemu-host-key' >> /root/.ssh/authorized_keys chmod 0600 /root/.ssh/authorized_keys chmod 0600 /root/.ssh
in der Gitlab config.toml
wird nur eine neuer Runner angelegt, in der custom Sektion werden 3 zusätzlich Scripte angelegt:
[[runners]] name = xxx ... [runners.custom] prepare_exec = "/root/gitlab-qemu/prepare" run_exec = "/root/gitlab-qemu/run" cleanup_exec = "/root/gitlab-qemu/cleanup"
prepare
#!/bin/bash
VM_ID="runner-$CUSTOM_ENV_CI_RUNNER_ID-project-$CUSTOM_ENV_CI_PROJECT_ID-concurrent-$CUSTOM_ENV_CI_CONCURRENT_PROJECT_ID-job-$CUSTOM_ENV_CI_JOB_ID"
read LOWERPORT UPPERPORT < /proc/sys/net/ipv4/ip_local_port_range
while :
do
PORT="`shuf -i $LOWERPORT-$UPPERPORT -n 1`"
ss -lpn | grep -q ":$PORT " || break
done
echo -n $PORT > ~/${VM_ID}.port
echo "Preparing VM $VM_ID"
case $CUSTOM_ENV_CI_JOB_IMAGE in
amd64-freebsd*)
screen -S $VM_ID -Logfile ~/log/${VM_ID}.screen -L -d -m qemu-system-x86_64 -cpu host -enable-kvm -m 4G -smp 4 -drive file=~/FreeBSD-VM10G.raw,if=virtio -nographic -net nic,model=e1000 -net user,hostfwd=tcp::${PORT}-:22 -snapshot -pidfile ~/${VM_ID}.pid
;;
amd64-netbsd*)
screen -S $VM_ID -Logfile ~/log/${VM_ID}.screen -L -d -m qemu-system-x86_64 -cpu host -enable-kvm -m 4G -smp 4 -drive file=~/netbsd-10.0-2023-11-30.qcow2,if=virtio -nographic -net nic,model=e1000 -net user,hostfwd=tcp::${PORT}-:22 -snapshot -pidfile ~/${VM_ID}.pid
;;
amd64-openbsd*)
screen -S $VM_ID -Logfile ~/log/${VM_ID}.screen -L -d -m qemu-system-x86_64 -cpu host -enable-kvm -m 4G -smp 4 -drive file=~/openbsd-7.3-2023-04-22.qcow2,if=virtio -nographic -net nic,model=e1000 -net user,hostfwd=tcp::${PORT}-:22 -snapshot -pidfile ~/${VM_ID}.pid
;;
*)
echo "Unknown arch"
exit "$SYSTEM_FAILURE_EXIT_CODE"
;;
esac
ssh-keygen -f "~/.ssh/known_hosts" -R "[localhost]:${PORT}" || true
# Wait for ssh to become available
echo "Waiting for sshd to be available [localhost]:${PORT}"
for i in $(seq 1 120); do
if timeout 5 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i ~/ci-access.key -p${PORT} root@localhost true >/dev/null 2>/dev/null; then
break
fi
if [ "$i" == "120" ]; then
echo 'Waited 120 seconds for sshd to start, exiting...'
# Inform GitLab Runner that this is a system failure, so it
# should be retried.
exit "$SYSTEM_FAILURE_EXIT_CODE"
fi
sleep 1s
done
Mit der -snapshot
Option wird das Image Read Only gemountet. Somit können wir sicherstellen, dass immer wieder ein sauberes Environment zur Verfügung steht.
run
#!/bin/bash VM_ID="runner-$CUSTOM_ENV_CI_RUNNER_ID-project-$CUSTOM_ENV_CI_PROJECT_ID-concurrent-$CUSTOM_ENV_CI_CONCURRENT_PROJECT_ID-job-$CUSTOM_ENV_CI_JOB_ID" ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i ~/ci-access.key -p$(cat ~/${VM_ID}.port) root@localhost bash < "$1"
cleanup
#!/bin/bash VM_ID="runner-$CUSTOM_ENV_CI_RUNNER_ID-project-$CUSTOM_ENV_CI_PROJECT_ID-concurrent-$CUSTOM_ENV_CI_CONCURRENT_PROJECT_ID-job-$CUSTOM_ENV_CI_JOB_ID" kill $(cat ~/${VM_ID}.pid) rm ~/${VM_ID}.pid rm ~/${VM_ID}.port In der.gitlab-ci.yml
geben wir nun folgenden Dinge an:build:freebsd: stage: build when: manual tags: - qemu image: amd64-freebsd-13 script: - uname -a