URL: https://linuxfr.org/news/petit-etat-de-l-art-des-systemes-d-initialisation-1 Title: Petit état de l'art des systèmes d'initialisation (1) Authors: Joris Dedieu Jarvis, Jiehong, needs, ZeroHeure, Nils Ratusznik, Fopossum, Brndan, Benoît Sibaud, Joël Thieffry, Storm, Ignatz Ledebur, talou, Misc, etenil, lenod, reno, Sylvain Blandel et claudex Date: 2012年11月13日T12:51:30+01:00 License: CC By-SA Tags: rcng, openrc, upstart, runit, systemd, lennart_poettering et debian Score: 60 Ces dernier temps, la question de l'initialisation du système d'exploitation a été au cœur des ~~trolls~~ discussions. Nous allons faire un point sur les différentes approches mise en œuvre possédant une implémentation libre. Dans cette première partie, nous allons voir arbitrairement quatre systèmes d'initialisation : [OpenRC](http://www.gentoo.org/proj/en/base/openrc/), rcNG, [Upstart](http://upstart.ubuntu.com/) et [runit](http://smarden.org/runit/index.html). Nous n'aborderons pas systemd du fait qu'il a déjà été évoqué dans de nombreux contenus ([ici](https://linuxfr.org/news/le-point-sur-udev-et-systemd), [ici](https://linuxfr.org/news/%C3%A9volutions-techniques-de-systemd) et [là](https://linuxfr.org/news/un-entretien-avec-lennart-poettering) par exemple). _Note : merci à Jarvis Jiehong, needs, Fopossum, Brndan, Joël Thieffry, Storm, MrSpackMan, Nils Ratusznik, Misc, reno, Sylvain Blandel, Benoît Sibaud, lenod,talou, etenil, qui sont les véritables auteurs de cette dépêche_. ---- ---- # OpenRC # ## Présentation ## [OpenRC](http://www.gentoo.org/proj/en/base/openrc/) est un système d'initialisation du système lancé au moment du début du port [Gentoo/FreeBSD](https://wiki.gentoo.org/wiki/Gentoo_FreeBSD). Il cherche à être indépendant du système sous-jacent. Il s'adapte à diverses implémentation d'init. Le précédent système d'initialisation de Gentoo s'appuyait massivement sur des script bash. Lors de l'initialisation du port Gentoo/FreeBSD il est devenu indispensable d'utiliser une solution plus portable : c'est dans cette optique que [Roy Marples](http://roy.marples.name/projects/openrc/wiki) a lancé le développement d'OpenRC. OpenRC, bien qu'utilisant sysinit sous Gentoo par exemple, s'affranchit des niveaux d'exécutions (_runlevels_) habituels en introduisant la notion de niveaux d'exécutions nommés. Ainsi, lors du démarrage du système, on passera du niveau _boot_ au niveau _default_. Les principaux avantages d'OpenRC sont sa rapidité, sa gestion des dépendances entre services, et la possibilité de paralléliser (dans une certaine mesure) le démarrage des services. On trouve par défaut, sur une installation OpenRC, les niveaux d'exécution suivants : `boot`, `default`, `shutdown` et `sysinit`. Dans ces répertoires se trouvent des liens symboliques pointant vers `/etc/init.d` où se trouvent effectivement les scripts d'init. Le binaire `/sbin/rc` est au centre du système. Il est généralement invoqué via le script `/etc/rc`. ## Anatomie d'un script d'init OpenRC ## Nous allons prendre l'exemple de metalog, un des gestionnaires de journaux (_system loggers_) disponible sous Gentoo. ```bash #!/sbin/runscript # Copyright 1999-2011 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: /var/cvsroot/gentoo-x86/app-admin/metalog/files/metalog.initd,v 1.5 2011年09月23日 03:15:23 vapier Exp $ extra_started_commands="buffer unbuffer" PIDFILE=/var/run/metalog.pid depend() { need localmount use clock hostname after bootmisc provide logger } ssd() { start-stop-daemon --exec /usr/sbin/metalog --pidfile "${PIDFILE}" "$@" ; } start() { ebegin "Starting metalog" ssd --start -- \ --daemonize --pidfile="${PIDFILE}" ${METALOG_OPTS} eend $? } stop() { ebegin "Stopping metalog" ssd --stop eend $? } buffer() { ebegin "Enabling log buffering" ssd --signal USR2 eend $? } unbuffer() { ebegin "Disabling log buffering" ssd --signal USR1 eend $? } ``` Les cibles par défaut des scripts sont `start`, `stop` et `restart`. Ce script est un bon exemple de la versatilité d'OpenRC puisqu'il définit deux nouvelles cibles `buffer` et `unbuffer`. Bien que la cible `restart` ne soit pas définie, elle existe tout de même. La partie `depend` liste tous les services nécessaires au bon fonctionnement du programme. On voit dans ce cas que metalog n'a pas besoin du réseau pour démarrer (il y aurait un `need net` déclaré sinon), et il fournira au système le service `logger` nécessaire au lancement d'autres services. ## Configuration ## La configuration des services lancés par OpenRC est relativement simple et se fait par l'intermédiaire des fichiers de configuration portant le nom du service se trouvant dans le répertoire `/etc/conf.d` et du fichier global `/etc/rc.conf`. ### Comportement global ### La configuration d'OpenRC est regroupée dans le fichier `/etc/rc.conf`. Très abondamment commenté, il permet par exemple de définir si le boot doit être interactif ou parallélisé. ### Paramétrage d'un service ### Pour paramétrer un service, il doit y avoir une entrée correspondante dans le répertoire `/etc/conf.d`. Les fichiers présents dans ce répertoire servent à passer des arguments supplémentaires aux démons. Ils sont toujours abondamment commentés et simples à comprendre. Si nous reprenons notre exemple de metalog, le fichier correspondant dans `/etc/conf.d` est le suivant : ```bash # /etc/conf.d/metalog # $Header: /var/cvsroot/gentoo-x86/app-admin/metalog/files/metalog.confd,v 1.7 2006年02月08日 01:04:02 vapier Exp $ # Some useful options: # -a Log with buffering # -s Log without buffering # See `metalog --help` for more METALOG_OPTS="" # Options used by /usr/sbin/consolelog.sh # Space delimited list of devices to write "console" messages to #CONSOLE="/dev/console /dev/tty10" CONSOLE="/dev/tty10" # Format of logging (make sure you use single quotes) FORMAT='1ドル [2ドル] 3ドル' ``` ## Avantages et inconvénients ## OpenRC est portable. Il est utilisé sous Gentoo par défaut et peut être utilisé sous FreeBSD et NetBSD sans difficulté. L'utilisation des niveaux d'exécution nommés permet d'en créer des spécifiques très facilement. On peut, pour un ordinateur portable par exemple, créer un niveau d'exécution nommé « battery » et indiquer au système, via un événement ACPI, de passer à ce niveau d'exécution lorsque le portable fonctionne sur batterie. Nous pouvons ainsi arrêter des services précis pour économiser de l'énergie. C'est en couleurs ! On voit très vite quand il y a du rouge dans le démarrage ! Et le rouge, c'est mal. Après [5 ans](http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/sys-apps/openrc/?hideattic=0) de développement, il était tout de même utilisé quotidiennement par des milliers d'utilisateurs en ~arch (la version de test de Gentoo) sans aucun problème. Depuis la version 0.11.8 (disponible dans l'arbre portage depuis le 7 décembre 2012) OpenRC est considéré comme stable et peut donc être utilisé par tous les gentooistes sans risque de casser entièrement son système de démarrage. La lecture du [guide de migration en anglais](http://www.gentoo.org/doc/en/openrc-migration.xml) reste néanmoins une bonne source d'information pour bien comprendre les différences entre le baselayout-1 et le baselayout-2 et les modifications éventuelles à apporter à son système pour profiter pleinement des capacités de ce système d'initialisation. Il est à noter que les versions 0.12 et supérieures (toujours en ~arch) disposent du support des [CGroups](http://wiki.gentoo.org/wiki/OpenRC/CGroups). De nombreuses fonctionnalités d'OpenRC sont décrites sur le wiki officiel Gentoo dans la [catégorie OpenRC](http://wiki.gentoo.org/wiki/Category:OpenRC). Dernier inconvénient, les scripts d'init doivent être ré-écrits pour OpenRC : en effet, il n'utilise pas ceux disponibles pour les autres distributions plus « traditionnelles ». Cependant, peu de distributions se sont penchées dessus. # rcNG # On parle ici de l'init sous NetBSD, FreeBSD et DragonFlyBSD. Le principe de base est classique : * un init simple et robuste ; * du shell bourne (évolution d'ash). ## Initialisation ## `init` est lancé par défaut après le chargement du noyau. Il initialise les terminaux, gère les journaux de session et l'état du système. Il est configuré par [/etc/ttys](http://www.freebsd.org/cgi/man.cgi?query=ttys&apropos=0&sektion=5&manpath=FreeBSD+9.0-RELEASE&arch=default&format=html) qui détermine la nature des différents terminaux. C'est un automate à état fini qui essaye de remplir plusieurs objectifs comme on peut le lire dans [les notes d'implémentation](http://svnweb.freebsd.org/base/head/sbin/init/NOTES?view=co) : 1. Un traitement _fasciste_ des signaux. Y compris ceux émanant du matériel : * SIGSYS (appel système inexistant) est suspect, on appelle la routine qui détermine si le problème se produit souvent avant, éventuellement, de déclencher le désastre ; * SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGXCPU, SIGXFSZ dénotent les erreurs irrécupérables et conduisent irrémédiablement au désastre ; * SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGUSR1, SIGUSR2 permettent à l'utilisateur de déclencher un changement d'état. 1. Une prise en charge élégante des erreurs fatales en essayant, par exemple, d'envoyer un message sur la console et d'attendre un peu avant de redémarrer. 1. Une prise en charge des fils la moins coûteuse possible : * ne pas surveiller un processus endormi ; * ne pas utiliser SIGCHILD, jugé trop coûteux ; * appliquer une heuristique pour quitter rapidement getty ; * gérer les appels systèmes interrompus (EINTR) en cas de changement de transition. L'automate lui même est défini ainsi : 1. mode mono-utilisateur ; en sortant, passer à 2 ; 1. lancement du mode multi-utilisateurs ; en sortant, aller à 3 ; retourner à 1 si erreur ; 1. lecture du fichier ttys(5) ; en sortant, aller à 4 ; 1. mode multi-utilisateurs ; aller en 5, 6 ou 7 suivant le signal envoyé ; 1. mode nettoyage (relecture du fichier tty(5) et application des modifications) ; aller en 4 ; 1. mode ennuyeux (système verrouillé : pas de nouvelles sessions) ; aller en 5 ou 7 suivant le signal reçu ; 1. mort ; signaler tous les fils (SIGHUP originel : raccrocher), attendre 30 secondes et aller en 1. ## Lancement des services ## Ce qui nous intéressera particulièrement est la transition 2. Celle-ci lance l’exécution du script `/etc/rc`. Rc, dit NG, est le système mis en œuvre par NetBSD puis FreeBSD. Il est également à l'origine du système utilisé jusqu'à très récemment par ArchLinux. Il se situe historiquement dans la lignée des init dits _BSD_. Mais il remplace avantageusement les scripts historiques `/etc/rc.service` par quelque chose du plus souple et de facile à configurer. Il va lancer dans le bon ordre les différentes tâches nécessaires au démarrage du mode multi-utilisateur. Chaque tâche correspond à un script dans le répertoire `/etc/rc.d` qui effectue en principe une tâche simple (en moyenne 64 lignes par script, commentaires compris). Les scripts trop complexes tendent à être éliminés au profit d'autres solutions. Par exemple la commande `jail` qui lance les conteneurs de même nom a été réécrite. Cela permettra de remplacer plus de 700 lignes du script de rc par un simple `jail -c`. L'ordre de lancement est évalué en fonction des mots clés PROVIDE, REQUIRE et BEFORE présents dans les scripts. Chaque script est ainsi _sourcé_ dans l'ordre. Le fichier `/etc/default/rc.conf`, fournit la configuration par défaut sous la forme ```variable=valeur``` qui peut être surchargée dans le fichier `/etc/rc.conf`. Exemple de script de rc : ```sh # PROVIDE: syslogd # REQUIRE: mountcritremote cleanvar newsyslog # BEFORE: SERVERS . /etc/rc.subr name="syslogd" rcvar="syslogd_enable" pidfile="/var/run/syslog.pid" command="/usr/sbin/${name}" required_files="/etc/syslog.conf" start_precmd="syslogd_precmd" extra_commands="reload" sockfile="/var/run/syslogd.sockets" evalargs="rc_flags=\"set_socketlist \$rc_flags\"" altlog_proglist="named" syslogd_precmd() { local _l _ldir # Transitional symlink for old binaries # if [ ! -L /dev/log ]; then ln -sf /var/run/log /dev/log fi rm -f /var/run/log # Create default list of syslog sockets to watch # ( umask 022 ;> $sockfile ) # If running named(8) or ntpd(8) chrooted, added appropriate # syslog socket to list of sockets to watch. # for _l in $altlog_proglist; do eval _ldir=\$${_l}_chrootdir if checkyesno ${_l}_enable && [ -n "$_ldir" ]; then echo "${_ldir}/var/run/log">> $sockfile fi done # If other sockets have been provided, change run_rc_command()'s # internal copy of $syslogd_flags to force use of specific # syslogd sockets. # if [ -s $sockfile ]; then echo "/var/run/log">> $sockfile eval $evalargs fi return 0 } set_socketlist() { local _s _socketargs _socketargs= for _s in `cat $sockfile | tr '\n' ' '` ; do _socketargs="-l $_s $_socketargs" done echo $_socketargs } load_rc_config $name run_rc_command "1ドル" ``` Une fois son travail terminé, rc rend la main à init qui ouvre les terminaux. Le système est lancé. init n'a plus alors qu'à attendre la prochaine ouverture de session ou la prochaine transition. Les services peuvent être gérés en utilisant le script ```/etc/rc.d/_XXX_ [one|force]start|stop|status|restart``` ou via l’utilitaire service(8). Au moment de l’arrêt c'est le script `/etc/rc.shutdown` qui est invoqué. # Upstart # ## Présentation ## [Upstart](http://upstart.ubuntu.com/) est un système d'initialisation créé en 2006 par [Scott James Remnant](http://netsplit.com/), employé alors chez Canonical. Bien que son développeur principal soit parti de Canonical, il est encore en développement. Il est écrit en C en utilisant la bibliothèque [NIH Utility Library](https://launchpad.net/libnih). La dernière version (1.10) est parue le 23 août. Upstart gère le démarrage et l'arrêt des services en fonction d'événements. Il doit donc gérer un arbre de dépendances qui permet de définir à l'avance le comportement d'un service en fonction d'un événement. ## Utilisation ## La commande principale est initctl : ``` initctl status udev udev start/running, process 330 ``` Rien de bien nouveau au niveau des actions sur les services : * start : démarrer le service ; * stop : arrêter le service ; * restart : relancer le service ; * reload : recharger le service ; * status : connaître l'état du service. La commande permet d'avoir d'autres renseignements. Par exemple, pour lister les différents services : ``` initctl list [...] udev start/running, process 330 [...] ``` * udev : nom du service ; * start/running : l'état ; * process 330 : pid du processus lié au service. ## Anatomie d'un script d'init Upstart ## Les fichiers de configuration se trouve dans le répertoire : `/etc/init/`. Exemple de configuration : ```sh cat /etc/init/udev.conf # udev - device node and kernel event manager # # The udev daemon receives events from the kernel about changes in the # /sys filesystem and manages the /dev filesystem. description "device node and kernel event manager" start on virtual-filesystems stop on runlevel [06] expect fork respawn exec /sbin/udevd --daemon ``` * start on : quand faut-il démarrer le service ? * stop on : quand faut-il stopper le service (ici : runlevel 0 ou 6) ? * expect fork : le processus s'attend à avoir une seule fois un fork (voir [ici](http://upstart.ubuntu.com/cookbook/#expect-fork)) ; * respawn : permet de démarrer le service si celui-ci a été stoppé pour certaine raison (voir [ici](http://upstart.ubuntu.com/cookbook/#respawn)) ; * exec : la commande à lancer. Comme on peut le constater dans la [documentation](http://upstart.ubuntu.com/cookbook/#configuration), il est possible de configurer un script de façon importante. ## Avantages et inconvénients ## Il est (ou a été) utilisé par défaut par de nombreuses distributions : Ubuntu, Red Hat Entreprise Linux, Fedora et Chrome OS. Ce qui démontre une bonne stabilité. Il est encore en développement, il essaie de rattraper le retard par rapport à systemd : [logind](http://www.phoronix.com/scan.php?page=news_item&px=MTMyMDE), [cgroups](https://lists.ubuntu.com/archives/upstart-devel/2012-May/001877.html), ... # runit # Présent sur Debian comme système de démarrage alternatif, [runit](http://smarden.org/runit/index.html) est un remplaçant multiplate-forme de sysVinit, il se veut aussi simple et minimal que possible. Le développement de l'implémentation initiale [n'est plus actif depuis fin 2009](http://freecode.com/projects/runit), mais il en existe une autre, introduite dans [Busybox 1.3.0](http://busybox.net/oldnews.html) et toujours maintenue. Il permet de paralléliser (dans une certaine mesure) le démarrage, de définir des niveaux d'exécution nommés et de superviser les services. ## Fonctionnement ## Le fonctionnement de runit est plutôt simple : * stage 1 (_initialisation_) : toutes les tâches d'initialisations du système sont effectuées ici, elles sont décrites dans `/etc/runit/1` ; si l'une d'elles échoue, runit est capable de démarrer un _shell_ d'urgence, sinon il lance le stage 2 ; * stage 2 (_stage principal_) : lance et gère toutes les tâches de `/etc/runit/2` ; celui-ci prend fin uniquement lors de l'extinction ou du redémarrage, il laissera alors la main au stage 3 ; * stage 3 (_extinction/redémarrage_) : termine le stage 2 si celui-ci tourne encore, et effectue toutes les tâches d'extinction ou de redémarrage. ## Services ## Runit agit aussi comme gestionnaire de services et permet de gérer les démons grâce au programme `sv`. Ce dernier s'utilise de la manière suivante (pour plus de commandes voir la page de manuel sv(8)) : `sv [start|stop|status|restart] service`. Pour gérer ces services, deux répertoires sont utilisés : * `/etc/sv/` qui contient un dossier pour chaque service, contenant un script bash `run`, qui se charge de lancer le service, et un sous-dossier `log/` contenant lui aussi un script bash `run` qui lance cette fois-ci le programme d'écriture des journaux ; * `/etc/service/` : c'est ici que l'on active/désactive un service ; ce répertoire ne contient que des liens symboliques, la commande typique pour activer un service est la suivante : `ln -s /etc/sv/git-daemon/ /etc/service/`. Une fois le service créé et activé, on peut utiliser `sv` pour le gérer. Ci-dessous, un exemple assez simple mais amplement suffisant. ### Exemple de service : git-daemon ### Le fichier `/etc/sv/git-daemon/run` : ```bash #!/bin/bash exec 2>&1 echo 'git-daemon starting.' exec chpst -ugitdaemon:git \ "$(git --exec-path)"/git-daemon --verbose --reuseaddr \ --base-path=/home/git/repositories /home/git/repositories ``` Vous noterez que `chpst` est un outil de runit permettant de changer l'état d'un processus. Ici on l'utilise pour changer le groupe et l'utilisateur sous lequel va tourner le service. Le fichier `/etc/sv/git-daemon/log/run` : ```bash #!/bin/bash set -e LOG=/var/log/git-daemon test -d "$LOG" || mkdir -p -m2750 "$LOG" && chown gitlog:adm "$LOG" exec chpst -ugitlog svlogd -tt "$LOG" ``` Vous noterez également que `svlogd` est aussi fourni par runit qui le définit comme le gestionnaire de journaux privilégié. Et pour le lancer : `sv start git-daemon` ! ## Journaux ## Si `svlogd` est utilisé, on peut alors consulter les fichiers journaux dans le dossier suivant : `/var/log/git-daemon/` (dans le cas de notre exemple vu ci-dessus, sinon remplacer 'git-daemon' par le nom de votre service). Dans ce dossier, on trouve les fichiers suivant : * `current` : contient les derniers _logs_ enregistrés par le service ; un moyen simple de les lire est d'utiliser la commande `tail`, par exemple : `tail -f /var/log/git-daemon/current` ; * des fichiers nommés de la sorte : `@` + horodate (_timestamp_) + `.s` ; lorsque `current` devient trop gros, `svlogd` le renomme selon la dernière horodate enregistrée, et crée un nouveau fichier `current` : c'est la rotation des fichiers journaux. Pour gérer le format des journaux, ou pour toute autre tâche liée aux journaux, la page du manuel svlogd(8) devrait vous combler.

AltStyle によって変換されたページ (->オリジナル) /