Linux heeft vele gezichten: hoe je op elke distributie moet werken

Linux heeft vele gezichten: hoe je op elke distributie moet werken

Het creëren van een back-upapplicatie die op elke distributie werkt, is geen gemakkelijke taak. Om ervoor te zorgen dat Veeam Agent voor Linux werkt op distributies van Red Hat 6 en Debian 6 tot OpenSUSE 15.1 en Ubuntu 19.04, moet je een reeks problemen oplossen, vooral als je bedenkt dat het softwareproduct een kernelmodule bevat.

Het artikel is gemaakt op basis van materiaal uit een toespraak op de conferentie LinuxPeter2019.

Linux is niet alleen een van de meest populaire besturingssystemen. In essentie is dit een platform op basis waarvan je iets unieks, iets eigens kunt maken. Dankzij dit heeft Linux veel distributies die verschillen in hun set softwarecomponenten. En hier doet zich een probleem voor: om een ​​softwareproduct op welke distributie dan ook te laten functioneren, moet je rekening houden met de kenmerken van elke distributie.

Pakketbeheerders. .deb versus .rpm

Laten we beginnen met het voor de hand liggende probleem van het distribueren van het product over verschillende distributies.
De meest gebruikelijke manier om softwareproducten te distribueren is door het pakket in een repository te plaatsen, zodat de pakketbeheerder die in het systeem is ingebouwd het van daaruit kan installeren.
We hebben echter twee populaire pakketformaten: rpm и deb. Dit betekent dat iedereen zal moeten steunen.

In de wereld van deb-pakketten is het compatibiliteitsniveau verbazingwekkend. Hetzelfde pakket wordt geïnstalleerd en werkt even goed op zowel Debian 6 als Ubuntu 19.04. De standaarden voor het proces van het bouwen van pakketten en het werken ermee, vastgelegd in oude Debian-distributies, blijven relevant in het nieuwerwetse Linux Mint en het elementaire besturingssysteem. Daarom is in het geval van Veeam Agent voor Linux één deb-pakket voor elk hardwareplatform voldoende.

Maar in de wereld van rpm-pakketten zijn de verschillen groot. Ten eerste vanwege het feit dat er twee volledig onafhankelijke distributeurs zijn, Red Hat en SUSE, waarvoor compatibiliteit volkomen onnodig is. Ten tweede hebben deze distributeurs daar distributiekits van. ondersteunend en experimenteel. Er is ook geen noodzaak voor compatibiliteit tussen beide. Het bleek dat el6, el7 en el8 hun eigen pakketten hebben. Apart pakket voor Fedora. Pakketten voor SLES11 en 12 en een apart pakket voor openSUSE. Het grootste probleem zijn afhankelijkheden en pakketnamen.

Afhankelijkheidsprobleem

Helaas komen dezelfde pakketten vaak onder verschillende namen in verschillende distributies terecht. Hieronder vindt u een gedeeltelijke lijst met afhankelijkheden van veeam-pakketten.

Voor EL7:
Voor SLES 12:

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

Als gevolg hiervan is de lijst met afhankelijkheden uniek voor de distributie.

Wat nog erger wordt, is wanneer een bijgewerkte versie zich begint te verbergen onder de oude pakketnaam.

Voorbeeld:

Het pakket is bijgewerkt in Fedora 24 ncursussen van versie 5 naar versie 6. Ons product is gebouwd met versie 5 om compatibiliteit met oudere distributies te garanderen. Om de oude 5e versie van de bibliotheek op Fedora 24 te gebruiken, moest ik het pakket gebruiken ncurses-compat-libs.

Als resultaat zijn er twee pakketten voor Fedora, met verschillende afhankelijkheden.

Verder interessanter. Na de volgende distributie-update wordt het pakket ncurses-compat-libs bij versie 5 van de bibliotheek blijkt deze niet beschikbaar te zijn. Het is duur voor een distributeur om oude bibliotheken naar een nieuwe versie van de distributie te slepen. Na enige tijd herhaalde het probleem zich in SUSE-distributies.

Als gevolg hiervan moesten sommige distributies hun expliciete afhankelijkheid van ncurses-libsen repareer het product zodat het met elke versie van de bibliotheek kan werken.

