Introduction
Avec Python, lors de l’installation d’un produit, par exemple Alerta server, beaucoup de dépendances peuvent être aussi installées.
python@vpsfrsqlpac2$ pip3 search alerta
alerta (7.4.0) - Alerta unified command-line tool and SDK alerta-server (7.4.1) - Alerta server WSGI application ...
python@vpsfrsqlpac2$ pip3 install alerta-server
Installing collected packages: pymongo, certifi, urllib3, chardet, idna, requests, MarkupSafe, Jinja2, Werkzeug, itsdangerous, click, Flask, blinker, sentry-sdk, Flask-Compress, pyyaml, six, python-dateutil, pycparser, cffi, bcrypt, cryptography, pyparsing, Flask-Cors, PyJWT, pytz, alerta-server Running setup.py install for MarkupSafe ... done Running setup.py install for blinker ... done Running setup.py install for Flask-Compress ... done Running setup.py install for pyyaml ... done Running setup.py install for pycparser ... done Successfully installed Flask-1.1.1 Flask-Compress-1.4.0 Flask-Cors-3.0.8 Jinja2-2.10.3 MarkupSafe-1.1.1 PyJWT-1.7.1 Werkzeug-0.16.0 alerta-server-7.4.1 bcrypt-3.1.7 blinker-1.4 certifi-2019.11.28 cffi-1.13.2 chardet-3.0.4 click-7.0 cryptography-2.8 idna-2.8 itsdangerous-1.1.0 pycparser-2.19 pymongo-3.10.1 pyparsing-2.4.6 python-dateutil-2.8.1 pytz-2019.3 pyyaml-5.3 requests-2.22.0 sentry-sdk-0.14.0 six-1.13.0 urllib3-1.25.7
Il devient fastidieux de gérer la pollution de la distribution globale Python: dépendances, conflits de versions de packages, binaires…
De plus, certains packages peuvent être nécessaires pour un seul utilisateur/produit.
Par défaut, tous les packages et les dépendances sont téléchargés et installés dans $PYTHON_HOME/lib/python<version>/site-packages
.
Le package Python virtualenv
résout ce type de problème. Un utilisateur peut gérer et exécuter son propre environnement isolé sans
aucune installation de package dans la distribution Python globale. L’environnement virtuel est indépendant de la distribution source Python,
cependant une option permet l’utilisation des packages installés dans la distribution source.
Dans le schéma ci-dessous :
- L’environnement virtuel
py-influxdb
est complètement isolé et 2 packages y sont installés. - Dans l’environnement virtuel
py-alerta
pour l’utilisateuralerta
, les packagesalerta
sont installés, mais l’environnement peut aussi utiliser les packages installés dans la distribution système (PyMySQL, psycopg2, pymongo
).
Ainsi, les packages utilisés par la plupart des utilisateurs peuvent être installés dans la distribution système, et les packages nécessaires à un seul utilisateur/produit dans un environnement virtuel avec virtualenv.
Voyons comment créer et utiliser des environnements virtuels, et comment les packages et versions sont gérés dans les distributions virtuelles et système.
Contexte
Dans cet article, Python 3.8 a été compilé et installé dans le répertoire personnalisé /opt/python/python-3.8
. Notre philosophie :
aucune installation dans les répertoires systèmes du système d’exploitation (/usr
…).
Le compte python
(groupe : wapp
) est le propriétaire de la distribution système /opt/python/python-3.8
.
L’environnement Python 3.8 est chargé en sourçant le fichier $HOME/.python-3.8
ci-dessous.
$HOME/.python-3.8
#!/bin/bash
export PYHOME=/opt/python/python-3.8
export PATH=$PYHOME/bin:$PATH
export LD_LIBRARY_PATH=$PYHOME/lib:$LD_LIBRARY_PATH
export PYTHONPATH=/opt/python/packages
export PGLIB=/opt/postgres/pgsql-11/lib
export LD_LIBRARY_PATH=$PGLIB:$LD_LIBRARY_PATH
python@vpsfrsqlpac2$ . $HOME/.python-3.8 python@vpsfrsqlpac2$ which python3 python@vpsfrsqlpac2$ which pip3
/opt/python/python-3.8/bin/python3 /opt/python/python-3.8/bin/pip3
La variable d’environnement personnalisée $PYHOME
spécifie le répertoire racine de Python 3.8 (/opt/python/python-3.8
).
Installation de virtualenv (optionnel)
Un environnement virtuel est créé avec 2 méthodes possibles :
virtualenv
(package PyPI).python3 -m venv
(mode natif).
virtualenv
présente l’avantage d’être verbeux lors de la création de l’environnement virtuel
par rapport au mode natif.
La méthode native autorise quant à elle la création de plusieurs environnements virtuels à la fois.
Pour installer le package virtualenv
dans la distribution globale avec pip3
:
python@vpsfrsqlpac2$ pip3 install virtualenv
Collecting virtualenv Downloading virtualenv-16.7.9-py2.py3-none-any.whl (3.4 MB) |..............................| 3.4 MB 4.3 MB/s Installing collected packages: virtualenv Successfully installed virtualenv-16.7.9
virtualenv
est installé dans le répertoire $PYHOME/bin
.
Créer et utiliser des environnements virtuels
Créer un référentiel où tous les environnements virtuels seront installés. Il s’agira d’un simple répertoire créé en dehors des distributions python :
python@vpsfrsqlpac2$ cd /opt/python
python@vpsfrsqlpac2$ mkdir virtualenvs
La variable d’environnement $PYVENV
identifie ce répertoire.
python@vpsfrsqlpac2$ export PYVENV=/opt/python/virtualenvs
Créons l’environnement virtuel py-alerta
qui sera utilisé par le compte alerta
:
- Avec
virtualenv
:python@vpsfrsqlpac2$ virtualenv $PYVENV/py-alerta
Using base prefix '/opt/python/python-3.8' New python executable in /opt/python/virtualenvs/py-alerta/bin/python3.8 Also creating executable in /opt/python/virtualenvs/py-alerta/bin/python Installing setuptools, pip, wheel... done.
- En mode natif :
python@vpsfrsqlpac2$ python3 -m venv --copies $PYVENV/py-alerta
L’option
--copies
est utilisée pour copier les binaires et librairies Python dans l’environnement virtuel : en évitant les liens symboliques, les futures montées de version de Python seront facilitées (sujet non abordé ici).
L’interpréteur Python (python3
…) est copié dans le répertoire $PYVENV/py-alerta/bin
. Le répertoire
$PYVENV/py-alerta/lib/python3.8
est également préparé à partir de $PYHOME/lib/python3.8
pour l’installation des packages
puis les packages pip
et setuptools
y sont copiés.
La commande peut être exécutée plusieurs fois, cela n’altère pas les packages éventuellement déjà existants sauf
si l’option --clear
a été utilisée, seuls les binaires et scripts source sont écrasés (python3
, pip3
, activate
…)
Exécuter le script $PYVENV/py-alerta/bin/activate
pour utiliser l’environnement virtuel :
python@vpsfrsqlpac2$ source $PYVENV/py-alerta/bin/activate
(py-alerta) python@vpsfrsqlpac2:~$
L’invite est modifiée avec le nom de l’environnement virtuel (préfixe). La variable d’environnement $PATH
est modifiée en conséquence :
(py-alerta) python@vpsfrsqlpac2:~$ echo $PATH
/opt/python/virtualenvs/py-alerta/bin:/opt/python/python-3.8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Les exécutables python3
et pip3
par défaut sont ceux de l’environnement virtuel.
(py-alerta) python@vpsfrsqlpac2:~$ which python3 (py-alerta) python@vpsfrsqlpac2:~$ which pip3
/opt/python/virtualenvs/py-alerta/bin/python3 /opt/python/virtualenvs/py-alerta/bin/pip3
En utilisant Python, le path est également modifié en conséquence pour les chemins d’installation des packages :
(py-alerta) python@vpsfrsqlpac2:~$ python3
import sys sys.path
['', '/opt/python/packages', '/opt/python/virtualenvs/py-alerta/lib/python38.zip', '/opt/python/virtualenvs/py-alerta/lib/python3.8', '/opt/python/virtualenvs/py-alerta/lib/python3.8/lib-dynload', '/opt/python/python-3.8/lib/python3.8', '/opt/python/virtualenvs/py-alerta/lib/python3.8/site-packages']
Dans l’environnement virtuel, les packages seront installés dans le répertoire /opt/python/virtualenvs/py-alerta/lib/python3.8/site-packages
et
les binaires dans le répertoire /opt/python/virtualenvs/py-alerta/bin
.
Exemple : installation du package chardet
dans l’environnement virtuel py-alerta
.
(py-alerta) python@vpsfrsqlpac2:~$ pip3 install chardet
Collecting chardet Using cached chardet-3.0.4-py2.py3-none-any.whl (133 kB) Installing collected packages: chardet Successfully installed chardet-3.0.4
(py-alerta) python@vpsfrsqlpac2:~$ pip3 show chardet
Name: chardet Version: 3.0.4 Summary: Universal encoding detector for Python 2 and 3 Home-page: https://github.com/chardet/chardet Author: Daniel Blanchard Author-email: dan.blanchard@gmail.com License: LGPL Location: /opt/python/virtualenvs/py-alerta/lib/python3.8/site-packages Requires: Required-by:
Les environnements virtuels n’altèrent pas toute définition existante dans la variable d’environnement $PYTHONPATH
.
Pour quitter l’environnement virtuel, lancer la fonction deactivate
, fonction créée après avoir exécuté le script activate
.
(py-alerta) python@vpsfrsqlpac2:~$ deactivate
python@vpsfrsqlpac2:~$
L’environnement est alors de retour à la distribution globale Python 3.8.
python@vpsfrsqlpac2:~$ which python3
/opt/python/python-3.8/bin/python3
Les environnements virtuels et les packages systèmes
Qu’en est-il d’un package déjà installé dans la distribution système ? Par exemple, PyMySQL est installé pour être disponible par défaut :
python@vpsfrsqlpac2:~$ pip3 list
Package Version ---------- ------- PyMySQL 0.9.3
Évidemment, ce package ne sera pas disponible dans l’environnement virtuel. Il faut utiliser l’option --system-site-packages
lors de la création de
l’environnement virtuel afin de pouvoir utiliser les packages installés dans la distribution source globale :
- Avec
virtualenv :
python@vpsfrsqlpac2:~$ virtualenv --system-site-packages $PYVENV/py-alerta
- Mode natif :
python@vpsfrsqlpac2:~$ python3 -m venv --copies --system-site-packages $PYVENV/py-alerta
python@vpsfrsqlpac2:~$ source $PYVENV/py-alerta/bin/activate (py-alerta) python@vpsfrsqlpac2:~$ pip3 list
Package Version ---------- ------- PyMySQL 0.9.3
Le répertoire $PYHOME/lib/python<version>/site-packages
est ajouté dans le path avec l’option --system-site-packages
:
(py-alerta) python@vpsfrsqlpac2:~$ python3
import sys sys.path
['', '/opt/python/packages', '/opt/python/virtualenvs/py-alerta/lib/python38.zip', '/opt/python/virtualenvs/py-alerta/lib/python3.8', '/opt/python/virtualenvs/py-alerta/lib/python3.8/lib-dynload', '/opt/python/python-3.8/lib/python3.8', '/opt/python/virtualenvs/py-alerta/lib/python3.8/site-packages', '/opt/python/.local/lib/python3.8/site-packages', '/opt/python/python-3.8/lib/python3.8/site-packages']
Aucune crainte à avoir niveau sécurité, l’environnement virtuel sait quand il n’est pas le propriétaire d’un package, essayer de supprimer un package de la distribution système depuis un environnement virtuel échoue :
(py-alerta) python@vpsfrsqlpac2:~$ pip3 uninstall PyMySQL
Found existing installation: PyMySQL 0.9.3 Not uninstalling pymysql at /opt/python/python-3.8/lib/python3.8/site-packages, outside environment /opt/python/virtualenvs/py-alerta Can't uninstall 'PyMySQL'. No files were found to uninstall.
Pour les mises à niveau (upgrades), c’est légèrement différent. Dans l’exemple ci-dessous, le package chardet 3.0.0 est installé dans le référentiel système :
(py-alerta) python@vpsfrsqlpac2:~$ pip3 list
Package Version ---------- ------- chardet 3.0.0
La mise à niveau échoue en essayant de supprimer le package système, en revanche la mise à niveau installe la nouvelle version dans l’environnement virtuel :
(py-alerta) python@vpsfrsqlpac2:~$ pip3 install --upgrade chardet
Collecting chardet Using cached chardet-3.0.4-py2.py3-none-any.whl (133 kB) Installing collected packages: chardet Attempting uninstall: chardet Found existing installation: chardet 3.0.0 Not uninstalling chardet at /opt/python/python-3.8/lib/python3.8/site-packages, outside environment /opt/python/virtualenvs/py-alerta Can't uninstall 'chardet'. No files were found to uninstall. Successfully installed chardet-3.0.4
(py-alerta) python@vpsfrsqlpac2:~$ pip3 list
Package Version ---------- ------- chardet 3.0.4
L’environnement virtuel utilise de nouveau celui du système lorsque le package est supprimé de l’environnement virtuel :
(py-alerta) python@vpsfrsqlpac2:~$ pip3 uninstall chardet
Found existing installation: chardet 3.0.4 Uninstalling chardet-3.0.4: Would remove: /opt/python/virtualenvs/py-alerta/bin/chardetect /opt/python/virtualenvs/py-alerta/lib/python3.8/site-packages/chardet-3.0.4.dist-info/* /opt/python/virtualenvs/py-alerta/lib/python3.8/site-packages/chardet/* Proceed (y/n)? y Successfully uninstalled chardet-3.0.4
(py-alerta) python@vpsfrsqlpac2:~$ pip3 list
Package Version ---------- ------- chardet 3.0.0
Une version spécifique peut être installée dans l’environnement virtuel et elle a priorité sur la version système, la version peut même être inférieure à la version système :
(py-alerta) python@vpsfrsqlpac2:~$ pip3 install chardet==3.0.2
Collecting chardet==3.0.2 Downloading chardet-3.0.2-py2.py3-none-any.whl (133 kB) |...........................| 133 kB 5.0 MB/s Installing collected packages: chardet Attempting uninstall: chardet Found existing installation: chardet 3.0.0 Not uninstalling chardet at /opt/python/python-3.8/lib/python3.8/site-packages, outside environment /opt/python/virtualenvs/py-alerta Can't uninstall 'chardet'. No files were found to uninstall. Successfully installed chardet-3.0.2
(py-alerta) python@vpsfrsqlpac2:~$ pip3 list
Package Version ---------- ------- chardet 3.0.2
Quand la version d’un package système ne répond pas aux pré-requis, la version appropriée est installée dans l’environnement virtuel : par exemple
le package alerta-server
a besoin de chardet <3.1.0,>=3.0.2
, mais la version système est 3.0.0
.
(py-alerta) python@vpsfrsqlpac2:~$ pip3 install alerta-server
... Collecting chardet<3.1.0,>=3.0.2 Using cached chardet-3.0.4-py2.py3-none-any.whl (133 kB) ... Attempting uninstall: chardet Found existing installation: chardet 3.0.0 Not uninstalling chardet at /opt/python/python-3.8/lib/python3.8/site-packages, outside environment /opt/python/virtualenvs/py-alerta Can't uninstall 'chardet'. No files were found to uninstall. Successfully installed Flask-1.1.1 Flask-Compress-1.4.0 Flask-Cors-3.0.8 Jinja2-2.10.3 MarkupSafe-1.1.1 PyJWT-1.7.1 Werkzeug-0.16.0 alerta-server-7.4.1 bcrypt-3.1.7 blinker-1.4 certifi-2019.11.28 cffi-1.13.2 chardet-3.0.4 click-7.0 cryptography-2.8 idna-2.8 itsdangerous-1.1.0 pycparser-2.19 pymongo-3.10.1 pyparsing-2.4.6 python-dateutil-2.8.1 pytz-2019.3 pyyaml-5.3 requests-2.22.0 sentry-sdk-0.14.1 six-1.14.0 urllib3-1.25.8
(py-alerta) python@vpsfrsqlpac2:~$ pip3 list
Package Version ---------- ------- chardet 3.0.4
Compilation de librairies
Certains packages ont besoin de compiler des librairies (*.so
): psycopg2 (package Python pour PostgreSQL).
Pas de problème particulier pour compiler des librairies dans un environnement virtuel.
(py-alerta) python@vpsfrsqlpac2:$ export PATH=/opt/postgres/pgsql-11/bin:$PATH (py-alerta) python@vpsfrsqlpac2:$ pip3 install psycopg2
Collecting psycopg2 Using cached psycopg2-2.8.4.tar.gz (377 kB) Building wheels for collected packages: psycopg2 Building wheel for psycopg2 (setup.py) ... done ... Successfully built psycopg2 Installing collected packages: psycopg2 Successfully installed psycopg2-2.8.4
La librairie _psycopg.cpython-38-x86_64-linux-gnu.so
est compilée dans le répertoire $PYVENV/py-alerta/lib/python3.8/site-packages/psycopg2
.
(py-alerta) python@vpsfrsqlpac2:$ python3
import psycopg2
Il faut juste s’assurer que la variable d’environnement $LD_LIBRARY_PATH
contient le chemin vers la librairie libpq.so.5
si elle n’est pas installée
dans les répertoires systèmes (/usr
). Pas de différence par rapport à la procédure d’installation dans une distribution Python classique.
export LD_LIBRARY_PATH=/opt/postgres/pgsql-11/lib:$LD_LIBRARY_PATH
Environnement virtuel Python pour Alerta
À présent, créons un environnement virtuel complet pour Alerta, les packages nécessaires sont très nombreux et on ne souhaite
pas installer l’intégralité de ceux-ci dans la distribution globale système Python.
L’option --system-site-packages
est utilisée, Alerta a besoin de psycopg2
.
python@vpsfrsqlpac2$ virtualenv --system-site-packages $PYVENV/py-alerta python@vpsfrsqlpac2$ source $PYVENV/py-alerta/bin/activate (py-alerta) python@vpsfrsqlpac2:~/virtualenvs$ pip3 install alerta-server (py-alerta) python@vpsfrsqlpac2:~/virtualenvs$ pip3 list
Package Version --------------- ---------- alerta-server 7.4.1 bcrypt 3.1.7 blinker 1.4 certifi 2019.11.28 ...
Le package "Alerta unified command-line tool and SDK" est également installé :
(py-alerta) python@vpsfrsqlpac2:~/virtualenvs$ pip3 install alerta (py-alerta) python@vpsfrsqlpac2:~/virtualenvs$ pip3 list
Package Version --------------- ---------- alerta 7.4.0 alerta-server 7.4.1 ...
Les exécutables alertad
(Alerta daemon server) et alerta
(Alerta command line) sont alors bien installés dans $PYVENV/py-alerta/bin
.
Le script $HOME/.profile
pour le user alerta
est mis à jour afin d’y ajouter l’activation de l’environnement virtuel py-alerta
:
$HOME/.profile (/opt/alerta/.profile)
if [ -f "/opt/python/.python-3.8" ] ; then
. /opt/python/.python-3.8
if [ -f $PYVENV/py-${USER}/bin/activate ] ; then
source $PYVENV/py-$USER/bin/activate
fi
fi
La commande pip3 list
retourne les bonnes informations concernant les packages :
alerta@vpsfrsqlpac2$ . $HOME/.profile (py-alerta) alerta@vpsfrsqlpac2$ pip3 list
Package Version --------------- ---------- alerta 7.4.0 alerta-server 7.4.1 ...
Tout est prêt :
(py-alerta) alerta@vpsfrsqlpac2:~$ alertad run --port 20003 --host vpsfrsqlpac2
2020-01-24 16:50:15,311 werkzeug[1944]: * Running on http://vpsfrsqlpac2:20003/ (Press CTRL+C to quit)
Conclusion
- Les packages les plus communs (PyMySQL, psycopg2…) sont installés dans la distribution système Python.
- Les environnements virtuels Python sont utilisés lorsque des packages "exotiques" sont nécessaires pour très peu d’utilisateurs, cela évite de polluer la distribution système avec conflits de versions et divergences pour d’autres packages et applications.
- Les problèmes de versions de package peuvent être résolus à l’aide d’environnements virtuels Python.
- Les environnements virtuels Python sont très utiles pour tester les installations de dépendances et à des fins de développement.