Linux er mangefacet: hvordan man arbejder på enhver distribution

Linux er mangefacet: hvordan man arbejder på enhver distribution

At skabe en sikkerhedskopieringsapplikation, der fungerer på enhver distribution, er en udfordring. For at sikre Veeam Agent for Linux fungerer på distributioner fra Red Hat 6 til Debian 6, helt op til OpenSUSE 15.1 og Ubuntu 19.04, skal man tackle en række problemer, især når man tager højde for, at produktet indeholder en kernemodul.

Artiklen er baseret på materiale fra et oplæg på konferencen LinuxPiter 2019.

Linux er ikke bare en af de mest populære OS'er. Det er i realiteten en platform, hvor man kan skabe noget unikt, noget eget. Dette har resulteret i mange distributioner af Linux, som adskiller sig ved mængden af softwarekomponenter. Her opstår problemet: for at et softwareprodukt kan fungere på enhver distribution, skal man tage hensyn til de specifikke forhold for hver enkelt.

Pakkehåndterere. .deb vs .rpm

Lad os starte med det åbenlyse problem ved distribution af produkter til forskellige distributioner.
Den mest typiske metode til distribution af softwareprodukter er at lægge en pakke på et repository, så den indbyggede pakkehåndterer i systemet kan installere den derfra.
Men vi har to populære pakkeformater: rpm og deb. Det betyder, at vi skal støtte hver enkelt.

I deb-pakkernes verden er kompatibilitetsniveauet imponerende. Den samme pakke installeres og fungerer lige godt på både Debian 6 og Ubuntu 19.04. Standarderne for pakkeopbygning og arbejdsgange, der blev lagt i de gamle Debian-distributioner, forbliver relevante i de moderne Linux Mint og elementary OS. Derfor er én deb-pakke til hver hardwareplatform tilstrækkeligt for Veeam Agent for Linux.

Men i rpm-pakkernes verden er forskellene store. For det første, fordi der er to helt uafhængige distributører, Red Hat og SUSE, som ikke behøver at være kompatible. For det andet har disse distributører distributioner med teknisk support og eksperimentelle. Der er heller ikke behov for kompatibilitet mellem dem. Det resulterer i, at der er specifikke pakker for el6, el7 og el8. Separat pakke til Fedora. Pakker til SLES11 og 12 og en særskilt for openSUSE. Det primære problem er med afhængigheder og pakke-navne.

Afhængighedsproblemer

Desværre har de samme pakker ofte forskellige navne i forskellige distributioner. Nedenfor er en ufuldstændig liste over afhængigheder for veeam-pakken.

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

Som resultat er afhængighedslisten unik for distributionen.

Det bliver værre, når en opdateret version begynder at gemme sig under det gamle pakkebetegnelse.

Eksempel:

I Fedora 24 er pakken blevet opdateret ncurses fra version 5 til version 6. Vores produkt blev bygget med version 5 for at sikre kompatibilitet med ældre distributioner. For at bruge den gamle version 5 af biblioteket i Fedora 24 måtte man bruge pakken ncurses-compat-libs.

Som resultat får Fedora to pakker med forskellige afhængigheder.

Her bliver det interessant. Efter endnu en opdatering af distributionen bliver pakken ncurses-compat-libs med version 5 af biblioteket utilgængelig. For distributøren er det besværligt at trække gamle biblioteker ind i den nye version af distributionen. Efter noget tid opstod problemet også i SUSE-distributionerne.

Som resultat måtte nogle distributioner opgive den klare afhængighed fra ncurses-libs, og produktet blev justeret, så det kunne arbejde med enhver version af biblioteket.

For resten, i version 8 af Red Hat er der ikke længere en metapakke python, der henviste til den gode gamle python 2.7. Der er python2 og python3.

Alternativ til pakkestyring

Problemet med afhængigheder er gammelt og har længe været tydeligt. Tænk bare på Dependency hell.
At kombinere forskellige biblioteker og applikationer så de stabilt fungerer og ikke konflkterer—det er faktisk dette problem, enhver Linux-distributør forsøger at løse.

Pakkestyringssystemet Snappy fra Canonical. Hovedidéen: applikationen kører i et isoleret miljø, beskyttet mod hovedsystemet. Hvis applikationer har brug for biblioteker, leveres de sammen med selve applikationen.

Flatpak giver også mulighed for at køre applikationer i et isoleret miljø ved hjælp af Linux Containere. Sandkasseidéen anvendes også af AppImage.

Disse løsninger muliggør oprettelse af én pakke til alle distributioner. I tilfælde af at Flatpak installation og kørsel af applikationen er mulig selv uden administratorens viden.

Hovedproblemet er, at ikke alle applikationer kan køre i et isoleret miljø. Nogle har brug for direkte adgang til platformen. Jeg nævner ikke engang kerne-moduler, som er stærkt afhængige af kernen og slet ikke passer ind i sandkassekonceptet.

Et andet problem er, at populære enterprise-distributioner fra Red Hat og SUSE endnu ikke understøtter Snappy og Flatpak.

Som følge heraf er Veeam Agent for Linux ikke tilgængelig hverken på snapcraft.io hverken på flathub.org.

Afslutningsvis om spørgsmålet vedrørende pakkehåndtere, bemærker jeg, at der er en mulighed for helt at undgå pakkehåndtere ved at samle binære filer og installationsscripts i én pakke.

Sådan en bundle gør det muligt at skabe én samlet pakke til forskellige distributioner og platforme, samt at gennemføre en interaktiv installationsproces med den nødvendige tilpasning. Jeg har kun stødt på sådanne pakker til Linux fra VMware.

Problemet med opdateringer

Linux er mangefacet: hvordan man arbejder på enhver distribution
Selv hvis alle afhængighedsproblemer er løst, kan programmet opføre sig forskelligt på samme distribution. Det handler om opdateringer.

Der er 3 opdateringsstrategier:

  • Den enkleste er aldrig at opdatere. Du sætter serveren op og glemmer den. Hvorfor opdatere, når alt fungerer? Problemerne begynder ved den første henvendelse til support.
  • Man kan stole på distributøren og sætte automatisk opdatering op. I så fald er et opkald til supporten sandsynligt straks efter en mislykket opdatering.
  • Muligheden for manuel opdatering kun efter afprøvning på testinfrastruktur er den sikreste, men også den dyreste og mest arbejdsintensive. Langt fra alle kan tillade sig dette.

Da forskellige brugere bruger forskellige opdateringsstrategier, skal man både understøtte den nyeste version samt alle tidligere udgivelser. Dette komplicerer både udviklings- og testprocessen og giver hovedpine til supportteamet.

Mangfoldighed af hardwareplatforme

Forskellige hardwareplatforme er et problem, der i høj grad er specifikt for native kode. I det mindste skal man samle binærer for hver understøttet platform.

I projektet Veeam Agent for Linux kan vi slet ikke få det til at fungere på nogen RISC-baserede platforme.

Jeg vil ikke gå i detaljer med dette spørgsmål. Jeg vil kun nævne de vigtigste problemer: platformafhængige typer som size_t, strukturudjævning og byte order.

Statisk og/eller dynamisk linking

Linux er mangefacet: hvordan man arbejder på enhver distribution
Men spørgsmålet om "Hvordan linker man med biblioteker - dynamisk eller statisk?" er værd at diskutere.

Som regel bruger C/C++ programmer på Linux dynamisk linking. Det fungerer fint, hvis programmet er bygget specifikt til en bestemt distribution.

Hvis målet er at dække forskellige distributioner med én binær fil, må man orientere sig efter den ældste understøttede distribution. For os er det Red Hat 6. Den indeholder gcc 4.4, som endda ikke understøtter standarden C++11. helt.

Vi bygger vores projekt med gcc 6.3, som fuldt ud understøtter C++14. Det vil sige, at vi i dette tilfælde må tage biblioteket libstdc++ og boost med til Red Hat 6. Det er nemmest at linke til dem statisk.

Men desværre er det ikke muligt at linke statisk med alle biblioteker.

For det første, systembiblioteker såsom libfuse, libblkid skal linkes dynamisk for at sikre kompatibiliteten med kernen og dens moduler.

For det andet er der en nuance med licenserne.

GPL-licensen tillader i princippet kun at linke biblioteker med open source-kode. MIT og BSD tillader statisk linking og gør det muligt at inkludere biblioteker i projektet. Men LGPL virker ikke som om den modsiger statisk linking, men kræver at der stilles de nødvendige filer til rådighed for linking.

Generelt vil brugen af dynamisk linking beskytte mod behovet for at stille noget til rådighed.

Bygning af C/C++ applikationer

For at bygge C/C++ applikationer til forskellige platforme og distributioner er det tilstrækkeligt at finde eller samle en passende version af gcc og bruge cross-compilere til specifikke arkitekturer, samt samle hele bibliotekssættet. Dette arbejde er ganske gennemførligt, men ret besværligt. Og der er ingen garantier for, at den valgte compiler og de valgte biblioteker vil give en fungerende version.

En åbenlys fordel: infrastrukturen bliver meget enklere, da hele byggeprocessen kan udføres på én maskine. Derudover er det tilstrækkeligt at samle ét sæt binære filer til én arkitektur, og så kan de pakkes i pakker til forskellige distributioner. Det er netop sådan, pakkerne til Veeam for Veeam Agent for Linux samles.

Modsat denne mulighed kan man blot forberede en build farm, det vil sige flere maskiner til samling. Hver sådan maskine vil sørge for kompilering af applikationen og pakkeopbygning til et specifikt distributionssystem og en bestemt arkitektur. I dette tilfælde udføres kompileringen med de værktøjer, som distributøren har forberedt. Det vil sige, at trin med at forberede kompileringsværktøjet og vælge biblioteker bliver overflødigt. Desuden kan byggesprocessen nemt paralleliseres.

Der er dog en ulempe ved denne tilgang: for hver distribution inden for samme arkitektur skal der samles sit eget sæt binære filer. Ulempen er også, at et sådant antal maskiner skal vedligeholdes, hvilket kræver meget diskplads og RAM.

Sådan samles KMOD-pakkerne af kædemodulet veeamsnap til Red Hat-distributioner.

Open Build Service

Kollegaerne fra SUSE forsøgte at implementere en form for gylden middelvej i form af en speciel service til kompilering af applikationer og pakkeopbygning — openbuildservice.

I bund og grund er det en hypervisor, der opretter en virtuel maskine, installerer alle nødvendige pakker i den, udfører kompileringen af applikationen og pakkeopbygningen i dette isolerede miljø, hvorefter den virtuelle maskine frigøres.

Linux er mangefacet: hvordan man arbejder på enhver distribution

Planlægningssystemet implementeret i OpenBuildService vil selv bestemme, hvor mange virtuelle maskiner det kan starte for optimal hastighed i pakkeopbygningen. Den indbyggede signeringsmekanisme vil automatisk signere pakkerne og lægge dem i det indbyggede repository. Det indbyggede versionskontrolsystem vil gemme historik over ændringer og opbygninger. Man skal blot tilføje sine kilder til dette system. Det er heller ikke nødvendigt at opsætte en server selv, man kan benytte den åbne.

Her er der dog et problem: en sådan kombination passer dårligt ind i den eksisterende infrastruktur. For eksempel er versionskontrol ikke nødvendig, da vi allerede har vores egne til kilderne. Signeringsmekanismen adskiller sig også: der bruges en speciel server. Repositoryet er heller ikke nødvendigt.

Desuden er understøttelsen af andre distributioner — for eksempel Red Hat — ret sparsom, hvilket er helt forståeligt.

En fordel ved sådan en service er den hurtige support af den nyeste version af SUSE-distributionen. Inden den officielle meddelelse om udgivelsen bliver de nødvendige pakker til byggeriet lagt ud på det offentlige repository. I listen over tilgængelige distributioner i OpenBuildService vises den nye. Vi sætter et flueben, og den tilføjes til byggeplanen. På denne måde kan tilføjelsen af en ny version af distributionen ske næsten med ét klik.

I vores infrastruktur, der bruger OpenBuildService, samles hele mangfoldigheden af KMP-pakker til veeamsnap-kernemodulet for SUSE-distributioner.

Næste vil jeg fokusere på spørgsmål, der er specifikke for kernemoduler.

kernel ABI

Linux kernemoduler har historisk set været distribueret i form af kildekode. Problemet er, at skaberne af kernen ikke påtager sig byrden med at støtte en stabil API for kernemoduler, langt mindre på binær niveau, også kendt som kABI.

For at bygge et modul til den almindelige kerne er det nødvendigt at have netop denne kernes header-filer, og det vil kun fungere på denne kerne.

DKMS muliggør automatiseringen af byggeprocessen for moduler ved opdatering af kernen. Som resultat bruger brugere af Debian-repositoriet (og dets mange slægtninge) kernemoduler enten fra distributørens repository eller bygget fra kilden med hjælp fra DKMS.

Men en sådan situation tilfredsstiller ikke Enterprise-segmentet. Distributører af proprietær kode ønsker at distribuere deres produkt som samlede binærfiler.

Administratorer ønsker ikke at have udviklingsværktøjer på produktionsservere af sikkerhedsmæssige årsager. Distributører af Enterprise Linux — såsom Red Hat og SUSE — har besluttet, at de kan støtte en stabil kABI for deres brugere. Resultatet har været KMOD-pakker til Red Hat og KMP-pakker til SUSE.

Essensen af denne løsning er ret simpel. For en bestemt version af distributionen fryses kernen API. Distributøren hævder, at de bruger netop kernen, for eksempel version 3.10, og laver kun rettelser og forbedringer, som ikke berører kerne-grænsefladerne, og moduler bygget til den allerførste kerne kan bruges til alle efterfølgende uden rekompilering.

Red Hat erklærer kABI-kompatibilitet for distributionen gennem hele livscyklussen. Det vil sige, at en samlet modul til RHEL 6.0 (udgivelse november 2010) også skal fungere på version 6.10 (udgivelse juni 2018). Og det er næsten 8 år. Naturligvis er det en ret kompleks opgave.
Vi har registreret flere tilfælde, hvor moduler som følge af problemer med kABI-kompatibilitet ophørte med at fungere.

Efter at modulet veeamsnap, der blev bygget til RHEL 7.0, viste sig at være inkompatibelt med kernen fra RHEL 7.5, men alligevel blev indlæst og garanteret nedbrød serveren, opgav vi helt at bruge kABI-kompatibilitet for RHEL 7.

I øjeblikket indeholder KMOD-pakken til RHEL 7 en samling for hver versionsudgivelse og et script, der sikrer indlæsning af modulet.

SUSE har taget en mere forsigtig tilgang til spørgsmålet om kABI-kompatibilitet. De sikrer kABI-kompatibilitet kun inden for en enkelt service pack.

For eksempel blev udgivelsen af SLES 12 i september 2014. Og SLES 12 SP1 kom allerede i december 2015, altså lidt over et år senere. Selvom begge udgivelser bruger kerne 3.12, er de kABI-incompatible. Det er tydeligt, at det er langt enklere at opretholde kABI-kompatibilitet i blot et år. Den årlige cyklus for opdatering af kerne-modulet bør ikke forhindre moduludviklerne.

Som følge af denne politik fra SUSE har vi ikke registreret et eneste problem med kABI-kompatibilitet for vores modul veeamsnap. Sandheden er, at antallet af pakker til SUSE er næsten en orden større.

Patches og backports

Selvom distributørerne forsøger at sikre kABI-kompatibilitet og stabilitet i kernen, forsøger de også at forbedre ydeevnen og rette defekter i denne stabile kerne.

Derudover holder kerneludviklerne for enterprise linux øje med ændringer i den vanille kerne og overfører dem til deres "stabile".

Nogle gange fører dette til nye fejl.

I den seneste udgivelse af Red Hat 6 blev der lavet en fejl i en af de mindre opdateringer. Den førte til, at modulet veeamsnap garanteret nedbrød systemet ved frigivelse af snapshots. Ved at sammenligne kildekoden til kernen før og efter opdateringen fandt vi, at årsagen var backport. En lignende fix blev lavet i vanillekernen version 4.19. Bare i den vanille kerne fungerede denne fix normalt, men da den blev overført til "stabile" 2.6.32 opstod der et problem med spin-locking.

Selvfølgelig er fejl noget, som alle og altid oplever, men var det værd at trække koden fra 4.19 til 2.6.32 og risikere stabiliteten? Jeg er ikke sikker...

Det værste er, når marketing kommer ind i det, mens man trækker i det mentale reb mellem 'stabilitet' og 'modernisering'. Marketingafdelingen skal have en stabil kerne i den opdaterede distribution, samtidig med at den skal være bedre i ydeevne og have nye funktioner. Dette fører til mærkelige kompromiser.

Da jeg forsøgte at samle modulet på kerne 4.4 fra SLES 12 SP3, blev jeg overrasket over at finde funktionaliteten fra den vanilje 4.8. Efter min mening ligner implementeringen af blokindgang/udgang i kerne 4.4 fra SLES 12 SP3 mere kerne 4.8 end den tidligere stabile 4.4 kerne fra SLES 12 SP2. Jeg vil ikke bedømme, hvad procentdelen var af overført kode fra kerne 4.8 til SLES-4.4 for SP3, men det føles for mig svært at kalde kerne det samme stabile 4.4.

Det mest problematiske ved at skrive et modul, der fungerer lige godt på forskellige kerner, er, at man ikke længere kan stole på kerneversionen. Man må også tage hensyn til distributionen. Det er godt, at man nogle gange kan knytte sig til en define, der kommer med den nye funktionalitet, men sådan en mulighed opstår ikke altid.

Som følge heraf får koden mærkelige betingede kompilationsdirektiver.

Der findes også patches, der ændrer det dokumenterede API for kernen.
Jeg stødte på distributionen KDE neon 5.16 og blev meget overrasket over at se, at kaldet til lookup_bdev i denne kernelversion ændrede listen over indparameterne.

For at kunne samle det, måtte jeg i makefile tilføje et script, der tjekker, om parameteren mask er til stede for funktionen lookup_bdev.

Signaturer for kerne-moduler

Men lad os vende tilbage til spørgsmålet om distribution af pakker.

En af fordelene ved stabil kABI er, at kerne-moduler kan signeres som binære filer. I så fald kan udvikleren være sikker på, at modulet ikke er blevet beskadiget ved et uheld eller ændret med vilje. Dette kan verificeres med kommandoen modinfo.

Red Hat og SUSE distributioner tillader at kontrollere signaturen af modulet og indlæse det kun, hvis det tilhørende certifikat er registreret i systemet. Certifikatet er en offentlig nøgle, der bruges til at signere modulet. Vi distribuerer det som en separat pakke.

Problemet her er, at certifikaterne kan enten være indbygget i kernen (de bruges af distributører) eller skal skrives til den ikke-flygtige EFI-hukommelse ved hjælp af en utility. mokutil. Utility mokutil ved installation af certifikatet kræver en genstart af systemet, og inden kernelens opstart foreslår det til administratoren at tillade indlæsning af det nye certifikat.

Dermed kræver tilføjelsen af et certifikat fysisk adgang til systemet fra administratoren. Hvis maskinen er placeret et sted i cloud’en eller blot i en fjern server, og adgangen blot er netværksbaseret (f.eks. via ssh), så vil det ikke være muligt at tilføje certifikatet.

EFI på virtuelle maskiner

Selvom EFI allerede længe har været understøttet af næsten alle producenters bundkort, kan administratoren ved installation af systemet muligvis ikke tænke over nødvendigheden af EFI, og det kan være deaktiveret.

Ikke alle hypervisorer understøtter EFI. VMWare vSphere understøtter EFI fra version 5.
Microsoft Hyper-V har også fået støtte for EFI fra Hyper-V for Windows Server 2012R2.

Men i standardkonfigurationen er denne funktionalitet deaktiveret for Linux-maskiner, hvilket betyder, at certifikatet ikke kan installeres.

I vSphere 6.5 kan man kun indstille muligheden Secure Boot i den gamle version af webgrænsefladen, der kører via Flash. Web UI i HTML-5 halter stadig meget bagefter.

Eksperimentelle distributioner

Og til sidst lad os se på spørgsmålet om eksperimentelle distributioner og distributioner uden officiel støtte. På den ene side vil man næppe finde sådanne distributioner på servere i seriøse organisationer. Der er ingen officiel støtte til sådanne distributioner. Derfor kan man ikke sørge for teknisk support af produktet på en sådan distribution.

Men sådanne distributioner bliver en praktisk platform til at afprøve nye eksperimentelle løsninger. For eksempel Fedora, OpenSUSE Tumbleweed eller Unstable-versioner af Debian. De er ganske stabile. De har altid nye versioner af programmer og altid en ny kernel. Om et år kan denne eksperimentelle funktionalitet findes i den opdaterede RHEL, SLES eller Ubuntu.

Så hvis noget ikke fungerer på en eksperimentel distribution, er det en grund til at undersøge problemet og løse det. Man skal være klar over, at denne funktionalitet snart vil dukke op på brugernes produktionsservere.

Den nuværende liste over officielt understøttede distributioner for version 3.0 kan du studere her. Men den faktiske liste over distributioner, som vores produkt kan køre på, er meget større.

Jeg var personligt interesseret i et eksperiment med OS "Elbrus". Efter justering af veeam-pakken blev vores produkt installeret og fungerede. Jeg skrev om dette eksperiment på Habra i artikel.

Og støtten til nye distributioner fortsætter. Vi forventer snart version 4.0. Betaversionen burde snart være tilgængelig, så hold øje med whats-new!

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster