Linux Embedded

Le blog des technologies libres et embarquées

Introduction au 📦 paquetage pour Debian

Pourquoi générer des paquets ?


Il existe de très nombreux moyens de distribuer du logiciel. L’un de ces moyens s’appelle le paquet. Il s’agit d'un fichier archive contenant tout le nécessaire pour installer et désinstaller un logiciel et dont le format a été prédéfini pour pouvoir être utilisé simplement à l’aide d’outils dédiés.

Les paquets (et leurs mécanismes) sont un outil intéressant, car :

  • Ils peuvent s’intégrer proprement dans l’existant
  • Ils sont faciles à utiliser, même pour un utilisateur non expert. 
  • Il est possible de gérer tout leur cycle de vie facilement : installation, désinstallation, mise à jour.

Ils ont néanmoins quelques défauts : 

  • Conçus pour s’intégrer dans le système, ils ne sont pas réfléchis pour être isolés du reste de l’environnement, contrairement à des formats tels que Flatpak/Snap. 
  • Ils sont liés de façon forte à une distribution Gnu/Linux sur une version donnée. 
  • Ils ne sont, par défaut, pas conçus pour gérer des configurations spécifiques de logiciel, contrairement aux logiciels de gestion de configuration tels qu’Ansible. Ils seront donc utilisés de préférence pour la gestion de logiciels dans leur configuration "de base".

Bref, les paquets de distribution Gnu/Linux sont un compromis intéressant pour distribuer du logiciel.

Les paquets dans Debian

Dans la suite de l’article, nous allons nous intéresser spécifiquement au paquet de la distribution Gnu/Linux Debian, mais il existe d'autres formats pour d’autres systèmes tels que le format .rpm

Sous Debian, les paquets sont la méthode recommandée pour installer du logiciel. Les dépôts officiels Debian permettent d’installer des logiciels avec une relative confiance sur leur contenu, c’est donc un choix logique pour distribuer du logiciel pour un système Debian.

La suite de l’article s’intéressera à la création de paquet Debian et à leur organisation, mais ne traitera pas de leur utilisation en tant qu’utilisateur. De nombreuses documentations sur le gestionnaire apt et autres interfaces de gestion des paquets existent : par exemple ici.

Petit tour des outils possibles

Si vous vous intéressez au paquetage Debian pour la première fois, vous avez peut-être remarqué qu’il n’est pas forcément aisé de trouver des informations pour créer votre propre paquet Debian. Une des raisons à cela est que les paquets Debian sont assez anciens, ainsi le format général actuel des paquets reste globalement le même depuis la version 0.93 de Debian, soit depuis 1995 !

Depuis tout ce temps, beaucoup de choses ont changé dans la façon d’aborder les paquets et divers outils ont ainsi été créés par-dessus la structure de base pour rendre la gestion plus gérable dans divers cas.

Certains outils de paquetage peuvent parfois être complètement indépendants des outils de développement standard et d’autres complètement intégrés (exemple : CPack permet de générer des paquets depuis CMake) !

Pour bien débuter, il faut donc comprendre certaines choses : 

  • Il faut d’abord bien séparer la spécification d’un paquet, ce qu’elle nous autorise à faire, et les différents outils de génération de paquets, qui se greffent par-dessus.
  •  Ensuite, il est utile de savoir quels outils utiliser et où trouver la documentation pour ce faire.

Il existe différentes routes pour générer un paquet : 

  • À la “main”, à partir de la spécification. Je ne conseille pas, sauf pour apprendre. 
  • À l’aide des outils Debian recommandés pour générer des paquets conforme Debian1, notamment : 
    • debmake: un outil bien pratique pour créer des paquets source à partir de code source. 
    • dh: un mécanisme pour simplifier la génération de paquet compatible et pleinement fonctionnel en peu de code. Les paquets source générés par debmake utilisent dh. 
    • debuild, sbuild ou encore debspawn : des outils pour générer à proprement parler le paquet binaire.
    •  git-buildpackage: une surcouche pour aider à la gestion des paquets Debian dans des dépôts git. Il est commun que les paquets officiels sur salsa.debian.org utilisent ce mécanisme. 
    • lintian: un outil pour valider la conformité du paquet vis-à-vis des règles Debian.
  •  Avec des outils tiers : Ces outils peuvent paraître plus simples à utiliser que les outils officiels, mais ne sont pas conçus pour répondre aux exigences spécifiques d’un paquet Debian officiel, ce qui peut rendre leur utilisation finalement plus compliquée. 
    • CPack (CMake), FPM … : outils ayant pour but de générer des vrais paquets de logiciel. Vous aurez probablement à utiliser l’un de ces outils si la conformité Debian n’est pas nécessaire. 
    • equivs: très simple, plutôt pour générer des méta-paquets (Vu dans la suite de l’article). 
    • CheckInstall: outils pour remplacer “make install” et pouvoir plus facilement désinstaller un binaire compilé localement via le gestionnaire de paquet. 
  • Il existe certains outils anciennement officiels qui sont maintenant dépréciés tels que CDBS (une alternative à dh), je ne les conseille pas. De moins en moins de paquets les utilisent.
  • Enfin, pour terminer, il existe un petit nouveau : debputy, qui tente de simplifier la création de paquet conforme Debian. Il est encore trop tôt pour savoir s’il arrivera à remplacer les outils actuels tels que dh.

Introspection d’un paquet binaire

Peu importe l’outil que vous utiliserez pour générer votre paquet binaire, il respectera toujours une organisation bien spécifique.

Quels éléments composent un paquet Debian et à quoi servent-ils ?

Un paquet Debian binaire2 est avant tout une archive d'extension .deb qui contient :

  • un fichier texte debian-binary contenant la version du format, à ce jour 2.0.
  • une archive compressée control. Elle contient des métadonnées pour le paquet.
  • une archive compressée data. Elle contient les fichiers à installer.

Un point utile à savoir est que la méthode de compression d’un paquet Debian peut varier. Ainsi, si la méthode standard est gzip (ce qui donne les archives control.tar.gz et data.tar.gz ), il est tout à fait possible d’avoir d’autres types de compression.

Archive Data

L’archive data contient les fichiers et dossiers à installer à partir de la racine du système. Elle contient aussi l’information sur les permissions des fichiers3.

Exemple avec nginx_1.22.1-9_amd64 :

data.tar.gz
└── usr
    ├── sbin
    │   └── nginx
    └── share
        ├── doc
        │   └── nginx
        │       ├── changelog.Debian.gz
        │       ├── changelog.gz
        │       └── copyright
        └── man
            └── man8
                └── nginx.8.gz

Archive Control

L’archive control contient toutes les métadonnées nécessaires au paquet.

Exemple avec nginx_1.22.1-9_amd64 :

control.tar.gz
├── control
├── postinst
├── prerm
├── md5sums
└── triggers

Fichier control

Le fichier le plus important est control, il contient les métadonnées les plus générales : 

  • nom du paquet: Packages 
  • version: Version 
  • architecture: Architecture 
  • description: Description 

Mais aussi des informations très importantes sur les dépendances de paquets : 

  • dépendances du paquet : Depends (apt ira les installer avec le paquet). 
  • paquets incompatibles : Breaks(apt proposera de les désinstaller ou refusera l’installation selon le cas). 
  • paquets virtuels fournis : Provides (mécanisme pour fournir un même service avec plusieurs paquets différents).
  •  …

Exemple avec nginx_1.22.1-9_amd64 :

Package: nginx
Version: 1.22.1-9
Architecture: amd64
Maintainer: Debian Nginx Maintainers <pkg-nginx-maintainers@alioth-lists.debian.net>
Installed-Size: 1330
Depends: libc6 (>= 2.34), libcrypt1 (>= 1:4.1.0), libpcre2-8-0 (>= 10.22), libssl3 (>= 3.0.0), zlib1g (>= 1:1.1.4), iproute2, nginx-common (<< 1.22.1-9.1~), nginx-common (>= 1.22.1-9)
Breaks: nginx-core (<< 1.22.1-6~), nginx-extras (<< 1.22.1-6~), nginx-light (<< 1.22.1-6~)
Replaces: nginx-core (<< 1.22.1-6~), nginx-extras (<< 1.22.1-6~), nginx-light (<< 1.22.1-6~)
Provides: httpd, httpd-cgi, nginx-abi-1.22.1-7
Section: httpd
Priority: optional
Homepage: https://nginx.org
Description: small, powerful, scalable web/proxy server
 Nginx ("engine X") is a high-performance web and reverse proxy server
 created by Igor Sysoev. It can be used both as a standalone web server
 and as a proxy to reduce the load on back-end HTTP or mail servers.

