Linux ten moitas caras: como traballar en calquera distribución

Linux ten moitas caras: como traballar en calquera distribución

Crear unha aplicación de copia de seguridade que funcione en calquera distribución non é tarefa sinxela. Para garantir que o Veeam Agent for Linux funcione en distribucións desde Red Hat 6 e Debian 6, ata OpenSUSE 15.1 e Ubuntu 19.04, tes que resolver unha serie de problemas, especialmente tendo en conta que o produto de software inclúe un módulo do núcleo.

O artigo foi creado a partir de materiais dun discurso na conferencia Linux Peter 2019.

Linux non é só un dos sistemas operativos máis populares. Esencialmente, esta é unha plataforma sobre a base da cal podes facer algo único, algo propio. Grazas a isto, Linux ten moitas distribucións que se diferencian no seu conxunto de compoñentes de software. E aquí xorde un problema: para que un produto de software funcione en calquera distribución, hai que ter en conta as características de cada unha.

Xestores de paquetes. .deb vs .rpm

Comecemos co problema obvio de distribuír o produto en diferentes distribucións.
A forma máis típica de distribuír produtos de software é colocar o paquete nun repositorio para que o xestor de paquetes integrado no sistema poida instalalo desde alí.
Non obstante, temos dous formatos de paquete populares: rpm и deb. Isto significa que todos terán que apoiar.

No mundo dos paquetes deb, o nivel de compatibilidade é incrible. O mesmo paquete instálase e funciona igual de ben tanto en Debian 6 como en Ubuntu 19.04. Os estándares para o proceso de construción de paquetes e traballo con eles, establecidos nas antigas distribucións de Debian, seguen sendo relevantes no novo Linux Mint e no SO elemental. Polo tanto, no caso de Veeam Agent para Linux, é suficiente un paquete deb para cada plataforma de hardware.

Pero no mundo dos paquetes rpm, as diferenzas son grandes. En primeiro lugar, debido a que hai dous distribuidores completamente independentes, Red Hat e SUSE, para os que a compatibilidade é completamente innecesaria. En segundo lugar, estes distribuidores teñen kits de distribución daqueles. apoio e experimental. Tampouco hai necesidade de compatibilidade entre eles. Resultou que el6, el7 e el8 teñen os seus propios paquetes. Paquete separado para Fedora. Paquetes para SLES11 e 12 e outro separado para openSUSE. O principal problema son as dependencias e os nomes dos paquetes.

Problema de dependencia

Desafortunadamente, os mesmos paquetes a miúdo acaban con nomes diferentes en distribucións diferentes. A continuación móstrase unha lista parcial das dependencias do paquete veeam.

Para EL7:
Para SLES 12:

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

Como resultado, a lista de dependencias é única para a distribución.

O que empeora é cando unha versión actualizada comeza a ocultarse baixo o antigo nome do paquete.

Exemplo:

O paquete foi actualizado en Fedora 24 ncurses da versión 5 á versión 6. O noso produto foi construído coa versión 5 para garantir a compatibilidade con distribucións máis antigas. Para usar a 5ª versión antiga da biblioteca en Fedora 24, tiven que usar o paquete ncurses-compat-libs.

Como resultado, hai dous paquetes para Fedora, con diferentes dependencias.

Ademais máis interesante. Despois da próxima actualización de distribución, o paquete ncurses-compat-libs coa versión 5 da biblioteca resulta que non está dispoñible. É caro para un distribuidor arrastrar bibliotecas antigas a unha nova versión da distribución. Despois dun tempo, o problema repetiuse nas distribucións SUSE.

Como resultado, algunhas distribucións tiveron que abandonar a súa dependencia explícita ncurses-libs, e corrixe o produto para que poida funcionar con calquera versión da biblioteca.

Por certo, na versión 8 de Red Hat xa non hai un metapaquete python, que se refería ao bo vello pitón 2.7. Ahí está python2 и python3.

Alternativa aos xestores de paquetes

O problema das dependencias é antigo e hai tempo que é obvio. Só lembra o inferno da dependencia.
Combinar varias bibliotecas e aplicacións para que todas funcionen de forma estable e non entren en conflito - de feito, esta é a tarefa que calquera distribuidor de Linux tenta resolver.

O xestor de paquetes tenta resolver este problema dunha forma completamente diferente. Mal humor de Canonical. A idea principal: a aplicación execútase nun sandbox illado e protexido do sistema principal. Se unha aplicación precisa de bibliotecas, estas son subministradas coa propia aplicación.

