Déploiement d’une application (paquet Debian)

Expression du besoin

Dans le cadre du déploiement d’une application, on a souvent besoin de réaliser un programme d’installation de celle-ci. Une solution possible est de créer un paquet.

Un paquet ou parfois paquetage (package) est une archive (souvent compressée) comprenant les fichiers, les informations et procédures nécessaires à l’installation d’un logiciel sur un système d’exploitation en s’assurant de la cohérence fonctionnelle du système ainsi modifié. L’utilisation d’un paquetage logiciel est un élément constitutif d’une bonne pratique d’intégration logicielle.

Les types de paquets les plus répandus sous Linux sont :

  • deb est le format de fichier des paquets logiciels de la distribution Debian GNU/Linux. Presque toutes les distributions basées sur Debian utilisent aussi ce format (Ubuntu par exemple).

  • rpm (Red Hat Package) est un système de gestion de paquets de logiciels utilisé sur certaines distributions GNU/Linux. C’est le format utilisé par Linux Standard Base (LSB).

  • pacman (contraction de package-manager) est le gestionnaire de paquets officiel de la distribution Linux Arch Linux. Pacman utilise des archives .tar.gz, .bz2 ou .xz pour ses paquets.

Voir aussi : le format tgz (fichier archive créé avec tar et ensuite compressé généralement avec gzip), msi (pour les fichiers d’installation pour Windows Installer) …

Lire :

Déploiement

Pour réaliser une procédure d’installation d’une application, il faudra décomposer celle-ci en trois parties :

  • fabriquer une version finale (release) de l’application (make) en édition statique ou dynamique
  • fabriquer un paquet
  • installer le paquet sur une machine cible

Ces trois parties sont parfois dépendantes de la plateforme et des outils utilisés.

Voir aussi :

Fabriquer une version finale de l’application (release)

De manière générale, il faut résoudre un certain nombre de problèmes et répondre à quelques choix.

  • Droits et licence ? Les droits et les fichiers à déployer (consulter le contrat de licence de Qt par exemple) et les droits et les fichiers à appliquer à son application. Lire : www.gnu.org/licenses/.

  • Statique ou dynamique ? Il faudra choisir entre fabriquer un exécutable indépendant (statique) ou non (dynamique). Sous Linux, les dépendances sont nombreuses : architecture multi-platerforme, bibliothèques, etc … Lire : linux-deployment.html.

  • Librairies dynamiques ? Les bibliothèques dynamiques contiennent du code exécutable (des fonctions formant une API) qui sera susceptible d’être utilisé par un (ou plusieurs) programmes au moment de leur exécution. En cas de besoin, la librairie dynamique sera chargée en mémoire et son code sera alors utilisable par le programme demandeur. Il en résulte les avantages suivants : la taille du programme est réduite (puisque le code dont il a besoin se trouve dans la librairie), la possibilité de faire évoluer la librairie sans avoir à recompiler (si le prototype des fonctions définies dans la librairie reste inchangé). L’inconvénient majeur reste l’obligation de la présence de la librairie sur le système cible pour que le programme puisse s’exécuter. L’extension usuelle d’une librairie dynamique sous Linux est .so (pour Windows, ce sera .dll)

  • Dépendances ? Il y a plusieurs techniques pour connaître les dépendances externes d’une application : utiliser un utilitaire qui recherche ces dépendances (les commandes ldd, objdump, strace, dpkg et dpkg-depcheck par exemple sous Linux) ou appliquer une démarche (rudimentaire !) qui teste l’application sur une machine vierge (une machine virtuelle par exemple) et qui résout les dépendances les unes après les autres.

  • L’emplacement ? Il faudra déterminer où installer l’application (dans les chemins partagés /usr/bin/ et /usr/local/bin, séparés dans /opt/ ou dans $HOME pour Linux). On peut aussi envisager de créer une entrée dans le menu Application de l’environnement de bureau et aussi un raccoruci.

  • Les fichiers de l’application à déployer ? Il faut évidemment recenser les fichiers (ainsi que l’arborescence) qui composent l’application et qui devront être déployer avec celle-ci. De manière générale, on trouve : l’exécutable, l’icône (.ico), des fichiers de configuration (comme les .ini), des fichier multimédia (comme des images), des fichiers d’aide (comme les .chm ou les pages man, des fichiers .html, …), un fichier licence, un fichier readme, etc …

