Files
r35157_nenjimhub-os/NenjimHub-ReadMe.md

10 KiB

NenjimHub: Alpine, valgfri rå swap og OpenZFS

Designet bruger en klassisk MBR-partitionstabel:

  • partition 1: FAT32 til Alpine diskless, APKoVL og APK-cache
  • partition 2: valgfri rå Linux-swap
  • partition 3: resten af kortet som OpenZFS-poolen rpool

ZFS er altid partition 3. Hvis den rå swapstørrelse er 0, oprettes partition 2 ikke; partitionsnummer 2 står blot tomt. Det gør layoutet entydigt for alle profiler.

flash.sh skriver kun til partition 1. Partition 2 og 3 ændres ikke, så en senere Alpine-opdatering ikke overskriver swap eller ZFS-data.

Filer i samme mappe

alpine-rpi-3.24.1-aarch64.img
flash.sh
headless.apkovl.tar.gz
installZeroTier.sh
NenjimHub.conf
prepare-storage.sh
unattended.sh
wpa_supplicant.conf
zerotier-one-1.16.2-linux-musl-aarch64-sso0  # valgfri
zulu25.36.205-ca-jre25.0.4.1-linux_musl_aarch64.tar.gz

prepare-storage.sh downloader som udgangspunkt det officielle statiske zrepl-linux-arm64-program fra zrepl v0.7.0 og kontrollerer SHA-256-værdien fra GitHub. Det kan i stedet placeres lokalt ved siden af scriptet med navnet zrepl-linux-arm64.

Fælles konfiguration

Ret kun NenjimHub.conf; både prepare-storage.sh, flash.sh og første boot bruger den samme fil. DEVICE skal være hele SD-kortet, eksempelvis /dev/sdc, og aldrig en partition som /dev/sdc1.

Standardprofilen til Raspberry Pi Zero 2W er:

DEVICE="/dev/sdc"
NENJIMHUB_HOSTNAME="alpine-nenjim"
CONSOLE_KEYMAP_LAYOUT="dk"
CONSOLE_KEYMAP_VARIANT="dk"
SYSTEM_LOCALE="C.UTF-8"

VIRT_ZVOL_SIZE_MIB="4096"

SWAP_SIZE_MIB_PART="2048"
SWAP_SIZE_MIB_ZFS="0"
SWAP_SIZE_PCT_ZRAM="25"

SWAP_PRI_ZRAM="300"
SWAP_PRI_ZFS="200"
SWAP_PRI_PART="100"

ZEROTIER_ENABLE_SSO="0"
ZEROTIER_VERSION="1.16.2"

Sæt NENJIMHUB_HOSTNAME til et unikt navn for hvert apparat, eksempelvis nenjimhub-01. Værdien må være ét hostname-led på 1-63 bogstaver, tal eller bindestreger og må ikke begynde eller slutte med en bindestreg.

CONSOLE_KEYMAP_LAYOUT="dk" og CONSOLE_KEYMAP_VARIANT="dk" vælger det almindelige danske PC-tastatur på Linux-konsollen. Første boot kontrollerer keymap-navnet før setup-alpine, så en stavefejl stopper med en tydelig fejl i stedet for at åbne en interaktiv menu.

SYSTEM_LOCALE="C.UTF-8" giver et neutralt UTF-8-loginmiljø uden at vælge engelske eller danske dato- og talformater. Installationen aktiverer samtidig Unicode på Linux-konsollen.

En swaptype slås fra ved at sætte dens størrelse eller procent til 0. Prioritet 0 er derimod en gyldig Linux-swapprioritet og slår ikke noget fra.

PC'en skal have OpenZFS 2.4.3, ZFS-kernemodulet indlæst, FAT/ext4-værktøjer, Python 3 og enten Podman eller Docker. Minimumskapaciteten beregnes ud fra konfigurationen; standardprofilen er beregnet til et SD-kort solgt som 16 GB.

Trin 1: klargør hele kortet

sudo ./prepare-storage.sh

Dette trin sletter hele SD-kortet. Det opretter de valgte partitioner, rpool, datasets rpool/home, rpool/software og rpool/sysop samt det ext4-formaterede zvol rpool/virt. Java og zrepl lægges på rpool/software.

Størrelsen på rpool/virt styres særskilt af VIRT_ZVOL_SIZE_MIB; den har ingen forbindelse til ZFS-swapstørrelsen.

Trin 2: installer eller opdater Alpine

sudo ./flash.sh

Dette trin erstatter kun partition 1. Det bygger på PC'en en matchende Alpine Raspberry Pi-kernel/modloop med zfs-rpi og lægger first-boot-filerne ind. Som sikkerhed skal du skrive NENJIMHUB, når scriptet beder om bekræftelse.

Scriptet gemmer også PC'ens aktuelle UTC-tid på kortet, så Pi'en uden RTC kan validere HTTPS-certifikater, inden netværkstiden er synkroniseret. Vent på slutteksten Alpine partition 1 is ready.

Ved en senere Alpine-opdatering køres kun trin 2. flash.sh bevarer /sysop fra det gamle APKoVL, mens alle ZFS-data ligger urørt på partition 3.

Første boot

Pi'en gør følgende automatisk:

  1. aktiverer den rå swap-partition, hvis den er konfigureret
  2. aktiverer midlertidig ZRAM til installationen, hvis ZRAM er konfigureret
  3. importerer rpool fra partition 3
  4. opretter og aktiverer rpool/swap, hvis dens størrelse er større end 0
  5. installerer pakker og genbruger en prekompileret ZeroTier-binærfil eller bygger ZeroTier med ét compile-job, hvis filen ikke findes
  6. skriver den endelige ZRAM-størrelse, opretter APKoVL og genstarter

rpool/swap oprettes på Pi'en, så volblocksize kan følge den faktiske værdi fra getconf PAGESIZE. ZeroTier-kontrollen summerer al aktiv swap; den er ikke afhængig af, om pladsen kommer fra partition, ZRAM eller ZFS.

På Pi Zero 2W er ZEROTIER_ENABLE_SSO="0" standard. Det udelader den meget store Rust/Cargo-toolchain og bygger ZeroTier med GCC og ét job. Sæt værdien til 1, hvis hubben senere skal kunne bruge ZeroTier-netværk, som kræver SSO; det gør førstegangsinstallationen væsentligt tungere.

Genbrug den færdigbyggede ZeroTier-fil

Når en Pi har bygget ZeroTier færdig, kopieres binærfilen til PC'en fra den persistente ZFS-placering. Kør dette på PC'en i mappen med scripts og erstat PI-ADRESSE med Pi'ens IP-adresse:

scp sysop@PI-ADRESSE:/usr/local/software/zerotier/current/zerotier-one \
  ./zerotier-one-1.16.2-linux-musl-aarch64-sso0
chmod 0755 ./zerotier-one-1.16.2-linux-musl-aarch64-sso0

Ved næste kørsel kopierer flash.sh automatisk filen til kortet. Første boot installerer den direkte og testkører den på Pi'en; både arkitektur og den forventede version skal passe. Filnavnet indeholder også SSO-profilen, så et SSO-build ikke forveksles med standardbuildet uden SSO.

Hvis den navngivne fil ikke findes ved siden af flash.sh, falder installationen automatisk tilbage til lokal kompilering på Pi'en. Det er derfor nok at slette eller flytte filen på PC'en, før et nyt SD-kort klargøres, for at fremtvinge en ny kompilering.

tmux, htop og btop installeres i den tidlige pakkegruppe. Pakken kitty-terminfo gør, at de kan bruges direkte fra Kitty med TERM=xterm-kitty, og musl-locales plus SYSTEM_LOCALE giver UTF-8 til tekstbaserede programmer. Installationen kan følges lokalt sådan:

tmux new-session -s install
tail -f /media/mmcblk0p1/NenjimHub-Install.log

Når brugeren nenjim er oprettet, findes samme log her:

tail -f /var/log/NenjimHub-Install.log

Den sidste linje før genstart viser den samlede tid fra start af unattended installation til reboot, målt monotont og vist som HH:MM:SS.

På normale boots venter nenjim-wifi-ready op til 60 sekunder på wlan0, før Wi-Fi og networking startes. Tilsvarende venter nenjim-virt på det asynkront oprettede /dev/zvol/rpool/virt-link, før ext4 kontrolleres og Docker samt containerd får adgang til deres datalager. Begge ventetider er afgrænsede, så en hardware- eller udev-fejl ikke kan blokere boot uendeligt.

Loginprompten på HDMI-konsollens tty1 startes af BusyBox init via /etc/inittab, ikke som en OpenRC-service. Installationen sikrer og gemmer denne entry, så sysop kan logge ind lokalt efter boot.

Inden det endelige APKoVL oprettes, køres en fuld apk cache sync. Det er vigtigt i diskless mode, fordi også pakker som eudev, der blev installeret før den persistente cache blev aktiveret, skal ligge som APK-filer på bootpartitionen. De egne storage- og Wi-Fi-services bruger udev-settle som valgfri rækkefølge og ikke som en hård afhængighed.

apk cache sync er den autoritative cachekontrol. Tomme metadatapakker som udev-init-scripts kræver ikke nødvendigvis en separat payloadfil med samme navn; installationen kontrollerer derfor de leverede udev-services frem for at gætte cachefilnavne.

Konti efter installation:

sysop / sysop    administrator via password-beskyttet doas og Docker-gruppen
nenjim / nenjim  almindelig bruger uden wheel, doas og Docker-adgang

Medlemskab af Docker-gruppen er i praksis root-adgang. Det gives derfor kun til sysop; nenjim fjernes eksplicit fra både wheel og docker.

Direkte root-login er låst på både normal konsol og SSH. Skift de to standard-passwords, før maskinen placeres på et netværk, som andre har adgang til.

Persistente placeringer

/etc/NenjimHub.conf            kopi af den anvendte provisioningprofil
/home                          rpool/home
/usr/local/software            rpool/software
/media/sysop                   rpool/sysop
/media/virt                    ext4 på rpool/virt
/var/lib/docker                -> /media/virt/docker
/var/lib/containerd            -> /media/virt/containerd
/sysop/zerotier                -> /media/sysop/zerotier
/sysop/zrepl                   -> /media/sysop/zrepl
/etc/zrepl/zrepl.yml           -> /sysop/zrepl/zrepl.yml

Selve /sysop ligger i Alpine/APKoVL, så sysop stadig kan logge ind, hvis ZFS ikke kan importeres. De vigtige ZeroTier- og zrepl-data ligger på ZFS.

zrepl starter med den gyldige no-op-konfiguration jobs: []. Efter redigering kan konfigurationen kontrolleres og servicen genstartes sådan:

doas zrepl configcheck
doas rc-service zrepl restart

Swap-profiler og prioriteter

Linux foretrækker det højeste prioritetsnummer. Scripts accepterer enhver selvstændig prioritet fra 0 til 32767. Derfor kan ZFS-swap godt gives højere prioritet end partitions-swap. Første boot skriver en advarsel, hvis dette valg bruges, men afviser det ikke.

En profil til en Pi med mere RAM kan eksempelvis være:

SWAP_SIZE_MIB_PART="1024"
SWAP_SIZE_MIB_ZFS="4096"
SWAP_SIZE_PCT_ZRAM="75"

SWAP_PRI_ZRAM="300"
SWAP_PRI_ZFS="200"
SWAP_PRI_PART="100"

ZRAM-størrelsen beregnes ved hver normal opstart ud fra MemTotal; pladsen bruges kun efter behov. Under førstegangsinstallationen anvendes midlertidigt 100 % logisk ZRAM-størrelse, hvorefter den ønskede procent gemmes til næste boot. Sættes SWAP_SIZE_PCT_ZRAM="0", oprettes og aktiveres ZRAM slet ikke.

Swap på et ZFS-zvol kan under ekstremt hukommelsespres skabe en uheldig afhængighed mellem ZFS og swap. Den rå partition er derfor den sikreste høje belastningsbuffer på Pi Zero 2W. På en større Pi kan ZFS-swap prioriteres højere, hvis det er det ønskede kompromis. ZFS ARC begrænses separat via ZFS_ARC_MAX_MIB.