Flatpak tamén che permite executar aplicacións nun sandbox mediante Linux Containers. Tamén se utiliza a idea de sandbox AppImage.

Estas solucións permítenche crear un paquete para calquera distribución. En caso de Flatpak a instalación e o lanzamento da aplicación é posible aínda sen o coñecemento do administrador.

O principal problema é que non todas as aplicacións poden executarse nun sandbox. Algunhas persoas necesitan acceso directo á plataforma. Nin sequera estou a falar de módulos do núcleo, que dependen estritamente do núcleo e non encaixan no concepto de sandbox.

O segundo problema é que as distribucións populares no entorno empresarial de Red Hat e SUSE aínda non teñen soporte para Snappy e Flatpak.

Neste sentido, o axente de Veeam para Linux non está dispoñible snapcraft.io non encendido flathub.org.

Para concluír a pregunta sobre os xestores de paquetes, gustaríame sinalar que hai unha opción para abandonar os xestores de paquetes por completo combinando ficheiros binarios e un script para instalalos nun paquete.

Tal paquete permítelle crear un paquete común para diferentes distribucións e plataformas, realizar un proceso de instalación interactivo, realizando a personalización necesaria. Só atopei paquetes deste tipo para Linux de VMware.

Problema de actualización

Linux ten moitas caras: como traballar en calquera distribución
Aínda que se resolvan todos os problemas de dependencia, o programa pode executarse de forma diferente na mesma distribución. É cuestión de actualizacións.

Hai 3 estratexias de actualización:

  • O máis sinxelo é non actualizar nunca. Configurei o servidor e esquecinme. Por que actualizar se todo funciona? Os problemas comezan a primeira vez que contactas co servizo de asistencia. O creador da distribución só admite a versión actualizada.
  • Podes confiar no distribuidor e configurar actualizacións automáticas. Neste caso, é probable unha chamada ao soporte inmediatamente despois dunha actualización sen éxito.
  • A opción de actualizar manualmente só despois de executalo nunha infraestrutura de proba é a máis fiable, pero cara e lenta. Non todos poden permitilo.

Dado que diferentes usuarios usan estratexias de actualización diferentes, é necesario admitir tanto a versión máis recente como todas as publicadas anteriormente. Isto complica tanto o proceso de desenvolvemento como de proba e engade dores de cabeza ao equipo de soporte.

Variedade de plataformas de hardware

As diferentes plataformas de hardware son un problema que é en gran parte específico do código nativo. Como mínimo, tes que recoller binarios para cada plataforma compatible.

No proxecto Veeam Agent for Linux, aínda non podemos admitir nada como este RISC.

Non vou determe neste tema en detalle. Só vou esbozar os principais problemas: tipos dependentes da plataforma, como size_t, aliñamento da estrutura e orde de bytes.

Vinculación estática e/ou dinámica

Linux ten moitas caras: como traballar en calquera distribución
Pero a pregunta é "Como conectar coas bibliotecas, de forma dinámica ou estática?" paga a pena discutir.

Como regra xeral, as aplicacións C/C++ en Linux usan ligazóns dinámicas. Isto funciona moi ben se a aplicación está construída específicamente para unha distribución específica.

Se a tarefa é cubrir varias distribucións cun ficheiro binario, entón tes que centrarte na distribución compatible máis antiga. Para nós, este é Red Hat 6. Contén gcc 4.4, que nin sequera o estándar C++ 11 é compatible. totalmente.

Construímos o noso proxecto usando gcc 6.3, que admite totalmente C++14. Por suposto, neste caso, en Red Hat 6 tes que levar o libstdc++ e aumentar as bibliotecas contigo. O xeito máis sinxelo é vinculalos de forma estática.

Pero, por desgraza, non todas as bibliotecas se poden ligar de forma estática.

En primeiro lugar, as bibliotecas do sistema como libfuse, libblkid é necesario enlazar de forma dinámica para garantir a súa compatibilidade co núcleo e os seus módulos.

En segundo lugar, hai unha sutileza coas licenzas.

A licenza GPL permíteche basicamente vincular bibliotecas só con código opensource. MIT e BSD permiten ligazóns estáticas e permiten incluír bibliotecas nun proxecto. Pero a LGPL non parece contradicir a ligazón estática, senón que esixe que se compartan os ficheiros necesarios para a vinculación.

En xeral, usar ligazóns dinámicas evitará que teñas que proporcionar nada.

Creación de aplicacións C/C++

Para construír aplicacións C/C++ para diferentes plataformas e distribucións, abonda con seleccionar ou construír unha versión adecuada de gcc e usar compiladores cruzados para arquitecturas específicas e montar todo o conxunto de bibliotecas. Este traballo é bastante factible, pero bastante problemático. E non hai garantía de que o compilador e as bibliotecas seleccionados ofrezan unha versión viable.

Unha vantaxe obvia: a infraestrutura simplifícase moito, xa que todo o proceso de construción pódese completar nunha única máquina. Ademais, abonda con recoller un conxunto de binarios para unha arquitectura e pode empaquetalos en paquetes para diferentes distribucións. Así se crean os paquetes veeam para Veeam Agent para Linux.

A diferenza desta opción, pode simplemente preparar unha granxa de construción, é dicir, varias máquinas para a montaxe. Cada máquina deste tipo proporcionará compilación de aplicacións e montaxe de paquetes para unha distribución específica e unha arquitectura específica. Neste caso, a compilación realízase mediante os medios elaborados polo distribuidor. É dicir, elimínase a fase de preparación do compilador e selección de bibliotecas. Ademais, o proceso de construción pódese paralelizar facilmente.

Non obstante, este enfoque ten unha desvantaxe: para cada distribución dentro da mesma arquitectura, terás que recoller o teu propio conxunto de ficheiros binarios. Outra desvantaxe é que hai que manter un número tan grande de máquinas e asignar unha gran cantidade de espazo en disco e RAM.

Así é como se compilan os paquetes KMOD do módulo do núcleo veeamsnap para as distribucións de Red Hat.

Servizo de construción aberta

Os compañeiros de SUSE intentaron implementar un punto intermedio en forma de servizo especial para compilar aplicacións e montar paquetes. servizo openbuild.

Esencialmente, é un hipervisor que crea unha máquina virtual, instala nela todos os paquetes necesarios, compila a aplicación e constrúe o paquete neste ambiente illado, despois de que se libera a máquina virtual.

Linux ten moitas caras: como traballar en calquera distribución

O programador implementado en OpenBuildService determinará cantas máquinas virtuais pode lanzar para unha velocidade óptima de construción de paquetes. O mecanismo de sinatura integrado asinará os paquetes e cargaraos no repositorio integrado. O sistema de control de versións incorporado gardará o historial de cambios e compilacións. Só queda engadir as túas fontes a este sistema. Nin sequera tes que configurar o servidor ti mesmo; podes usar un aberto.

Non obstante, hai un problema: unha colleitadora deste tipo é difícil de encaixar na infraestrutura existente. Por exemplo, o control de versións non é necesario; xa temos o noso propio para os códigos fonte. O noso mecanismo de sinatura é diferente: usamos un servidor especial. Tampouco é necesario un repositorio.

Ademais, o soporte para outras distribucións, por exemplo, Red Hat, está implementado bastante mal, o que é comprensible.

A vantaxe deste servizo é o soporte rápido para a próxima versión da distribución SUSE. Antes do anuncio oficial do lanzamento, os paquetes necesarios para a montaxe publícanse nun repositorio público. Aparece unha nova na lista de distribucións dispoñibles en OpenBuildService. Marcamos a caixa e engádese ao plan de construción. Así, engadir unha nova versión da distribución realízase en case un clic.

Na nosa infraestrutura, mediante OpenBuildService, ensambla toda a variedade de paquetes KMP do módulo do núcleo veeamsnap para distribucións SUSE.

A continuación, gustaríame determe en cuestións específicas dos módulos do núcleo.

núcleo ABI

Os módulos do núcleo de Linux distribuíronse historicamente en forma de orixe. O feito é que os creadores do núcleo non se cargan coa preocupación de apoiar unha API estable para os módulos do núcleo, e especialmente a nivel binario, máis coñecido como kABI.

Para construír un módulo para un núcleo de vainilla, definitivamente necesitas as cabeceiras deste núcleo en particular, e só funcionará neste núcleo.

DKMS permítelle automatizar o proceso de construción de módulos ao actualizar o núcleo. Como resultado, os usuarios do repositorio de Debian (e os seus moitos parentes) usan módulos do núcleo xa sexa desde o repositorio do distribuidor ou ben compilados desde a fonte usando DKMS.