Overigens is er in versie 8 van Red Hat geen metapakket meer python, wat verwees naar het goede oude python 2.7. er bestaat python2 и python3.

Alternatief voor pakketbeheerders

Het probleem met afhankelijkheden is oud en al lang duidelijk. Denk maar aan de afhankelijkheidshel.
Het combineren van verschillende bibliotheken en applicaties zodat ze allemaal stabiel werken en geen conflicten veroorzaken - in feite is dit de taak die elke Linux-distributeur probeert op te lossen.

De pakketbeheerder probeert dit probleem op een heel andere manier op te lossen. pittig van Canoniek. Het hoofdidee: de applicatie draait in een sandbox die geïsoleerd en beschermd is tegen het hoofdsysteem. Als voor een applicatie bibliotheken nodig zijn, worden deze bij de applicatie zelf geleverd.

Flatpak Hiermee kunt u ook applicaties in een sandbox uitvoeren met behulp van Linux Containers. Het sandbox-idee wordt ook gebruikt AppImage.

Met deze oplossingen kunt u één pakket voor elke distributie maken. In het geval van Flatpak installatie en starten van de applicatie is mogelijk, zelfs zonder medeweten van de beheerder.

Het grootste probleem is dat niet alle applicaties in een sandbox kunnen draaien. Sommige mensen hebben directe toegang tot het platform nodig. Ik heb het niet eens over kernelmodules, die strikt afhankelijk zijn van de kernel en niet passen in het sandbox-concept.

Het tweede probleem is dat de in de enterprise-omgeving populaire distributies van Red Hat en SUSE nog geen ondersteuning bieden voor Snappy en Flatpak.

In dit opzicht is Veeam Agent voor Linux niet beschikbaar snapcraft.io helemaal niet flathub.org.

Om de vraag over pakketbeheerders af te ronden, zou ik willen opmerken dat er een optie is om pakketbeheerders helemaal achterwege te laten door binaire bestanden en een script om ze te installeren in één pakket te combineren.

Met zo'n bundel kunt u één gemeenschappelijk pakket maken voor verschillende distributies en platforms, een interactief installatieproces uitvoeren en de nodige aanpassingen uitvoeren. Ik ben dergelijke pakketten voor Linux alleen van VMware tegengekomen.

Updateprobleem

Linux heeft vele gezichten: hoe je op elke distributie moet werken
Zelfs als alle afhankelijkheidsproblemen zijn opgelost, kan het programma op dezelfde distributie anders werken. Het gaat om updates.

Er zijn 3 updatestrategieën:

  • De eenvoudigste is om nooit te updaten. Ik heb de server opgezet en vergeten. Waarom updaten als alles werkt? De problemen beginnen de eerste keer dat u contact opneemt met de ondersteuning. De maker van de distributie ondersteunt alleen de bijgewerkte release.
  • U kunt de distributeur vertrouwen en automatische updates instellen. In dit geval wordt er waarschijnlijk onmiddellijk na een mislukte update een beroep op de ondersteuning gedaan.
  • De optie om handmatig te updaten nadat het op een testinfrastructuur is uitgevoerd, is het meest betrouwbaar, maar duur en tijdrovend. Niet iedereen kan het betalen.

Omdat verschillende gebruikers verschillende updatestrategieën gebruiken, is het noodzakelijk om zowel de nieuwste release als alle eerder uitgebrachte releases te ondersteunen. Dit bemoeilijkt zowel het ontwikkel- als het testproces en zorgt voor extra kopzorgen voor het ondersteuningsteam.

Verscheidenheid aan hardwareplatforms

Verschillende hardwareplatforms vormen een probleem dat grotendeels specifiek is voor native code. U moet minimaal binaire bestanden verzamelen voor elk ondersteund platform.

In het Veeam Agent voor Linux-project kunnen we zoiets als deze RISC nog steeds niet ondersteunen.

Ik zal niet in detail op deze kwestie ingaan. Ik zal alleen de belangrijkste problemen schetsen: platformafhankelijke typen, zoals size_t, structuuruitlijning en bytevolgorde.

Statische en/of dynamische koppeling

Linux heeft vele gezichten: hoe je op elke distributie moet werken
Maar de vraag is: “Hoe kan ik linken met bibliotheken – dynamisch of statisch?” waard om te bespreken.

