Python : un environnement vraiment isolé avec GNU Guix

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


Résumé
Peut-on créer facilement un environnement de tests complètement reproductible pour son application Python ? La solution est-elle vraiment virtualenv ? Un gestionnaire de paquets fonctionnel ne ferait-il pas mieux l'affaire ?

Body

Virtualenv est un logiciel très populaire chez les développeurs Python : il leur permet de définir des environnements virtuels au sein desquels ils peuvent installer des paquets Python sans modifier l'état de leur système. Nous verrons dans cet article que cette approche présente quelques problèmes et montrerons comment les résoudre en utilisant GNU Guix.

De nombreux développeurs Python utilisent aujourd'hui virtualenv, un outil dédié à la création d'environnements virtuels isolés. Sa principale utilité est de permettre d'installer plusieurs versions d'un même paquet Python (par exemple pour tester une application Web avec Django 1.8 et 1.9), ce qui est généralement difficile, sinon impossible, avec le gestionnaire de paquets fourni par une distribution GNU/Linux classique. De plus, ces paquets ne sont pas installés dans le site-packages global, évitant ainsi de « polluer » le système. Malheureusement, virtualenv souffre de quelques défauts que nous commencerons par lister avant de montrer comment, à l'aide de GNU Guix[1], un gestionnaire de paquets fonctionnel, il est possible de construire un environnement de développement réellement isolé du reste du système.

1. Virtualenv : un environnement isolé ?

Voyons tout d’abord comment, actuellement, la plupart des développeurs Python créent un environnement de développement « isolé ».

1.1 Utilisation de virtualenv

On peut facilement créer un environnement « virtuel » embarquant Python 3.4 grâce à la commande suivante :

$ virtualenv -p python3.4 py34

Il suffit ensuite de l'activer, ce qui permet d'y gérer ses paquets sans être root :

$ source py34/bin/activate

(py34)$ pip list

pip (1.5.6)

setuptools (18.8)

(py34)$ python -c "import six"

Traceback (most recent call last):

   File "<string>", line 1, in <module>

ImportError: No module named 'six'

(py34)$ pip install six

Downloading/unpacking six

   Downloading six-1.10.0-py2.py3-none-any.whl

Installing collected packages: six

Successfully installed six

Cleaning up...

(py34)$ python -c "import six"

(py34)$ deactivate

$

On peut remarquer que la bibliothèque six, bien qu'installée sur le système (c'est le paquet python3-six sous Debian) n'est pas disponible au sein de l'environnement virtuel et doit y être installée avec pip.

Il est possible de créer de nombreux environnements virtuels et d'y installer des paquets différents. On peut ainsi lancer les tests d'un logiciel dans plusieurs environnements, fournissant des versions différentes de Python et des dépendances, afin de s'assurer que l'application fonctionnera correctement dans diverses configurations. Malheureusement, l'isolation n'est pas parfaite.

1.2 Dépendances

La gestion des dépendances peut parfois laisser à désirer : le problème principal est que pip, qui est utilisé pour installer des paquets au sein d'un environnement virtuel, ne peut gérer que des paquets Python. Voyons quelques exemples.

1.2.1 Erreur à l’installation

(py34)$ pip install cffi

...

c/_cffi_backend.c:15:17: fatal error: ffi.h: No such file or directory

compilation terminated

error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

Une erreur survient : l'installation du paquet cffi comporte en effet une phase de compilation qui requiert la présence de certains fichiers d'en-tête, dont ffi.h. Il convient donc d'installer libffi-dev, qui fournit ffi.h, (sous Debian) avant de chercher à installer cffi, ce qui est problématique pour deux raisons :

- une partie des dépendances sera gérée par apt : l'environnement n'est donc plus vraiment isolé ;

- la commande pip install cffi donnera des résultats différents selon la machine sur laquelle elle sera exécutée, selon que le fichier d'en-tête ffi.h s'y trouve ou non : on ne peut donc pas reproduire de manière fiable un environnement.

1.2.2 Erreur à l’exécution

Le projet OpenStack utilise pbr (Python Build Reasonableness), une bibliothèque dont l'objectif est de simplifier l'écriture du setup.py. Elle nécessite la présence du binaire Git lors de l'exécution ; que se passe-t-il s'il n'est pas disponible ?