Non obstante, esta situación non se adapta especialmente ao segmento Enterprise. Os distribuidores de código propietario queren distribuír o produto como binarios compilados.

Os administradores non queren manter as ferramentas de desenvolvemento nos servidores de produción por razóns de seguridade. Os distribuidores de Linux Enterprise como Red Hat e SUSE decidiron que podían soportar kABI estable para os seus usuarios. O resultado foron paquetes KMOD para Red Hat e paquetes KMP para SUSE.

A esencia desta solución é bastante sinxela. Para unha versión específica da distribución, a API do núcleo está conxelada. O distribuidor afirma que usa o núcleo, por exemplo, 3.10, e só realiza correccións e melloras que non afectan ás interfaces do núcleo, e os módulos recollidos para o primeiro núcleo poden usarse para todos os seguintes sen recompilar.

Red Hat reclama a compatibilidade de kABI para a distribución durante todo o seu ciclo de vida. É dicir, o módulo ensamblado para rhel 6.0 (lanzamento en novembro de 2010) tamén debería funcionar na versión 6.10 (lanzamento en xuño de 2018). E isto son case 8 anos. Por suposto, esta tarefa é bastante difícil.
Gravamos varios casos nos que o módulo veeamsnap deixou de funcionar debido a problemas de compatibilidade con kABI.

Despois de que o módulo veeamsnap, compilado para RHEL 7.0, resultou ser incompatible co núcleo de RHEL 7.5, pero se cargou e garantiuse que fallaría o servidor, abandonamos por completo o uso da compatibilidade kABI para RHEL 7.

Actualmente, o paquete KMOD para RHEL 7 contén un conxunto para cada versión de lanzamento e un script que carga o módulo.

SUSE abordou a tarefa de compatibilidade kABI con máis coidado. Ofrecen compatibilidade kABI só dentro dun paquete de servizos.

Por exemplo, o lanzamento de SLES 12 tivo lugar en setembro de 2014. E SLES 12 SP1 xa estaba en decembro de 2015, é dicir, pasou algo máis dun ano. Aínda que ambas versións usan o núcleo 3.12, son incompatibles con kABI. Obviamente, manter a compatibilidade kABI durante só un ano é moito máis sinxelo. O ciclo anual de actualización do módulo do núcleo non debería causar problemas aos creadores de módulos.

Como resultado desta política de SUSE, non rexistramos nin un só problema coa compatibilidade de kABI no noso módulo veeamsnap. É certo que o número de paquetes para SUSE é case unha orde de magnitude maior.

Parches e backports

Aínda que os distribuidores intentan garantir a compatibilidade de kABI e a estabilidade do núcleo, tamén intentan mellorar o rendemento e eliminar os defectos deste núcleo estable.

Ao mesmo tempo, ademais do seu propio "traballar sobre erros", os desenvolvedores do kernel Linux empresarial supervisan os cambios no núcleo de vainilla e transfórmanos ao seu "estable".

Ás veces isto leva a outros novos erros.

No último lanzamento de Red Hat 6, cometeuse un erro nunha das actualizacións menores. Levou ao feito de que o módulo veeamsnap estaba garantido para fallar o sistema cando se publicou a instantánea. Despois de comparar as fontes do núcleo antes e despois da actualización, descubrimos que o backport era o culpable. Fixouse unha corrección similar na versión 4.19 do núcleo de vainilla. É só que esta corrección funcionou ben no núcleo de vainilla, pero ao transferilo ao "estable" 2.6.32, xurdiu un problema co spinlock.

Claro que todo o mundo sempre ten erros, pero valeu a pena arrastrar o código da 4.19 á 2.6.32, arriscando a estabilidade?... Non estou seguro...

O peor é cando o marketing se involucra no tira e afloxa entre a "estabilidade" e a "modernización". O departamento de márketing necesita que o núcleo da distribución actualizada sexa estable, por unha banda, e ao mesmo tempo teña mellor rendemento e teña novas funcionalidades. Isto leva a estraños compromisos.

Cando tentei construír un módulo no núcleo 4.4 de SLES 12 SP3, sorprendeume atopar a funcionalidade de vanilla 4.8 nel. Na miña opinión, a implementación de bloque de E/S do núcleo 4.4 de SLES 12 SP3 é máis semellante ao núcleo 4.8 que a versión anterior do núcleo estable 4.4 de SLES12 SP2. Non podo xulgar que porcentaxe de código foi transferido do núcleo 4.8 ao SLES 4.4 para SP3, pero nin sequera podo chamar ao núcleo o mesmo 4.4 estable.

O máis desagradable disto é que ao escribir un módulo que funcionaría igual de ben en diferentes núcleos, xa non pode confiar na versión do núcleo. Tamén hai que ter en conta a distribución. É bo que ás veces poidas involucrarte nunha definición que aparece xunto con novas funcionalidades, pero esta oportunidade non sempre aparece.

Como resultado, o código queda cuberto de estrañas directivas de compilación condicional.

Tamén hai parches que cambian a API do núcleo documentada.
Atopeime coa distribución Neon de KDE 5.16 e quedou moi sorprendido ao ver que a chamada lookup_bdev nesta versión do núcleo cambiou a lista de parámetros de entrada.

Para reunilo, tiven que engadir un script ao makefile que verifica se a función lookup_bdev ten un parámetro de máscara.

Asinando módulos do núcleo

Pero volvamos ao tema da distribución de paquetes.

Unha das vantaxes do kABI estable é que os módulos do núcleo poden asinarse como un ficheiro binario. Neste caso, o programador pode estar seguro de que o módulo non foi danado accidentalmente ou modificado intencionadamente. Podes comprobalo co comando modinfo.

As distribucións Red Hat e SUSE permítenche comprobar a sinatura do módulo e cargala só se o certificado correspondente está rexistrado no sistema. O certificado é a clave pública coa que se asina o módulo. Distribuímolo como paquete separado.

O problema aquí é que os certificados poden incorporarse no núcleo (os distribuidores utilízanos) ou deben escribirse na memoria non volátil EFI mediante unha utilidade. mokutil. Utilidade mokutil Ao instalar un certificado, esixe que reinicie o sistema e, mesmo antes de cargar o núcleo do sistema operativo, pídelle ao administrador que permita a carga dun novo certificado.

Así, engadir un certificado require acceso de administrador físico ao sistema. Se a máquina está situada nalgún lugar da nube ou simplemente nunha sala de servidores remota e o acceso só se realiza a través da rede (por exemplo, a través de ssh), entón será imposible engadir un certificado.

EFI en máquinas virtuais

A pesar de que EFI foi apoiado durante moito tempo por case todos os fabricantes de placas nai, ao instalar un sistema, o administrador pode non pensar na necesidade de EFI e pode estar desactivado.

Non todos os hipervisores admiten EFI. VMWare vSphere admite EFI a partir da versión 5.
Microsoft Hyper-V tamén obtivo soporte EFI comezando por Hyper-V para Windows Server 2012R2.

Non obstante, na configuración predeterminada esta funcionalidade está desactivada para máquinas Linux, o que significa que non se pode instalar o certificado.

En vSphere 6.5, configure a opción Bota segura só é posible na versión antiga da interface web, que se executa a través de Flash. A interface de usuario web en HTML-5 aínda está moi atrás.

Distribucións experimentais

E, finalmente, consideremos o tema das distribucións experimentais e as distribucións sen apoio oficial. Por unha banda, é improbable que este tipo de distribucións se atopen nos servidores de organizacións serias. Non hai soporte oficial para este tipo de distribucións. Polo tanto, proporciónaos. O produto non se pode admitir nesta distribución.

Non obstante, tales distribucións convértense nunha plataforma conveniente para probar novas solucións experimentais. Por exemplo, Fedora, OpenSUSE Tumbleweed ou versións Unstable de Debian. Son bastante estables. Sempre teñen novas versións dos programas e sempre un novo núcleo. Nun ano, esta funcionalidade experimental pode acabar nun RHEL, SLES ou Ubuntu actualizado.

Polo tanto, se algo non funciona nunha distribución experimental, esta é unha razón para descubrir o problema e resolvelo. Debes estar preparado para o feito de que esta funcionalidade aparecerá pronto nos servidores de produción dos usuarios.

Podes estudar a lista actual de distribucións admitidas oficialmente para a versión 3.0 aquí. Pero a lista real de distribucións nas que pode funcionar o noso produto é moito máis ampla.

Persoalmente, interesoume o experimento co sistema operativo Elbrus. Despois de finalizar o paquete veeam, o noso produto instalouse e funcionou. Escribín sobre este experimento en Habré en Artigo.

Ben, o soporte para novas distribucións continúa. Estamos á espera de que se publique a versión 4.0. A beta está a piques de aparecer, así que estea atento Que hai de novo!

Fonte: www.habr.com

Engadir un comentario