Administration Système, LP MRIT 2022 - 2023

Plan du cours


Programmation shell

Démarrer avec RosettaHub

Quelques outils pour installer des paquets : la problématique des dépendances

Conteneurs et composants d'isolation (LXC, cgroup, namespace) : environnements virtualisés

Introduction aux technologies DevOps


Préambule

L'évaluation du module consiste à rédiger un compte rendu de TP reprenant l'ensemble des manipulations que vous allez faire. Il ne s'agit pas de vouloir traiter l'ensemble des questions proposéses, mais d'en sélectionner un sous ensemble, que vous jugerez intéressant. Pour édiger un compte rendu de TP, il est opportun de suivre les recommandations suivantes :


Programmation shell

Le shell est un interpréteur de commandes et aussi un langage de programmation. Il existe de nombreux shell (interpréteurs de commandes), parmi lesquels sh, bash, tcsh, zsh... Sur un système d'exploitation Unix, il est utilisé pour programmer des enchainements de tâches visant par exemple le déploiement, l'installation et la configuration d'un Service. Sur ma machine personnelle, je trouve par exemple les scripts suivants :

MBPdeChristophe:local christophecerin$ cd /
MBPdeChristophe:/ christophecerin$ find . -iname "*.sh"
./usr/bin/power_report.sh
./usr/libexec/feedback/sleepwake.sh
./usr/libexec/postfix/mk_postfix_spool.sh
./usr/libexec/postfix/set_credentials.sh
find: ./usr/sbin/authserver: Permission denied
./usr/local/go/misc/ios/clangwrap.sh
./usr/local/go/src/cmd/go/mkalldocs.sh
./usr/local/go/src/cmd/vendor/github.com/google/pprof/test.sh
./usr/local/go/src/runtime/mknacl.sh
./usr/local/go/src/syscall/mkall.sh
./usr/local/go/src/syscall/mkerrors.sh
./usr/local/go/src/syscall/mksysnum_plan9.sh
./usr/local/bin/pv.sh
./usr/local/bin/unix-lpr.sh
./usr/local/bin/gvmap.sh
./usr/local/bin/lprsetup.sh

Remise en forme / Révisions Relire les chapitres d'un cours de système du semestre 1 : Chapitre 4 et Chapitre 5. Pour continuer à réviser les notions vues au réalable voir le lien suivant à l'Idris. Vous pouvez aussi consulter Wikipedia pour un résumé des principales commandes Unix. Encore mieux : le super résumé des commandes Bash. Il y a aussi un point spécial pour lire des fichiers texte.

Ecriture de scripts. Les objectifs de ce polycopié sont d'introduire la syntaxe du langage de commande bash et de faire du lien avec les notions fondamentales de tout langage de programmation : mise en séquence, choix et itération. Par ailleurs on remarquera que bash est un langage beaucoup moins typé que C par exemple : on peut ranger dans i un entier puis, plus loin dans le code source, une chaine. Par ailleurs, bash possède un mécanisme d'évaluation d'expressions un peu particulier et ne permet pas de faire directement de l'arithmétique sur les réels. Cela constitue également deux points de discussion du cours. En un mot, bash est replacé dans un contexte permettant de le situer entre les langages «à la C» et les langages dits de script (Perl, Python...).

Introduction aux expressions régulières. Il s'agit de décrire des motifs au moyen de classes prédéfinies normalisées. Ces classes prédéfinies sont des raccourcis pour faciliter la tâche du programmeur. Différents exemples de description de motifs via des classes sont présentés dans différents outils/langages. Par ailleurs et bien que non étudiées, voir aussi les pages sur la norme UNICODE pour exprimer des motifs.

Unix tools et REGEX (introduction à sed, cut, tail, head et notions de awk). Bash peut être utilisé pour l'administration d'un système : des fichiers en langage bash permettent l'activation de services, la vérification qu'un service est actif... Pour réaliser ces tâches, les outils sed, tail, head et awk sont introduits pour filtrer le résultat de commandes Unix (cp, ls, ps, cut ...) ou de scripts bash (un script bash est un programme dans la syntaxe du langage bash qui peut faire des appels à des commandes Unix externes au langage). On en profite pour compléter la description de motifs qui sont mis en correspondance avec un texte à vérifier (notion d'expression régulière).

Le cours sur le langage C et les appels système. Les objectifs sont d'être sensibilisé à la hiérarchie des droits entre utilisateurs et d'apprendre à programmer des appels aux fonctions internes du système d'exploitation. Les appels systèmes renvoient aux structures de données du noyau Unix. Les appels systèmes peuvent être effectués en mode utilisateur (un utilisateur ayant des droits minimaux peut les appeler) ou en mode noyau (le super utilisateur seul peut les effectuer – par exemple, reprogrammer l'ordonnanceur des processus). Ensuite nous passerons à la présentation des outils make et des outils d'archivage ... Il s'agit ici d'aspects organisationnels visant à structurer les différentes phases permettant de passer d'un code source à un code exécutable. A cette occasion nous parlerons aussi des fichiers objets, des librairies partagées, des librairies statiques.

Les exercices sont ici ou encore . Il y a également des exercices pour SED. Enfin vous pouvez consulter les questions et réponses à certains problèmes récurrents.


Démarrer avec RosettaHub

La ressource informatique (CPU, disque, réseau) est abondante... et parfois gratuite. Nous allons utiliser la plateforme RosettaHub pour prendre des machines viruelles chez Amazon. Le point d'entrée et la documentation à lire est le suivant.

Je vais commenter toute la documentation et nous allons réaliser la réservation d'instances chez Amazon.

Il y a un point technique qui heurte souvent les étudiants : la notion de clés publiques / clés privées. Ces notions sont utiles pour les questions d'authentification qui reposent sur les certificats de confiance. Pour se familiariser avec ces notions, voir le cours de crypto ou encore, de manière pratique à ce document à la partie SSH. La génération de clés est détaillée ici. C'est très important pour nous puisqu'il va falloir s'authentifier auprès d'Amazon/RosettaHub. En fait il y a deux façons de voir les choses. Soit vous générez des clés et vous devez les déposer sur le "serveur", soit c'est le serveur qui vous donne des clés que vous devez déposer dans un répertoire .ssh de votre arborescence.

Pour un compte AWS Educate, l'accès aux informations relatives à AWSAccessKeyId et AWSSecretKey s'effectue à partir des menus décrits aux Figures 1 et 2. Veuillez cliquer sur l'onglet qui est souligné en rouge sur la Figure 1 pour accéder aux informations... qui sont cachées sur la Figure 2 pour ne pas révéler de secret !

Figure 1: Menu relatif à votre compte Educate
Figure 2: Les informations sont cachées mais elles sont là !

Quelques outils pour installer des paquets sous Linux : la problématique des dépendances

Historiquement il y avait plusieurs formats pour les applications packagées pour une distribution Linux : rpm, deb... De même, il y a plusieurs outils pour automatiser l'installation et la configuration d'une application que vous souhaitez installer. Vous pouvez prendre comme point d'entrée la documentation Ubuntu suivante.

Utiliser apt pour installer des paquets

Comme exercice d'application, vous pouvez prendre une machine virtuelle chez Amazon et demander l'installation de LAMP (Apache, PHP, Mysql). Attention, il va falloir ouvrir le port 80 pour que le service Apache soit accessible depuis l'extérieur d'Amazon. Veuillez configurer les services réseux en conséquence.

Trois exercices pour appréhender la gestion de paquets

Les trois exercices qui suivent permettent de travailler la notion de dépendances au niveau de Linux puis au niveau d'un langage de programmation. Vous êtes ici admin sys mais aussi développeur. La problématique de gestion des dépendances est la même : comment s'assurer que je peux mettre à jour un système ou une application ?

a) Ecrivez un script Bash qui automatise l'installation de la pile logicielle LAMP (historiquement : Apache MySql et PHP... vous remplacerez MySql par MariaDB). Attention, il faut aussi automatiser la configuration des trois services, donc le script ne se réduit pas à trois apt-get install.

b) Commencez par installer Go (golang) sur votre machine, puis lisez https://go.dev/doc/modules/managing-dependencies. Rejouer les exemples de la page https://www.honeybadger.io/blog/golang-go-package-management/ Rappel : Go est le langage de programmation de Google. Le projet Kubernetes est par exemple développé en Go.

c) Pour Python, lire et comprendre la page https://pip.pypa.io/en/latest/getting-started/ qui résume la gestion de paquets via pip. Télécharger le fichier test_ecoindex.py depuis le dépot https://github.com/christophe-cerin/Ecoindex-Revisited et écrire deux versions différentes et admissibles de requirements.txt pour gérer les dépendances de ce code Python, et que de ce code Python. Ecrire également des tests qui convainquent que l'installation et l’exécution de test_ecoindex.py sont effectives.

d) Rust est un langage de programmation qui sert depuis peu pour la construction du noyau Linux. Lire d'abord cette introduction au langage Rust, puis allez à la section de gestion des paquets avec Cargo. Rejouer l'exemple qui vous est proposé mais en modifiant la fonction main() afin d'exécuter le script Bash pi.sh. Je vous laisse découvrir comment faire pour exécuter un programme externe.

Pour votre culture générale, passez un peu de temps ce week-end pour comprendre l'essence et la nature du projet NIX (https://nixos.org/ et https://github.com/NixOS/nix et https://nix-tutorial.gitlabpages.inria.fr/nix-tutorial/getting-started.html pour des exemples)

Gestion des paquets en Python - Application à AWS / Libcloud

Attention, Python par exemple a une gestion propre des paquets. Veuillez par exemple installer libcloud. Pour faire les exemples de la home page de libcloud, en utilisant EC2 comme provider, vous allez avoir besoin d'informations pour l'authentification auprès de AWS. Vous avez aussi besoin d'informations sur les tailles et noms d'images disponbiles. Pour cela, veuillez consulter le fichier de taille 12Mo contenant des informations utiles pour vous. Au final, veuillez adapter le code :

  #
  # For more information about EC2 driver, check
  # https://libcloud.readthedocs.io/en/stable/compute/drivers/ec2.html
  #
  from libcloud.compute.types import Provider
  from libcloud.compute.providers import get_driver

  cls = get_driver(Provider.EC2)
  driver = cls('My access key','My secret key', region='My region')
  # Hint: file rootkey.csv contains many information

  sizes = driver.list_sizes()
  images = driver.list_images()

  size = [s for s in sizes if s.id == 't2.micro' and s.ram == 1024][0]
  image = [i for i in images if 'My prefered AMI id' in i.id][0]

  print('-=-=-=-=-=-=-=-=-=-=-')
  print('Size: '+str(size))
  print('Image: '+str(image))
  print('-=-=-=-=-=-=-=-=-=-=-')

  node = driver.create_node(name='libcloud_cerin', size=size, image=image)
  print('Node: '+str(node))

  #print(sizes)
  #print(images)

Votre objectif est de faire apparaitre votre instance ainsi créée dans le dashbord des instances AWS. Veuillez faire une capture d'écran pour montrer que vous avez réussi à créer une instance, de manière programmatique. Passez ensuite à l'adaptation du code suivant qui va réaliser une mise à jour de l'instance créée. Cependant, il y a un problème avec l'appel à deploy_node(). Pouvez-vous le corriger... en examinant la documentation de cette fonction ?

  #
  # For more information about EC2 driver, check
  # https://libcloud.readthedocs.io/en/stable/compute/drivers/ec2.html
  # and also
  # https://libcloud.readthedocs.io/en/stable/compute/examples.html
  #
  from libcloud.compute.types import Provider
  from libcloud.compute.providers import get_driver
  from libcloud.compute.deployment import MultiStepDeployment
  from libcloud.compute.deployment import ScriptDeployment, SSHKeyDeployment

  cls = get_driver(Provider.EC2)
  driver = cls('........','.......', region='eu-west-1')
  # file rootkey.csv contains useful information

  sizes = driver.list_sizes()
  images = driver.list_images()

  size = [s for s in sizes if s.id == 't2.micro' and s.ram == 1024][0]
  image = [i for i in images if 'ami-0f1d11c92a9467c07' in i.id][0]

  print('-=-=-=-=-=-=-=-=-=-=-')
  print('Size: '+str(size))
  print('Image: '+str(image))
  print('-=-=-=-=-=-=-=-=-=-=-')

  # Shell script to run on the remote server to install emacs
  SCRIPT = '''#!/usr/bin/env bash
  apt -y update && apt -y upgrade && apt-get -y install emacs
  '''

  # A simple script to install emacs post boot, can be much more complicated.
  step_1 = ScriptDeployment(SCRIPT)

  msd = MultiStepDeployment([step_1])

  node = driver.deploy_node(name='libcloud_cerin', size=size, image=image, deploy=msd)
  print('Node: '+str(node))

  #print(sizes)
  #print(images)

  ################################
  MBPdeChristophe:~ christophecerin$ pip3 install paramiko
  WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
  Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
  To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
  Defaulting to user installation because normal site-packages is not writeable
  Collecting paramiko
  Downloading paramiko-2.7.2-py2.py3-none-any.whl (206 kB)
  |████████████████████████████████| 206 kB 7.0 MB/s
  Collecting bcrypt>=3.1.3
  Downloading bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl (31 kB)
  Requirement already satisfied: six>=1.4.1 in /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site-packages (from bcrypt>=3.1.3->paramiko) (1.15.0)
  Collecting cffi>=1.1
  Downloading cffi-1.14.4-cp38-cp38-macosx_10_9_x86_64.whl (176 kB)
  |████████████████████████████████| 176 kB 24.9 MB/s
  Collecting cryptography>=2.5
  Downloading cryptography-3.3.1-cp36-abi3-macosx_10_10_x86_64.whl (1.8 MB)
  |████████████████████████████████| 1.8 MB 31.1 MB/s
  Requirement already satisfied: six>=1.4.1 in /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site-packages (from bcrypt>=3.1.3->paramiko) (1.15.0)
  Collecting pycparser
  Downloading pycparser-2.20-py2.py3-none-any.whl (112 kB)
  |████████████████████████████████| 112 kB 31.2 MB/s
  Collecting pynacl>=1.0.1
  Downloading PyNaCl-1.4.0-cp35-abi3-macosx_10_10_x86_64.whl (380 kB)
  |████████████████████████████████| 380 kB 25.5 MB/s
  Requirement already satisfied: six>=1.4.1 in /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site-packages (from bcrypt>=3.1.3->paramiko) (1.15.0)
  Installing collected packages: pycparser, cffi, pynacl, cryptography, bcrypt, paramiko
  Successfully installed bcrypt-3.2.0 cffi-1.14.4 cryptography-3.3.1 paramiko-2.7.2 pycparser-2.20 pynacl-1.4.0

A l'issue des modifications, modulo l'adresse IP de votre instance et après un ssh dans l'instance, vous devriez obtenir quelque chose comme ce qui suit, avec notamment l'information comme quoi l'instance est bien à jour :

  MBPdeChristophe:~ christophecerin$ python3 libcloud_Create_EC2_node_with_post_install.py
  -=-=-=-=-=-=-=-=-=-=-
  Size: <NodeSize: id=t2.micro, name=t2.micro, ram=1024 disk=0 bandwidth=None price=0.0126 driver=Amazon EC2 ...>
  Image: <NodeImage: id=ami-0f1d11c92a9467c07, name=ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20200729, driver=Amazon EC2  ...>
  -=-=-=-=-=-=-=-=-=-=-
  Node: <Node: uuid=a9a2d98332864335f6a883794afd1ab96e5ceff5, name=libcloud_cerin, state=RUNNING, public_ips=['52.211.241.27'], private_ips=['172.31.3.45'], provider=Amazon EC2 ...>
  MBPdeChristophe:~ christophecerin$ ssh -i "CERIN-MRIT.pem" ubuntu@ec2-52-211-241-27.eu-west-1.compute.amazonaws.com
  The authenticity of host 'ec2-52-211-241-27.eu-west-1.compute.amazonaws.com (52.211.241.27)' can't be established.
  ECDSA key fingerprint is SHA256:laU5xVsi702Vl+gpa0P+21/I2UivFD2Dlbw/7RDOwCw.
  Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
  Warning: Permanently added 'ec2-52-211-241-27.eu-west-1.compute.amazonaws.com,52.211.241.27' (ECDSA) to the list of known hosts.
  Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-1021-aws x86_64)

  * Documentation:  https://help.ubuntu.com
  * Management:     https://landscape.canonical.com
  * Support:        https://ubuntu.com/advantage

  System information as of Sun Dec 13 17:14:10 UTC 2020

  System load:  0.84              Processes:             107
  Usage of /:   26.9% of 7.69GB   Users logged in:       0
  Memory usage: 26%               IPv4 address for eth0: 172.31.3.45
  Swap usage:   0%


  0 updates can be installed immediately.
  0 of these updates are security updates.


  *** System restart required ***
  ubuntu@ip-172-31-3-45:~$ 

Enfin, si vous avez du temps, vous pouvez envisager l'installation, la configuration et le provisionnement automatique d'un serveur VNC dans votre VM Amazon... et vous y connecter. L'objectif est d'obtenir l'image qui suit :

Figure 1 : Résultat du déploiement automatique dans Amazon du gestionnaire de fenêtres Xfce ainsi que d'un serveur VNC.

Depuis un terminal à la maison, je dois d'abord ouvrir un tunnel ssh sur la machine chez Amazon (avec des redirections de ports -- 5901 étant le port de communication par défaut du serveur VNC) :

  ssh -i "CERIN-MRIT.pem" -L 5901:127.0.0.1:5901 -C -N -l ubuntu 54.154.63.209

Puis, toujours depuis un terminal à la maison, je lance le client novnc. Au lancement, on me donne l'URL que je dois taper dans mon navigateur pour accéder à la VM d'Amazon. Voir la barre de navigation de la Figure 1.

  MBPdeChristophe:noVNC-1.2.0 christophecerin$ ./utils/launch.sh --vnc localhost:5901
  readlink: illegal option -- f
  usage: readlink [-n] [file ...]
  Warning: could not find self.pem
  No installed websockify, attempting to clone websockify...
  Cloning into '/Users/christophecerin/Downloads/noVNC-1.2.0/websockify'...
  remote: Enumerating objects: 13, done.
  remote: Counting objects: 100% (13/13), done.
  remote: Compressing objects: 100% (11/11), done.
  remote: Total 4221 (delta 5), reused 6 (delta 2), pack-reused 4208
  Receiving objects: 100% (4221/4221), 4.61 MiB | 990.00 KiB/s, done.
  Resolving deltas: 100% (2775/2775), done.
  Using local websockify at /Users/christophecerin/Downloads/noVNC-1.2.0/websockify/run
  Starting webserver and WebSockets proxy on port 6080


  Navigate to this URL:

  http://MBPdeChristophe:6080/vnc.html?host=MBPdeChristophe&port=6080

  Press Ctrl-C to exit


  WebSocket server settings:
  - Listen on :6080
  - Web server. Web root: /Users/christophecerin/Downloads/noVNC-1.2.0
  - No SSL/TLS support (no cert file)
  - proxying from :6080 to localhost:5901
  192.168.1.142 - - [14/Dec/2020 10:22:38] 192.168.1.142: Plain non-SSL (ws://) WebSocket connection
  192.168.1.142 - - [14/Dec/2020 10:22:38] 192.168.1.142: Path: '/websockify'
  192.168.1.142 - - [14/Dec/2020 10:22:38] connecting to: localhost:5901
  handler exception: [Errno 57] Socket is not connected
  ^CIn exit

  Terminating WebSockets proxy (26113)
  MBPdeChristophe:noVNC-1.2.0 christophecerin$ 

Pour l'installation, dans une machine Ubuntu, d'un serveur VNC, voir ce lien. Pour le client novnc voir cet autre lien.

Gestion des paquets avec Go

Le langage de programmation Go a aussi un mécanisme de gestion spécifique des librairies qui lui est propre. Voir ici pour installer une librairie de clustering (rassembler des objets identiques). A titre d'exercice, vous pouvez installer Go, puis cette librairie, puis vous pouvez faire tourner un des exemples proposé.


Conteneurs et composants d'isolation : environnements virtualisés

Les conteneurs offent des mécanismes de virtualisation des ressources du système d'exploitation. Ils sont en train de supplanter les mécanismes de machines virtuelles (VM) pour de nombreuses raisons. Ils sont par exemples moins gourmands en terme de mémoire consommée.

Un point d'entrée possible pour les notions de virtualisation est tout simplement la page Wikipedia. Je vais bien entendu commenter chacune des techniques. Nous allons plus particulièrement commenter les notions de cgroups et les name spaces qui regroupent les concepts (voir en bas de la page Wikipedia pour des tutoriels / documentation). Ces notions sont au coeur des projets orientés conteneurs comme Docker.

Pour jouer avec les conteneurs :

  • Nous allons utiliser l'interface de programmation LXC. Je vous invite à suivre l'exemple Getting Started. Si nous étions plus ambitieux, nous pourrions nous servir de cet exemple pour concevoir un outil "à la Docker" c.à.d capable d'allouer, à partir d'une file de requêtes, des conteneurs sur différentes machines du cloud Amazon.
  • Nous allons faire le TP suivant qui concerne les machines virtuelles (VMs) et les conteneurs.


Introduction aux technologies DevOps

Le devops est un mouvement en ingénierie informatique et une pratique technique visant à l'unification du développement logiciel (dev) et de l'administration des infrastructures informatiques (ops), notamment l'administration système. Nous allons nous contenter ici d'examiner un outil de la chaîne des outils de DevOps.

Nous pouvons effectivement suivre pas à pas l'utilisation de Ansible. Nous pouvons déployer 3 machines dans Amazon et automatiser le déploiement d'applications sur ces machines. Ansible est fait pour cela ! Enfin, pour nous qui sommes des grands débuttants avec ces technologies, c'est sur le papier. Nous allons voir ce que l'on peut vraiment faire en pratique. La clef du succès est d'être au clair sur les concepts d'Ansible, par exemple en lisant la page suivante issue du site du projet. Nous y verrons qu'Ansible est un outil "that automates cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs." Un couteau Suisse ?

Pour votre information et concernant les outils DevOps pour configuration, provisionning et deploiement, l'univers de la distribution Linux Ubuntu utilise l'outil conjure-up qui est construit sur les technologies Juju, MAAS et LXD (voir le User manual). Conjure-up va vous permettre d'installer simplement des frameworks complexes tels que OpenStack ou Kubernetes.

Mais pour le TP, nous allons utiliser un autre outil dans la famille des outils DevOps : le sujet de votre travail est ici. Patience, patience !

Pour une discussion sur "Ansible et Vagrant", je vous recommande cette page et si nous avons du temps nous pourrions examiner ces exemples de couplage Ansible-Vagrant pour installer et configurer différentes VMs. Ce sont des exemple d'utilisation du provisionner Ansible dans Vagrant.