Cet article se veut compréhensible par les profanes.
Ce qu’est un programme informatique
En première approche, nous pouvons définir un programme informatique comme un automate auquel on fournit des données, et qui répond par un résultat. Les données peuvent être un texte tapé au clavier, un déplacement de souris, le contenu d’un document, un flux reçu par le réseau ; le résultat peut être un affichage à l’écran, un enregistrement sur un disque, l’envoi d’un message par le réseau, etc.
Si nous examinons plus en détail un programme informatique, nous verrons un texte dont les mots sont, d’une part, les noms d’opérations élémentaires réalisables par un calculateur donné, d’autre part, les noms des données, objets de ces opérations, appelées aussi opérandes.
Chaque calculateur particulier, ou processeur, possède un jeu d’opérations élémentaires qui lui est propre. Les conventions selon lesquelles ces mots peuvent être agencés définissent la syntaxe du langage machine de ce calculateur particulier.
Le processeur possède des circuits logiques pour interpréter un texte conforme à la syntaxe de son langage machine, et possède un circuit d’amorçage qui lui permet de commencer à fonctionner par la première opération élémentaire du programme. Ensuite, la succession des opérations à effectuer sera déduite du texte du programme selon des procédés décrits ci-dessous.
Dans le cas où le calculateur considéré est un ordinateur physique, à chacune des opérations élémentaires exécutables correspond un ensemble de circuits électroniques, capables d’effectuer le calcul stipulé selon la valeur de ses opérandes. L’ensemble des circuits destinés à une opération est nommé primitive, c’est un objet physique. Une opération à laquelle correspond une primitive du processeur est nommée instruction de ce processeur. La description des primitives disponibles sur un processeur constitue l’architecture matérielle de ce processeur.
Une opération élémentaire réalise un calcul. Il faut entendre ici calcul au sens large. Un calcul élémentaire peut être :
– un calcul arithmétique, dont les opérandes sont des nombres ;
– un calcul logique, dont les opérandes valent vrai ou faux ;
– la recopie, le déplacement ou la modification d’une donnée, dont les opérandes sont le nom de la donnée à recopier ou à modifier et le nom de la donnée de destination.
De façon à pouvoir combiner des opérations élémentaires pour construire des programmes plus complexes, il faut en outre disposer d’opérations de commande, qui permettent, fondamentalement, trois choses :
– l’exécution en séquence d’une série d’opérations élémentaires, mentionnées les unes à la suite des autres dans le texte ;
– le choix, en fonction de la valeur des opérandes, de l’opération suivante à effectuer (alternative) ;
– la décision, en fonction de la valeur des opérandes, de répéter un certain nombre de fois une opération donnée, ou une séquence d’opérations.
Cette assertion a été démontrée et est connue comme le théorème de Böhm et Jacopini (ou théorème de la programmation structurée). C’est un résultat important parce qu’il simplifie considérablement la question de la programmation de tout algorithme, aussi complexe soit-il.
(On trouvera à la fin de cet article, dans les commentaires des lecteurs, une discussion de ce passage)
Muni de ces opérations élémentaires et des moyens de les combiner, je peux donc écrire des programmes qui décrivent des algorithmes. Un algorithme est une méthode générale pour effectuer un certain calcul (au sens large donné ci-dessus), le programme est une réalisation particulière d’un algorithme, dans un langage donné.
Mémoire, processeur et persistance
Le texte du programme en cours d’exécution et des données qu’il traite est enregistré dans un dispositif appelé mémoire. Les résultats des calculs sont aussi placés dans la mémoire. La mémoire peut être vue comme un tableau dont chaque case peut contenir une donnée, c’est-à-dire soit un opérande, soit le nom d’une opération élémentaire, soit le résultat d’un calcul. Chaque case du tableau a un nom, qui permet de désigner et de retrouver la donnée qu’elle contient. Le nom d’une case de mémoire peut être son numéro d’ordre à partir du début du tableau, on pourra dire alors qu’il s’agit de l’adresse de cette case.
Les opérations élémentaires d’un ordinateur physique ont accès à la mémoire : elles peuvent aller y chercher un opérande dont elles connaissent le nom, et y stocker un résultat. Ces deux opérations fondamentales sont souvent désignées par leur nom anglais : Load et Store.
Comme le texte du programme est lui-même enregistré en mémoire, il est possible de le considérer comme un ensemble de données, auxquelles on peut faire subir des traitements. Il est notamment possible d’examiner le comportement d’un programme en cours d’exécution, et même de le modifier, ce qui rend possible le diagnostic de ses éventuels dysfonctionnements au moyen d’un logiciel dit de débogage, mais aussi des actions malveillantes.
La mémoire d’un ordinateur physique est généralement volatile, c’est-à-dire que son contenu s’évanouit lors de l’extinction de l’ordinateur. C’est pourquoi on lui adjoint une mémoire persistante, souvent sous la forme d’un disque dur, mais de plus en plus souvent sous forme de mémoire Flash, analogue aux clés USB. Il convient d’enregistrer en mémoire persistante les données que l’on veut conserver, documents, résultats de calculs, textes des programmes.
Décomposition en sous-programmes
Le texte d’un programme est soumis au calculateur qui l’interprète et qui effectue les calculs prescrits par le texte.
Une opération que, très couramment, pourra effectuer un programme, ce sera invoquer un autre programme (appelé dès lors sous-programme). L’invocation (ou appel) de sous-programme est une primitive de tout calculateur raisonnable. Lors de l’appel, le programme appelant fournit au sous-programme des données, appelées arguments ou paramètres. Lorsqu’il se termine, le sous-programme renvoie au programme appelant le résultat de son calcul.
L’invocation en chaîne de sous-programmes permet de construire des systèmes aussi complexes que l’on veut, tout en maîtrisant leur complexité parce que chaque sous-programme peut être examiné et testé isolément. Par exemple, des systèmes d’exploitation tels que Linux ou Windows comportent quelques dizaines de millions d’instructions et quelques dizaines de milliers de sous-programmes.
Le concept de sous-programme est un des plus importants de la science informatique.
L’unification sous une même forme du texte du programme et du texte des données, et l’idée d’enregistrer ce texte dans une mémoire unique, constituent l’architecture de von Neumann, du nom de son inventeur.
Corrado Böhm et Giuseppe Jacopini ont montré que la séquence, l’alternative et la répétition étaient suffisantes pour construire tout programme possible, point dont on trouvera une discussion à la fin de cet article, dans les commentaires des lecteurs.
Un programme particulier : le système d’exploitation
Munis de ce modèle de calcul, examinons ce programme un peu particulier qu’est un système d’exploitation (Operating System en anglais, ou OS). Son rôle est de présenter à l’utilisateur d’un calculateur (utilisateur qui peut d’ailleurs être un autre programme) une vue simplifiée et stylisée du calculateur sous-jacent. En effet, le système d’exploitation d’un ordinateur physique doit effectuer des opérations sur des disques durs, écrans, imprimantes et autres dispositifs matériels, dits périphériques, dont il existe une grande variété. Il est indispensable d’interposer une couche d’abstraction entre ces matériels et l’utilisateur : je peux recopier le texte de mon programme sur mon disque dur sans savoir combien celui-ci possède de pistes et combien il peut stocker de caractères par piste. Le système d’exploitation me cache ces détails, qui n’ont aucun intérêt pour moi, mais que l’ingénieur qui écrit le sous-programme du système chargé d’écrire sur le disque doit connaître (ce sous-programme se nomme un pilote d’appareil périphérique, en anglais driver). Incidemment, la prise réseau est un périphérique comme un autre.
De même, le système d’exploitation me cache les méthodes complexes grâce auxquelles je peux exécuter simultanément sur mon ordinateur plusieurs logiciels : naviguer sur le Web, y copier des données pour les recopier dans la fenêtre du traitement de texte, imprimer un autre texte, etc.
En fait, tous les autres programmes sont des sous-programmes du système d’exploitation.
Machines virtuelles
Dans le cas simple, sans recours à la virtualisation, il y a un ordinateur, sur cet ordinateur est installé un système d’exploitation, et ainsi on peut exécuter des programmes sous le contrôle de ce système d’exploitation, qui s’interpose entre le programme et le matériel de l’ordinateur. Le matériel, ce sont des appareils qui sont capables d’émettre et de recevoir des signaux électroniques qui commandent leur fonctionnement.
Maintenant, instruit par les lignes ci-dessus, je peux écrire un logiciel qui se comporte en tout point comme un autre ordinateur (qui le simule, ou qui l’émule, selon le jargon en usage). Et ce simulacre d’ordinateur peut accueillir un système d’exploitation, qui lui même permettra l’exécution de logiciels. Ce logiciel qui fait semblant d’être un ordinateur, on l’appelle une machine virtuelle. Sur un ordinateur physique, je peux ainsi avoir plusieurs machines virtuelles qui émulent plusieurs autres ordinateurs physiques et/ou plusieurs autres systèmes d’exploitation. C’est très pratique pour les usages suivants :
– Tester un nouveau système sans mobiliser un ordinateur à cet effet.
– Avoir plusieurs systèmes actifs simultanément sur le même ordinateur : Linux, OpenBSD, Windows...
– Il est même possible d’avoir une machine virtuelle qui simule un ordinateur physique d’un modèle différent de la machine d’accueil, avec un jeu d’instructions (une architecture matérielle) différent(e).
– Comme les machines virtuelles ont des système d’exploitation différents, deux logiciels qui fonctionnent sur deux machines virtuelles différentes sont mieux isolés l’un de l’autre que s’ils coexistaient sous le contrôle du même système, ce qui a des avantages en termes de sécurité.
– Une machine virtuelle est constituée de logiciel, et aussi des données nécessaires à son fonctionnement, telles que paramètres du système et données des utilisateurs, enregistrées sur support persistant. L’ensemble constitué du texte du logiciel de la machine virtuelle et des données persistantes associées constitue l’image physique de la machine virtuelle, recopiable, transférable par le réseau.
– Une machine virtuelle, c’est du logiciel et des données, donc il est possible de la recopier comme un document ordinaire ; ainsi, avec la virtualisation, l’administration des systèmes devient plus facile : déplacer un serveur, c’est déplacer un fichier, le sauvegarder, c’est copier un fichier sur une clé USB, doubler un serveur, c’est recopier un fichier, cela prend quelques secondes et quelques clics de souris, sans se déplacer en salle machine (on dit maintenant centre de données) ; c’est sur ce principe que repose l’informatique dans les nuages (cloud computing), qui consiste à créer à la demande de nouvelles machines virtuelles et à les déplacer par le réseau sur les machines physiques les moins chargées, par exemple en Nouvelle-Zélande pour profiter du décalage horaire.
– Bien sûr, pour tout ce qui est enseignement, travaux pratiques, expériences, c’est très commode.
L’invention de la virtualisation des ordinateurs remonte à 1967, une époque où le moindre ordinateur coûtait des millions et occupait des centaines de mètres-carrés, par des équipes d’IBM à Grenoble et à Cambridge, pour des ordinateurs IBM 360-67. Ils ont été à l’origine en 1972 du système VM/370, qui est l’ancêtre de la famille de logiciels VMware. Jusque dans les années 2000, la puissance des ordinateurs disponibles limitait l’usage de la virtualisation, qui était néanmoins très utile pour tester de nouveaux systèmes sans avoir à déployer toute une infrastructure physique. Aujourd’hui la puissance des ordinateurs disponibles est très supérieure aux besoins des travaux les plus courants, alors le recours aux machines virtuelles est la règle dans le monde des entreprises. Le marché de l’hébergement de sites Web repose très largement sur cette technologie, et maintenant sur l’informatique en nuages, qui en est l’évolution normale.
Différents niveaux de virtualisation : conteneurs et hyperviseur
Comme la virtualisation repose sur du logiciel qui simule du matériel, l’imitation peut se faire de diverses façons :
– S’il faut simplement des systèmes isolés les uns des autres sur la même machine physique, il existe des systèmes de cloisonnement qui procurent à chaque logiciel serveur un environnement qui donne l’illusion de disposer d’une machine privée :
containers Linux, jail FreeBSD. Il y a en fait un seul système d’exploitation en service, mais chaque serveur fonctionne comme s’il était seul, ce qui lui confère une sécurité accrue (sauf défaillance du logiciel).
– S’il faut vraiment des machines virtuelles distinctes, mais toutes sur le même modèle de processeur (même architecture matérielle), il faudra interposer entre le matériel et les différentes copies du système d’exploitation un logiciel de simulation, mais les opérations élémentaires seront néanmoins effectuées par le matériel sous-jacent, ce qui évitera la grande diminution des performances qui serait entraînée par la simulation en logiciel des dites opérations.
VMware, Xen, KVM, Citrix, Microsoft Hyper-V Server sont de tels systèmes, nommés hyperviseurs. Les hyperviseurs sont en fait des systèmes d’exploitation allégés de beaucoup des fonctions qui seront dévolues aux OS hébergés. Les processeurs modernes sont équipés de dispositifs matériels qui facilitent leur exécution (Intel VT et AMD Pacifica).
– Ce n’est que si l’on veut simuler sur un ordinateur physique d’architecture A (par exemple Intel x86) une machine virtuelle d’architecture B (par exemple ARM Cortex-A50) qu’il faudra simuler sur A, par du logiciel, le jeu d’opérations élémentaires de B, ce qui aura un coût élevé en termes de performances. QEMU est un logiciel libre d’émulation de processeur, créé par Fabrice Bellard, qui offre ce type de possibilité, par l’intermédiaire d’un hyperviseur tel que Xen ou KVM.
Toutes ces machines virtuelles peuvent bien sûr communiquer entre elles et avec le vaste monde par un réseau... virtuel évidemment ! mais qui doit néanmoins établir des passerelles, voire des ponts, avec le réseau réel, par l’intermédiaire de routeurs et de commutateurs virtuels : tous les systèmes de virtualisation modernes fournissent ce type d’accessoire, dès lors que l’on sait virtualiser, on peut tout virtualiser.
Comme une machine physique, une machine virtuelle peut être « démarrée » et « arrêtée » ; dans ce cas il s’agira en réalité du lancement d’un programme et de son arrêt.
Machines virtuelles pour des langages
Les machines virtuelles mentionnées jusqu’ici visent à émuler des machines physiques et les systèmes d’exploitation qui s’y appliquent, mais il y a d’autres possibilités. Il existe ainsi des machines virtuelles spécialisées pour l’exécution de programmes rédigées dans un certain langage. Les plus célèbres sont les machines virtuelles pour le langage Java (JVM), mais il y en a pour d’autres langages. Le texte du programme Java est traduit dans le langage de la machine virtuelle, appelé code intermédiaire (bytecode). La machine virtuelle sait interpréter le code intermédiaire, comme le processeur physique sait interpréter le langage machine.
Ce programme peut ensuite être diffusé par le réseau et être exécuté sur tout ordinateur, physique ou virtuel, doté d’un exemplaire de la JVM, ce qui donne naissance à la notion de code mobile, très utile pour tout ce qui est programmation pour le Web, parce qu’ainsi on n’a pas besoin de savoir quel type d’ordinateur et de système d’exploitation utilise le destinataire.
Administration d’un système informatique
Pour maintenir un ordinateur en état de marche correct, un certain nombre de tâches doivent être effectuées régulièrement, notamment :
– mise à jour du système d’exploitation et des logiciels à partir des nouvelles versions fournies par les éditeurs ;
– mise à jour des bases de données des systèmes anti-virus et anti-intrusion ;
– mise à jour de la base de données des utilisateurs autorisés pour tenir compte des arrivées et des départs ;
– consultation quotidienne des journaux d’incidents ;
– sauvegarde des données ;
– vérification de la disponibilité d’un espace de stockage de données suffisant ;
– application des corrections de sécurité pour supprimer les vulnérabilités connues.
Ces opérations (la liste n’est pas complète), que nous désignerons du terme d’« administration système », peuvent être en partie automatisées, elles sont bien sûr moins absorbantes pour un poste de travail personnel que pour un serveur avec des dizaines d’utilisateurs directs, ou que pour un serveur Web ouvert à tous les publics, mais elles constituent une part importante du travail des ingénieurs système, que les serveurs soient virtuels ou des machines physiques.
Administration d’un système virtuel éteint
Les opérations d’administration du système d’une machine physique supposent que la machine soit en marche : en effet, la consultation des paramètres du système, leur modification, les copies de fichiers supposent que soient actifs un éditeur de texte, et quelques commandes du système, et que l’on ait accès aux données persistantes sur les disques durs, à tout le moins. Machine éteinte, rien ne serait possible.
Il en va tout autrement pour une machine virtuelle : nous avons vu qu’en fait elle était constituée de logiciels et de données hébergées sur un ordinateur physique. De ce fait, machine virtuelle arrêtée - et à condition bien sûr que la machine physique sous-jacente, elle, ne soit pas arrêtée - il est possible, grâce au système d’exploitation et aux logiciels de la machine physique d’accueil, d’accéder aux paramètres de son système et à ses données. Si l’on en connaît le format et l’organisation, on pourra effectuer les opérations d’administration. Enfin, c’est plus vite dit que fait.
Trois ingénieurs de CA Technologies à Hyderabad en Inde et à Datchet en Angleterre, Nishant Thorat, Arvind Raghavendran et Nigel Groves, ont mis en œuvre une telle solution d’administration, et ils ont écrit dans les Communications of the ACM, Vol. 56 No. 4, Pages 75-81, un article qui la décrit. Ils ont tiré parti du fait que les principaux éditeurs de systèmes de virtualisation se sont entendus sur des formats de données publiés. La Distributed Management Task Force (DMTF ; http://dmtf.org/) a publié l’Open Virtualization Format, ou OVF, une spécification adoptée par les principaux éditeurs (tels que Citrix, Microsoft et VMware) et acceptée comme norme en août 2010 par l’American National Standards Institute (ANSI ; http://ansi.org/).
Les avantages d’une telle solution sont patents : à l’heure de l’informatique en nuage, où les machines virtuelles se propagent aux quatre coins de l’Internet et s’y reproduisent à qui mieux mieux, leur appliquer « au vol » un plan de maintenance est bien plus difficile que pour un parc de machines physiques sagement rangées dans les armoires d’un centre de données. Il est plus facile de travailler sur l’image physique qui a servi à engendrer toutes ces machines virtuelles, et qui est généralement stockée dans un endroit centralisé bien identifié.
Nos auteurs ne manquent pas de souligner que cette solution présente aussi des inconvénients (mineurs) : certaines opérations qui nécessitent l’observation de la machine en marche ne sont pas possibles, et il reste du travail à faire pour que l’on puisse utiliser les mêmes procédures d’administration sur les machines arrêtées et sur les machines en marche.