Gestion de paquets sûre et flexible avec GNU Guix

Magazine
Marque
GNU/Linux Magazine
Numéro
194
Mois de parution
juin 2016
Spécialité(s)


Résumé
Les distributions GNU/Linux classiques sont mal aimées. Cet article revient sur leurs limites et donne un aperçu de la solution que propose le projet GNU avec Guix, un gestionnaire de paquets transactionnel, flexible et personnalisable.

Body

Linux Weekly News dénombre plus de 500 distributions GNU/Linux [1] et y voit une « célébration de la diversité ».  Avec ça, le problème de la distribution de logiciels a été largement exploré, et probablement largement résolu, se dit-on.  Et pourtant !

Cet article traite d'un nouveau gestionnaire de paquets, GNU Guix [2], qui fournit mises à jour transactionnelles, retours en arrière, et est extensible et personnalisable à souhait.

Les distributions « classiques » ont certaines limitations, comme l'impossibilité de revenir en arrière après une mise à jour ou la difficulté de reproduire un environnement logiciel exact. La profusion de gestionnaires de paquets annexes ajoute à la confusion, et l'utilisation de Docker contourne ces difficultés sans les corriger. GNU Guix met en œuvre une gestion des paquets fonctionnelle qui entend résoudre certains de ces problèmes.

1. Le problème

Avec une distribution GNU/Linux « classique », une mise à jour est toujours quitte ou double : il ne vaut mieux pas qu'une coupure électrique intervienne pendant la mise à jour (on risque de se retrouver avec un système inutilisable), ou qu'un des nouveaux paquets ne fonctionne pas (difficile de revenir en arrière).

Une fois que l'on a une machine avec une distribution classique qui fonctionne bien, on aimerait pouvoir reproduire son état, c'est-à-dire l'ensemble des paquets installés et la configuration associée, sur une autre machine par exemple. C'est chose difficile, car on n'est jamais sûr de pouvoir réinstaller les mêmes paquets aux mêmes versions, et parce qu'une partie de la configuration du système échappe complètement au gestionnaire de paquets. Le fait qu'il soit devenu courant de combiner beaucoup de gestionnaires de paquets (Bower, Cabal, CPAN, npm, pip, etc.) rend le contrôle de l'environnement logiciel plus difficile encore.

Docker permet de contourner la difficulté en permettant de « figer » une image de l'état du système. Pour y parvenir, on va stocker dans un Dockerfile la séquence de commandes permettant a priori d'atteindre l'état souhaité.

Cette approche risque de ne pas être reproductible, puisque l'effet des commandes dépend de l'état des dépôts de code source des gestionnaires de paquets utilisés dans l'image Docker. Elle favorise un empilement de couches sans donner une vision globale dans la composition des paquets. Enfin, elle a d'autres inconvénients comme l'utilisation inefficace du stockage et la difficulté de s'assurer que chaque image contient les mises à jour de sécurité critiques.

2. La gestion de paquets « fonctionnelle »

Aux alentours de 2004, Eelco Dolstra a commencé son travail de thèse sur Nix [3], un gestionnaire de paquets fonctionnel. Ici « fonctionnel » fait référence non pas au fait qu'il fonctionne (bien qu'il fonctionne), mais au paradigme de gestion de paquets, qui s'inspire de la programmation fonctionnelle telle que mise en œuvre par des langages comme OCaml, Haskell ou Scheme.

L'idée est de voir chaque paquet comme une valeur immuable, résultat de l'application d'une fonction de compilation à un ensemble d'arguments. Par exemple, le binaire du logiciel GIMP est vu comme le résultat d'appliquer une fonction qui lance ./configure && make && make install à un ensemble d'entrées : le source de GIMP, GCC, la bibliothèque standard du C (libc), la bibliothèque GTK+, etc. À son tour, GTK+ est le résultat de cette fonction appliquée à d'autres arguments. De cette façon, on exprime un graphe de dépendances tel que celui de la figure 1.

coreutils-graph

Fig. 1 : Graphe de dépendances à la compilation des outils de base GNU (Coreutils) produit par la commande guix graph coreutils.

