
🇸🇮 Ko USB inštalacija ves čas pada — namesti Linux prek omrežja
Kako je pokvarjen USB ključek pomagal postaviti dvojnik strežnika.
Včeraj sem dobil nov strežnik(rabljen). Nič posebnega — majhen HP T630 thin client, namenjen temu, da postane še en strežnik v mojem domačem omrežju. Prvi načrt je bil preprost: priklopim monitor, zaženem Ubuntu installer z USB ključka in namestim sistem.
Seveda ni šlo tako. 🙂 Instalacija je začela padati z I/O errorjem. Na tej točki je vedno isto vprašanje:
Je problem USB ključek ali disk v računalniku?
In to vprašanje je bolj pomembno, kot se zdi. BIOS-ov “disk health” test lahko brez težav pokaže, da je disk zdrav. To pa še ne pomeni, da bo disk uspešno preživel dejansko pisanje več deset gigabajtov podatkov med instalacijo. Po drugi strani pa lahko tudi USB ključek večino časa deluje popolnoma normalno in odpove samo pri določenem bloku. Torej sem imel dve neznanki. In ker nisem imel drugega USB ključka pri roki, sem naredil nekaj drugega: USB sem popolnoma izločil iz enačbe.
Network boot
Na enem od obstoječih Linux strežnikov sem postavil majhen PXE/proxyDHCP strežnik z dnsmasq. Pomemben del je bil, da nisem želel posegati v obstoječi DHCP na routerju. Zato sem uporabil proxyDHCP način. Strežnik ni dodeljeval IP naslovov. Obstoječemu DHCP strežniku je samo povedal:
“Ta računalnik se želi zagnati po omrežju. Boot image je tukaj.”
In tukaj sem naletel na zanimivo malenkost, ki mi je vzela največ časa.
Samo dhcp-boot ni bilo dovolj!
Sprva sem imel nastavljen dhcp-match in dhcp-boot.
V logih sem lepo videl:
PXEClient:Arch:00000
Torej je strežnik PXE zahtevo videl.
Toda računalnik se nikakor ni premaknil naprej.
DHCP se je samo vrtel.
Problem je bil v tem, da pravi PXE ROM na mrežni kartici uporablja nekoliko bolj specifičen PXE boot-server discovery proces. Rešitev so bile eksplicitne pxe-service direktive za BIOS in EFI.
Ko sem jih dodal, je network boot preprosto začel delovati.
In nenadoma USB ključek sploh ni bil več pomemben.
Za boot sem na mini serverju uporabil netboot.xyz, nato pa iz njegovega menija izbral Ubuntu Server.
---
Ampak potem se je zgodilo nekaj zanimivejšega
# Ampak potem se je zgodilo nekaj zanimivejšega
Ko je novi T630 končno dobil sistem, sem ugotovil, da ga pravzaprav ne želim postaviti kot popolnoma ločen, prazen testni strežnik.
-Želel sem nekaj precej bolj uporabnega:
vzporedno kopijo trenutnega produkcijskega okolja.
Ne backup v klasičnem smislu.
Ne development environment.
Ampak shadow server.
Strežnik, ki lahko uporablja realne podatke produkcije, vendar produkcije ne more spreminjati.
To je pomembna razlika.
# Shadow server
Ideja je preprosta:
PRODUCTION
│
│ read only
▼
┌──────────────┐
│ SHADOW SERVER│
└──────────────┘
│
▼
test / razvoj
Produkcija ostane produkcija.
Novi strežnik lahko bere njene podatke, vendar nima pravice pisati nazaj.
To pomeni, da lahko na njem preizkušam:
- nove verzije aplikacij,
- nove module,
- migracije,
- konfiguracijo,
- nove integracije,
- spremembe arhitekture,
brez tega, da bi eksperiment vplival na dejanski sistem.
# Ne git clone
Pri tem sem naletel še na eno zanimivo stvar.
Del produkcijskega sistema je bil Git checkout, vendar je bil shallow clone.
Zato klasični git bundle ni bil prava pot.
Namesto tega sem se odločil za preprostejši pristop:
rsync celotnega checkouta, skupaj z .git mapo.
S tem dobim praktično kopijo trenutnega delovnega okolja, Git metadata pa ostanejo uporabna.
To je ena od situacij, kjer je preprosta rešitev bolj uporabna od “pravilne” Git teorije.
Najpomembnejši del: podatki
Pri podatkih pa nisem želel narediti tega:
Shadow server ima SSH dostop do produkcije in lahko uporablja običajen uporabniški ključ.
To je preveč široko.
Namesto tega sem ustvaril poseben SSH ključ samo za to nalogo.
Na produkcijskem strežniku je ključ v authorized_keys omejen na:
rrsync -ro /pot/do/mape
in dodatno:
no-port-forwarding
Produkcija ostane produkcija.
Novi strežnik lahko bere njene podatke, vendar nima pravice pisati nazaj.
Pri podatkih pa nisem želel narediti tega:
Shadow server ima SSH dostop do produkcije in lahko uporablja običajen uporabniški ključ.
To je preveč široko.
Namesto tega sem ustvaril poseben SSH ključ samo za to nalogo.
Na produkcijskem strežniku je ključ v authorized_keys omejen na:
no-X11-forwarding no-agent-forwarding no-pty
Tako shadow server nima “SSH dostopa do produkcije” v splošnem smislu.
Ima samo eno sposobnost:
- prebrati določeno mapo.
To je precej boljša meja zaupanja.
Ena majhna past pri rrsync
Tudi tukaj je bila ena zanimiva podrobnost.
Ko rrsync omeji dostop na določeno mapo, klient ne sme ponovno podati absolutne poti.
Torej namesto:
server:/var/www/html/data
uporabiš nekaj v smislu:
server:./
Ker je korenska pot že določena z rrsync.
Če tega ne upoštevaš, lahko dobiš precej zabavne podvojene poti.
In potem pride Git
Ko sem na shadow strežnik prenesel produkcijske podatke, se je pojavil nov problem.
Nekatere JSON datoteke so bile v Git repozitoriju že prisotne kot razvojni placeholderji.
Produkcijski podatki so jih prepisali.
Git je seveda takoj povedal:
modified
Te datoteke pa morajo ostati drugačne na tej konkretni instalaciji.
Nisem želel spreminjati skupnega .gitignore, ker to ni splošno pravilo projekta.
Zato je prava rešitev lokalna:
git update-index --skip-worktree path/to/file.json
Za nove lokalne datoteke pa:
.git/info/exclude
To je lep primer razlike med:
“ta datoteka je povsod ignorirana”
in:
“ta datoteka je v tem checkoutu namerno drugačna.”
Skrivnosti pa ne kopiramo kar tako
Pri postavljanju shadow strežnika sem moral ločiti tudi običajne podatke od stvari, kot so:
* TLS certifikati, * zasebni ključi, * SMTP gesla, * podpisni certifikati.
Če je nekaj root:root in 600, tega ne poskušam “na silo” prebrati.
Če je potreben prenos, ga naredi administrator z enkratnim sudo postopkom in datoteko prenese na ciljni strežnik z ustreznimi pravicami.
To je pomembno pravilo:
Shadow okolje naj bo kopija sistema, ne kopija vseh njegovih skrivnosti.
# Še ena stvar, ki je nisem pričakoval
Ko kopiraš produkcijsko aplikacijo na drugo lokacijo, ni dovolj samo kopirati datoteke.
Stare aplikacije imajo pogosto absolutne poti:
https://production.example/...
ali:
/var/www/html/old-app/...
Na shadow strežniku lahko to povzroči zelo čudne posledice.
Lokalna aplikacija lahko nehote začne klicati pravo produkcijo.
Zato je bilo treba pregledati:
* absolutne URL-je, * filesystem poti, * konfiguracijo, * module, * zunanje API-je.
In pri tem sem naletel še na zanimiv arhitekturni problem.
# Ko funkcija “manjka”
Pri prehodu iz stare monolitne različice sistema na novejšo modularno različico se lahko zgodi, da neka stara pot vrne:
404
Prva reakcija je:
“Aha, funkcija manjka.”
Toda to ni nujno res.
Lahko je bila funkcija medtem izločena v samostojen modul oziroma svoj Git repository.
Zato je boljši vrstni red:
- 1. preveri, ali funkcija obstaja,
- 2. preveri, ali je postala samostojen modul,
- 3. poišči njeno novo lokacijo,
- 4. šele nato popravljaj ali odstranjuj staro referenco.
To je lekcija, ki je uporabna daleč preko tega konkretnega strežnika.
# Od pokvarjenega USB-ja do nove arhitekture
In tako je iz precej banalnega problema:
> “Ubuntu se noče namestiti.”
nastalo nekaj precej bolj uporabnega.
Dobil sem:
- network boot okolje,
- nov strežnik,
- kopijo produkcijskega Git okolja,
- read-only dostop do realnih podatkov,
- ločeno testno okolje,
- in predvsem možnost, da na njem razvijam brez strahu, da bom kaj pokvaril na produkciji.
Najbolj zanimivo pri takšnih projektih je ravno to, da problem, ki ga sprva poskušaš samo odpraviti, včasih pokaže boljšo arhitekturo.
Tokrat je bil problem USB ključek.
Rešitev pa ni bila nov USB ključek.
Rešitev je bila:
network boot + shadow production environment.
In mislim, da bo ta T630 od zdaj naprej precej bolj uporaben, kot sem sprva načrtoval.