Diagnostiquer un serveur GNU/Linux

Introduction

Quels sont les outils pour comprendre ce qui se passe sur un serveur qui “semble” lent? Pour répondre, voici une liste des principaux outils en ligne de commande pour diagnostiquer un serveur GNU/Linux.

Escargot géant africain (Achatina fulica)

Cette liste est extraite d’un article écrit par Brendan D. Gregg paru sur le blog technique de Netflix. Contrairement à l’article original je ne présenterai pas uptime (qui donne la charge moyenne pendant la dernière minute écoulée, ainsi que celle des 5 et des 15 dernières minutes), top , ou dmesg | tail, pour me concentrer uniquement sur des outils moins connus.

Liste des outils

vmstat 1

vmstat affiche des informations sur l’état de la mémoire. vmstat 1 ajoute en plus une ligne de mise à jour de ces informations toutes les secondes.

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0 3504512 743984 1847300 4610056    3   10  1538  2221   20   20 31 17 51  1  0
 0  0 3504512 736676 1847316 4616228    0    0     0    17 1884 4703  4  3 93  0  0
 1  0 3504512 728116 1847320 4624320    2    0     2    90 1433 3385  3  2 94  0  0
 0  0 3504512 734148 1847332 4616124    0    0     3   125 1451 3574  4  2 94  0  0
 2  0 3504512 733700 1847336 4616124    0    0     0     5 1443 3480  4  2 94  0  0

Les colonnes à surveiller:

  • r: nombre de processus en cours (running) ou en attente;
  • free: mémoire disponible en kilobytes;
  • si et so: swap in et swap out.
  • us, sy, id, wa, et st: moyenne sur l’ensemble des processeurs des valeurs suivantes
    • user time
    • system time
    • idle
    • wait
    • stolen time

À noter que la première ligne affiche les valeurs moyennes depuis le démarrage de la machine. D’ailleurs vmstat (sans le 1) n’affiche que cette ligne.

Autres options:

  • -w: affiche sur plus de largeur, ce qui améliore la visibilité des nombres dans les colonnes;
  • le nombre à la fin de la commande indique l’intervalle de rafraîchissement (ici 1 = toutes les secondes);
  • si deux nombre apparaissent, le deuxième indique le nombre de rafraîchissement à effectuer avant de s’arrêter.

mpstat -P ALL 1

mpstat -P ALL 1 affiche l’occupation des processeurs, toute les secondes.

18:01:48     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
18:01:49     all    8.08    0.00    4.04    0.00    0.00    1.01    0.00    0.00    0.00   86.87
18:01:49       0    8.08    0.00    4.04    0.00    0.00    1.01    0.00    0.00    0.00   86.87
^C

Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
Average:     all    5.12    0.00    1.71    0.00    0.00    0.68    0.00    0.00    0.00   92.49
Average:       0    5.12    0.00    1.71    0.00    0.00    0.68    0.00    0.00    0.00   92.49

Si la charge reste haute et toujours sur le même processeur, on est en présence d’une application non threadée, qui bloque le processeur.

Comme vmstat, cette commande prend deux nombres en arguments (période et nombre de rafraîchissements)

pidstat 1

Affichage par processeur (avant dernière colonne) les processus les plus gourmands en détaillant la répartition user time, system time et wait.

Linux 4.19.97-v7+ (thelibrary)  05/16/2020      _armv7l_        (4 CPU)

04:41:01 PM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
04:41:02 PM     0       522    0.96    0.00    0.00    0.00    0.96     2  tmux: server
04:41:02 PM     0     29866    0.96    3.85    0.00    0.00    4.81     1  pidstat

04:41:02 PM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
04:41:03 PM     0      9173    0.00    3.00    0.00    0.00    3.00     0  top
04:41:03 PM     0     29856    0.00    1.00    0.00    0.00    1.00     0  kworker/u8:0-events_unbound
04:41:03 PM     0     29858    1.00    0.00    0.00    0.00    1.00     2  kworker/2:2-events
04:41:03 PM     0     29866    3.00    2.00    0.00    0.00    5.00     1  pidstat
^C

