15%

Économisez 15% sur tous les services d'hébergement

Testez vos compétences et obtenez Réduction sur tout plan d'hébergement

Utilisez le code :

Skills
Commencer
09.10.2024

Gestion des ressources système avec la commande `ulimit` sur Linux

La commande `ulimit` est un utilitaire shell intégré aux systèmes Unix et Linux qui applique des limites de ressources par processus et par utilisateur, empêchant tout processus ou utilisateur unique d’épuiser les ressources système telles que le temps CPU, la mémoire, les descripteurs de fichiers ouverts et le nombre de processus. Elle fonctionne au niveau du noyau via l’appel système `setrlimit()`, ce qui en fait l’un des mécanismes les plus directs et les moins coûteux disponibles pour les administrateurs système en matière de gouvernance des ressources.

Pour tout serveur exécutant des charges de travail en production — qu’il s’agisse d’une application web à fort trafic, d’un moteur de base de données ou d’une pile de microservices conteneurisés — des paramètres `ulimit` mal configurés ou absents constituent l’une des principales causes de défaillances en cascade, de processus incontrôlés et de pannes système complètes. Configurer correctement ces limites n’est pas facultatif ; c’est une hygiène d’infrastructure fondamentale.

Fonctionnement interne de `ulimit`

Lorsqu’un processus shell appelle `ulimit`, il invoque les appels système `getrlimit()` et `setrlimit()` définis dans la norme POSIX. Chaque limite est représentée par une paire de valeurs : une limite logicielle et une limite matérielle. Ces valeurs sont stockées par processus dans le descripteur de processus du noyau et sont héritées par les processus enfants au moment de `fork()`.

Ce modèle d’héritage est essentiel à comprendre. Si vous définissez des valeurs `ulimit` dans une session shell, chaque processus engendré par ce shell — y compris les démons lancés via des scripts init — hérite de ces limites. À l’inverse, les limites définies dans `/etc/security/limits.conf` s’appliquent au moment de la connexion PAM, et non à l’exécution, ce qui signifie qu’elles ne prennent effet que pour les nouvelles sessions de connexion, et non pour les services déjà en cours d’exécution.

Limites logicielles vs. limites matérielles

PropriétéLimite logicielleLimite matérielle
Qui peut l’augmenterTout utilisateur non privilégié (jusqu’à la limite matérielle)Uniquement root (`CAP_SYS_RESOURCE`)
Qui peut la réduireTout utilisateurTout utilisateur (irréversible sans root)
ApplicationAppliquée par le noyauSert de plafond pour la limite logicielle
Cas d’utilisation typiqueLimite opérationnelle quotidienneMaximum absolu pour la politique de sécurité
Indicateur dans `ulimit``-S``-H`

Une erreur opérationnelle courante consiste à définir la limite matérielle égale à la limite logicielle. Cela supprime toute flexibilité pour qu’un processus puisse temporairement augmenter ses propres limites, ce que certaines applications (comme certaines implémentations JVM et moteurs de bases de données) font légitimement au démarrage.

Référence complète : indicateurs de ressources `ulimit`

IndicateurRessourceUnitéValeur courante en production
`-t`Temps CPUSecondes`unlimited` pour les démons
`-f`Taille maximale de fichierBlocs de 512 octets`unlimited` ou limite spécifique
`-d`Taille du segment de données (tas)KB`unlimited` pour les applications Java
`-s`Taille de la pileKB`8192` (par défaut)
`-c`Taille du fichier core dumpBlocs de 512 octets`0` (désactivé en production)
`-m`Taille maximale de l’ensemble résidentKBRarement appliqué (utiliser cgroups)
`-v`Mémoire virtuelle (espace d’adressage)KB`unlimited` pour la plupart des services
`-n`Descripteurs de fichiers ouvertsNombre`65536` ou plus pour les serveurs très sollicités
`-u`Nombre maximal de processus utilisateurNombre`4096`–`65536` selon le rôle
`-l`Mémoire verrouillée (mlock)KBÉlevé pour Redis, Elasticsearch
`-i`Signaux en attenteNombreLa valeur système par défaut est généralement suffisante
`-q`Octets de file de messages POSIXOctetsValeur système par défaut
`-r`Priorité d’ordonnancement en temps réelPriorité`0` sauf pour les charges de travail RT
`-e`Priorité d’ordonnancement maximale (nice)Valeur niceValeur système par défaut

Utilisation pratique de `ulimit` avec contexte réel

Affichage des limites actuelles

“`bash

ulimit -a # All soft limits for the current shell

ulimit -aH # All hard limits for the current shell

“`

