📕 Logiciel et exécution
| L’icône rouge 📕 signifie que ce chapitre ne sera pas présenté en séance de CM, et sera donc entièrement à travailler en autonomie. Il est important de l’avoir lu et préparé avant la séance sur le chapitre suivant. |
Avant d’apprendre à déployer un logiciel, il faut d’abord comprendre ce qu’implique l’exécution d’un logiciel dans un environnement donné. Ce chapitre présente succinctement quelques notions de base.
1. Exécution d’un logiciel
Un logiciel est toujours exécuté dans un environnement. À sa base, un environnement comporte généralement du matériel (processeur, mémoire, stockage, réseau, etc.), ainsi qu’un système d’exploitation (Linux, Windows, etc.). Le système d’exploitation est responsable de toutes les interactions avec le matériel, et expose aux logiciels une représentation abstraite de ce dernier, que ce soit le stockage représenté sous la forme d’un système de fichiers, ou le réseau représenté par un adressage IP.
Au dessus du système d’exploitation se trouve tout un ensemble de fichiers, comportant notamment :
-
Un ensemble de logiciels que l’on souhaite exécuter pour accomplir des tâches. Un logiciel peut prendre la forme d’un binaire exécutable nativement (par exemple un programme C compilé), d’un binaire exécutable par une plateforme d’exécution (par exemple un programme Java compilé en
.jar) ou encore d’un script interprétable (par exemple un programme Python.pyou shell.sh). -
Un ensemble de dépendances requises par les logiciels exécutés. Ces dépendances comportent principalement des bibliothèques logicielles (bibliothèque C, Java, Python, etc.), mais aussi des exécutables (utilitaires, interpréteurs, etc.).
-
Un ensemble de données manipulées par les logiciels exécutés. Ces données incluent à la fois des fichiers de configuration (par exemple un fichier
.jsonou.yml) et des données de travail (par exemple une base de données).
| Un environnement peut prendre la forme d’un système informatique physique (c’est à dire avec du vrai matériel), ou bien d’un système informatique virtuel (c’est à dire avec du matériel virtuel "simulé"), aussi appelé machine virtuelle. Dans ce cours, on ne fera pas de distinction explicite entre les deux situations. |
L’exécution d’un logiciel va générer un processus dans l’environnement, à savoir une représentation en memoire du logiciel exécuté et de son état à l’exécution. Une fois en exécution, le processus va aller chercher et utiliser les dépendances dont il a besoin, et va écrire et/ou lire les données avec lesquelles il doit travailler.
| Il est possible d’exécuter simultanément le même logiciel plusieurs fois, ce qui crée alors plusieurs processus à partir du même logiciel. |
On exécute Simplestblog ainsi qu’une bases de données MariaDB associée :
On notera que cela nécessite de préparer l’environnement pour y avoir :
-
Un interpréteur Python permettant d’exécuter Simplestblog. On choisit pour cela l’implémentation officielle Python, appelée CPython, en version 3.
-
La bibliothèque logicielle Python Flask.
-
Un système de gestion de base de données compatible MySQL. On choisit d’utiliser le logiciel MariaDB.
-
MariaDB nécessite d’utiliser un répertoire où stocker tous les fichiers de stockage de la base de données.
| Pour le moment le schéma ne montre pas la communication entre les deux processus, ce qui sera détaillé plus loin dans le cours lorsqu’on parlera de réseau. |
| Il est crucial qu’un processus ait bien toujours accès à tout ce dont il a besoin. En cas de dépendances ou de données absentes, le comportement obtenu risque d’être incorrect (par exemple, un plantage) ! |
2. Configuration d’un logiciel
La majorité des logiciels peuvent être configurés au moment de leur lancement, que ce soit pour leur confier les informations qu’ils requièrent (par exemple indiquer à une base de données où stocker ses fichiers) ou pour influencer leur mode de fonctionnement (par exemple indiquer à une base de données comment optimiser ses tables).
On compte au moins trois manières courantes de configurer un logiciel à son lancement : la ligne de commande, les variables d’environnement, et les fichiers de configuration.
| Parmi ces trois stratégies, certains logiciels choisissent de n’en utiliser une seule, tandis que d’autres choisissent d’en combiner plusieurs (voire les trois !). Il n’y a pas de règle universelle ! |
2.1. Ligne de commande
Lorsqu’un logiciel s’exécute à l’aide d’une commande, il peut souvent recevoir un ensemble d'arguments passés avec cette commande. Ces arguments sont généralement passés de deux manières :
-
Soit à l’aide d’une option, à savoir un paramètre avec un nom explicite. Une option peut être soit:
-
sans valeur (
--option) pour simplement activer un comportement (par exemplels --reverseindique àlsde lister les fichiers dans l’ordre inverse), -
avec valeur (
--option=valeurou--option valeur) pour passer une donnée spécifique (par exemplels --sort=sizepour passer la valeursizeà l’option--sort)
-
-
Soit à l’aide d’un paramètre positionnel, à savoir un paramètre sans nom explicite devant être à une position précise dans la commande (par exemple dans la commande
cp fichier1 fichier2,fichier1est la valeur donnée à un premier paramètre positionnel correspondant au fichier source,fichier2est la valeur donnée à un second paramètre positionnel correspondant à la destination).
Le cas d’étude Simplestblog est un logiciel Python qui doit être exécuté à l’aide d’un autre logiciel Python appelé Flask.
Pour cela, Flask fournit une commande appelée waitress-serve, que nous utilisons ainsi :
$ waitress-serve --call simplestblog:create_app
Dans cette commande, on passe la valeur simplestblog:create_app à l’option --call, pour indiquer à Flask quel fichier Python et quelle fonction doivent être exécutés pour démarrer Simplestblog.
2.2. Variables d’environnement
Une variable d’environnement est une manière universelle de stocker une valeur au sein d’un environnement ou au sein d’un processus.
Par convention elle est écrite en majuscules sous la forme VARIABLE=valeur.
Une variable d’environnement peut être définie à plusieurs niveaux :
-
Elle peut-être définie par le système d’exploitation au niveau de l’environnement d’exécution. Cela permet de définir des valeurs qui sont transmises à l’intégralité des processus qui s’exécutent dans cet environnement. Par exemple le système d’exploitation définit typiquement la variable
HOMEqui contient l’emplacement du répertoire utilisateur, ou bien la variablePATHqui contient la liste des répertoires contenant des programmes exécutables. -
Elle peut-être définie au niveau d’un processus spécifique, soit au moment du lancement du processus, soit durant son exécution. Cela permet non seulement de confier des valeurs au processus, mais cela permet aussi à un processus de définir des variables qui seront transmises à tous ses processus enfants.
Une variables d’environnement peut donc soit servir à transmettre des "informations générales" à tout un ensemble de processus, soit transmettre des "informations spécifiques" à un processus particulier. Dans le second cas, le rôle joué par une variable d’environnement est très similaire à celui d’une option avec valeur définie dans une ligne de commande.
Le logiciel Simplestblog utilise la variable d’environnement SIMPLESTBLOG_SETTINGS_FILE pour savoir à quel emplacement se situe le fichier de configuration qu’il doit utiliser pour son exécution.
Ainsi, si on prépare un fichier de configuration à l’emplacement /monrepertoire/config.py, on peut donner cette information au processus en démarrant le logiciel avec les commandes suivante :
$ export SIMPLESTBLOG_SETTINGS_FILE=/monrepertoire/config.py
$ waitress-serve --call simplestblog:create_app
2.3. Fichiers de configuration
Un logiciel peut choisir de recevoir ses valeurs de configuration en lisant un fichier de configuration écrit dans un langage informatique qu’il comprend. On utilise généralement pour cela un langage spécialisé dans la représentation de données, comme les langages JSON, YAML, TOML ou INI. Certains logiciels possèdent également leur propre langage de configuration, et d’autres vont parfois directement utiliser le langage de programmation dans lequel ils sont écrits.
Un fichier de configuration comporte toujours des paramètres auxquels sont associés des valeurs. En fonction du langage de configuration, il peut être également par exemple possible de répartir les paramètres dans différentes sections, ou bien de définir des paramètres structurés chacun composé de plusieurs sous-paramètres.
Simplestblog doit être configuré à l’aide d’un fichier de configuration écrit directement dans le langage Python. Ce fichier doit uniquement comporter une liste de déclaration des variables suivantes :
-
SECRET_KEYest une clé secrète unique interne au logiciel, qui lui permet notamment de sécuriser les comptes utilisateurs. Cette clé doit être différente et aléatoire pour chaque déploiement de Simplestblog. -
DB_TYPEpermet de choisir entre une base de données MySQL (mysql) ou SQLite (sqlite). -
MYSQL_DATABASE_HOSTest le nom d’hôte (ou, à défaut, l’adresse IP) pour se connecter à un serveur compatible MySQL existant contenant les données de l’instance SimplestBlog. -
MYSQL_DATABASE_USERest le nom d’utilisateur à utiliser pour se connecter au serveur de base de données. -
MYSQL_DATABASE_PASSWORDest le mot de passe à utiliser pour se connecter au serveur de base de données. -
MYSQL_DATABASE_DBest le nom de la base de données à utiliser au sein du serveur de base de données. -
MYSQL_DATABASE_PORTest le nom du port réseau sur lequel se connecter surMYSQL_DATABASE_HOST.
Un exemple de fichier config.py peut donc être :
SECRET_KEY = "LGGQWzcR2F9Gz9E3LseiV7VqJUY"
DB_TYPE = "mysql"
MYSQL_DATABASE_HOST = "172.0.0.10"
MYSQL_DATABASE_USER = "simplestblog"
MYSQL_DATABASE_PASSWORD = "CqbVx4G5fG7wm9VdgexJLNB5PWZ"
MYSQL_DATABASE_DB = "simplestblog"
MYSQL_DATABASE_PORT = "3306"
3. Comptes utilisateurs et droits d’accès
| Bien que les notions présentées ici concernent tout système d’exploitation (Linux, Windows, Mac, etc), les exemples évoqués sont spécifiques à un environnement de type Linux. |
Au sein d’un environnement, le système exploitation exige que chaque action sur l’environnement soit réalisée à l’aide d’un compte utilisateur. Un compte utilisateur possède un ensemble de droits qui définissent quels logiciels, périphériques, et fichiers peuvent être exécuté, lus ou modifiés par ce compte utilisateur.
Chaque processus exécuté dans un environnement est exécuté par un unique compte utilisateur, qui va définir quels sont les droits accordés à ce processus.
Ainsi, si un compte utilisateur a le droit de modifier le contenu du répertoire /etc, alors un processus exécuté par ce compte utilisateur pourra modifier le répertoire /etc.
Bien utilisé, ce système permet d’éviter à un processus de lire une information qu’il n’est pas en droit de lire (comme une clé de chiffrement), ou de commettre des ravages parmi des fichiers qu’il n’est pas censé modifier ou supprimer.
Un compte utilisateur peut correspondre :
-
soit à une personne humaine qui utilise un environnement − par exemple chaque étudiant⋅e possède un compte utilisateur permettant de se connecter à une machine de TP ;
-
soit à un rôle abstrait, qui ne correspond à aucune personne humaine spécifique, et qui n’existe que pour restreindre de manière précise les droits accordés à certains processus, par exemple :
-
www-dataest un compte utilisateur de ce type souvent utilisé pour exécuter les serveurs web (Apache, Nginx, etc), et qui permet de restreindre les droits de ces processus pour limiter les attaques provenant d’acteurs malicieux. -
root, le plus connu, est le compte utilisateur de ce type qui possède des droits absolus sur l’intégralité de l’environnement. C’est généralement le seul compte utilisateur qui a le droit de modifier les fichiers du système d’exploitation, et par conséquent le seul compte qui peut facilement installer (ou désinstaller) des logiciels systèmes dans l’environnement.Un compte utilisateur non-root peut se voir confier le droit d’utiliser une commande appelée sudo, qui permet de déclencher un processus comme s’il avait été lancé par le compteroot. L’administrateur système d’un environnement possède habituellement le droit d’utilisersudo.
-
Supposons un interpréteur de commandes dans un environnement Ubuntu, lancé par un compte utilisateur obiwan qui ne possède par les droits root :
obiwan@alderaan:~$
Si on essaie de créer un fichier dans le répertoire utilisateur du compte obiwan, tout fonctionne sans erreur :
obiwan@alderaan:~$ echo "Bonjour !" > ~/message.txt
obiwan@alderaan:~$ cat ~/message.txt
Bonjour !
Par contre si on essaie de créer un fichier dans un répertoire système comme /etc, une erreur apparait car le compte utilisateur utilisé n’a pas le droit de modifier le répertoire /etc :
obiwan@alderaan:~$ echo "Bonjour !" > /etc/message.txt
bash: /etc/message.txt: Permission denied
En revanche, si on est connecté avec le compte utilisateur root :
root@alderaan:/#
On peut essayer à nouveau de créer un fichier dans un répertoire système comme /etc, et constater qu’il n’y a pas d’erreur, car root possède tous les droits dans l’environnement :
root@alderaan:/ echo "Bonjour !" > /etc/message.txt
root@alderaan:/ cat /etc/message.txt
Bonjour !