Upgrade aus China schlägt wegen Git-Problemen fehl

Wir betreiben eine Discourse-Instanz auf einem Aliyun/Alibaba-Server mit Ubuntu 20.04. Wie bei allem, was mit Git zu tun hat, stoßen wir aufgrund der Großen Firewall auf Probleme. Das manuelle Upgraden mit launcher rebuild app scheitert in den meisten Fällen aufgrund von GnuTLS-Fehlern (verschiedene Arten). Dies hängt nicht von den auf dem Server installierten Git-Versionen ab, sondern tatsächlich von der Handshake-Verarbeitung innerhalb der GFW; natürlich verstehen wir die Details nicht, aber mehrere Quellen diskutieren dieses Problem ausführlich. Daher ist das manuelle Kompilieren von Git mit OpenSSL ebenfalls keine Option.

Manchmal kommt der Pull-Prozess zwar über den Kern hinaus und schafft es sogar, das Docker Manager-Plugin zu klonen, aber nach 2–3 Plugin-Pulls tritt in der Regel ein Timeout oder ein anderer Fehler auf.

Beispiel:

$ ./launcher rebuild app
Ensuring launcher is up to date
Fetching origin
Launcher is up-to-date
Stopping old container
+ /usr/bin/docker stop -t 60 app
app
cd /pups && git pull && git checkout v1.0.3 && /pups/bin/pups --stdin
fatal: unable to access 'https://github.com/discourse/pups.git/': gnutls_handshake() failed: The TLS connection was non-properly terminated.
76630913bae18d6b45b6b3ecc3ec390c1e69222a493f2ecf424ee06adf9d1002
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one.
./discourse-doctor may help diagnose the problem.

Dieser Fehler ist ebenfalls recht häufig:

fatal: unable to access 'https://github.com/discourse/discourse.git/': GnuTLS recv error (-54): Error in the pull function.

Mögliche Lösung 1
Beim Klonen von GitHub liefert die Nutzung von SSH anstelle von HTTPS normalerweise bessere Ergebnisse oder führt nicht zum Fehler. Aufgrund der einzigartigen Rebuild-Aufgabe von Discourse habe ich jedoch keine Ahnung, wo und was zu konfigurieren ist, damit der Launcher über SSH statt über HTTPS zieht. Ist es möglich, die Discourse-Instanz so einzurichten?

Mögliche Lösung 2
Als weitere Option steht mir ein SOCKS5-Proxy zur Verfügung, um die GFW zu umgehen zum Anschauen von Pornos und auf blockierte Ressourcen von innerhalb Chinas zuzugreifen. Ich weiß, dass Git so konfiguriert werden kann, dass es das socks://-Protokoll verwendet, aber leider verstehe ich nicht, wie und wo die Konfiguration in Discourse einzurichten ist, damit die Pull-Prozesse des Discourse-Launchers den Proxy nutzen können. Ich möchte dies nicht mit git config --global für den Root-Benutzer lösen, sondern diese Informationen lieber in einer Konfiguration für die Discourse-Repositories hinterlegen. Kann mir jemand zeigen, wie das geht?

Es ist mühsam, da wir diese Discourse-Instanz in unserem Intranet nutzen und unsere Instanz derzeit seit über einem Monat im Grunde tot ist, was natürlich schwerwiegende Auswirkungen auf unsere Abläufe hat.

2 „Gefällt mir“

Bringt es etwas, die Proxy-Umgebungsvariablen im app.yml unter dem Abschnitt env zu setzen?
Und hier ist eine Lösung für Rubygem unter der GFW:

Hast du gesehen: Replace rubygems.org with taobao mirror to resolve network error in China

Vielen Dank. Die Ruby-Gems verursachen keine Probleme, da ich die in Ihrem Beitrag erwähnte Vorlage von Anfang an in unsere app.yml integriert habe, was hervorragend funktioniert.

Es geht um das Klonen des Haupt-Repositories und der Plugin-Repositories.

Ich muss die Umgebungsvariablen für Git-Flags prüfen. Leider bin ich bei Docker und insbesondere bei docker-compose-Dateien nicht so bewandert. Können Sie mir eine Quelle empfehlen?

Discourse verwendet meines Wissens nach kein docker-compose.

Ich glaube, wenn Sie den folgenden Befehl zum Hook before_web hinzufügen, funktioniert es, ähnlich wie in web.china.template.yml:

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

Und falls Sie nach dem Build keinen Proxy mehr benötigen, fügen Sie Folgendes zum Hook after_web hinzu:

git config --global --unset http.proxy

Alle Hooks laufen innerhalb des Containers, daher sehe ich hier kein Problem.

1 „Gefällt mir“
2 „Gefällt mir“

Ein weiterer Beweis dafür, wie ahnungslos ich bezüglich Docker bin. Ja, es ist offensichtlich keine docker-compose-Datei. Heißt das dann „Dockerfile“? Oder bezieht sich dieser Begriff auf die config.json? Egal, dein Hinweis hat mich in die richtige Richtung gelenkt; der Hook sollte lediglich before_code statt before_web heißen.

Kurz gesagt: Richte einen SOCKS5-Proxy mit shadowsocks-libev ein, der auf dem lokalen Rechner an der Adresse 172.17.0.1 (nicht localhost) lauscht, gib die Proxy-Informationen wie in deiner Nachricht übermittelt weiter und starte den Neuaufbau der App.

Ich werde hier eine detaillierte Anleitung verfassen, da ich davon ausgehe, dass noch mehr Menschen diese schmerzhafte Erfahrung durchmachen. Momentan habe ich zwar noch Probleme mit den Theme-Komponenten-Repositories, sodass mein rebuild noch nicht erfolgreich war, aber ich habe zumindest alle Plugin-Downloads erfolgreich abgeschlossen.

Etwas irrelevant für das eigentliche Thema, aber das Problem, mit dem ich kämpfe, ist nicht die Startfähigkeit der App, sondern dass die vorhandene redis-server-Konfiguration – die wir auf einem anderen Rechner haben – nicht mit dem tatsächlichen Status der aktuellen App übereinstimmt. Daher kann ich den Container nicht starten und die Theme-Komponenten über die GUI deaktivieren, da diese beim Klonen ein Timeout erhalten.

Vielen Dank, dass Sie mich auf Ihre Erklärung hingewiesen haben. Ich möchte jedoch einige Anmerkungen hinzufügen, da das Beispiel nicht ganz passt.

  1. Ich verstehe das nicht, sorry? Der Befehl env gibt mir viele Informationen, aber keine im Zusammenhang mit meiner gitconfig.
  2. Da ich Punkt 1 nicht verstehe, konnte ich nicht herausfinden, welche Variablen weitergegeben werden müssen. Ich habe auch keine git flags zum env-Abschnitt in app.yml hinzugefügt, sondern sie über einen hook aufgerufen.
  3. Das war nicht notwendig, da ich nicht den gesamten Container über den Socks-Proxy laufen lassen möchte, sondern nur den git fetch-Prozess. Ich nehme jedoch an, dieser Punkt bezog sich eher auf den ursprünglichen Anwendungsfall in dem Thread, auf den Sie verwiesen haben.

Aber noch einmal vielen Dank, Ihr Input hat mich in die richtige Richtung gelenkt. Daumen hoch für das Discourse-Team! :ok_hand:

1 „Gefällt mir“

Haben Sie Aliyun gekauft und eine Region im chinesischen Festland ausgewählt?

Aliyun in HK/International hat dieses Problem nicht.

1 „Gefällt mir“

Vielleicht haben Sie dies bereits diskutiert, aber falls Sie es noch nicht gefunden haben, hier ist ein Skript, das Sie ausführen können, um Git über OpenSSL zu installieren:

Schmerzloses manuelles Upgrade innerhalb Chinas

Schritte

  1. SOCKS5-Proxy außerhalb Chinas einrichten
  2. Proxy-Verbindung auf dem CN-Server konfigurieren
  3. Eine Vorlage für einfachere Bearbeitung erstellen
  4. Git-Proxy-Einstellungen zur Vorlage hinzufügen
  5. Vorlage in app.yml einbinden
  6. App neu erstellen

1 - Remote-SOCKS5

Für die Benutzerfreundlichkeit (und ihre freundliche Preisgestaltung) empfehle ich die Einrichtung eines Digital-Ocean-Servers, z. B. in Singapur. Verwenden Sie einfach einen Standard-Ubuntu-Server, führen Sie alle grundlegenden Sicherheitskonfigurationen durch (SSH-Schlüsselpaare, UFW usw.) und installieren Sie dann Shadowsocks:

auf dem Remote-Computer
$ sudo apt install shadowsocks-libev

Konfigurieren Sie die Proxy-Einstellungen:

$ cd /etc/shadowsocks-libev

# Ich bewahre die Originaldateien gerne auf
$ sudo cp config.json orig.config.json
$ sudo nano config.json

Achten Sie besonders auf Timeout und Methode:

{
    "server":"123.123.123.123", # IP des Remote-Servers
    "server_port":8400, # Ihnen überlassen
    "local_port":1080,
    "password":"Swordfish", 
    "timeout":600, # <= unbedingt erforderlich!
    "method":"chacha20-ietf-poly1305"
}

