La mise à niveau depuis la Chine échoue en raison de problèmes git

Nous exécutons une instance Discourse sur un serveur Ubuntu 20.04 Aliyun/Alibaba et, comme pour tout ce qui est lié à Git, nous rencontrons des problèmes dus au Grand Pare-feu. La mise à jour manuelle avec launcher rebuild app échoue la plupart du temps en raison d’erreurs GnuTLS (de divers types). Cela ne concerne pas les versions de Git installées sur le serveur, mais est en fait lié à la gestion de la poignée de main à l’intérieur du GFW ; bien sûr, nous ne comprenons pas les détails, mais plusieurs sources discutent de cette question en détail. Par conséquent, compiler Git manuellement avec OpenSSL n’est pas non plus une option.

Parfois, le processus de pull dépasse le noyau, parvient même à cloner le plugin Docker Manager, mais après 2 à 3 pulls de plugins, il y a généralement un délai d’attente ou une autre erreur.

Exemple :

$ ./launcher rebuild app
Assurance que le lanceur est à jour
Récupération de l'origine
Le lanceur est à jour
Arrêt de l'ancien conteneur
+ /usr/bin/docker stop -t 60 app
app
cd /pups && git pull && git checkout v1.0.3 && /pups/bin/pups --stdin
fatal: impossible d'accéder à 'https://github.com/discourse/pups.git/': gnutls_handshake() échoué : La connexion TLS n'a pas été correctement terminée.
76630913bae18d6b45b6b3ecc3ec390c1e69222a493f2ecf424ee06adf9d1002
** ÉCHEC DU BOOTSTRAP ** veuillez faire défiler vers le haut et rechercher les messages d'erreur précédents, il peut y en avoir plus d'un.
./discourse-doctor peut aider à diagnostiquer le problème.

Celui-ci est également assez courant :

fatal: impossible d'accéder à 'https://github.com/discourse/discourse.git/': GnuTLS recv error (-54) : Erreur dans la fonction de pull.

solution potentielle 1
Généralement, lors du clonage depuis GitHub, le faire via SSH au lieu de HTTPS donne de meilleurs résultats ou ne échoue pas, mais en raison de la tâche unique de reconstruction de Discourse, je n’ai aucune idée de quoi configurer et où, afin que le lanceur effectue des pulls via SSH au lieu de HTTPS. Est-il possible de configurer l’instance Discourse pour le faire ?

solution potentielle 2
Comme autre option, j’ai un proxy SOCKS5 disponible pour contourner le GFW pour regarder du contenu pornographique afin d’accéder à des ressources bloquées depuis l’intérieur de la Chine, et je sais que Git peut être configuré pour utiliser le protocole socks://, mais malheureusement, je ne comprends pas comment et où configurer cela dans Discourse, afin que les processus de pull du lanceur Discourse puissent utiliser le proxy. Je voudrais éviter de le faire avec git config --global pour l’utilisateur root, mais plutôt avoir cette information dans une configuration pour les dépôts Discourse. Quelqu’un peut-il m’indiquer comment y parvenir ?

C’est fastidieux, car nous utilisons cette instance Discourse dans notre intranet et actuellement, notre instance est essentiellement morte depuis plus d’un mois, ce qui a bien sûr un impact sévère sur nos opérations.

2 « J'aime »

Est-ce que passer les variables d’environnement du proxy dans app.yml sous la section env permet de résoudre le problème ?
Et voici une solution pour Rubygem sous le GFW :

Avez-vous vu Replace rubygems.org with taobao mirror to resolve network error in China ?

Merci beaucoup. Les gems Ruby ne posent pas de problème, car j’ai intégré le modèle mentionné dans votre publication dans notre app.yml dès le départ, ce qui fonctionne à merveille.

Il s’agit de cloner le dépôt principal ainsi que les dépôts des plugins.

Je dois vérifier les variables d’environnement pour les options Git ; malheureusement, je suis très faible en Docker, et particulièrement avec les fichiers docker-compose. Avez-vous une ressource à me recommander ?

Discourse n’utilise pas docker-compose, à ma connaissance.

Je pense qu’ajouter la commande ci-dessous au hook before_web pourrait le faire fonctionner, comme le fait web.china.template.yml.

git config --global http.proxy socks5://yourproxy:port

Et si vous n’avez plus besoin du proxy après la construction, ajoutez ce qui suit au hook after_web :

git config --global --unset http.proxy

Tous les hooks s’exécutent à l’intérieur du conteneur, donc je ne pense pas que cela posera problème.

1 « J'aime »
2 « J'aime »

