Solución de problemas de fallos de arranque en Discourse

Todavía estoy teniendo dificultades con el nuevo proceso de «pre-empaquetado» (pre-bundling). El arranque (bootstrap) falla en mi instancia de prueba y no sé por qué. Cabe destacar que se trata de una configuración con una base de datos PostgreSQL externa. Los contenedores se ejecutan detrás de un HAProxy como acelerador SSL. Aquí solo arranco el contenedor web_only. La versión actual de la compilación (antes del arranque) es 3.5.0.beta8-dev, Commits · discourse/discourse · GitHub

Este es el archivo YAML que está fallando actualmente:

# IMPORTANTE: ESTABLECE UNA CONTRASEÑA SECRETA en Postgres para el usuario Discourse
# TODO: cambia SOME_SECRET en esta plantilla

templates:
  - "templates/web.template.yml"
  ## Descomenta la siguiente línea para habilitar el escucha IPv6
  #- "templates/web.ipv6.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml"
  ## Descomenta estas dos líneas si deseas agregar Lets Encrypt (https)
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

## ¿Qué puertos TCP/IP debe exponer este contenedor?
## Si deseas que Discourse comparta un puerto con otro servidor web como Apache o nginx,
## consulta https://meta.discourse.org/t/17247 para más detalles
expose:
  - "80:80"   # http
  - "443:443" # https

# Usa la clave 'links' para vincular contenedores, es decir, usa la bandera Docker --link.
links:
  - link:
      name: redis
      alias: data

# ¿Algunos argumentos extra para Docker?
# docker_args:

params:
  ## ¿Qué revisión de Git debe usar este contenedor? (por defecto: tests-passed)
  #version: tests-passed

env:
  LC_ALL: en_US.UTF-8
  LANG: en_US.UTF-8
  LANGUAGE: en_US.UTF-8
  DISCOURSE_DEFAULT_LOCALE: de

  ## ¿Cuántas solicitudes web concurrentes se admiten? Depende de la memoria y los núcleos de CPU.
  ## se establecerá automáticamente por el arranque según los CPUs detectados, o puedes sobrescribirlo
  UNICORN_WORKERS: 4

  ## TODO: El nombre de dominio al que responderá esta instancia de Discourse
  DISCOURSE_HOSTNAME: 'forum2.netzwissen.de'

  ## Descomenta si quieres que el contenedor se inicie con el mismo
  ## nombre de host (opción -h) que el especificado arriba (por defecto "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: Lista de correos electrónicos separados por comas que serán administradores y desarrolladores
  ## en el registro inicial, ejemplo 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'admin@netzwissen.de'

  ## TODO: El servidor de correo SMTP utilizado para validar nuevas cuentas y enviar notificaciones
  # SE REQUIEREN: dirección, nombre de usuario y contraseña de SMTP
  # ADVERTENCIA: el carácter '#' en la contraseña de SMTP puede causar problemas.
  DISCOURSE_SMTP_ADDRESS: mail.netzwissen.de
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: discourse@netzwissen.de
  DISCOURSE_SMTP_PASSWORD: [xxxxxxxxxxxxxxxxx}
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (opcional, por defecto true)
  #DISCOURSE_SMTP_DOMAIN: discourse.example.com    # (requerido por algunos proveedores)
  DISCOURSE_NOTIFICATION_EMAIL: discourse@netzwissen.de    # (dirección desde la cual enviar notificaciones)

  ## Si agregaste la plantilla de Lets Encrypt, descomenta abajo para obtener un certificado SSL gratuito
  #LETSENCRYPT_ACCOUNT_EMAIL: me@example.com

## configura la conectividad a las bases de datos
  DISCOURSE_DB_SOCKET: ''
  DISCOURSE_DB_USERNAME: [xxxxxxxxxxx]
  DISCOURSE_DB_NAME: [xxxxxxxxxxxxxxx]
  DISCOURSE_DB_HOST: [xxxxxxxxxxxxxxx]
  DISCOURSE_DB_PASSWORD: [xxxxxxxxxxxxxxx]
  ## caché de redis en el contenedor vecino
  DISCOURSE_REDIS_HOST: redis

  ## La dirección CDN http o https para esta instancia de Discourse (configurada para extraer)
  ## consulta https://meta.discourse.org/t/14857 para más detalles
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com