In de regel gebruiken C/C++-toepassingen onder Linux dynamische koppelingen. Dit werkt prima als de applicatie specifiek voor een specifieke distributie is gebouwd.

Als het de taak is om verschillende distributies met één binair bestand af te dekken, dan moet je je concentreren op de oudste ondersteunde distributie. Voor ons is dit Red Hat 6. Het bevat gcc 4.4, wat zelfs de C++11-standaard niet ondersteunt geheel.

We bouwen ons project met gcc 6.3, dat C++14 volledig ondersteunt. In dit geval moet je op Red Hat 6 uiteraard de libstdc++ en boost-bibliotheken bij je hebben. De eenvoudigste manier is om er statisch naar te linken.

Maar helaas kunnen niet alle bibliotheken statisch gekoppeld worden.

Ten eerste systeembibliotheken zoals libfuse, libblkid het is noodzakelijk om dynamisch te linken om hun compatibiliteit met de kernel en zijn modules te garanderen.

Ten tweede is er een subtiliteit met licenties.

Met de GPL-licentie kunt u in principe alleen bibliotheken koppelen met opensource-code. MIT en BSD maken statische koppelingen mogelijk en maken het mogelijk bibliotheken in een project op te nemen. Maar de LGPL lijkt statisch koppelen niet tegen te spreken, maar vereist dat de bestanden die nodig zijn voor het koppelen worden gedeeld.

Over het algemeen voorkomt het gebruik van dynamische koppelingen dat u iets hoeft op te geven.

Het bouwen van C/C++-applicaties

Om C/C++-applicaties voor verschillende platforms en distributies te bouwen, volstaat het om een ​​geschikte versie van gcc te selecteren of te bouwen en cross-compilers voor specifieke architecturen te gebruiken en de volledige set bibliotheken samen te stellen. Dit werk is heel haalbaar, maar behoorlijk lastig. En er is geen garantie dat de geselecteerde compiler en bibliotheken een werkbare versie zullen leveren.

Een voor de hand liggend voordeel: de infrastructuur wordt sterk vereenvoudigd, omdat het hele bouwproces op één machine kan worden voltooid. Bovendien is het voldoende om één set binaire bestanden voor één architectuur te verzamelen en kunt u deze in pakketten voor verschillende distributies verpakken. Dit is hoe veeam-pakketten worden gebouwd voor Veeam Agent voor Linux.

In tegenstelling tot deze optie kunt u eenvoudig een bouwboerderij voorbereiden, dat wil zeggen meerdere machines voor montage. Elk van deze machines zal applicatiecompilatie en pakketassemblage bieden voor een specifieke distributie en een specifieke architectuur. In dit geval wordt de compilatie uitgevoerd met behulp van de middelen die door de distributeur zijn voorbereid. Dat wil zeggen dat de fase van het voorbereiden van de compiler en het selecteren van bibliotheken wordt geëlimineerd. Bovendien kan het bouwproces eenvoudig worden geparallelliseerd.

Er zit echter een keerzijde aan deze aanpak: voor elke distributie binnen dezelfde architectuur zul je je eigen set binaire bestanden moeten verzamelen. Een ander nadeel is dat er zo'n groot aantal machines moet worden onderhouden en dat er een grote hoeveelheid schijfruimte en RAM moet worden toegewezen.

Dit is hoe KMOD-pakketten van de veeamsnap-kernelmodule worden gecompileerd voor Red Hat-distributies.

Bouwservice openen

Collega's van SUSE probeerden een middenweg te implementeren in de vorm van een speciale service voor het compileren van applicaties en het samenstellen van pakketten - openbouwservice.

In wezen is het een hypervisor die een virtuele machine aanmaakt, daarin alle benodigde pakketten installeert, de applicatie compileert en het pakket in deze geïsoleerde omgeving bouwt, waarna de virtuele machine wordt vrijgegeven.

Linux heeft vele gezichten: hoe je op elke distributie moet werken

De in OpenBuildService geïmplementeerde planner bepaalt hoeveel virtuele machines er kunnen worden gestart voor een optimale snelheid voor het bouwen van pakketten. Het ingebouwde ondertekeningsmechanisme ondertekent de pakketten en uploadt ze naar de ingebouwde repository. Het ingebouwde versiebeheersysteem slaat de geschiedenis van wijzigingen en builds op. Het enige dat overblijft is eenvoudigweg uw bronnen aan dit systeem toevoegen. Je hoeft de server niet eens zelf in te stellen; je kunt een open server gebruiken.

Er is echter een probleem: zo’n rooier is lastig in te passen in de bestaande infrastructuur. Versiebeheer is bijvoorbeeld niet nodig; we hebben al een eigen versiebeheer voor de broncodes. Ons handtekeningmechanisme is anders: we gebruiken een speciale server. Een repository is ook niet nodig.

Bovendien is de ondersteuning voor andere distributies - bijvoorbeeld Red Hat - nogal slecht geïmplementeerd, wat begrijpelijk is.

Het voordeel van een dergelijke service is snelle ondersteuning voor de volgende versie van de SUSE-distributie. Vóór de officiële aankondiging van de release worden de pakketten die nodig zijn voor de assemblage op een openbare repository geplaatst. Er verschijnt een nieuwe in de lijst met beschikbare distributies op OpenBuildService. Wij vinken het vakje aan en het wordt toegevoegd aan het bouwplan. Het toevoegen van een nieuwe versie van de distributie gebeurt dus met bijna één klik.

In onze infrastructuur wordt met behulp van OpenBuildService de volledige verscheidenheid aan KMP-pakketten van de veeamsnap-kernelmodule voor SUSE-distributies samengesteld.

Vervolgens wil ik graag stilstaan ​​bij kwesties die specifiek zijn voor kernelmodules.

kernel ABI

Linux-kernelmodules zijn van oudsher in bronvorm gedistribueerd. Feit is dat de makers van de kernel zichzelf niet belasten met de zorg om een ​​stabiele API voor kernelmodules te ondersteunen, en vooral op binair niveau, verder kABI genoemd.

Om een ​​module voor een vanillekernel te bouwen, heb je zeker de headers van deze specifieke kernel nodig, en deze zal alleen op deze kernel werken.

Met DKMS kunt u het proces van het bouwen van modules automatiseren bij het updaten van de kernel. Als gevolg hiervan gebruiken gebruikers van de Debian-repository (en de vele verwanten ervan) kernelmodules uit de repository van de distributeur of gecompileerd vanuit de broncode met behulp van DKMS.

Deze situatie is echter niet bijzonder geschikt voor het Enterprise-segment. Distributeurs van bedrijfseigen code willen het product distribueren als gecompileerde binaire bestanden.

Beheerders willen om veiligheidsredenen geen ontwikkeltools op productieservers bewaren. Enterprise Linux-distributeurs zoals Red Hat en SUSE besloten dat ze stabiele kABI voor hun gebruikers konden ondersteunen. Het resultaat waren KMOD-pakketten voor Red Hat en KMP-pakketten voor SUSE.

De essentie van deze oplossing is vrij eenvoudig. Voor een specifieke versie van de distributie is de kernel-API bevroren. De distributeur stelt dat hij de kernel gebruikt, bijvoorbeeld 3.10, en alleen correcties en verbeteringen aanbrengt die de kernelinterfaces niet beïnvloeden, en dat de modules die voor de allereerste kernel zijn verzameld, voor alle volgende kunnen worden gebruikt zonder hercompilatie.

Red Hat claimt kABI-compatibiliteit voor de distributie gedurende de gehele levenscyclus. Dat wil zeggen dat de samengestelde module voor rhel 6.0 (uitgave november 2010) ook zou moeten werken op versie 6.10 (uitgave juni 2018). En dit is bijna 8 jaar. Uiteraard is deze taak behoorlijk moeilijk.
We hebben verschillende gevallen geregistreerd waarin de veeamsnap-module niet meer werkte vanwege kABI-compatibiliteitsproblemen.

Nadat de veeamsnap-module, gecompileerd voor RHEL 7.0, incompatibel bleek te zijn met de kernel van RHEL 7.5, maar deze laadde en de server gegarandeerd crashte, hebben we het gebruik van kABI-compatibiliteit voor RHEL 7 helemaal stopgezet.

Momenteel bevat het KMOD-pakket voor RHEL 7 een assembly voor elke releaseversie en een script dat de module laadt.

SUSE benaderde de taak van kABI-compatibiliteit zorgvuldiger. Ze bieden alleen kABI-compatibiliteit binnen één servicepack.

De release van SLES 12 vond bijvoorbeeld plaats in september 2014. En SLES 12 SP1 was al in december 2015, dat wil zeggen dat er iets meer dan een jaar verstreken is. Hoewel beide releases de 3.12-kernel gebruiken, zijn ze kABI-incompatibel. Het is duidelijk dat het veel eenvoudiger is om de kABI-compatibiliteit slechts een jaar lang te behouden. De jaarlijkse updatecyclus van de kernelmodule zou geen problemen moeten veroorzaken voor modulemakers.

Als gevolg van dit SUSE-beleid hebben we geen enkel probleem met kABI-compatibiliteit in onze veeamsnap-module geregistreerd. Het is waar dat het aantal pakketten voor SUSE bijna een orde van grootte groter is.

Patches en backports

Hoewel distributeurs proberen de kABI-compatibiliteit en kernelstabiliteit te garanderen, proberen ze ook de prestaties te verbeteren en defecten van deze stabiele kernel te elimineren.

Tegelijkertijd monitoren de ontwikkelaars van de zakelijke Linux-kernel, naast hun eigen 'werk aan fouten', veranderingen in de vanille-kernel en brengen deze over naar hun 'stabiele' kernel.

Soms leidt dit tot nieuwe fouten.

In de nieuwste release van Red Hat 6 is er een fout gemaakt in een van de kleine updates. Het leidde ertoe dat de veeamsnap-module het systeem gegarandeerd crashte toen de snapshot werd vrijgegeven. Nadat we de kernelbronnen voor en na de update hadden vergeleken, kwamen we erachter dat de backport de schuldige was. Een soortgelijke oplossing is aangebracht in de vanillekernelversie 4.19. Het is alleen zo dat deze oplossing prima werkte in de vanillekernel, maar bij het overbrengen naar de “stabiele” 2.6.32 ontstond er een probleem met de spinlock.

Natuurlijk heeft iedereen altijd fouten, maar was het de moeite waard om de code van 4.19 naar 2.6.32 te slepen, waardoor de stabiliteit in gevaar kwam? Ik weet het niet zeker...

Het ergste is wanneer marketing betrokken raakt bij het touwtrekken tussen ‘stabiliteit’ en ‘modernisering’. De marketingafdeling heeft de kern van de bijgewerkte distributie nodig om enerzijds stabiel te zijn en tegelijkertijd beter te presteren en nieuwe functies te hebben. Dit leidt tot vreemde compromissen.

Toen ik probeerde een module te bouwen op kernel 4.4 vanuit SLES 12 SP3, was ik verrast toen ik daarin functionaliteit uit vanille 4.8 aantrof. Naar mijn mening lijkt de blok-I/O-implementatie van de 4.4-kernel uit SLES 12 SP3 meer op de 4.8-kernel dan de vorige release van de stabiele 4.4-kernel uit SLES12 SP2. Ik kan niet beoordelen welk percentage van de code is overgebracht van kernel 4.8 naar SLES 4.4 voor SP3, maar ik kan de kernel niet eens dezelfde stabiele 4.4 noemen.

Het meest onaangename hieraan is dat je bij het schrijven van een module die op verschillende kernels even goed zou werken, niet langer op de kernelversie kunt vertrouwen. Ook moet je rekening houden met de verdeling. Het is goed dat je soms betrokken kunt raken bij een definitie die samen met nieuwe functionaliteit verschijnt, maar deze mogelijkheid doet zich niet altijd voor.

Als gevolg hiervan raakt de code overwoekerd met vreemde voorwaardelijke compilatierichtlijnen.

Er zijn ook patches die de gedocumenteerde kernel-API wijzigen.
Ik kwam de distributie tegen KDE neon 5.16 en was zeer verrast om te zien dat de lookup_bdev-aanroep in deze kernelversie de lijst met invoerparameters veranderde.

Om het voor elkaar te krijgen, moest ik een script aan het makefile toevoegen dat controleert of de lookup_bdev-functie een mask-parameter heeft.