Une autre preuve de mon incompétence en matière de Docker. Oui, c’est évident que ce n’est pas un fichier docker-compose. Est-ce qu’on l’appelle « Docker file » ? Ou ce terme fait-il référence au config.json ? Peu importe, votre conseil m’a orienté dans la bonne direction ; il faut simplement appeler le hook before_code au lieu de before_web.

En bref : Configurez un proxy SOCKS5 avec shadowsocks-libev, écoutez sur la machine locale à l’adresse 172.17.0.1 (pas localhost), transmettez les informations du proxy comme indiqué dans votre message, puis reconstruisez l’application.

Je rédigerai un guide détaillé ici, car je suppose qu’il y a d’autres personnes qui traversent cette expérience douloureuse. Pour l’instant, je rencontre encore des problèmes avec les dépôts de composants de thème, donc ma rebuild n’a pas encore abouti, mais j’ai au moins réussi toutes les récupérations de plugins.

Légèrement hors sujet par rapport au thème principal, mais la difficulté que je rencontre n’est pas de pouvoir démarrer l’application, car la configuration existante du redis-server — que nous avons sur une autre machine — ne correspond pas à la réalité de l’état actuel de l’application. Je ne peux donc pas démarrer le conteneur et désactiver les composants de thème via l’interface graphique, qui rencontre un délai d’attente lors de leur clonage.

Merci beaucoup de m’avoir orienté vers votre explication, mais je souhaiterais ajouter quelques remarques, car l’exemple ne correspond pas parfaitement.

  1. Je ne comprends pas cela, désolé ? La commande env me donne beaucoup d’informations, mais aucune n’est liée à mon gitconfig.
  2. Comme je n’ai pas compris le point 1), je n’ai pas pu déterminer quelles variables transmettre. Je n’ai pas non plus ajouté les git flags à la section env dans app.yml, mais je les ai appelés via un hook.
  3. Cela n’était pas nécessaire, car je ne souhaite pas que tout le conteneur passe par le proxy SOCKS, mais uniquement le processus git fetch. Je suppose cependant que ce point concernait davantage le cas d’utilisation original mentionné dans le thread auquel vous avez fait référence.

Mais merci encore, vos conseils m’ont orienté dans la bonne direction. Bravo à l’équipe Discourse ! :ok_hand:

1 « J'aime »

Avez-vous acheté Aliyun et choisi une région située en Chine continentale ?

Aliyun HK/international ne rencontrera pas ce problème.

1 « J'aime »

De plus, vous avez peut-être déjà discuté de ce détail, mais au cas où vous ne l’auriez pas trouvé, voici un script que vous pouvez exécuter pour installer git via openssl :

Mise à jour manuelle sans douleur depuis la Chine

étapes

  1. créer un proxy SOCKS5 hors de Chine
  2. configurer et établir la connexion proxy sur le serveur CN
  3. créer un modèle pour faciliter l’édition
  4. ajouter les paramètres proxy git au modèle
  5. inclure le modèle dans app.yml
  6. reconstruire l’application

1 - SOCKS5 distant

Pour plus de commodité (et leur tarification avantageuse), je recommande de configurer un serveur Digital Ocean, par exemple à Singapour. Utilisez simplement un serveur Ubuntu standard, effectuez toutes les configurations de sécurité de base requises (paires de clés SSH, UFW, etc.), puis installez Shadowsocks :

sur la machine distante
$ sudo apt install shadowsocks-libev

Configurez les paramètres du proxy :

$ cd /etc/shadowsocks-libev

# J'aime conserver les fichiers d'origine
$ sudo cp config.json orig.config.json
$ sudo nano config.json

Portez une attention particulière au délai d’attente (timeout) et à la méthode :

{
    "server":"123.123.123.123", # IP du serveur distant
    "server_port":8400, # à vous de choisir
    "local_port":1080,
    "password":"Swordfish", 
    "timeout":600, # <= essentiel !
    "method":"chacha20-ietf-poly1305"
}

Assurez-vous de vérifier attentivement tous les paramètres dans la configuration systemd (/lib/systemd/system/shadowsocks-libev-local@.service). Activez le service shadowsocks-libev-local@.service, redémarrez, puis vérifiez que le service est en cours d’exécution.

2 - configurer la connexion proxy sur le serveur CN

sur la machine Discourse

$ sudo apt install shadowsocks-libev

Si vous êtes chez Aliyun, recherchez les paramètres du pare-feu dans leur console étrange et vérifiez les paramètres de port respectifs.

Vous n’avez pas besoin de vous embrouiller avec les paramètres systemd sur la machine cliente, mais gardez des fichiers de configuration séparés pour Docker et l’utilisation normale, car vous pourriez vouloir utiliser le proxy SOCKS5 en dehors du contexte de Docker. Dans ce cas, vous voudrez utiliser 127.0.0.1 plutôt que les adresses réseau accessibles par Docker.

