Mise-à-jour Ubuntu Server

Il y a un an, j’écrivais un article sur l’installation de serveur HTTP. J’expliquais qu’à l’époque j’avais utilisé un petit serveur virtuel sous Ubuntu 16.04.

Vous le savez sûrement, le cycle de sortie des versions de la distribution Ubuntu respecte un rythme qui fait qu’une version LTS (Long Term Support, support longue durée, avec des mises-à-jours pendant 5 ans) sort tous les deux ans, et des versions intermédiaires tous les six mois.
La version 16.04 était une version LTS, ce qui est plutôt bien pour un serveur. Mais si mettre à jour un serveur tous les 6 mois est assez contraignant, attendre 2 ans peut être embêtant si on a besoin de packages récents.

Donc comment faire pour mettre à jour une 16.04 en 17.04 ?

(toutes les commandes ci-dessous sont à exécuter en tant que root)
Pour commencer, on va s’assurer que le système est bien à jour :

# apt-get update
# apt-get dist-upgrade

Puis on va redémarrer le serveur (au cas où le kernel a été mis à jour, par exemple) :

# reboot

Une fois le serveur redémarré, on va s’assurer que le package “update-manager-core” est installé (il devrait l’être, mais on ne sait jamais) :

# apt-get install update-manager-core

On va ensuite éditer le fichier /etc/update-manager/release-upgrades car il contient une directive importante pour la mise-à-jour du système ; par défaut, l’option “Prompt” vaut “lts”, ce qui fait qu’on ne pourra mettre à jour notre système 16.04 que vers une prochaine LTS (ce sera la 18.04, qui sortira en avril 2018). Si on veut que le système se mette à jour vers n’importe quelle version (LTS ou intermédiaire), il faut que le fichier contienne la ligne suivante :

Prompt=normal

Avant de lancer la mise-à-jour, il faut savoir qu’en cas de problème les choses peuvent être un peu compliquées dans le cas où on met un serveur à jour à distance. Le programme de mise à jour va démarrer un second serveur SSH sur le port 1022 ; il faut donc d’abord ouvrir ce port dans votre firewall, ou bien l’ouvrir temporairement avec la commande :

# iptables -A INPUT -p tcp --dport 1022 -j ACCEPT

Je vous recommande aussi de lancer la mise-à-jour dans un terminal géré par le programme “screen” ; il sera ainsi possible de récupérer votre terminal même si vous vous faites déconnecter (à la condition de pouvoir rétablir une connexion SSH et que la machine n’a pas redémarré entretemps). Commencez par l’installer si nécessaire, puis exécutez-le :

# apt-get install screen
# screen

(il faut appuyer une deuxième fois sur la touche Entrée pour entrer dans le terminal)
On peut ensuite lancer la mise-à-jour :

# do-release-upgrade

Au fur et à mesure que les paquets logiciels seront mis à jour, on va vous demander si vous souhaitez mettre à jour les fichiers de configuration ou si vous souhaitez garder votre version locale. À vous de voir ce que vous préférez, mais si un logiciel change de version majeure, vos fichiers de configuration risquent de ne plus être compatibles ; il vaut peut-être mieux faire d’abord une copie de vos fichiers, d’accepter de les mettre à jour, puis de regarder les différences une à une.

Enfin, sachez que − pour cet exemple précis − la mise-à-jour se fait théoriquement de la version 16.04 vers la version 16.10 ; il faut donc renouveler l’opération une seconde fois. Toutefois, lors de mes tests sur plusieurs machines, une seule opération de mise-à-jour m’a amené directement en version 17.04.
Si vous n’êtes pas sûr, vous pouvez connaître la version installée de la manière suivante :

# more /etc/lsb-release

Autre méthode, qui fonctionne sur un grand nombre de distributions (toutes celles qui sont conformes aux spécifications de la Linux Standard Base) :

# lsb_release -a

 

Bug des sessions PHP sous Debian/Ubuntu

Je suis tombé sur un truc un peu étrange récemment, sur mes serveurs de production.

Au moment de faire une mise en production, notre programme de déploiement a remonté une erreur inhabituelle. En regardant de plus près, je me suis rendu compte qu’il n’avait pas pu écrire sur le disque les fichiers correspondant aux nouvelles versions des projets. Pourtant, il restait encore énormément de place sur le disque dur (à peine 15% d’espace disque utilisé).
Le soucis venait du fait que tous les inodes du système de fichiers avaient été consommés. Wow, la vache. Avoir bouffé tous les inodes, alors que 85% d’espace disque est encore libre, ça voulait dire qu’un nombre incroyable de minuscules fichiers avait été créé.

Le premier réflexe est de se demander quel bout de code on a bien pu écrire, qui génère cette merde. Et pour analyser l’origine du problème, la première étape est déjà d’essayer de savoir dans quel répertoire ces fichiers ont été créés. Donc on a fait un script pour compter le nombre de fichiers dans chaque répertoire. La fête, quoi.

On a découvert qu’il y avait plus de 16 millions de fichiers dans le répertoire /var/lib/php5. Attendez… qu’est-ce qui peut bien avoir créé autant de fichiers dans ce répertoire ?
Pas besoin de chercher très longtemps pour s’apercevoir qu’il s’agit de l’endroit où PHP écrit les fichiers servant à stocker les sessions utilisateurs.

Mais normalement, les sessions sont effacées au bout d’un certain temps. Tout le monde sait ça. C’est d’autant plus étonnant que notre framework Temma utilise son propre système de sessions (stockées dans Memcache), et que donc nous ne devrions pas créer ces fichiers car les sessions PHP sont contournées.
J’ai commencé par essayer de comprendre pourquoi les fichiers de sessions n’ont pas été effacés après un certain délai. Ce comportement est géré dans le fichier de configuration de PHP, par les directives session.gc_maxlifetime, session.gc_probability et session.gc_divisor. Pour faire simple, une installation standard sous Ubuntu (et, semble-t-il, aussi sous Debian) prévoit que les sessions aient une durée de 24 minutes.

Par contre, il existe deux manières différentes de faire le ménage dans les sessions.
La première est de configurer PHP pour qu’à chaque requête entrante, il se donne une chance de faire le ménage parmi les sessions ouvertes. Cela est calculé avec les paramètres que j’ai cités juste avant. Par exemple, le ménage dans les sessions pourra être fait toutes les mille requêtes (ce qui veut dire qu’une requête sur mille sera ralentie par ce traitement supplémentaire).
La seconde manière est de faire tourner régulièrement un script, en le lançant par crontab, dont le rôle est de faire le ménage pour effacer les fichiers correspondant aux sessions qui sont arrivées à expiration.

Sur Ubuntu (et donc sûrement sur Debian aussi), c’est la seconde solution qui a été choisie. Mais le truc complètement incompréhensible, c’est que le script lancé par crontab est commenté !
Pour être exact, il s’agit du fichier /etc/cron.d/php5. Il ne contient qu’une seule ligne, dont la commande est censée s’exécuter toutes les demi-heures. Mais comme je le disais, cette ligne est commentée. Donc le ménage n’est jamais fait.

Dans notre cas, le truc particulièrement con, c’est que les sessions PHP n’auraient pas dû être utilisées. Comme je l’ai dit plus haut, notre framework possède son propre système de session. Le hic, c’est que lorsque j’ai ouvert ce framework sous licence libre, j’ai ajouté une petite évolution : C’est bien beau de gérer nos sessions dans Memcache, mais cette solution ne peut pas satisfaire tout le monde. Donc il possède un fallback qui l’amène à utiliser les sessions PHP si les sessions n’ont pas explicitement été configurées pour utiliser le cache.

Partant de là, le code qui s’occupe de nos médias (principalement l’affichage des images sur nos sites) a connu un petit bug de configuration, qui activait les sessions. Cela ne sert à rien, on est d’accord ; il n’y a pas besoin de session utilisateur pour servir une image.
Mais comme il n’était pas prévu que les sessions soient activées, elles n’étaient évidemment pas configurées pour être stockées en cache. Donc elles se sont retrouvées à passer par le mécanisme des sessions PHP.
C’est ainsi que nous nous sommes retrouvés à écrire des fichiers sur le disque dur pour chaque visiteur de passage sur nos sites…

Alors si jamais vous vous retrouvez à cours d’inode, commencez par regarder du côté des sessions, on ne sait jamais.