## El ID de cuenta y la clave de licencia de Maxmind Geolocation para búsquedas de direcciones IP
## consulta https://meta.discourse.org/t/-/173941 para más detalles
  #DISCOURSE_MAXMIND_ACCOUNT_ID: 123456
  #DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456

volumes:
  - volume:
      host: /mnt/data/discourse/shared/web-only
      guest: /shared
  - volume:
      host: /mnt/data/discourse/shared/web-only/log/var-log
      guest: /var/log

## Los plugins van aquí
## consulta https://meta.discourse.org/t/19157 para más detalles
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-shared-edits.git
# algunos plugins se eliminaron, ya que ahora están empaquetados con el núcleo
# https://meta.discourse.org/t/bundling-more-popular-plugins-with-discourse-core/373574
## = ahora empaquetados
##          - git clone https://github.com/discourse/discourse-chat-integration.git
##          - git clone https://github.com/discourse/discourse-openid-connect.git
##          - git clone https://github.com/discourse/discourse-calendar.git
##          - git clone https://github.com/angusmcleod/discourse-events.git
##          - git clone https://github.com/discourse/discourse-data-explorer.git
##          - git clone https://github.com/discourse/discourse-reactions.git
##          - git clone https://github.com/discourse/discourse-chat.git
##          - git clone https://github.com/discourse/discourse-ai.git
##          - git clone https://github.com/discourse/discourse-topic-voting.git
##          - git clone https://github.com/discourse/discourse-post-voting.git
##          - git clone https://github.com/discourse/discourse-user-notes.git
##          - git clone https://github.com/discourse/discourse-solved.git
          - git clone https://github.com/discourse/discourse-docs-card-filter.git
          - git clone https://github.com/discourse/discourse-doc-categories.git
##          - git clone https://github.com/discourse/discourse-assign.git
##          - git clone https://github.com/discourse/discourse-templates.git
          - git clone https://github.com/discourse/discourse-saved-searches.git
          - git clone https://github.com/discourse/discourse-tooltips.git
          - git clone https://github.com/discourse/discourse-category-experts.git
          - git clone https://github.com/discourse/discourse-activity-pub.git
          - git clone https://github.com/discourse/discourse-follow.git
          - git clone https://github.com/nathan-nz/discourse-wikified-posts.git
          - git clone https://github.com/discourse/discourse-whos-online.git
          - git clone https://github.com/merefield/discourse-workflow.git

## Recuerda, esto es sintaxis YAML; solo puedes tener un bloque con un nombre
run:
  - exec: echo "Beginning of custom commands"

  ## Si quieres configurar el inicio de sesión con contraseña para root, descomenta y cambia:
  ## Usa solo una de las siguientes líneas:
  #- exec: /usr/sbin/usermod -p 'PASSWORD_HASH' root
  - exec: /usr/sbin/usermod -p "$(mkpasswd -m sha-256 'xxxxxxxxxxxxxxx')" root

