Linux are multe fețe: cum să lucrezi pe orice distribuție

Linux are multe fețe: cum să lucrezi pe orice distribuție

Crearea unei aplicații de rezervă care funcționează pe orice distribuție nu este o sarcină ușoară. Pentru a vă asigura că Veeam Agent pentru Linux funcționează pe distribuții de la Red Hat 6 și Debian 6, la OpenSUSE 15.1 și Ubuntu 19.04, trebuie să rezolvați o serie de probleme, mai ales având în vedere că produsul software include un modul kernel.

Articolul a fost creat pe baza unor materiale dintr-un discurs la conferință Linux Peter 2019.

Linux nu este doar unul dintre cele mai populare sisteme de operare. În esență, aceasta este o platformă pe baza căreia poți face ceva unic, ceva al tău. Datorită acestui fapt, Linux are multe distribuții care diferă în setul lor de componente software. Și aici apare o problemă: pentru ca un produs software să funcționeze pe orice distribuție, trebuie să ții cont de caracteristicile fiecăruia.

Managerii de pachete. .deb vs .rpm

Să începem cu problema evidentă a distribuirii produsului în diferite distribuții.
Cel mai tipic mod de a distribui produse software este de a pune pachetul într-un depozit, astfel încât managerul de pachete încorporat în sistem să îl poată instala de acolo.
Cu toate acestea, avem două formate de pachet populare: rpm и debutantă. Aceasta înseamnă că toată lumea va trebui să susțină.

În lumea pachetelor deb, nivelul de compatibilitate este uimitor. Același pachet se instalează și funcționează la fel de bine atât pe Debian 6, cât și pe Ubuntu 19.04. Standardele pentru procesul de construire a pachetelor și de lucru cu acestea, stabilite în vechile distribuții Debian, rămân relevante în noul Linux Mint și în sistemul de operare elementar. Prin urmare, în cazul Veeam Agent pentru Linux, un pachet deb pentru fiecare platformă hardware este suficient.

Dar în lumea pachetelor rpm, diferențele sunt mari. În primul rând, datorită faptului că există doi distribuitori complet independenți, Red Hat și SUSE, pentru care compatibilitatea este complet inutilă. În al doilea rând, acești distribuitori au truse de distribuție de la aceștia. suport și experimental. Nu este nevoie nici de compatibilitate între ele. S-a dovedit că el6, el7 și el8 au propriile lor pachete. Pachet separat pentru Fedora. Pachete pentru SLES11 și 12 și unul separat pentru openSUSE. Problema principală este dependențele și numele pachetelor.

Problemă de dependență

Din păcate, aceleași pachete ajung adesea sub nume diferite în distribuții diferite. Mai jos este o listă parțială a dependențelor pachetului veeam.

Pentru EL7:
Pentru SLES 12:

  • libblkid
  • libgcc
  • libstdc++
  • ncurses-libs
  • fuze-libs
  • file-libs
  • veeamsnap=3.0.2.1185
  • libblkid1
  • libgcc_s1
  • libstdc++6
  • libmagic1
  • libfuse2
  • veeamsnap-kmp=3.0.2.1185

Ca rezultat, lista de dependențe este unică pentru distribuție.

Ceea ce devine mai rău este atunci când o versiune actualizată începe să se ascundă sub vechiul nume de pachet.

Exemplu:

Pachetul a fost actualizat în Fedora 24 ncursuri de la versiunea 5 la versiunea 6. Produsul nostru a fost construit cu versiunea 5 pentru a asigura compatibilitatea cu distribuțiile mai vechi. Pentru a folosi vechea versiune a 5-a a bibliotecii pe Fedora 24, a trebuit să folosesc pachetul ncurses-compat-libs.

Ca rezultat, există două pachete pentru Fedora, cu dependențe diferite.

Mai mult mai interesant. După următoarea actualizare de distribuție, pachetul ncurses-compat-libs cu versiunea 5 a bibliotecii se dovedește a fi indisponibilă. Este costisitor pentru un distribuitor să tragă biblioteci vechi într-o versiune nouă a distribuției. După ceva timp, problema s-a repetat în distribuțiile SUSE.

Ca urmare, unele distribuții au trebuit să renunțe la dependența lor explicită de ncurses-libsși remediați produsul astfel încât să poată funcționa cu orice versiune a bibliotecii.

Apropo, în versiunea 8 a Red Hat nu mai există un meta pachet piton, care se referea la vechiul bun piton 2.7. Există python2 и piton3.

Alternativă la managerii de pachete

Problema dependențelor este veche și a fost de multă vreme evidentă. Amintește-ți iadul Dependenței.
Pentru a combina diverse biblioteci și aplicații, astfel încât toate să funcționeze stabil și să nu intre în conflict - de fapt, aceasta este sarcina pe care orice distribuitor Linux încearcă să o rezolve.

Managerul de pachete încearcă să rezolve această problemă într-un mod complet diferit. Vioi de la Canonical. Ideea principală: aplicația rulează într-un sandbox izolat și protejat de sistemul principal. Dacă o aplicație necesită biblioteci, acestea sunt furnizate împreună cu aplicația în sine.

Flatpak de asemenea, vă permite să rulați aplicații într-un sandbox folosind containere Linux. Se folosește și ideea sandbox AppImage.

Aceste soluții vă permit să creați un pachet pentru orice distribuție. In caz de Flatpak instalarea și lansarea aplicației este posibilă chiar și fără știrea administratorului.

Problema principală este că nu toate aplicațiile pot rula într-un sandbox. Unii oameni au nevoie de acces direct la platformă. Nici măcar nu vorbesc despre modulele kernel, care sunt strict dependente de kernel și nu se încadrează în conceptul sandbox.

A doua problemă este că distribuțiile populare în mediul de întreprindere de la Red Hat și SUSE nu conțin încă suport pentru Snappy și Flatpak.

În acest sens, Veeam Agent pentru Linux nu este disponibil snapcraft.io nu pe flathub.org.

Pentru a încheia întrebarea despre managerii de pachete, aș dori să observ că există o opțiune de a abandona complet managerii de pachete prin combinarea fișierelor binare și a unui script pentru instalarea lor într-un singur pachet.

Un astfel de pachet vă permite să creați un pachet comun pentru diferite distribuții și platforme, să efectuați un proces de instalare interactiv, realizând personalizarea necesară. Am întâlnit doar astfel de pachete pentru Linux de la VMware.

Problemă de actualizare

Linux are multe fețe: cum să lucrezi pe orice distribuție
Chiar dacă toate problemele de dependență sunt rezolvate, programul poate rula diferit pe aceeași distribuție. Este o chestiune de actualizări.

Există 3 strategii de actualizare:

  • Cel mai simplu este să nu actualizați niciodată. Am configurat serverul și am uitat de el. De ce să actualizezi dacă totul funcționează? Problemele încep prima dată când contactați asistența. Creatorul distribuției acceptă doar versiunea actualizată.
  • Puteți avea încredere în distribuitor și puteți configura actualizări automate. În acest caz, un apel la asistență este probabil imediat după o actualizare nereușită.
  • Opțiunea de actualizare manuală numai după rularea acesteia pe o infrastructură de testare este cea mai fiabilă, dar costisitoare și consumatoare de timp. Nu toată lumea își poate permite.

Deoarece utilizatorii diferiți folosesc strategii de actualizare diferite, este necesar să se susțină atât cea mai recentă versiune, cât și toate cele lansate anterior. Acest lucru complică atât procesul de dezvoltare, cât și procesul de testare și adaugă bătăi de cap echipei de asistență.

Varietate de platforme hardware

Diferite platforme hardware sunt o problemă care este în mare parte specifică codului nativ. Cel puțin, trebuie să colectați fișiere binare pentru fiecare platformă acceptată.

În proiectul Veeam Agent pentru Linux, încă nu putem susține nimic ca acest RISC.

Nu mă voi opri în detaliu asupra acestei probleme. Voi sublinia doar principalele probleme: tipuri dependente de platformă, cum ar fi size_t, alinierea structurii și ordinea octeților.

Legături statice și/sau dinamice

Linux are multe fețe: cum să lucrezi pe orice distribuție
Dar întrebarea este „Cum să faci legătura cu bibliotecile - dinamic sau static?” merita discutat.

De regulă, aplicațiile C/C++ sub Linux folosesc legături dinamice. Acest lucru funcționează excelent dacă aplicația este construită special pentru o anumită distribuție.

Dacă sarcina este să acoperiți diverse distribuții cu un fișier binar, atunci trebuie să vă concentrați pe cea mai veche distribuție acceptată. Pentru noi, acesta este Red Hat 6. Conține gcc 4.4, pe care nici măcar standardul C++11 nu îl acceptă complet.

Ne construim proiectul folosind gcc 6.3, care acceptă complet C++14. Desigur, în acest caz, pe Red Hat 6 trebuie să porți cu tine libstdc++ și să ampli bibliotecile. Cea mai ușoară modalitate este de a le conecta static.

Dar, din păcate, nu toate bibliotecile pot fi legate static.

În primul rând, biblioteci de sistem, cum ar fi libfuse, libblkid este necesară legarea dinamică pentru a asigura compatibilitatea acestora cu nucleul și modulele acestuia.

În al doilea rând, există o subtilitate cu licențele.

Licența GPL vă permite practic să conectați biblioteci numai cu codul opensource. MIT și BSD permit legarea statică și permit includerea bibliotecilor într-un proiect. Dar LGPL nu pare să contrazică legăturile statice, ci necesită ca fișierele necesare pentru legare să fie partajate.

În general, utilizarea legăturilor dinamice vă va împiedica să furnizați ceva.

Construirea de aplicații C/C++

Pentru a construi aplicații C/C++ pentru diferite platforme și distribuții, este suficient să selectați sau să construiți o versiune adecvată de gcc și să folosiți compilatoare încrucișate pentru arhitecturi specifice și să asamblați întregul set de biblioteci. Această lucrare este destul de fezabilă, dar destul de supărătoare. Și nu există nicio garanție că compilatorul și bibliotecile selectate vor oferi o versiune funcțională.

Un avantaj evident: infrastructura este mult simplificată, deoarece întregul proces de construire poate fi finalizat pe o singură mașină. În plus, este suficient să colectați un set de binare pentru o arhitectură și le puteți împacheta în pachete pentru diferite distribuții. Acesta este modul în care sunt construite pachetele veeam pentru Veeam Agent pentru Linux.

Spre deosebire de această opțiune, puteți pregăti pur și simplu o fermă de construcție, adică mai multe mașini pentru asamblare. Fiecare astfel de mașină va oferi compilarea aplicației și asamblarea pachetelor pentru o distribuție specifică și o arhitectură specifică. În acest caz, compilarea se realizează folosind mijloacele pregătite de distribuitor. Adică, etapa de pregătire a compilatorului și de selectare a bibliotecilor este eliminată. În plus, procesul de construire poate fi ușor paralelizat.

Există, totuși, un dezavantaj al acestei abordări: pentru fiecare distribuție din aceeași arhitectură, va trebui să colectați propriul set de fișiere binare. Un alt dezavantaj este că un număr atât de mare de mașini trebuie întreținut și o cantitate mare de spațiu pe disc și RAM trebuie alocată.

Acesta este modul în care pachetele KMOD ale modulului de nucleu veeamsnap sunt compilate pentru distribuțiile Red Hat.

Deschideți serviciul de compilare

Colegii de la SUSE au încercat să implementeze o cale de mijloc sub forma unui serviciu special pentru compilarea aplicațiilor și asamblarea pachetelor - openbuildservice.

În esență, este un hypervisor care creează o mașină virtuală, instalează toate pachetele necesare în ea, compilează aplicația și construiește pachetul în acest mediu izolat, după care mașina virtuală este eliberată.

Linux are multe fețe: cum să lucrezi pe orice distribuție

