Aggiornamento dalla Cina fallito a causa di problemi con git

Stiamo eseguendo un’istanza di Discourse su un server Aliyun/Alibaba con Ubuntu 20.04 e, come per tutto ciò che riguarda Git, affrontiamo problemi dovuti alla Grande Muraglia Firewall. L’aggiornamento manuale con launcher rebuild app fallisce nella maggior parte dei casi a causa di errori GnuTLS (di vario tipo). Non è correlato alle versioni di Git installate sul server; è anzi legato alla gestione dell’handshake all’interno del GFW; ovviamente non comprendiamo i dettagli, ma diverse fonti discutono ampiamente questa questione. Di conseguenza, compilare manualmente Git con OpenSSL non è un’opzione percorribile.

A volte il processo di pull supera il nucleo e riesce persino a clonare il plugin Docker Manager, ma dopo 2-3 pull di plugin si verifica solitamente un timeout o un altro errore.

Esempio:

$ ./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.

Questo è anch’esso piuttosto comune:

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

Soluzione potenziale 1
Di solito, quando si clona da GitHub, farlo tramite SSH invece di HTTPS dà risultati migliori o non fallisce, ma a causa dell’attività di rebuild unica di Discourse, non ho idea di dove configurare cosa affinché il launcher effettui il pull tramite SSH invece di HTTPS. È possibile configurare l’istanza di Discourse per farlo?

Soluzione potenziale 2
Come altra opzione, ho a disposizione un proxy SOCKS5 per aggirare il GFW per guardare pornografia e accedere a risorse bloccate dall’interno della Cina, e so che Git può essere configurato per utilizzare il protocollo socks://, ma purtroppo non capisco come e dove impostare la configurazione in Discourse in modo che i processi di pull del launcher di Discourse possano utilizzare il proxy. Vorrei evitare di farlo con git config --global per l’utente root, ma preferirei avere queste informazioni in una configurazione specifica per i repository di Discourse. Qualcuno può indicarmi come ottenere questo risultato?

È complicato, poiché utilizziamo questa istanza di Discourse nella nostra intranet e attualmente la nostra istanza è praticamente ferma da oltre un mese, il che ha ovviamente un impatto grave sulle nostre operazioni.

2 Mi Piace

Passare le variabili d’ambiente del proxy nel file app.yml nella sezione env risolve il problema?
Ecco una soluzione per Rubygem sotto il GFW:

Hai visto Replace rubygems.org with taobao mirror to resolve network error in China

Grazie mille. I gem di Ruby non causano problemi, poiché ho già integrato il modello menzionato nel tuo post nel nostro app.yml fin dall’inizio, e funziona alla perfezione.

Si tratta di clonare il repository principale e i repository dei plugin.

Devo verificare le variabili d’ambiente per i flag di Git; purtroppo non sono molto pratico con Docker e, in particolare, con i file docker-compose. Hai qualche risorsa da indicarmi?

Per quanto ne so, Discourse non utilizza docker-compose.

Credo che aggiungere il seguente comando all’hook before_web possa risolvere il problema, come fa web.china.template.yml:

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

Se non hai più bisogno del proxy dopo la build, aggiungi quanto segue all’hook after_web:

git config --global --unset http.proxy

Tutti gli hook vengono eseguiti all’interno del contenitore, quindi non credo che questo possa essere un problema.

1 Mi Piace
2 Mi Piace

Un’ulteriore prova di quanto sia ignorante riguardo a Docker. Già, ovviamente non è un file docker-compose. Si chiama “Docker file”? O quel termine si riferisce al config.json? Comunque sia, il tuo consiglio mi ha indicato la direzione giusta; il hook dovrebbe semplicemente chiamarsi before_code invece di before_web.

In breve: Configura un proxy SOCKS5 con shadowsocks-libev, ascolta sulla macchina locale su 172.17.0.1 (non localhost), passa le informazioni del proxy come indicato nel tuo messaggio e ricostruisci l’app.

Scriverò una guida dettagliata qui, poiché presumo che ci siano altre persone che stanno passando attraverso questa esperienza dolorosa. Al momento sto ancora affrontando problemi con i repository dei componenti del tema, quindi la mia rebuild non è ancora riuscita, ma ho superato almeno tutti i fetch dei plugin.

Leggermente irrilevante rispetto all’argomento specifico, ma il problema che sto affrontando non è riuscire ad avviare l’app, poiché la configurazione esistente di redis-server - che abbiamo su un’altra macchina - non corrisponde alla realtà dello stato attuale dell’app. Quindi non posso avviare il contenitore e disattivare i componenti del tema tramite l’interfaccia grafica, che vanno in timeout durante il loro cloning.

