
Ustvariti aplikacijo za varnostno kopiranje, ki deluje na kateri koli distribuciji, je zahtevna naloga. Da bi zagotovili delovanje Veeam Agent for Linux na distribucijah od Red Hat 6 in Debian 6 do OpenSUSE 15.1 in Ubuntu 19.04, je potrebno reševati vrsto težav, še posebej, če upoštevamo, da programski izdelek vključuje jedrni modul.
Članek je bil pripravljen na podlagi nastopa na konferenci .
Linux ni le ena izmed najbolj priljubljenih operacijskih sistemov. V bistvu je to platforma, na kateri lahko ustvarite nekaj edinstvenega, nekaj svojega. Zaradi tega je na voljo veliko Linux distribucij, ki se razlikujejo po naboru programskih komponent. Tu se pojavi težava: da bi programski izdelek deloval na kateri koli distribuciji, je potrebno upoštevati posebnosti vsakega.
Upravitelji paketov. .deb vs .rpm
Začnimo z očitno težavo distribucije izdelka za različne distribucije.
Najbolj tipičen način distribucije programskih izdelkov je objava paketa v repozitoriju, da ga lahko vgrajeni upravitelj paketov v sistemu namesti od tam.
Imamo pa dva priljubljena formata paketov: rpm in deb. Torej je treba podpirati vsak.
V svetu deb-paketov je raven združljivosti osupljiva. Enak paket se enako dobro namesti in deluje tako na Debian 6 kot na Ubuntu 19.04. Standardi postopka gradnje paketov in dela z njimi, določeni v starejših Debian distribucijah, ostajajo aktualni tudi v sodobnih Linux Mint in elementary OS. Zato pri Veeam Agent for Linux zadostuje en deb-paket za vsako strojno platformo.
V svetu rpm-paketov pa so razlike velike. Prvič, ker obstajata dva povsem neodvisna distributerja, Red Hat in SUSE, pri katerih združljivost ni potrebna. Drugič, ti distributerji imajo distribucije s tehnično podporo in eksperimentalne. Med njimi združljivost prav tako ni potrebna. Tako smo prišli do tega, da imamo svoje pakete za el6, el7 in el8. Poseben paket za Fedora. Paketi za SLES11 in 12 ter ločen za openSUSE. Glavna težava so odvisnosti in imena paketov.
Težava z odvisnostmi
Žal se enaki paketi pogosto pojavijo pod različnimi imeni v različnih distribucijah. Spodaj je nepopoln seznam odvisnosti paketa veeam.
Za EL7:
Za SLES 12:
- libblkid
- libgcc
- libstdc++
- ncurses-libs
- fuse-libs
- file-libs
- veeamsnap = 3.0.2.1185
- libblkid1
- libgcc_s1
- libstdc++6
- libmagic1
- libfuse2
- veeamsnap-kmp = 3.0.2.1185
Kot je seznam odvisnosti edinstven za distribucijo.
Še slabše je, ko se pod starim imenom paketa začne skrivati posodobljena različica.
Primer:
V Fedora 24 se je posodobil paket ncurses z različice 5 na različico 6. Naš izdelek je bil sestavljen natančno z 5. različico, da bi zagotovili združljivost s starimi distribucijami. Za uporabo stare 5. različice knjižnice v Fedora 24 je bilo potrebno uporabiti paket ncurses-compat-libs.
Kot rezultat na Fedora nastaneta dva paketa z različnimi odvisnostmi.
Naprej postane zanimivo. Po še eni posodobitvi distribucije paket ncurses-compat-libs z 5. različico knjižnice postane nedostopen. Za distributerja je drago vleči stare knjižnice v novo različico distribucije. Čez nekaj časa se je težava ponovila tudi v distribucijah SUSE.
Kot rezultat so se morali nekateri distributerji odpovedati eksplicitni odvisnosti od ncurses-libs, izdelek pa popraviti tako, da lahko deluje z katerokoli različico knjižnice.
Mimogrede, v 8. različici Red Hat ni več meta-paketa python, ki je skliceval na staro dobro python 2.7. Na voljo je python2 in python3.
Alternativa paketnim upraviteljem
Težava z odvisnostmi je stara in že dolgo očitna. Spomnimo se na ala Dependency hell.
Združiti raznolike knjižnice in aplikacije tako, da vse stabilno delujejo in se ne konfliktirajo - to nalogo v resnici poskuša rešiti vsak Linux distributer.
Popolnoma drugače to težavo poskuša rešiti paketni upravitelj Snappy od Canonical. Osnovna ideja: aplikacija deluje v izoliranem in zaščitenem peskovniku od glavnega sistema. Če aplikaciji potrebujete knjižnice, se te dostavijo skupaj z aplikacijo.
Flatpak prav tako dovoljuje zagon aplikacij v peskovniku, pri čemer uporablja Linux Containers. Idejo peskovnika uporabi tudi AppImage.
Te rešitve omogočajo ustvarjanje enega paketa za vse distribucije. V primeru Flatpak je namestitev in zagon aplikacije možen celo brez vedenja skrbnika.
Osnovna težava je, da ne morejo vse aplikacije delovati v peskovniku. Nekatere potrebujejo neposreden dostop do platforme. O modulih jedra, ki močno odvisni od jedra in se nikakor ne prilegajo v koncept peskovnika, niti ne govorim.
Druga težava - priljubljene distribucije v korporativnem okolju, kot sta Red Hat in SUSE, še ne podpirajo Snappy in Flatpak.
Zaradi tega Veeam Agent for Linux ni na niti na .
Na koncu vprašanja o upravljavcih paketov moram omeniti, da obstaja možnost popolnoma opustiti upravljavce paketov in združiti binarne datoteke ter skript za njihovo namestitev v en sam paket.
Takšen paket omogoča ustvarjanje enega skupnega paketa za različne distribucije in platforme, kar omogoča interaktiven proces namestitve ter nujno prilagajanje. S takimi paketi sem se srečal pri Linuxu le od VMware.
Problem posodobitev

Tudi če so vse težave z odvisnostmi rešene, lahko program deluje različno na isti distribuciji. Problem so posodobitve.
Obstajajo 3 strategije posodabljanja:
- Najenostavnejša je, da nikoli ne posodabljamo. Nastaviš strežnik in pozabiš. Zakaj posodobitve, če vse deluje? Težave se začnejo ob prvem kontaktu s podporo. Ustvarjalec distribucije podpira le posodobljeno različico.
- Lahko se zaupaš distribucijskemu podjetju in nastaviš samodejno posodabljanje. V tem primeru je klic v podporo verjeten takoj po neuspešni posodobitvi.
- Možnost ročne posodobitve šele po preizkušanju na testni infrastrukturi je najgotovnejša, vendar draga in zamudna. Daleč od tega, da si to lahko privošči vsak.
Ker različni uporabniki uporabljajo različne strategije posodabljanja, je treba podpirati tako najnovejšo različico kot tudi vse prejšnje izdaje. To otežuje tako razvojni proces kot testiranje ter povzroča težave podporni službi.
Raznolikost strojnih platform
Različne strojne platforme so težava, ki je v znatni meri specifična prav za native-kodo. Vsaj za vsako podporno platformo je potrebno zgraditi binarne datoteke.
V projektu Veeam Agent for Linux še ne moremo podpreti niti ene stvari za RISC.
Ne bom se podrobno ustavljal pri tem vprašanju. Omenil bom le glavne težave: platformno odvisni tipi, kot so size_t, poravnava struktur in vrstni red bajtov.
Statično in/ali dinamično povezovanje

Vprašanje "Kako se povezovati z bibliotekami - dinamično ali statično?" pa je vredno razprave.
Na splošno C/C++ aplikacije pod Linuxom uporabljajo dinamično povezovanje. To deluje odlično, če je aplikacija zgrajena posebej za določeno distribucijo.
Če je cilj zajeti različne distribucije s pomočjo ene same binarne datoteke, se je treba osredotočiti na najstarejšo podporno distribucijo. Za nas je to Red Hat 6. Ta vsebuje gcc 4.4, ki celo standard C++11 ne podpira. .
Naš projekt sestavljamo s pomočjo gcc 6.3, ki popolnoma podpira C++14. Seveda v tem primeru na Red Hat 6 knjižnici libstdc++ in boost moramo nositi s seboj. Najlažje je povezati se z njima statično.
Žal pa ni mogoče z vsemi knjižnicami povezovati statično.
Prvič, sistemske knjižnice, kot so libfuse, libblkid je treba povezati dinamično, da se zagotovi njihova združljivost z jedrom in njegovimi moduli.
Drugič, obstaja majhna težava glede licenc.
Licenca GPL načeloma dovoljuje povezovanje knjižnic samo z odprtokodnim kodom. MIT in BSD dovoljujeta statično povezovanje in omogočata vključitev knjižnic v projekt. Vendar pa LGPL nekako ne nasprotuje statični povezavi, vendar zahteva, da se zagotovi dostop do datotek, potrebnih za povezovanje.
Na splošno bo uporaba dinamičnega povezovanja preprečila potrebo po zagotavljanju nečesa.
Zbiranje C/C++ aplikacij
Za zbiranje C/C++ aplikacij za različne platforme in distribucije je dovolj, da izberemo ali zberemo ustrezno različico gcc in uporabimo križne prevajalnike za specifične arhitekture ter zberemo celoten nabor knjižnic. To je povsem izvedljivo, a precej zamudno. In ni nobenih jamstev, da izbrani prevajalnik in knjižnice zagotavljajo delujočo različico.
Očitna prednost: infrastruktura se zelo poenostavi, saj se celoten postopek zbiranja lahko opravi na enem računalniku. Poleg tega je dovolj, da zberemo en komplet binarnih datotek za eno arhitekturo in jih lahko pakiramo v pakete za različne distribucije. Tako se zbirajo paketi veeam za Veeam Agent for Linux.
Namesto te rešitve lahko preprosto pripravite build farmo, torej več strojev za sestavljanje. Vsak tak stroj bo zagotavljal kompilacijo aplikacije in pripravo paketa za določen distribucijski sistem in specifično arhitekturo. V tem primeru se kompilacija izvede z orodji, ki jih je pripravil distributer. Tako se izognete fazi priprave kompilatorja in izbiri knjižnic. Poleg tega je proces sestavljanja enostavno paralelizirati.
Seveda pa ima ta pristop tudi slabost: za vsak distribucijski sistem znotraj ene arhitekture bo treba sestaviti svoj nabor binarnih datotek. Tudi slabost je ta, da je potrebno vzdrževati tolikšno število strojev, kar zahteva veliko diskovnega prostora in RAM-a.
Tako se sestavljajo KMOD paketi modula jedra veeamsnap za distribucijske sisteme Red Hat.
Open Build Service
Kolegi iz SUSE so poskusili uresničiti svojo zlato sredino v obliki posebne storitve za kompilacijo aplikacij in pripravo paketov — .
V bistvu gre za hipervizor, ki ustvarja virtualni stroj, namešča vse potrebne pakete, izvaja kompilacijo aplikacije in sestavi paket v tem izoliranem okolju, po katerem se tak virtualni stroj osvobodi.

Načrtovalnik, implementiran v OpenBuildService, sam določi, koliko virtualnih strojev lahko zažene za optimalno hitrost sestavljanja paketov. Vgrajeni mehanizem podpisa samodejno podpiše pakete in jih naloži na vgrajen repozitorij. Vgrajeni sistem za verzioniranje ohranja zgodovino sprememb in sestavljanj. Ostane le, da v to sistem dodate svoje izvorne kode. Tudi strežnik ni nujno dvigniti sam, temveč lahko izkoristite odprto različico.
Tu pa je problem: takšen kombajn se težko vklopi v obstoječo infrastrukturo. Na primer, verzioniranje ni potrebno, saj imamo svojega za izvorne kode. Mehanizem podpisa se razlikuje: uporabljamo poseben strežnik. Repozitorij prav tako ni potreben.
Poleg tega je podpora za druge distribucijske sisteme — na primer, Red Hat — precej omejena, kar je povsem razumljivo.
Prednost takšne storitve je hitra podpora za novo različico distribucije SUSE. Pred uradnim razglasitvijo o izdaji so potrebni paketki za sestavljanje na voljo v javnem repozitoriju. Na seznamu razpoložljivih distribucij v OpenBuildService se pojavi nov. Označimo ga in doda se v načrt sestavljanja. Tako dodajanje nove različice distribucije poteka skoraj z enim klikom.
V naši infrastrukturi, ki uporablja OpenBuildService, se zbira vsa raznolikost KMP paketov modula jedra veeamsnap za distribucije SUSE.
Nato bi se rad osredotočil na vprašanja, specifična prav za module jedra.
kernel ABI
Moduli jedra Linuxa so se zgodovinsko širili v obliki izvorne kode. Gre za to, da ustvarjalci jedra ne obremenjujejo sebe s skrbjo za podporo stabilnega API za module jedra, še posebej na binarni ravni, kar velja za kABI.
Za sestavljanje modula za vanilno jedro so nujni header-ji prav tega jedra in deloval bo samo na tem jedru.
DKMS omogoča avtomatizacijo procesa sestavljanja modulov ob posodobitvi jedra. Kot rezultat, uporabniki repozitorija Debian (in njegovih številnih sorodnikov) uporabljajo module jedra bodisi iz repozitorija dobavitelja bodisi sestavljene iz izvorne kode s pomočjo DKMS.
Toda taka situacija ne ustreza prav Enterprise-segmentu. Distribuatorji proprietarne kode želijo širiti izdelek v obliki zbranih binarnih datotek.
Skupni administratorji ne želijo hraniti razvojnika na produkcijskih strežnikih iz varnostnih razlogov. Distribuatorji Enterprise Linux — kot so Red Hat in SUSE — so se odločili, da bodo za svoje uporabnike podpirali stabilno kABI. Tako so se pojavili KMOD paketi za Red Hat in KMP paketi za SUSE.
Osnova takšnega rešitev je precej preprosta. Za določeno različico distribucije se API jedra zamrzne. Distribuator izjavi, da uporablja prav to jedro, na primer 3.10, in uvaja samo popravke in izboljšave, ki nikakor ne vplivajo na vmesnike jedra, tako da lahko moduli, zbrani za prvotno jedro, delujejo za vse nadaljnje brez ponovne kompajlacije.
Red Hat trdi, da bo ohranila kABI združljivost za distribucijo skozi celotno življenjsko dobo. To pomeni, da bi moral zgrajen modul za rhel 6.0 (izdaja november 2010) delovati tudi na različici 6.10 (izdaja junij 2018). To je skoraj 8 let. Seveda je to precej zapletena naloga.
Zabeležili smo več primerov, ko je zaradi težav s kABI združljivostjo modul veeamsnap prenehal delovati.
Ko se je modul veeamsnap, zgrajen za RHEL 7.0, izkazal za nezdružljivega z jedrom iz RHEL 7.5, čeprav se je nalagal in zagotovo sesul strežnik, smo opustili uporabo kABI združljivosti za RHEL 7 na splošno.
Trenutno KMOD paket za RHEL 7 vsebuje zbirko za vsako različico izdaje in skript, ki zagotavlja nalaganje modula.
SUSE je k nalogi kABI združljivosti pristopila bolj previdno. KABI združljivost zagotavljajo le v okviru ene različice servisnega paketa.
Na primer, izdaja SLES 12 je bila objavljena septembra 2014. SLES 12 SP1 pa že decembra 2015, kar pomeni, da je preteklo malo več kot eno leto. Kljub temu, da obe izdaji uporabljata jedro 3.12, sta si kABI nezdružljivi. Očitno je, da je vzdrževanje kABI združljivosti samo eno leto bistveno lažje. Letni cikel posodobitev modula jedra ne bi smel povzročati težav ustvarjalcem modulov.
Zaradi te politike SUSE nismo zabeležili nobenih težav s kABI združljivostjo našega modula veeamsnap. Res pa je, da je število paketov za SUSE skoraj za red večje.
Popravki in backporti
Kljub temu, da se distributerji trudijo zagotavljati kABI združljivost in stabilnost jedra, si tudi prizadevajo izboljšati zmogljivost in odpraviti napake tega stabilnega jedra.
Poleg lastnega 'dela na napakah' razvijalci jedra enterprise linux spremljajo spremembe v vanilijevem jedru in jih prenašajo v svoje 'stabilno'.
Včasih to pripelje do novih .
V zadnjem izdajanju Red Hat 6 v enem od manjših posodobitev je bila storjena napaka. To je povzročilo, da je modul veeamsnap zagotovo sesul sistem ob sproščanju posnetka. Po primerjavi izvornih kod jedra pred in po posodobitvi smo ugotovili, da je bila za vse kriva backport. Podoben popravek je bil narejen v vanilijevem jedru različice 4.19. Toda v vanilijevem jedru je ta popravek deloval normalno, pri prenosu v 'stabilno' 2.6.32 pa je nastala težava s spin-lockom.
Seveda, napake se zgodijo vsem in vedno, vendar ali je bilo vredno prenašati kodo iz 4.19 v 2.6.32, ob tem pa tvegati stabilnost?.. Nisem prepričan…
Najhuje je, ko se k vlečenju vrvi "stabilnost""modernizacija" priključi marketing. Marketingu je treba, da je jedro posodobljenega distribucijskega sistema stabilno, hkrati pa bolj učinkovito in z novimi funkcijami. To vodi do čudnih kompromisov.
Ko sem poskusil zgraditi modul na jedru 4.4 iz SLES 12 SP3, sem s presenečenjem odkril, da ima funkcionalnost iz navadne 4.8. Po mojem mnenju je implementacija blokovnega I/O jedra 4.4 iz SLES 12 SP3 bolj podobna jedru 4.8 kot prejšnji stabilni 4.4 iz SLES12 SP2. Ne morem oceniti, kakšen je bil delež prenesene kode iz jedra 4.8 v SLES-ovih 4.4 za SP3, a jih ne morem imenovati kot še vedno stabilno 4.4.
Najbolj neprijetno pri tem je, da pri pisanju modula, ki bi enako dobro deloval na različnih jedrih, več ne moremo zanašati na različico jedra. Treba je upoštevati tudi distribucijo. Dobro je, da se včasih lahko zanašamo na definicijo, ki se pojavi skupaj z novo funkcionalnostjo, a ta možnost ne pride vedno.
Zaradi tega se koda obda s čudnimi direktivami pogojne kompajlacije.
Pojavljajo se tudi popravki, ki spremenijo dokumentirano API jedra.
Naletel sem na distribucijo 5.16 in sem bil zelo presenečen, ko sem opazil, da je klic lookup_bdev v tej različici jedra spremenil seznam vhodnih parametrov.
Za gradnjo je bilo treba dodati skript v makefile, ki preveri, ali ima funkcija lookup_bdev parameter mask.
Podpis jedrskih modulov
Vrnimo se k vprašanju distribucije paketov.
Ena izmed prednosti stabilnega kABI je, da se jedrski moduli v obliki binarne datoteke lahko podpišejo. V tem primeru se lahko razvijalec prepriča, da modul ni bil naključno poškodovan ali namerno spremenjen. To je mogoče preveriti z ukazom modinfo.
Distribucije Red Hat in SUSE omogočajo preverjati podpis modula in ga naložiti le, če je v sistemu registriran ustrezen certifikat. Certifikat predstavlja javni ključ, s katerim se modul podpiše. Širimo ga kot ločen paket.
Težava je v tem, da so certifikati lahko bodisi vgrajeni v jedro (nanje se sklicujejo distributerji) bodisi jih je treba zapisati v neobčutljivo EFI pomnilnik z uporabo programa. mokutil. Alat mokutil pri namestitvi certifikata zahteva ponovni zagon sistema in celo pred nalaganjem jedra operacijskega sistema ponuja skrbniku, da odobri nalaganje novega certifikata.
Tako dodajanje certifikata zahteva fizični dostop skrbnika do sistema. Če se naprava nahaja nekje v oblaku ali preprosto v oddani strežniški lokaciji ter je dostopna le prek omrežja (na primer prek ssh), dodajanje certifikata ne bo mogoče.
EFI na virtualnih napravah
Kljub temu, da EFI že dolgo podpira skoraj vsak proizvajalec matičnih plošč, lahko skrbnik pri namestitvi sistema ne pomisli na potrebo po EFI in ga lahko izklopi.
Ne vsi hipervizorji podpirajo EFI. VMWare vSphere podpira EFI od različice 5 naprej.
Microsoft Hyper-V je prav tako začel podpirati EFI od Hyper-V za Windows Server 2012R2.
Vendar je v privzeti konfiguraciji ta funkcionalnost za Linux naprave izključena, kar pomeni, da certifikata ni mogoče namestiti.
V vSphere 6.5 je nastavitev Secure Boot možno nastaviti le v stari različici spletnega vmesnika, ki deluje preko Flash. Spletni vmesnik na HTML-5 še močno zaostaja.
Eksperimentalne distribucije
Nazadnje bomo obravnavali vprašanje eksperimentalnih distribucij in distribucij brez uradne podpore. Po eni strani takšnih distribucij verjetno ne boste našli na strežnikih resnih organizacij. Takšne distribucije nimajo uradne podpore. Zato zagotavljanje tehnične podpore za izdelek na takšni distribuciji ni mogoče.
Vendar te distribucije postajajo prikladna platforma za preizkušanje novih eksperimentalnih rešitev. Na primer, Fedora, OpenSUSE Tumbleweed ali nestabilne različice Debiana. So precej stabilne. Vedno vključujejo nove različice programov in vedno novo jedro. Čez leto lahko ta eksperimentalna funkcionalnost postane del posodobljenega RHEL, SLES ali Ubuntu.
Tako, če kaj ne deluje na eksperimentalni distribuciji — je to priložnost, da se razjasni težava in jo reši. Treba je biti pripravljen, da se ta funkcionalnost kmalu pojavi na produkcijskih strežnikih uporabnikov.
Trenutna lista službeno podržavanih distribucija za verziju 3.0 može se proučiti . Međutim, stvarna lista distribucija na kojima naš proizvod može raditi je mnogo šira.
Osobno me zanimalo eksperimentiranje s OS-om 'Elbrus'. Nakon dorade paketa veeam, naš proizvod se instalirao i počeo raditi. O ovom eksperimentu pisao sam na Habr-u u .
Podrška novim distribucijama se nastavlja. Očekujemo dolazak verzije 4.0. Beta bi trebala biti dostupna uskoro, pa pratite !
Izvor: habr.com
