![]() |
|
|
Livres informatique et ebook |
Les news de la semaine

Cette rubrique recense différentes nouvelles, quelques articles ou encore des trucs et astuces. Si vous souhaitez y publier un texte, écrivez à :
articles @ digitbooks.fr
Comment fonctionne init dans les nouvelles distributions ?
Vous maitrisez parfaitement le fonctionnement d’init et sa configuration avec le fichier /etc/inittab. Or les versions récentes d’Ubuntu et de Fedora n’utilisent plus le mécanisme traditionnel d’init, et vous vous demandez bien par quoi il a été remplacé, ainsi que la raison de ce changement ?
Ces distributions utilisent désormais upstart, qui apporte une souplesse inégalée dans la mise en œuvre de services sur un système GNU/Linux. Nous verrons une application pratique complexe à réaliser avec la commande init traditionnelle et les scripts du répertoire /etc/init.d
Le nouveau mécanisme utilisé s’appelle upstart. Il s’appuie sur le principe de job, décrit dans le répertoire /etc/event.d.
La description d’un job indique le comportement du job lorsque qu’un événement se produit, d’une façon similaire à celle de l’ancien fichier /etc/inittab où une ligne décrivait par un mot-clé, comme once ou respawn, le comportement qu’avait init vis-à-vis de la commande indiquée lors d’un changement de niveau. Nous verrons que la notion de job offre bien plus de souplesse que la ligne dans /etc/inittab.
Ces jobs sont contrôlés par la commande initctl, qui permet de les démarrer ou les arrêter interactivement. Cette fonctionnalité était tout à fait inconnue avec l’ancien mécanisme où la seule solution, quand une commande était en respawn, était d’éditer le fichier de configuration, puis de lancer telinit q pour indiquer à init de relire /etc/inittab.
Ce répertoire contient autant de fichier qu’il y a de jobs à prendre en compte. Voici le contenu du répertoire pour une distribution Ubuntu 8.10 :
control-alt-delete last-good-boot logd rc0 rc1 rc2 rc3 rc4 rc5 rc6 rc-default rcS rcS-sulogin sulogin tty1 tty2 tty3 tty4 tty5 tty6
Les noms des fichiers de cette liste laissent présager à quoi correspond chaque job : chacun d’eux correspond à une ligne de l’ancien fichier /etc/inittab.
Si l’on souhaite ajouter un nouveau job au système, il suffit de placer, dans ce répertoire, un fichier de description du job.
Cette commande est l’outil majeur de l’administrateur qui a besoin de gérer les jobs. L’argument help permet d’obtenir la liste des différentes options disponibles.
Par exemple, initctl list fournit la liste des jobs du système, avec leur état :
control-alt-delete (stop) waiting last-good-boot (stop) waiting logd (stop) waiting rc-default (stop) waiting rc0 (stop) waiting rc1 (stop) waiting rc2 (stop) waiting rc3 (stop) waiting rc4 (stop) waiting rc5 (stop) waiting rc6 (stop) waiting rcS (stop) waiting rcS-sulogin (stop) waiting sulogin (stop) waiting tty1 (start) running, process 6772 tty2 (start) running, process 5278 tty3 (start) running, process 5280 tty4 (start) running, process 5271 tty5 (start) running, process 5272 tty6 (start) running, process 5281
Pour arrêter un job, il suffit d’utiliser l’argument stop, puis pour le lancer, l’argument start.
Par exemple, pour arrêter l’invite de connexion sur le pseudo terminal tty6 :
initctl stop tty6
tty6 (stop) running, process 5281 tty6 (stop) pre-stop, (main) process 5281 tty6 (stop) stopping, process 5281 tty6 (stop) killed, process 5281 tty6 (stop) post-stop tty6 (stop) waiting
Et pour relancer cette même invite :
initctl start tty6
tty6 (start) waiting tty6 (start) starting tty6 (start) pre-start tty6 (start) spawned, process 2297 tty6 (start) post-start, (main) process 2297 tty6 (start) running, process 2297
initctl permet également d’émettre des événements, avec le paramètre emit. L’administrateur peut définir lui-même de nouveaux événements, même si dans la majorité des cas, il ne travaillera qu’avec ceux préconfigurés par le système et init.
La commande initctl emit prend comme argument un nom, suivi de paramètres et de définition de variables d’environnement.
Les principaux événements du système sont :
|
Evénement |
Description |
|
stalled |
il n’y a plus de job lancé et aucun événement n’est en attente. |
|
control-alt-delete |
les touches Control-Alt-Delete ont été appuyées |
|
kbdrequest |
un évenement clavier est survenu |
|
power-status-changed |
init a reçu le signal SIGPWR |
|
starting <job> |
le job indiqué a reçu une demande de démarrage |
|
started <job> |
le job indiqué a démarré |
|
stopping <job> |
le job indiqué a reçu une demande de d’arrêt |
|
stopped <job> |
le job indiqué est arrêté |
|
startup |
le système démarre |
|
runlevel <niveau> |
Init passe au niveau indiqué |
Un fichier job comporte plusieurs groupes :
Un premier groupe décrivant le comportement du job lorsque tel ou tel événement se produit. Il contient des instructions start on ou stop on, suivies d’un ou plusieurs événements.
Un second groupe décrit le comportement du job. Il contient des instructions comme respawn ou daemon.
Un troisième groupe décrit les actions à mener. Il contient des instructions comme exec ou script, ainsi que pre-start ou post-start.
Un dernier groupe concerne les instructions définissant l’environnement des actions exécutées, comme env ou ulimit.
Je vous invite à consulter le manuel d’events pour avoir une description détaillée de ces différentes instructions.
Les actions du
troisième groupe sont l’une des évolutions marquantes, avec la
possibilité de définir des scripts directement dans le job, au lieu
d’avoir à les écrire dans des fichiers extérieurs. Ces scripts
internes permettent d’effectuer des tests, d’utiliser des
variables ou des arguments passés en paramètre.
En première
approche, les jobs ne contenant qu’une instruction exec
sont une simple adaptation des lignes de l’ancien fichier
/etc/inittab. Le nouveau mécanisme n’a alors comme seul intérêt
que la possibilité d’arrêter ou de relancer un job. C’est le
cas du premier exemple ci-après.
Par contre, les jobs utilisant
les instructions pre-XXX,
post-XXX
ou script évitent l’écriture
de scripts complexes externes au job. C’est la cas du second
exemple présenté.
Premier exemple simple, utilisant une instruction exec : le job tty1 d’une distribution Ubuntu :
# tty1 - getty # # This service maintains a getty on tty1 from the point the system is # started until it is shut down again.
start on stopped rc2 start on stopped rc3 start on stopped rc4 start on stopped rc5
stop on runlevel 0 stop on runlevel 1 stop on runlevel 6
respawn exec /sbin/getty 38400 tty1
Second exemple plus complexe, évitant l’écriture d’un script externe au job : rc3
# rc3 - runlevel 3 compatibility # # This task runs the old sysv-rc runlevel 3 (user defined) scripts. # It is usually started by the telinit compatibility wrapper.
start on runlevel 3
stop on runlevel [!3]
console output script set $(runlevel --set 3 || true) if [ "$1" != "unknown" ]; then PREVLEVEL=$1 RUNLEVEL=$2 export PREVLEVEL RUNLEVEL fi
exec /etc/init.d/rc 3 end script
Bon, me direz-vous, upstart est plus souple. Mais dans la pratique, est-ce que cela peut m’être utile personnellement ? Ou n’est-ce utile que pour les éditeurs de distributions ? J’ai quelques réponses à proposer.
N’avez-vous jamais été gêné par le nombre réduit de niveaux disponibles avec init ? Personnellement, sur certains types de serveurs, j’aurais parfois eu besoin de modes de fonctionnement du système plus nombreux. Aujourd’hui, dans la mesure où je peux définir mes propres événements, je n’ai plus cette limitation.
Le mécanisme de lancement des services avec les scripts présents dans les répertoires /etc/rcn.d est très souple, mais si je souhaite abandonner l’environnement graphique, il faut que je change de niveau. Il faut donc que je sois absolument sur que les niveaux 3 et 5 (dans une distribution Fedora) sont exactement identiques. Avec upstart, je n’ai pas de questions à me poser, en exécutant simplement la commande initctl stop prefdm.
Imaginons
maintenant que je veuille être sûr que le démon sshd est toujours
opérationnel sur mon système, sauf lorsque je décide de l’arrêter
parce que je suis physiquement devant l’écran du serveur. Je ne
peux pas m’appuyer sur le mécanisme standard du script
/etc/rc3.d/S55sshd, parce que rien ne relancera le démon
sshd s’il est tué pour une raison ou une autre. Si je ne dispose
que d’init ancienne méthode, j’ajoute une ligne dans
/etc/inittab, avec l’option respawn. Et si je dois
arrêter sshd, je dois modifier le fichier et lancer telinit
q. Mais lorsque j’ai terminé mon opération, je ne dois
surtout pas oublier de faire la modification inverse dans le fichier
/etc/inittab, ni de relancer à nouveau telinit q.
On n’est pas du tout dans une démarche de qualité et de sécurité
puisque la sécurité dépend de ma mémoire !
Alors qu’avec
upstart, il me suffit d’écrire un job tel que :
start on runlevel 3console output respawn exec /usr/sbin/sshd
(NB : ce script est simplissime et ne sert que d’illustration. Dans un cas réel, il faudrait s’inspirer du script /etc/init.d/sshd pour avoir un fonctionnement plus harmonieux de sshd).
Il n’existe encore que très peu de documentation sur upstart. On peut trouver sur le site du projet upstart des éléments en anglais : http://upstart.ubuntu.com/.
J’ai essayé de dresser un petit tour de description de ce nouveau mécanisme qui apporte bien plus de souplesse que l’ancien init. Dans le mesure où ce mécanisme est encore nouveau et en pleine évolution, votre distribution ne suit peut être pas tout ce qui a été indiqué. N’hésitez pas à me contacter sur mon blog « on ne fait pas de la magie » si vous avez des questions ou des remarques.