Pour inspecter les limites d’un processus en cours d’exécution spécifique (PID), lisez directement depuis le système de fichiers proc — c’est la source faisant autorité et cela contourne les rapports au niveau du shell :

“`bash

cat /proc/<PID>/limits

“`

Cela est inestimable lors du dépannage d’un service démarré par systemd ou un script init, où `ulimit -a` au niveau du shell ne reflètera pas les limites réelles du processus.

Définition des limites logicielles et matérielles

“`bash

Set soft limit for open file descriptors

ulimit -Sn 65536

Set hard limit for open file descriptors

ulimit -Hn 131072

Set both simultaneously (soft = hard = value)

ulimit -n 65536

“`

Désactivation des core dumps en production

“`bash

ulimit -c 0

“`

Les core dumps peuvent consommer des gigaoctets d’espace disque en quelques secondes lorsqu’un processus à forte mémoire plante. Les désactiver en production est une pratique standard, sauf si vous déboguez activement. Pour les environnements de développement, définissez un chemin dédié en utilisant `sysctl kernel.core_pattern` avec une limite de core non nulle.

Restriction du temps CPU pour les processus non fiables

“`bash

ulimit -t 30

“`

Cela envoie `SIGXCPU` au processus lorsqu’il atteint la limite logicielle de temps CPU, et `SIGKILL` à la limite matérielle. Cela est particulièrement utile dans les environnements d’hébergement partagé ou lors de l’exécution de scripts soumis par des utilisateurs.

Augmentation de la limite de descripteurs de fichiers ouverts pour les services à haute concurrence

Nginx, HAProxy, PostgreSQL et Redis nécessitent tous un grand nombre de descripteurs de fichiers ouverts sous charge. La valeur système par défaut de 1024 est dangereusement basse pour la production :

“`bash

ulimit -n 65536

“`

Cependant, cela n’affecte que la session shell actuelle. Pour une configuration persistante, utilisez les méthodes décrites dans la section suivante.

Rendre les paramètres `ulimit` persistants

Méthode 1 : `/etc/security/limits.conf`

Il s’agit de l’approche PAM standard pour les limites persistantes au niveau utilisateur :

“`

/etc/security/limits.conf

<domain> <type> <item> <value>

  • soft nofile 65536
  • hard nofile 131072

nginx soft nproc 4096

nginx hard nproc 8192

postgres soft nofile 65536

postgres hard nofile 65536

postgres soft memlock unlimited

postgres hard memlock unlimited

“`

Le caractère générique `*` s’applique à tous les utilisateurs mais ne s’applique pas à root. Root nécessite une entrée explicite :

“`

root soft nofile 65536

root hard nofile 131072

“`

Assurez-vous que le module PAM est chargé. Vérifiez que `/etc/pam.d/common-session` (Debian/Ubuntu) ou `/etc/pam.d/system-auth` (RHEL/CentOS) contient :

“`

session required pam_limits.so

“`

Méthode 2 : fichiers drop-in `/etc/security/limits.d/`

Pour une gestion plus propre, notamment dans les systèmes de gestion de configuration comme Ansible ou Puppet, placez des fichiers de limites spécifiques aux services dans le répertoire drop-in :

“`bash

/etc/security/limits.d/99-nginx.conf

nginx soft nofile 65536

nginx hard nofile 131072

“`

Les fichiers de ce répertoire sont traités après `limits.conf` et le remplacent, ce qui les rend idéaux pour le réglage spécifique aux applications sans modifier la configuration de base.

Méthode 3 : unités de service systemd (la norme moderne)

Pour les services gérés par systemd — ce qui représente la majorité des distributions Linux modernes — `limits.conf` n’est pas appliqué par défaut. systemd gère ses propres limites de ressources par unité de service :

“`ini

/etc/systemd/system/nginx.service.d/limits.conf

[Service]

LimitNOFILE=65536

LimitNPROC=4096

LimitCORE=0

LimitMEMLOCK=infinity

“`

Après modification, rechargez et redémarrez :

“`bash

systemctl daemon-reload

systemctl restart nginx

“`

Vérifiez les limites appliquées :

“`bash

cat /proc/$(systemctl show -p MainPID nginx | cut -d= -f2)/limits

“`

Il s’agit de la méthode la plus fiable pour les services en production et devrait être l’approche par défaut sur tout système exécutant systemd (Ubuntu 16.04+, CentOS 7+, Debian 8+).

Méthode 4 : fichiers de profil shell

Pour les limites de session utilisateur qui s’appliquent de manière interactive, ajoutez des commandes `ulimit` à `/etc/profile` (système global) ou `~/.bashrc` / `~/.profile` (par utilisateur). Cette approche convient aux postes de travail des développeurs mais ne convient pas aux processus démons.