Grazie mille per avermi indirizzato alla tua spiegazione, ma vorrei aggiungere alcune osservazioni, poiché l’esempio non corrisponde perfettamente.

  1. Non capisco questo, scusa? Il comando env mi fornisce molte informazioni, ma nessuna relativa al mio gitconfig.
  2. Poiché non ho capito il punto 1), non sono riuscito a capire quali variabili passare. Inoltre, non ho aggiunto le git flags alla sezione env in app.yml, ma le ho chiamate tramite un hook.
  3. Questo non era necessario, poiché non voglio che tutto il container passi attraverso i proxy SOCKS, ma solo il processo git fetch. Tuttavia, suppongo che questo punto fosse più specifico per il caso d’uso originale nel thread a cui hai fatto riferimento.

Grazie ancora, il tuo contributo mi ha indicato la direzione giusta. Un pollice in su per il team di Discourse! :ok_hand:

1 Mi Piace

Hai acquistato su Aliyun e scelto una regione nella Cina continentale?

Aliyun di Hong Kong/internazionale non avrà questo problema.

1 Mi Piace

Inoltre, forse hai già discusso questo dettaglio, ma nel caso non l’abbia trovato, ecco uno script che puoi eseguire per installare git tramite openssl

Aggiornamento manuale senza dolore dall’interno della Cina

passaggi

  1. crea un proxy SOCKS5 al di fuori della Cina
  2. configura e imposta la connessione proxy sul server CN
  3. crea un modello per una modifica più semplice
  4. aggiungi le impostazioni proxy git al modello
  5. includi il modello in app.yml
  6. ricostruisci l’app

1 - SOCKS5 remoto

Per facilità d’uso (e per i loro prezzi convenienti) consiglio di impostare un server Digital Ocean, ad esempio a Singapore. Usa semplicemente un server Ubuntu standard, segui tutte le configurazioni di sicurezza di base (coppie di chiavi SSH, UFW, ecc.), quindi installa Shadowsocks:

sulla macchina remota
$ sudo apt install shadowsocks-libev

Configura le impostazioni del proxy:

$ cd /etc/shadowsocks-libev

# Mi piace mantenere i file originali
$ sudo cp config.json orig.config.json
$ sudo nano config.json

Presta molta attenzione a timeout e metodo:

{
    "server":"123.123.123.123", # IP del server remoto
    "server_port":8400, # a tua scelta
    "local_port":1080,
    "password":"Swordfish", 
    "timeout":600, # <= essenziale!
    "method":"chacha20-ietf-poly1305"
}

Assicurati di controllare attentamente tutte le impostazioni nella configurazione systemd (/lib/systemd/system/shadowsocks-libev-local@.service). Abilita il servizio shadowsocks-libev-local@.service, riavvia e verifica che il servizio sia in esecuzione.

2 - imposta la connessione proxy sul server CN

sulla macchina Discourse

$ sudo apt install shadowsocks-libev

Se sei su Aliyun, cerca le impostazioni del firewall nella loro console particolare e controlla le impostazioni della porta corrispondente.

Non devi smanettare con le impostazioni systemd sulla macchina client, ma mantieni file di configurazione separati per Docker e per l’uso regolare, poiché potresti voler utilizzare il proxy SOCKS5 al di fuori del contesto di Docker; in tal caso, vorresti usare 127.0.0.1 invece degli indirizzi di rete accessibili da Docker.

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

adatta la configurazione a qualcosa di simile a questo

$ sudo nano local.json

{
    "server":["123.123.123.123"], # IP della macchina remota
    "mode":"tcp_and_udp", # questa annotazione è diversa a causa delle diverse versioni di shadowsocks-libev nella mia configurazione
    "server_port":8400,
    "local_address":"127.0.0.1",
    "local_port":1080,
    "password":"Swordfish",
    "timeout":600, # <= assicurati di questo
    "method":"chacha20-ietf-poly1305"
}

Per comodità, aggiungiamo un alias al nostro .bashrc:

$ nano ~/.bashrc

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

adatta l’altra configurazione per far passare Docker attraverso la rete della macchina host

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

imposta l’alias per utilizzare la configurazione specifica di Docker:

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

3 & 4 - crea un modello per mantenere il tuo app.yml ordinato

Questo è assolutamente opzionale e dipende dai tuoi gusti; preferisco mantenere app.yml leggibile e breve, mantenendo invece i componenti altrove. Dai un nome a tuo piacimento, ho scelto web.git.template.yml.

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

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 

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

L’ho testato con l’hook after_web, ma non ha funzionato.

5 - adatta app.yml

Chiama il modello nel tuo app.yml:

$ cd /<directory di 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"

La tua sezione template probabilmente è diversa, assicurati solo di includere web.china e i template web.git-blabla (o come li hai chiamati).
Non esporre 1080:1080 nel tuo app.yml!

6 - ricostruzione

Prima di ricostruire, verifica che le impostazioni del proxy funzionino quando cloni con 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 

Questo aggiunge ovviamente i flag proxy al file .gitconfig dell’utente nella directory home, quindi fai attenzione a rimuoverli dopo i test.
Seleziona un repository casuale grande su Github con un sacco di file e controlla la velocità di clonazione. Se la tua configurazione è corretta, dovresti essere in grado di clonare a circa 12-15 MB/s, a seconda della tua configurazione Aliyun. Se la velocità della connessione sale lentamente da 200 KB/s a circa 10 MB/s, allora i tuoi sforzi non sono stati coronati da successo.