GNU Guix a été créé en 2013 pour reprendre les fondements de Nix, mais en fournissant une interface de programmation unifiée et embarquée dans le langage Scheme, un langage de programmation fonctionnelle générique, mis en œuvre par GNU Guile [3].  De cette façon, Guix a accès à tout Guile - compilateur, dévermineur, bibliothèques, environnement de développement, etc. - et tout Guix est accessible en Scheme.

Autrement dit, Guix est une bibliothèque Scheme comme une autre, et la distribution toute entière est une bibliothèque où chaque paquet est un objet Scheme. Le but recherché, et atteint, est que l'on puisse simplement écrire des fonctions qui manipulent des paquets, écrire des interfaces utilisateurs et autres applications qui se servent de Guix. Guix fournit ainsi un langage d'empaquetage universel (s'applique à des paquets C, mais aussi PyPI, RubyGems, ELPA, etc.), plusieurs interfaces utilisateurs (ligne de commandes, Emacs, et Web), un outil de gestion d'environnements de développement (guix environment, comme Virtualenv, rvm, etc., mais pour tout type de paquet), un outil de vérification des paquets (guix lint), un outil de mise à jour des recettes de paquets (guix refresh), et d'autres.

Mais l'enjeu de cette approche est, plus généralement, de fournir un système transparent et bidouillable que les usagers puissent s'approprier plus facilement, pour exercer la liberté n°1 que le logiciel libre leur donne [4].

3. Installation

Il est possible d'installer Guix comme un gestionnaire de paquets supplémentaire (un de plus !) sur votre distribution GNU/Linux. Il cohabitera pacifiquement avec la distribution et sans interférence : Guix installe ses affaires dans /gnu/store comme nous le verrons plus bas, et vous pouvez à tout moment ajouter ou enlever les paquets installés avec Guix de PATH et autres variables.

L'installation peut se faire de plusieurs façons comme détaillé dans le manuel de Guix [4], le plus simple étant d'utiliser les binaires précompilés fournis par le projet.

Le démon guix-daemon prend en charge la compilation des paquets et/ou le téléchargement de binaires précompilés provenant de sources autorisées. Pour que la compilation de paquets puisse être vue comme une fonction « pure » et soit reproductible, ce démon s'assure que la compilation est effectuée dans un environnement isolé, un conteneur.

4. En avant !

Une fois guix-daemon démarré, on peut déjà lancer une construction de paquets :

$ guix build hello

Le fichier suivant sera téléchargé:

   /gnu/store/zby49aqfbd9w9br4l52mvb3y6f9vfv22-hello-2.10

Found valid signature for /gnu/store/zby49aqfbd9w9br4l52mvb3y6f9vfv22-hello-2.10

From https://mirror.hydra.gnu.org/nar/…-hello-2.10

Downloading zby49a…-hello-2.10 (170KiB installed)...

 https://mirror.hydra.gnu.org/nar/…-hello-2.10 737KiB/s 00:00 | 49KiB transferred

/gnu/store/zby49aqfbd9w9br4l52mvb3y6f9vfv22-hello-2.10

$ /gnu/store/zby49aqfbd9w9br4l52mvb3y6f9vfv22-hello-2.10/bin/hello

Bonjour, le monde !

Ce qu'on voit ici, c'est qu'à une compilation du paquet GNU Hello, guix build a substitué un binaire pré-compilé téléchargé directement depuis mirror.hydra.gnu.org. Le résultat est ce long nom de répertoire en /gnu/store qui contient effectivement la commande hello.

Tout ce que produit Guix arrive dans le répertoire /gnu/store, qu'on appelle l'entrepôt (le store en anglais). Par exemple, hello a notamment une dépendance à l'exécution sur la bibliothèque standard du langage C (libc), qui elle est aussi dans l'entrepôt, comme le montre cette commande qui liste les dépendances à l'exécution :

$ guix gc --references /gnu/store/zby49aqfbd9w9br4l52mvb3y6f9vfv22-hello-2.10

/gnu/store/8m00x5x8ykmar27s9248cmhnkdb2n54a-glibc-2.22

/gnu/store/v39bh3ln3ncnzhyw0kd12d46kww9747v-gcc-4.9.3-lib

/gnu/store/zby49aqfbd9w9br4l52mvb3y6f9vfv22-hello-2.10

Cette longue chaîne en base32 dans les chemins ci-dessus est en fait le condensé SHA256 de toutes les dépendances utilisées à la compilation pour produire ce résultat. Dans le cas de Hello, les dépendances à la compilation sont : le source de Hello, le script de compilation, mais aussi la libc, le compilateur, Bash, coreutils, sed, grep, awk, etc. Vraiment toutes les dépendances ! De cette manière, on a vraiment une correspondance directe entre le source, y compris les outils de compilation, et le binaire produit — c’est une formalisation de la notion de Corresponding Source telle que décrite dans la GNU GPL.

Cette correspondance source/binaire est cruciale.  Elle signifie que les usagers n'ont pas à faire confiance aveuglément à un fournisseur de binaire : les usagers peuvent à tout moment compiler localement et vérifier qu'ils obtiennent le même résultat, à l'octet près, que le fournisseur de binaires. C'est exactement ce que vérifie la commande guix challenge.

5. Les profils

Évidemment, on n’a pas vraiment envie de taper ces chemins à la main. La commande guix package permet à chaque usager (pas besoin d'être root) de maintenir des profils où sont installés des paquets. Il suffit de rajouter un profil dans PATH et ses paquets deviennent disponibles. Par exemple, pour installer Emacs et Vim (on ne sait jamais) dans son profil par défaut, ~/.guix-profile, on fait simplement :

$ guix package --install emacs vim

Les paquets suivants seront installés:

   vim  7.4     /gnu/store/…-vim-7.4

   emacs        24.5    /gnu/store/…-emacs-24.5

Les dérivations suivantes seront compilées:

   /gnu/store/...-profile.drv

   /gnu/store/...-gtk-icon-themes.drv

   /gnu/store/...-ca-certificate-bundle.drv

   /gnu/store/...-info-dir.drv

Le fichier suivant sera téléchargé:

   /gnu/store/...-vim-7.4

[...]

2 paquets dans le profil

Il pourrait être nécessaire de définir les variables d'environnement suivantes:

   export PATH="/home/alice/.guix-profile/bin"

   export INFOPATH="/home/alice/.guix-profile/share/info"

$ guix package --list-installed

emacs   24.5    out     /gnu/store/...-emacs-24.5

vim     7.4     out     /gnu/store/...-vim-7.4

Guix est attentionné et nous indique même les variables d’environnement à définir pour pouvoir utiliser les paquets installés. Pour que ces variables soient automatiquement définies, on peut rajouter cette ligne dans ~/.bash_profile :

GUIX_PROFILE="$HOME/.guix-profile" . "$GUIX_PROFILE/etc/profile"

Cette opération est transactionnelle : on peut taper <Ctrl> + <C> à tout moment, et soit à la fois Emacs et Vim seront installés, soit aucun ne le sera. C’est aussi le cas pour des transactions plus complexes :

$ guix package -r vim -i nano

Le paquet suivant sera supprimé:

   vim  7.4     /gnu/store/…-vim-7.4

Le paquet suivant sera installé:

   nano 2.5.3   /gnu/store/…-nano-2.5.3

[...]

2 paquets dans le profil

Chaque transaction donne lieu à une nouvelle génération du profil :

$ guix package --list-generations

Génération 1    Mar 30 2016 14:29:05

  emacs 24.5    out     /gnu/store/...-emacs-24.5

  vim   7.4     out     /gnu/store/...-vim-7.4

Génération 2    Mar 30 2016 14:39:02    (actuel)

  emacs 24.5    out     /gnu/store/...-emacs-24.5

  nano  2.5.3   out     /gnu/store/...-nano-2.5.3

On peut à tout moment basculer vers une autre génération, la précédente par exemple :

$ guix package --roll-back

switched from generation 2 to 1

Ce mécanisme vaut aussi pour les mises à jour (avec --upgrade)... et c'est très rassurant !

6. Maîtriser ses environnements logiciels

Un profil n'est rien d'autre qu'une forêt de liens symboliques :

$ readlink -f ~/.guix-profile

/gnu/store/...-profile

$ readlink ~/.guix-profile/bin/emacs

/gnu/store/...-emacs-24.5/bin/emacs

On peut donc en créer autant qu'on veut, et Guix saura nous dire quelles sont les variables d'environnement qui vont bien :

$ guix package -p ~/dev-python -i python@2.7 python2-numpy

Les paquets suivants seront installés:

   python2-numpy        1.10.4  /gnu/store/…-python2-numpy-1.10.4

   python       2.7.10  /gnu/store/…-python-2.7.10

2 paquets dans le profil

Il pourrait être nécessaire de définir les variables d'environnement suivantes:

   export PATH="/home/ludo/dev-python/bin"

   export PYTHONPATH="/home/ludo/dev-python/lib/python2.7/site-packages"

$ guix package -p ~/dev-python --search-paths

export PATH="/home/ludo/dev-python/bin"

export PYTHONPATH="/home/ludo/dev-python/lib/python2.7/site-packages"

$ eval `guix package -p ~/dev-python --search-paths`

$ python -c "import numpy; print(numpy.version.version)"

1.10.4

L'outil guix environment permet de créer des environnements de développement temporaires, à la volée. Par exemple, pour un environnement Python 2.x avec Numpy comme ci-dessus, on pourrait simplement faire :

$ guix environment --ad-hoc python@2 python2-numpy -- \

     python -c "import numpy; print(numpy.version.version)"

1.10.4

L'outil peut aussi nous mettre dans l'environnement de développement d'un logiciel spécifique. Par exemple, quelqu'un voulant bidouiller GIMP peut récupérer le source puis se mettre dans un environnement d'où on pourra recompiler la bête :

$ tar xf `guix build --source gimp`

$ cd gimp-2.8.14

$ guix environment gimp --container

[env]# echo $PATH

/gnu/store/…-profile/bin:/gnu/store/…-profile/sbin

[env]# echo $C_INCLUDE_PATH

/gnu/store/…-profile/include

[env]# echo $PKG_CONFIG_PATH

/gnu/store/…-profile/lib/pkgconfig

[env]# ./configure && make

Ici guix environment a démarré un Bash avec l'invite [env] dans lequel tous les paquets nécessaires pour compiler GIMP sont disponibles, et où toutes les variables requises sont définies. Plus simple que de le faire à la main, et sans interférence sur le reste du système !

L'option --container est facultative ; elle permet de créer l'environnement dans un conteneur isolé du reste du système, où seuls une partie de /gnu/store et le répertoire courant sont visibles, grâce à l'utilisation des user namespaces du noyau. Cela garantit d'avoir un environnement « propre » et isolé.

Un prochain article explorera l'utilisation de guix environment pour du développement Python.

7. Bidouiller la distrib'

Guix est conçu pour faciliter la bidouille.  En ligne de commandes, on peut déjà construire ou installer un paquet en précisant un code source différent et/ou des dépendances différentes :

# Compile une "release candidate" de Emacs.

$ guix build emacs --with-source=./emacs-25.1rc2.tar.gz

# Recompile Git en remplaçant OpenSSL par LibreSSL dans tout

# son arbre de dépendances.

$ guix build git --with-input=openssl=libressl

Puisque toutes les structures de données et interfaces de programmation de Guix sont exposées, on peut aussi définir des variantes de paquets existants. Par exemple, pour créer une variante de Emacs qui ne dépende pas de D-Bus, on peut définir une variable emacs-sans-dbus dont la valeur est un paquet qui hérite du paquet emacs, mais retire la dépendance sur D-Bus, puis ajouter le fichier à GUIX_PACKAGE_PATH :

$ cat > /tmp/my-emacs.scm <<EOF

(define-module (my-emacs)

  #:use-module (guix packages)

  #:use-module (gnu packages emacs)

  #:use-module (srfi srfi-1))  ;manipulation de listes

(define-public emacs-sans-dbus

  (package (inherit emacs)

    (name "emacs-sans-dbus")

    (inputs (alist-delete "dbus" (package-inputs emacs)))))

EOF

$ export GUIX_PACKAGE_PATH=/tmp

$ guix package --list-available=emacs

emacs   24.5    out     gnu/packages/emacs.scm:69:2

[...]

emacs-sans-dbus 24.5    out     my-emacs.scm:7:2

$ guix build emacs-sans-dbus --dry-run

La dérivation suivante serait compilée:

   /gnu/store/…-emacs-sans-dbus-24.5.drv

Les commandes ont automatiquement pris en compte notre Emacs personnalisé, et celui-ci va magiquement suivre les changements et mises à jour faites au paquet emacs de la distribution, avec juste notre modification.

Les usagers peuvent donc facilement maintenir un dépôt de paquets privé avec leurs personnalisations, à la personal package archive (PPA), ou encore publier leurs propres définitions de paquets. Un aspect que nous n'avons qu'effleuré ci-dessus est la « programmabilité » : on peut par exemple écrire des fonctions qui renvoient des paquets en fonction des paramètres, ou encore réécrire le graphe de dépendance d'un paquet donné, comme le fait l'option --with-input ci-dessus. La frontière entre utilisation et développement de la distribution est floue !

Conclusion

GNU Guix permet à des utilisateurs non privilégiés d'installer des paquets de façon transactionnelle, de créer des environnements logiciels contrôlés, et de personnaliser la distribution. Guix fournit actuellement plus de 3 200 logiciels libres. Guix et GuixSD sont encore considérés en version beta, mais s'approchent dangereusement de la 1.0. La dernière version est sortie fin mars 2016, fruit du travail d'une cinquantaine de personnes - rejoignez-nous ! Dans un prochain article, nous verrons comment cela se généralise à une distribution tout entière avec GuixSD.

Références

[1] « The LWN.net Linux Distribution List », https://lwn.net/Distributions/

[2] Site officiel de GNU Guix : https://gnu.org/software/guix/

[3] Site officiel de GNU Guile : https://gnu.org/software/guile/

[4] Instructions d'installation de Guix : https://gnu.org/software/guix/download/

[5] Site officiel de Nix : https://nixos.org/nix/

[6] « Qu'est-ce que le logiciel libre ? », https://gnu.org/philosophy/free-sw.fr.html




Article rédigé par

Les derniers articles Premiums

Les derniers articles Premium

Game & Watch : utilisons judicieusement la mémoire

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Au terme de l'article précédent [1] concernant la transformation de la console Nintendo Game & Watch en plateforme de développement, nous nous sommes heurtés à un problème : les 128 Ko de flash intégrés au microcontrôleur STM32 sont une ressource précieuse, car en quantité réduite. Mais heureusement pour nous, le STM32H7B0 dispose d'une mémoire vive de taille conséquente (~ 1,2 Mo) et se trouve être connecté à une flash externe QSPI offrant autant d'espace. Pour pouvoir développer des codes plus étoffés, nous devons apprendre à utiliser ces deux ressources.

Raspberry Pi Pico : PIO, DMA et mémoire flash

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Le microcontrôleur RP2040 équipant la Pico est une petite merveille et malgré l'absence de connectivité wifi ou Bluetooth, l'étendue des fonctionnalités intégrées reste très impressionnante. Nous avons abordé le sujet du sous-système PIO dans un précédent article [1], mais celui-ci n'était qu'une découverte de la fonctionnalité. Il est temps à présent de pousser plus loin nos expérimentations en mêlant plusieurs ressources à notre disposition : PIO, DMA et accès à la flash QSPI.

Programmation des PIO de la Raspberry Pi Pico

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

La carte Pico de Raspberry Pi est appréciable à bien des égards. Ses ressources, son prix, ses deux cœurs ARM... Mais ce morceau de silicium qu'est le RP2040 renferme une fonctionnalité unique : des blocs PIO permettant de créer librement des périphériques supplémentaires qu'il s'agisse d'éléments standardisés comme SPI, UART ou i2c, ou des choses totalement exotiques et très spécifiques à un projet ou un environnement donné. Voyons ensemble comment prendre en main cette ressource et explorer le monde fantastique des huit machines à états de la Pico !

Les listes de lecture

8 article(s) - ajoutée le 01/07/2020
Découvrez notre sélection d'articles pour faire vos premiers pas avec les conteneurs, apprendre à les configurer et les utiliser au quotidien.
11 article(s) - ajoutée le 02/07/2020
Si vous recherchez quels sont les outils du DevOps et comment les utiliser, cette liste est faite pour vous.
8 article(s) - ajoutée le 02/07/2020
Il est essentiel d'effectuer des sauvegardes régulières de son travail pour éviter de perdre toutes ses données bêtement. De nombreux outils sont disponibles pour nous assister dans cette tâche.
Voir les 49 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous