Можно ли подключаться к базе данных напрямую из отдельного приложения?

Приложение будет находиться вне контейнера Docker Discourse, но на том же сервере. Если это так, не могли бы кто-нибудь поделиться деталями о том, как это сделать, или направить к руководству или инструкции?

Есть ли также какие-либо недостатки в таком подходе по сравнению с использованием плагина/API DE?

Недостатки в основном связаны с тем, что такое соединение может использоваться для доступа на запись. Это требование?

Если вашей интеграции требуется доступ на запись к базе данных, рассмотрите возможность написания плагина, который предоставляет только необходимые вам операции.

Это не является обязательным требованием, но я готов принять это как недостаток :slight_smile:

Я начал использовать ваш плагин DE, но, к сожалению, думаю, что мой случай использования потребует прямого подключения, так как я отправляю слишком много запросов через API для некоторых страниц (и это только с моим посещением сайта). В основном это пользовательские запросы, поэтому я не уверен, влияет ли это на ситуацию. Тем не менее, мне всё ещё нравится плагин DE!
Не могли бы вы подсказать, какой лучший способ подключиться к базе данных Postgres напрямую, вне контейнера? И форум, и сайт находятся на одном сервере, если это имеет значение.


Редактирование: Похоже, я достигаю ограничения скорости с плагином DE, но я точно помню, что Сэм говорил, что если запросы приходят с одного и того же сервера, ограничение скорости не применяется — всё ещё так?

Хотя это возможно, другое приложение может захватывать блокировки таблиц и мешать нормальной работе Discourse.

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

Спасибо за информацию, Рафаэль. Я буду использовать исключительно операторы SELECT и, насколько мне известно, они не блокируют. Поэтому мне нужно будет беспокоиться только об изменениях в таблице на стороне Discourse (например, при обновлении) и о том, когда я смогу временно отключить другое приложение. Это снимет проблемы с блокировками?

Что касается репликации базы данных, это кажется интересным вариантом — можно ли это делать на лету, чтобы отставание составляло не более пары минут? (Мне нужно часто получать последние темы — почти на каждой странице сайта они есть, хотя я и кэширую их на две минуты, но кэш зависит от страницы/критериев, и таких страниц будут сотни). Также этот вариант может перестать работать по мере роста базы данных? (На другом форуме Discourse моя база данных уже занимает несколько гигабайт.)

(Я не думаю, что создание плагина здесь будет уместно, так как не вижу, как это может быть лучше плагина Data Explorer; на самом деле плагин DE почти идеален — за исключением этой проблемы.)

У кого-нибудь есть идеи, почему это не работает?

Я следовал некоторым сообщениям от @pfaffman и @Nacho_Caballero в этой теме: How to make the database (or part of it) accessible to a cloud data processor?, а также сообщению от @mpalmer здесь: Accessing to the database from outside the container - #4 by mpalmer.

Сначала я отредактировал файл app.yml следующим образом:

expose:
  - "127.0.0.2:5432:5432"

Пересобрал контейнер. Внутри контейнера установил пароль для пользователя postgres и смог подключиться изнутри контейнера с помощью следующей команды:

psql -h localhost -d discourse -U postgres

Однако, когда я выхожу из контейнера и пытаюсь подключиться, получаю:

# psql -h 127.0.0.2 -p 5432 -d discourse -U postgres
psql: сервер неожиданно закрыл соединение
	Скорее всего, это означает, что сервер завершился аномально
	до или во время обработки запроса.

Я также пробовал менять порт на другой, но получаю ту же ошибку. IP-адрес 127 я получил из команды docker ps и раздела Network Settings (у меня запущено три отдельных экземпляра Discourse).

Если я изменю IP-адрес (на один из IP-адресов других форумов Discourse), получаю (более немедленный и) другой ответ/сообщение, так что вышеуказанное кажется частично верным:

# psql -h 127.0.0.3 -p 5432 -d discourse -U postgres
psql: не удалось подключиться к серверу: отказ в соединении
	Запущен ли сервер на хосте "127.0.0.3" и принимает ли он
	TCP/IP-соединения на порту 5432?

Есть ли у кого-нибудь идеи, что я делаю не так? Поиск в Google по запросу psql: server closed the connection unexpectedly указывает на проблему с сетью — значит, нужно ли что-то ещё изменить внутри контейнера?

Мне удалось заставить это работать (извне контейнера) с помощью SSH-туннеля. Я создал нового пользователя вместо использования postgres и настроил нестандартные порты для SSH и postgres, но это должно сработать и для вашей конфигурации:

ssh -L 5432:localhost:5432 ВНЕШНИЙ_IP_VPS "psql -U postgres -d discourse -h localhost"

ВНЕШНИЙ_IP_VPS — это IP-адрес, который вы используете для подключения к вашему удалённому серверу.

Если это всё ещё не работает, попробуйте изменить открытый IP в app.yml, чтобы использовать IP docker bridge вместо внутреннего IP контейнера, полученного из docker ps. Не уверен, что это обязательно, но именно так настроено у меня:

expose:
  - "127.0.0.1:5432:5432"
# или, если используется нестандартный порт:  - "127.0.0.1:КАСТОМНЫЙ_ПОРТ:5432"

Не забудьте пересобрать контейнер после этого.

Дайте знать, как получится. Мне потребовалось ОЧЕНЬ МНОГО времени, чтобы всё заработало (а теперь это кажется таким простым), поэтому я с радостью помогу.

Спасибо за информацию @Nacho_Caballero… особенно за ссылку о docker!

Похоже, что совет в вашей (и в другой) ветке был верным: вам нужно:

expose:
  - "127.17.0.1:5432:5432"

…как упоминается в той ссылке. Docker автоматически перенаправит запрос на правильный IP-адрес вашего контейнера (что логично, учитывая, что эти IP-адреса динамические — об этом я и думал). Думаю, для большинства настроек этого достаточно.

Хотя я уже пробовал это сделать — так что, возможно, вы задаётесь вопросом, в чём была моя проблема. Мой фаервол! (Кажется, я узнал ошибку psql: server closed the connection unexpectedly!)

Всё теперь исправлено — спасибо всем :blush:

Хорошо знать! Рад, что вы это выяснили. Ваш фаервол — это iptables? Как вы открыли порт?

Я использую firewalld, но для iptables что-то вроде этого должно сработать:

iptables -A INPUT -p tcp --dport xxxx -j ACCEPT
iptables -A OUTPUT -p tcp --dport xxxx -j ACCEPT