📘 Introduction

logo.drawio

1. Contexte

1.1. Dichotomie développement / exploitation

Regardons comment est définie l’informatique sur Wikipédia :

L'informatique est un domaine d’activité scientifique, technique, et industriel concernant le traitement automatique de l’information numérique par l’exécution de programmes informatiques hébergés par des dispositifs électriques-électroniques : des systèmes embarqués, des ordinateurs, des robots, des automates, etc.
— Wikipédia (français)

On distingue deux parties dans cette définition :

  • d’une part « le traitement automatique de l’information numérique par l’exécution de programmes », autrement dit : résoudre des problèmes à l’aide de programmes informatiques.

  • d’autre part « l’exécution de programmes informatiques hébergés par des dispositifs électriques-électroniques », autrement dit : un programme doit être installé sur une machine puis exécuté.

La plupart des spécialités de l’informatique − science des données, génie logiciel, traitement du langage, systèmes distribués, etc. −, s’intéressent en premier lieu à la première partie de cette définition. L’essentiel d’un parcours d’enseignement dans une formation en informatique se concentre donc en premier lieu sur cette question, à savoir résoudre des problèmes par le développement (en anglais, development) de programmes adaptés.

Cependant, comme écrit dans la seconde partie de cette définition, le cycle de vie d’un programme n’est pas terminé une fois ce dernier écrit : il est encore nécessaire de l’installer sur une machine (poste utilisateur, serveur, téléphone, capteur, montre, routeur,…) et le faire fonctionner dans un environnement particulier (matériel, système d’exploitation, conditions physiques, cohabitation ou collaboration avec d’autres programmes, …), afin d’accomplir une tâche donnée dans un contexte donné (calcul intensif dans le cloud, usage récréatif ponctuel sur téléphone, tâche de fond légère sur un serveur, …). Dans ce cours on nomme exploitation (en anglais, operations) toute la partie du cycle de vie d’un logiciel où ce dernier est déployé dans l’environnement auquel il est destiné, et est entre les mains de ses utilisateurs.

On notera que c’est durant la phase d’exploitation qu’un logiciel va bel et bien pouvoir réellement résoudre les problèmes pour lesquels il a été conçu.

On peut schématiser étapes traditionnelles de la vie d’un logiciel de la manière suivante :

informatique2.drawio
Figure 1. (Très) grandes étapes du cycle de vie d’un logiciel

Historiquement, le développement et l’exploitation sont associés à deux rôles généralement séparés :

  • Le concepteur / développeur de logiciel, en première ligne durant la phase de développement. Ses tâches incluent − sans ordre ni exhaustivité − d’analyser les besoins, concevoir le logiciel, mettre au point des algorithmes, sélectionner et/ou préparer des données, écrire le code du programme, écrire et exécuter des tests unitaires, compiler et/ou empaqueter un programme, etc.

  • L’administrateur système, en première ligne dans la phase d’exploitation. Ses tâches vont inclure préparer des machines (physiques ou virtuelles), installer et configurer un système d’exploitation, configurer un réseau virtuel, piloter un serveur à distance, déployer le logiciel dans le cloud, copier un fichier de configuration, puis effectuer la maintenance opérationnelle du système en exploitation.

Voyons maintenant comment s’articulent ces deux activités sous la forme d’un processus itératif :

processus.drawio
Figure 2. Développement et exploitation sous forme de processus itératif
  • À gauche, le point de départ est un ensemble de besoins qui justifient de développer un nouveau logiciel. Cet ensemble de besoins est généralement rédigé sous la forme d’un cahier des charges.

  • Ces besoins sont ensuite traduits en tâches de conception et développement, qui mènent à produire une version du logiciel attendu.

  • Une version produite du logiciel passe ensuite en test d’acceptation, aussi appelée la recette. C’est lors de cette étape que le logiciel est mis à l’épreuve dans des conditions d’usage réalistes afin de vérifier qu’il permet bien de répondre aux besoins, et qu’il ne comporte pas de défaut.

    • Si on réalise lors de cette étape que les besoins initiaux étaient mal énumérés ou incomplets, alors on repart en élaboration des besoins en vue de produire une nouvelle version du logiciel.

    • Si les tests d’acceptation ne sont pas réussis, on repart en conception et développement pour corriger le problème, ce qui donnera une nouvelle version du logiciel.

    • Si les tests d’acceptation sont réussis, on passe à l’étape suivante.

  • Enfin, si tout est OK, le logiciel est mis en exploitation (ce qui inclut un déploiement sur les machines souhaités) et peut être utilisé réellement. Durant la mise en exploitation, il est à nouveau possible que des défauts soient identifiés ou que de nouveaux besoins émergent, ce qui dans les deux cas entraînera là aussi une nouvelle itération de développement et de mise en exploitation.

Dans ce cours nous faisons généralement l’hypothèse que c’est le même acteur − par exemple la même entreprise − qui développe un logiciel et le met en exploitation. Cependant c’est n’est pas toujours le cas : un grand nombre d’entreprises, collectifs et communautés ne font que développer des logiciels, qui doivent ensuite être mis en exploitation par les clients et/ou utilisateurs de ces logiciels. Une premier exemple serait un éditeur qui vend un logiciel à une seconde entreprise, qui doit ensuite se charger de mettre en exploitation le dit logiciel sur sa propre infrastructure. Un autre exemple serait un fournisseur de service qui choisisse d’utiliser un logiciel libre existant pour son service, et qui se charge donc uniquement de la mise en exploitation du logiciel, tandis que le développement est assuré par la communauté libre.

Dans ce processus itératif, on peut voir que tout ce qui concerne la production d’une version du logiciel fait partie du domaine du développement, tandis que la mise en exploitation est du domaine de l'administration système. Les tests d’acceptation sont un peu à la frontière entre les deux domaines, car sont nécessaires pour valider une version du logiciel − ce qui concerne directement l’équipe développement − mais nécessitent pour cela de faire un premier déploiement du logiciel dans un environnement réaliste − ce qui concerne directement l’équipe administration système.

Ce qu’on peut retenir de ce processus, c’est que les deux domaines d’activité (développement et administration système) sont extrêmement dépendants l’un de l’autre, et doivent nécessairement travailler ensemble afin d’atteindre l’objectif commun : la bonne livraison du logiciel et la satisfaction des besoins.

1.2. Cas d’études utilisés dans ce cours

Pour rendre la problématique un peu plus concrète, voyons deux cas d’études élaborés pour les besoins de ce cours. Chacun de ces cas d’étude comporte une partie développement, et une partie de mise en exploitation.

Il est possible que vous ne connaissiez pas les langages de programmation ou les outils utilisés pour développer ces deux projets. Pas de panique, il n’est pas demandé de comprendre le travail de développement réalisé sur chacun de ces deux projets ! Il vous sera simplement demandé, dans le cadre de ce cours, d’être capable de mettre en place l’intégration et l’exploitation un logiciel déjà développé, en comprenant simplement quelles contraintes il faudra satisfaire dans chaque cas.
Cas d’étude 1 : Automatic-Image-Converter

On développe et on souhaite mettre en exploitation un logiciel appelé Automatic-Image-Converter permettant de convertir automatiquement des fichiers image de différents formats (jpg, png, bmp, etc.) vers un format unique choisi.

On développe ce logiciel en Java, et le code utilise une bibliothèque logicielle appelée Batik pour être capable de convertir des images d’entrée de format svg. Cela signifie que Batik doit être téléchargé, puis que Automatic-Image-Converter doit être compilé à l’aide d’un compilateur Java, et enfin qu’un exécuteur Java doit être utilisé pour l’exécuter.

Les dépendances de Automatic-Image-Converter comportent donc :

  • la bibliothèque Java Batik,

  • un exécuteur Java compatible.

Le logiciel s’exécute en arrière-plan d’un système, et va continuellement traiter toutes les images déposées dans un répertoire d’entrée donné, pour déposer dans un répertoire de sortie les versions converties. Automatic-Image-Converter est configurable à l’aide d’un ensemble d'arguments qui doivent lui être donnés lors de son démarrage. Ces arguments incluent notamment les répertoires d’entrée et de sortie, ainsi que le format de sortie souhaité.

Pour résumer, on peut schématiser l’architecture de Automatic-Image-Converter comme ceci :

aic overview.drawio

Et même si Automatic-Image-Converter ne possède pas d’interface graphique, voici à quoi ressemble les informations textuelles qu’il produit durant son exécution dans un terminal :

Starting processing input folder /inputs, to generate in folder /outputs
Starting conversion of /inputs/hex.png in jpg
Image converted successfully into: /outputs/hex.png.jpg
Deleting /inputs/hex.png
Starting processing input folder /inputs, to generate in folder /outputs
Starting conversion of /inputs/tree.png in jpg
Image converted successfully into: /outputs/tree.png.jpg
Deleting /inputs/tree.png
Le code source de Automatic-Image-Converter et toute sa documentation technique est disponible publiquement sur l’instance Gitlab de Nantes Université.

Dans ce cours, on s’intéressera à ce cas d’étude de deux manière :

  • La phase de développement de Automatic-Image-Converter nécessite notamment un compilateur Java et l’outil de construction Maven. Ce dernier se charge de toutes les étapes menant à une version livrable (compilation, tests unitaires, packaging).

  • La phase d’exploitation de Automatic-Image-Converter nécessite d’installer Automatic-Image-Converter et toutes ses dépendances dans un environnement de déploiement, et de démarrer son exécution.

Cas d’étude 2 : SimplestBlog

On développe et on souhaite mettre en exploitation un logiciel appelé Simplestblog permettant d’héberger un blog en ligne. Les fonctionnalités attendues sont de pouvoir créer des comptes utilisateurs, s’authentifier avec l’un de ces comptes, et créer des articles qui apparaissent alors sur la page d’accueil.

On développe ce logiciel en Python à l’aide du framework Flask. Cela signifie que Simplestblog requiert un interpréteur Python pour être exécuté, et que cet interpréteur Python ait accès à une copie de la bibliothèque logicielle Flask.

Lorsqu’il s’exécute, SimplestBlog agit comme un serveur HTTP qui écoute sur le port réseau 8080, auquel peut se connecter un navigateur web comme Firefox. À chaque fois qu’il est sollicité, SimplestBlog produit une page web (à savoir un document .html) qui est envoyée au navigateur, qui l’affiche. En retour, le navigateur peut agir sur la page web, ce qui va à nouveau solliciter SimplestBlog, et ainsi de suite.

SimplestBlog repose sur une base de données pour mémoriser les comptes et les articles créés. SimplestBlog est compatible avec une base soit SQLite (donc sous la forme d’un simple fichier), soit MySQL (donc qui nécessite d’exécuter à côté un système de base de données compatible MySQL).

Les dépendances de Simplestblog comportent donc :

  • la bibliothèque Python Flask,

  • un exécuteur Python compatible,

  • (optionnellement) un système de base de données compatible MySQL.

Pour son exécution, SimplestBlog nécessite un fichier de configuration qui définit un ensemble de paramètres pour son fonctionnement − notamment les informations pour se connecter à la base de données choisie.

Par exemple, voici à quoi ressemble un fichier de configuration SimplestBlog lorsqu’on souhaite se connecter à une base de données compatible MySQL :

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"
  • SECRET_KEY est 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_TYPE permet de choisir entre MySQL et SQLite. Ici on choisit MySQL.

  • MYSQL_DATABASE_HOST est 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_USER est le nom d’utilisateur à utiliser pour se connecter au serveur de base de données.

  • MYSQL_DATABASE_PASSWORD est le mot de passe à utiliser pour se connecter au serveur de base de données.

  • MYSQL_DATABASE_DB est le nom de la base de données à utiliser au sein du serveur de base de données.

  • MYSQL_DATABASE_PORT est le nom du port réseau sur lequel se connecter sur MYSQL_DATABASE_HOST.

Lors de sa toute première exécution, il est nécessaire de manuellement demander à SimplestBlog d’effectuer une initialisation de la base de données, afin de créer toutes les tables nécessaires pour y ranger les données.

Pour résumer, si on se concentre sur le cas d’usage avec base de données MySQL, on peut schématiser l’architecture de SimplestBlog comme ceci :

simplestblog overview.drawio

Et une fois en fonctionnement, SimplestBlog ressemble à ceci une fois ouvert dans un navigateur :

simplestblog screenshot
Le code source de SimplestBlog et toute sa documentation technique est disponible publiquement sur l’instance Gitlab de Nantes Université.

Dans ce cours, on s’intéressera à ce cas d’étude de deux manières :

  • La phase de développement de Simplestblog nécessite notamment un compilateur Python et un analyseur de code Python, et l’exécution d’un ensemble de tests unitaires à l’aide de Pytest. Il faut en outre orchestrer l’exécution de ces outils à chaque fois que l’ont souhaite produire une nouvelle version.

  • La phase d’exploitation de Simplestblog nécessite d’installer Simplestblog et toutes ses dépendances dans un environnement de déploiement, de démarrer le logiciel, et de le rendre accessible aux utilisateurs par le réseau.

1.3. Organisation type et problématique

Pour mettre en œuvre le processus itératif présenté en Figure 2, une organisation type prend la forme suivante :

vue generale deploiements.drawio
Figure 3. Vue simplifiée d’une organisation type pour produire et mettre en exploitation un produit logiciel

L’activité "développement" consiste à produire (ou améliorer) le code source du logiciel produit, et à construire une version livrable du logiciel à partir de ce code source. Pour cela, on peut distinguer deux types d’environnements :

  • l'environnement de développement est la machine sur laquelle le développeur produit des changements sur le code source.

  • l'environnement d’intégration est la machine utilisée pour intégrer tous les changements réalisés sur le code, et pour construire la version livrable du logiciel (à l’aide de compilateurs, gestionnaires de dépendances, etc.).

Dans certains cas c’est le même environnement qui sert pour le développement et l’intégration.

Afin de produire le logiciel attendu, un ensemble d'outils de construction doivent être déployés dans les environnement de développement et d’intégration. Ces outils incluent par exemple des compilateurs, des gestionnaires de dépendances, ou des exécuteurs de test unitaire. Il est également nécessaire "d’orchestrer" l’exécution de tous ces outils pour produire une version livrable fiable à l’issue de cette phase.

L’activité "administration système" consiste à déployer la version livrable du logiciel produite dans différents environnements, notamment :

  • l'environnement de recette, qui est utilisé pour valider la version produite vis à vis des besoins initiaux,

  • l'environnement de production, qui est l’endroit final où est installé le logiciel pour une utilisation par les utilisateurs finaux.

Dans une organisation plus complexe, on pourra trouver également un environnement de pré-production entre l’environnement de recette et de production.

Pour mettre en œuvre cette organisation type, il faut faire face à certains défis, notamment :

  • Dans toutes les activités présentées, il est nécessaire de savoir déployer des logiciels dans un environnement donné. C’est une action à la fois nécessaire pour déployer les logiciels nécessaires au développement (compilateur, gestionnaire de dépendance, etc.), et pour déployer la version livrable du logiciel produit. Cependant, il n’est pas toujours facile de déployer un logiciel de manière fiable.

  • L’activité de développement peut nécessiter d'intégrer et vérifier les changements produits par plusieurs développeurs, possiblement à un rythme soutenu. Il faut en outre produire de nouvelles versions de logiciel en suivant ce rythme .

  • L’activité d’administration système nécessite de déployer le logiciel produit sur toute une diversité d’environnements, ce qui nécessite une orchestration pas toujours triviale.

2. Objectifs de ce cours

  • Comprendre certains enjeux liés au déploiement d’un logiciel.

  • Apprendre les bases théoriques et pratiques de la conteneurisation, une technique aujourd’hui incontournable dans tous les domaines de l’informatique pour déployer des logiciels,

  • Comprendre comment utiliser la conteneurisation pour gérer les différentes étapes de mise en exploitation d’un logiciel,

Ce cours est-il pour moi ?

Est-ce que votre spécialité nécessite d’écrire des algorithmes ou des programmes, que ce soit un logiciel d’optimisation, une pipeline de traitement de données, un algorithme de traitement d’image, un logiciel d’aide à la décision, ou une application web divisée en frontend et backend?

Si la réponse est oui, alors vous êtes au bon endroit !

Quel que soit le domaine dans lequel s’inscrit un logiciel, peu importe la forme qu’il prend, quel que soit le langage dans lequel il est écrit, ce logiciel connaîtra un jour une phase d’exploitation. Par conséquent, être capable d’organiser la phase de développement pour faciliter et accélérer la phase d’exploitation, ou être capable d’en comprendre les enjeux, ou encore pouvoir même y prendre part directement, sera toujours bénéfique quel que soit le contexte. À minima, cela vous permettra de discuter avec les personnes responsables de la phase d’exploitation, et au mieux cela vous permettra de mener cette phase conjointement.

Pour donner un exemple concret, différents acteurs dans le monde de la science des données ont fait le constat que les pipelines de traitement de données étaient souvent laborieuses à déployer, et que beaucoup de temps et d’effort était nécessaire pour incorporer des changements à un tel pipeline jusqu’à son re-déploiement. Suite à ce constat, il a été proposé d’adapter les principes du DevOps au monde de la science des données, ce qui a donné lieu à ce qu’on appelle désormais le DataOps, qui est désormais la norme dans toutes les grandes industries dans ce domaine.

3. Références

  • Humble, Jez, and David Farley. Continuous delivery: reliable software releases through build, test, and deployment automation. Pearson Education, 2010.

  • https://fr.wikipedia.org/wiki/Informatique (consulté le 24/08/2023)