X: First working version for RasPi Zero 2W
This commit is contained in:
@@ -0,0 +1,268 @@
|
||||
# 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
|
||||
|
||||
```text
|
||||
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:
|
||||
|
||||
```ini
|
||||
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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
tmux new-session -s install
|
||||
tail -f /media/mmcblk0p1/NenjimHub-Install.log
|
||||
```
|
||||
|
||||
Når brugeren `nenjim` er oprettet, findes samme log her:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
```text
|
||||
/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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```ini
|
||||
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`.
|
||||
Reference in New Issue
Block a user