Kernelmodules ondertekenen

Maar laten we terugkeren naar de kwestie van de pakketdistributie.

Een van de voordelen van stabiele kABI is dat kernelmodules kunnen worden ondertekend als een binair bestand. In dit geval kan de ontwikkelaar er zeker van zijn dat de module niet per ongeluk beschadigd of opzettelijk gewijzigd is. Je kunt dit controleren met het modinfo-commando.

Met Red Hat- en SUSE-distributies kunt u de handtekening van de module controleren en deze alleen laden als het bijbehorende certificaat op het systeem is geregistreerd. Het certificaat is de publieke sleutel waarmee de module is ondertekend. Wij distribueren het als een apart pakket.

Het probleem hier is dat certificaten in de kernel kunnen worden ingebouwd (distributeurs gebruiken ze) of met behulp van een hulpprogramma naar het niet-vluchtige EFI-geheugen moeten worden geschreven. mokutil. Nutsvoorziening mokutil Wanneer u een certificaat installeert, moet u het systeem opnieuw opstarten en, zelfs voordat de kernel van het besturingssysteem wordt geladen, wordt de beheerder gevraagd om het laden van een nieuw certificaat toe te staan.

Voor het toevoegen van een certificaat is dus fysieke beheerderstoegang tot het systeem vereist. Als de machine ergens in de cloud of simpelweg in een externe serverruimte staat en de toegang alleen via het netwerk verloopt (bijvoorbeeld via ssh), dan is het onmogelijk om een ​​certificaat toe te voegen.

EFI op virtuele machines

Ondanks het feit dat EFI al lang door bijna alle moederbordfabrikanten wordt ondersteund, denkt de beheerder bij het installeren van een systeem mogelijk niet na over de noodzaak van EFI en kan deze worden uitgeschakeld.

Niet alle hypervisors ondersteunen EFI. VMWare vSphere ondersteunt EFI vanaf versie 5.
Microsoft Hyper-V kreeg ook EFI-ondersteuning, te beginnen met Hyper-V voor Windows Server 2012R2.

In de standaardconfiguratie is deze functionaliteit echter uitgeschakeld voor Linux-machines, waardoor het certificaat niet kan worden geïnstalleerd.

Stel in vSphere 6.5 de optie in Beveiligd Opstarten alleen mogelijk in de oude versie van de webinterface, die via Flash draait. De webinterface op HTML-5 loopt nog steeds ver achter.

Experimentele distributies

En laten we tot slot eens kijken naar de kwestie van experimentele distributies en distributies zonder officiële steun. Aan de ene kant is het onwaarschijnlijk dat dergelijke distributies op de servers van serieuze organisaties worden gevonden. Er is geen officiële ondersteuning voor dergelijke distributies. Geef deze daarom door. Het product kan niet worden ondersteund op een dergelijke distributie.

Dergelijke distributies worden echter een handig platform voor het uitproberen van nieuwe experimentele oplossingen. Bijvoorbeeld Fedora, OpenSUSE Tumbleweed of instabiele versies van Debian. Ze zijn behoorlijk stabiel. Ze hebben altijd nieuwe versies van programma's en altijd een nieuwe kernel. Over een jaar kan deze experimentele functionaliteit terechtkomen in een vernieuwde RHEL, SLES of Ubuntu.

Dus als iets niet werkt op een experimentele distributie, is dit een reden om het probleem te achterhalen en op te lossen. U moet erop voorbereid zijn dat deze functionaliteit binnenkort op de productieservers van gebruikers zal verschijnen.

U kunt de huidige lijst met officieel ondersteunde distributies voor versie 3.0 bestuderen hier. Maar de echte lijst met distributies waarop ons product kan werken is veel breder.

Persoonlijk was ik geïnteresseerd in het experiment met het Elbrus OS. Nadat we het veeam-pakket hadden afgerond, was ons product geïnstalleerd en werkend. Ik schreef over dit experiment op Habré in статье.

Welnu, de ondersteuning voor nieuwe distributies gaat door. We wachten op de release van versie 4.0. De bèta staat op het punt te verschijnen, dus houd het in de gaten wat is er nieuw!

Bron: www.habr.com

Voeg een reactie