La actualización desde China falla debido a problemas de git

Estamos ejecutando una instancia de Discourse en un servidor Aliyun/Alibaba con Ubuntu 20.04 y, como ocurre con todo lo relacionado con Git, enfrentamos problemas debido al Gran Cortafuegos. La actualización manual con launcher rebuild app suele fallar por errores de GnuTLS (de varios tipos). No está relacionado con las versiones de Git instaladas en el servidor; de hecho, se debe al manejo del handshake dentro del Gran Cortafuegos; por supuesto, no entendemos los detalles, pero varias fuentes discuten este tema en profundidad. Por lo tanto, compilar Git manualmente con OpenSSL tampoco es una opción.

A veces, el proceso de pull logra pasar el núcleo e incluso logra clonar el plugin Docker Manager, pero después de 2 o 3 extracciones de plugins, suele haber un tiempo de espera agotado u otro error.

Ejemplo:

$ ./launcher rebuild app
Asegurando que el launcher esté actualizado
Obteniendo origen
El launcher está actualizado
Deteniendo el contenedor antiguo
+ /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
** FALLO EN EL INICIO ** por favor, desplace hacia arriba y busque mensajes de error anteriores; puede haber más de uno.
./discourse-doctor puede ayudar a diagnosticar el problema.

Este también es bastante común:

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

Solución potencial 1
Generalmente, al clonar desde GitHub, hacerlo mediante SSH en lugar de HTTPS da mejores resultados o no falla, pero debido a la tarea única de reconstrucción de Discourse, no tengo idea de dónde configurar qué para que el launcher realice las extracciones mediante SSH en lugar de HTTPS. ¿Es posible configurar la instancia de Discourse para hacerlo?

Solución potencial 2
Como otra opción, tengo disponible un proxy SOCKS5 para eludir el Gran Cortafuegos para ver pornografía y acceder a recursos bloqueados desde dentro de China. Sé que Git se puede configurar para usar el protocolo socks://, pero desafortunadamente no entiendo cómo y dónde configurar esto en Discourse para que los procesos de pull del launcher de Discourse puedan usar el proxy. Me gustaría evitar hacerlo con git config --global para el usuario root, sino tener esta información en una configuración para los repositorios de Discourse. ¿Alguien puede indicarme cómo lograr esto?

Es engorroso, ya que usamos esta instancia de Discourse en nuestra intranet y, en este momento, nuestra instancia está básicamente muerta desde hace más de un mes, lo que, por supuesto, tiene un impacto severo en nuestras operaciones.

2 Me gusta

¿Funciona pasar las variables de entorno del proxy en app.yml dentro de la sección env?
Y aquí hay una solución para Rubygem bajo el GFW:

¿Viste Replace rubygems.org with taobao mirror to resolve network error in China?

Muchas gracias. Los gems de Ruby no causan problemas, ya que hemos incorporado la plantilla mencionada en tu publicación en nuestro app.yml desde el principio, y funciona de maravilla.

Se trata de clonar el repositorio principal y los repositorios de los plugins.

Necesito revisar las variables de entorno para las banderas de Git; lamentablemente, no me manejo bien con Docker y, en especial, con los archivos de docker-compose. ¿Podrías indicarme alguna fuente de consulta?

Discourse no utiliza docker-compose, que yo sepa.

Creo que agregar el siguiente comando al hook before_web podría hacerlo funcionar, tal como lo hace web.china.template.yml:

git config --global http.proxy socks5://tuproxy:puerto

Y si ya no necesitas el proxy después de la compilación, agrega lo siguiente al hook after_web:

git config --global --unset http.proxy

Todos los hooks se ejecutan dentro del contenedor, así que no creo que sea un problema.

1 me gusta
2 Me gusta

Otra prueba más de lo ignorante que soy con Docker. Sí, obviamente no es un archivo docker-compose. ¿Se llama “Docker file”? ¿O ese término se refiere al config.json? Da igual, tu consejo me orientó en la dirección correcta; solo que el gancho debería llamarse before_code en lugar de before_web.

En resumen: Configura un proxy SOCKS5 con shadowsocks-libev, escucha en la máquina local en 172.17.0.1 (no en localhost), pasa la información del proxy como indicaste en tu mensaje y reconstruye la aplicación.

Escribiré una guía detallada aquí, ya que asumo que hay más personas pasando por esta experiencia dolorosa. Por ahora, aún tengo problemas con los repositorios de componentes de temas, por lo que mi rebuild aún no ha tenido éxito, pero al menos he superado todas las descargas de complementos.

Aunque es ligeramente irrelevante para el tema principal, el problema que enfrento no es poder iniciar la aplicación, ya que la configuración existente del redis-server (que tenemos en otra máquina) no coincide con la realidad del estado actual de la aplicación. Por eso no puedo iniciar el contenedor y desactivar los componentes de temas mediante la interfaz gráfica, la cual se queda en espera (timeout) al intentar clonarlos.

Muchas gracias por dirigirme a tu explicación, pero me gustaría añadir algunas observaciones, ya que el ejemplo no encaja perfectamente.

  1. No entiendo esto, ¿lo siento? El comando env me proporciona mucha información, pero nada relacionado con mi gitconfig.
  2. Como no entendí el punto 1), no pude determinar qué variables pasar. Tampoco agregué las git flags a la sección env en app.yml, sino que las llamé a través de un hook.
  3. Esto no fue necesario, ya que no quiero que todo el contenedor pase por el proxy SOCKS, sino solo el proceso git fetch, aunque supongo que este punto se refería más al caso de uso original en el hilo al que te referiste.

Pero gracias de nuevo, tu aporte me orientó en la dirección correcta. ¡Pulgar arriba para el equipo de Discourse! :ok_hand:

1 me gusta

¿Compraste Aliyun y seleccionaste una región dentro del continente chino?

Aliyun en HK/internacional no tendrá este problema.

1 me gusta

Además, es posible que ya hayas discutido este detalle, pero por si no lo encontraste, aquí hay un script que puedes ejecutar para instalar git mediante openssl:

Actualización manual sin dolor desde China

pasos

  1. crear un proxy SOCKS5 fuera de China
  2. configurar y establecer la conexión del proxy en el servidor de CN
  3. crear una plantilla para facilitar la edición
  4. agregar la configuración del proxy de git a la plantilla
  5. incluir la plantilla en app.yml
  6. reconstruir la aplicación

1 - SOCKS5 remoto

Para facilitar su uso (y por sus precios amigables), recomiendo configurar un servidor de Digital Ocean, por ejemplo, en Singapur. Simplemente utilice un servidor Ubuntu estándar, complete todas las configuraciones básicas de seguridad (pares de claves SSH, UFW, etc.) y luego instale Shadowsocks:

en la máquina remota
$ sudo apt install shadowsocks-libev

Configure los ajustes del proxy:

$ cd /etc/shadowsocks-libev

# Me gusta mantener los archivos originales
$ sudo cp config.json orig.config.json
$ sudo nano config.json

Preste mucha atención al tiempo de espera (timeout) y al método:

{
    "server":"123.123.123.123", # IP del servidor remoto
    "server_port":8400, # a su elección
    "local_port":1080,
    "password":"Swordfish", 
    "timeout":600, # <= ¡esencial!
    "method":"chacha20-ietf-poly1305"
}

Asegúrese de verificar dos veces toda la configuración en la configuración de systemd (/lib/systemd/system/shadowsocks-libev-local@.service). Habilite el servicio shadowsocks-libev-local@.service, reinicie y verifique que el servicio se esté ejecutando.

2 - configurar la conexión del proxy en el servidor de CN

en la máquina de Discourse

$ sudo apt install shadowsocks-libev

Si está en Aliyun, busque la configuración del firewall en su extraña consola y verifique la configuración del puerto correspondiente.

No necesita perder el tiempo con la configuración de systemd en la máquina cliente, pero mantenga archivos de configuración separados para Docker y uso regular, ya que es posible que desee usar el proxy SOCKS5 fuera del contexto de Docker; en ese caso, querrá usar 127.0.0.1 en lugar de las direcciones de red accesibles por Docker.

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

Adapte la configuración a algo similar a esto:

$ sudo nano local.json

{
    "server":["123.123.123.123"], # la IP de la máquina remota
    "mode":"tcp_and_udp", # esta anotación es diferente debido a las diferentes versiones de shadowsocks-libev en mi configuración
    "server_port":8400,
    "local_address":"127.0.0.1",
    "local_port":1080,
    "password":"Swordfish",
    "timeout":600, # <= asegúrese de esto
    "method":"chacha20-ietf-poly1305"
}

Por comodidad, agreguemos un alias a nuestro .bashrc:

$ nano ~/.bashrc

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

Adapte la otra configuración para permitir que Docker pase por la red de la máquina anfitriona:

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

Establezca el alias para usar la configuración específica de Docker:

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

3 y 4 - crear una plantilla para mantener su app.yml ordenado

Esto es absolutamente opcional y depende de sus preferencias; yo prefiero mantener app.yml legible y breve, y en su lugar mantener los componentes en otro lugar. Déle cualquier nombre según su gusto; yo elegí web.git.template.yml.

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

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 

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

Lo he probado con el hook after_web, pero no funcionó.

5 - adaptar el app.yml

Llame a la plantilla en su app.yml:

$ cd /<directorio de 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"

Su sección de plantillas probablemente se ve diferente, solo asegúrese de incluir web.china y las plantillas web.git-blabla (o como las haya nombrado). No exponga 1080:1080 en su app.yml!

6 - reconstrucción

Antes de reconstruir, verifique que su configuración de proxy funcione al clonar 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 

Esto, por supuesto, agrega las banderas de proxy al archivo .gitconfig del usuario en el directorio home, así que tenga cuidado de eliminar esto después de las pruebas. Seleccione un repositorio grande y aleatorio en GitHub con muchos archivos y verifique su velocidad de clonación. Si su configuración es correcta, debería poder clonar a ~12-15 MB/s, dependiendo de su configuración de Aliyun. Si su velocidad de conexión sube lentamente desde 200 KB/s hasta aproximadamente 10 MB/s, entonces sus esfuerzos no fueron exitosos.

Finalmente, reconstruya:

$ cd /<directorio de discourse>

# ejecute el proxy usando el alias que hemos configurado antes
$ dockershadow
$ ./launcher rebuild app

El proceso de reconstrucción fallará a menudo, por lo que necesita paciencia (y posiblemente Baijiu). Cuantos menos plugins tenga configurados en su app.yml, más probable es que su reconstrucción tenga éxito.

7 - observaciones

Aún considero esto como una solución temporal, no un procedimiento listo para producción, así que quizás alguien tenga una idea sobre cómo reflejar el repositorio de GitHub en China para hacer esto menos doloroso. Y como todos sabemos, los mecanismos opacos dentro del GFW siguen cambiando.

Por supuesto, un proxy SOCKS5 es solo una de muchas opciones, pero me gusta tener soluciones de uso múltiple a mano.

Si alguien tiene una idea sobre cómo hacer que esta solución temporal esté lista para producción, aprecio sus comentarios. Discourse es un software fantástico, pero asumo que una de las razones por las que no se usa ampliamente en China son los engorrosos procesos de instalación y mantenimiento. Intentar actualizar mediante GUI me dio una tasa de falla del 100% durante el último año, sin importar qué configuración de tiempo de espera hubiera configurado en mi proxy inverso de Nginx.

La traducción al chino seguirá pronto

7 Me gusta

Exactamente. Dado que el propósito principal de esta instancia es formar parte de un marco de red interna de la empresa, HK, por desgracia, no es una opción debido a la latencia. Además, las instancias (próximas) que atienden a clientes se encargarán de usuarios del continente chino, tan pronto como resuelva la autenticación de Weixin, por lo que necesito una solución viable para las zonas de Aliyun en el continente.

Muchas gracias. He revisado varias guías al respecto, pero dado que la causa principal del problema no es la autenticación TLS de Git en sí, sino la verificación del handshake en los procesos de inspección de paquetes del GFW, opté por no seguir este enfoque. Compilar git con openssl puede abrir las puertas a un nuevo mundo lleno de problemas, tal como había leído.

La mayoría de los componentes del tema también se extraen de GitHub al construir (o al iniciar el contenedor), por lo que es posible que exista otro hook donde añadir el proxy de git que podría ayudar. No elimines el proxy si quieres que funcione con la interfaz gráfica. Además, parece que redis-server no puede ser la causa.

El redis-server fue solo otro problema que añadió complejidad al fallo en la reconstrucción. Fue como un bucle: la configuración externa de Redis había cambiado, mientras que el estado previo a la reconstrucción de la aplicación necesitaba esa configuración específica de Redis para iniciarse. Sin embargo, no pudo reconstruirse porque la obtención de componentes del tema no funcionaba.
Afortunadamente, después de 20-20 intentos de reconstrucción, finalmente se actualizaron y obtuvieron los componentes del tema.

En el contexto general del diseño de la aplicación, sería útil contar con documentación sobre cómo reconstruir en un “modo seguro”, es decir, reconstruir la aplicación de forma independiente de los complementos o temas. No pude encontrar un hook para procesar los componentes del tema, ni tampoco cómo desactivar (en contraste con desinstalar) los complementos, lo cual fue una pena.

Edición: ¡Vaya! Ahora veo el enlace al modo seguro. No lo había encontrado antes (en China no tenemos Google, así que intentamos encontrar algo relevante con Bing…). ¡Dios mío, eso nos habría ayudado mucho!

¿Entonces especificaste un servidor Redis administrado como Discourse with DO managed Redis - #3 by Falco y falló al reconstruir?

El problema de Redis era de importancia secundaria, pero añadía una complejidad significativa al problema general de Git. Como puedes ver en mi publicación detallada anterior, he resuelto los problemas.

Y sí, desde el principio habíamos conectado un clúster distribuido de Redis a nuestro Discourse. Sin embargo, no está gestionado; solo se encuentra en otras máquinas.

Un fallo en la conexión al servidor de Redis impidió que la aplicación se iniciara, por lo que no pude desactivar los componentes del tema desde la interfaz gráfica.

Aplicar una nueva configuración de Redis requería una reconstrucción de la aplicación, lo cual no fue posible debido al fallo al obtener los repositorios de GitHub.

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

1 me gusta

En caso de que alguien encuentre problemas incluso con la configuración del proxy HTTP agregada,

GnuTLS recv error (-110): La conexión TLS se terminó de forma inadecuada.

Además de la solución original, agregue las propiedades postBuffer a continuación a una plantilla para resolver mi problema. Se requiere gnutls-bin para instalar

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

# opcional
  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 Me gusta