6 min readDe Kicked Team
Tool-uri care rulează pe router: de ce construim software de infrastructură single-binary și local-first
Trei tool-uri open-source, o singură filosofie de design: control plane-ul trăiește pe mașină, se livrează ca un singur binar static, aplică modificările cu un auto-revert armat și îți spune sincer ce deține. Iată de ce.
- Open Source
- Infrastructure
- Linux
Anul acesta am lansat trei tool-uri open-source: nftably pentru administrarea nftables, birdy pentru administrarea BIRD și meerkat pentru a înțelege ce spune Suricata. Fac lucruri diferite, dar oricine se uită la toate trei va observa că au aceeași formă: un singur binar Go, cu SQLite în spate, care rulează chiar pe router, servește o interfață web din interiorul binarului și aplică modificările cu un auto-revert armat.
Forma asta nu e o întâmplare. Acest articol este raționamentul din spatele ei — valorile și compromisurile pe care le-am acceptat ca să le respectăm.
Control plane-ul aparține locului unde sunt consecințele
Modelul dominant pentru tooling-ul de infrastructură este un control plane aflat altundeva: un dashboard SaaS, un controller de flotă, un agent care „sună acasă". Are avantaje reale la scară. Înseamnă însă și că lucrul care îți configurează firewall-ul, sesiunile BGP sau IDS-ul depinde de uptime-ul unui furnizor, de continuarea unui abonament și de o cale de rețea care poate fi exact ce tocmai s-a stricat.
Noi construim invers. Tool-ul rulează pe mașina al cărei comportament îl schimbă. Dacă mașina e sus, control plane-ul ei e sus. Dacă internetul e jos, tot poți intra printr-un tunel SSH și repara firewall-ul — cu același tool, văzând aceeași stare. Nimic nu părăsește mașina: fără telemetrie, fără date de alerte trimise către backend-ul altcuiva înainte să le poți citi tu, ceea ce se întâmplă să fie și comportamentul corect pe uplink-urile taxate la trafic pe care trăiesc de fapt routerele de edge.
Un router ar trebui să supraviețuiască fiecărei relații cu un furnizor pe care o are proprietarul lui. Software-ul care îl administrează ar trebui construit în consecință.
Un binar, un singur fișier de stare
Fiecare tool este un singur binar Go static. Interfața web este încorporată cu go:embed, așa că nu există niciun pas de build cu node și niciun director de asset-uri de ținut sincronizat. Starea este un singur fișier SQLite. Nu există agent, nu există message bus, nu există controller de pornit mai întâi.
Consecințele operaționale sunt tocmai ideea:
- Instalarea înseamnă: pui binarul pe mașină, rulezi
init, pornești serviciul. - Upgrade-ul înseamnă: înlocuiești binarul, restartezi. Câteva secunde de downtime pentru o interfață de administrare, zero pentru data plane-ul pe care îl administrează.
- Backup-ul înseamnă: copiezi un fișier.
- Debugging-ul înseamnă: un proces, un log, pe mașina la care te uitai deja.
Fiecare dependență pe care o trage un tool după el este o promisiune pe care cineva trebuie s-o țină ani de zile. Preferăm să promitem mai puțin și să ne ținem de cuvânt.
Siguranța este o funcționalitate, nu o clauză de exonerare
Software-ul care rulează cu root pe infrastructură de rutare și firewall trebuie să trateze „și dacă modificarea asta e greșită?" ca pe o problemă de design de primă clasă, pentru că persoana care aplică modificarea ajunge de obicei la mașină prin chiar lucrul pe care îl schimbă.
Așa că toate cele trei tool-uri împărtășesc aceeași disciplină:
- Mai întâi dry-run — configurațiile candidate sunt verificate sintactic (
nft --check, parserul propriu al BIRD) înainte să se aplice orice. - Arată diff-ul — revizuiești exact ce se va schimba, iar aplicarea este un act deliberat în interfață, niciodată un efect secundar.
- Aplică atomic — modificarea ajunge ca o singură tranzacție, nu ca o secvență de stări intermediare.
- Armează revert-ul — după aplicare, un rollback este armat. Dacă modificarea te-a deconectat, configurația anterioară revine singură; dacă mai poți ajunge la interfață, confirmi și rămâne.
La fel de importantă este proprietatea explicită. nftably generează întregul conținut al fiecărei tabele pe care o administrează și nu atinge niciodată una pe care n-o administrează. birdy generează întregul bird.conf din baza lui de date. Este o regulă tăioasă, și ambele README-uri o spun într-o casetă de avertizare pe care nu ai cum s-o ratezi: regulile scrise de mână în teritoriu administrat vor dispărea după următoarea aplicare; nu îndrepta tool-ul către o configurație la care ții fără s-o imporți mai întâi. Credem că un avertisment sincer despre distrugere valorează mai mult decât o funcție de merge care funcționează pe jumătate, în tăcere. Poți raționa despre „tool-ul deține acest fișier"; nu poți raționa despre „tool-ul păstrează de obicei majoritatea lucrurilor".
Setările implicite cu opinie bat butoanele infinite
birdy generează default-deny la export conform RFC 8212, filtrare de prefixe și ASN-uri bogon, drop pentru RPKI invalid și enforce-first-AS pe eBGP — și refuză categoric să genereze o configurație despre care crede că este un route leak. nftably vine cu preset-uri de bune practici și validează că o regulă raw nu poate evada din lanțul ei.
Să expui fiecare buton și să-l lași pe operator să se spânzure singur e mai ușor de construit și mai ușor de apărat — „tool-ul a făcut ce ai cerut". Dar majoritatea operatorilor cu un singur router nu au nevoie de fiecare buton; au nevoie de configurația pe care ar fi scris-o un inginer atent. Codificarea bunelor practici ca setare implicită înseamnă că drumul leneș și drumul corect sunt același drum. Ieșirea de urgență (reguli raw, blocuri de configurație raw) există, păzită, pentru cazul cu adevărat neobișnuit — setările implicite nu sunt o cușcă, sunt o podea.
De ce 0BSD
Toate cele trei tool-uri sunt licențiate 0BSD — funcțional, domeniu public. Fără cerință de atribuire, fără text de licență de livrat, fără review juridic ca să copiezi un fișier în propriul tău tree. Sunt tool-uri pentru operatori; licența n-ar trebui să fie niciodată motivul pentru care unul stă nefolosit. Dacă o companie construiește ceva peste ele, asta înseamnă că licența funcționează, nu că eșuează.
Compromisul, spus pe șleau
Filosofia asta are o limită și merită numită: sunt tool-uri pentru o singură mașină făcută bine, nu pentru flote. Un router este administrat local; mai multe routere birdy pot fi observate unul lângă altul, dar administrarea rămâne locală pentru fiecare mașină, în mod deliberat. Când rulezi cincizeci de routere, vrei sursa de adevăr într-un pipeline de IPAM/automatizare și configurațiile generate central — iar la scara aceea, modelele SaaS și cu controller împotriva cărora am argumentat mai sus încep să-și merite complexitatea.
Majoritatea rețelelor nu au cincizeci de routere. Au unul sau două — AS-ul mic, edge-ul din colocare, laboratorul care a devenit producție pe nesimțite. Coada aceea lungă este prost deservită de tooling construit pentru flote, și pentru ea construim noi.
Concluzii
- Local-first este o poziție de fiabilitate, nu nostalgie: control plane-ul împarte soarta cu mașina, nu cu un furnizor.
- Distribuția plictisitoare este o funcționalitate — un binar, un fișier SQLite, upgrade prin înlocuire.
- Mecanismele de siguranță și regulile oneste de proprietate contează mai mult în nișa asta decât numărul de funcționalități.
- Cunoaște-ți limita — o singură mașină făcută bine, fără pretenția de a fi un manager de flotă.
Dacă edge-ul tău înseamnă una sau două mașini importante și vrei să fie administrate cu acest gen de grijă — rutare, firewall, monitorizare, hosting — exact asta facem.