(py34)$ git clone https://github.com/openstack/python-keystoneclient

(py34)$ sudo apt-get remove git

(py34)$ cd python-keystoneclient

(py34)$ python setup.py install

...Are you sure that git is installed?

...

(py34)$ echo $?

1

Certes, cet exemple est un peu tiré par les cheveux : pbr est conçu pour être utilisé dans un dépôt Git, il est relativement normal qu'il ne fonctionne pas lorsque Git n'est pas installé. Toutefois, nous voyons ici que le couple pip/virtualenv n'ayant pas connaissance des dépendances à l'exécution et ces dernières pouvant être installées en dehors de l'environnement virtuel, il est possible de supprimer l'une d'entre elles par erreur.

1.2.3 Impact sur les performances : le cas de PyYAML

Essayons maintenant d'exécuter le code suivant, qui charge un grand nombre de fichiers YAML et affiche à l'écran le temps d'exécution :

import os

import timeit

import yaml



try:

   from yaml import CSafeLoader as SafeLoader

except ImportError:

   from yaml import SafeLoader



def test():

   for f in os.listdir('/tmp/yaml-files'):

      yaml.load(f, Loader=SafeLoader)



if __name__ == '__main__':

   print(timeit.timeit("test()",

      setup="from __main__ import test",

      number=1000))

Le paquet yaml permet de charger un fichier grâce à la méthode load en utilisant un module écrit en Python (SafeLoader) ou en C (CSafeLoader) si la bibliothèque libyaml (le paquet libyaml-dev sous Debian) est présente sur le système. Les performances peuvent être radicalement différentes : sur ma machine, le temps d'exécution est passé de 3,5 secondes à 1 seconde en utilisant la version écrite en C !

Des problèmes de performance pourront donc apparaître sur certaines machines et pas d'autres, quand bien même les environnements virtuels seraient similaires : l'état du reste du système a en effet un impact sur le module utilisé pour charger nos fichiers YAML.

1.3 Variables d’environnement

Un des avantages d'un environnement dit « virtuel » est de permettre de reproduire le comportement d'un programme sur de nombreuses machines différentes, notamment afin que tous les développeurs puissent lancer les tests unitaires dans des conditions similaires. Il est toutefois extrêmement facile d'introduire des variations, même en utilisant virtualenv. Ainsi, les variables d'environnement ne sont pas modifiées lors de l'activation d'un environnement virtuel, or elles peuvent changer le fonctionnement d'un programme du tout au tout :

$ LANG=C python3 -c "print('é')"

Unable to decode the command from the command line:

UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 7:

surrogates not allowed


$ LANG=en_US.UTF-8 python3 -c "print('é')"

é

Deux développeurs ayant deux valeurs différentes pour la variable LANG verront donc deux comportements très différents pour ce programme Python pourtant très simple.

2. Construire son environnement avec Guix