Stellen Sie sicher, dass Sie alle Einstellungen in der systemd-Konfiguration (/lib/systemd/system/shadowsocks-libev-local@.service) doppelt überprüfen. Aktivieren Sie den shadowsocks-libev-local@.service, starten Sie den Computer neu und prüfen Sie, ob der Dienst läuft.

2 - Proxy-Verbindung auf dem CN-Server einrichten

auf der Discourse-Maschine

$ sudo apt install shadowsocks-libev

Wenn Sie bei Aliyun sind, suchen Sie in deren seltsamer Konsole nach den Firewall-Einstellungen und prüfen Sie die jeweiligen Port-Einstellungen.

Sie müssen nicht mit den systemd-Einstellungen auf dem Client-Computer herumprobieren, aber halten Sie separate Konfigurationsdateien für Docker und den regulären Gebrauch bereit, da Sie den SOCKS5-Proxy möglicherweise außerhalb des Docker-Kontexts verwenden möchten. In diesem Fall würden Sie 127.0.0.1 anstelle der für Docker zugänglichen Netzwerkadressen verwenden.

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

Passen Sie die Konfiguration an etwas Ähnliches an:

$ sudo nano local.json

{
    "server":["123.123.123.123"], # IP der Remote-Maschine
    "mode":"tcp_and_udp", # Diese Anmerkung unterscheidet sich aufgrund verschiedener shadowsocks-libev-Versionen in meiner Einrichtung
    "server_port":8400,
    "local_address":"127.0.0.1",
    "local_port":1080,
    "password":"Swordfish",
    "timeout":600, # <= darauf achten
    "method":"chacha20-ietf-poly1305"
}

Aus Bequemlichkeit fügen wir einen Alias zu unserer .bashrc hinzu:

$ nano ~/.bashrc

# einfügen
alias dockershadow='ss-local -c /etc/shadowsocks-libev/local.json'

Passen Sie die andere Konfiguration an, damit Docker über das Netzwerk der Host-Maschine läuft:

$ 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"
}

Setzen Sie den Alias für die Verwendung der Docker-spezifischen Konfiguration:

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

3 & 4 - Vorlage erstellen, um Ihre app.yml übersichtlich zu halten

Dies ist absolut optional und hängt von Ihrem Geschmack ab; ich bevorzuge es, die app.yml lesbar und kurz zu halten und stattdessen Komponenten an anderer Stelle zu verwalten. Geben Sie ihr einen beliebigen Namen nach Ihrem Geschmack, ich habe web.git.template.yml gewählt.

$ nano templates/web.git.template.yml
# einfügen:

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 

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

Ich habe es mit dem Hook after_web getestet, aber das hat nicht funktioniert.

5 - app.yml anpassen

Rufen Sie die Vorlage in Ihrer app.yml auf:

$ cd /<discourse dir>
$ 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"

Ihr Vorlagen-Abschnitt sieht höchstwahrscheinlich anders aus, stellen Sie einfach sicher, dass Sie web.china und die web.git-blabla (oder wie auch immer Sie sie genannt haben) Vorlagen einfügen.
Nicht 1080:1080 in Ihrer app.yml exponieren!

6 - Neuerstellung

Bevor Sie neu erstellen, überprüfen Sie, ob Ihre Proxy-Einstellungen beim Klonen mit Git funktionieren.

$ 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 

Dies fügt natürlich die Proxy-Flags Ihrer .gitconfig im Home-Verzeichnis des Benutzers hinzu, also achten Sie darauf, dies nach dem Testen zu entfernen.
Wählen Sie ein zufälliges großes Repository auf GitHub mit vielen Dateien und überprüfen Sie Ihre Klon-Geschwindigkeit. Wenn Ihre Konfiguration korrekt ist, sollten Sie mit etwa 12-15 MB/s klonen können, abhängig von Ihrer Aliyun-Einrichtung. Wenn Ihre Verbindungsgeschwindigkeit langsam von 200 KB/s auf etwa 10 MB/s ansteigt, waren Ihre Bemühungen nicht erfolgreich.

Schließlich neu erstellen:

$ cd /<discourse directory>

# Proxy ausführen, indem wir den zuvor gesetzten Alias verwenden
$ dockershadow
$ ./launcher rebuild app

Der Neuerstellungsprozess wird häufig fehlschlagen, daher benötigen Sie Geduld (und möglicherweise Baijiu). Je weniger Plugins in Ihrer app.yml eingestellt sind, desto wahrscheinlicher ist es, dass Ihre Neuerstellung erfolgreich ist.

7 - Anmerkungen

Ich betrachte dies immer noch als Workaround, nicht als produktionsreifes Verfahren, also hat vielleicht jemand eine Idee, wie man das GitHub-Repository in China spiegeln kann, um dies weniger schmerzhaft zu machen. Und wie wir alle wissen, ändern sich die intransparenten Mechanismen innerhalb der GFW ständig.

Natürlich ist ein SOCKS5-Proxy nur eine von vielen Optionen, aber ich mag es, Mehrzwecklösungen zur Hand zu haben.

Wenn jemand eine Idee hat, wie man diesen Workaround produktionsreif macht, schätze ich Ihre Eingabe. Discourse ist fantastische Software, aber ich nehme an, einer der Gründe, warum sie in China nicht weit verbreitet ist, sind die umständlichen Installations- und Wartungsprozesse. Der Versuch, über die GUI zu aktualisieren, ergab im letzten Jahr eine 100%ige Ausfallrate, egal welche Timeout-Einstellungen ich in meinem Nginx-Reverse-Proxy konfiguriert hatte.

Chinesische Übersetzung folgt

7 „Gefällt mir“

Genau. Da der Hauptzweck dieser Instanz darin besteht, Teil eines firmeninternen Netzwerks zu sein, ist HK leider aufgrund der Latenz keine Option. Außerdem werden die (bevorstehenden) clientseitigen Instanzen Nutzer aus dem chinesischen Festland bedienen – sobald ich die Weixin-Authentifizierung geklärt habe. Daher benötige ich eine funktionierende Lösung für die Aliyun-Zonen auf dem chinesischen Festland.

Vielen Dank. Ich habe mehrere Anleitungen dazu geprüft, aber da die Hauptursache des Problems nicht die TLS-Authentifizierung von Git an sich ist, sondern die Handshake-Prüfung in den Paketinspektionsprozessen der GFW, habe ich mich von diesem Ansatz distanziert. Die Kompilierung von git mit openssl kann Türen zu einer neuen Welt voller Schmerzen öffnen, wie ich gelesen habe.

Die meisten Theme-Komponenten werden auch beim Erstellen (oder beim Start des Containers?) von GitHub gezogen. Möglicherweise gibt es einen weiteren Hook, um den Git-Proxy hinzuzufügen, was helfen könnte. Entfernen Sie den Proxy nicht, wenn er mit der GUI funktionieren soll. Und redis-server scheint dies nicht verursachen zu können.

Der redis-server war nur ein weiteres Problem, das die Wiederherstellung zusätzlich erschwert hat. Es war so etwas wie ein Teufelskreis: Die externe Redis-Konfiguration hatte sich geändert, während der Zustand der App vor dem Neuaufbau genau diese spezifische Redis-Konfiguration benötigte, um zu starten. Ein Neuaufbau war jedoch nicht möglich, da das Abrufen der Theme-Komponenten nicht funktionierte.
Ich hatte jedoch Glück: Nach 20 bis 20 Neuaufbau-Versuchen wurden die Theme-Komponenten-Updates schließlich heruntergeladen.

Im Gesamtkontext des App-Designs wäre es schön, eine Dokumentation zu haben, wie man im „Safe Mode

Also hast du einen verwalteten Redis-Server wie in Discourse with DO managed Redis - #3 by Falco angegeben, und der Neuaufbau ist fehlgeschlagen?

Das Redis-Problem war von untergeordneter Bedeutung, hat jedoch die Komplexität des gesamten Git-Problems erheblich erhöht. Wie Sie meinem ausführlichen Beitrag oben entnehmen können, habe ich die Probleme gelöst.

Und ja, wir haben von Anfang an einen verteilten Redis-Cluster mit unserem Discourse verbunden. Dieser wird jedoch nicht verwaltet, sondern läuft einfach auf anderen Maschinen.

Ein Verbindungsfehler zum Redis-Server hat verhindert, dass die Anwendung gestartet werden konnte, sodass ich die Theme-Komponenten nicht über die GUI deaktivieren konnte.
Das Anwenden einer neuen Redis-Konfiguration erforderte einen Neuaufbau der Anwendung, der aufgrund eines Fehlers beim Abrufen aus den GitHub-Repositories nicht durchgeführt werden konnte.

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

1 „Gefällt mir“

Falls jemand Probleme hat, auch wenn die HTTP-Proxy-Einstellung hinzugefügt wurde,

GnuTLS recv error (-110): Die TLS-Verbindung wurde nicht ordnungsgemäß beendet.

Zusätzlich zur ursprünglichen Lösung fügen Sie die postBuffer-Eigenschaften unterhalb einer Vorlage hinzu, um mein Problem zu lösen. gnutls-bin muss installiert werden

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

# optional
  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 „Gefällt mir“