infine ricostruisci:

$ cd /<directory di discourse>

# esegui il proxy usando l'alias che abbiamo impostato prima
$ dockershadow
$ ./launcher rebuild app

Il processo di ricostruzione fallirà spesso, quindi hai bisogno di pazienza (e possibilmente Baijiu). Più pochi plugin hai impostato nel tuo app.yml, più è probabile che la ricostruzione abbia successo.

7 - osservazioni

Considero ancora questo come un workaround, non una procedura pronta per la produzione, quindi forse qualcuno ha un’idea su come specchiare il repository GitHub in Cina, per rendere tutto questo meno doloroso. E come sappiamo tutti, i meccanismi opachi all’interno del GFW continuano a cambiare.

Ovviamente un proxy SOCKS5 è solo una delle molte opzioni, ma mi piace avere soluzioni multiuso a portata di mano.

Se qualcuno ha un’idea su come rendere questo workaround pronto per la produzione, apprezzo il tuo contributo. Discourse è un software fantastico, ma suppongo che una delle ragioni per cui non è ampiamente utilizzato in Cina siano i processi di installazione e manutenzione complicati. Tentare di aggiornare tramite GUI mi ha dato un tasso di fallimento del 100% nell’ultimo anno, indipendentemente dalle impostazioni di timeout configurate nel mio reverse proxy nGinx.

La traduzione in cinese seguirà

7 Mi Piace

Esatto. Dato che lo scopo principale di questa istanza è far parte di un framework intranet aziendale, HK purtroppo non è un’opzione a causa della latenza. Inoltre, le istanze (imminenti) rivolte ai clienti interagiranno con utenti della Cina continentale, non appena avrò risolto l’autenticazione Weixin, quindi ho bisogno di una soluzione funzionante per le zone Aliyun della Cina continentale.

Grazie mille. Ho consultato diverse guide a riguardo, ma poiché la causa principale del problema non è l’autenticazione TLS di Git in sé, bensì il controllo dell’handshake nei processi di ispezione dei pacchetti del GFW, ho preferito evitare questo approccio. Compilare git con openssl può aprire le porte a un nuovo mondo pieno di difficoltà, come avevo letto.

La maggior parte dei componenti del tema viene anche scaricata da GitHub durante la compilazione (o l’avvio del contenitore?), quindi potrebbe esserci un altro hook per aggiungere il proxy git che potrebbe aiutare, e non rimuovere il proxy se vuoi che funzioni con l’interfaccia grafica. Inoltre, redis-server non sembra essere la causa del problema.

Il redis-server era solo un altro problema che aveva aggiunto complessità al fallimento della ricostruzione. Era una sorta di loop: la configurazione esterna di redis era cambiata, mentre lo stato dell’app pre-ricostruzione richiedeva quella specifica configurazione redis per avviarsi. Non poteva ricostruire, tuttavia, perché il recupero dei componenti del tema non funzionava.
Ho avuto fortuna, però, dopo 20-20 esecuzioni di ricostruzione e finalmente gli aggiornamenti dei componenti del tema sono stati recuperati.

Nel contesto generale della progettazione dell’app, sarebbe utile avere una documentazione su come ricostruire in “modalità sicura”, ovvero ricostruire l’app indipendentemente da plugin o temi. Non sono riuscito a trovare un hook per elaborare i componenti del tema, né come disattivare (a differenza di disinstallare) i plugin, il che è stato una delusione.

Modifica: Wow, ora vedo il link alla modalità sicura. Non l’avevo trovato prima (nessun Google per noi in Cina, provate a trovare qualsiasi cosa rilevante con Bing…). Dio, questo mi avrebbe aiutato moltissimo!

Quindi hai specificato un server Redis gestito come Discourse with DO managed Redis - #3 by Falco, ma la ricostruzione è fallita?

Il problema di Redis era di importanza secondaria, ma ha aggiunto una complessità significativa al problema generale di Git. Come puoi vedere dal mio post approfondito sopra, ho risolto i problemi.

E sì, fin dall’inizio abbiamo collegato un cluster Redis distribuito al nostro Discourse. Non è gestito, ma è semplicemente su altre macchine.

Un guasto nella connessione al server Redis ha impedito l’avvio dell’applicazione, quindi non sono riuscito a disattivare i componenti del tema tramite l’interfaccia grafica.

L’applicazione di una nuova configurazione di Redis richiedeva una ricostruzione dell’app, che non è stata possibile a causa del fallimento nel recupero dai repository GitHub.

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

1 Mi Piace

Nel caso in cui qualcuno riscontri problemi anche con l’impostazione del proxy http aggiunta,

GnuTLS recv error (-110): La connessione TLS è stata terminata in modo improprio.

Oltre alla soluzione originale, aggiungi le proprietà postBuffer di seguito a un modello per risolvere il mio problema. gnutls-bin è richiesto per l’installazione

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

# opzionale
  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 Mi Piace