Profils de configuration `ulimit` basés sur les rôles

Différents rôles de serveur nécessitent des profils de limites de ressources fondamentalement différents. Appliquer des valeurs par défaut génériques à tous les types de serveurs est une source courante de défaillances subtiles et difficiles à diagnostiquer.

Serveur web (Nginx / Apache)

“`

nofile: 65536–131072 # High concurrency requires many open sockets + files

nproc: 4096 # Worker processes + threads

core: 0 # Disable core dumps in production

“`

Base de données relationnelle (PostgreSQL / MySQL)

“`

nofile: 65536 # Many concurrent connections = many file descriptors

memlock: unlimited # Required for shared memory and huge pages

nproc: 4096

stack: 8192 KB

core: 0

“`

Serveur d’applications Java (Tomcat / Spring Boot)

“`

nofile: 65536

nproc: 65536 # JVM thread-per-connection models spawn many threads

data: unlimited # JVM heap is allocated from the data segment

stack: 512 KB # Reduce stack size to fit more threads in memory

“`

Redis / Stockage de données en mémoire

“`

nofile: 65536

memlock: unlimited # Prevents swapping of memory-mapped data

“`

Pièges critiques et cas limites

La limite `nproc` compte les threads, pas seulement les processus. Sous Linux, les threads sont implémentés comme des processus légers (`clone()` avec mémoire partagée). Une application Java avec 500 threads compte pour 500 contre la limite `nproc`. Cela surprend de nombreux administrateurs qui définissent des valeurs `nproc` conservatrices et se demandent ensuite pourquoi leur JVM plante avec `OutOfMemoryError: unable to create new native thread`.

`ulimit -v` limite l’espace d’adressage virtuel, pas la RAM physique. De nombreux administrateurs définissent `-v` en pensant limiter l’utilisation de la mémoire. En réalité, ils limitent l’espace d’adressage virtuel, qui inclut les fichiers mappés en mémoire, les bibliothèques partagées et le métaspace JVM. Définir cette valeur trop basse provoquera des échecs `mmap()` et des erreurs d’application cryptiques.

`ulimit` ne s’applique pas rétroactivement. La modification des limites dans `limits.conf` ou un fichier d’unité systemd n’affecte pas les processus déjà en cours d’exécution. Vous devez redémarrer le service pour que les nouvelles limites prennent effet.

Les environnements de conteneurs contournent `ulimit` de manière inattendue. Dans Docker, les valeurs par défaut de `ulimit` sont définies au niveau du démon (`/etc/docker/daemon.json`) et peuvent être remplacées par conteneur avec `–ulimit`. Cependant, les limites du conteneur sont bornées par les limites du noyau hôte. Définir `nofile=1048576` dans un conteneur alors que l’hôte a `nofile=65536` reviendra silencieusement à la limite de l’hôte.

Le plafond système `nofile` est distinct des limites par processus. Le paramètre noyau `fs.file-max` (défini via `sysctl`) contrôle le nombre total de descripteurs de fichiers dans l’ensemble du système. Même si `nofile` par processus est défini à une valeur élevée, atteindre `fs.file-max` provoquera des erreurs `ENFILE` à l’échelle du système. Vérifiez et ajustez les deux :

“`bash

sysctl fs.file-max

sysctl -w fs.file-max=2097152

“`

`ulimit` vs. cgroups : choisir le bon outil

Capacité`ulimit` / `setrlimit`cgroups v2
PortéePar processus (hérité par les enfants)Par groupe de processus
Limitation de la mémoireEspace d’adressage virtuel uniquement (`-v`)Application réelle RSS + swap
Limitation du CPUBudget de temps CPU (`-t`)Contrôleur de bande passante CPU (% précis)
Limitation des E/SNon pris en chargePondération et limites de débit des E/S bloc
Limitation réseauNon pris en chargeNécessite l’intégration tc + cgroup
PersistanceVia PAM ou systemdVia les tranches systemd ou cgroupfs
Compatibilité avec les conteneursLimitéeNative (Docker, Kubernetes utilisent cgroups)
GranularitéGrossièreFine

`ulimit` reste le bon outil pour les limites rapides par session, les plafonds de descripteurs de fichiers et le contrôle des core dumps. Pour une isolation complète des ressources — notamment dans les environnements multi-locataires ou les charges de travail conteneurisées — cgroups v2 est le mécanisme supérieur. Sur un environnement VPS Hosting ou Serveur Dédié bien configuré, les deux mécanismes sont généralement utilisés en combinaison : `ulimit` pour les garde-fous par processus et cgroups pour les budgets de ressources agrégés.