## para operación detrás del equilibrador de carga haproxy con nginx local en el host del contenedor
  - replace:
      filename: /etc/nginx/conf.d/discourse.conf
      from: "types {"
      to: |
        set_real_ip_from 127.0.0.1/24;
        set_real_ip_from 10.0.0.0/24;
        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
        proxy_set_header Host $http_host;
        proxy_set_header X-Request-Start "t=${msec}";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https; # reemplazado $thescheme;
        proxy_set_header X-Real-IP $remote_addr;
        types {

  ## Si quieres autorizar usuarios adicionales, descomenta y cambia:
  #- exec: ssh-import-id username
  #- exec: ssh-import-id anotherusername

  - exec: echo "End of custom commands"
  - exec: awk -F\# '{print $1;}' ~/.ssh/authorized_keys | awk 'BEGIN { print "Authorized SSH keys for this container:"; } NF\u003e=2 {print $NF;}'

Incluso cuando agrego un bloque rm -rf en el YAML:

- rm -rf discourse-chat-integration  
- rm -rf discourse-openid-connect         
- rm -rf discourse-calendar         
- rm -rf discourse-events         
- rm -rf discourse-data-explorer         
- rm -rf discourse-reactions         
- rm -rf discourse-chat         
- rm -rf discourse-ai         
- rm -rf discourse-topic-voting         
- rm -rf discourse-post-voting         
- rm -rf discourse-user-notes         
- rm -rf discourse-solved         
- rm -rf discourse-assign         
- rm -rf discourse-templates

El arranque sigue fallando con:

/usr/local/lib/ruby/gems/3.3.0/gems/pups-1.3.0/lib/pups.rb
/usr/local/bin/pups --stdin

FAILED
--------------------
Pups::ExecError: cd /var/www/discourse && su discourse -c 'bundle exec rake db:migrate' failed with return #<Process::Status: pid 669 exit 1>
Location of failure: /usr/local/lib/ruby/gems/3.3.0/gems/pups-1.3.0/lib/pups/exec_command.rb:131:in `spawn'
exec failed with the params {"cd"=>"$home", "tag"=>"migrate", "hook"=>"db_migrate", "cmd"=>["su discourse -c 'bundle exec rake db:migrate'"]}

Interpretaría esto como un error en la migración de la base de datos en “bundle exec rake db:migrate”. Pero, ¿cuál es la causa raíz aquí? La base de datos discourse2 ya tiene la extensión vector, que era requerida para el plugin discourse-ai (ya instalado previamente):

postgres=# \c discourse2  
psql (15.12 (Ubuntu 15.12-1.pgdg22.04+1), server 13.20 (Ubuntu 13.20-1.pgdg22.04+1))  
You are now connected to database "discourse2" as user "postgres".  
discourse2=# \dx  
                                   List of installed extensions  
  Name   | Version |   Schema   |                            Description                               
----------+---------+------------+-------------------------------------------------------------------  
hstore   | 1.7     | public     | data type for storing sets of (key, value) pairs  
pg_trgm  | 1.5     | public     | text similarity measurement and index searching based on trigrams  
plpgsql  | 1.0     | pg_catalog | PL/pgSQL procedural language  
unaccent | 1.1     | public     | text search dictionary that removes accents  
vector   | 0.8.0   | public     | vector data type and ivfflat and hnsw access methods  
(5 rows)

Más tarde también veo los mensajes de sugerencia del plugin, aunque las líneas “git clone” están todas comentadas en el YAML:

---
HINT: The plugin 'discourse-openid-connect' is now bundled with Discourse and should not be included in your container configuration.
Remove the line 'git clone https://github.com/discourse/discourse-openid-connect' from your containers/web_only.yml file, then try again.
For more information, see https://meta.discourse.org/t/373574
---

Para ser honesto, ahora mismo estoy un poco perdido ::sleepy_face:

¿qué devuelve free -h?

root@docker3a:/var/discourse/containers# free -h
total used free shared buffers cache available
Mem: 3.8Gi 2.0Gi 1.1Gi 3.8Mi 969Mi 1.8Gi

probablemente 4 GB de swap

Lo siento, mi culpa, la salida se cortó

root@docker3a:~# free -h
total used free shared buff/cache available
Mem: 3,8Gi 2,0Gi 1,1Gi 3,8Mi 971Mi 1,8Gi
Swap: 974Mi 0B 974Mi

La VM ya tiene 4 GB de memoria. Añadí 2 GB más y reinicié otro ./launcher rebuild web_only^, resultando en el mismo error. Así que dudo que tengamos un problema de compilación relacionado con el espacio aquí…

Bueno, necesitaba 2 GB de swap con 8 GB de RAM.

Volví a intentarlo con 8 GB de RAM, con el mismo resultado de error. Tenga en cuenta que esta es una máquina virtual basada en kernel (KVM) en un host proxmox (Features - Proxmox Virtual Environment).

Un invitado QEMU/KVM solicita memoria al host a medida que el sistema operativo invitado la necesita, pero no devuelve la memoria al host automáticamente si el sistema operativo invitado ya no la necesita. Si el host necesita memoria, el kernel pedirá a los procesos que devuelvan la RAM no utilizada, por lo que QEMU intentará recuperar algo de memoria, pero depende de que el sistema operativo invitado la libere primero.

Nunca tuve problemas de memoria con la configuración de 4 GB de RAM y 4 CPU, ni siquiera con el plugin discourse-ai. Los problemas de arranque solo aparecieron después de este anuncio de agrupación…

¿Este plugin discourse-openid-connect está en algún lugar de su archivo yml?

Este es un problema de migración, ¿puede desplazarse hacia arriba para encontrar qué falló al migrar?

¿Está este plugin discourse-openid-connect en algún lugar de tu archivo yml?

Este es un problema de migración, ¿puedes desplazarte hacia arriba para encontrar qué falló en la migración?

Hasta ahora tenía discourse-openid-connect en mi lista de plugins. Lo eliminé para la “build post-bundling”. Ahora solo me quedan estos plugins en el archivo yml de la build:

## plugins no incluidos en el bundle
- git clone https://github.com/discourse/docker_manager.git\\`
- git clone https://github.com/discourse/discourse-shared-edits.git`
- git clone https://github.com/discourse/discourse-docs-card-filter.git`
- git clone https://github.com/discourse/discourse-doc-categories.git`
- git clone https://github.com/discourse/discourse-saved-searches.git`
- git clone https://github.com/discourse/discourse-tooltips.git`
- git clone https://github.com/discourse/discourse-category-experts.git`
- git clone https://github.com/discourse/discourse-activity-pub.git`

  • git clone https://github.com/discourse/discourse-follow.git
  • git clone ``https://github.com/nathan-nz/discourse-wikified-posts.git
  • git clone https://github.com/discourse/discourse-whos-online.git
  • git clone \\\https://github.com/merefield/discourse-workflow.git\\

La build parece fallar en ‘bundle exec rake db:migrate’. Pero unas líneas más arriba veo un

Gem::LoadError: no se puede activar multipart-post-2.4.0, ya activado multipart-post-2.4.1 (Gem::LoadError)

[…]
discourse-wikified-posts ya está en la última versión compatible discourse-workflow ya está en la última versión compatible docker_manager ya está en la última versión compatible I,
[2025-07-28T06:34:13.916393 #1] INFO -- : ` cd /var/www/discourse & su discourse -c 'bundle exec rake db:migrate' rake aborted! Gem::LoadError: no se puede activar multipart-post-2.4.0, ya activado multipart-post-2.4.1 (Gem::LoadError) /var/www/discourse/lib/plugin_gem.rb:25:in `load' /var/www/discourse/lib/plugin/instance.rb:861:in `gem' […]

No tengo conocimientos de ruby, pero ¿quizás esto sea un conflicto de paquetes entre multipart-post-2.4.0 y multipart-post-2.4.1 ?

¡Gracias!
Thommie

Y provocó que dos de mis compilaciones se cayeran. Al menos uno de los plugins de CDCK está utilizando una versión antigua.

Este es el sistema funcionando como está diseñado.

Cuando gestionamos dependencias de gemas usando Gemfile y Gemfile.lock, tenemos dependbot escaneando actualizaciones, nos mantenemos actualizados usando nuestros procesos internos.

Como diseñador de plugins, ahora puedes depender de las dependencias de gemas que enviamos en el núcleo.

Esto significa que debes eliminar multipart-post de tu plugin plugin.rb y simplemente requerirlo desde donde lo estés usando.

Una cosa menos de la que deben preocuparse los autores de plugins.

Comentarios útiles, gracias.

@Thomas_Rother He eliminado la dependencia del plugin, inténtalo de nuevo con la compilación.

@merefield @sam :smiley: - ¡¡éxito!! Con el commit 6be7a44 en el plugin de Robert GitHub - merefield/discourse-workflow: A workflow system for Topics that implements a configurable multi-stage process la compilación es exitosa. ¡Gracias por el análisis y la solución!