Thématiques principales

Affichage des articles dont le libellé est debian. Afficher tous les articles
Affichage des articles dont le libellé est debian. Afficher tous les articles

mercredi 22 avril 2020

Maintenance Raid

On avait vu comment monter des disques en Raid [raid]. Mais je n'avais pas évoqué la question de comment reprendre un disque défaillant.

Data pas de panique, un disque peu très bien avoir eut un soucis de connexion et le raid l'a détecté et l'a donc placer en erreur.

Identification


Pour savoir si un disque est ko, il faut utiliser l'utilitaire mdadm:

1
$ mdadm --detail /dev/md0

Le récapitulatif qui vous sera fourni vous donnera alors l’état des disques faisant parti du Raid.

En suite une fois identifié le problème, et dans la mesure ou le disque est recupérable alors il faudra identifier le disque en question pour ensuite le réintroduire dans le raid.

Pour cela un simple!:

1
$ fdisk -l

Réparation 


Puis pour réintroduire le disque:

1
$ mdadm --manage /dev/md0 --add /dev/sdd1

(Si c'est le disque sdd1 qui était initialement dans le raid)

Alors le disque va etre resynchroniser (car peut être qu'il n'a pas ete mise a jour des dernieres infos.

Pour voir l’état de la resynhro, il suffit d'observer le fichier mdstat avec

1
$ watch cat /proc/mdstat

Et la vous aurez votre raid de nouveau opérationnel.

Références:


[raid] https://un-est-tout-et-tout-est-un.blogspot.com/2020/03/montage-raid.html
[mdadm] https://doc.ubuntu-fr.org/raid_logiciel

lundi 30 mars 2020

Montage Raid

Introduction

Aujourd'hui un article court! et qui va aussi me servir d'aide mémoire: RAID!

Besoin

RAID? Oui RAID [ubuntu-raid], pas le produit anti mouche, mais la solution de résilience du stockage! Attention, ici on ne parle pas de base de données mais d'une solution permettant de gérer la sauvegarde de données en terme de disponibilité et d’intégrité en cas de panne! Il s'agit en fait d'une technique de gestion des données au niveau le plus bas possible, entre autre, au niveau des disques!

Solutions

Ainsi Il va exister différents niveaux RAID, assurant différents types de gestions des disques, allant de RAID 0 a RAID 10:
  • RAID 0: il ne s'agit pas d'une configuration permettant d'assurer de la sauvegarde mais de pouvoir tirer le maximum des performances des disques (en distribuant les données). Cette config nécessite au moins 2 disques.
  • RAID 1: avec deux disques au moins, cette configuration permet de dupliquer a l'identique les informations sur les disques comme s'il n'y en avait qu'un. Ainsi en cas de panne, la redondance permet de garantir les données. Coté performance, vous permettrez d’améliorer le nombre d’accès disque parallèle au meilleur taux de transfert (limité a la vitesse d’accès disque classique)
  • RAID 5: le RAID 5 est une combinaison du RAID 0 et du RAID 1 et nécessite 3 disques au minimum permettant d’améliorer les perf et de se garantir de la perte d'un disque. au delà les données seront perdu.
  • RAID 6: le RAID 6, c'est du RAID 5 mais avec une gestion permettant la perte acceptable de deux disques avant la perte irrémédiable de données. Cela nécessite donc 4 disques...
  • RAID 10: Avec 4 disques, ce mode est une combinaison matricielle du RAID 1 sur n disque et du RAID 0 sur m cluster des disques RAID 1. Le RAID 1 a pour but de garantir l’intégrité des données alors que le RAID 0 se veut optimiser les performances.

Exemple


Le cas du RAID 1

Identification des disques


1
fdisk -l

Creation du RAID 1


1
mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sda1 /dev/sdb1


Formatage du disque


1
mkfs.ext4 /dev/md0

Montage du disque

Ajouter au fichier /etc/fstab la ligne suivante
/dev/md0 /mnt/raid ext4 defaults 0 1
Pour ensuite monter le disque


1
mount -a

References

[ubuntu-raid] https://doc.ubuntu-fr.org/raid_logiciel

dimanche 11 août 2019

Déployer du Python

L’idée de cet article est de nous intéresser aux modes de livraison possible d’un programme python. L'enjeux est important car, en effet, écrire du code c’est bien mais sans livraison, c’est comme si ce code n’existait pas! Il faut donc avoir des moyens fiables et rapides permettant de fournir à un client son application python “clef en main”.

Via les sources

Dans cette approche ce qui sera fourni ce sera directement les sources qui seront mis à disposition de l’utilisateur final. Ce dernier aura alors la charge de fournir un environnement disposant non seulement de python dans la version adéquate mais aussi d’avoir pre-installer les modules dont l’application dépende.

Par exemple, sur une machine Debian, pour lancer l’application, il va être nécessaire préalablement de faire :

1
2
3
4
5
$ apt-get update && apt-get install -y --no-install-recommends python3 \
   python3-pip python3-dev \
$ apt-get clean && rm -rf /var/lib/apt/lists/
$ pip3 install --upgrade pip setuptools
$ pip3 install dependencies

Pour finalement pouvoir lancer l’application sur un appel du module :

1
$ python3 -m monAppli

Le point négatif de cet approche est la gestion des droits car lors du lancement de l’application, et à moins de préciser que l’on veille que python reste en mode interpréteur [pyt-pyc], différents fichiers vont être générés sur le poste cible. Il importe donc que ces fichiers puisse être généré sans être gêné par des permissions du systèmes mal prévu (et qui seront de toute façon délicat à mettre en oeuvre).

Via les fichiers pré-compilés

C’est une possibilité il faut l’avouer mais alors il ne sera pas possible de faire de patch ou de modification du code source sans compter que ce code sera globalement dispatcher dans un ensemble de fichiers et de répertoire (à l’image des sources).

Cela n'empêchera pas de devoir aussi préparer l’environnement d'exécution comme avec les sources. Donc c’est moins risqué coté permissions systèmes mais on perd un peu l'intérêt du python (le côté interpréteur)

À ce compte là, il serait alors mieux de simplifier la livraison en réalisant un package de l’application.

Exe, deb, rpm, etc...

Alors il est clair que faire un package de livraison, ca sera forcement en prenant en compte l’environnement de déploiement et il ne sera pas possible de déployer de la même manière sous windows où sous linux.

L'intérêt de l’approche est de fournir au client une seule référence et sera donc plus simple à gérer d’autant plus que selon la plateforme, cela permettre de bénéficier mécaniquement des avantages du mode de distribution (utilisation de aptitude et gestionnaire de paquet sous linux, pre-installation et configuration de paquets en dépendances, etc.

Pourtant les problèmes cités ci dessus seront toujours présents, code sources ou fichiers pre-compilés, il faudra gérer la dispersion de fichiers dans l’environnement.

On voit bien donc que le problème ici n’est pas le package de livraison, mais son contenu. Heureusement la communauté python à pensé à tout et à fournir différents outils pour livrer de façon cohérente notre application.

Pre-packaging

Ainsi pour réaliser ce pre-packaging, il existe quelques outils comme [setuptools], [distutils], [zipapp], [pyInstaller], py2exe (Windows) ou encore [cx_Freeze] (Windows et Linux) pour ne citer que les plus connu.

PyInstaller


Le plus simple à utiliser est PyInstaller, on l’installe et on l’applique sur le main:

1
2
$ pip install pyinstaller
$ pyinstaller monAppliv.py

et on obtient un répertoire dist dans nos sources contenant notre applications et toutes les librairies nécessaire à son exécution.

En voyant ca vous allez me dire, ok on a troqué les fichiers sources oi pre-compilé avec des librairies…. oui mais la il n’est pas nécessaire d’installer python sur le poste! Par contre attention, la construction qui à été réalisé à être spécifique à une plateforme… donc il faudra prévoir un build pyinstaller par plateforme cible.

setuptools


Setuptools est à l’inverse un package qui va permettre de construire un module versionable comme ceux télécharger lors de l’utilisation de pip install.

Setuptools repose sur distutils et je ne présenterai donc pas ce dernier qui est de plus bas niveau dans la construction des modules package python.

Setuptools est probablement l’outil le plus employé par la communauté car il permet l'intégration du module développé au sein d’un Server exploitable via pip. Ainsi même si python doit être préalablement installer sur le poste cible, la gestion des sources et fichier pre-compilés devient complètement transparent pour le développeur et le client.

De plus, contrairement au contraintes d’une gestion externe du packaging, setuptools, en gérant le versionning va faciliter via pip la mise à jour et l'évolution de l’application.

Pour cela il faut d’abord créer un descripteur de l’application et ce en python. Par exemple dans le cas de nos applications ReST [rest-py], on va créer un fichier setup.py contenant le code suivant:

1
2
3
4
5
6
7
8
from setuptools import setup, find_packages
setup(
    name="people",
    version="0.1.0",
    packages=find_packages(),
    scripts=['people.py','json_tk.py','human.py'],
    install_requires=['docutils>=0.3','Flask>=1.1.1']
)

Ensuite ce code sera exécuté bêtement comme un script :

1
$python setup.py sdist

Ce code va alors produire un targz de notre application contenant nos sources et déclarant les dépendances adéquates pour son installation.

Ainsi une fois packager il suffit alors de fournir ce package au client que celui ci exécute la commande suivante:

1
$ pip install people-0.1.0.tar.gz

Notre application est alors installée dans python (à cette occasion on préférera utiliser un virtualenv…) Et utilisable comme ceci:


1
$ python -m people

Dans cet exemple, avec setuptools, on voit que l’on est beaucoup moi adhérant à la plateforme mais que cela implique que python soit préalable installer dans celle-ci.

L’avantage sera évidemment sa mise à jour mais on notera que si ici on a créé un module setup.py, le nom de ce fichier est impératif sinon l’installation ne sera pas possible avec pip. du coup on notera que notre façon de faire nos applications dans l’exemple [rest-py] se prête finalement assez mal avec cette approche (à moins de séparer le code métier du code applicatif mais cela peut être laborieux)

Conclusions

Nous venons de passer en revue l’ensemble des manière de livrer et déployer une application python. Toutes ces façons de faire comportent leur lot d’avantages et d'inconvenants. On notera malgré tout que la communauté python n’est pas en reste de solution pour fournir des approches, il restera ensuite à la charge des développeurs de faire un choix selon le contexte et les contraintes.

Cependant, nous n’avons pas évoqué une dernière solution possible pour la livraison et le déploiement de nos applications python…. à votre avis???

Références:

[rest-py] https://un-est-tout-et-tout-est-un.blogspot.com/2019/08/rest-avec-python.html
[pyt-pyc] https://stackoverflow.com/questions/154443/how-to-avoid-pyc-files
[distutils] https://docs.python.org/fr/3/library/distutils.html
[pyinstaller] https://www.pyinstaller.org/
[zipapp] https://docs.python.org/fr/3/library/zipapp.html
[setuptools] https://setuptools.readthedocs.io/en/latest/setuptools.html
[cx-freeze] https://cx-freeze.readthedocs.io/en/latest/index.html

samedi 24 mars 2018

Maven : assembly, targz et jdeb

Aujourd’hui nous allons nous intéresser à la production du livrable issue de la production logicielle. Le sujet ne va pas etre forcement tres long a traiter tant maven permet de chose si l’on utilise les bons plugins.

La production du livrable impose avant tout la définition de celui ci. Souvent, il va être dépendant de la plateforme et du langage. Dans notre cas, nous allons tâcher de produire nos composants dans le contexte d’utilisation du langage Java et nous nous projeterons dans une plateforme linux, la debian et la plateforme windows.

Bien sûr on aurait pu passer par l’utilisation de profile maven dans lequel nous aurions spécifier selon l’OS différents plugins afin de répondre à cette problématique de production. Par exemple en définissant les profiles suivants:

<profiles>
 <profile>
  <activation>
   <os>
    <family>windows</family>
   </os>
  </activation>
  <build>...</build>
  ...
 </profile>
 <profile>
  <activation>
   <os>
    <family>linux</family>
   </os>
  </activation>
  <build>...</build>
  ...
 </profile>
</profiles>


Nous n'utilisons pas cette approche car d’une part non nécessaire puisque Java est multiplateforme et d’autre part elle complexifie lourdement la production (l’utilisation de profile n’etant une bonne chose que si on en peut vraiment pas faire autrement)

Au lieu de cela, nous allons plutôt tricher un peu et prendre le parti pris que nous souhaitons livrer simplement un targz pour windows et un deb sous linux (comme cela, on pourra produire le même jar et livrer d’un côté un script bash pour lancer notre appli et de l’autre un bat.) Pour répondre à ce problème nous allons utiliser le plugin maven-assembly-plugin.

Ce plugin est un plugin indispensable pour la plupart des builds maven car au delà de l’utilisation ce que nous allons en faire, il permet de faire surtout toute sorte de compositions, de construire tout type de paquet de livraison mais aussi de pouvoir construire des jar au contenu spécifique (nous y reviendrons mais pas dans cet article) .

Nous avons donc deux types de packaging à réaliser, un pour le targz et un autre pour le deb. On va configurer le plugin pour qu’il fasse les deux en même temps en définissant deux fichiers d’assembly:

<plugin>
 <groupid>org.apache.maven.plugins</groupid>
 <artifactid>maven-assembly-plugin</artifactid>
 <version>2.5.3</version>
      <configuration>
  <finalname>${project.artifactId}-${project.version}</finalname>
  <ignoredirformatextensions>true</ignoredirformatextensions>
  <outputdirectory>${project.build.directory}</outputdirectory>
       </configuration>

 <executions>
  <!-- Packaging debian -->
  <execution>
   <id>assembly-debian</id>
   <phase>prepare-package</phase>
   <goals>
    <goal>single</goal>
   </goals>
   <configuration>
    <appendassemblyid>false</appendassemblyid>
    <descriptors>
     <descriptor>src/main/assembly/assembly-debian.xml</descriptor>
    </descriptors>
   </configuration>
  </execution>
  <execution>
   <id>assembly-targz</id>
   <phase>package</phase>
   <goals>
    <goal>single</goal>
   </goals>
   <configuration>
    <appendassemblyid>false</appendassemblyid>
    <descriptors>
     <descriptor>src/main/assembly/assembly-targz.xml</descriptor>
    </descriptors>
   </configuration>
  </execution>
 </executions>
</plugin>


Quelques explications sur l’utilisation du plugin dans le pom. On précise le répertoire de sortie et le nom général de la composition. On spécifie ensuite par type de composition un élément de configuration en utilisant appendAssemblyId. Ceci permet d’ajouter le classifier “assembly” au nom de la composition, mais ici on va s’en passer. On met false. On précise également pendant quelle phase et quel goal les assembly devront être construit. Enfin on donne au plugin le fichier d’assembly qui précise le contenu de la composition.

Le fichier assembly est la dernière partie permettant de construire la composition. Il s’agit d’un fichier xml définissant plusieur choses: le format de sortie, les dépendances à joindre et ou les déposer et enfin les répertoires annexes que la composition doit contenir. Regardons celui du targz:

<assembly>
 <id>bundle</id>
 <formats>
  <format>tar.gz</format>
 </formats>
 <includebasedirectory>false</includebasedirectory>

 <dependencysets>
<!--  Inclusion interfaces classifier et librairies-->
  <dependencyset>
   <unpack>false</unpack>
   <scope>runtime</scope>
   <useprojectartifact>false</useprojectartifact>
   <useprojectattachments>true</useprojectattachments>
   <outputdirectory>/opt/monappli</outputdirectory>
   <includes>
    <include>*:${project.artifactId}:*:assembly:*</include>
   </includes>
  </dependencyset>
 </dependencysets>

  <filesets>
      <fileset>
          <directory>src/main/debian/etc/init.d</directory>
          <outputdirectory>/etc/init.d</outputdirectory>
          <usedefaultexcludes>true</usedefaultexcludes>
          <filtered>true</filtered>
          <includes>
              <include>monappli</include>
          </includes>
      </fileset>
  </filesets>
</assembly>


Inutile de commenter le format, il parle de lui-même. Les dependencySet se construisent pour incorporer à la composition les éléments des dépendances qu’il faudra ajouter et sous quel forme. Par exemple on peut spécifier si elles seront dézipper dans la composition (cela est pratique par exemple lorsque l’on veut fusionner des artifacts ensemble pour faire un jar), le répertoire ou ces éléments seront déposé et enfin un ensemble d'artifact déclarer sous la forme d’une regex.

Les fileSet précisent de la même manière que pour les artifacts l’ensemble des fichiers et répertoires à construire dans notre composition. Ces éléments sont généralement issus des ressources du projets et il est possible de réaliser du remplacement clef/valeur dedans (via le resources filtering). A l’issu de l’application de l’assembly, on aura alors tous ces éléments dans un tar.gz… cool!

Bon bien du coup on fait pareil pour le paquet debian non? et bien pas tout à fait. sur le principe, on va procéder de la même manière en utilisant un fichier d’assembly rigoureusement identique sauf sur le format que nous définirons a “dir”. Ce format ne fait rien a part préparer les éléments de la composition. Pourquoi prendre ce format? Tout simplement parce que le plugin assembly n’est pas capable de construire quelque chose d’aussi complexe qu’un paquet debian. On va donc s’appuyer d’un autre plugin pour faire cela: jdeb. Avant cela je vous renvoie à [3] pour compléter vos ressources avec les fichiers de contrôles qui vont bien et les intégrer à l’assembly.

Ceci étant fait, penchons nous sur le plugin jdeb. Celui ci se configure assez classiquement en précisant sa phase de build et son goal. A cela, on va preciser le nom du paquet debian, le repertoire des fichiers de controles, et enfin un ensemble de dataset precisant tous les repertoire, fichiers et autres resources qui va falloir ajouter au paquet. Attention, a ce nieau, il faut avoir une vision clair des droits qui seront appliqué lors de l’installation, puisque l’on va les preciser ici. Voyons cela:

<plugin>
 <artifactid>jdeb</artifactid>
 <groupid>org.vafer</groupid>
 <version>1.5</version>
 <executions>
  <execution>
   <phase>package</phase>
   <goals>
    <goal>jdeb</goal>
   </goals>
   <configuration>
    <deb>${project.build.directory}/${project.artifactId}-${build}_${versiontimestamp}_all.deb</deb>
    <verbose>true</verbose>
    <controldir>${project.build.directory}/${project.artifactId}-${project.version}/DEBIAN</controldir>
    <dataset>
     <data>
      <src>${project.build.directory}/${project.artifactId}-${project.version}/opt</src>
      <type>directory</type>
      <mapper>
       <type>perm</type>
       <prefix>/opt</prefix>
      </mapper>
     </data>
    </dataset>
   </configuration>
  </execution>
 </executions>
</plugin>


Voilà, nous venons de passer en revu comment construire les livrables de nos projets. Bien sur faire du java permet déjà de packager les sources mais pour être propre, l'idéal est de fournir un composant standard comme un targz ou mieux un deb contenant tous les éléments permettant de faire vivre l’application (fichier de conf, de scripts, etc…)

Références: 

[1] https://maven.apache.org/plugins/maven-assembly-plugin/single-mojo.html
[2] https://github.com/tcurdt/jdeb/blob/master/src/examples/maven/pom.xml
[3] https://un-est-tout-et-tout-est-un.blogspot.fr/2017/12/construire-un-paquet-debian.html

lundi 26 février 2018

Dépôt Debian signé

Dans un article précédent nous avions traité de la construction de dépôts debian. Basiquement nous nous étions contenté de l’initialisation du listing des packages du dépôt en effectuant un scanpackage [1].

Aujourd’hui de façon à rendre un peu plus fiable et sécurisé les paquets et fournir plus de garanties aux utilisateurs du dépôts, nous allons regarder comment signer les éléments du dépôts, mais nous allons aussi industrialiser un peu la méthode de production du dépôt.

Pour cela nous allons tout d’abord récupérer reprepro [2] et gpg2 [3-4]. On aurait pu faire sans reprepro mais bon, quand il existe un outil qui sait faire autant ne pas s’en priver [5-6].

Générer la clef pour signer le dépôt

Tout d’abord il faut construire une clef pour notre futur dépôt et on vérifie la présence de notre clef dans le trousseau

gpg2 --gen-key
gpg2 --list-keys

Puis on export cette clef dans répertoire accessible au travers de votre serveur apache (un chemin proche de l’url du futur repo par exemple)

gpg2 --armor --export votreNom@mail.com >> /var/www/pathInApache/key/keyName.gpg.key

Ici par exemple notre clef sera accessible à l'adresse http://localhost/pathInApache/key/keyName.gpg.key. Pour l’ajouter il faudra ajouter la clef publique en mode admin (en root ou en ajoutant des sudo

wget -O - http://hostserver/pathInApache/key/keyName.gpg.key | apt-key add -

Comme ça lorsque l’on aura a faire le apt-get update, apt sera capable de vérifier la signature, grâce à la clef.

Construction du dépôt

Une fois la clef configurée, il ne nous reste plus qu'à construire le dépôt pour mettre à disposition les paquets Debian. Pour ce faire, nous allons dans un premier temps utiliser reprepro qui va automatiser une très grosse partie du travail en partant d’une config et d’un répertoire de livraison dans lequel nous déposerons nos paquets à la suite de leur production.

Il nous faut tout d’abord définir un répertoire accessible via http donc un répertoire tel que /var/www/apt par exemple. Au passage dans ce répertoire on peut y placer notre répertoire key, qui contient la clef publique du dépôt.

Dans ce répertoire apt nous allons y créer un répertoire livraison dédié aux paquets Debian. A côté de celui ci nous allons également créer un répertoire conf dans lequel on va déposer un fichier que l’on nommera distributions. Ce fichier contiendra toutes les informations nécessaire à reprepro pour initialiser le dépôt et l’alimenter.

Ainsi ce fichier doit contenir les champs suivants [10]:

Origin: Votre nom ou un url 
Label: monLabel 
Suite: stable 
Codename: le nom code de votre projet comme wheeze ou xenial par exemple “monCode” 
Version: 1.0 
Architectures: i386 amd64 armhf 
Components: all non-free contrib 
Description: Un peu de blabla 
SignWith: yes

Le paramètre SignWith est essentiellement le plus important pour ce qui nous préoccupe, c’est a dire de faire un dépôt signé. A la place du yes, il est possible de mettre la clef GPG mais avec le yes, reprepro ira directement la chercher dans le trousseau.

Ainsi on va avoir l’arborescence suivante:
  • /var/www/apt/conf/distributions
  • /var/www/apt/key/keyName.gpg.key
  • /var/www/apt/livraison/
On met un Debian dans le répertoire livraison et on applique la commande suivante:


APT_DIR=”/var/www/apt”reprepro --dbdir $APT_DIR/db --confdir $APT_DIR/conf -b $APT_DIR/deb include monCode $APT_DIR/livraison/*.deb

reprepro va procéder a l’analyse du répertoire livraison en récupérer la dernière version des Debian présents et les classer dans un répertoire deb/pool. Dans ce même répertoire, il va constituer un répertoire dists dans lequel il déposera l'équivalent du scanpackage avec sa version signée qui permettra au client d’identifier notre dépôt avec la clef publique qu’il aura obtenu. Le répertoire db est un répertoire de travail de reprepro, nous ne nous attarderons pas dessus.

Bien sur pour à chaque nouvelle production des paquets, il faudra rappeler ce script. Pour cela, il est possible d’utiliser le daemon mini-dinstall [11-13]. Cela sera peut être l’occasion d’un autre article.

Pour les plus avisés qui voudront aller vraiment plus loin, je vous invite lire l’article de Vincent qui reprend un cas d’utilisation complet [9]

Note (26/08/2018) : attention a utiliser les commandes gpg2 avec sudo de facon a ce que les clefs soient accessibles lors de l'appel de reprepro qui se fait assez logiquement aussi en sudo (puisque c'est pour initialiser le depot.... )

Note 2 (26/08/2018) Sinon pour convertir de gpg a gpg2 et reciproqement:

gpg2 --export-secret-keys | gpg --import -
gpg --export-secret-keys | gpg2 --import -

Références

[1] https://un-est-tout-et-tout-est-un.blogspot.fr/2017/12/faire-un-depot-debian.html
[2] https://doc.ubuntu-fr.org/tutoriel/comment_creer_depot
[3] https://www.gnupg.org/
[4] https://doc.ubuntu-fr.org/gnupg#utilisation_et_configuration
[5] https://wiki.debian-fr.xyz/Faire_un_d%C3%A9pot_sign%C3%A9_ou_non
[6] http://blog.glehmann.net/2015/01/27/Creating-a-debian-repository/
[7] https://www.francoz.net/doc/gpg/x218.html
[8] http://www.serveur-linux.info/2012/01/depot-personnalise-paquets-debian/
[9] https://vincent.bernat.im/fr/blog/2014-depots-apt-locaux
[10] https://blog.packagecloud.io/eng/2017/03/23/create-debian-repository-reprepro/
[11] https://github.com/shartge/mini-dinstall
[12] https://manpages.debian.org/stretch/mini-dinstall/mini-dinstall.1.en.html
[13] https://debian-handbook.info/browse/fr-FR/stable/sect.setup-apt-package-repository.html

vendredi 29 décembre 2017

Construire un paquet Debian


Dans l’article précédent, nous avions vu comment préparer un dépôt debian viable de façon a faire des installation et des déploiements sur une plateforme debian [3].

Nous allons nous intéresser dans ce présent article sur comment alimenter notre dépôt et donc comment nous allons procéder pour construire un paquet debian.

Structure du paquet debian

Un paquet debian [4] n’est initialement qu’un tar.gz dont l'extension est .deb, construit à l’aide de la commande dpkg-deb (il existe d’autre approche comme jdeb [5]) qui sera déployé à la racine /. Cela signifie qu’il sera nécessaire lors de la conception du paquet de reproduire l’arborescence cible si l’on souhaite déployer des fichiers dans des répertoires précis du système.

Ainsi par exemple si l’on souhaite construire un paquet permettant de déployer un binaire dans le système, on créera un répertoire du nom du paquet dans lequel on trouvera le chemin /usr/bin/monBinaire:
/home/moi/monPaquet/usr/bin/monBinaire
Ainsi quand l’on construira le paquet, celui ci déposera monBinaire dans /usr/bin.

Cette démarche est valable pour tout fichier déposé statiquement dans le système. A noter que lors de cette étape, dpkg, le composant procédant à l’installation, fait le listing des fichiers déposés et défini le paquet (et ses éventuelles versions futur) comme responsable du cycle de vie du fichier dans le système. Ceci a pour intérêt de détecter lors de l’installation d'éventuels conflit entre paquet qui seront à traiter par des primitives particulières quand cela est possible [2] (ce ne sera pas le cas dans cet article). Pour que dpkg puisse clairement identifier le paquet, celui ci doit obligatoirement contenir un fichier de control contenant toutes les informations sur l’identité, la version, l’utilisation du paquet. Vous verrons plus loin dans l’article ou le déposer et comment le construire

Par contre si nous avons ici un moyen simple et efficace pour déployer des fichiers, nous n’avons rien pour dynamiquement configurer l’installation en fonction du système courant.
En effet, souvent, lors de l’installation, il est nécessaire de prendre en considération au mieux des besoins et de l’environnement en initialisant des fichiers de conf selon les autres applications présentes, le contexte réseau éventuel ou même des préférences utilisateurs.

La première approche est alors d’apporter statiquement des configurations par défaut et de les modifier après l’installation. Cette approche fonctionne si et seulement si l'application ne nécessite pas une synchronisation particulière avec d’autres applications du système qui nécessite un redémarrage (par exemple la prise en compte d’un plugin par une application amené par deux paquets différents qu’il faut nécessairement redémarrer)

Les fichiers du responsable


Pour répondre à ce problème spécifique, en plus du fichier de control (obligatoire) et il est possible de définir des fichiers du responsable (postinst, preinst, postrm et prerm). Ces fichiers sont à placer dans un répertoire DEBIAN de notre paquet. Notre paquet devient alors:
(/home/moi) ./monPaquet/usr/bin/monBinaire(/home/moi) ./monPaquet/DEBIAN/control (obligatoire)(/home/moi) ./monPaquet/DEBIAN/postinst (optionnel)(/home/moi) ./monPaquet/DEBIAN/preinst (optionnel)(/home/moi) ./monPaquet/DEBIAN/postrm (optionnel)(/home/moi) ./monPaquet/DEBIAN/prerm (optionnel)
Ces fichiers sont alors exécuter automatiquement par l’outil dpkg [6] pendant l’installation ou la suppression.

Par exemple la phase d’installation exécute les phases suivantes:



De la même façon la suppression d’un paquet exécute les fichiers du responsables comme suit:



Enfin leur combinaison permet d’obtenir le comportement que l’on aura lors d’une mise à jour:



A noter que les scripts peuvent être des simples fichiers qui s'exécutent indifféremment du contexte (pas de la phase) mais qu’il est possible de leur attribuer des spécificités selon que l’on fait justement par exemple une installation ou une mise a jour. Pour cela il est conseillé de s’appuyer sur un squelette de script par défaut ou skeleton [7] (que je ne détaillerai pas ici).

Le fichier de control

Voila maintenant que l’on a construit la structure du deb, il reste finaliser le debian en définissant dans le détail le fichier de control.

Le fichier de control est comme dit sommairement au début de cet article, la pièce d’identitée du paquet debian a construire.

Il se constitue des champs suivant [8] (directement extrait de la documentation):
Package: hello
Version: 2.9-2+deb8u1
Architecture: amd64
Maintainer: Santiago Vila <sanvila@debian.org>
Depends: libc6 (>= 2.14)
Conflicts: hello-traditional
Breaks: hello-debhelper (<< 2.9)
Replaces: hello-debhelper (<< 2.9), hello-traditional
Section: devel
Priority: optional
Homepage: http://www.gnu.org/software/hello/
Description: example package based on GNU hello
      The GNU hello program produces a familiar, friendly greeting.  It
      allows non-programmers to use a classic computer science tool which
      would otherwise be unavailable to them.
      .
      Seriously, though: this is an example of how to do a Debian package.
      It is the Debian version of the GNU Project's `hello world' program
      (which is itself an example for the GNU Project).
  • Le champ « Package » contient le nom du paquet. C'est le nom par lequel les outils de gestion de paquets peuvent le manipuler. Il est habituellement similaire mais pas nécessairement le même que la première chaîne composant le nom de l'archive Debian.
  • Le champ de « Version » donne le numéro de version du composant.
  • Le champ « Architecture » indique pour quel processeur ce binaire particulier a été compilé.
  • Le champ « Depends » donne une liste des paquets qui doivent être installés afin d'installer ce paquet avec succès.
  • La ligne « Section » indique la section où le paquet Debian est conservé sur les sites FTP de Debian.
  • Le champ « Maintainer » contient l'adresse électronique de la personne actuellement responsable de la maintenance du paquet.
  • Le champ « Description » fournit un bref résumé des fonctionnalités du paquet.

Bien sur tous ces champs suivant une nomenclature et de standards pour permettre de normaliser l’utilisation des paquets. Entre autre par exemple il est important de respecter certaines règles d'écriture du numéro de version afin de permettre des mises à jours conforme a l’attendu (voir les schémas du chapitre des fichiers du responsable sur les phases du cycle de vie d’installation, désinstallation et de mise à jour des paquets).

Chaque champs peut avoir son importance même s’ils ne sont pas obligatoire. Il convient donc de bien les étudier afin de prévenir ou de gérer les conflits entre paquets.

Construction du paquet debian

Pour finir cet article, il fait maintenant finaliser le packaging en construisant le .deb. Pour cela il suffit d’appeler la commande dpkg-deb:
dpkg-deb --build $REPERTOIRE_DEBIAN $REPO_DEBIAN/
avec REPERTOIRE_DEBIAN contenant le chemin du debian a packager et REPO_DEBIAN le répertoire de destination ou mettre le deb final (on privilégiera directement le dépôt debian)

Voila le paquet est construit et déposé dans un dépôt, il ne reste qu'à l’installer après une mise a jour du dépôt et un apt-get coté client.

Références

[1] http://blog.valouille.fr/2013/10/creer-un-paquet-debian-vide/
[2] https://www.debian.org/doc/manuals/debian-handbook/sect.package-meta-information.fr.html
[3] https://www.debian.org/doc/manuals/debian-faq/index.fr.html#contents
[4] https://www.debian.org/doc/manuals/debian-faq/ch-pkg_basics.fr.html
[5] http://tcurdt.github.io/jdeb/
[6] https://www.debian.org/doc/debian-policy/#maintainer-script-flowcharts
[7] https://lists.debian.org/debian-mentors/1998/04/msg00004.html
[8] https://www.debian.org/doc/manuals/debian-faq/ch-pkg_basics.fr.html#s-controlfile