Linux a plusieurs visages: comment travailler sur n'importe quelle distribution



La création d'une application de sauvegarde qui s'exécute sur n'importe quelle distribution n'est pas une tâche facile. Pour vous assurer que Veeam Agent pour Linux fonctionne sur les distributions de RHEL 6 et Debian 6, jusqu'à openSUSE Leap 15.1 et Ubuntu 19.04, vous devez résoudre une série de problèmes, en particulier lorsque vous considérez que le module du noyau fait partie du produit logiciel.

Cet article est basé sur une présentation à la conférence LinuxPiter 2019 .

Linux n'est pas seulement l'un des systèmes d'exploitation les plus populaires. En fait, c'est une plate-forme sur la base de laquelle vous pouvez faire quelque chose d'unique, quelque chose de vôtre. Pour cette raison, Linux a de nombreuses distributions qui diffèrent dans un ensemble de composants logiciels. Et le problème se pose ici: pour que le produit logiciel fonctionne sur n'importe quelle distribution, vous devez prendre en compte les caractéristiques de chacune.

Gestionnaires de packages. .deb vs .rpm


Commençons par le problème évident de la distribution du produit pour différentes distributions.
La façon la plus courante de distribuer des produits logiciels est de placer le package dans le référentiel afin que le gestionnaire de packages intégré au système puisse l'installer à partir de là.
Cependant, nous avons deux formats de packages populaires: rpm et deb . Donc, tout le monde devra soutenir.

Dans le monde des packages deb, le niveau de compatibilité est incroyable. Le même paquet s'installe également bien et fonctionne à la fois sur Debian 6 et Ubuntu 19.04. Les normes pour le processus de construction de paquets et leur utilisation, établies dans les anciennes distributions Debian, restent pertinentes dans la nouvelle version de Linux Mint et du système d'exploitation élémentaire. Par conséquent, dans le cas de Veeam Agent pour Linux, un package deb pour chaque plate-forme matérielle est suffisant.

Mais dans le monde des packages rpm, les différences sont grandes. Tout d'abord, en raison du fait qu'il existe deux distributeurs complètement indépendants de Red Hat et SUSE, pour lesquels la compatibilité n'est absolument pas nécessaire. Deuxièmement, ces distributeurs ont des distributions de ceux-ci. support et expérimental. Entre eux, la compatibilité n'est pas non plus nécessaire. Il s'est avéré que pour el6, el7 et el8 leurs propres packages. Paquet séparé pour Fedora. Packages pour SLES11 et 12 et séparés pour openSUSE. Le problème principal est les dépendances et les noms de package.

Problème de dépendance


Hélas, les mêmes packages se retrouvent souvent sous des noms différents dans des distributions différentes. Vous trouverez ci-dessous une liste partielle des dépendances des packages veeam.
Pour EL7:Pour SLES 12:
  • libblkid
  • libgcc
  • libstdc ++
  • ncurses-libs
  • Fuse-libs
  • bibliothèques de fichiers
  • veeamsnap = 3.0.2.1185
  • libblkid1
  • libgcc_s1
  • libstdc ++ 6
  • libmagic1
  • libfuse2
  • veeamsnap-kmp = 3.0.2.1185

Par conséquent, la liste des dépendances est unique à la distribution.

Cela empire lorsqu'une version mise à jour commence à se cacher sous l'ancien nom du package.

Un exemple:

Fedora 24 a mis à jour le package ncurses de la version 5 à la version 6. Notre produit a été construit avec la version 5 afin d'assurer la compatibilité avec les anciennes distributions. Pour utiliser l'ancienne 5e version de la bibliothèque sur Fedora 24, j'ai dû utiliser le paquet ncurses-compat-libs .

Par conséquent, deux packages apparaissent pour Fedora, avec des dépendances différentes.

Plus intéressant. Après la prochaine mise à jour du package de distribution, le package ncurses-compat-libs avec la 5e version de la bibliothèque n'est pas disponible. Il n'est pas rentable pour un distributeur d'extraire d'anciennes bibliothèques dans une nouvelle version de distribution. Après un certain temps, le problème a été répété dans les distributions SUSE.

Par conséquent, pour certaines distributions, j'ai dû abandonner la dépendance explicite de ncurses-libs et corriger le produit afin qu'il puisse fonctionner avec n'importe quelle version de la bibliothèque.

Soit dit en passant, dans la 8e version de Red Hat, il n'y a plus de méta-package python qui faisait référence au bon vieux python 2.7 . Il existe python2 et python 3.

Alternative aux gestionnaires de packages


Le problème des dépendances est ancien et évident depuis longtemps. Rappelez-vous juste l'enfer de la dépendance.
Combinez différentes bibliothèques et applications afin qu'elles fonctionnent toutes de manière stable et n'entrent pas en conflit - en fait, tout distributeur Linux essaie de résoudre ce problème.

Le gestionnaire de paquets canonique Snappy essaie de résoudre ce problème de manière très différente. L'idée principale: l'application s'exécute dans un bac à sable isolé et protégé du système principal. Si l'application a besoin de bibliothèques, elles sont livrées avec l'application elle-même.

Flatpak vous permet également d'exécuter des applications dans le bac à sable à l'aide de conteneurs Linux. Il existe également AppImage , qui vous permet de créer des images portables de programmes.

Ces solutions vous permettent de créer un package pour toutes les distributions. Dans le cas de Flatpak et AppImage, l' installation et le lancement de l'application sont possibles même à l'insu de l'administrateur.

Le problème principal est que toutes les applications ne peuvent pas s'exécuter dans le bac à sable et sans privilèges root . Certains ont besoin d'un accès direct à la plateforme. Je ne parle pas des modules du noyau, qui dépendent fortement du noyau et ne rentrent pas dans le concept du bac à sable.

Le deuxième problème est que les distributions populaires de Red Hat et SUSE dans l'environnement d'entreprise ne prennent pas encore en charge Snappy et Flatpak.

À cet égard, Veeam Agent pour Linux n'est ni sur snapcraft.io ni sur flathub.org .

À la fin de la question sur les gestionnaires de packages, je note qu'il existe une option pour abandonner complètement les gestionnaires de packages en combinant des fichiers binaires et un script pour les installer dans un package.

Un tel ensemble vous permet de créer un package commun pour différentes distributions et plates-formes, d'effectuer un processus d'installation interactif, en effectuant la personnalisation nécessaire. Je suis tombé sur de tels packages pour Linux uniquement à partir de VMware.

Problème de mise à jour



Même si tous les problèmes de dépendance sont résolus, le programme peut fonctionner différemment sur la même distribution. Le point est dans les mises à jour.

Il existe 3 stratégies de mise à niveau:

  • Le plus simple est de ne jamais mettre à jour. Configuré le serveur et oublié. Pourquoi les mises à jour si tout fonctionne? Les problèmes commencent la première fois que vous contactez l'assistance. Le créateur de la distribution ne prend en charge qu'une version mise à jour.
  • Vous pouvez faire confiance au distributeur et configurer des mises à jour automatiques. Dans ce cas, un appel au support est probable immédiatement après une mise à jour infructueuse.
  • L'option de mise à jour manuelle uniquement après l'avoir exécutée sur l'infrastructure de test est la plus fidèle, mais coûteuse et longue. Tout le monde n'est pas en mesure de se le permettre.

Étant donné que différents utilisateurs utilisent différentes stratégies de mise à jour, vous devez prendre en charge la dernière version et toutes les versions précédentes. Cela complique le processus de développement et le processus de test ajoute un casse-tête au service de support.

Variété de plates-formes matérielles


Diverses plates-formes matérielles sont un problème largement spécifique au code natif. Au minimum, vous devez collecter des fichiers binaires pour chaque plate-forme prise en charge.

Dans le projet Veeam Agent pour Linux, nous ne pouvons toujours pas prendre en charge au moins quelque chose comme RISC.

Je ne m'attarderai pas sur cette question en détail. Je ne décrirai que les principaux problèmes: les types dépendants de la plate-forme tels que size_t , l'alignement des structures et l'ordre des octets.

Liaison statique et / ou dynamique



Et voici la question «Comment établir un lien avec les bibliothèques - dynamiquement ou statiquement?» mérite d'être discuté.

En règle générale, les applications Linux C / C ++ utilisent la liaison dynamique. Cela fonctionne très bien si l'application est conçue spécifiquement pour une distribution spécifique.

Si la tâche consiste à couvrir une variété de distributions avec un fichier binaire, vous devez vous concentrer sur la distribution prise en charge la plus ancienne. Pour nous, il s'agit de Red Hat 6. Il contient gcc 4.4, que même la norme C ++ 11 ne prend pas entièrement en charge.

Nous construisons notre projet en utilisant gcc 6.3, qui prend entièrement en charge C ++ 14. Naturellement, dans ce cas sur Red Hat 6, la bibliothèque libstdc ++ et boost doit être traînée. Le moyen le plus simple de les lier est statiquement.

Mais hélas, toutes les bibliothèques ne peuvent pas être liées statiquement.

Tout d'abord, les bibliothèques système, telles que libfuse , libblkid, doivent être liées dynamiquement pour s'assurer qu'elles sont compatibles avec le noyau et ses modules.

Deuxièmement, il y a une subtilité avec les licences.

La licence GPL permet essentiellement de lier des bibliothèques uniquement avec du code opensource. MIT et BSD permettent la liaison statique et permettent aux bibliothèques d'être incluses dans le projet. Mais LGPL ne semble pas contredire la liaison statique, mais nécessite le partage des fichiers nécessaires à la liaison.

En général, l'utilisation de la liaison dynamique protégera contre la nécessité de fournir quelque chose.

Création d'applications C / C ++


Pour créer des applications C / C ++ pour différentes plates-formes et distributions, il suffit de sélectionner ou de compiler une version appropriée de gcc et d'utiliser des compilateurs croisés pour des architectures spécifiques, afin de collecter l'ensemble complet des bibliothèques. Ce travail est tout à fait réalisable, mais plutôt gênant. Et il n'y a aucune garantie que le compilateur et les bibliothèques sélectionnés fourniront une option viable.

Un plus évident: l'infrastructure est grandement simplifiée, car l'ensemble du processus d'assemblage peut être effectué sur une seule machine. De plus, il suffit de collecter un ensemble de fichiers binaires pour une architecture et vous pouvez les regrouper dans des packages pour différentes distributions. C'est ainsi que les packages veeam pour Veeam Agent pour Linux sont construits.

Contrairement à cette option, vous pouvez simplement préparer la ferme de génération, c'est-à-dire plusieurs machines pour l'assemblage. Chacune de ces machines fournira la compilation de l'application et l'assemblage du package pour une distribution particulière et une architecture spécifique. Dans ce cas, la compilation est effectuée par les moyens que le distributeur a préparés. Autrement dit, l'étape de préparation du compilateur et la sélection des bibliothèques ne sont plus nécessaires. De plus, le processus d'assemblage peut être facilement parallélisé.

Il y a cependant un inconvénient à cette approche: pour chaque distribution dans la même architecture, vous devrez assembler votre propre ensemble de fichiers binaires. Un autre inconvénient est que de nombreuses machines doivent être maintenues pour allouer une grande quantité d'espace disque et de RAM.

Ainsi, les packages KMOD du module de noyau veeamsnap pour les distributions Red Hat sont collectés.

Service de construction ouvert


Les collègues de SUSE ont essayé d'implémenter un terrain d'entente en tant que service spécial pour la compilation d'applications et la construction de packages - openbuildservice .

En substance, c'est un hyperviseur qui crée une machine virtuelle, y installe tous les packages nécessaires, compile l'application et compile le package dans cet environnement isolé, après quoi une telle machine virtuelle est libérée.



Le planificateur implémenté dans OpenBuildService déterminera le nombre de machines virtuelles qu'il peut exécuter pour la vitesse de génération de package optimale. Le mécanisme de signature intégré lui-même signera les packages et les placera dans le référentiel intégré. Le système de contrôle de version intégré enregistre l'historique des modifications et des assemblages. Reste à ajouter simplement votre code source à ce système. Même le serveur lui-même n'est pas nécessaire d'augmenter, mais vous pouvez utiliser celui ouvert.

Ici, cependant, il y a un problème: une telle moissonneuse-batteuse est difficile à intégrer dans l'infrastructure existante. Par exemple, le contrôle de version n'est pas nécessaire, nous avons déjà le nôtre pour les sources. Le mécanisme de signature est différent: un serveur spécial est utilisé. Le référentiel n'est également pas nécessaire.

De plus, la prise en charge d'autres distributions - par exemple, Red Hat - est implémentée assez mal, ce qui est compréhensible.

L'avantage de ce service est la prise en charge rapide de la prochaine version de la distribution SUSE. Avant l'annonce officielle de la version, les packages requis pour l'assemblage sont téléchargés dans le référentiel public. Une nouvelle apparaît dans la liste des distributions disponibles sur OpenBuildService. Nous mettons une coche et elle est ajoutée au plan de montage. Ainsi, l'ajout d'une nouvelle version de la distribution s'effectue en presque un clic.

Dans notre infrastructure, en utilisant OpenBuildService, nous assemblons toute la variété des packages KMP du module de noyau veeamsnap pour les distributions SUSE.

De plus, je voudrais m'attarder sur les problèmes spécifiques aux modules du noyau.

noyau ABI


Historiquement, les modules du noyau Linux ont été distribués sous forme source. Le fait est que les créateurs du noyau ne se pèsent pas sur le soin de maintenir une API stable pour les modules du noyau, et encore plus au niveau binaire, puis kABI.

Pour construire un module pour le noyau vanilla, les en-têtes de ce noyau particulier sont requis, et cela ne fonctionnera que sur ce noyau.

DKMS vous permet d'automatiser le processus d'assemblage des modules lors de la mise à jour du noyau. En conséquence, les utilisateurs du référentiel Debian (et ses nombreux parents) utilisent des modules du noyau soit à partir du référentiel de distribution, soit assemblés à partir des sources à l'aide de DKMS.

Cependant, cette situation n'est pas particulièrement confortable avec le segment Entreprise. Les distributeurs de code propriétaires souhaitent distribuer le produit sous forme de binaires compilés.

Les administrateurs ne souhaitent pas conserver les outils de développement sur les serveurs de production pour des raisons de sécurité. Les distributeurs Enterprise Linux - tels que Red Hat et SUSE - ont décidé qu'ils pouvaient maintenir un kABI stable pour leurs utilisateurs. En conséquence, les packages KMOD pour Red Hat et les packages KMP pour SUSE sont apparus.

L'essence de cette solution est assez simple. L'API du noyau est gelée pour une version spécifique de la distribution. Le distributeur déclare qu'il utilise le noyau, par exemple, 3.10, et n'apporte que des corrections et améliorations qui n'affectent en aucune façon les interfaces du noyau, et les modules assemblés pour le tout premier noyau peuvent être utilisés pour tous les suivants sans recompilation.

Red Hat annonce la compatibilité kABI pour la distribution tout au long du cycle de vie. Autrement dit, le module assemblé pour rhel 6.0 (version de novembre 2010) devrait également fonctionner sur la version 6.10 (version de juin 2018). Et cela fait presque 8 ans. Naturellement, la tâche est plutôt compliquée.
Nous avons enregistré plusieurs cas où, en raison de problèmes de compatibilité kABI, le module veeamsnap a cessé de fonctionner.

Après que le module veeamsnap compilé pour RHEL 7.0 se soit avéré incompatible avec le noyau de RHEL 7.5, mais qu'il a chargé et garanti l'abandon du serveur, nous avons refusé d'utiliser la compatibilité kABI pour RHEL 7 en général.

Actuellement, le package KMOD pour RHEL 7 contient un assembly pour chaque version et un script qui fournit le chargement du module.

SUSE a abordé la tâche de compatibilité kABI plus attentivement. Ils offrent la compatibilité kABI dans un seul service pack.

Par exemple, la sortie de SLES 12 a eu lieu en septembre 2014. Et SLES 12 SP1 est déjà en décembre 2015, c'est-à-dire qu'un peu plus d'un an s'est écoulé. Bien que les deux versions utilisent le noyau 3.12, elles ne sont pas compatibles avec kABI. De toute évidence, le maintien de la compatibilité kABI pendant un an est beaucoup plus facile. Le cycle annuel de mise à jour des modules de base ne devrait pas poser de problèmes aux créateurs des modules.

Grâce à cette politique SUSE, nous n'avons résolu aucun problème de compatibilité kABI dans notre module veeamsnap. Certes, le nombre de packages pour SUSE est presque un ordre de grandeur plus grand.

Patches et backports


Malgré le fait que les distributeurs tentent d'assurer la compatibilité kABI et la stabilité du noyau, ils essaient également d'améliorer les performances et d'éliminer les défauts de ce noyau stable.

De plus, en plus de leur propre «travail sur les erreurs», les développeurs du noyau Linux d'entreprise suivent les changements dans le noyau vanilla et les transfèrent dans leur noyau «stable».

Parfois, cela conduit à de nouvelles erreurs .

La dernière version de Red Hat 6 a fait une erreur dans l'une des mises à jour mineures. Cela a conduit au fait que le module veeamsnap était garanti de planter le système lorsque l'instantané a été publié. En comparant les sources du noyau avant et après la mise à jour, nous avons découvert que le backport était à blâmer. Un correctif similaire a été fait dans la version 4.19 du noyau vanilla. Mais seulement dans le noyau vanilla, ce correctif a bien fonctionné, et lors du transfert vers la version "stable" 2.6.32, il y avait un problème avec spin-lock.

Bien sûr, tout le monde a toujours des erreurs, mais cela valait-il la peine de faire glisser le code de 4.19 à 2.6.32, risquant de compromettre la stabilité? .. Je ne suis pas sûr ...

Pire encore, lorsque le marketing est lié au remorqueur de la guerre, la «stabilité» <-> «la modernisation». Le département marketing a besoin que le cœur de la distribution mise à jour soit stable, d'une part, et en même temps meilleur en performance et doté de nouvelles fonctionnalités. Cela conduit à d'étranges compromis.

Lorsque j'ai essayé de construire un module sur le noyau 4.4 de SLES 12 SP3, j'ai été surpris d'y trouver des fonctionnalités de vanilla 4.8. À mon avis, l'implémentation d'E / S de bloc du noyau 4.4 de SLES 12 SP3 ressemble plus à un noyau 4.8 que la version précédente du noyau 4.4 stable de SLES12 SP2. Je ne peux pas juger quel pourcentage de code a été transféré du noyau 4.8 vers SLES 4.4 pour SP3, mais je n'ai toujours pas la possibilité d'appeler le noyau le même 4.4 stable.

La chose la plus désagréable à ce sujet est que lorsque vous écrivez un module qui fonctionne aussi bien sur différents cœurs, vous ne pouvez plus compter sur la version du noyau. Nous devons également prendre en compte la distribution. Il est bon que parfois vous puissiez vous impliquer dans une définition qui apparaît avec de nouvelles fonctionnalités, mais cette fonctionnalité n'apparaît pas toujours.

Par conséquent, le code est entouré de directives sophistiquées pour la compilation conditionnelle.

Il existe également des correctifs qui modifient l'API du noyau documentée.
Je suis tombé sur un kit de distribution KDE néon 5.16 et j'ai été très surpris de voir que l'appel lookup_bdev dans cette version du noyau a changé la liste des paramètres d'entrée.

Pour se réunir, nous avons dû ajouter un script dans le makefile qui vérifie si la fonction lookup_bdev a un paramètre de masque.

Signature des modules du noyau


Mais revenons à la question de la distribution des packages.

L'un des avantages de kABI stable est que les modules du noyau peuvent être signés en tant que fichier binaire. Dans ce cas, le développeur peut être sûr que le module n'a pas été accidentellement endommagé ou modifié intentionnellement. Vous pouvez le vérifier avec la commande modinfo.

Les distributions Red Hat et SUSE vous permettent de vérifier la signature d'un module et de le télécharger uniquement si le certificat approprié est enregistré dans le système. Le certificat est la clé publique par laquelle le module est signé. Nous le distribuons dans un package séparé.

Le problème ici est que les certificats peuvent être intégrés au noyau (ils sont utilisés par les distributeurs) ou doivent être écrits dans une mémoire EFI non volatile à l'aide de l'utilitaire mokutil . Lors de l'installation du certificat, l'utilitaire mokutil nécessite un redémarrage du système et même avant le chargement du noyau du système d'exploitation, il propose à l'administrateur d'autoriser le téléchargement du nouveau certificat.

Ainsi, l'ajout d'un certificat nécessite un accès physique administrateur au système. Si la machine est située quelque part dans le cloud ou juste dans une salle de serveurs distante et que l'accès se fait uniquement via le réseau (par exemple, via ssh), il sera impossible d'ajouter un certificat.

EFI sur les machines virtuelles


Malgré le fait que EFI a longtemps été pris en charge par presque tous les créateurs de la carte mère, lors de l'installation du système, l'administrateur peut ne pas penser au besoin d'EFI, et il peut être désactivé.

Tous les hyperviseurs ne prennent pas en charge EFI. VMWare vSphere prend en charge EFI depuis la version 5.
Microsoft Hyper-V a également reçu la prise en charge EFI, à commencer par Hyper-V pour Windows Server 2012R2.

Cependant, dans la configuration par défaut, cette fonctionnalité est désactivée pour les machines Linux, ce qui signifie que le certificat ne peut pas être installé.

Dans vSphere 6.5, vous pouvez définir l'option Secure Boot uniquement dans l'ancienne version de l'interface Web qui fonctionne via Flash. L'interface utilisateur Web sur HTML-5 est loin derrière.

Distributions expérimentales


Et enfin, considérons la question des distributions expérimentales et des distributions sans support officiel. D'une part, de telles distributions sont peu susceptibles d'être trouvées sur les serveurs d'organisations sérieuses. Il n'y a pas de support officiel pour de telles distributions. Par conséquent, pour les fournir. le support produit sur une telle distribution n'est pas possible.

Cependant, ces distributions deviennent une plate-forme pratique pour tester de nouvelles solutions expérimentales. Par exemple, Fedora, OpenSUSE Tumbleweed ou la version instable de Debian. Ils sont assez stables. Ils ont toujours de nouvelles versions de programmes et toujours un nouveau noyau. Après un an, cette fonctionnalité expérimentale peut être dans la mise à jour RHEL, SLES ou Ubuntu.

Donc, si quelque chose ne fonctionne pas sur le kit de distribution expérimental, c'est l'occasion de trier le problème et de le résoudre. Vous devez être préparé au fait que cette fonctionnalité apparaîtra bientôt sur les serveurs de production des utilisateurs.

La liste actuelle des distributions officiellement prises en charge pour la version 3.0 se trouve ici . Mais la véritable liste des distributions sur lesquelles notre produit est capable de fonctionner est beaucoup plus large.

Personnellement, j'étais intéressé par une expérience avec le système d'exploitation Elbrus. Après la mise à jour du package veeam, notre produit a été installé et gagné. À propos de cette expérience, j'ai écrit sur Habré dans un article .

Eh bien, le support des nouvelles distributions continue. Nous attendons la sortie de la version 4.0. La bêta est sur le point d'apparaître, alors restez à l' affût des nouveautés !

Source: https://habr.com/ru/post/fr471226/


All Articles