Instalación de Discourse para desarrollo en macOS usando asdf y docker-compose

Tenga en cuenta que esta es una guía de instalación para un entorno de desarrollo no compatible. Las guías oficialmente compatibles para macOS están aquí (nativo) y aquí (Docker). Proceda bajo su propio riesgo.

El objetivo de esta guía es contenerizar postgres y redis, pero mantener ruby fuera de los contenedores.

Intenté el enfoque de Discourse para desarrollo usando Docker, pero resultó ser demasiado lento en mi máquina.

Luego, revisé la guía de Discourse para desarrollo en macOS. Pero lo primero que hizo el script fue instalar brew. brew puede ser excelente, pero he estado usando MacPorts durante mucho tiempo y me gustaría seguir resistiendo con éxito la instalación de brew. Además, ese script también realizaba instalaciones globales de cosas como postgresql y redis, lo cual preferiría poder mantener a nivel de proyecto.

Así que esto es lo que funcionó para mí usando una combinación de asdf y docker-compose. El resultado es un punto medio entre los dos enfoques descritos anteriormente. postgres y redis se ejecutan en un contenedor usando docker-compose para que puedan fijarse en las versiones oficiales y las instalaciones que Discourse utiliza en producción. Rails se ejecuta directamente en el hardware. Esta combinación es considerablemente más rápida para mí. Los resultados pueden variar.

Si desea seguir los pasos, necesitará tener instalados en su máquina tanto asdf como Docker. (¡OMG, asdf es realmente fantástico! Debería conseguirlo si tiene algún interés en mantener fácilmente muchos entornos de desarrollo diferentes. Reemplaza renv, nvm… aparentemente casi todo excepto jenv.)

Si observa lo que hacía el script de instalación para macOS, puede separar lo que se instala en tres categorías:

  • entornos y herramientas de línea de comandos como ruby y yarn. Instalaremos estos y fijaremos sus versiones en nuestro directorio de proyecto usando asdf.
  • servicios, específicamente postgres y redis. Los instalaremos usando Docker Compose, nuevamente para poder fijar sus versiones a lo que necesitamos para este proyecto y también tener un entorno de desarrollo que podamos iniciar y detener fácilmente.
  • otros, principalmente bibliotecas para manipulación de imágenes como ImageMagick y optimización. Estas se pueden instalar usando brew, port o directamente desde el código fuente.

También necesitaremos reconfigurar ligeramente nuestro entorno de desarrollo para conectarse al servidor postgres ejecutado por docker-compose.

Código fuente de Discourse

Todos los pasos a continuación deben realizarse dentro de su directorio de código fuente de Discourse:

git clone https://github.com/discourse/discourse.git && cd discourse

Esto es importante ya que aquí es donde asdf guardará su archivo de configuración .tool-versions y donde crearemos nuestro archivo docker-compose.yml para Docker.

asdf

Hay tres cosas que necesitamos instalar usando asdf: ruby, yarn y postgres. Afortunadamente, asdf facilita tanto la instalación de todo a la vez como la fijación de las versiones en nuestro directorio de proyecto. Primero, cree .tool-versions con este contenido:

yarn 1.22.2
ruby 2.6.5
postgres 10.12

Luego, simplemente ejecute asdf install.

Ahora debería poder realizar los pasos de instalación de bibliotecas de Ruby incluidos en el script y más adelante en las instrucciones:

gem update --system
gem install bundler
gem install rails
gem install mailcatcher
gem install pg -- --with-pg-config=$HOME/.asdf/installs/postgres/10.12/bin/pg_config
bundle install

Es posible que necesite ajustar la ruta a pg_config dependiendo de dónde instaló asdf.

docker-compose.yml

A continuación, necesitamos crear nuestro archivo docker-compose.yml configurado para iniciar redis y postgres. El mío se ve así:

version: "3"
networks:
  discourse:
    driver: bridge
services:
  data:
    image: "geoffreychallen/discourse_data:latest"
    command: /sbin/boot
    ports:
      - "5432:5432"
      - "6379:6379"
    volumes:
      - "data_shared:/shared/"
      - "data_logs:/var/log/"
    networks:
      - discourse
volumes:
  data_shared:
    driver: local
  data_logs:
    driver: local

Gracias a @pfaffman por la sugerencia de usar un contenedor de datos estándar de Discourse. geoffreychallen/discourse_data:latest se construye a partir de Discourse Docker. Usé el archivo de muestra data.yml con dos cambios. Primero, establecí la contraseña del usuario discourse como “discourse”. Segundo, hice que ese usuario fuera superusuario para que pueda crear bases de datos de prueba. Aquí está la parte hooks de mi archivo data.yml:

