CentOS 8 - Problème difficile à dépanner - probablement au niveau du réseau

kortex
2020-05-26T20:00:07+02:00
Linux.redhat, postgresql

Sommaire

Description du problème

Détails techniques

Changements majeurs entre CentOS 7 et CentOS 8

Détails et logs pour le problème rencontré

Ce qui a été testé

Bonsoir,

Je me permets de poster ce message pour solliciter la communauté à propos d'un problème qui nous tient en échec depuis plusieurs semaines mon équipe et moi même.

Description du problème

Nous avons un script développé en Python qui sert à rafraîchir une base de données PostgreSQL de test à partir d'un dump PostgreSQL de production :
- cet outil est développé et maintenu en interne
- il est utilisé depuis deux ans

Le client pg_restore est exécuté depuis une machine X et le serveur PostgreSQL est sur une machine Y : il y a donc communication au travers du réseau et les deux machines sont dans le même réseau (aucun routage entre les deux).

Pour le fonctionnement général du script :
- il exécute des scripts pré-restauration (kill des connexions, etc)
- il exécute un pg_restore : pour être plus précis, le dump étant compressé en bz2 on fait un pbunzip2 dump.bz2 | pg_restore [arguments]
- il exécute des scripts post-restauration (activation de comptes utilisateurs, etc)

Ce script est ordonnancé tous les dimanches grâce à un crontab et était à l'origine exécuté depuis une machine CentOS 7 : nous n'avons jamais eu aucun soucis.

Puis, dans le cadre d'un projet de migration CentOS 7 -> CentOS 8 toujours en cours, nous avons migré ce service sur une nouvelle machine virtuelle CentOS 8 :
- c'est bien une nouvelle machine installée en plus de la machine CentOS 7
- ce n'est donc pas une mise à jour majeure

Et là c'est le drame :
- quand ce script est exécuté depuis CentOS 7 : tout fonctionne bien
- quand ce script est exécuté depuis CentOS 8 : il échoue au bout d'un certain temps et sensiblement toujours au même endroit

Détails techniques

Ces deux machines virtuelles sont hébergées sur une infrastructure VMware 6.7U3 : elles se trouvent sur le même ESXi.

Elles ont la même quantité de mémoire, la même configuration au niveau des disques durs virtuels, le même nombre de vCPU, etc : bref elles sont identiques en tout point d'un point de vue virtualisation.

D'un point de vue système d'exploitation nous sommes en CentOS 7.6 d'un côté et CentOS 8.1 de l'autre.

La CentOS 8 a un kernel 4.18.0-147.5.1.el8_1.x86_64.

Changements majeurs entre CentOS 7 et CentOS 8

Il y en a beaucoup mais ceux sur lesquels nous nous sommes concentrés sont :

le réseau qui est maintenant (CentOS 8) géré par NetworkManager (network-scripts avant)

le pare-feu iptables qui utilise maintenant (CentOS 8) un backend nftables côté kernel

Il y a aussi la GLibc mais pour l'instant nous n'avons pas creusé de ce côté.

Détails et logs pour le problème rencontré

Alors déjà le problème se produit toujours plus ou moins au même endroit mais nous écartons un soucis dans le dump car à chaque restauration le dump utilisé est différent et, comme dit, ça fonctionne depuis une machine CentOS 7.

Ce serait donc plutôt sur le temps que ça se joue : je vérifie demain mais, de mémoire, le pg_restore tombe en échec après 4H30.

Voici un exemple de l'erreur retournée par pg_restore :

pg_restore: creating FK CONSTRAINT "myscheme1.mytable1 fkey_1"
pg_restore: [archiver (db)] Error from TOC entry 31721; 2606 45850 FK CONSTRAINT mytable1 key_1 myowner
pg_restore: [archiver (db)] could not execute query: no connection to the server
Command was: ALTER TABLE ONLY "myscheme1"."mytable1"
ADD CONSTRAINT "fkey_1" FOREIGN KEY ("MyColumn1") REFERENCES "myscheme2"."mytable2"("MyColumn2") DEFERRABLE INITIALLY DEFERRED;
pg_restore: [archiver (db)] could not execute query: no connection to the server
Command was:—Completed on 2020-05-09 06:14:59 CEST

pg_restore: [archiver (db)] could not execute query: no connection to the server
[...]
WARNING: errors ignored on restore: 12568

En utilisant strace, nous avons obtenu ceci :

recvfrom(6, 0x5172353, 5, 0, NULL, NULL) = -1 ECONNRESET (Connection reset by peer)
sendto(6, "\25\3\3\0\32\272\362\307j\311"..., 31, MSG_NOSIGNAL, NULL, 0) = -1 EPIPE (Broken pipe)

Ce qui a été testé

Beaucoup de choses :
- avec et sans SSL entre le client pg_restore et le serveur PostgreSQL
- mise à jour mineure de PostgreSQL côté client uniquement : 10.11 -> 10.12
- on a récupéré des paramètres avec "sysctl -a" depuis la machine CentOS 7 et nous avons injecté cela sur la machine CentOS 8
- mise à jour complète de la machine CentOS 8 avec "dnf update"
- avec et sans le paquet NetworkManager-config-server installé
- avec et sans notre script Python (un coup via le script, un coup via un pg_restore natif)
- avec NetworkManager
- sans NetworkManager mais avec network-scripts (l'ancien système de gestion du réseau de RHEL / CentOS)
- le backend firewall semble être nftables par défaut depuis CentOS 8 : nous avons essayé avec iptables en frontend, firewalld et nft
- avec un "nice -20"
- avec un keep alive dans la session PostgreSQL

Rien de tout ceci n'a donné de résultats.

Par contre, une chose donne un résultat positif : désactiver le pare-feu de la machine cliente CentOS 8 (celle depuis laquelle le pg_restore est exécutée).
Sur cette machine (comme sur la CentOS 7 d'ailleurs), nous avons quelques règles iptables pour n'autoriser que certains flux entrants et on ne filtre rien en sortie (on est en OUTPUT ACCEPT).

Si on désactive le pare-feu sur la machine cliente CentOS 8, nous avons un taux de réussite de 100% de nos restaurations avec pg_restore.

Alors ici ça me chiffonne.

Comme dit tout au début : nous passons par le réseau car les machines clientes et serveur sont distantes.
Par contre nous sommes dans le même réseau : il n'y a pas de routage ou que sais-je entre le client et le serveur (la connexion client -> serveur est donc directe).

Et on ne filtre rien en sortie côté pare-feu (OUTPUT -> ACCEPT).
Ici ça me permets déjà de supposer qu'en l'absence de règles de filtrage, à partir du moment ou le pare-feu est activé, alors les paquets réseaux vont traverser cette couche du kernel qui gère le pare-feu.
Êtes-vous d'accord avec cela ?

Le fait que le problème se produise à peu près (à quelques secondes / minutes près) après le même temps nous fait penser à une sorte de timeout.
Mais ça nous paraît bizarre car ce ne serait pas un timeout d'inactivité (le pg_restore bosse en continue) mais un timeout tout court.
Sauf que l'on ne voit rien nul part qui puisse expliquer cela.

2 tests ont été évoqués mais non réalisés :
- changer d'ESXi : on pourra essayer mais personnellement je n'y crois pas (les machines CentOS 7 et 8 sont sur le même ESXi)
- essayer un kernel plus récent : nous sommes en train de compiler un kernel 5.6 et nous allons essayer avec (probablement demain)

Est-ce quelqu'un aurait-il une idée qui puisse expliquer cela svp ?

Je vous remercie d'avance pour votre aide / vos idées :)