Aller au contenu

Installation de zéro

Version

Page écrite pour pupitre 0.1.35-1.

Cette page mène d'une machine vide à une salle servie : la VM, le réseau, le paquet (tout fait ou construit depuis les sources), la configuration, le premier boîtier, les comptes élèves, la console et la vérification. Elle renvoie aux pages de Fonctionnement interne et aux notes d'installation du dépôt, en anglais, pour le détail, au lieu de les recopier. Les fonctions récentes portent la mention « (depuis 0.1.N) » : si votre paquet est plus ancien, voyez Versions et fonctionnalités.

Installer pupitre de zéro : préparer l'hôte, créer la VM, puis le paquet tout fait ou les sources, installer, configurer, allumer le premier boîtier, comptes élèves, console, vérifier

Prérequis

Quoi Exigence Pourquoi
Système Debian 13 (trixie), et lui seul Le paquet dépend de systemd (>= 254) : l'unité de siège utilise RestartSteps= et RestartMaxDelaySec=, absents de Debian 12.
Hyperviseur KVM avec libvirt Celui que décrit cette page. Un autre hyperviseur doit offrir une carte en pont sur le VLAN des boîtiers.
Réseau Une carte de la VM en pont, sur le même VLAN que les boîtiers Voir plus bas : ni NAT, ni routage.
Commutateur Gigabit Un siège en vidéo atteint environ 6 Mio/s ; treize sièges en vidéo à la fois font environ 660 Mbit/s.
Boîtiers Dell Wyse 1010, adresse par DHCP pupitre ne sert pas de DHCP : celui du VLAN donne leur adresse aux boîtiers.

Le détail du réseau, des débits et du dimensionnement est sur la page Architecture et réseau.

Créer la VM

Ressources

Tableau indicatif, le même que dans Architecture et réseau, où se trouve la règle de calcul :

Sièges vCPU Mémoire Disque Débit maximal vers le serveur
5 2 8 Go 30 Go ≈ 255 Mbit/s
10 4 16 Go 40 Go ≈ 510 Mbit/s
15 6 32 Go 50 Go ≈ 765 Mbit/s
20 8 32 Go 60 Go ≈ 1 020 Mbit/s, au-delà d'un lien à 1 Gbit/s

Le débit maximal est celui où tous les postes lisent une vidéo en même temps ; en bureautique, comptez environ 2,3 Mbit/s par poste. Le démonstrateur (tools/demo-vm.sh) se contente de 2 vCPU, 4 Go et 20 Go. Au-delà de 15 sièges, le nombre par défaut depuis 0.1.35, réglez seats dans /etc/pupitre/pupitre.conf (seats = 0 lève la limite).

La mémoire se dimensionne sur le navigateur, pas sur le bureau : un bureau au repos coûte de 128 à 162 Mio de plus par siège, mais Firefox ouvert sur une seule page en ajoute environ 590 Mio.

Compression mémoire zram

zram compresse en mémoire les pages froides des sièges (environ 5 pour 1 pour un bureau au repos) et permet de tenir avec moins de mémoire que le tableau. Rien n'est posé par le paquet :

  1. sudo apt install systemd-zram-generator. Ce paquet seul change déjà l'échange de la machine : Debian livre une section [zram0] nue, qui crée tout de suite un périphérique zram de la moitié de la mémoire, compressé en lz4.
  2. Copiez les deux fichiers livrés par pupitre, qui passent à zstd et à une taille par siège : /usr/share/pupitre/zram-generator.conf vers /etc/systemd/zram-generator.conf, et /usr/share/pupitre/99-pupitre-zram.conf vers /etc/sysctl.d/. Ajustez zram-size à environ 500 Mio par siège, sans dépasser la moitié de la mémoire.
  3. Posez PUPITRE_MEMOIRE=1 dans un drop-in de pupitre-seat@.service (voir Les sièges) : chaque siège reçoit une limite souple MemoryHigh de (mémoire moins 2048 Mio) divisée par PUPITRE_SEATS (15 par défaut), jamais moins de 512 Mio. Un nombre à la place de 1 fixe la limite à la main, en Mio. Il n'y a volontairement pas de MemoryMax, qui tuerait le navigateur d'un élève.

Pourquoi une carte en pont, jamais de NAT

Le boîtier trouve le serveur par une diffusion UDP sur le port 52330, et fast_tcp2 lui parle en TCP brut sur une socket AF_PACKET, adressée à la MAC du boîtier. Une diffusion ne traverse ni un NAT ni un routeur : la carte de la VM doit être dans le même domaine de diffusion que les boîtiers. Le Wi-Fi ne se ponte pas. Le protocole n'a ni authentification ni chiffrement : un VLAN réservé aux boîtiers et au serveur est préférable.

Installer Debian 13

Installez Debian 13 sans bureau (tâches « utilitaires usuels du système » et « serveur SSH »). Ce choix compte : la brique dns-recherche-sure, allumée par défaut (depuis 0.1.33), suppose un /etc/resolv.conf écrit par dhcpcd, ce que donne une installation sans bureau (ifupdown et dhcpcd). Avec NetworkManager, elle refuse de s'allumer, l'installation continue et le dit.

La commande suivante reprend celle du démonstrateur (tools/demo-vm.sh), sans son fichier de préréponses : l'installateur pose donc ses questions sur la console série. Ajustez le nom, la mémoire, les vCPU et le disque à votre salle (voir la documentation de virt-install).

virt-install --connect qemu:///system --name pupitre --memory 4096 --vcpus 2 \
  --disk size=20 --osinfo detect=on,require=off \
  --location https://deb.debian.org/debian/dists/trixie/main/installer-amd64/ \
  --extra-args "console=ttyS0,115200n8" \
  --network network=default,model=virtio \
  --graphics none

La carte en pont s'ajoute ensuite. La démo utilise macvtap en mode pont sur l'interface filaire de l'hôte (ici enp1s0, à remplacer), décrite dans un fichier nic.xml :

<interface type='direct'>
  <source dev='enp1s0' mode='bridge'/>
  <model type='virtio'/>
</interface>
virsh -c qemu:///system attach-device pupitre nic.xml --persistent

Dans la VM, cette nouvelle carte prend une adresse par DHCP (une entrée iface ... inet dhcp dans /etc/network/interfaces). Avec macvtap, l'hôte lui-même ne joint pas la VM par cette carte : c'est pourquoi la démo garde aussi la carte NAT de libvirt, pour ssh et apt. Un pont Linux (br0) sur l'hyperviseur convient aussi : voir la documentation de libvirt.

Le raccourci de démonstration

Depuis une copie du dépôt, tools/demo-vm.sh <interface filaire> :

  • fait tout d'un coup : construit le paquet s'il n'y en a pas, installe Debian 13 sans question, ajoute la carte macvtap, installe pupitre et pointe sa configuration sur la bonne carte ;
  • dure 20 à 40 minutes ;
  • jamais pour une salle : il crée le compte demo, mot de passe pupitre, avec sudo sans mot de passe, connu de tous ;
  • prend le paquet le plus récemment modifié parmi ../pupitre_*_amd64.deb : vérifiez lequel.

Détails : A demo server in a virtual machine.

Chemin A : le paquet tout fait

Le paquet vient de l'artefact deb de l'intégration continue du dépôt (gardé un mois), ou d'une construction locale (chemin B). Aucun dépôt APT n'est publié à ce jour. Le dossier dist/ du dépôt ne contient qu'un ancien paquet 0.1.0-1 : ne vous en servez pas.

sudo apt install ./pupitre_0.1.35-1_amd64.deb

Le ./ dit à apt qu'il s'agit d'un fichier. Le paquet tire Xvfb, Xfce, LibreOffice et Firefox ESR avec leurs menus en français, PulseAudio, nftables, FUSE, Unbound, et recommande LightDM et son écran de connexion : n'installez pas avec --no-install-recommends, vous perdriez le mode élèves.

Ce que fait l'installation :

  1. crée l'utilisateur système pupitre, /var/lib/pupitre/home et /var/log/pupitre ;
  2. crée /home/eleves, parent des répertoires des élèves ;
  3. donne à /usr/lib/pupitre/fast_tcp2 les capacités cap_net_raw et cap_sys_nice : socket brute et priorité temps réel, sans être root ;
  4. allume dns-recherche-sure à la première installation, ou une seule fois en venant d'une version antérieure à 0.1.33 ; un échec ne bloque pas l'installation ;
  5. active user_allow_other dans /etc/fuse.conf, pour la clé USB ;
  6. active et démarre pupitre-nft, pupitre-manager et pupitre-web.

Les sièges (pupitre-seat@N) ne démarrent jamais seuls au boot : c'est le gestionnaire qui les lance quand un boîtier s'annonce.

Chemin B : depuis les sources

Sur une Debian 13, depuis une copie du dépôt :

sudo apt install build-essential devscripts equivs dpkg-dev
sudo mk-build-deps -i -r debian/control
PATH=/usr/bin:/bin dpkg-buildpackage -us -uc -b

mk-build-deps installe les dépendances de construction déclarées dans debian/control (debhelper, dh-python, pybuild, numpy, Pillow, pytest, libfuse3-dev, pkg-config). -us -uc : pas de signature ; -b : paquet binaire seulement.

Pourquoi PATH=/usr/bin:/bin. Un python3 qui n'est pas celui du système en tête du PATH (un virtualenv, pyenv, l'interpréteur d'un outil comme PlatformIO) casse pybuild avec No module named build. L'intégration continue impose la même forme.

La construction compile fast_tcp2 et wyse_cle_fuse, puis lance les tests : les programmes de test en C (make check) et pytest -m "not e2e". Un paquet qui se construit est donc un paquet dont les tests passent ; DEB_BUILD_OPTIONS=nocheck les saute. Les tests seuls, sans construire :

PATH=/usr/bin:/bin python3 -m pytest -q tests -m "not e2e"

Les tests e2e demandent un vrai boîtier ou un navigateur piloté ; ils ne tournent ni à la construction ni dans l'intégration continue.

Le paquet est déposé dans le répertoire parent du dépôt, ../pupitre_0.1.35-1_amd64.deb. Copiez-le sur la VM et reprenez le chemin A.

Configuration

Le gestionnaire : /etc/pupitre/pupitre.conf

Un seul réglage est indispensable : interface, qui doit désigner la carte en pont.

[server]
interface = enp7s0
sudo systemctl restart pupitre-manager
Clé Défaut Rôle
[server] interface eth0 la carte sur le VLAN des boîtiers
[server] ip vide : lue sur l'interface au démarrage adresse du serveur
[server] seats 15 (depuis 0.1.35 ; 0 : sans limite) nombre de sièges
[server] enroll yes inscription automatique d'un boîtier inconnu
[paths] seats_file /var/lib/pupitre/seats.json table MAC vers siège
[web] listen, port 127.0.0.1, 8080 console web
[web] password_file vide mot de passe de la console (depuis 0.1.14)

Un siège déjà lancé garde l'interface et l'adresse avec lesquelles il a démarré. Après un changement de l'une ou de l'autre, arrêtez puis redémarrez le gestionnaire (systemctl stop arrête tous les sièges), ou redémarrez les sièges. Voir Installing Pupitre, Configure et Gestionnaire.

Les sièges : variables PUPITRE_*

Le gestionnaire n'écrit dans /run/pupitre/seat-N.env que l'identité du siège (numéro, MAC et adresse du boîtier, adresse du serveur, interface). Tout autre réglage d'un siège passe par un drop-in systemd de son unité, jamais par pupitre.conf :

Pour le seul siège 3, le fichier est /etc/systemd/system/pupitre-seat@3.service.d/reglages.conf :

[Service]
Environment=PUPITRE_CONNEXION=eleves
Environment=PUPITRE_FERMETURE=900
sudo systemctl daemon-reload && sudo systemctl restart pupitre-seat@3

Un drop-in du gabarit, dans /etc/systemd/system/pupitre-seat@.service.d/reglages.conf, vaut pour tous les sièges (exemple : zram). Un drop-in dans /etc/systemd/system appartient à l'administrateur : il survit aux mises à jour.

Les réglages usuels, avec leur défaut dans 0.1.35-1 :

Variable Défaut Effet
PUPITRE_CONNEXION fixe eleves : écran de connexion par siège (depuis 0.1.27)
PUPITRE_FERMETURE 600 s (0 : jusqu'à PUPITRE_GRACE) ferme la session d'un élève dont le boîtier reste éteint (depuis 0.1.27)
PUPITRE_GRACE 600 s (0 : jamais) durée pendant laquelle le bureau est gardé sans boîtier (depuis 0.1.13)
PUPITRE_LAYOUT fr disposition du clavier
PUPITRE_QUIET_KEYS 1 journaux sans frappe ; jamais 0 sur le siège d'un élève

Les autres variables sont posées par le lanceur ; ne les changez pas sans raison. La liste complète est dans Versions et fonctionnalités et Siège ; ce qui se personnalise (apparence, Firefox, briques) est sur la page Couches personnalisables.

Premier boîtier et enrôlement

Branchez un boîtier sur le VLAN et allumez-le :

  1. il diffuse son annonce sur UDP 52330, par salves espacées d'environ 10 s ;
  2. le gestionnaire cherche sa MAC dans /var/lib/pupitre/seats.json ;
  3. inconnue et avec enroll = yes, elle reçoit aussitôt le plus petit numéro de siège libre ;
  4. le gestionnaire écrit /run/pupitre/seat-N.env et démarre pupitre-seat@N ;
  5. le bureau, ou l'écran de connexion en mode élèves, paraît sur l'écran du boîtier.

Le bureau paraît en une dizaine de secondes. Le lanceur fait jusqu'à cinq essais d'ouverture du lien (PUPITRE_ATTEMPTS) ; un siège qui n'y parvient pas peut attendre une dizaine de minutes avant d'être relancé : le bouton Restart de la console va plus vite.

Une fois tous les boîtiers de la salle inscrits, passez enroll = no : un boîtier égaré restera inactif, listé dans la console sous « Stations without a seat », où le bouton Assign lui donne un siège. Sur un siège en session, le bouton Identify affiche « Seat N » en grand sur l'écran du boîtier pendant 5 s, pratique pour étiqueter la salle. Voir Gestionnaire, Enrolment.

Mode élèves et comptes (depuis 0.1.27)

Par défaut (fixe), un siège ouvre directement un bureau, sous l'utilisateur système pupitre-seat-N, le même pour tous ceux qui s'assoient devant. En mode eleves, LightDM montre un écran de connexion sur le siège, chaque élève ouvre une session sous son propre compte, et une déconnexion ramène l'écran de connexion en une seconde environ, sans couper le lien avec le boîtier.

  1. Créer les comptes. Aucun outil de pupitre ne le fait dans 0.1.35-1 : ce sont des comptes locaux, authentifiés par PAM. Il n'y a pas d'annuaire (AD ou LDAP).

    sudo useradd -M -d /home/eleves/lea.cm1 -s /bin/bash lea.cm1
    sudo passwd lea.cm1
    

    Le répertoire /home/eleves/<compte> est créé en 0700 à la première connexion, depuis /etc/skel. Un nom de compte ne contient que lettres, chiffres, ., _ et -. pupitre ne traite comme élève qu'un compte d'uid 1000 ou plus (UID_MIN), ni root, ni membre de sudo ou de adm : à la déconnexion, rien de ce que l'élève a lancé ne survit, et un adulte qui essaie un siège avec son propre compte ne perd que la session de ce siège.

  2. Redémarrer LightDM une fois, après la première installation du paquet. LightDM ne lit sa configuration qu'au démarrage, et le redémarrer ferme toutes les sessions ouvertes : c'est pour cela que le paquet ne le fait pas. Tant que ce n'est pas fait, les élèves ne peuvent pas se connecter et le siège journalise LightDM started before pupitre's configuration. Hors temps de classe :

    sudo systemctl restart lightdm
    
  3. Activer le mode, siège par siège, par le drop-in Environment=PUPITRE_CONNEXION=eleves (voir Les sièges), puis daemon-reload et redémarrage du siège.

Délai de fermeture. PUPITRE_FERMETURE (600 s) ferme la session d'un élève dont le boîtier reste éteint ; le retour du boîtier annule le compte à rebours. PUPITRE_GRACE la borne : quand PUPITRE_GRACE n'est pas 0, le délai effectif est le plus petit des deux, et PUPITRE_FERMETURE=0 veut dire « jusqu'à PUPITRE_GRACE ».

La déconnexion ne relance ni Xvfb ni le lien avec le boîtier. Le détail est dans Siège, section Pupils' logins.

Console web et son mot de passe

La console montre l'écran de chaque siège en direct et pilote chaque boîtier. Elle écoute par défaut sur 127.0.0.1:8080, sans mot de passe : seul quelqu'un qui a déjà un compte sur le serveur l'atteint. Depuis votre poste :

ssh -L 8080:127.0.0.1:8080 admin@serveur

puis ouvrez http://127.0.0.1:8080.

Sur le réseau, un mot de passe est obligatoire (depuis 0.1.14). La console refuse de démarrer sur une adresse non locale sans mot de passe.

sudo pupitre-web --mot-de-passe /etc/pupitre/console-password

La commande le demande deux fois, sans écho, et écrit son empreinte (PBKDF2) en mode 600. Il n'y a volontairement aucune option pour le passer en argument : il finirait dans ps et dans l'historique du shell. Puis, dans /etc/pupitre/pupitre.conf :

[web]
listen = 192.0.2.10
password_file = /etc/pupitre/console-password
sudo systemctl restart pupitre-web

Ce que la console ne donne pas : pas de chiffrement (HTTP en clair), un seul mot de passe partagé, pas de comptes, pas de trace de qui a fait quoi. Gardez-la sur un réseau d'administration, ou derrière le tunnel ssh. Voir Console web, Security.

La console web : un poste en session, avec les boutons Identify, Relink, Logs et Restart

Vérification

systemctl is-active pupitre-nft pupitre-manager pupitre-web
systemctl status 'pupitre-seat@*'
journalctl -u pupitre-manager

Les trois services doivent répondre active. Dans la console, le siège passe à « In session », ce qui veut dire que le lien avec le boîtier est prêt, pas qu'un élève est connecté. La preuve finale reste l'écran du boîtier : bureau ou écran de connexion, clavier et souris qui répondent.

Mise à jour

sudo apt install ./pupitre_<nouvelle version>_amd64.deb

Depuis 0.1.27, une mise à jour ne coupe plus le lien des sièges : la règle nftables est rechargée en place, en une seule transaction. Le gestionnaire et la console redémarrent, les sièges continuent. Depuis 0.1.26, les répertoires des sièges restent à leur propriétaire.

Une mise à jour n'allume ni n'éteint aucune brique de contrôle, sauf dns-recherche-sure une seule fois en venant d'une version antérieure à 0.1.33. En revanche, le contenu d'une brique déjà active n'est pas rafraîchi : relancez sudo pupitre-controle activer <brique> pour chaque brique active (voir Couches personnalisables).

Dépannage

Quand un poste ne répond pas, du geste le plus doux au plus fort :

Geste Ce qu'il fait L'élève
Logs (console) montre la fin d'un journal du siège, choisi dans une liste fermée : session, encodeur, bureau, Xvfb, entrées, curseur, clé (depuis 0.1.14) ne perd rien
Relink (console) refait le lien avec le boîtier sans toucher au bureau, en 15 à 60 s (depuis 0.1.14) garde son bureau
Restart (console) redémarre le siège ; le boîtier reste noir 30 à 90 s perd sa session
Cycle d'alimentation débrancher puis rebrancher le boîtier perd sa session

Un boîtier figé ne revient que par un cycle d'alimentation, et peut rester injoignable près d'une demi-heure après un figeage.

En ligne de commande :

  • journalctl -u pupitre-manager et journalctl -u pupitre-seat@N (avec -f pour suivre) ;
  • /var/log/pupitre/seat-N/ : session.log, xvfb.log, desktop.log, input.log, encoder.log, et selon les fonctions curseur.log, cle.log ;
  • le journal du client fast_tcp2, dans le même répertoire, lisible par root seul, les dix plus récents gardés (depuis 0.1.31) ; son chemin figure sur la ligne fast_tcp2 stderr -> de session.log. Il contient des octets nuls : lisez-le avec grep -a. La console ne le sert jamais.

RGPD. Aucun journal ne capture frappe, mouvement de souris, contenu d'écran ou de fichier par défaut. Le client masque les rapports d'entrée sans aucun réglage (depuis 0.1.31). Ne mettez PUPITRE_QUIET_KEYS=0 que sur une machine d'essai, jamais sur le siège d'un élève.

Deux comportements à connaître :

  • un clavier ou une souris branchés après l'allumage du boîtier ne sont pas pris de façon fiable, et le boîtier peut redémarrer. Branchez-les boîtier éteint ; sinon, éteignez et rallumez le boîtier : le bureau reste ;
  • un siège ne passe en Failed que sur un échec rapide (fichier d'environnement manquant, affichage qui ne s'ouvre pas) ; un boîtier qui n'atteint jamais le flux laisse son siège en Starting.

Les limites connues sont listées dans Installing Pupitre, Known limits.

Préconisations

  • Une VM dédiée, Debian 13 sans bureau, une carte en pont sur un VLAN réservé aux boîtiers et au serveur, un commutateur gigabit.
  • Le paquet plutôt que la copie de travail. Le chemin B sert à construire le paquet, pas à faire tourner une salle : le paquet pose les capacités, la règle nftables et les unités systemd.
  • Construire avec PATH=/usr/bin:/bin, toujours, sans nocheck : les tests font partie de la construction.
  • enroll = no dès que la salle est inscrite, et une étiquette sur chaque boîtier (Identify).
  • La console sur la boucle locale, jointe par ssh. Si elle doit être sur le réseau : mot de passe, et réseau d'administration.
  • Les réglages de siège dans des drop-ins, jamais dans les fichiers du paquet : ils survivent aux mises à jour.
  • Les mises à jour hors temps de classe. Elles ne coupent plus le lien depuis 0.1.27, mais elles redémarrent le gestionnaire et la console.
  • Dimensionner la mémoire sur Firefox (590 Mio par élève), et envisager zram, dont la configuration est livrée dans /usr/share/pupitre mais n'est jamais posée toute seule.
  • Commencer petit. Montez la salle par paliers et regardez la charge du serveur avant d'ajouter des boîtiers.