hooks:
  after_postgres:
    - exec:
        stdin: |
          alter user discourse with password 'discourse';
        cmd: sudo -u postgres psql discourse
        raise_on_fail: false
    - exec:
        stdin: |
          alter user "discourse" with superuser;
        cmd: sudo -u postgres psql discourse
        raise_on_fail: false

Nuevamente, esto es solo en caso de que quiera construir su propio contenedor de datos de Discourse y no usar el mío. Por favor, no use este contenedor en producción: ¡es completamente inseguro!

En esta configuración, exponemos tanto los puertos estándar de postgres como de redis y ejecutamos el comando de arranque que el contenedor necesita para iniciar.

Una vez que su docker-compose.yml esté en su lugar, pruébelo:

docker-compose up

Asumiendo que todo está configurado correctamente, debería ver que redis y postgres se inician. Presione Control-C para cancelar o docker-compose down si por alguna razón algo no se cierra correctamente.

Bibliotecas varias

La mayoría de las bibliotecas de optimización de imágenes se pueden instalar usando port o brew. Así es como hacerlo con port:

sudo port install imagemagick pngquant optipng jhead jpegoptim gifsicle

svgo se puede instalar una vez que tenga npm. No voy a cubrir eso, ya que es bastante sencillo.

Por si acaso, según parece, ninguna de estas herramientas es obligatoria. Veo advertencias durante varios pasos posteriores sobre su ausencia, pero nada parece explotar.

config/database.yml y spec/fixtures/multisite/two_dbs.yml

Finalmente, necesitamos reconfigurar ligeramente nuestro entorno de desarrollo para conectarse correctamente a postgres. Por defecto, intenta usar un socket Unix, que no es exportado por nuestro contenedor.

Para solucionar esto, debe modificar config/database.yml. Esencialmente, en todas partes donde vea:

adapter: postgresql

Reemplácelo con:

adapter: postgresql
host: localhost
username: discourse
password: discourse

La adición de host hace que Discourse no use un socket, y username y password hacen que Discourse se conecte usando el usuario de base de datos predeterminado de Discourse y la contraseña que establecimos anteriormente.

Tuve que hacer este cambio tres veces en config/database.yml: una vez bajo development, luego bajo test y finalmente bajo profile. Para que la suite de pruebas funcionara, también tuve que hacer un cambio similar en spec/fixtures/multisite/two_dbs.yml.

Aquí vamos…

¡Bien, vamos a ello! En una ventana, inicie su entorno de desarrollo usando docker-compose:

docker-compose up

En una segunda ventana, ejecutemos los pasos de configuración de la base de datos:

bundle exec rake db:create

Asumiendo que funcionó, ahora puede continuar en el punto correspondiente de la guía para macOS basada en brew.

Cuando termine de trabajar, detenga docker-compose y podrá guardar su entorno de desarrollo hasta la próxima vez.

Si desea eliminar permanentemente la base de datos y el contenido de redis, simplemente ejecute docker-compose down -v para borrar los volúmenes persistentes junto con los propios contenedores. Pero sin el flag -v, docker-compose down mantendrá su base de datos entre sesiones de desarrollo.

¿Pasan las pruebas?

Mi configuración falló en dos casos de prueba:

Failures:

  1) UploadCreator#create_for pngquant should apply pngquant to optimized images
     Failure/Error: expect(upload.filesize).to eq(9558)

       expected: 9558
            got: 9550

       (compared using ==)
     # ./spec/lib/upload_creator_spec.rb:115:in `block (4 levels) in <main>'

  2) tasks/uploads uploads:secure_upload_analyse_and_update when store is external when secure media is enabled rebakes the posts attached
     Failure/Error: expect(post1.reload.baked_at).not_to eq(post1_baked)

       expected: value != 2020-03-08 03:20:01.777117000 +0000
            got: 2020-03-08 03:20:01.777117000 +0000

       (compared using ==)

       Diff:
         <The diff is empty, are your objects producing identical `#inspect` output?>
     # ./spec/tasks/uploads_spec.rb:90:in `block (5 levels) in <main>'

Finished in 19 minutes 21 seconds (files took 13.67 seconds to load)
4297 examples, 2 failures, 11 pending

Para mí, el primero parece que pngquant está funcionando un poco mejor de lo esperado. No estoy seguro de por qué eso representa un fallo. El segundo tampoco lo entiendo. Pero esto me parece razonable.

¡Feliz hacking!

5 Me gusta