¿Es este proceso seguro? Puedo ejecutar una configuración de múltiples contenedores sin problemas en un entorno de desarrollo, pero si empiezo a usarlo en un entorno de producción, mientras los usuarios acceden al contenedor antiguo y el nuevo contenedor inicia y ejecuta el paso de migración de la base de datos, las solicitudes al contenedor antiguo seguirán utilizando la lógica de backend antigua y guardarán los datos según lo definido en la versión anterior, incluso después de que termine el paso de migración de la base de datos (pero antes de que finalice todo el proceso de inicio).
Aunque sé que esto no es un problema relacionado con Discourse en sí (un entorno con varias réplicas podría tener este problema si una réplica se actualiza antes que la otra, a menos que detengas todas antes de actualizar, pero esto probablemente no será el caso si quieres alta disponibilidad), ¿el proceso que describes sigue siendo seguro, de manera general?
Una cosa en la que puedo pensar es asegurarme de mantener siempre Discourse actualizado para tener la migración de base de datos mínima entre reconstrucciones. Pero en cualquier caso, esto todavía no es ideal, y podrían surgir problemas incluso en este caso.
La configuración de múltiples contenedores parece ser uno de los enfoques recomendados (aunque no es el estándar con solo 1 contenedor), así que creo que debería ser seguro y solo estoy pensando demasiado.
¿Sabes si funciona bien en sitios de producción (haciendo el inicio en un contenedor incluso mientras otro está en ejecución)? Solo pregunto para conocer a personas que ya lo han hecho en sitios de producción, para tener algo de retroalimentación y saber si funciona bien, incluso después de varias reconstrucciones, si hay alguna trampa, etc. Como dije, en un entorno de desarrollo funciona bien.
Si deseas tiempo de inactividad cero, hay un par de pasos adicionales que deben realizarse: deshabilitar “post-migrations” en los nuevos contenedores, desplegar completamente el nuevo contenedor, habilitar post-migrations y luego volver a desplegar. Esto evitará que se ejecuten las migraciones de eliminación de columnas hasta que el código antiguo ya no esté en ejecución.
Aún no hay una guía paso a paso (howto) para esto; solo está documentado aquí:
Sin embargo, en su mayoría, la mayoría de los foros pueden tolerar uno o tres minutos de tiempo de inactividad cada mes.
Sí. En la mayoría de los casos, no hay migraciones que interrumpan el contenedor en ejecución.
También puedes configurarlo para que las migraciones estén deshabilitadas en web_only.yml, y luego, una vez que el nuevo contenedor esté en ejecución, hacer algo como:
cd /var/www/discourse;SKIP_POST_DEPLOYMENT_MIGRATIONS=0 rake db:migrate
Luego seleccionamos el contenedor que queremos que esté activo mediante un enlace simbólico al socket real, así:
Digamos que queremos que el contenedor socket2 esté activo:
ls -sf /var/discourse/shared/socket2/nginx.http.sock /var/run/nginx.http.sock
Digamos que queremos hacer un cambio en socket1 y poner socket1 en activo:
cd /var/discourse
./launcher rebuild socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock
Nota: no hay razón para hacer bootstrap solo del contenedor socket1, porque el contenedor está expuesto mediante un socket de dominio Unix en su propio directorio compartido / volumen, por lo que ambos contenedores de “aplicación web” pueden ejecutarse al mismo tiempo:
No hay “colisión de vinculación de puertos” expuesta como cuando se expone un puerto de contenedor TCP/IP. Por esta razón, solo expongo un socket de dominio Unix en producción (no un puerto TCP/IP).
Por supuesto, puedes hacer bootstrap si quieres:
cd /var/discourse
./launcher bootstrap socket1
./launcher start socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock
Depende de ti, pero ten en cuenta que si ejecutas ambos contenedores al mismo tiempo, ambos ejecutarán sidekiq y ejecutarán trabajos programados, así lo hemos experimentado; por lo que ocasionalmente sincronizamos nuestras cargas en ambos contenedores.
Esto funciona impecablemente para nosotros y podemos reconstruir un contenedor de aplicación web y ponerlo en activo con prácticamente tiempo de inactividad cero. Nos tomamos muy en serio el tiempo de inactividad en producción y lo evitamos siempre que podemos.
Nota:
Este método (anterior) está diseñado para la parte de la aplicación web de la solución, no para el contenedor de datos. No he creado una solución similar para los datos; pero quién sabe, tal vez algún día, dedicaré tiempo a construir algo similar (pero diferente, por supuesto) para el contenedor de datos (una especie de método de “dos contenedores de datos, sincronizar las bases de datos”, totalmente por definir en mi mente en este momento).
Así que, en realidad, estoy haciendo lo contrario de esto:
Como dije, en un entorno de desarrollo funciona bien.
Generalmente no configuro esto en desarrollo porque lleva más tiempo configurar y no es necesario en desarrollo porque un poco de tiempo de inactividad está bien, ya que es solo “yo y el código” (no está en vivo con usuarios y bots accediendo al sitio) y además no uso Docker en desarrollo** (en el escritorio).
Espero que esto ayude.
Con “desarrollo”, me refiero al desarrollo de software (por ejemplo, plugins); no simplemente a “preparar” una instalación de Discourse, a lo que me refiero como “preparación” y no “desarrollo” (solo para ser muy claro).
Gracias, no sabía eso. Es una gran característica y puedo ver cómo evita problemas como el que mencioné antes (aunque esto no evitará cambios en la lógica que utilicen columnas ya existentes, pero ese debería ser un caso más raro).
Gracias por la respuesta. SKIP_POST_DEPLOYMENT_MIGRATIONS parece ser lo que @riking mencionó y parece ser lo que yo buscaba, para evitar que las migraciones rompan lo que se está haciendo en el contenedor en ejecución.
Gracias por tu explicación. Eso parece un buen enfoque para mí, alternando entre dos contenedores (para poder tener un contenedor en ejecución mientras el otro se inicia).
Cuando dije entorno de desarrollo, me refería a que era un entorno de desarrollo remoto que usé para probar la configuración de múltiples contenedores (tanto en la misma máquina como teniendo los contenedores en máquinas diferentes).
Dije desarrollo y no staging porque en un entorno de staging usaría los archivos yml con los mismos complementos y una copia de seguridad de la base de datos de producción para probar. Pero es cierto que, si solo quiero configurar un entorno de desarrollo, en la mayoría de los casos usaría el enfoque de un solo contenedor.
Por lo que puedo ver, esta guía es mucho texto alrededor de:
hacer una copia de seguridad
crear una instancia completamente nueva de Discourse, con más palabras pero los mismos resultados que simplemente ejecutar discourse-setup 2container
restaurar
¿Por qué no simplemente mover o copiar /var/discourse/shared/standalone/{postgres,redis}* a /var/discourse/shared/data después de un apagado limpio y antes de iniciar dos nuevos contenedores desde archivos containers/*.yml separados? Una copia de seguridad/restauración parece una forma muy pesada de mover todos esos datos, añadiendo horas innecesarias al proceso. ¿Estoy pasando por alto algo obvio aquí?
Acabo de probar este proceso en mi Discourse de prueba y también separé Redis mientras estaba en ello, solo para asegurarme de cubrir todas las bases. Edición: He movido la descripción a un nuevo tema:
El sitio parece funcionar correctamente sin un ciclo de copia de seguridad/restauración. ¿Hay algo no obvio que deba verificar?
Hice el mismo proceso para un Discourse relativamente grande y está funcionando bien. Decidí que en producción nombraría mi nuevo contenedor web_only como app, para que mis dedos sigan haciendo lo correcto de forma natural. Después de escribir los nuevos archivos container/*.yml, el tiempo de inactividad para toda la migración fue de 12 minutos, mucho más rápido de lo que habría sido para un ciclo de copia de seguridad/restauración.
Es solo que requiere un poco más de trabajo y comprensión de cómo funcionan las cosas. La restauración de copias de seguridad es más a prueba de errores.
Supongo que simplemente coincidimos en no estar de acuerdo. Pensaría que si alguien es competente para ejecutar múltiples contenedores, puede ejecutar unos pocos comandos, y no creo que esos comandos sean más difíciles de escribir que bin/rails c y empezar a teclear comandos de Ruby por aquí, ni que requieran habilidades significativamente más o diferentes a las necesarias para usar múltiples contenedores en absoluto. Pero migraré el contenido a una nueva publicación separada en lugar de dejarlo enterrado en un comentario aquí.
¡Y si cometen un error, no hay sustituto para una copia de seguridad antes de una migración! ¡Espero haberlo dejado claro en mi artículo, que ahora está enlazado arriba!
Ahí está la falla en tu argumento. Agregar 2container a ./discourse-setup no incluye ninguna medida de competencia. Hay muchas personas que ejecutan dos contenedores simplemente porque ven temas como este y asumen que hay algún secreto o que es “lo que hay que hacer”.
El tema de postgres 12 debería servir como una advertencia cuando se trata de la complejidad añadida. Usar una copia de seguridad como paso entre estados permite a un usuario volver a un solo contenedor renombrando un único archivo; una vez que empiezas a mover carpetas, esa simplicidad se pierde.
@Stephen Hay un fallo en tu argumento: la descripción de contenedores múltiples está llena de advertencias sobre la necesidad de asumir la responsabilidad de las actualizaciones y comprender cómo funciona, y la descripción larga de arriba está tan oscurecida que probablemente cualquiera que la viera se rendiría de todos modos. Lee mi Migrate quickly to separate web and data containers y dime que no asustará a las personas que tendrán dificultades para seguirlo, o que no enfatiza la necesidad de realizar copias de seguridad y la capacidad de volver a una copia de seguridad si algo sale mal.
Estaba muy molesto cuando ejecuté ./launcher rebuild app poco después de migrar a un servidor más potente (para una corrección de seguridad) y tener mi sitio caído durante un tiempo excesivamente largo, gran parte del cual se dedicó a reconstruir las partes de postgres del contenedor. Fue entonces cuando encontré la documentación de 2 contenedores y esta documentación, y realmente no quería pasar por otras 4 horas de inactividad para migrar, así que seguí soportando largas interrupciones para ./launcher rebuild app para evitar las 4 horas de inactividad que tomaría una restauración. Como persona vagamente competente, me molestó mucho durante mucho tiempo que esta configuración estuviera efectivamente oculta.
El tema de postgres 12 es una excelente referencia, porque las personas terminan con más tiempo de inactividad porque tienen que reconstruir toda la aplicación varias veces, cuando podrían estar reconstruyendo solo el contenedor de postgres dos veces. No puedo decir que haya leído todo el hilo debido a la eliminación automática a los 6 días, pero no me parece en absoluto obvio que las implementaciones de múltiples contenedores incompetentes sean el problema principal, o incluso un problema importante allí.
(Lo siento, a veces me canso un poco de la idea de que “todos los usuarios son incompetentes” por aquí.)
Puede que no tenga sentido para ti, pero para aquellos de nosotros que hemos estado aquí en meta durante 6 o 7 años ofreciendo asistencia a personas en Support, siempre tendrá sentido contar con una estrategia de reversión.
Los errores sí llegan a los entornos de pruebas aprobadas; ocasionalmente, las limitaciones de velocidad de RubyGems afectan las reconstrucciones e incluso GitHub ha tenido sus propios altibajos. Por esa razón sola, no veo ningún valor en realizar un cambio de estado que dificulte simplemente renombrar un archivo y ejecutar ./launcher start app.
Tu tolerancia al riesgo puede ser diferente; en ese caso, puedes tomar un camino distinto. Para quienes regularmente ayudan a recoger los escombros, la guía actual funciona bien.
No siento que hayas leído realmente el proceso que escribí, ya que escribes como si no hubiera enfatizado la necesidad de tener la capacidad de restaurar. Por favor, léelo y luego vuelve para considerar editar lo que escribiste y convertirlo en una declaración veraz sobre mis instrucciones. Tal como está, siento que me estás dando lecciones sin siquiera tomarte la molestia de leer lo que escribí.
Sin embargo, he añadido muchas más advertencias adicionales, incluida una en la parte superior, que superan las advertencias en este mensaje, el cual ha estado aquí durante cinco años y sigue siendo la ubicación canónica para las instrucciones sobre este proceso de migración.
Primero que nada, ¡gracias por intentar despejar esta “selva” para nosotros, aventureros ! Probablemente estaré en tu lugar en unos días…
¿Qué hay en el archivo multisite.yml?
Recientemente configuré un foro de Discourse autoalojado en un VPS. Las cargas se almacenan en Wasabi. Lo mismo para las copias de seguridad. Todo está alojado en Linode.
Utilicé la plantilla independiente y encontré que la configuración fue un soplo de aire fresco en comparación con otros programas. ¡Fue sublime! Una pura alegría. Ojalá cada proyecto de código abierto prestara tanta atención a la instalación y configuración como lo hizo Discourse.
Sin embargo, aquí está el problema. Tengo una instancia dedicada de PostgreSQL ejecutándose en un servidor separado, accesible solo mediante una dirección RFC-1918 que no es accesible desde Internet, y me gustaría que Discourse la utilizara. No me gusta mucho que los servidores de base de datos se ejecuten en el mismo servidor que el servidor web o de aplicaciones.
Entonces, ¿hay alguna manera de separar la base de datos independiente y moverla a mi clúster de bases de datos dedicado?
Supongo que todo lo que necesitaré hacer es realizar un pgdump de la base de datos de Discourse, moverla a mi base de datos dedicada y restaurarla, seguido de un vacuum analyze en todas las tablas de PostgreSQL después de la restauración/importación, y luego simplemente apuntar la aplicación de Discourse a la nueva base de datos a través de la red.
Pero no puedo encontrar dónde se almacenan las credenciales de la base de datos. Miré en app.yml, pero no parecen haber entradas de base de datos, y cuando revisé la carpeta ../templates/, ninguno de los archivos yml parecía tener credenciales de base de datos.
¿Es realmente posible lo que estoy intentando hacer?
Si normalmente no hay credenciales para la base de datos postgres integrada, ¿hay alguna manera de ejecutar un pgdump y volcar la base de datos desde el contenedor independiente?