Установка Discourse для разработки на macOS с использованием asdf и docker-compose

Обратите внимание: это руководство по установке в неподдерживаемой среде разработки. Официально поддерживаемые руководства для macOS находятся здесь (нативная установка) и здесь (Docker). Действуйте на свой страх и риск.

Цель этого руководства — изолировать PostgreSQL и Redis в контейнерах, но оставить Ruby вне их.

Я попробовал подход Discourse для разработки с использованием Docker, но он оказался слишком медленным на моей машине.

Затем я обратил внимание на руководство по установке Discourse для разработки на macOS. Однако первое, что делает скрипт, — это установка brew. brew может быть отличным инструментом, но я уже давно использую MacPorts и хотел бы продолжить успешно сопротивляться установке brew. Кроме того, этот скрипт также выполняет глобальную установку таких компонентов, как PostgreSQL и Redis, что я предпочитаю делать на уровне каждого проекта.

Поэтому вот что сработало для меня с использованием комбинации asdf и docker-compose. Результат — нечто среднее между двумя описанными выше подходами. PostgreSQL и Redis запускаются в контейнере с помощью docker-compose, чтобы можно было зафиксировать официальные версии, используемые Discourse в продакшене. Rails работает «на металле». Это сочетание для меня значительно быстрее. У кого-то может быть иначе.

Если вы хотите следовать этому руководству, вам понадобятся установленные на вашей машине asdf и Docker. (Ого, asdf действительно фантастичен… вам определенно стоит его установить, если вы хоть немного заинтересованы в удобном управлении множеством различных сред разработки. Он заменяет renv, nvm… кажется, почти всё, кроме jenv.)

Если посмотреть, что делает скрипт установки для macOS, можно разделить устанавливаемые компоненты на три категории:

  • окружения командной строки и инструменты, такие как ruby и yarn. Мы установим их и зафиксируем их версии в директории проекта с помощью asdf.
  • сервисы — в частности, PostgreSQL и Redis. Мы установим их с помощью Docker Compose, чтобы снова зафиксировать их версии под нужды этого проекта и получить среду разработки, которую можно легко запускать и останавливать.
  • прочее — в основном библиотеки для манипуляций с изображениями, такие как ImageMagick, и оптимизации. Их можно установить с помощью brew, port или напрямую из исходного кода.

Нам также потребуется слегка перенастроить среду разработки для подключения к серверу PostgreSQL, запущенному через docker-compose.

Исходный код Discourse

Все шаги ниже должны выполняться внутри директории с исходным кодом Discourse:

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

Это важно, так как именно здесь asdf сохранит свой конфигурационный файл .tool-versions, и именно здесь мы создадим файл docker-compose.yml для Docker.

asdf

Нам нужно установить три компонента с помощью asdf: ruby, yarn и postgres. К счастью, asdf позволяет легко установить их все сразу и зафиксировать версии в директории проекта. Сначала создайте файл .tool-versions со следующим содержимым:

yarn 1.22.2
ruby 2.6.5
postgres 10.12

Затем просто выполните asdf install.

Теперь вы должны быть в состоянии выполнить шаги установки Ruby-библиотек, включенные в скрипт и описанные далее в руководстве:

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

Возможно, вам потребуется скорректировать путь к pg_config в зависимости от того, где вы установили asdf.

docker-compose.yml

Далее нам нужно создать файл docker-compose.yml, настроенный для запуска Redis и PostgreSQL. Мой выглядит так:

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

Благодаря @pfaffman за предложение использовать стандартный контейнер данных Discourse. Образ geoffreychallen/discourse_data:latest собран на основе Discourse Docker. Я использовал примерный файл data.yml с двумя изменениями. Во-первых, я установил пароль пользователя discourse равным discourse. Во-вторых, я сделал этого пользователя суперпользователем, чтобы он мог создавать тестовые базы данных. Вот часть hooks моего файла 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

Снова, это только на случай, если вы захотите собрать свой собственный контейнер данных Discourse и не использовать мой. Пожалуйста, не используйте этот контейнер в продакшене — он полностью небезопасен!

В этой конфигурации мы открываем стандартные порты PostgreSQL и Redis и запускаем команду boot, необходимую контейнеру для старта.

Как только ваш docker-compose.yml будет готов, запустите его:

docker-compose up

При условии, что всё настроено правильно, вы увидите запуск Redis и PostgreSQL. Нажмите Control-C для отмены или выполните docker-compose down, если по какой-то причине что-то не закрывается корректно.

Различные библиотеки

Большинство библиотек для оптимизации изображений можно установить с помощью port или brew. Вот как это сделать через port:

sudo port install imagemagick pngquant optipng jhead jpegoptim gifsicle

svgo можно установить после установки npm. Я не буду это описывать, так как это довольно просто.

Кстати, насколько я могу судить, ни один из этих инструментов не является обязательным. Я вижу предупреждения на различных последующих этапах об их отсутствии, но ничего не ломается.

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

Наконец, нам нужно слегка перенастроить среду разработки для правильного подключения к PostgreSQL. По умолчанию он пытается использовать Unix-сокет, который не экспортируется нашим контейнером.

Чтобы исправить это, нужно изменить файл config/database.yml. Фактически, везде, где вы видите:

adapter: postgresql

Замените это на:

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

Добавление host заставляет Discourse не использовать сокет, а добавление username и password заставляет Discourse подключаться с использованием пользователя базы данных Discourse по умолчанию и пароля, который мы установили выше.

Мне пришлось внести это изменение три раза в config/database.yml: один раз в секции development, затем в секции test и, наконец, в секции profile. Чтобы тестовый набор работал, мне также пришлось внести аналогичное изменение в spec/fixtures/multisite/two_dbs.yml.

Поехали…

Ладно, давайте начнем! В одном окне запустите среду разработки с помощью docker-compose:

docker-compose up

Во втором окне выполните шаги настройки базы данных:

bundle exec rake db:create

Если всё прошло успешно, теперь вы можете продолжить с соответствующего места в руководстве по установке для macOS на основе brew (ссылка).

Когда вы закончите работу, остановите docker-compose, и вы сможете закрыть среду разработки до следующего раза.

Если вы хотите навсегда удалить содержимое базы данных и Redis, просто выполните docker-compose down -v, чтобы очистить постоянные тома вместе с самими контейнерами. Но без флага -v команда docker-compose down сохранит вашу базу данных между сеансами разработки.

Проходят ли тесты?

Моя настройка не прошла два тестовых случая:

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

Для меня первый случай выглядит так, будто pngquant работает чуть лучше, чем ожидалось. Не понимаю, почему это считается провалом. Второй случай я тоже не понимаю. Но в целом всё выглядит логично.

Удачной разработки!

5 лайков