Linux tiene muchas caras: cómo funcionar en cualquier distribución

Linux tiene muchas caras: cómo funcionar en cualquier distribución

Crear una aplicación de respaldo que funcione en cualquier distribución no es una tarea fácil. Para garantizar que Veeam Agent para Linux funcione en distribuciones desde Red Hat 6 y Debian 6 hasta OpenSUSE 15.1 y Ubuntu 19.04, debe resolver una variedad de problemas, especialmente considerando que el producto de software incluye un módulo de kernel.

El artículo fue creado a partir de materiales de un discurso en la conferencia. Linux Pedro 2019.

Linux no es sólo uno de los sistemas operativos más populares. Básicamente, se trata de una plataforma a partir de la cual puedes crear algo único, algo propio. Gracias a esto, Linux cuenta con muchas distribuciones que se diferencian en su conjunto de componentes de software. Y aquí surge un problema: para que un producto de software funcione en cualquier distribución, hay que tener en cuenta las características de cada una.

Gestores de paquetes. .deb frente a .rpm

Comencemos con el problema obvio de distribuir el producto entre diferentes distribuciones.
La forma más típica de distribuir productos de software es colocar el paquete en un repositorio para que el administrador de paquetes integrado en el sistema pueda instalarlo desde allí.
Sin embargo, tenemos dos formatos de paquetes populares: rpm и debutante. Esto significa que todos tendrán que apoyar.

En el mundo de los paquetes deb, el nivel de compatibilidad es asombroso. El mismo paquete se instala y funciona igualmente bien tanto en Debian 6 como en Ubuntu 19.04. Los estándares para el proceso de creación de paquetes y trabajar con ellos, establecidos en las antiguas distribuciones de Debian, siguen siendo relevantes en el novedoso Linux Mint y en el sistema operativo elemental. Por tanto, en el caso de Veeam Agent para Linux, un paquete deb para cada plataforma de hardware es suficiente.

Pero en el mundo de los paquetes rpm, las diferencias son grandes. En primer lugar, por el hecho de que existen dos distribuidores completamente independientes, Red Hat y SUSE, para los cuales la compatibilidad es completamente innecesaria. En segundo lugar, estos distribuidores tienen kits de distribución de esos. soporte y experimental. Tampoco hay necesidad de compatibilidad entre ellos. Resultó que el6, el7 y el8 tienen sus propios paquetes. Paquete separado para Fedora. Paquetes para SLES11 y 12 y uno aparte para openSUSE. El principal problema son las dependencias y los nombres de los paquetes.

problema de dependencia

Desafortunadamente, los mismos paquetes a menudo terminan con nombres diferentes en diferentes distribuciones. A continuación se muestra una lista parcial de las dependencias del paquete veeam.

Para EL7:
Para SLES 12:

  • libblkid
  • libgcc
  • libstdc ++
  • ncurses-libs
  • bibliotecas-fusibles
  • bibliotecas de archivos
  • veeamsnap=3.0.2.1185
  • libblkid1
  • libgcc_s1
  • libstdc ++ 6
  • libmagic1
  • libfuse2
  • veeamsnap-kmp=3.0.2.1185

Como resultado, la lista de dependencias es única para la distribución.

Lo que empeora es cuando una versión actualizada comienza a ocultarse bajo el nombre del paquete anterior.

Ejemplo:

El paquete ha sido actualizado en Fedora 24. maldiciones de la versión 5 a la versión 6. Nuestro producto fue creado con la versión 5 para garantizar la compatibilidad con distribuciones anteriores. Para usar la quinta versión antigua de la biblioteca en Fedora 5, tuve que usar el paquete ncurses-compat-libs.

Como resultado, existen dos paquetes para Fedora, con diferentes dependencias.

Más interesante. Después de la siguiente actualización de distribución, el paquete ncurses-compat-libs con la versión 5 de la biblioteca resulta que no está disponible. A un distribuidor le resulta caro arrastrar bibliotecas antiguas a una nueva versión de la distribución. Después de un tiempo, el problema se repitió en las distribuciones SUSE.

Como resultado, algunas distribuciones tuvieron que abandonar su dependencia explícita de ncurses-libsy arreglar el producto para que pueda funcionar con cualquier versión de la biblioteca.

Por cierto, en la versión 8 de Red Hat ya no hay metapaquete pitón, que se refería al buen viejo python 2.7. Hay python2 и pitón3.

Alternativa a los administradores de paquetes

El problema de las dependencias es antiguo y evidente desde hace mucho tiempo. Sólo recuerda el infierno de la dependencia.
Combinar varias bibliotecas y aplicaciones para que todas funcionen de manera estable y no entren en conflicto; de hecho, esta es la tarea que cualquier distribuidor de Linux intenta resolver.