Average:      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
Average:        0       522    0.49    0.00    0.00    0.00    0.49     -  tmux: server
Average:        0      9173    0.00    1.47    0.00    0.00    1.47     -  top
Average:        0     29856    0.00    0.49    0.00    0.00    0.49     -  kworker/u8:0-events_unbound
Average:        0     29858    0.49    0.00    0.00    0.00    0.49     -  kworker/2:2-events
Average:        0     29866    1.96    2.94    0.00    0.00    4.90     -  pidstat

Cette commande se rapproche de la commande top mais au lieu de rafraîchir l’écran en effaçant les informations précédentes, elle affiche continuellement des nouvelles données. Ce qui est le cas de la plupart des commandes fournies ici.

pidstat est aussi une commande qui prend deux nombres en arguments (période et nombre de rafraîchissements).

iostat -xz 1

Cette command affiche la charge sur les disques (sur les périphériques de type block plus exactement).

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1,00    0,00    2,25    0,00    0,00   96,75

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0,00     0,00    6,00    0,00   636,00     0,00   212,00     0,00    0,00    0,00    0,00   0,00   0,00
dm-0              0,00     0,00    6,00    0,00   636,00     0,00   212,00     0,00    0,00    0,00    0,00   0,00   0,00
dm-1              0,00     0,00    6,00    0,00   636,00     0,00   212,00     0,00    0,00    0,00    0,00   0,00   0,00

^C

Les informations les plus importantes sont:

  • r/s, w/s, rkB/s, wkB/s: les lectures/écrites, en nombre et en bande passante par seconde;
  • await: l’attente moyenne en milli-seconde avant la réponse à une requête, ce qui est un bon indicateur de problème, si l’attente est trop longue;
  • avgqu­sz: taille moyenne de la queue d’attente du périphérique;
  • %util: l’utilisation du périphérique.

À noter que iostat -xy 1 affiche aussi des informations sur l’utilisation moyenne de tous les processeurs.

Note sur les options:

  • il est possible de spécifier un périphérique (exemple: iostat -xz sda 1)
  • -x: affiche plus de statistiques;
  • -z: n’affiche pas les périphériques inactifs pendant la période d’analyse;
  • -h: statistiques pour les humains;
  • -t: affiche l’heure;
  • encore une commande à deux nombres pour arguments.

free -m (ou mieux free -m -h)

Cette command affiche simplement l’état de la mémoire.

              total        used        free      shared  buff/cache   available
Mem:          7.3Gi       2.2Gi       2.0Gi       468Mi       3.1Gi       4.3Gi
Swap:          15Gi       1.0Mi        15Gi

sar -n DEV 1

Cette commande affiche la bande passante utilisée par chaque interface réseau.

^C

16:37:46        IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
16:37:47           lo     12.86     12.86      1.65      1.65      0.00      0.00      0.00      0.00
16:37:47         eth0      7.14      7.14      0.41      1.48      0.00      0.00      0.00      0.01
16:37:47         eth1      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00

Average:        IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
Average:           lo      6.68      6.68      1.07      1.07      0.00      0.00      0.00      0.00
Average:         eth0     23.06     36.29      1.83     43.52      0.00      0.00      0.00      0.36
Average:         eth1     33.11     19.87     42.08      2.10      0.00      0.00      0.00      0.03

La dernière colonne est particulièrement intéressante puisqu’elle affiche le taux d’usage, qui permet de voir si une interface est saturée.

Sar est une commande à deux nombres pour arguments.

sar -n TCP,ETCP 1

Cette commande affiche un résumé des métriques TCP et des erreurs réseaux.

^C

16:49:36     active/s passive/s    iseg/s    oseg/s
16:49:36         0.00      0.00     50.00     47.06

16:49:36     atmptf/s  estres/s retrans/s isegerr/s   orsts/s
16:49:36         0.00      0.00      0.00      0.00      0.00

Average:     active/s passive/s    iseg/s    oseg/s
Average:         0.00      0.00     13.98     13.74

Average:     atmptf/s  estres/s retrans/s isegerr/s   orsts/s
Average:         0.00      0.00      0.00      0.00      0.00

Les colonnes indiquent:

  • active/s: le nombre de connexions ouvertes par la machine elle même par seconde;
  • passive/s: le nombre de connexions entrantes par seconde;
  • retrans/s: le nombre de retransmission.

Si ce dernier nombre est élevé, cela signifie qu’il y a certainement un problème réseau.

La commande sar possède de nombreuses option pour analyser le réseau:

  • -n EDEV:
  • -n EIP (ou -n EIP6): les erreurs au niveau de la couche ip v4 (ou v6)

Les arguments à l’option -n peuvent se combiner (par exemple: -n EDEV,EIP,EIP6) et surtout n’oublier l’argument 1 pour calculer et afficher les résultats toutes les minutes.

Conclusion

Pour obtenir plus d’informations, la page manuelle (aka man) de chaque commande viendra compléter cet article qui ne fait qu’effleurer le sujet.

Aucun de ces outils ne s’appuient sur BPF, une technologie qui est en passe de devenir le passage obligé pour l’analyse de performance des machines en temps réel.

En attendant les outils basés sur BPF, ceux présentés ici ont l’avantage d’être disponibles sur toutes les machines, y compris celles ayant des noyaux âgés.

Utiliser pihole en ligne de commmande

Un Pihole à usage multiple

Pihole est un logiciel fantastique pour supprimer la publicité, le traçage et bloquer l’accès à des sites indésirables. Il peut aussi être utilisé pour bloquer l’accès à certain site de façon temporaire.

Trou noir dans lequel la publicité est envoyée par Pihole

Par exemple, pour ne pas être tenté d’aller surfer sur Twitter pendant les heures de travail, ou pour empêcher ses enfants de rester trop longtemps sur Youtube, il peut être utile de bloquer l’accès à ces sites uniquement à certaines heures.

L’interface web de pihole est peu pratique pour un tel usage. Il vaut mieux utiliser la ligne de commande et cron. Le programme pihole permet en effet d’ajouter et de supprimer des sites via la ligne de commande.

Le script

Voici donc un mini script pour ajouter ou supprimer des sites à la blacklist.

#!/bin/bash
                            set -e

                            readonly SCRIPTNAME=$(basename $0)
                            readonly PIHOLE=/usr/local/bin/pihole

                            readonly LIST='(^|\.)dailymotion\.com$
                            (^|\.)vimeocdn\.com$
                            (^|\.)vimeo\.com$
                            (^|\.)googlevideo\.com$
                            (^|\.)youtube\.(de|fr|be|com)
                            '

                            action () {
                            local action=$1
                            local del=""
                            if [[ "${action}" == "allow" ]]
                            then
                            del='--delmode'
                            fi
    $PIHOLE --regex $del -q "'"${LIST}"'"
                            }

                            readonly ARG1=$1
                            case "$ARG1" in
    block)
        action block
        ;;
    allow)
        action allow
        ;;
    *)
                            echo "Usage: $SCRIPTNAME {block|allow}" >&2
                            exit 3
        ;;
                            esac

Example de crontab

Pour autoriser uniquement l’accès aux sites entre 17 heure et 18:30 le week-end:

0 17 * * 1,2,3,4,5 /usr/local/bin/dynamic-regex-list.sh allow >  /dev/null 2>&1
30 18 * * 1,2,3,4,5 /usr/local/bin/dynamic-regex-list.sh block >  /dev/null 2>&1

Dans cet exemple, le script a été nommé dynamic-regex-list.sh et placé dans le répertoire /usr/local/bin/.

Construire ses propres images Raspbian

Le problème

Si, comme moi, la première chose que vous faites après le démarrage d’une Raspberry PI sur distribution Raspbian c’est de désinstaller tous les logiciels inutiles, alors j’ai trouvé le logiciel qu’il vous faut: pi-gen. Il s’agit ni plus ni moins du logiciel utilisé pour construire les images Raspbian.

Correctement configuré, il vous permettra de construire une distribution Raspbian aux petits oignons.

Raspberry 3 dans son boitier

La solution

La première étape consiste à récupérer le contenu du dépôt git sur github.

git clone https://github.com/RPi-Distro/pi-gen

Il y a ensuite quelques éléments à modifier:

  1. le fichier Dockerfile afin de contourner un bug qui empêche les machines 64 Bits la construction des images;
  2. le fichier config pour écraser quelques valeurs par défaut;
  3. les «/stages/» qui sont les différentes étapes de constructions de l’image Raspbian.

Utiliser Docker

J’ai simplement remplacé la première ligne afin de construire les images avec des programmes 32 bits:

diff --git a/Dockerfile b/Dockerfile
index 2e53149..d680d7f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM debian:buster
+FROM i386/debian:buster
 
 ENV DEBIAN_FRONTEND noninteractive