$ cd /etc/shadowsocks-libev
$ sudo cp config.json local.json
$ sudo cp config.json docker.json

Adaptez la configuration à quelque chose de similaire à ceci :

$ sudo nano local.json

{
    "server":["123.123.123.123"], # l'IP de la machine distante
    "mode":"tcp_and_udp", # cette annotation diffère en raison de versions différentes de shadowsocks-libev dans ma configuration
    "server_port":8400,
    "local_address":"127.0.0.1",
    "local_port":1080,
    "password":"Swordfish",
    "timeout":600, # <= assurez-vous de cela
    "method":"chacha20-ietf-poly1305"
}

Pour plus de commodité, ajoutons un alias à notre .bashrc :

$ nano ~/.bashrc

# coller
alias dockershadow='ss-local -c /etc/shadowsocks-libev/local.json'

Adaptez l’autre configuration pour permettre à Docker d’utiliser le réseau de la machine hôte :

$ sudo nano docker.json

{
    "server":["123.123.123.123"],
    "mode":"tcp_and_udp",
    "server_port":8400,
    "local_address":"172.17.0.1",
    "local_port":1080,
    "password":"Swordfish",
    "timeout":600,
    "method":"chacha20-ietf-poly1305"
}

Définissez l’alias pour utiliser la configuration spécifique à Docker :

alias dockershadow='ss-local -c /etc/shadowsocks-libev/docker.json'

3 & 4 - créer un modèle pour garder votre app.yml propre

Ceci est tout à fait optionnel et dépend de vos préférences ; je préfère garder le app.yml lisible et court, et maintenir les composants ailleurs. Donnez-lui un nom selon vos goûts, j’ai choisi web.git.template.yml.

$ nano templates/web.git.template.yml
# coller :

hooks:
  before_code:
    - exec:
       cmd:
         - git config --global http.proxy socks5://172.17.0.1:1080
         - git config --global https.proxy socks5://172.17.0.1:1080
         - git config --global https.sslVerify = false 

# optionnel
  after_code:
    - exec:
       cmd:
         - git config --global --unset http.proxy
         - git config --global --unset https.proxy
         - git config --global --unset https.sslVerify

Je l’ai testé avec le hook after_web, mais cela n’a pas fonctionné.

5 - adapter le app.yml

Appelez le modèle dans votre app.yml :

$ cd /<répertoire discourse>
$ sudo nano containers/app.yml


templates:
  - "templates/web.template.yml"
  - "templates/web.china.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml"
  - "templates/web.git.template.yml"

Votre section de modèles ressemble probablement différemment, assurez-vous simplement d’inclure web.china et les modèles web.git-blabla (ou ce que vous avez nommé). Ne exposez pas 1080:1080 dans votre app.yml !

6 - reconstruction

Avant de reconstruire, vérifiez que vos paramètres proxy fonctionnent lors du clonage avec git.

$ git config --global http.proxy socks5://172.17.0.1:1080
$ git config --global https.proxy socks5://172.17.0.1:1080
$ git config --global https.sslVerify = false 

Cela ajoute bien sûr les drapeaux proxy à votre .gitconfig utilisateur dans le répertoire home, alors faites attention à les supprimer après les tests. Sélectionnez un dépôt aléatoire volumineux sur Github avec une multitude de fichiers et vérifiez votre vitesse de clonage. Si votre configuration est correcte, vous devriez pouvoir cloner à environ 12-15 Mo/s, selon votre configuration Aliyun. Si votre vitesse de connexion monte lentement de 200 Ko/s à environ 10 Mo/s, alors vos efforts n’ont pas abouti.

Enfin, reconstruisez :

$ cd /<répertoire discourse>

# lancez le proxy en utilisant l'alias que nous avons défini précédemment
$ dockershadow
$ ./launcher rebuild app

Le processus de reconstruction échouera souvent, alors vous avez besoin de patience (et éventuellement de Baijiu). Plus vous avez peu de plugins définis dans votre app.yml, plus il est probable que votre reconstruction réussisse.

7 - remarques

Je considère toujours cela comme une solution de contournement, pas une procédure prête pour la production, donc peut-être que quelqu’un a une idée pour miroirer le dépôt GitHub en Chine, afin de rendre cela moins douloureux. Et comme nous le savons tous, les mécanismes opaques à l’intérieur du GFW continuent de changer.

Bien sûr, un proxy SOCKS5 n’est qu’une option parmi d’autres, mais j’aime avoir des solutions polyvalentes à portée de main.

Si quelqu’un a une idée pour rendre cette solution de contournement prête pour la production, j’apprécie vos commentaires. Discourse est un logiciel fantastique, mais je suppose que l’une des raisons pour lesquelles il n’est pas largement utilisé en Chine est la complexité des processus d’installation et de maintenance. Tenter de mettre à jour via l’interface graphique m’a donné un taux d’échec de 100 % au cours de l’année dernière, peu importe les paramètres de délai d’attente que j’avais configurés dans mon proxy inverse nGinx.

Traduction chinoise à suivre

7 « J'aime »

Exactement. Étant donné que l’objectif principal de cette instance est de faire partie d’un cadre d’intranet d’entreprise, HK n’est malheureusement pas une option en raison de la latence. De plus, les instances destinées aux clients (à venir) traiteront des utilisateurs de Chine continentale – dès que j’aurai résolu l’authentification Weixin – je dois donc trouver une solution fonctionnelle pour les zones Aliyun de Chine continentale.

Merci beaucoup. J’ai consulté plusieurs guides à ce sujet, mais comme la cause principale du problème n’est pas l’authentification TLS de Git en soi, mais plutôt la vérification de la poignée de main dans les processus d’inspection des paquets du GFW, je me suis abstenu de cette approche. Compiler git avec openssl peut ouvrir les portes à un nouveau monde rempli de difficultés, comme je l’avais lu.

La plupart des composants du thème sont également récupérés depuis GitHub lors de la construction (ou du démarrage du conteneur ?). Il est donc possible qu’il existe un autre hook pour ajouter le proxy Git, ce qui pourrait aider. N’oubliez pas de conserver le proxy si vous souhaitez que l’interface graphique fonctionne correctement. Par ailleurs, redis-server ne semble pas être la cause du problème.

Le redis-server n’était qu’un autre problème ayant ajouté de la complexité à l’échec de la reconstruction. C’était un peu un cercle vicieux : la configuration externe de Redis avait changé, tandis que l’état de l’application avant la reconstruction nécessitait cette configuration Redis spécifique pour démarrer. Elle ne pouvait pas se reconstruire, car la récupération des composants du thème ne fonctionnait pas.
J’ai eu de la chance cependant : après 20 à 20 tentatives de reconstruction, les mises à jour des composants du thème ont enfin été récupérées.

Dans le contexte global de la conception de l’application, il serait agréable d’avoir une documentation expliquant comment reconstruire en « mode sécurisé », c’est-à-dire reconstruire l’application indépendamment des plugins ou des thèmes. Je n’ai pas pu trouver de hook pour traiter les composants du thème, ni comment désactiver (contrairement à la désinstallation) les plugins, ce qui était décevant.

Édit : Waouh, je vois maintenant le lien vers le mode sécurisé. Je ne l’avais pas trouvé auparavant (pas de Google pour nous en Chine, essayez de trouver quoi que ce soit de pertinent avec Bing…). Mon Dieu, cela aurait beaucoup aidé !

Alors, vous avez spécifié un serveur Redis géré comme dans Discourse with DO managed Redis - #3 by Falco, mais la reconstruction a échoué ?

Le problème Redis était secondaire, mais il a considérablement complexifié le problème global lié à Git. Comme vous pouvez le constater dans mon article détaillé ci-dessus, j’ai résolu les problèmes.

Et oui, nous avions connecté un cluster Redis distribué à notre instance Discourse dès le début. Cependant, il n’est pas géré et réside simplement sur d’autres machines.

Une défaillance de la connexion au serveur Redis a empêché le démarrage de l’application, ce qui m’a empêché de désactiver les composants du thème via l’interface graphique.
L’application d’une nouvelle configuration Redis nécessitait une reconstruction de l’application, laquelle n’a pas pu être effectuée en raison d’un échec de la récupération depuis les dépôts GitHub.

https://meta.discourse.org/t/a-fork-of-discourse-docker-repo-for-china

1 « J'aime »

Au cas où quelqu’un rencontrerait des problèmes même avec le paramètre de proxy http ajouté,

GnuTLS recv error (-110): La connexion TLS a été terminée de manière inappropriée.

En plus de la solution originale, ajoutez les propriétés postBuffer ci-dessous à un modèle pour résoudre mon problème. gnutls-bin est requis pour l’installation

hooks:
  before_code:
    - exec:
       cmd:
         - apt-get update -y
         - apt-get install -y gnutls-bin
         - git config --global http.proxy socks5://172.17.0.1:1080
         - git config --global https.proxy socks5://172.17.0.1:1080
         - git config --global https.sslVerify false
         - git config --global http.postBuffer 1048576000

# optionnel
  after_code:
    - exec:
       cmd:
         - git config --global --unset http.proxy
         - git config --global --unset https.proxy
         - git config --global --unset https.sslVerify
         - git config --global --unset http.postBuffer
2 « J'aime »