Chapitre 914 minIntermédiaire
Processus et services : ps, kill, systemctl
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- observer les processus et la charge d'une machine ;
- arrêter un processus proprement avec le bon signal ;
- piloter un service avec
systemctlet lire son état ; - écrire une unité systemd pour une application et la durcir ;
- modifier un service fourni par un paquet sans toucher à son fichier.
3 exercices corrigés
Un processus est un programme en cours d'exécution, identifié par un numéro (PID) ; un service est un processus lancé au démarrage et surveillé par systemd, le premier processus du système. Ce chapitre montre comment observer les processus et la charge d'une machine, leur envoyer des signaux, puis piloter les services avec systemctl, écrire une unité systemd pour une application maison et modifier un service existant sans toucher au fichier du paquet.
Observer les processus
Chaque processus a un PID, un processus parent (PPID), un propriétaire, et consomme du processeur et de la mémoire. Le noyau les expose dans /proc/<PID>/.
| Commande | Ce qu'elle montre |
|---|---|
ps aux | Tous les processus : utilisateur, PID, %CPU, %MEM, commande |
ps -ef --forest | Tous les processus, avec la parenté en arbre |
ps -u www-data | Les processus d'un compte |
pgrep -a nginx | Les PID et commandes dont le nom correspond |
pstree -p | L'arbre des processus depuis systemd (PID 1) |
top | Vue en direct, triée par consommation (P processeur, M mémoire, k tuer, q quitter) |
htop | La même chose, plus lisible (paquet htop) |
uptime | Durée de fonctionnement et charge moyenne sur 1, 5 et 15 minutes |
free -h | Mémoire vive et swap utilisées |
clambert@srv-web:~$ ps aux | grep [n]ginx
root 620 0.0 0.1 11404 1640 ? Ss 08:12 0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data 621 0.0 0.3 12960 6196 ? S 08:12 0:01 nginx: worker process
www-data 622 0.0 0.3 12960 6196 ? S 08:12 0:01 nginx: worker process
Le processus maître de nginx tourne en root pour ouvrir le port 443, puis lance des processus de travail sous www-data, qui traitent les requêtes : c'est le moindre privilège appliqué par le logiciel lui-même. Les crochets de [n]ginx évitent que grep se trouve lui-même dans la liste.
La charge moyenne (load average) compte les processus qui s'exécutent ou attendent le processeur (ou un disque). Elle se compare au nombre de cœurs : 0.80 sur une machine à 2 cœurs, c'est calme ; 6.00 durablement, des processus font la queue. nproc affiche le nombre de cœurs.
Les signaux
On agit sur un processus en lui envoyant un signal :
| Signal | Numéro | Effet | Envoyé par |
|---|---|---|---|
SIGTERM | 15 | Demande de s'arrêter proprement (le programme ferme ses fichiers) | kill PID (signal par défaut) |
SIGKILL | 9 | Arrêt immédiat par le noyau, sans que le programme puisse réagir | kill -9 PID, en dernier recours |
SIGHUP | 1 | Beaucoup de services y relisent leur configuration | kill -HUP PID |
SIGINT | 2 | Interruption | Ctrl+C |
SIGSTOP / SIGCONT | 19 / 18 | Suspendre / reprendre | kill -STOP, kill -CONT |
pkill nginx et killall nginx envoient un signal par nom. Pour un service, on passe plutôt par systemctl stop ou systemctl kill : systemd sait quels processus appartiennent au service.
Priorité. La valeur nice va de -20 (le plus prioritaire) à 19 (le plus gentil avec les autres), 0 par défaut. nice -n 10 tar czf archive.tgz /srv/journaux lance une compression en arrière-plan sans ralentir le reste ; sudo renice -n 15 -p 2741 change la priorité d'un processus déjà lancé. Seul root peut augmenter une priorité.
Avant-plan et arrière-plan. Dans un terminal, commande & lance en arrière-plan ; Ctrl+Z suspend la commande en cours ; jobs liste, bg relance en arrière-plan, fg ramène au premier plan. Une commande lancée ainsi s'arrête quand la session SSH se ferme : pour un long traitement, utilise nohup commande &, ou mieux une session tmux qu'on retrouve après une déconnexion.
systemd et les unités
systemd est le premier processus lancé par le noyau (PID 1). Il démarre tous les autres, dans le bon ordre, les surveille, les relance s'ils s'arrêtent, et collecte leurs journaux. Il décrit chaque chose à gérer par une unité (unit), un fichier texte :
| Type d'unité | Suffixe | Exemple |
|---|---|---|
| Service | .service | nginx.service, ssh.service |
| Minuterie | .timer | apt-daily.timer, logrotate.timer (chapitre 15) |
| Point de montage | .mount | tmp.mount, généré pour chaque ligne de /etc/fstab |
| Socket | .socket | Démarre un service à la première connexion |
| Cible | .target | Un groupe d'unités : multi-user.target, rescue.target |
Les unités livrées par les paquets sont dans /usr/lib/systemd/system/ ; celles de l'administrateur, et ses modifications, dans /etc/systemd/system/, qui a priorité. On ne modifie jamais les fichiers de /usr/lib : une mise à jour du paquet les écraserait.
Piloter un service avec systemctl
| Commande | Effet |
|---|---|
systemctl status nginx | État, PID, dernières lignes du journal |
sudo systemctl start nginx / stop | Démarre / arrête maintenant |
sudo systemctl restart nginx | Arrête puis redémarre (coupe les connexions en cours) |
sudo systemctl reload nginx | Relit la configuration sans interruption (si le service le permet) |
sudo systemctl enable nginx / disable | Démarre / ne démarre plus au démarrage de la machine |
sudo systemctl enable --now nginx | Active au démarrage et démarre maintenant |
sudo systemctl mask cups | Interdit tout démarrage, même manuel ou par dépendance (unmask pour lever) |
systemctl is-active nginx, is-enabled nginx | Réponse d'un mot, pratique dans un script |
systemctl --failed | Les unités en échec |
systemctl list-units --type=service --state=running | Les services qui tournent |
systemctl cat nginx | Le fichier de l'unité et ses surcharges |
sudo systemctl daemon-reload | Relit les fichiers d'unité après une modification |
clambert@srv-web:~$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since mer. 2026-11-04 08:12:03 CET; 1h 40min ago
Docs: man:nginx(8)
Process: 612 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Process: 618 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Main PID: 620 (nginx)
Tasks: 3 (limit: 2307)
Memory: 4.1M (peak: 4.6M)
CPU: 38ms
CGroup: /system.slice/nginx.service
├─620 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
├─621 "nginx: worker process"
└─622 "nginx: worker process"
Trois lignes à lire en premier : Loaded dit où est le fichier et si le service est activé au démarrage (enabled) ; Active dit s'il tourne (active (running)), s'il a échoué (failed) ou s'il est arrêté (inactive (dead)) ; les dernières lignes du journal, sous le cadre, donnent souvent la cause d'un échec.
Écrire une unité pour une application
Le site de suivi des livraisons s'appuie sur une petite application (une API écrite en Python) qui écoute sur 127.0.0.1:8080, derrière nginx. Plutôt que de la lancer à la main dans un terminal, on en fait un service : elle démarrera avec la machine, sera relancée si elle plante, tournera sous un compte dédié sans privilège, et ses messages iront dans le journal.
sudo adduser --system --group --home /opt/suivi suivi # compte système dédié
sudo nano /etc/systemd/system/suivi-api.service
[Unit]
Description=API du site de suivi des livraisons
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=suivi
Group=suivi
WorkingDirectory=/opt/suivi
ExecStart=/usr/bin/python3 /opt/suivi/app.py
Restart=on-failure
RestartSec=5
UMask=0027
# Durcissement : pas de nouveaux privilèges, système en lecture seule, /tmp privé
NoNewPrivileges=yes
ProtectSystem=full
ProtectHome=yes
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
| Section, directive | Rôle |
|---|---|
[Unit] After=, Wants= | Démarrer après que le réseau est configuré |
[Service] Type=simple | Le processus lancé par ExecStart est le service lui-même |
User=, Group= | Le compte sous lequel il tourne |
Restart=on-failure, RestartSec=5 | Relancer 5 secondes après un plantage (pas après un arrêt demandé) |
NoNewPrivileges=, ProtectSystem=, ProtectHome=, PrivateTmp= | Limiter ce que le service pourrait faire s'il était détourné |
[Install] WantedBy=multi-user.target | enable le rattache au démarrage normal du serveur |
sudo systemctl daemon-reload
sudo systemctl enable --now suivi-api
systemctl status suivi-api
journalctl -u suivi-api -f
systemd-analyze verify /etc/systemd/system/suivi-api.service vérifie la syntaxe, et systemd-analyze security suivi-api note l'exposition du service, de 0 (très protégé) à 10, avec la liste des protections qui manquent.
Modifier un service sans toucher au paquet
Pour changer le comportement d'un service fourni par un paquet, on écrit une surcharge (drop-in) : un petit fichier qui ajoute ou remplace des directives. systemctl edit la crée au bon endroit :
sudo systemctl edit nginx
L'éditeur s'ouvre sur /etc/systemd/system/nginx.service.d/override.conf. On y écrit seulement ce qui change :
[Service]
Restart=on-failure
RestartSec=10
À l'enregistrement, systemctl edit recharge la configuration de systemd. systemctl cat nginx affiche le fichier d'origine suivi de la surcharge. Une mise à jour du paquet nginx remplacera son fichier dans /usr/lib, jamais ta surcharge.
Les cibles et le démarrage
Une cible regroupe les unités d'un état du système. Les principales :
| Cible | État | Équivalent historique |
|---|---|---|
multi-user.target | Serveur normal, multi-utilisateur, réseau, sans interface graphique | Niveau 3 |
graphical.target | multi-user + interface graphique | Niveau 5 |
rescue.target | Mode de secours : un seul utilisateur (root), systèmes de fichiers montés, peu de services | Niveau 1 |
emergency.target | Mode d'urgence : seul / est monté, en lecture seule |
systemctl get-default affiche la cible de démarrage (multi-user.target sur un serveur sans bureau). systemd-analyze blame liste les unités les plus lentes au démarrage ; systemd-analyze critical-chain montre la chaîne qui a retardé l'arrivée à la cible. Le démarrage complet, de l'UEFI à la cible, est détaillé avec le dépannage au chapitre 17.
Exercices
Exercice 1 sur 3 start, enable ou reload ? Réussi À revoir
Donne la commande pour chaque situation sur srv-web :
- Tu viens de modifier
/etc/nginx/sites-available/suiviet veux l'appliquer sans couper les visiteurs. - Le service
cups(impression) n'a rien à faire sur un serveur et ne doit plus jamais démarrer. - Après l'installation de
fail2ban, tu veux qu'il tourne maintenant et après chaque redémarrage. - Tu viens de créer
/etc/systemd/system/suivi-api.service;systemctl start suivi-apirépond « Unit suivi-api.service not found ».
Voir la réponseMasquer la réponse de l'exercice 1
sudo nginx -t && sudo systemctl reload nginx: on teste la syntaxe, et on recharge seulement si le test réussit.sudo systemctl disable --now cups, etsudo systemctl mask cupspour qu'aucune dépendance ne puisse le relancer. Mieux encore :sudo apt purge cups.sudo systemctl enable --now fail2ban.- systemd n'a pas encore lu le nouveau fichier :
sudo systemctl daemon-reload, puissudo systemctl enable --now suivi-api.
Tu avais trouvé ?
Exercice 2 sur 3 Lire un état de service Réussi À revoir
● suivi-api.service - API du site de suivi des livraisons
Loaded: loaded (/etc/systemd/system/suivi-api.service; enabled; preset: enabled)
Active: activating (auto-restart) (Result: exit-code) since mer. 2026-11-04 10:31:12 CET; 3s ago
Process: 3310 ExecStart=/usr/bin/python3 /opt/suivi/app.py (code=exited, status=1/FAILURE)
Main PID: 3310 (code=exited, status=1/FAILURE)
nov. 04 10:31:12 srv-web python3[3310]: PermissionError: [Errno 13] Permission denied: '/var/lib/suivi/exports'
nov. 04 10:31:12 srv-web systemd[1]: suivi-api.service: Failed with result 'exit-code'.
- Le service démarrera-t-il au prochain redémarrage de la machine ?
- Que fait systemd en ce moment ?
- Quelle est la cause, et comment la corriger ?
Voir la réponseMasquer la réponse de l'exercice 2
- Oui :
enabledsur la ligne Loaded. - Il attend avant de relancer le service (
activating (auto-restart)), comme le demandeRestart=on-failure: le programme s'est terminé avec le code 1, un échec. - L'application, qui tourne sous le compte
suivi, n'a pas le droit d'écrire dans/var/lib/suivi/exports. Il faut donner ce dossier au compte du service :sudo mkdir -p /var/lib/suivi/exports && sudo chown -R suivi:suivi /var/lib/suivi && sudo chmod 750 /var/lib/suivi /var/lib/suivi/exports. Une autre solution, plus propre, est la directiveStateDirectory=suividans l'unité : systemd crée alors/var/lib/suiviau démarrage, avec le bon propriétaire.
Tu avais trouvé ?
Exercice 3 sur 3 Un processus qui ne répond plus Réussi À revoir
Un script d'export lancé à la main par Moussa Diallo (PID 4120) bloque depuis une heure et consomme 100 % d'un cœur. Décris, dans l'ordre, les commandes pour le constater et l'arrêter proprement.
Voir la réponseMasquer la réponse de l'exercice 3
- Constater :
top(oups -o pid,user,%cpu,etime,cmd -p 4120) montre le processus, son propriétaire, sa consommation et sa durée. - Demander l'arrêt propre :
kill 4120(SIGTERM, sanssudopuisqu'il appartient àmdiallo, qui le lance lui-même). - Attendre quelques secondes, vérifier avec
ps -p 4120. S'il est toujours là :kill -9 4120. - Chercher la cause avant de relancer (fichier verrouillé, boucle infinie), dans la sortie du script ou dans le journal.
Tu avais trouvé ?