Quelques paramètres de base

Le fichier config contient quelques paramètres de base de l’installation:

  • l’utilisateur par défaut et son mot de passe: FIRST_USER_NAME et FIRST_USER_PASS;
  • si ssh est actif au démarrage (il ne l’est pas par défaut): ENABLE_SSH;
  • les paramètres wifi: WPA_ESSID, WPA_PASSWORD et WPA_COUNTRY;
  • l’image à construire doit-elle être compressée ou pas: DEPLOY_ZIP;
  • la timezone, qui est située à Londres par défaut, et donc décalée d’une heure avec Paris et Berlin: TIMEZONE_DEFAULT;
  • la liste des stages à exécuter (cf. ci-après), configurée ainsi chez moi: STAGE_LIST="stage0 stage1 stage2".

La liste complètes des paramètres est lisibles dans le fichier README du projet.

Configuration des stages

Les stages sont les étapes successives de construction de l’image Raspbian. Il y a cinq étapes. L’image est bootable après l’étape 1. L’étape 2 contient la configuration de la timezone, l’installation et la configuration du client ntp, la création du premier utilisateur, etc.

Les stages 3, 4 et 5 installent des logiciels supplémentaires dont X11, un environnement bureautique, etc.

De mon côté j’ai construit le stage 2, mais en le modifiant pour y enlever des paquets que je n’utiliserai pas. Pour cela j’ai modifié les fichiers nommés XX-packages présents dans les sous répertoires du répertoires stage2.

Il est aussi de créer son propre stage sur mesure, et de l’inclure dans le paramètre STAGE_LIST. Là encore le fichier README est votre ami.

Construction des images

Construire l’image Raspbian est ensuite aussi simple que:

./build-docker.sh

L’image sera créée dans le répertoire deploy. Ensuite, il suffit d’un cat /path-to/deploy/yourimage-name.img > /dev/sdX/dev/sdX est votre carte SD, et vous voilà prêt à démarrer votre Raspberry avec votre distribution construite sur mesure!

Notes en vrac de fin d’année

Encore un mini post avec une série de mini trucs. Rien d’extra ordinairement nouveau ici, mais c’est pratique de publier en vrac des notes prises au fil des jours pour pouvoir ensuite les retrouver facilement.

Git

git diff-tree --no-commit-id --name-only -r master..develop pour lister les fichiers modifiés entre deux commits, ou deux branches (ici master et develop).

Ansible

J’ai eu du mal à trouver comment exécuter en local_action une commande du module shell. La solution: utiliser _raw_params comme ci-dessous:

- name: Build frontend
                            local_action:
                            module: shell
                            _raw_params: grunt build
                            args:
                            chdir: "{{ build_root_path }}/src/views/"
                        

Mysql

Quelques commandes en vrac, suffisamment explicites pour ne pas avoir à les commenter, à garder sous le coude:

SHOW FULL PROCESSLIST;
                            SET GLOBAL general_log = 1;
SHOW TABLE LIKE 'prefix%';
                        

Configuration

Je ne suis pas un fanatique de la configuration à outrance des logiciels utilisables dans un terminal. J’essaie généralement de me contenter de la configuration par défaut, afin de ne pas être pris au dépourvu ensuite lorsque je dois utiliser ces mêmes logiciels sur un serveur distant, où ces personnalisations seront absentes.

Dernièrement j’ai fait une exception pour tmux. Dans 90% des cas, lorsque je découpe une fenêtre, je souhaite rester dans le même répertoire duquel j’ai lancé la découpe. En revanche, lorsque j’ouvre une nouvelle fenêtre, je souhaite retourner dans mon HOME, ce qui est le comportement par défault. C’est très pratique sur mon ordinateur personnel, et si je n’ai pas cette fonctionnalité sur un serveur, je peux m’en passer aisément. J’ai donc créé un fichier ~/.tmux.conf avec la configuration suivante:

bind '"' split-window -c "#{pane_current_path}"
bind % split-window -h -c "#{pane_current_path}"
                        

Je n’utilise emacs que sur mon ordinateur personnel. Pour me me connecter à une base de données mariadb (ou mysql) en utilisant un autre port que le port standard, ce qui arrive systématiquement en utilisant des base de données hébergé dans des containers, j’ai dû ajouter la ligne suivante: