2.1 Les services avec OpenRC

☕ A la machine à café de CorpTech

« À l’époque, quand on demandait au prestataire si le serveur tournait, la discussion devenait soudainement assez floue... »

Donc avant d’aller plus loin, on va poser les bases de ce qu’est réellement un programme, un démon, et comment un service est censé fonctionner sur un système Alpine Linux.

2.1.1. Un programme

Sur un système Unix, un programme c'est simplement un fichier exécutable. Lorsqu’il est lancé par un utilisateur, il devient un processus : le noyau lui attribue un identifiant, un espace mémoire, du temps processeur et les ressources nécessaires à son exécution.

Processus IDentifiant (PID)

La commande ps affiche la liste des processus en cours d’exécution sur le système

ps
 2491 alice     0:00 sshd-session: alice@pts/0
 2492 alice     0:00 -sh
 2538 alice     0:00 ps

Observations :

  • chaque ligne correspond à un programme en cours d’exécution ;
  • la première colonne est un numéro : le PID.
  • la seconde colonne correspond à l’utilisateur propriétaire du processus ici alice;
  • la troisième colonne indique le temps CPU consommé par le processus ;
  • la dernière colonne indique le programme lancé, avec ses arguments éventuels.

A retenir

Un processus est un programme en cours d’exécution, identifié par un PID (ProcessID) exécuté par un utilisateur.

Information

BusyBox est un binaire unique qui regroupe de nombreuses commandes Unix (ps, ls, cp, mount, kill, etc.). Chaque commande n’est donc pas un programme indépendant mais un même et unique binaire BusyBox. La sortie exacte de ps sur d'autres distributions peut varier, mais les colonnes restent conceptuellement les mêmes.

Un fichier exécutable et un processus sont deux choses très différentes.
Par exemple le fichier exécutable /bin/ps existe en permanence sur le disque, même lorsque la commande ps n’est pas utilisée. Lorsqu’il est exécuté, le noyau crée un processus distinct à partir de ce fichier : il lui attribue un PID, de la mémoire, un état et du temps processeur. Une fois l’exécution terminée, le processus disparaît, mais le fichier exécutable reste inchangé.

Un processus n’est donc pas un fichier.
En revanche, sur les systèmes Unix, le noyau expose l’état des processus à travers un pseudo-système de fichiers : /proc.

Faites le test:

ls /proc

On y trouve notamment :

  • des dossiers numérotés : un par processus (PID) ;
  • A l'intérieur de ces dossiers, des fichiers décrivant l'état d'un processus (mémoire, CPU, etc.).

Concrètement si vous voyez un dossier /proc/2435, c'est que le processus 2435 est actif. Ce dossier existe tant que ce processus tourne . Ce dossier disparaît dès que le processus 2435 sera arrêté.

Faisons un premier test. La commande sleep demande au noyau d’attendre pendant un temps donné en secondes.

sleep 300

Le terminal est bloqué, rien ne s’affiche, rien ne peut être saisi. Pourtant, quelque chose est toujours en cours d’exécution.

Utilisez le raccourci CTRL+Z pour stopper le processus. Il est suspendu par le signal SIGTSTP et n’est plus exécuté du tout (temps CPU figé).

Ctrl + Z
[1]+  Stopped  sleep 300

Un processus stoppé existe toujours, mais le noyau ne lui attribue plus de temps processeur.

Affichez les processus en cours d'exécution:

ps

Notez le PID du processus 'sleep 300'. Pour mon cas c'est le 3170.

Afficher le contenu du dossier /proc:

ls /proc

Vous devriez voir le dossier correspondant à votre PID.

Le processus est maintenant stoppé. Pour reprendre son exécution, on demande au noyau de lui délivrer SIGCONT (reprise) via kill.

Pour cela tapez la commande :

kill -CONT <N° de PID>

L’option -CONT demande au noyau de reprendre l’exécution d’un processus stoppé.

Retenez que la commande kill demande au noyau d’envoyer un signal à un processus cible.

C’est quoi un signal ?

Rappel

  • Le noyau (kernel) est la partie centrale du système d’exploitation.
  • Il s’exécute en permanence, en mode privilégié, et contrôle l’accès au processeur, à la mémoire, aux périphériques et aux processus.
  • Un processus utilisateur ne peut pas agir directement sur les ressources : toute action passe par le noyau.

Un signal est un mécanisme du noyau qui permet d'imposer un événement à un processus.

Certains signaux proviennent du terminal (Ctrl+C -> SIGINT , Ctrl+Z -> SIGTSTP), d’autres sont envoyés explicitement via la commande kill. Le noyau transmet le signal au processus quelle que soit son origine.

Signal À quoi il sert Commande associée
SIGTERM 15 Demander à un programme de s’arrêter proprement kill <PID> / kill -TERM <PID>
SIGKILL 9 Forcer l’arrêt immédiat (dernier recours) kill -KILL <PID>
SIGINT 2 Interruption depuis le clavier (Ctrl+C) kill -INT <PID>
SIGSTOP 19 Suspension forcée d’un processus kill -STOP <PID>
SIGCONT 18 Reprise d’un processus suspendu kill -CONT <PID>
Exemples:
kill -KILL <PID>    # arrêt brutal
kill -STOP <PID>    # suspension forcée
kill -CONT <PID>    # reprise
kill -INT  <PID>    # interruption (équivalent Ctrl+C)

Petite nuance

SIGSTOP et SIGTSTP ont le même effet observable : ils suspendent un processus jusqu’à la réception de SIGCONT.

La différence porte sur l’origine du signal et sur le contrôle laissé au processus.

  • SIGSTOP est envoyé par le noyau via la commande (kill -STOP <PID>). Le processus ne peut ni l’intercepter, ni l’ignorer.
  • SIGTSTP (terminal stop) est envoyé depuis un terminal lorsqu'un utilisateur tape Ctrl+Z. Le processus a la possibilité de l’intercepter ou de l’ignorer.

Synthèse

  • Un programme lancé devient un processus.
  • Un processus a un PID et une existence visible dans /proc.
  • Ctrl+C interrompt
  • Ctrl+Z suspend.
  • kill demande au noyau d’envoyer un signal à un processus cible.
  • kill -9 (-9 est l’équivalent numérique de -KILL) impose un arrêt brutal sans nettoyage (attention aux verrous, fichiers temporaires ou sockets laissés en l’état).

2.1.2. Un démon (daemon)

Certains programmes doivent fonctionner en continu pour fournir une fonctionnalité aux utilisateurs comme un service web (serveur apache2 ou nginx).

Note

Un démon est un programme conçu pour fonctionner sans interaction utilisateur, détaché de tout terminal, généralement lancé au démarrage par le système d’initialisation.

Exemples

  • sshd → permet l’exécution d'un Shell sécurisé à distance
  • crond → exécute les tâches planifiées
  • nginx → permet l'accès à des pages web
  • syslogd → enregistre les logs

Donc a priori ces programmes devraient pouvoir :

  • démarrer tout seul dès que le système est prêt,
  • fonctionner en arrière-plan,
  • et rester actifs même si aucun utilisateur ne les utilise.

Le problème fondamental est que si un démon démarre un peu quand il en a envie, il y a de forte chance pour que l'environnement système ne soit pas encore prêt . Par exemple si :

  • sshd se lance avant que le réseau ne soit initialisé, son lancement échouera.
  • nginx échouera si le dossier de logs n’est pas monté.
  • crond agira de façon incohérente si l’heure n’est pas encore réglée.

Note

Un démon seul ne sait pas quand démarrer, ni gérer ses dépendances, ni attendre que l’environnement soit prêt et encore moins se relancer en cas d'échec.

2.1.3. Le démarrage d’un système Linux

Revenons un instant sur la séquence de démarrage d'un OS (même si cela n'a aucun secret pour vous ...) Quand la machine s’allume :

  1. L'UEFI initialise les périphérique puis rend la main
  2. Le noyau Linux se charge .
  3. Les systèmes de fichiers sont montés.
  4. Les pilotes s’initialisent.
  5. Les interfaces réseau apparaissent.
  6. Les démons peuvent enfin démarrer.

Note

Encore une fois un démon ne sait pas dans quel ordre se placer dans cet ordre logique, d'autant plus qu'un démon n'a pas de vue sur l'état du système. Il lui faut donc un chef d’orchestre.

2.2 TP Les services avec OpenRC.png

2.1.4. Pourquoi orchestrer les démons ?

Comme on vient de le voir, sans orchestration, on obtiendrait des erreurs imprévisibles les démons s'activeraient dans un ordre aléatoire, des dépendances entre démons ne seraient pas respectées et au final on obtiendrait un système instable, incohérent et surtout pas fiable.

Pour que tout fonctionne correctement, on a besoin d'un mécanisme qui :

  • organise les dépendances entre démons,
  • sait dans quel ordre démarrer les démons,
  • sait quand un démon peut démarrer,
  • sait arrêter proprement un démon,
  • sait vérifier son état,
  • sait activer/désactiver le démarrage automatique d'un démon .

C’est le travail du système d’initialisation (init system) et donc d'OpenRC

2.1.5. OpenRC

OpenRC est le chef d’orchestre de notre distribution Alpine Linux. Il fournit :

2.1.5.a Un cadre pour décrire chaque service

Chaque service possède un script dans /etc/init.d/ où il est indiqué :

  • comment démarrer,
  • comment s'arrêter,
  • de quoi dépend le service.

2.1.5.b Un système de dépendances

Exemple :

depend() {
    need net
}

OpenRC en déduit automatiquement l’ordre de démarrage.

2.1.5.c Un mécanisme d’auto-démarrage

Sur Alpine Linux, un runlevel est un répertoire qui regroupe les services devant être lancés à un moment donné du démarrage ou de l’arrêt du système.

Concrètement :

  • chaque runlevel correspond à un état logique du système ;
  • un service est « dans un runlevel » s’il existe un lien symbolique vers son script dans ce répertoire.
ls /etc/runlevels/boot/
bootmisc    hostname    hwclock     loadkmap    modules     networking  seedrng     swap        sysctl      syslog
ls /etc/runlevels/default/
acpid   crond   ntpd    sshd    syslog

Exemples :

  • /etc/runlevels/boot/ : services indispensables au démarrage (montage, udev, etc.)
  • /etc/runlevels/default/ : services lancés par défaut
  • /etc/runlevels/shutdown/ : services arrêtés lors de l’extinction

Par exemple quand tu fais :

rc-update add sshd

OpenRC crée un lien symbolique vers /etc/init.d/sshd dans /etc/runlevels/default/.

alpine:~$ ls -la /etc/runlevels/default/
total 8
drwxr-xr-x    2 root     root          4096 Dec 21 17:46 .
drwxr-xr-x    7 root     root          4096 Nov 21 23:26 ..
lrwxrwxrwx    1 root     root            17 Nov 21 23:26 acpid -> /etc/init.d/acpid
lrwxrwxrwx    1 root     root            17 Nov 21 23:26 crond -> /etc/init.d/crond
lrwxrwxrwx    1 root     root            16 Nov 21 23:26 ntpd -> /etc/init.d/ntpd
lrwxrwxrwx    1 root     root            16 Nov 21 23:26 sshd -> /etc/init.d/sshd
lrwxrwxrwx    1 root     root            18 Dec 21 17:46 syslog -> /etc/init.d/syslog

Point clé à retenir :

Un runlevel est une liste de services que le système doit activer ou désactiver à un moment donné de son exécution.

2.1.5.d Une interface uniforme pour gérer les services

OpenRC fournit une commande unique (rc-service) permettant d’exécuter les actions (start, stop, status ... ) définies dans les scripts /etc/init.d :

rc-service <service> start
rc-service <service> stop
rc-service <service> status

Jetez un oeil au script d'initialisation du démon sshd :

cat /etc/init.d/sshd

2.1.5.e Un arrêt structuré du système

OpenRC orchestre l’arrêt des services en s’appuyant sur les scripts /etc/init.d et sur le runlevel shutdown, ce qui conduit à :

  • respecter l’ordre imposé par les dépendances,
  • exécuter les routines d’arrêt définies par chaque service,
  • ne pas intervenir au-delà de ce que prévoit le script.

2.1.6. Synthèse

Du programme → au démon → orchestration → OpenRC

  1. Un programme est exécuté ponctuellement.
  2. Un démon fonctionne en continu en arrière-plan.
  3. Un démon échoue si l’environnement n’est pas prêt.
  4. Il faut donc orchestrer l’ordre de démarrage.
  5. Cette orchestration est assurée par le système d’initialisation.
  6. Sur Alpine Linux, ce rôle est rempli par OpenRC.
  7. OpenRC rend le démarrage prévisible et reproductible.
  8. OpenRC ne garantit ni la disponibilité, ni la relance automatique d’un service défaillant.

En résumé

Les démons accomplissent les tâches. OpenRC organise leur exécution.

Pour info

Par défaut sur Alpine Linux, le Kernel Watchdog n’est ni activé ni configuré. Ce mécanisme du noyau Linux permet de redémarrer automatiquement le système en cas de blocage irrécupérable (watchdog = « chien de garde »). Alpine ne l’active pas par défaut, car son utilisation nécessite l’installation d’un démon et de dépendances supplémentaires, ce qui augmenterait la surface d’attaque. Retenez simplement qu’il est possible d’utiliser un mécanisme pour surveiller des services, processus ou ressources spécifiques, mais celui-ci n’est pas activé par défaut et doit être installé/configuré manuellement.

2.1.7. Références

Note

2.1.8. Exercices

📝 Exercice 1 – Découverte

À rendre

  1. Listez tous les services disponibles.

  2. Listez les services activés au démarrage.

  3. Donnez le chemin exact du script networking.

Format attendu : commandes + réponses.

📝 Exercice 2 – Manipulation

À rendre

  1. Démarrez crond.
  2. Vérifiez son état.
  3. Activez-le au démarrage.
  4. Redémarrez la machine.
  5. Vérifiez qu’il est bien lancé après reboot.

**Justifiez votre réponse à l’aide de ps ou rc-status. **

📝 Exercice 3 – Analyse

À rendre

Expliquez la différence entre :

rc-service sshd start

et

rc-update add sshd

(Attendu : start = exécution immédiate, add = démarrage automatique au prochain boot.)

📝 Exercice 4 – Recherche documentaire

À rendre

À partir des sources officielles Alpine :

✔️ Expliquez le rôle de :

  • /etc/init.d

  • /etc/runlevels/default

  • /etc/conf.d

✔️ Citez les URLs et extraits pertinents.