Le chapitre 7 du manuel Debian et le Debian policy manual donnent un nombre important d’informations sur ces mécaniques.

dpkg-deb -I

Il est possible de récupérer les informations d’un paquet facilement avec dpkg-deb -I:

dpkg-deb -I "./nginx_1.22.1-9_amd64.deb"
new Debian package, version 2.0.
size 527396 bytes: control archive=1372 bytes.
 904 octets,    16 lignes      control              
 318 octets,     5 lignes      md5sums              
 689 octets,    34 lignes   *  postinst             #!/bin/sh
 313 octets,    22 lignes   *  prerm                #!/bin/sh
  30 octets,     1 lignes      triggers             
Package: nginx
Version: 1.22.1-9
Architecture: amd64
Maintainer: Debian Nginx Maintainers <pkg-nginx-maintainers@alioth-lists.debian.net>
Installed-Size: 1330
Depends: libc6 (>= 2.34), libcrypt1 (>= 1:4.1.0), libpcre2-8-0 (>= 10.22), libssl3 (>= 3.0.0), zlib1g (>= 1:1.1.4), iproute2, nginx-common (<< 1.22.1-9.1~), nginx-common (>= 1.22.1-9)
Breaks: nginx-core (<< 1.22.1-6~), nginx-extras (<< 1.22.1-6~), nginx-light (<< 1.22.1-6~)
Replaces: nginx-core (<< 1.22.1-6~), nginx-extras (<< 1.22.1-6~), nginx-light (<< 1.22.1-6~)
Provides: httpd, httpd-cgi, nginx-abi-1.22.1-7
Section: httpd
Priority: optional
Homepage: https://nginx.org
Description: small, powerful, scalable web/proxy server
Nginx ("engine X") is a high-performance web and reverse proxy server
created by Igor Sysoev. It can be used both as a standalone web server
and as a proxy to reduce the load on back-end HTTP or mail servers.

Scripts de mainteneurs (optionnel)

Les scripts de mainteneurs sont des scripts shell à exécuter lors de diverses étapes de la vie du paquet, ils sont appelés avec des paramètres en entrée qui peuvent être utilisés pour discriminer les cas.

Les scripts de mainteneurs sont : 

  • preinst: avant installation. 
  • postinst: après installation. 
  • prerm: avant suppression. 
  • postrm: après suppression.

Exemple avec le script prerm de nginx_1.22.1-9_amd64 :

#!/bin/sh
set -e
case "$1" in
  remove|remove-in-favour|deconfigure|deconfigure-in-favour)
    if [ -x /etc/init.d/nginx ]; then
      invoke-rc.d nginx stop || exit $?
    fi
    ;;
  upgrade|failed-upgrade)
    ;;
  *)
    echo "prerm called with unknown argument \`$1'" >&2
    exit 1
    ;;
esac
exit 0

Le script de mainteneur prerm du paquet nginx s’exécute avant la suppression du paquet. On voit que le service nginx est arrêté dans tous les cas sauf en cas de mise à jour.

Pour savoir utiliser ces scripts correctement if vaut mieux jeter un coup d’œil aux diagrammes d’actions ici ou .

⚠️ Une chose importante à savoir est que ces scripts autorisent une grande liberté, ce qui peut facilement mener à leur mauvaise conception. Il faut être très vigilant sur ce que l’on met dedans.

En effet, si le script appelle un programme non installé, l’installation échouera. De même, il faut prendre en compte le contexte d’installation. Par exemple : les conteneurs docker sont incompatibles avec systemd, donc un paquet conçu uniquement pour systemd (en démarrant un service avec systemctl par exemple) ne sera probablement pas fonctionnel dans un conteneur.

Dans le cas des paquets officiels Debian, ce problème peut être partiellement résolu par l’intégration de code par dh qui permettra d’appliquer de bonnes pratiques (c'est à dire compatibles avec la distribution Debian). Si vous n’utilisez pas ces outils, par exemple en utilisant Cpack, il vous faudra donc une plus grande vigilance.

Conffiles (optionnel)

Les fichiers de configurations conffiles sont considérés comme des fichiers un peu différents des autres. La modification de ceux-ci doit parfois être conservée en cas de mise à jour.

Ainsi, en fournissant une liste de fichiers qui doivent être traités comme des fichiers de configuration dans les fichiers conffiles, on permet une gestion plus fine de ces fichiers.

Exemple avec le conffiles de nginx-common_1.22.1-9_amd64 :

/etc/default/nginx
/etc/init.d/nginx
/etc/logrotate.d/nginx
/etc/nginx/fastcgi.conf
/etc/nginx/fastcgi_params
/etc/nginx/koi-utf
/etc/nginx/koi-win
/etc/nginx/mime.types
/etc/nginx/nginx.conf
/etc/nginx/proxy_params
/etc/nginx/scgi_params
/etc/nginx/sites-available/default
/etc/nginx/snippets/fastcgi-php.conf
/etc/nginx/snippets/snakeoil.conf
/etc/nginx/uwsgi_params
/etc/nginx/win-utf
/etc/ufw/applications.d/nginx

Des options de dpkg permettent de gérer les comportements à avoir en cas de conflits.

md5sums

Les fichiers md5sums contiennent les sommes de contrôle de l’archive.

Exemple avec nginx_1.22.1-9_amd64 :

53d17c539bbfab41a06918cabb80bb13  usr/sbin/nginx
956f255d00a78afa88e0967fbf6ecb18  usr/share/doc/nginx/changelog.Debian.gz
7e8096ff673785a3727e6752caef245e  usr/share/doc/nginx/changelog.gz
3e7c76b5bcf60a9dbdbe9c89e1a846d7  usr/share/doc/nginx/copyright
771b1a8885261d3f40c0ca4862f6d173  usr/share/man/man8/nginx.8.gz

Ce fichier est normalement généré automatiquement par l’outil de génération de paquet.

triggers (optionnel)

Le mécanisme de trigger dpkg (voir aussi ici) sert à simplifier certains cas d’usages des scripts de maintenance. Les triggers permettent de déclencher le script postinstall triggered d’un paquet dans certaines conditions telles que : 

  • la modification d’un fichier lors de l’installation/désinstallation des autres paquets : cas implicite. 
  • l’activation explicite du trigger par un autre paquet : cas explicite.

Dans le cas du paquet nginx_1.22.1-9_amd64 , le fichier triggers contient un trigger explicite nommée nginx-reload:

interest-noawait nginx-reload

Et le script postinst triggered effectue un nginx reload.

Il est donc possible dans un nouveau paquet d’ajouter :

activate-noawait nginx-reload

Ce qui effectuera un appel au script de mainteneur postinst avec le paramètre triggered. Dans le cas du paquet nginx_1.22.1-9_amd64 pour Debian 12 «Bookworm»4 des dépôts officiel Debian, cela conduit au rechargement de nginx (nginx reload) à la fin de l’installation de ce nouveau paquet.

Un premier paquet avec Equivs

Equivs est un outil Debian pour générer des paquets Debian simple. Il est très pratique pour des cas simples comme celui des méta-paquets. Néanmoins, gardez en tête qu’Equivs n’est pas équipé pour générer des paquets Debian aux standards des paquets officiels de la distribution Debian, c’est plus un outil pour faire des paquets rapidement pour son propre usage.

C’est donc un excellent choix pour s’initier à la création de paquet.

Cas d’usage d’Equivs

Les usages préférentiels d’Equivs sont : 

  • Les méta-paquets: Ce sont des paquets “vides” (ou presque) mais qui contiennent des listes de dépendances, très pratiques pour installer/désinstaller une liste de programmes. L’usage des méta-paquets est courant sur Debian, ainsi des paquets comme gnome ou encore libreoffice sont des méta-paquets. 
  • Les faux-paquets: Il s’agit là de paquets “vides” dont le nom reprend le nom de paquets existants par ailleurs. Le seul but étant de mentir au système de paquet en lui faisant croire que tel paquet est bel et bien installé dans la version voulue.

Pour ceux qui connaissent python, on pourrait considérer les méta-paquets générés avec Equivs comme l’équivalent Debian d’un requirements.txt, bien qu’il soit possible de faire différemment.

Utilisons Equivs.

L’usage d’Equivs s’avère très simple :

  1. On installe le paquet equivs.
sudo apt install equivs
  1. Ensuite, on génère un fichier de configuration pour notre paquet. Dans notre cas d’exemple, on générera un paquet "custom-sysadmin", un paquet englobant des outils sysadmin pour notre propre usage :
equivs-control custom-sysadmin.conf

 Le fichier custom-sysadmin.conf est généré avec un contenu basé sur le fichier de modèle /usr/share/equivs/template.ctl. Rempli de commentaires, il nous donne une aide précieuse pour pouvoir générer une configuration complète et valide:

### Commented entries have reasonable defaults.
### Uncomment to edit them.
# Source: <source package name; defaults to package name>
Section: misc
Priority: optional
# Homepage: <enter URL here; no default>
Standards-Version: 3.9.2
Package: <package name; defaults to equivs-dummy>
# Version: <enter version here; defaults to 1.0>
# Maintainer: Your Name <yourname@example.com>
# Pre-Depends: <comma-separated list of packages>
# Depends: <comma-separated list of packages>
# Recommends: <comma-separated list of packages>
# Suggests: <comma-separated list of packages>
# Provides: <comma-separated list of packages>
# Replaces: <comma-separated list of packages>
# Architecture: all
# Multi-Arch: <one of: foreign|same|allowed>
# Copyright: <copyright file; defaults to GPL2>
# Changelog: <changelog file; defaults to a generic changelog>
# Readme: <README.Debian file; defaults to a generic one>
# Extra-Files: <comma-separated list of additional files for the doc directory>
# Links: <pair of space-separated paths; First is path symlink points at, second is filename of link>
# Files: <pair of space-separated paths; First is file to include, second is destination>
#  <more pairs, if there's more than one file to include. Notice the starting space>
Description: <short description; defaults to some wise words> 
long description and info
.
  1. On peut maintenant modifier le fichier de configuration à notre guise avec notre éditeur favori, notamment les champs :
    • Package: Le nom de votre paquet. Je vous conseille de mettre un préfixe clair afin d’éviter les collisions avec des paquets officiels.
    • Version: La version de votre paquet, pratique pour garder une traçabilité des changements.
    • Depends: Une liste de dépendances - C’est ici que la magie opère. À noter que vous pouvez vous montrer plus ou moins strict sur les versions de dépendances valides.
    • Description: Une description de ce qu’est le paquet.

Après avoir retiré les commentaires, on obtient alors un fichier similaire à celui-ci :

Section: misc
Priority: optional
Standards-Version: 3.9.2
Package: custom-sysadmin
Version: 0.2
Maintainer: Guénaël Muller <guenael.muller@smile.fr>
Depends:
   git,
   htop (>=3.2),
   nano,
   neofetch,
   ssh
Description: Utils for sysadmin
Some custom chosen utils
for sysadmin usages
  1. On peut enfin générer le paquet et l’installer :
# génération du .deb
        equivs-build custom-sysadmin.conf
        # apt est capable d'installer des paquets locaux et leurs dépendances.
        sudo apt install ./*.deb

Voici un méta-paquet tout prêt. Vous pouvez ensuite le modifier (n’oubliez pas d’augmenter la version) et l’ajuster à votre guise.

Aller plus loin :

N’hésitez pas à regarder à l'intérieur des paquets Debian binaires pour bien comprendre leur organisation et leur fonctionnement. Comme on le voit ici, c’est très facile d’aller regarder.

Principe des paquets

Outils Officiels

CPack(CMake)

Equiv:


  1. Je vous recommande fortement la documentation de debmake, Les outils officiels sont malheureusement un vrai labyrinthe.
  2. Il existe pour debian et les outils officiels (dh, etc.) la notion de paquet source, mais ce n’est pas de cela dont on parle ici.
  3. Donner les bons droits de fichiers ou placer les fichiers aux bons endroits n’est pas forcément aisé. Les outils officiels vous forceront ou vous conseilleront une certaine organisation, mais d’autres outils vous laisseront libre de faire des mauvais choix.
  4. Bookworm est le nom de code de la version 12 de Debian sortie en juin 2023. C'est une version de production : utilisable par le plus grand nombre, car testée et validée.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.