Surveillance et validation des limites de ressources

Une surveillance proactive prévient les défaillances liées aux limites avant qu’elles ne deviennent des incidents en production.

Vérifier l’utilisation actuelle des descripteurs de fichiers à l’échelle du système :

“`bash

cat /proc/sys/fs/file-nr

Output: <allocated> <unused> <max>

“`

Trouver les processus approchant leur limite `nofile` :

“`bash

for pid in /proc/[0-9]*; do

pid_num=${pid##*/}

limit=$(awk '/Max open files/{print $4}' /proc/$pid_num/limits 2>/dev/null)

current=$(ls /proc/$pid_num/fd 2>/dev/null | wc -l)

[ -n "$limit" ] && [ "$limit" != "unlimited" ] &&

awk -v c=$current -v l=$limit -v p=$pid_num

'BEGIN{if(c/l>0.8) printf "PID %s: %d/%d (%.0f%%)n",p,c,l,c/l*100}'

done

“`

Outils pour la surveillance continue :

  • `lsof -u <username>` — lister tous les fichiers ouverts pour un utilisateur
  • `ss -s` — statistiques de socket (corrélées avec la pression `nofile`)
  • `htop` avec vue arborescente des processus — visualiser le nombre de processus par utilisateur
  • `sar -v` — utilisation historique des descripteurs de fichiers et des inodes via sysstat
  • Prometheus `node_exporter` — expose les métriques `node_filefd_allocated` et `node_filefd_maximum` pour les alertes

Pour les environnements exécutant un VPS avec cPanel ou d’autres panneaux de contrôle, bon nombre de ces limites sont préconfigurées par l’installateur du panneau, mais elles nécessitent fréquemment une augmentation à mesure que le trafic croît. Vérifiez toujours les limites réelles via `/proc/<PID>/limits` plutôt que de faire confiance à la documentation du panneau.

Implications de sécurité de `ulimit`

Les limites de ressources constituent également un contrôle de sécurité. Sans elles, un processus compromis ou bogué peut exécuter une bombe fork (`:(){ :|:& };:`), épuisant tous les emplacements de processus disponibles et rendant le système non réactif. Une limite `nproc` conservatrice par utilisateur est la principale mesure d’atténuation :

“`

  • hard nproc 4096

“`

De même, la désactivation des core dumps (`-c 0`) empêche que le contenu sensible de la mémoire — y compris les clés de chiffrement, les mots de passe et les jetons de session — ne soit écrit sur le disque dans un fichier lisible par tous.

Pour les environnements d’hébergement partagé ou tout serveur où plusieurs utilisateurs ont accès au shell, `ulimit` est une couche de sécurité obligatoire. Sur l’infrastructure d’Hébergement Web Partagé, ces limites sont généralement appliquées au niveau de la plateforme, mais les administrateurs gérant leur propre VPS multi-utilisateurs doivent les configurer explicitement.

Si votre serveur gère la terminaison SSL ou la gestion des certificats, assurez-vous que le processus gérant TLS (par exemple, Nginx, HAProxy) dispose de limites `nofile` suffisantes, car chaque connexion TLS nécessite plusieurs descripteurs de fichiers. Associez cela à des Certificats SSL correctement configurés pour éviter que les échecs liés aux certificats ne viennent aggraver les problèmes de ressources.

Pour les déploiements de serveurs de messagerie, Postfix et Dovecot sont particulièrement sensibles aux limites `nofile`, car chaque connexion e-mail simultanée et chaque accès à une boîte aux lettres consomme des descripteurs de fichiers. Si vous gérez votre propre infrastructure de messagerie plutôt que d’utiliser un Hébergement E-mail géré, régler `nofile` à au moins 65536 pour l’utilisateur mail est non négociable sur tout serveur modérément chargé.

Matrice de décision : quoi configurer et où

ScénarioMéthode recommandéeParamètres clés
Sessions utilisateur interactives`/etc/security/limits.conf``nofile`, `nproc`, `core`
Service géré par systemdSection `[Service]` de l’unité systemd`LimitNOFILE`, `LimitNPROC`, `LimitCORE`
Conteneur DockerIndicateur `–ulimit` ou `daemon.json``nofile`, `nproc`
Test shell ponctuelCommande `ulimit` directementTout indicateur
Serveur partagé multi-locataires`limits.conf` + application PAM`nproc`, `nofile`, `fsize`, `cpu`
Pod KubernetesContexte de sécurité du pod + cgroupsGéré par kubelet
Réglage spécifique à une applicationFichier drop-in `limits.d/`Paramètres spécifiques au service

Liste de contrôle des points clés techniques

  • Vérifiez toujours les limites appliquées via `/proc/<PID>/limits`, et non via `ulimit -a` au niveau du shell, pour les services en cours d’exécution.
  • Pour les services systemd, configurez les limites dans le fichier d’unité en utilisant les directives `Limit*` — `limits.conf` n’est pas lu par systemd par défaut.
  • Définissez `nofile` à au minimum `65536` pour tout service gérant des connexions réseau ; `131072` ou plus pour les charges de travail à haute concurrence.
  • Ne définissez jamais la limite matérielle égale à la limite logicielle, sauf si vous avez une exigence de sécurité spécifique — les applications ont besoin de marge pour s’auto-ajuster.
  • Désactivez les core dumps (`LimitCORE=0`) en production ; activez-les avec un chemin contrôlé en préproduction.
  • La limite `nproc` compte les threads sous Linux — tenez-en compte lors de la configuration des applications JVM ou Go runtime.
  • Ajustez `fs.file-max` via `sysctl` en parallèle des limites `nofile` par processus pour éviter l’épuisement `ENFILE` à l’échelle du système.
  • Dans les environnements conteneurisés, les limites du noyau hôte constituent le plafond absolu — les paramètres `ulimit` au niveau du conteneur ne peuvent pas les dépasser.
  • Utilisez cgroups v2 pour l’application des limites de mémoire et d’E/S ; utilisez `ulimit` pour les plafonds de descripteurs de fichiers, les nombres de processus et le contrôle des core dumps.
  • Après toute modification de limite dans `limits.conf` ou les fichiers d’unité systemd, redémarrez le service concerné et vérifiez avec `/proc/<PID>/limits`.

FAQ

`ulimit` s’applique-t-il aux processus root ?

Le caractère générique `*` dans `/etc/security/limits.conf` exclut explicitement root. Les processus root contournent également l’application des limites matérielles pour la plupart des types de ressources — root peut augmenter ses propres limites matérielles. Pour appliquer des limites à root, ajoutez une entrée explicite `root` dans `limits.conf`, bien que de nombreux services système s’exécutant en tant que root ignorent les limites appliquées par PAM s’ils sont démarrés en dehors d’une session de connexion.

Pourquoi ma modification de `limits.conf` n’a-t-elle aucun effet sur un service en cours d’exécution ?

`limits.conf` est appliqué par PAM au moment de la connexion. Les services démarrés par systemd, SysVinit ou Upstart ne passent pas par PAM et n’héritent donc pas des paramètres `limits.conf`. Configurez les limites directement dans le fichier d’unité systemd en utilisant `LimitNOFILE` et les directives associées, puis exécutez `systemctl daemon-reload && systemctl restart <service>`.

Quelle est la valeur maximale que je peux définir pour `nofile` ?

Le maximum par processus est borné par le paramètre noyau `fs.nr_open` (par défaut : 1 048 576 sur la plupart des noyaux). Le total à l’échelle du système est borné par `fs.file-max`. Vous pouvez augmenter `fs.nr_open` via `sysctl`, mais les valeurs supérieures à 1 048 576 nécessitent une recompilation du noyau sur les noyaux plus anciens. En pratique, 524 288 ou 1 048 576 couvre pratiquement tous les cas d’utilisation en production.

Comment vérifier si un processus a atteint sa limite `ulimit` ?

Consultez le journal du noyau avec `dmesg | grep -i "ulimit|RLIMIT|too many open|cannot allocate"`. Les journaux d’application afficheront généralement `EMFILE` (trop de fichiers ouverts), `ENOMEM` (échec d’allocation de mémoire) ou `EAGAIN` (ressource temporairement indisponible). Croisez avec `/proc/<PID>/limits` et le nombre actuel de descripteurs via `ls /proc/<PID>/fd | wc -l`.

`ulimit` est-il suffisant pour l’isolation des ressources dans un environnement multi-locataires ?

Non. `ulimit` fournit des garde-fous par processus et par utilisateur, mais n’applique pas de limites de bande passante mémoire, d’E/S disque ou de débit réseau. Pour une véritable isolation multi-locataires, combinez `ulimit` avec les contrôleurs de ressources cgroups v2, et envisagez l’isolation par espace de noms (espaces de noms utilisateur, espaces de noms PID) pour des frontières de sécurité plus solides. Sur une infrastructure gérée, ces contrôles sont généralement superposés au niveau de l’hyperviseur et du runtime de conteneur.

15%

Économisez 15% sur tous les services d'hébergement

Testez vos compétences et obtenez Réduction sur tout plan d'hébergement

Utilisez le code :

Skills
Commencer