Обратите внимание: это руководство по установке в неподдерживаемой среде разработки. Официально поддерживаемые руководства для 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 работает чуть лучше, чем ожидалось. Не понимаю, почему это считается провалом. Второй случай я тоже не понимаю. Но в целом всё выглядит логично.
Удачной разработки!