On désire au final regrouper toutes ces actions et tous ces fichiers dans un même et seul fichier : le paquet.

Créer un paquet Debian

Documentation de référence

L’arborescence

Il faut tout d’abord créer une arborescence qui va permettre ensuite de créer le paquet. Le répertoire racine doit avoir le nom du paquet. Ensuite, il doit y avoir un sous répertoire DEBIAN contenant certains fichiers :

  • control : fichier décrivant les informations relatives au paquet
  • postinst : script exécuté après l’installation du paquet
  • postrm : script exécuté après la désinstallation du paquet
  • pre* : les scripts exécutés avant l’installation du paquet

Remarques : Tous les fichiers post* et pre* doivent avoir les permissions 755 (rwxr-xr-x), idem pour les répertoires. Il est également possible de créer d’autres scripts dans le répertoire DEBIAN.

Le reste du contenu du répertoire racine représente une arborescence debian usuelle. C’est à dire que si on souhaite installer un fichier dans /urs/bin par exemple, il suffira de créer les sous répertoires usr et bin dans le répertoire racine et d’y placer ce qui devra être installé à cet endroit.

Commençons par créer les répertoires de base :

$ cd $HOME
$ mkdir -p qhelloworld/DEBIAN
$ cd qhelloworld

On va ensuite créer les répertoires ci-dessous et ycopier les fichiers suivants :

./usr/
./usr/bin/
./usr/bin/qhelloworld
./usr/share/
./usr/share/doc/
./usr/share/doc/qhelloworld/
./usr/share/doc/qhelloworld/COPYING
./usr/share/doc/qhelloworld/ChangeLog
./usr/share/doc/qhelloworld/AUTHORS
./usr/share/doc/qhelloworld/TODO
./usr/share/doc/qhelloworld/INSTALL
./usr/share/doc/qhelloworld/NEWS
./usr/share/doc/qhelloworld/README
./usr/share/man/
./usr/share/man/man1/
./usr/share/man/man1/qhelloworld.1.lzma

L’aroborescence de l’exemple est ici.

Le fichier control

Le fichier DEBIAN/control permet de décrire le paquet : dépendances, description, nom, auteur et mainteneur du paquet …

Documentation : DEBIAN/control

$ vim $HOME/qhelloworld/DEBIAN/control

Package: qhelloworld
Version: 1.0
Section: base
Priority: optional
Architecture: all
Depends: libc6, libgcc1, libstdc++6, libqtgui4, libqtcore4
Maintainer: Mr Doe <doe@nowhere.com>
Description: une description ...

Remarque : la description du paquet doit obligatoirement être suivie d’un retour à la ligne sinon dpkg-deb renverra une erreur lors de l’analyse syntaxique.

Une des partie essentielle dans les paquets est la gestion des dépendances (mot-clé Depends). On peut restreindre les dépendances à des versions particulières de chaque paquet nommé. La restriction de chaque paquet particulier est indiquée entre parenthèses après son nom avec une relation (<<, <=, =, >= et >>) suivie par une valeur de numéro de version. Par exemple : Depends: toto (>= 1.2)

Il existe un outil qui permet de lister les dépendances : dpkg-depcheck. On peut aussi s’aider des commandes ldd, objdump, et dpkg :

$ sudo apt-get install devscripts

$ dpkg-depcheck /$HOME/qhelloworld/usr/bin/qhelloworld
...
Packages used:
  libgnome2-0
  fonts-tlwg-mono
  fontconfig-config
  libxdamage1
  libpango1.0-0
  ttf-indic-fonts-core
  libgpg-error0
  libpcre3
  libx11-6

$ objdump -p /$HOME/qhelloworld/usr/bin/qhelloworld | grep NEEDED
  NEEDED               libQtGui.so.4
  NEEDED               libQtCore.so.4
  NEEDED               libstdc++.so.6
  NEEDED               libgcc_s.so.1
  NEEDED               libc.so.6

$ dpkg -S libQtGui.so.4
libqtgui4: /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.1

$ dpkg -S libQtCore.so.4
libqtcore4: /usr/lib/x86_64-linux-gnu/libQtCore.so.4.8

$ dpkg -S libstdc++.so.6
libstdc++6: /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16

$ dpkg -S libgcc_s.so.1
libgcc1: /lib/x86_64-linux-gnu/libgcc_s.so.1

$ dpkg -S libc.so.6
libc6: /lib/x86_64-linux-gnu/libc.so.6

Voir aussi : Gestion de la configuration

Les scripts de post et pré-installation

Le fichier DEBIAN/postinst est un script qui sera exécuté à la fin de l’installation du paquet.

On peut y faire par exemple des modifications de droits (chmod), de propriétaire (chown) ou des créations de répertoires cachés pour des configurations propres aux utilisateurs :

#!/bin/bash
if [ -f "/usr/bin/qhelloworld" ]
then
    chown root:root /usr/bin/qhelloworld
fi
if [ -d "/usr/share/doc/qhelloworld" ]
then
    chown root:root /usr/share/doc/qhelloworld/*
fi
if [ -f "/usr/share/man/man1/qhelloworld.1.lzma" ]
then
    chown root:root /usr/share/man/man1/qhelloworld.1.lzma
fi
mkdir ~/.qhelloworld
touch ~/.qhelloworld/profile
echo "Hello World !" > ~/.qhelloworld/profile

Le fichier DEBIAN/postrm est un script qui sera exécuté après la désinstallation. Par exemple :

#!/bin/bash
rm -rf ~/.qhelloworld

Création du paquet

Il faut se placer dans le répertoire contenant l’arborescence du paquet puis utiliser la commande dpkg-deb :

$ cd $HOME
$ ls
qhelloworld

$ dpkg-deb --build qhelloworld
dpkg-deb : construction du paquet « qhelloworld » dans « qhelloworld.deb ».

À moins de préciser --nocheck, dpkg-deb lit DEBIAN/control et l’analyse. Il cherche les erreurs de syntaxe et d’autres problèmes existants, puis il affiche le nom du paquet binaire qu’il construit. dpkg-deb vérifie aussi les permissions des scripts du responsable et des autres fichiers qu’il trouve dans le répertoire de contrôle DEBIAN.

Il est possible de visualiser le contenu du paquet :

$ dpkg-deb --contents qhelloworld.deb
drwxrwxr-x tv/tv             0 2017-04-21 06:56 ./
drwxrwxr-x tv/tv             0 2017-04-21 06:57 ./usr/
drwxrwxr-x tv/tv             0 2017-04-21 20:45 ./usr/bin/
-rwxr-xr-x tv/tv         14423 2017-04-21 18:03 ./usr/bin/qhelloworld
drwxr-xr-x tv/tv             0 2017-04-21 06:58 ./usr/share/
drwxrwxr-x tv/tv             0 2017-04-21 06:59 ./usr/share/doc/
drwxrwxr-x tv/tv             0 2017-04-21 07:01 ./usr/share/doc/qhelloworld/
-rw-r--r-- tv/tv         17992 2010-04-17 14:24 ./usr/share/doc/qhelloworld/COPYING
-rw-r--r-- tv/tv           140 2017-04-21 07:01 ./usr/share/doc/qhelloworld/ChangeLog
-rw-r--r-- tv/tv            55 2017-04-21 07:01 ./usr/share/doc/qhelloworld/AUTHORS
-rw-r--r-- tv/tv            30 2017-04-21 06:59 ./usr/share/doc/qhelloworld/TODO
-rw-r--r-- tv/tv           310 2017-04-21 07:00 ./usr/share/doc/qhelloworld/INSTALL
-rw-r--r-- tv/tv             0 2010-04-17 14:24 ./usr/share/doc/qhelloworld/NEWS
-rw-r--r-- tv/tv            20 2017-04-21 07:00 ./usr/share/doc/qhelloworld/README
drwxr-xr-x tv/tv             0 2010-04-17 14:24 ./usr/share/man/
drwxr-xr-x tv/tv             0 2010-04-17 14:24 ./usr/share/man/man1/
-rw-r--r-- tv/tv           489 2010-04-17 14:24 ./usr/share/man/man1/qhelloworld.1.lzma

Et d’obtenir des informations sur le paquet :

$ dpkg-deb -I archives/qhelloworld.deb 
 nouveau paquet Debian, version 2.0.
 taille 14050 octets : archive de contrôle = 569 octets.
     328 octets,     8 lignes      control              
     399 octets,    16 lignes   *  postinst             #!/bin/bash
      34 octets,     2 lignes   *  postrm               #!/bin/bash
 Package: qhelloworld
 Version: 1.0
 Section: base
 Priority: optional
 Architecture: all
 Depends: libc6, libgcc1, libstdc++6, libqtgui4, libqtcore4
 Maintainer: Mr Doe <doe@nowhere.com>
 Description: une description ...

Installation (et désintallation) du paquet

Pour installer le paquet, on peut simplement utiliser la commande dpkg :

$ sudo dpkg -i qhelloworld.deb

$ qhelloworld -v
qhelloworld 1.0 

Voir aussi : Comment installer un paquet ?

On peut vérifier l’état du paquet :

$ dpkg-query -s qhelloworld
Package: qhelloworld
Status: install ok installed
Priority: optional
Section: base
Maintainer: Mr Doe <doe@nowhere.com>
Architecture: all
Version: 1.0
Depends: libc6, libgcc1, libstdc++6, libqtgui4, libqtcore4
Description: une description ...

$ dpkg -l | grep qhelloworld
ii  qhelloworld    1.0     une description ...

$ dpkg-query -L qhelloworld
/.
/usr
/usr/bin
/usr/bin/qhelloworld
/usr/share
/usr/share/doc
/usr/share/doc/qhelloworld
/usr/share/doc/qhelloworld/COPYING
/usr/share/doc/qhelloworld/ChangeLog
/usr/share/doc/qhelloworld/AUTHORS
/usr/share/doc/qhelloworld/TODO
/usr/share/doc/qhelloworld/INSTALL
/usr/share/doc/qhelloworld/NEWS
/usr/share/doc/qhelloworld/README
/usr/share/man
/usr/share/man/man1
/usr/share/man/man1/qhelloworld.1.lzma

Pour désinstaller avec dpkg, on peut utiliser l’option -r (remove) qui laisse les fichiers de configuration ou l’option -P (purge) qui supprtime tout :

$ sudo dpkg -P qhelloworld

Le paquet de l’exemple est ici.

Bonus : création d’un dépôt local (intranet)

Côté serveur :

$ mkdir -p /var/cache/apt/archives

$ cp *.deb /var/cache/apt/archives

$ dpkg-scanpackages ./ /dev/null | gzip -9c > Packages.gz

$ cp Packages.gz /var/cache/apt/archives

$ ln -s /var/cache/apt/archives /var/www/html/packages

$ vim /etc/httpd/conf/httpd.conf

<Directory /var/www/html/packages>
    Options Indexes FollowSymLinks
</Directory>

$ sudo /etc/init.d/httpd restart

Côté client :

$ sudo vim /etc/apt/sources.list

## Depot local intranet
deb http://192.168.52.85/packages ./

$ sudo apt-get update

Retour au sommaire