Az immutable operációs rendszer
Az Aeon Desktop, az OpenSUSE immutable asztali operációs rendszere, amely a szerver operációs rendszernek szánt MicroOS alapjaira épülve kezdte meg pályafutását, azóta azonban már önálló ággá vált. Valójában a rendszer alapjai a 2017-ben indult, majd pár év múlva elkaszált Kubic projektig nyúlik vissza.
Az Aeon a Tumbleweed csomagjaiból építkezik, így egy rolling rendszerről beszélünk, de mégsem tekinthetjük azonosnak a Tumbleweeddel, hiszen felépítését tekintve teljesen más.
Jó néhány éve léteznek immutable rendszerek szerver, desktop, mobil és IoT vonalon is. Ott van többek közt a SUSE MicroOS, a SUSE SLE Micro, a Kalpa, Fedorától az Atomic desktops vonal alatt futó disztribúciók (Silverblue, Kinoite, stb.), Canonicaltól az Ubuntu Core, a Gentootól a CoreOS, a Red Hat Atomic Host a Red Hattól, és a Debianra épülő EndlessOS és a VanillaOS is, illetve az évtizedek óta létező, nem csak Linux-alapú rendszerek beágyazott vonalon. Immutable rendszerek futnak továbbá az okostelefonokon, és a NAS-ok többségén is.
Én azért döntöttem az Aeon mellett, mert mostanában szinte csak OpenSUSE rendszereket használok, így kézenfekvő választás volt egy immutable OpenSUSE rendszer kipróbálása.
Régóta kíváncsi vagyok, hogy mit tud nyújtani egy immutable rendszer a hagyományos felépítésű rendszerekhez képest, így lassan két hónapja, hogy feltelepítettem az Aeont. Eleve úgy indultam neki a tesztelésnek, hogy nem csak néhány kört akarok futni vele, mert szerintem ez a koncepció megérdemli a tüzetesebb vizsgálatot, bár sosem szoktam "félkész" (béta/alfa/RC) rendszereket kipróbálni, de most kivételt tettem. Jelen pillanatban az Aeonból az RC3-as kiadás érhető el, így én is ez alapján írom a tapasztalataimat. A tervek szerint ez az utolsó RC kiadás, úgyhogy valószínűleg a végleges kiadás sincs már túl messze, viszont mivel az Aeon a Tumbleweed csomagjaira épül, így addigra elég sok minden változhat még.
Immutábilis operációs rendszer
Az immutable (magyarul immutábilis, azaz megváltozhatatlan) operációs rendszer alapját egy csak olvasható fájlrendszer képezi, amin a rendszerállományok helyezkednek el. Ennek a megoldás az az előnye, hogy egy hibás vagy káros szoftver nem tudja felülírni a rendszerfájlokat, még sudo jogosultsággal sem.
Viszont egy immutable operációs rendszer általában ennél többet is nyújt, jellemzően az immutabilitás, az atomizáció, és a konténerizáció hármas fogalma kapcsolódik össze egy immutable rendszerben. Az alábbiakban pár bekezdésben áttekintjük, mint az az atomicitás, és mi az a konténerizáció.
Az atomicitás
Az atomicitás azt jelenti, hogy több műveletet egyetlen, elemi (atomi, azaz oszthatatlan) műveletben hajtunk végre.
Amikor "hagyományos" csomagkezelővel (apt, zypper, dnf, pacman, stb.) frissítjük a rendszerünket, a csomagkezelő a csomagokat egyesével tölti le és telepíti fel. Ennél a módszernél fenn áll a veszélye annak, hogy a csomagkezelő egy hiba folytán leáll, vagy külső hatás miatt a csomagtelepítés félbeszakad, és a rendszer inkonzisztens állapotban marad, ahol a csomagok egy része még korábbi verziójú, a másik részük viszont már friss.
Ezzel szemben az immutable operációs rendszerek által alkalmazott módszerrel a csomagfrissítés gyakorlatilag egyetlen lépésben történik meg. Bár a zypper ugyanúgy tölti le és telepíti a csomagokat, mint nem immutable rendszer esetén, de ezt egy új snapshotra teszi, és ezt a snapshotot egyetlen lépésben "húzza be" a rendszer alá a következő indításkor (erről lásd lejjebb), így éri el az atomicitást.
Mint ahogy nem tudsz egy fél, vagy egy háromnegyed bájtot a lemezre írni, hanem csak egy teljes bájtot, ugyanúgy nem tud félig lefrissítetlen és félig lefrissített állapotban maradni a rendszer - vagy lefrissül, vagy nem.
Konténerizáció
A konténer tulajdonképpen egy elszeparált futattókörnyezet az operációs rendszeren belül. Egy konténerben futtatott program csak az ugyanabban a konténerben futó processzeket látja, csak az ugyanbban a konténerben lévő fájlokhoz, könyvtárakhoz és hálózati megosztásokhoz fér hozzá, csak a konténernek átadott eszközöket látja, és így tovább. Ráadásul nagyon egyszerűen szabályzhatók a konténerben futó folyamatok erőforrásai (CPU, memória, lemez I/O, stb.). Konténerizációnak egyszerűen azt hívjuk, amikor konténerben futtatunk egy programot.
Ennek a három megoldás, az immutabilitás, az atomizáció, és a konténerizáció összegyúrásából áll egy immutable operációs rendszer. Természetesen mindhárom technológiát lehet használni a többi nélkül (és használják is), és az is igaz, hogy nem feltétlenül igaz mind a három egy immutable operációs rendszerre, csupán általánosan jelenthető ki.
Nézzük meg, milyen előnyei vannak ennek a hármas megoldásnak:
- az atomicitásnak köszönhetően egy hibás vagy megszakadt frissítés bármikor visszaállítható egy gyors "rollbackkel"
- a konténerizált futtatásnak hála az alaprendszer és a felhasználói alkalmazások egymástól elszeparálva működnek, az alkalmazások nem "szemetelik" tele a csomagjaikkal a rendszert, és nem tudnak függőségi problémákba ütközni az alaprendszer csomagjaival
- ugyan ezen okból kifolyólag a programok jogosultságai finomabban és egyszerűbben szabályozhatók, mint a hagyományos UNIX-os ugo-rwx megoldással
- a frissítések telepítése gördülékenyebb és kevésbé kockázatos, kevesebb a stabilitást veszélyeztető faktor
Természetesen mindennek vannak hátrányai is:
- mivel a rendszer komplexebb, több rétegből áll, mint a hagyományos disztribúciók, ezért külön kell menedzselni az egyes alkalmazásrétegeket (rendszerszint, distrobox konténer(ek), flatpak, stb.)
- gyakrabban kell újraindítani
- a konténerizáció nincs ingyen, több erőforrást követel, mint a hagyományos módon futtatott programok
- egyes szoftverek nem képesek működni immutable rendszeren
- jelenleg az asztali környezetek közül sem mind használható immutable rendszerrel, az Aeon csak a Gnome-ot támogtja, a KDE például csak bizonyos megkötésekkel (pl. az SDDM hátterét nem lehet lecserélni, csak némi "hackeléssel") - ha KDE felületet szeretnék használni, próbáljuk ki a Kalpát (https://en.opensuse.org/Portal:Kalpa)
Az Aeon Desktop a következőket ígéri:
- minimális operációs rendszer réteg
- a rendszer és az alkalmazások elkülönítése
- beavatkozás nélküli automatikus frissítés
- hibás vagy nem működő rendszerfrissítés esetén automatikus visszaállítás
- gyorsaság, stabilitás, megbízhatóság, kiszámíthatóság
- letisztult Gnome felület
- asztali felhasználáshoz szükséges összetevők (média, játékok, GPU driverek, stb.) kiemelt támogatása
Vannak azonban komoly megkötések is:
- az Aeon nem támogatja a dual-bootot másik rendszerrel azonos lemezen, ha telepíted, a teljes lemezt fel fogja használni
- bootmanagerként nem Grub, hanem systemd-boot szolgál, tehát csak EFI-képes gépeken fog bebootolni
- mivel az Aeon erősen épít a BTRFS subvolume és snapshot funkciójára, ezért gyökérfájlrendszernek csak BTRFS használható (adatfájlrendszerként természetesen lehet használni mást is)
- a rendszer teljes lemeztitkosítással érkezik (full disk encryption), és ezt nem is lehet kikapcsolni (már akinek ez hátrány)
Mivel az Aeon erősen támaszkodik a BTRFS tulajdonságaira, azért az alábbiakban szentelünk pár bekezdést a BTRFS subvolume és snapshot funkcióira. Ezután áttekintjük a transactional-update és a distrobox parancsokat, később lesz pár szó a konténerizációról, utána pedig megnézzük a konkrét telepítést és a belakást.
Ezután kicsit mélyebben is megismerkedünk az említett két említett parancssal, majd lesz még néhány szó az Aeon sajátosságairól, végül a személyes véleményemet is leírom a rendszerről.
Subvolume-ok
A BTRFS fájlrendszer támogatja az ún. subvolume-ok (alkötetek) létrehozását. Ez a fájlrendszer egy elkülönített része ("fájlrendszer a fájlrendszeren belül"), mely saját file- és könyvtárhierarchiával rendelkezik, és ugyanúgy felcsatolható, mint bármilyen más fájlrendszer (mint pl. egy pendrive-on lévő partíció). A subvolume alapvetően könyvtárként jelenik meg, és ugyanúgy is tudjuk kezelni (át tudjuk nevezni, törölni tudjuk, stb.), amíg nincs felcsatolva, ha felcsatolásra kerül, akkor pedig csatolási pontként (mount point) látható, épp úgy, mint a már megszokott csatolási pontjaink.
BTRFS fájlrendszerben maga a gyökér (/) is a egy subvolume, Aeon alatt pedig a gyökér fájlrendszer több subvolume-ra van felosztva.
Ha megnézzük az Aeon subvolume-jait, ezt fogjuk látni:
@/home
@/opt
@/root
@/srv
@/var
@/usr/local
@/.snapshots
Itt a gyökér fájlrendszer (/) subvolume immutable, azaz csak olvasható, az összes többi írható és olvasható. Erre a felosztásra azért van szükség, mert a subvolume-on lévő könyvtárakban vagy olyan adatokat tárolunk, amelyek természetükből adódóan változnak (pl. logok a /var/log alatt), vagy felhasználói adatokat (pl. a /home) alatt, amiket nyilván írni is szeretnénk, nem csak olvasni. Így ezeket a könyvtárakat külön kell kezelnünk a rendszer részeitől.
Az /etc nem szerepel a felsorolásban, ennek pedig az az oka, hogy ez egy kitüntetett szerepű könyvtár, így működését speciális módon oldották meg, az OverlayFS segítségével. Az OverlayFS-ről lehet olvasni a neten, most egyelőre elég csak annyit tudni, hogy az /etc létezik csak írható, és írható-olvasható formában is, de ebből felhasználóként semmit nem fogunk érzékelni (legfeljebb annyit, hogy egyes konfigurációs fájlok alapértelmezett helye átkerült az /usr könyvtárba). Ugyanúgy kezelhetjük továbbra is az /etc-t, mint korábban.
A fájlrendszer részletesebb kifejtésért lásd Richard Brown, az Aeon vezető fejlesztőjének Reddit posztját: https://www.reddit.com/r/openSUSE/comments/117sdwj/comment/j9ekipe/
------
Subvolume vs. bind mount
Mik az előnyeik a subvolume-oknak a bind mounttal szemben?
- subvolume-ról lehet különálló snapshotot készíteni (lásd alább)
- eltérő opciókkal is fel lehet csatolni őket (pl. csak olvashatóként)
- subvolume-okra kvótát is be lehet állítani
------
Snapshotok
BTRFS-en a snapshot a fájlrendszer pillanatképe, azaz a fájlok- és mappák jelenlegi állapota. A snapshotok és a subvolume-ok szorosan összefüggnek, mivel a snapshot valójában egy speciális típusú subvolume, amely a fájlrendszer aktuális állapotát rögzíti. Tehát amikor snapshotot készítünk a fájlrendszerünkről, egy subvolume jön létre, ami a fájlrendszerünket tartalmazza, a mostani állapotában.
Mielőtt azonban azt gondolnák, hogy ez hosszú ideig tart és sok helyet foglal, tudnunk kell, hogy a snapshotok ún. copy-on-write metódussal készülnek. Ez azt jelenti, hogy amikor egy snapshotot készítünk, akkor NEM készül másolat a fájljainkról, hanem a másolat közvetlen azelőtt készül, mielőtt elkezdenénk módosítani az eredeti fájlokat (és akkor is csak azokról a blokkokról, amelyek módosulni fognak). Tehát a snapshot nem az eredeti fájlrendszer teljes másolatát tárolja, hanem csak egyfajta különbözetet az eredeti és a módosított blokkokról.
Így a fájlblokkok módosított állapota a jelenlegi fájlrendszeren lesz megtalálható, a eredeti (korábbi) állapotuk pedig a snapshoton. A rendszer minden pillanatban tökéletesen pontosan nyilvántartja, hogy az egyes fájlblokkok mely fájlokhoz tartoznak és mely snapshoton találhatók, így képes a módosításokat különválasztani az eredeti blokkoktól, és szükség esetén gyorsan visszaállítani az eredeti állapotot.
A fájlok, blokkok és snapshotok nyilvántartását a rendszer a felhasználó számára teljesen transzparensen hatja végre, minimális overheaddel.
Itt jön egy nagyon fontos dolog: a boot manager képes elindítani a rendszert egy adott snapshotról is, nem csak a jelenlegi fájlrendszerről.
Ez azt jelenti, hogy ha minden egyes csomagtelepítés/törlés (rendszerfrissítés) előtt készítünk egy snapshotot a rendszerünkről, és azon hajtjuk végre a változtatásokat, a következő bootoláskor pedig arról a snapshotról bootolunk be, akkor a rendszerünk korábbi állapota megmarad, és bármikor vissszaállhatunk rá. Így nem kell aggódnunk egy esetleg hibás frissítés miatt, egyszerűen csak bebootolunk egy korábbi snapshotról, és van egy működő rendszerünk.
Jelenleg több disztribúció is azt a gyakorlatot követi, hogy kernelfrissítés esetén megtart néhány korábbi változatot a kernelből. A snapshot révén nem csak a kernelből tarthatunk meg korábbi változatokat, hanem a rendszerből, amire pillanatok alatt visszaállhatunk.
Természetesen a snapshotkészítésből ki lehet zárni egyes könyvtárakat vagy subvolume-okat, amiket később nem szeretnénk visszaállítani, és magától értedődően - többek közt - a teljes /home alapértelmezetten ki is van zárva, azért, hogy egy esetleges visszaállítás ne érintse a személyes fájlainkat. A fent említett olvasható és írható subvolume-ok szintén ki vannak zárva, így ezekről nem készül snapshot, és egy esetleges rollback esetén sem kerülnek visszaállításra. Az /etc viszont nincs kizárva, egy rendszervisszaállítás hatására tehát az /etc tartalma is visszaáll a korábbi változatra.
------
A BTRFS send/receive módszerével ki tudjuk küldeni egy snapshot tartalmát egy fájlba vagy egy másik fájlrendszerre (pl. egy külső merevlemezre vagy hálózati megosztásra - akkor is, ha az nem BTRFS), ilyenkor az alapfájlrendszer, és azon felül a snapshot tartalma is kimegy, így tényleges másolat (backup) készíthető a fájlrendszerről. Részletek: https://btrfs.readthedocs.io/en/latest/Send-receive.html
------
transactional-update
A transactional-update-t parancsot előreveszem, mert szorosan kapcsolódik a snapshotokhoz, de itt szeretném jelezni, hogy NEM ez a programok telepítésének preferált módja! A transactional-update alapvetően a rendszer frissítéséhez használatos, és ezzel tudunk ugyan telepíteni/etávolítani/frissíteni csomagokat, de csak olyan, rendszerközeli csomagokhoz használjuk, amelyeknek mindenképp az alaprendszerben kell lenniük (GPU driverek, VPN kernel modulok, stb.).
Nos, most, hogy már jártasak vagyunk a subvolume-ok és a snapshotok világában, könnyű elmagyarázni ennek a hossznevű parancsnak a működését.
Amikor a transactional-update-et meghívjuk, minden egyes alkalommal készít egy snapshotot a jelenlegi fájlrendszerről, és arra dolgozik (telepít/töröl/frissít), azaz a futó rendszert egyáltalán nem érinti az adott művelet. Ezután, ha újraindítjuk a gépet, és a művelet (mondjuk egy teljes rendszerfrissítés) hibamentesen lefutott, az Aeon az új snapshotról fog bebootolni, ha azonban a művelet hibára futott, vagy valamilyen külső ok miatt megszakadt, akkor a korábbi snapshotról, így a rendszerünk szinte mindig biztosan indítható marad. Szerintem ez olyan jó megoldás, hogy szerintem az asztali disztróknak már rég így kellene működnie!
További előnye ennek a módszernek, hogy így nem alakulhat ki olyan állapot, ahol a rendszer részben még a régi csomagokat tartalmazza, részben viszont már az újakat. Vagy a régi verzió van fent, vagy az új - nincs köztes állapot.
A transactional-update
- biztosítja a rendszer számára az atomicitást (egy tranzakcióban történő frissítést)
- visszavonható, azaz ha az művelet hibával kilép, vagy valamilyen oknál fogva leáll (pl. elmegy az áram), a rendszer ezt érzékeli, és a teljes műveletet visszavonja (pontosabban nem is alkalmazza azt a snapshotot, amire dolgozott).
Ahogy feljebb is írtam, nem ezt a preferált telepítési mód, hanem (most kapaszkodj meg): a Flatpak! És erről itt nem is írok többet, mert a flatpakot mindenki ismeri, aki legalább két hete Linuxozik, és mindenkinek van is róla véleménye. Rengeteg anyag található róla a neten, még magyarul is van róla ez-az. Ha gondolod, olvasd el a Flatpakról szóló cikkem.
Egy másik csomagtelepítési módszerről szeretnék beszélni, ez pedig a Distrobox. De mielőtt mélyebben belemennénk, muszáj írnom pár szót a konténerizációról, hogy megértsd a distrobox működését. Ha esetleg olvastad a korábban közétett, Distroboxról szóló cikkem, akkor ezt a részt átugorhatod!
Konténerizáció Distrobox-szal
A Distrobox egy segédeszköz, amivel konténerizált Linuxot futtathatunk úgy, hogy a létrehozott konténer szorosan integrálódik a rendszerbe. Maga a Distrobox nem egy konténer implementáció, hanem Dockerre, Podmanre vagy Lilipodra épülve oldja meg a konténerizációt. A Podman a javasolt megoldás, mert "rootless", azaz nem szükséges hozzá, hogy folyamatosan fusson egy root szintű daemon, mint Docker esetében.
A konténerekben futó operációs rendszer kernele osztozik a gazdagépen futtatott kernellel, az izoláció kernel szinten történik, tehát a kerneltől "magasabb" (felhasználó-közelibb) szinten lévő rétegek különölnek.
------
"Egy kép többet mond minden szónál" elv alapján talán jobban érthető ez az egész, ha a fejlesztő oldalán megnézzük ezt az képet: https://user-images.githubusercontent.com/598882/144294862-f6684334-ccf4-4e5e-85f8-1d66210a0fff.png
------
Egy immutable rendszerben kifejezetten hasznos tud lenni a Distrobox, hiszen az egyik legfontosabb törekvés az, hogy az alaprendszert tartsuk tisztán és "minimálisan", és csak a legfontosabb csomagokat telepítsük oda, és így megvalósul a rendszer és az alkalmazások szeparációja. Viszont itt hívnám fel a figyelmet arra, hogy a Distrobox úgy lett kialakítva, hogy a konténerben futtatott rendszer a lehető legszorosabban integrálódjon a gazdarendszerbe, és ezt többek közt ezt azzal éri el, hogy a teljes /home könyvtárunkhoz hozzáfér, látja a futó folyamatainkat, osztozik a gazdarendszer X/Wayland sessionjével, stb. A distrobox konténerei tehát nagyon "nyitott" konténerek, ellentétben mondjuk egy Docker konténerrel, vagy egy flatpak csomaggal. Így ez nem tekinthető egy biztonsági megoldásnak (security sandbox), tehát veszélyes alkalmazásokat ne futtassunk Distrobox konténerben (sem)!
Továbbá, a konténer nem virtuális gép, tehát ne várjuk azt, hogy majd szépen látjuk, amint megjelenik a Plymouth képernyő, és majd szépen látjuk, ahogy bebootol a rendszer. A konténerezett disztribúciót parancssorból lehet kezelni, de ettől függetlenül grafikus alkalmazások is futtathatók benne.
Arra mindenképpen jó, hogy hagyományos módon, csomagkezelővel telepíthessünk szoftvereket immutable rendszeren, emellett pedig van még egy hatalmas előnye, hogy különféle disztribúciókat, és azok különféle verzióit is futtathatjuk egy időben! Ez azt jelenti, hogy egy adott csomagból használhatunk régebbi, Debian-os verziót, egy másikból mondjuk egy Fedorás verziót, egy harmadikból pedig egy nagyon friss Arch-verziót. Szerintem ez azért elég menő dolog :)
A cikk még nem ért véget, kérlek, lapozz!