Mit ‘gitlab’ Tagged einträge

Gitlab CI mit QEMU für FreeBSD, OpenBSD oder NetBSD oder alternative Architekturen

Sonntag, Dezember 31st, 2023

Fü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