El administrador de paquetes intenta resolver este problema de una manera completamente diferente. Rápido de Canónico. La idea principal: la aplicación se ejecuta en un sandbox aislado y protegido del sistema principal. Si una aplicación requiere bibliotecas, se proporcionan con la propia aplicación.

Flatpak También le permite ejecutar aplicaciones en un entorno limitado utilizando contenedores de Linux. La idea del sandbox también se utiliza. AppImage.

Estas soluciones le permiten crear un paquete para cualquier distribución. En caso de Flatpak La instalación y el lanzamiento de la aplicación son posibles incluso sin el conocimiento del administrador.

El principal problema es que no todas las aplicaciones pueden ejecutarse en un sandbox. Algunas personas necesitan acceso directo a la plataforma. Ni siquiera me refiero a los módulos del kernel, que dependen estrictamente del kernel y no encajan en el concepto de sandbox.

El segundo problema es que las distribuciones populares en el entorno empresarial de Red Hat y SUSE aún no contienen soporte para Snappy y Flatpak.

En este sentido, Veeam Agent para Linux no está disponible snapcraft.io de nada flathub.org.

Para concluir la pregunta sobre los administradores de paquetes, me gustaría señalar que existe una opción para abandonar los administradores de paquetes por completo combinando archivos binarios y un script para instalarlos en un solo paquete.

Dicho paquete le permite crear un paquete común para diferentes distribuciones y plataformas, realizar un proceso de instalación interactivo y realizar la personalización necesaria. Solo encontré paquetes de este tipo para Linux de VMware.

Problema de actualización

Linux tiene muchas caras: cómo funcionar en cualquier distribución
Incluso si se resuelven todos los problemas de dependencia, el programa puede ejecutarse de manera diferente en la misma distribución. Es cuestión de actualizaciones.

Hay 3 estrategias de actualización:

  • La más sencilla es no actualizar nunca. Configuré el servidor y lo olvidé. ¿Por qué actualizar si todo funciona? Los problemas comienzan la primera vez que contacta al soporte. El creador de la distribución solo admite la versión actualizada.
  • Puede confiar en el distribuidor y configurar actualizaciones automáticas. En este caso, es probable que se realice una llamada al soporte inmediatamente después de una actualización fallida.
  • La opción de actualización manual solo después de ejecutarla en una infraestructura de prueba es la más confiable, pero costosa y requiere mucho tiempo. No todo el mundo puede permitírselo.

Dado que diferentes usuarios utilizan diferentes estrategias de actualización, es necesario admitir tanto la última versión como todas las publicadas anteriormente. Esto complica tanto el proceso de desarrollo como el de prueba y añade dolores de cabeza al equipo de soporte.

Variedad de plataformas de hardware.

Las diferentes plataformas de hardware son un problema que es en gran medida específico del código nativo. Como mínimo, debes recopilar archivos binarios para cada plataforma compatible.

En el proyecto Veeam Agent para Linux, todavía no podemos admitir nada como este RISC.

No me detendré en este tema en detalle. Sólo describiré los principales problemas: tipos que dependen de la plataforma, como size_t, alineación de estructura y orden de bytes.

Vinculación estática y/o dinámica

Linux tiene muchas caras: cómo funcionar en cualquier distribución
Pero la pregunta es "¿Cómo vincularse con bibliotecas, de forma dinámica o estática?" vale la pena discutirlo.

Como regla general, las aplicaciones C/C++ en Linux utilizan enlaces dinámicos. Esto funciona muy bien si la aplicación está creada específicamente para una distribución específica.

Si la tarea es cubrir varias distribuciones con un archivo binario, entonces debe centrarse en la distribución compatible más antigua. Para nosotros, esto es Red Hat 6. Contiene gcc 4.4, que ni siquiera el estándar C++ 11 es compatible. completamente.

Construimos nuestro proyecto usando gcc 6.3, que es totalmente compatible con C++14. Naturalmente, en este caso, en Red Hat 6 debe llevar consigo las bibliotecas libstdc++ y boost. La forma más sencilla es vincularlos estáticamente.

Pero, lamentablemente, no todas las bibliotecas se pueden vincular estáticamente.

En primer lugar, las bibliotecas del sistema como libfusible, libblkid es necesario vincularlos dinámicamente para asegurar su compatibilidad con el kernel y sus módulos.

En segundo lugar, hay una sutileza con las licencias.

La licencia GPL básicamente le permite vincular bibliotecas sólo con código abierto. MIT y BSD permiten enlaces estáticos y permiten incluir bibliotecas en un proyecto. Pero la LGPL no parece contradecir la vinculación estática, sino que exige que se compartan los archivos necesarios para la vinculación.

En general, el uso de enlaces dinámicos evitará que tengas que proporcionar nada.

Creación de aplicaciones C/C++

Para crear aplicaciones C/C++ para diferentes plataformas y distribuciones, basta con seleccionar o crear una versión adecuada de gcc y utilizar compiladores cruzados para arquitecturas específicas y ensamblar el conjunto completo de bibliotecas. Este trabajo es bastante factible, pero bastante problemático. Y no hay garantía de que el compilador y las bibliotecas seleccionados proporcionen una versión viable.

Una ventaja obvia: la infraestructura se simplifica enormemente, ya que todo el proceso de construcción se puede completar en una sola máquina. Además, basta con recopilar un conjunto de binarios para una arquitectura y puede empaquetarlos en paquetes para diferentes distribuciones. Así es como se crean los paquetes de Veeam para Veeam Agent para Linux.

A diferencia de esta opción, simplemente puede preparar una granja de construcción, es decir, varias máquinas para el montaje. Cada una de estas máquinas proporcionará compilación de aplicaciones y ensamblaje de paquetes para una distribución específica y una arquitectura específica. En este caso, la recopilación se realiza mediante los medios preparados por el distribuidor. Es decir, se elimina la etapa de preparación del compilador y selección de bibliotecas. Además, el proceso de construcción se puede paralelizar fácilmente.

Sin embargo, este enfoque tiene una desventaja: para cada distribución dentro de la misma arquitectura, tendrá que recopilar su propio conjunto de archivos binarios. Otra desventaja es que es necesario mantener una gran cantidad de máquinas y asignar una gran cantidad de espacio en disco y RAM.

Así es como se compilan los paquetes KMOD del módulo del kernel veeamsnap para las distribuciones de Red Hat.

Servicio de compilación abierta

Los colegas de SUSE intentaron implementar un término medio en forma de un servicio especial para compilar aplicaciones y ensamblar paquetes. servicio de construcción abierta.

Esencialmente, es un hipervisor que crea una máquina virtual, instala todos los paquetes necesarios en ella, compila la aplicación y construye el paquete en este entorno aislado, después de lo cual se libera la máquina virtual.

Linux tiene muchas caras: cómo funcionar en cualquier distribución

El programador implementado en OpenBuildService determinará cuántas máquinas virtuales puede iniciar para lograr una velocidad óptima de creación de paquetes. El mecanismo de firma integrado firmará los paquetes y los cargará en el repositorio integrado. El sistema de control de versiones incorporado guardará el historial de cambios y compilaciones. Todo lo que queda es simplemente agregar sus fuentes a este sistema. Ni siquiera tienes que configurar el servidor tú mismo; puedes usar uno abierto.

Sin embargo, existe un problema: es difícil adaptar una cosechadora de este tipo a la infraestructura existente. Por ejemplo, el control de versiones no es necesario; ya tenemos el nuestro propio para los códigos fuente. Nuestro mecanismo de firma es diferente: utilizamos un servidor especial. Tampoco se necesita un repositorio.

Además, el soporte para otras distribuciones, por ejemplo Red Hat, está bastante mal implementado, lo cual es comprensible.

La ventaja de este servicio es la compatibilidad rápida con la próxima versión de la distribución SUSE. Antes del anuncio oficial del lanzamiento, los paquetes necesarios para el montaje se publican en un repositorio público. Aparece una nueva en la lista de distribuciones disponibles en OpenBuildService. Marcamos la casilla y se agrega al plan de construcción. Así, agregar una nueva versión de la distribución se realiza casi con un clic.

En nuestra infraestructura, utilizando OpenBuildService, se ensambla toda la variedad de paquetes KMP del módulo del kernel veeamsnap para distribuciones SUSE.

A continuación, me gustaría detenerme en cuestiones específicas de los módulos del kernel.

ABI del núcleo

Históricamente, los módulos del kernel de Linux se han distribuido en formato fuente. El hecho es que los creadores del kernel no se cargan con la preocupación de soportar una API estable para los módulos del kernel, y especialmente a nivel binario, denominado en adelante kABI.

Para construir un módulo para un kernel básico, definitivamente necesita los encabezados de este kernel en particular, y solo funcionará en este kernel.

DKMS le permite automatizar el proceso de creación de módulos al actualizar el kernel. Como resultado, los usuarios del repositorio de Debian (y sus muchos parientes) usan módulos del kernel ya sea del repositorio del distribuidor o compilados desde el código fuente usando DKMS.

Sin embargo, esta situación no conviene especialmente al segmento Enterprise. Los distribuidores de código propietario quieren distribuir el producto como binarios compilados.

Los administradores no quieren mantener las herramientas de desarrollo en los servidores de producción por razones de seguridad. Los distribuidores empresariales de Linux, como Red Hat y SUSE, decidieron que podían admitir kABI estable para sus usuarios. El resultado fueron paquetes KMOD para Red Hat y paquetes KMP para SUSE.

La esencia de esta solución es bastante simple. Para una versión específica de la distribución, la API del kernel está congelada. El distribuidor afirma que usa el kernel, por ejemplo 3.10, y solo hace correcciones y mejoras que no afectan las interfaces del kernel, y los módulos recopilados para el primer kernel se pueden usar para todos los siguientes sin necesidad de volver a compilarlos.

Red Hat afirma que la distribución es compatible con kABI durante todo su ciclo de vida. Es decir, el módulo ensamblado para rhel 6.0 (lanzamiento de noviembre de 2010) también debería funcionar en la versión 6.10 (lanzamiento de junio de 2018). Y esto son casi 8 años. Naturalmente, esta tarea es bastante difícil.
Hemos registrado varios casos en los que el módulo veeamsnap dejó de funcionar debido a problemas de compatibilidad con kABI.

Después de que el módulo veeamsnap, compilado para RHEL 7.0, resultó ser incompatible con el kernel de RHEL 7.5, pero se cargó y se garantizaba que colapsaría el servidor, abandonamos por completo el uso de la compatibilidad kABI para RHEL 7.

Actualmente, el paquete KMOD para RHEL 7 contiene un ensamblado para cada versión y un script que carga el módulo.

SUSE abordó la tarea de compatibilidad kABI con más cuidado. Proporcionan compatibilidad con kABI solo dentro de un paquete de servicio.

Por ejemplo, el lanzamiento de SLES 12 tuvo lugar en septiembre de 2014. Y SLES 12 SP1 ya fue en diciembre de 2015, es decir, ha pasado poco más de un año. Aunque ambas versiones utilizan el kernel 3.12, son incompatibles con kABI. Evidentemente, mantener la compatibilidad con kABI durante tan solo un año es mucho más sencillo. El ciclo anual de actualización del módulo del kernel no debería causar problemas a los creadores de módulos.

Como resultado de esta política de SUSE, no hemos registrado ni un solo problema con la compatibilidad de kABI en nuestro módulo veeamsnap. Es cierto que la cantidad de paquetes para SUSE es casi un orden de magnitud mayor.

Parches y backports

Aunque los distribuidores intentan garantizar la compatibilidad con kABI y la estabilidad del kernel, también intentan mejorar el rendimiento y eliminar los defectos de este kernel estable.

Al mismo tiempo, además de su propio "trabajo sobre errores", los desarrolladores del kernel empresarial de Linux monitorean los cambios en el kernel básico y los transfieren a su kernel "estable".

A veces esto lleva a otros nuevos. errores.

En la última versión de Red Hat 6, se cometió un error en una de las actualizaciones menores. Esto llevó al hecho de que se garantizaba que el módulo veeamsnap bloquearía el sistema cuando se publicara la instantánea. Después de comparar las fuentes del kernel antes y después de la actualización, descubrimos que el backport era el culpable. Se realizó una solución similar en la versión 4.19 del kernel básico. Es solo que esta solución funcionó bien en el kernel de vainilla, pero al transferirlo al "estable" 2.6.32, surgió un problema con el spinlock.

Por supuesto, todo el mundo siempre tiene errores, pero ¿valió la pena arrastrar el código de 4.19 a 2.6.32, arriesgando la estabilidad?... No estoy seguro...

Lo peor es cuando el marketing se ve envuelto en el tira y afloja entre “estabilidad” y “modernización”. El departamento de marketing necesita que el núcleo de la distribución actualizada sea estable, por un lado, y al mismo tiempo tenga mejor rendimiento y tenga nuevas características. Esto lleva a extraños compromisos.

Cuando intenté crear un módulo en el kernel 4.4 desde SLES 12 SP3, me sorprendió encontrar funcionalidad de Vanilla 4.8 en él. En mi opinión, la implementación de E/S en bloque del kernel 4.4 de SLES 12 SP3 es más similar al kernel 4.8 que a la versión anterior del kernel estable 4.4 de SLES12 SP2. No puedo juzgar qué porcentaje de código se transfirió del kernel 4.8 a SLES 4.4 para SP3, pero ni siquiera puedo llamar al kernel el mismo 4.4 estable.

Lo más desagradable de esto es que al escribir un módulo que funcionaría igualmente bien en diferentes núcleos, ya no se puede confiar en la versión del núcleo. También hay que tener en cuenta la distribución. Es bueno que a veces puedas involucrarte en una definición que aparece junto con una nueva funcionalidad, pero esta oportunidad no siempre aparece.

Como resultado, el código se llena de extrañas directivas de compilación condicional.

También hay parches que cambian la API del kernel documentada.
me encontré con la distribución KDE neón 5.16 y me sorprendió mucho ver que la llamada lookup_bdev en esta versión del kernel cambió la lista de parámetros de entrada.

Para armarlo, tuve que agregar un script al archivo MAKE que verifica si la función lookup_bdev tiene un parámetro de máscara.

Firmar módulos del kernel

Pero volvamos al tema de la distribución de paquetes.

Una de las ventajas de kABI estable es que los módulos del kernel se pueden firmar como un archivo binario. En este caso, el desarrollador puede estar seguro de que el módulo no ha sido dañado accidentalmente ni modificado intencionalmente. Puedes comprobar esto con el comando modinfo.

Las distribuciones de Red Hat y SUSE le permiten verificar la firma del módulo y cargarlo solo si el certificado correspondiente está registrado en el sistema. El certificado es la clave pública con la que se firma el módulo. Lo distribuimos como un paquete separado.

El problema aquí es que los certificados pueden integrarse en el kernel (los distribuidores los usan) o deben escribirse en la memoria no volátil EFI mediante una utilidad. mokutil. Utilidad mokutil Al instalar un certificado, es necesario reiniciar el sistema e, incluso antes de cargar el kernel del sistema operativo, solicita al administrador que permita la carga de un nuevo certificado.

Por lo tanto, agregar un certificado requiere acceso físico de administrador al sistema. Si la máquina está ubicada en algún lugar de la nube o simplemente en una sala de servidores remota y el acceso se realiza solo a través de la red (por ejemplo, a través de ssh), será imposible agregar un certificado.

EFI en máquinas virtuales

A pesar de que EFI ha sido compatible durante mucho tiempo con casi todos los fabricantes de placas base, al instalar un sistema, es posible que el administrador no piense en la necesidad de EFI y que esté deshabilitado.

No todos los hipervisores admiten EFI. VMWare vSphere admite EFI a partir de la versión 5.
Microsoft Hyper-V también obtuvo soporte EFI a partir de Hyper-V para Windows Server 2012R2.

Sin embargo, en la configuración predeterminada esta funcionalidad está deshabilitada para máquinas Linux, lo que significa que no se puede instalar el certificado.

En vSphere 6.5, configure la opción Comienza segura sólo es posible en la versión antigua de la interfaz web, que se ejecuta a través de Flash. La interfaz de usuario web en HTML-5 todavía está muy por detrás.

Distribuciones experimentales

Y finalmente, consideremos la cuestión de las distribuciones experimentales y las distribuciones sin soporte oficial. Por un lado, es poco probable que se encuentren distribuciones de este tipo en los servidores de organizaciones serias. No existe soporte oficial para este tipo de distribuciones. Por lo tanto, proporcione esos. El producto no puede ser compatible con dicha distribución.

Sin embargo, estas distribuciones se convierten en una plataforma conveniente para probar nuevas soluciones experimentales. Por ejemplo, Fedora, OpenSUSE Tumbleweed o versiones inestables de Debian. Son bastante estables. Siempre tienen nuevas versiones de programas y siempre un nuevo kernel. En un año, esta funcionalidad experimental puede terminar en un RHEL, SLES o Ubuntu actualizado.

Entonces, si algo no funciona en una distribución experimental, esta es una razón para descubrir el problema y resolverlo. Debe estar preparado para el hecho de que esta funcionalidad pronto aparecerá en los servidores de producción de los usuarios.

Puede estudiar la lista actual de distribuciones compatibles oficialmente para la versión 3.0. aquí. Pero la lista real de distribuciones en las que nuestro producto puede funcionar es mucho más amplia.

Personalmente, me interesó el experimento con el sistema operativo Elbrus. Después de finalizar el paquete veeam, nuestro producto quedó instalado y funcionando. Escribí sobre este experimento en Habré en статье.

Bueno, el soporte para nuevas distribuciones continúa. Estamos esperando que se lance la versión 4.0. Beta está a punto de aparecer, así que mantente atento qué hay de nuevo!

Fuente: habr.com

Añadir un comentario