Planificatorul implementat în OpenBuildService va determina câte mașini virtuale poate lansa pentru o viteză optimă de construire a pachetelor. Mecanismul de semnare încorporat va semna pachetele și le va încărca în depozitul încorporat. Sistemul de control al versiunilor încorporat va salva istoricul modificărilor și al versiunilor. Tot ce rămâne este să adăugați pur și simplu sursele la acest sistem. Nici măcar nu trebuie să configurați singur serverul; puteți utiliza unul deschis.

Există, totuși, o problemă: un astfel de recoltator este greu de încadrat în infrastructura existentă. De exemplu, controlul versiunilor nu este necesar; avem deja propriul nostru pentru codurile sursă. Mecanismul nostru de semnătură este diferit: folosim un server special. De asemenea, nu este necesar un depozit.

În plus, suportul pentru alte distribuții - de exemplu, Red Hat - este implementat destul de prost, ceea ce este de înțeles.

Avantajul unui astfel de serviciu este suportul rapid pentru următoarea versiune a distribuției SUSE. Înainte de anunțul oficial al lansării, pachetele necesare pentru asamblare sunt postate într-un depozit public. Unul nou apare în lista de distribuții disponibile pe OpenBuildService. Bifăm caseta și se adaugă la planul de construcție. Astfel, adăugarea unei noi versiuni a distribuției se face cu aproape un clic.

În infrastructura noastră, folosind OpenBuildService, este asamblată întreaga varietate de pachete KMP ale modulului kernel veeamsnap pentru distribuțiile SUSE.

În continuare, aș dori să mă opresc asupra problemelor specifice modulelor kernelului.

nucleul ABI

Modulele nucleului Linux au fost distribuite istoric în formă sursă. Faptul este că creatorii nucleului nu se împovărează cu preocuparea de a susține un API stabil pentru modulele kernelului, și mai ales la nivel binar, denumit în continuare kABI.

Pentru a construi un modul pentru un nucleu vanilla, cu siguranță aveți nevoie de anteturile acestui nucleu special și va funcționa numai pe acest nucleu.

DKMS vă permite să automatizați procesul de construire a modulelor atunci când actualizați nucleul. Drept urmare, utilizatorii depozitului Debian (și numeroasele sale rude) folosesc module de kernel fie din depozitul distribuitorului, fie compilate din sursă folosind DKMS.

Cu toate acestea, această situație nu se potrivește în mod deosebit segmentului Enterprise. Distribuitorii de cod de proprietate doresc să distribuie produsul ca binare compilate.

Administratorii nu doresc să păstreze instrumentele de dezvoltare pe serverele de producție din motive de securitate. Distribuitorii Enterprise Linux, cum ar fi Red Hat și SUSE, au decis că ar putea suporta kABI stabil pentru utilizatorii lor. Rezultatul au fost pachete KMOD pentru Red Hat și pachete KMP pentru SUSE.

Esența acestei soluții este destul de simplă. Pentru o versiune specifică a distribuției, API-ul kernel-ului este înghețat. Distribuitorul afirmă că folosește nucleul, de exemplu, 3.10, și face doar corecții și îmbunătățiri care nu afectează interfețele nucleului, iar modulele colectate pentru primul nucleu pot fi folosite pentru toate cele ulterioare fără recompilare.

Red Hat susține compatibilitatea kABI pentru distribuție pe parcursul întregului său ciclu de viață. Adică, modulul asamblat pentru rhel 6.0 (lansare noiembrie 2010) ar trebui să funcționeze și pe versiunea 6.10 (lansare iunie 2018). Și asta este aproape 8 ani. Desigur, această sarcină este destul de dificilă.
Am înregistrat câteva cazuri în care modulul veeamsnap a încetat să funcționeze din cauza problemelor de compatibilitate kABI.

După ce modulul veeamsnap, compilat pentru RHEL 7.0, s-a dovedit a fi incompatibil cu kernel-ul de la RHEL 7.5, dar s-a încărcat și s-a garantat să blocheze serverul, am abandonat complet utilizarea compatibilității kABI pentru RHEL 7.

În prezent, pachetul KMOD pentru RHEL 7 conține un ansamblu pentru fiecare versiune de lansare și un script care încarcă modulul.

SUSE a abordat sarcina compatibilității kABI cu mai multă atenție. Acestea oferă compatibilitate kABI doar într-un pachet de servicii.

De exemplu, lansarea SLES 12 a avut loc în septembrie 2014. Și SLES 12 SP1 era deja în decembrie 2015, adică a trecut puțin mai mult de un an. Chiar dacă ambele versiuni folosesc nucleul 3.12, ele sunt incompatibile cu kABI. Evident, menținerea compatibilității kABI pentru doar un an este mult mai ușoară. Ciclul anual de actualizare a modulelor nucleului nu ar trebui să cauzeze probleme creatorilor de module.

Ca urmare a acestei politici SUSE, nu am înregistrat o singură problemă cu compatibilitatea kABI în modulul nostru veeamsnap. Adevărat, numărul de pachete pentru SUSE este aproape cu un ordin de mărime mai mare.

Patch-uri și backport-uri

Deși distribuitorii încearcă să asigure compatibilitatea kABI și stabilitatea nucleului, ei încearcă, de asemenea, să îmbunătățească performanța și să elimine defectele acestui nucleu stabil.

În același timp, pe lângă propria „lucrare la erori”, dezvoltatorii întreprinderii Linux kernel-ul monitorizează modificările în nucleul vanilie și le transferă în cel „stabil”.

Uneori, acest lucru duce la altele noi greșeli.

În cea mai recentă versiune a Red Hat 6, a fost făcută o greșeală la una dintre actualizările minore. A dus la faptul că modulul veeamsnap era garantat să blocheze sistemul atunci când a fost lansat instantaneul. După ce am comparat sursele kernel-ului înainte și după actualizare, am aflat că backport-ul este de vină. O remediere similară a fost făcută în versiunea 4.19 a nucleului vanilie. Doar că această remediere a funcționat bine în nucleul de vanilie, dar la transferul în „stabilul” 2.6.32, a apărut o problemă cu spinlock.

Desigur, toată lumea are întotdeauna erori, dar a meritat să tragi codul de la 4.19 la 2.6.32, riscând stabilitatea?.. Nu sunt sigur...

Cel mai rău lucru este atunci când marketingul se implică în remorcherul dintre „stabilitate” și „modernizare”. Departamentul de marketing are nevoie de nucleul distribuției actualizate să fie stabil, pe de o parte, și, în același timp, să fie mai bun în performanță și să aibă caracteristici noi. Acest lucru duce la compromisuri ciudate.

Când am încercat să construiesc un modul pe kernel-ul 4.4 din SLES 12 SP3, am fost surprins să găsesc în el funcționalități de la vanilla 4.8. După părerea mea, implementarea bloc I/O a nucleului 4.4 de la SLES 12 SP3 este mai asemănătoare cu nucleul 4.8 decât versiunea anterioară a nucleului stabil 4.4 de la SLES12 SP2. Nu pot judeca ce procent de cod a fost transferat de la nucleul 4.8 la SLES 4.4 pentru SP3, dar nici măcar nu pot numi nucleul același stabil 4.4.

Cel mai neplăcut lucru este că atunci când scrieți un modul care ar funcționa la fel de bine pe diferite nuclee, nu vă mai puteți baza pe versiunea de kernel. Trebuie să ții cont și de distribuție. Este bine că uneori te poți implica într-o definiție care apare împreună cu o nouă funcționalitate, dar această oportunitate nu apare întotdeauna.

Drept urmare, codul devine supraîncărcat cu directive de compilare condiționată ciudate.

Există, de asemenea, patch-uri care modifică API-ul kernel-ului documentat.
Am dat peste distributie Noul KDE 5.16 și am fost foarte surprins să văd că apelul lookup_bdev din această versiune de kernel a schimbat lista parametrilor de intrare.

Pentru a le pune împreună, a trebuit să adaug un script la makefile care verifică dacă funcția lookup_bdev are un parametru de mască.

Semnarea modulelor kernelului

Dar să revenim la problema distribuției pachetelor.

Unul dintre avantajele kABI stabil este că modulele nucleului pot fi semnate ca fișier binar. În acest caz, dezvoltatorul poate fi sigur că modulul nu a fost deteriorat accidental sau modificat intenționat. Puteți verifica acest lucru cu comanda modinfo.

Distribuțiile Red Hat și SUSE vă permit să verificați semnătura modulului și să o încărcați numai dacă certificatul corespunzător este înregistrat în sistem. Certificatul este cheia publică cu care este semnat modulul. Îl distribuim ca un pachet separat.

Problema aici este că certificatele pot fi fie încorporate în nucleu (distribuitorii le folosesc), fie trebuie scrise în memoria nevolatilă EFI folosind un utilitar mokutil. Utilitate mokutil Când instalați un certificat, vă solicită să reporniți sistemul și, chiar înainte de a încărca nucleul sistemului de operare, solicită administratorului să permită încărcarea unui nou certificat.

Astfel, adăugarea unui certificat necesită acces de administrator fizic la sistem. Dacă mașina se află undeva în cloud sau pur și simplu într-o cameră de server la distanță și accesul se face numai prin rețea (de exemplu, prin ssh), atunci va fi imposibil să adăugați un certificat.

EFI pe mașinile virtuale

În ciuda faptului că EFI a fost mult timp susținut de aproape toți producătorii de plăci de bază, atunci când instalează un sistem, este posibil ca administratorul să nu se gândească la necesitatea EFI și poate fi dezactivat.

Nu toți hipervizoarele acceptă EFI. VMWare vSphere acceptă EFI începând cu versiunea 5.
Microsoft Hyper-V a câștigat și suport EFI începând cu Hyper-V pentru Windows Server 2012R2.

Cu toate acestea, în configurația implicită, această funcționalitate este dezactivată pentru mașinile Linux, ceea ce înseamnă că certificatul nu poate fi instalat.

În vSphere 6.5, setați opțiunea Încărcare sigură posibil doar în versiunea veche a interfeței web, care rulează prin Flash. Interfața de utilizare web pe HTML-5 este încă cu mult în urmă.

Distribuții experimentale

Și, în sfârșit, să luăm în considerare problema distribuțiilor experimentale și a distribuțiilor fără suport oficial. Pe de o parte, este puțin probabil să se găsească astfel de distribuții pe serverele organizațiilor serioase. Nu există suport oficial pentru astfel de distribuții. Prin urmare, furnizați-le. Produsul nu poate fi suportat pe o astfel de distribuție.

Cu toate acestea, astfel de distribuții devin o platformă convenabilă pentru a încerca noi soluții experimentale. De exemplu, versiunile Debian Fedora, OpenSUSE Tumbleweed sau Unstable. Sunt destul de stabili. Ei au întotdeauna versiuni noi de programe și întotdeauna un nucleu nou. Într-un an, această funcționalitate experimentală poate ajunge într-un RHEL, SLES sau Ubuntu actualizat.

Deci, dacă ceva nu funcționează pe o distribuție experimentală, acesta este un motiv pentru a descoperi problema și a o rezolva. Trebuie să fii pregătit pentru faptul că această funcționalitate va apărea în curând pe serverele de producție ale utilizatorilor.

Puteți studia lista actuală a distribuțiilor acceptate oficial pentru versiunea 3.0 aici. Dar lista reală a distribuțiilor pe care produsul nostru poate funcționa este mult mai largă.

Personal, m-a interesat experimentul cu sistemul de operare Elbrus. După finalizarea pachetului veeam, produsul nostru a fost instalat și funcțional. Am scris despre acest experiment pe Habré în articol.

Ei bine, suportul pentru noi distribuții continuă. Așteptăm lansarea versiunii 4.0. Beta este pe cale să apară, așa că fii atent ce mai e nou!

Sursa: www.habr.com

Adauga un comentariu