Linux má mnoho tváří: jak pracovat na jakékoli distribuci

Linux má mnoho tváří: jak pracovat na jakékoli distribuci

Vytvoření zálohovací aplikace, která funguje na jakékoli distribuci, není snadný úkol. Chcete-li zajistit, aby Veeam Agent pro Linux fungoval na distribucích od Red Hat 6 a Debian 6 až po OpenSUSE 15.1 a Ubuntu 19.04, musíte vyřešit řadu problémů, zejména s ohledem na to, že softwarový produkt obsahuje modul jádra.

Článek vznikl na základě materiálů z vystoupení na konferenci Linux Peter 2019.

Linux není jen jedním z nejpopulárnějších operačních systémů. V podstatě se jedná o platformu, na jejímž základě můžete vytvořit něco jedinečného, ​​něco vlastního. Díky tomu má Linux mnoho distribucí, které se liší sadou softwarových komponent. A zde nastává problém: aby softwarový produkt fungoval v jakékoli distribuci, musíte vzít v úvahu vlastnosti každé z nich.

Správci balíčků. .deb vs. .rpm

Začněme zřejmým problémem distribuce produktu napříč různými distribucemi.
Nejtypičtějším způsobem distribuce softwarových produktů je umístit balíček do úložiště, aby jej odtud mohl nainstalovat správce balíčků zabudovaný v systému.
Máme však dva oblíbené formáty balíčků: min и deb. To znamená, že všichni budou muset podporovat.

Ve světě deb balíčků je úroveň kompatibility úžasná. Stejný balíček se nainstaluje a funguje stejně dobře na Debianu 6 i Ubuntu 19.04. Standardy pro proces sestavování balíčků a práce s nimi, stanovené ve starých distribucích Debianu, zůstávají relevantní v novém Linux Mintu a základním OS. V případě Veeam Agent for Linux tedy stačí jeden deb balíček pro každou hardwarovou platformu.

Ale ve světě rpm balíčků jsou rozdíly velké. Jednak kvůli tomu, že existují dva zcela nezávislí distributoři, Red Hat a SUSE, u kterých je kompatibilita zcela zbytečná. Za druhé, tito distributoři mají od nich distribuční sady. podpůrné a experimentální. Ani mezi nimi není potřeba kompatibility. Ukázalo se, že el6, el7 a el8 mají své vlastní balíčky. Samostatný balíček pro Fedoru. Balíčky pro SLES11 a 12 a jeden samostatný pro openSUSE. Hlavním problémem jsou závislosti a názvy balíčků.

Problém se závislostí

Bohužel stejné balíčky často končí pod různými názvy v různých distribucích. Níže je uveden částečný seznam závislostí balíčků veeam.

Pro EL7:
Pro 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

V důsledku toho je seznam závislostí pro distribuci jedinečný.

Horší je, když se aktualizovaná verze začne skrývat pod starým názvem balíčku.

Příklad:

Balíček byl aktualizován ve Fedoře 24 nkurzy od verze 5 po verzi 6. Náš produkt byl vytvořen s verzí 5, aby byla zajištěna kompatibilita se staršími distribucemi. Pro použití staré 5. verze knihovny na Fedoře 24 jsem musel použít balíček ncurses-compat-libs.

Výsledkem jsou dva balíčky pro Fedoru s různými závislostmi.

Dále zajímavější. Po další aktualizaci distribuce balíček ncurses-compat-libs s verzí 5 knihovny se ukáže, že není k dispozici. Pro distributora je drahé přetahovat staré knihovny do nové verze distribuce. Po nějaké době se problém opakoval v distribucích SUSE.

V důsledku toho musely některé distribuce upustit od své explicitní závislosti na ncurses-libsa opravte produkt tak, aby fungoval s jakoukoli verzí knihovny.

Mimochodem, ve verzi 8 Red Hat již není meta balíček krajta, který odkazoval na staré dobré python 2.7. Tam je python2 и krajta3.

Alternativa ke správcům balíčků

Problém se závislostmi je starý a dlouho zřejmý. Jen si vzpomeňte na Dependency hell.
Kombinovat různé knihovny a aplikace tak, aby všechny fungovaly stabilně a nekolidovaly – to je vlastně úkol, který se snaží vyřešit každý distributor Linuxu.

Správce balíčků se snaží tento problém vyřešit úplně jiným způsobem. Elegantní od společnosti Canonical. Hlavní myšlenka: aplikace běží v izolovaném prostoru izolovaném a chráněném od hlavního systému. Pokud aplikace vyžaduje knihovny, jsou dodávány se samotnou aplikací.

Flatpak také umožňuje spouštět aplikace v karanténě pomocí Linuxových kontejnerů. Je také použit nápad s pískovištěm AppImage.

Tato řešení umožňují vytvořit jeden balíček pro jakoukoli distribuci. V případě Flatpak instalace a spuštění aplikace je možné i bez vědomí administrátora.

Hlavním problémem je, že ne všechny aplikace mohou běžet v sandboxu. Někteří lidé potřebují přímý přístup k platformě. To ani nemluvím o modulech jádra, které jsou striktně závislé na jádře a nezapadají do konceptu sandboxu.

Druhým problémem je, že distribuce oblíbené v podnikovém prostředí od Red Hat a SUSE zatím neobsahují podporu pro Snappy a Flatpak.

V tomto ohledu není Veeam Agent pro Linux k dispozici snapcraft.io vůbec ne www.flathub.org.

Na závěr otázky týkající se správců balíčků bych rád poznamenal, že existuje možnost zcela opustit správce balíčků zkombinováním binárních souborů a skriptu pro jejich instalaci do jednoho balíčku.

Takový balíček vám umožní vytvořit jeden společný balíček pro různé distribuce a platformy, provést interaktivní instalační proces a provést potřebné přizpůsobení. S takovými balíčky pro Linux jsem se setkal pouze od VMware.

Problém s aktualizací

Linux má mnoho tváří: jak pracovat na jakékoli distribuci
I když jsou všechny problémy se závislostmi vyřešeny, program může ve stejné distribuci běžet odlišně. Je to otázka aktualizací.

Existují 3 strategie aktualizace:

  • Nejjednodušší je nikdy neaktualizovat. Nastavil jsem server a zapomněl jsem na to. Proč aktualizovat, když vše funguje? Problémy začínají při prvním kontaktování podpory. Tvůrce distribuce podporuje pouze aktualizované vydání.
  • Distributorovi můžete důvěřovat a nastavit automatické aktualizace. V tomto případě bude volání podpory pravděpodobně bezprostředně po neúspěšné aktualizaci.
  • Možnost ruční aktualizace až po spuštění na testovací infrastruktuře je nejspolehlivější, ale nákladná a časově náročná. Ne každý si to může dovolit.

Vzhledem k tomu, že různí uživatelé používají různé strategie aktualizací, je nutné podporovat jak nejnovější verzi, tak všechny dříve vydané. To komplikuje jak vývojový, tak testovací proces a přispívá k bolestem hlavy týmu podpory.

Různé hardwarové platformy

Různé hardwarové platformy jsou problémem, který je do značné míry specifický pro nativní kód. Minimálně musíte sbírat binární soubory pro každou podporovanou platformu.

V projektu Veeam Agent for Linux stále nemůžeme podporovat nic podobného jako tento RISC.

Nebudu se touto problematikou podrobně zabývat. Nastíním pouze hlavní problémy: platformově závislé typy, jako např size_t, zarovnání struktury a pořadí bajtů.

Statické a/nebo dynamické propojení

Linux má mnoho tváří: jak pracovat na jakékoli distribuci
Otázka však zní: „Jak se propojit s knihovnami – dynamicky nebo staticky? stojí za to diskutovat.

Aplikace C/C++ pod Linuxem zpravidla používají dynamické spojování. To funguje skvěle, pokud je aplikace vytvořena speciálně pro konkrétní distribuci.

Pokud je úkolem pokrýt různé distribuce jedním binárním souborem, pak se musíte zaměřit na nejstarší podporovanou distribuci. Pro nás je to Red Hat 6. Obsahuje gcc 4.4, který ani standard C++11 nepodporuje plně.

Náš projekt stavíme pomocí gcc 6.3, který plně podporuje C++14. Přirozeně, v tomto případě na Red Hat 6 musíte mít s sebou knihovny libstdc++ a boost. Nejjednodušší je na ně odkazovat staticky.

Ale bohužel, ne všechny knihovny lze staticky propojit.

Jednak systémové knihovny jako např libfuse, libblkid je nutné dynamicky propojovat, aby byla zajištěna jejich kompatibilita s jádrem a jeho moduly.

Za druhé, je tu jemnost s licencemi.

Licence GPL v podstatě umožňuje propojovat knihovny pouze s opensource kódem. MIT a BSD umožňují statické propojení a umožňují začlenění knihoven do projektu. Ale nezdá se, že by LGPL odporovalo statickému linkování, ale vyžaduje, aby byly sdíleny soubory nezbytné pro propojení.

Obecně platí, že použití dynamického propojování zabrání tomu, abyste museli cokoliv poskytovat.

Vytváření aplikací C/C++

Pro tvorbu C/C++ aplikací pro různé platformy a distribuce stačí vybrat nebo sestavit vhodnou verzi gcc a použít cross-kompilátory pro konkrétní architektury a sestavit celou sadu knihoven. Tato práce je docela proveditelná, ale docela problematická. A neexistuje žádná záruka, že vybraný kompilátor a knihovny poskytnou funkční verzi.

Zjevná výhoda: infrastruktura je výrazně zjednodušena, protože celý proces sestavení lze dokončit na jednom počítači. Navíc stačí nasbírat jednu sadu binárek pro jednu architekturu a můžete je zabalit do balíčků pro různé distribuce. Takto jsou vytvářeny balíčky veeam pro Veeam Agent pro Linux.

Na rozdíl od této možnosti můžete jednoduše připravit farmu pro sestavení, tedy několik strojů pro montáž. Každý takový stroj zajistí kompilaci aplikací a sestavování balíčků pro konkrétní distribuci a specifickou architekturu. V tomto případě se kompilace provádí pomocí prostředků připravených distributorem. To znamená, že odpadá fáze přípravy kompilátoru a výběru knihoven. Proces sestavení lze navíc snadno paralelizovat.

Tento přístup má však nevýhodu: pro každou distribuci v rámci stejné architektury budete muset shromáždit vlastní sadu binárních souborů. Další nevýhodou je, že je potřeba udržovat tak velký počet strojů a alokovat velké množství místa na disku a RAM.

Takto jsou kompilovány balíčky KMOD modulu jádra veeamsnap pro distribuce Red Hat.

Otevřete službu Build Service

Kolegové ze SUSE se pokusili implementovat nějakou střední cestu v podobě speciální služby pro kompilaci aplikací a sestavování balíčků - služba openbuild.

V podstatě se jedná o hypervizor, který vytvoří virtuální stroj, nainstaluje do něj všechny potřebné balíčky, zkompiluje aplikaci a sestaví balíček v tomto izolovaném prostředí, načež je virtuální stroj uvolněn.

Linux má mnoho tváří: jak pracovat na jakékoli distribuci

Plánovač implementovaný v OpenBuildService určí, kolik virtuálních strojů může spustit pro optimální rychlost vytváření balíčků. Vestavěný mechanismus podepisování podepíše balíčky a nahraje je do vestavěného úložiště. Vestavěný systém správy verzí uloží historii změn a sestavení. Vše, co zbývá, je jednoduše přidat své zdroje do tohoto systému. Nemusíte ani sami nastavovat server, můžete použít otevřený.

Je tu však problém: takový kombajn je obtížné začlenit do stávající infrastruktury. Například není potřeba kontrola verzí, pro zdrojové kódy už máme vlastní. Náš podpisový mechanismus je jiný: používáme speciální server. Úložiště také není potřeba.

Navíc podpora jiných distribucí – například Red Hat – je implementována dost špatně, což je pochopitelné.

Výhodou takové služby je rychlá podpora další verze distribuce SUSE. Před oficiálním oznámením vydání jsou balíčky potřebné pro sestavení umístěny na veřejném úložišti. Nová se objeví v seznamu dostupných distribucí na OpenBuildService. Zaškrtneme políčko a přidá se do plánu sestavení. Přidání nové verze distribuce je tedy provedeno téměř jedním kliknutím.

V naší infrastruktuře je pomocí OpenBuildService sestavena celá řada balíčků KMP modulu jádra veeamsnap pro distribuce SUSE.

Dále bych se chtěl věnovat problémům specifickým pro moduly jádra.

jádro ABI

Moduly linuxového jádra byly historicky distribuovány ve zdrojové podobě. Faktem je, že se tvůrci jádra nezatěžují starostí o podporu stabilního API pro moduly jádra, a to zejména na binární úrovni, dále označované jako kABI.

Chcete-li sestavit modul pro vanilkové jádro, určitě potřebujete hlavičky tohoto konkrétního jádra a bude fungovat pouze na tomto jádře.

DKMS umožňuje automatizovat proces sestavování modulů při aktualizaci jádra. V důsledku toho uživatelé úložiště Debian (a mnoho jeho příbuzných) používají moduly jádra buď z úložiště distributora, nebo kompilované ze zdroje pomocí DKMS.

Tato situace však nevyhovuje zejména segmentu Enterprise. Distributoři proprietárního kódu chtějí produkt distribuovat jako kompilované binární soubory.

Správci nechtějí z bezpečnostních důvodů uchovávat vývojové nástroje na produkčních serverech. Distributoři Enterprise Linuxu, jako je Red Hat a SUSE, se rozhodli, že by mohli podporovat stabilní kABI pro své uživatele. Výsledkem byly balíčky KMOD pro Red Hat a balíčky KMP pro SUSE.

Podstata tohoto řešení je celkem jednoduchá. U konkrétní verze distribuce je rozhraní API jádra zmrazeno. Distributor uvádí, že používá jádro např. 3.10 a provádí pouze opravy a vylepšení, která nemají vliv na rozhraní jádra, a moduly shromážděné pro úplně první jádro lze použít pro všechna následující bez rekompilace.

Red Hat prohlašuje, že distribuce je kompatibilní s kABI po celou dobu jejího životního cyklu. To znamená, že sestavený modul pro rhel 6.0 (vydání listopad 2010) by měl fungovat i na verzi 6.10 (vydání červen 2018). A to už je skoro 8 let. Tento úkol je přirozeně poměrně obtížný.
Zaznamenali jsme několik případů, kdy modul veeamsnap přestal fungovat kvůli problémům s kompatibilitou kABI.

Poté, co se modul veeamsnap, zkompilovaný pro RHEL 7.0, ukázal jako nekompatibilní s jádrem z RHEL 7.5, ale načetl se a bylo zaručeno, že zhroutí server, jsme použití kompatibility kABI pro RHEL 7 úplně opustili.

V současné době obsahuje balíček KMOD pro RHEL 7 sestavení pro každou verzi vydání a skript, který načte modul.

SUSE přistoupilo k úkolu kompatibility kABI opatrněji. Poskytují kompatibilitu kABI pouze v rámci jednoho servisního balíčku.

Například vydání SLES 12 proběhlo v září 2014. A SLES 12 SP1 už bylo v prosinci 2015, tedy uplynulo něco málo přes rok. Přestože obě vydání používají jádro 3.12, nejsou kompatibilní s kABI. Je zřejmé, že udržení kompatibility kABI po dobu jednoho roku je mnohem jednodušší. Roční cyklus aktualizace modulů jádra by neměl způsobovat problémy tvůrcům modulů.

V důsledku těchto zásad SUSE jsme nezaznamenali jediný problém s kompatibilitou kABI v našem modulu veeamsnap. Pravda, počet balíčků pro SUSE je téměř o řád větší.

Patche a backporty

Přestože se distributoři snaží zajistit kompatibilitu kABI a stabilitu jádra, snaží se také zlepšit výkon a odstranit vady tohoto stabilního jádra.

Vývojáři podnikového linuxového jádra přitom kromě své vlastní „práce na chybách“ sledují změny ve vanilla kernelu a převádějí je do svého „stabilního“.

Někdy to vede k novým chyby.

V nejnovější verzi Red Hat 6 došlo k chybě v jedné z menších aktualizací. To vedlo k tomu, že modul veeamsnap zaručeně zhroutil systém, když byl snímek uvolněn. Po porovnání zdrojů jádra před a po aktualizaci jsme zjistili, že na vině je backport. Podobná oprava byla provedena ve verzi vanilla kernel 4.19. Je to tak, že tato oprava fungovala dobře ve vanilkovém jádře, ale při jejím přenosu do „stabilní“ 2.6.32 nastal problém se spinlockem.

Samozřejmě, každý má vždy chyby, ale stálo za to přetahovat kód z 4.19 na 2.6.32, riskovat stabilitu?.. nejsem si jistý...

Nejhorší je, když se marketing zapojí do přetahování mezi „stabilitou“ a „modernizací“. Marketingové oddělení potřebuje, aby jádro aktualizované distribuce bylo na jedné straně stabilní a zároveň výkonově lepší a mělo nové funkce. To vede k podivným kompromisům.

Když jsem se pokusil postavit modul na jádře 4.4 ze SLES 12 SP3, překvapilo mě, že jsem v něm našel funkčnost z vanilky 4.8. Podle mého názoru je bloková I/O implementace jádra 4.4 ze SLES 12 SP3 více podobná jádru 4.8 než předchozí vydání stabilního jádra 4.4 ze SLES12 SP2. Nemohu posoudit, jaké procento kódu bylo přeneseno z jádra 4.8 do SLES 4.4 pro SP3, ale nemohu ani nazvat jádro stejně stabilní 4.4.

Nejnepříjemnější na tom je, že při psaní modulu, který by fungoval stejně dobře na různých jádrech, se už nemůžete spolehnout na verzi jádra. Musíte také vzít v úvahu distribuci. Je dobré, že se někdy můžete zapojit do definice, která se objeví spolu s novou funkcí, ale tato příležitost se ne vždy objeví.

Výsledkem je, že kód zarůstá podivnými direktivami podmíněné kompilace.

Existují také opravy, které mění zdokumentované rozhraní API jádra.
Narazil jsem na distribuci KDE neon 5.16 a byl velmi překvapen, když viděl, že volání lookup_bdev v této verzi jádra změnilo seznam vstupních parametrů.

Abych to dal dohromady, musel jsem do makefile přidat skript, který kontroluje, zda funkce lookup_bdev má parametr mask.

Podepisování modulů jádra

Ale vraťme se k problematice distribuce balíčků.

Jednou z výhod stabilního kABI je, že moduly jádra lze podepsat jako binární soubor. V tomto případě si vývojář může být jistý, že modul nebyl náhodně poškozen nebo úmyslně upraven. Můžete to zkontrolovat pomocí příkazu modinfo.

Distribuce Red Hat a SUSE umožňují zkontrolovat podpis modulu a načíst jej pouze v případě, že je v systému registrován odpovídající certifikát. Certifikát je veřejný klíč, kterým je modul podepsán. Distribuujeme jako samostatný balíček.

Problém je v tom, že certifikáty mohou být buď zabudovány do jádra (distributoři je používají), nebo musí být zapsány do energeticky nezávislé paměti EFI pomocí nástroje mokutil. Utility mokutil Při instalaci certifikátu vyžaduje restart systému a ještě před načtením jádra operačního systému vyzve administrátora, aby povolil načtení nového certifikátu.

Přidání certifikátu tedy vyžaduje fyzický administrátorský přístup do systému. Pokud je stroj umístěn někde v cloudu nebo jednoduše ve vzdálené serverové místnosti a přístup je pouze přes síť (například přes ssh), pak nebude možné přidat certifikát.

EFI na virtuálních strojích

Navzdory skutečnosti, že EFI je již dlouho podporováno téměř všemi výrobci základních desek, při instalaci systému nemusí správce přemýšlet o potřebě EFI a může být zakázáno.

Ne všechny hypervizory podporují EFI. VMWare vSphere podporuje EFI od verze 5.
Microsoft Hyper-V také získal podporu EFI počínaje Hyper-V pro Windows Server 2012R2.

Ve výchozí konfiguraci je však tato funkce pro počítače se systémem Linux zakázána, což znamená, že certifikát nelze nainstalovat.

Ve vSphere 6.5 nastavte možnost Secure Boot možné pouze ve staré verzi webového rozhraní, které běží přes Flash. Webové uživatelské rozhraní na HTML-5 je stále daleko pozadu.

Experimentální distribuce

A nakonec se podívejme na problém experimentálních distribucí a distribucí bez oficiální podpory. Na jedné straně je nepravděpodobné, že by se takové distribuce nacházely na serverech seriózních organizací. Pro takové distribuce neexistuje žádná oficiální podpora. Proto je poskytněte. Produkt nelze v takové distribuci podporovat.

Takové distribuce se však stávají vhodnou platformou pro zkoušení nových experimentálních řešení. Například Fedora, OpenSUSE Tumbleweed nebo Unstable verze Debianu. Jsou celkem stabilní. Vždy mají nové verze programů a vždy nové jádro. Za rok může tato experimentální funkce skončit v aktualizovaném RHEL, SLES nebo Ubuntu.

Takže pokud něco nefunguje v experimentální distribuci, je to důvod, proč problém vyřešit a vyřešit. Musíte se připravit na to, že tato funkce se brzy objeví na produkčních serverech uživatelů.

Můžete si prostudovat aktuální seznam oficiálně podporovaných distribucí pro verzi 3.0 zde. Ale skutečný seznam distribucí, na kterých může náš produkt fungovat, je mnohem širší.

Osobně mě zaujal experiment s OS Elbrus. Po dokončení balíčku veeam byl náš produkt nainstalován a fungoval. O tomto experimentu jsem psal na Habré v článek.

Podpora nových distribucí pokračuje. Čekáme na vydání verze 4.0. Beta se brzy objeví, takže mějte pozor co je nového!

Zdroj: www.habr.com

Přidat komentář