Idéalement, nous aimerions conserver les avantages de virtualenv (construire des environnements virtuels, ne pas polluer notre système en y installant des paquets, gérer plusieurs versions d'une bibliothèque) sans rencontrer les problèmes que nous venons de lister. C'est chose possible grâce à GNU Guix !

2.1 Manuellement

GNU Guix est un gestionnaire de paquets fonctionnel dont les avantages et l'architecture sont détaillés dans GNU/Linux Magazine n° 194 pages 46 à 50. Il peut également être utilisé pour offrir des fonctionnalités similaires à celles proposées par virtualenv, grâce à la commande guix environment. Elle prend en argument un ou plusieurs noms de paquets disponibles dans GNU Guix :

$ guix environment python-keystoneclient

Dans GNU Guix, les paquets Python portent les mêmes noms que sur PyPI, mais sont préfixés par python-, pour les paquets Python 3 (la version par défaut), ou par python2-. La commande précédente crée un environnement dans lequel sont disponibles les dépendances du paquet python-keystoneclient. Nous pouvons vérifier que le paquet pytest, requis pour lancer les tests de python-keystoneclient, est bien disponible et a été construit par Guix :

$ python

>>> import pytest

>>> pytest.__file__

'/gnu/store/n7pr4jnw9p51vmyblw41ppimhpg5f9js-profile/lib/python3.4/site-packages/pytest-2.6.1-py3.4.egg/pytest.py'

Nous nous éloignons toutefois légèrement de l'approche de virtualenv, qui permet d'installer une liste de paquets plutôt que leurs dépendances ; on peut retrouver ce comportement en utilisant l'option --ad-hoc :

$ guix environment --ad-hoc python python-keystoneclient

$ python

>>> import keystoneclient

>>>

2.2 Une bien meilleure isolation

Nous pouvons donc reproduire le comportement de virtualenv et retrouver ses avantages en utilisant GNU Guix : nous pouvons en effet utiliser des paquets Python sans les installer réellement sur notre système et nous pouvons en installer plusieurs versions différentes si elles sont empaquetées. Mais qu'avons-nous vraiment à y gagner ?

2.2.1 Gestion complète des dépendances

L'isolation du reste du système est bien meilleure qu'avec virtualenv : en effet, toutes les dépendances sont spécifiées dans un paquet GNU Guix. Si l'on revient rapidement à la première partie de l'article, cela signifie que :

- l'installation de cffi ne peut pas échouer à cause de l'absence du fichier d'en-tête ffi.h : libffi est en effet une dépendance de cffi ;

- les dépendances à l'exécution sont spécifiées, même si ce ne sont pas des paquets Python : le paquet git est une dépendance du paquet python-pbr ;

- le paquet python-pyyaml sera toujours installé avec les extensions C, puisque libyaml est une de ses dépendances.

Nous pouvons vérifier tout cela en étudiant les dépendances des paquets grâce à la commande guix package :

$ guix package -s python-cffi | recsel -p dependencies

dependencies: ... python-pytest-2.6.1 ...


$ guix package -s python-pbr | recsel -p dependencies

dependencies: git-2.6.3 ...


$ guix package -s python-pyyaml | recsel -p dependencies

dependencies: libyaml-0.1.5 ...

2.2.2 Variables d'environnement sous contrôle

Nous avons vu que virtualenv ne modifiait pas les variables d'environnement et que cela pouvait être un problème pour reproduire un environnement correctement. GNU Guix permet de supprimer ces variables grâce à l'option --pure :

$ guix environment --ad-hoc --pure python python-keystoneclient

$ echo $PATH

/gnu/store/36106pz9mjkbp0ikb6f3cqsxfl0mc5ay-profile/bin

$ echo $PYTHONPATH

/gnu/store/36106pz9mjkbp0ikb6f3cqsxfl0mc5ay-profile/lib/python3.4/site-packages

Les variables PATH et PYTHONPATH ne contiennent plus qu'un seul chemin, qui mène aux binaires et aux bibliothèques d'un profil GNU Guix temporaire, dans lequel ne sont installés que les paquets python et python-keystoneclient. Les autres variables d'environnement sont supprimées, à l'exception de HOME, USER, LOGNAME, DISPLAY, TERM, TZ et PAGER.

2.2.3 La cerise sur le gâteau : un conteneur !

Nous venons de voir que la variable PATH était « purifiée » grâce à l'option --pure, ce qui devrait nous empêcher d'appeler une commande installée en dehors de notre environnement virtuel. Toutefois, il est encore possible d'utiliser un chemin absolu :

$ guix environment --ad-hoc --pure python

[env]$ make -v

bash: make: command not found

[env]$ /usr/bin/make -v

GNU Make 4.0

...

Pour pallier ce problème, la commande guix environment fournit une option --container, qui, comme son nom l'indique, permet de placer l'environnement virtuel dans un conteneur :

$ guix environment --ad-hoc --pure --container python

[env]sh-4.3# /usr/bin/make -v

sh: /usr/bin/make: No such file or directory

Nous avons donc désormais un environnement particulièrement bien isolé de notre système.

2.3 Aller plus loin avec guix-tox

De nombreux projets utilisent Tox [2], un outil en ligne de commande permettant de gérer des environnements virtuels, notamment pour lancer les tests unitaires :

$ cd monprojet/

$ tox -l # Listons les environnements définis dans tox.ini

py26

py27

py33

py34

pep8

La commande tox -epy27 utilisera virtualenv afin de créer un environnement virtuel, puis y lancera les tests en utilisant Python 2.7. Le but de cet article n'est pas de faire une présentation complète de Tox, mais il convient d'indiquer que des configurations complexes peuvent être définies dans le fichier tox.ini, ce qui en fait un outil de gestion d'environnements virtuels très pratique.

Malheureusement, Tox utilise virtualenv, ce qui nous expose aux problèmes définis précédemment. Une preuve de concept non officielle remplace virtualenv par tox dans Guix [3]. Un exemple d'utilisation :

$ GUIX_TOX_EXTRA=openssl guix-tox --env=guix -epy34

...

Ran 1133 (+1132) tests in 30.764s

PASSED (id=65, skips=4)

Nul besoin de modifier la configuration. De même, les commandes sont les mêmes,à deux exceptions près :

- l'option --env qui permet de sélectionner le gestionnaire d'environnements virtuels souhaité (guix ou virtualenv);

- la variable d'environnement GUIX_TOX_EXTRA qui permet de spécifier des dépendances non disponibles sur PyPI : ici le binaire openssl, utilisé dans les tests.

Conclusion

Nous avons vu les défauts de virtualenv qui nous empêchent d'obtenir des environnements virtuels de développement réellement isolés du reste de notre machine et parfaitement reproductibles, et nous savons désormais comment corriger ces problèmes grâce à GNU Guix. Toutefois, ce dernier n'est pas un remplacement miraculeux pour le couple pip/virtualenv : en effet, tous les paquets disponibles sur PyPI ne sont pas présents dans GNU Guix. Toutefois, l'approche fonctionnelle nous semble plus robuste que les solutions existantes.

Références

[1] Site officiel de GNU Guix :http://www.gnu.org/s/guix

[2] Site officiel de Tox : https://tox.readthedocs.org/

[3] Dépôt Git de guix-tox : https://git.framasoft.org/Steap/guix-tox




Article rédigé par

Par le(s) même(s) auteur(s)

Faut s’démener au FOSDEM !

Magazine
Marque
GNU/Linux Magazine
Numéro
213
Mois de parution
mars 2018
Résumé
Le FOSDEM (Free and OpenSource Developers European Meeting) est tellement incontournable qu’une part non négligeable des auteurs de GLMF s’y rend chaque année. De nombreuses mains et points de vue ont donc participé à ce compte-rendu, pour vous faire part du foisonnement de ce week-end intense.

Les derniers articles Premiums

Les derniers articles Premium

Quarkus : applications Java pour conteneurs

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

Initié par Red Hat, il y a quelques années le projet Quarkus a pris son envol et en est désormais à sa troisième version majeure. Il propose un cadre d’exécution pour une application de Java radicalement différente, où son exécution ultra optimisée en fait un parfait candidat pour le déploiement sur des conteneurs tels que ceux de Docker ou Podman. Quarkus va même encore plus loin, en permettant de transformer l’application Java en un exécutable natif ! Voici une rapide introduction, par la pratique, à cet incroyable framework, qui nous offrira l’opportunité d’illustrer également sa facilité de prise en main.

De la scytale au bit quantique : l’avenir de la cryptographie

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

Imaginez un monde où nos données seraient aussi insaisissables que le célèbre chat de Schrödinger : à la fois sécurisées et non sécurisées jusqu'à ce qu'un cryptographe quantique décide d’y jeter un œil. Cet article nous emmène dans les méandres de la cryptographie quantique, où la physique quantique n'est pas seulement une affaire de laboratoires, mais la clé d'un futur numérique très sécurisé. Entre principes quantiques mystérieux, défis techniques, et applications pratiques, nous allons découvrir comment cette technologie s'apprête à encoder nos données dans une dimension où même les meilleurs cryptographes n’y pourraient rien faire.

Les nouvelles menaces liées à l’intelligence artificielle

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

Sommes-nous proches de la singularité technologique ? Peu probable. Même si l’intelligence artificielle a fait un bond ces dernières années (elle est étudiée depuis des dizaines d’années), nous sommes loin d’en perdre le contrôle. Et pourtant, une partie de l’utilisation de l’intelligence artificielle échappe aux analystes. Eh oui ! Comme tout système, elle est utilisée par des acteurs malveillants essayant d’en tirer profit pécuniairement. Cet article met en exergue quelques-unes des applications de l’intelligence artificielle par des acteurs malveillants et décrit succinctement comment parer à leurs attaques.

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 58 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous