RabbitMQ cluster running in Docker
docker run -d -h node-1.rabbit \
--name rabbit \
-p "4369:4369" \
-p "5672:5672" \
-p "15672:15672" \
-p "25672:25672" \
-p "35197:35197" \
-e "RABBITMQ_USE_LONGNAME=true" \
-e "RABBITMQ_LOGS=/var/log/rabbitmq/rabbit.log" \
-v /data:/var/lib/rabbitmq \
-v /data/logs:/var/log/rabbitmq \
rabbitmq:3.6.6-management
В первой строке мы определяем имя хоста контейнера, которое будет использоваться для идентификации узла. Во второй строке мы определяем имя контейнера. В строках 3-7 сопоставляем порты контейнера с хостом. Таким образом, мы можем получить доступ к контейнеру через node-X.rabbit:PORT. Для получения дополнительной информации о портах RabbitMQ тут. После этого мы определяем некоторые переменные среды, которые будут использоваться для конфигурации RabbitMQ. В нашем случае устанавливаем только два, RABBITMQ_USE_LONGNAME = true, чтобы каждый узел связывался друг с другом, используя свое полное доменное имя. Мы также устанавливаем RABBITMQ_LOGS, поэтому весь вывод идет в файл журнала вместо STDOUT (что может быть проблемой на production). На 10-й и 11-й строках мы маунтим каталоги, которые создали для узла-1, в контейнер rabbit. Наконец, укажем, какой образ докера мы будем использовать. В этом случае RabbitMQ с плагином управления. Откройте браузер и перейдите по адресу http://node-1.rabbit:15672
Такой же конфиг для второго хоста (кроме имени хоста :))
Каждый узел RabbitMQ должен иметь файл с именем .erlang.cookie, расположенный в папке данных, в нашем случае /data. Этот файл содержит секрет (какой-то случайный хеш), который будет автоматически создан, если он не существует. Этот файл используется для определения того, может ли узел связываться с другим узлом. Связь будет разрешена, если оба узла используют один и тот же секрет в файле.erlang.cookie.
Просто скопируйте секрет с .erlang.cookie первого узла и вставьте во второй. Затем перезапустите контейнер Docker для второго узла.
Плагин rabbitmq-management – браузерный интерфейс для мониторинга и настройки множества функций RabbitMQ. Вы можете получить доступ к нему по адресу: http://node-1.rabbit:15672
Через вебинтерфейс кластер не настроить, поэтому мы будем использовать только инструмент командной строки rabbitmqctl.
Этот шаг не является обязательным, но для прода нужно будет отключить чисто из соображений безопасности. RabbitMQ по умолчанию создаст гостевого пользователя (пароль: guest).
С этого момента мы будем вызывать rabbitmqctl в docker-контейнерах RackbitMQ.
Удаляем пользователя guest:
docker exec rabbit rabbitmqctl delete_user guest
Вам просто нужно сделать это на первом узле. Как только мы создадим кластер и подключим к нему второй узел RabbitMQ, все конфигурации будут скопированы.
В учебных целях предположим, что у нас есть только один виртуальный хост /. Вся конфигурация будет на этом хосте. Еще раз, вам просто нужно сделать это на первом узле.
Создадим виртуальный хост:
docker exec rabbit rabbitmqctl add_vhost /
Я собираюсь создать двух пользователей. Один из них – пользователь-администратор, который может иметь доступ к пользовательскому интерфейсу браузера и вносить изменения в конфигурации кластера. Второй – пользователь уровня приложения, который будет иметь разрешения на взаимодействие с RabbitMQ на уровне приложения. Он будет иметь права на чтение / запись на виртуальный хост. Вы можете настроить его в соответствии с вашими потребностями.
# Admin user
docker exec rabbit rabbitmqctl add_user josuelima MyPassword999
docker exec rabbit rabbitmqctl set_user_tags josuelima administrator
# Application user
docker exec rabbit rabbitmqctl add_user ruby_app SuperPassword000
docker exec rabbit rabbitmqctl set_permissions -p / ruby_app ".*" ".*" ".*"
Еще раз, вам просто нужно сделать это на первом узле.
Теперь, когда наш первый узел настроен, присоединим наш второй узел к первому и запустим кластер. Все, что нам нужно, это остановить второй узел RabbitMQ (а не контейнер докера), а затем подключить его к первому узлу.
Перейдем ко второму узлу и сделаем это:
docker exec rabbit rabbitmqctl stop_app
docker exec rabbit rabbitmqctl join_cluster rabbit@node-1.rabbit
docker exec rabbit rabbitmqctl start_app
Прекрасно! Теперь второй узел скопирует все настройки с первого узла, и мы должны получить наш кластер. Вы можете проверить его в пользовательском интерфейсе или с помощью командной строки:
docker exec rabbit rabbitmqctl cluster_status
Теперь у вас есть кластер RabbitMQ, работающий в Docker. Если хотите добавить к нему больше узлов, просто создайте новый контейнер Docker с RabbitMQ и подключите его к кластеру.
Теперь, когда у нас работает кластер, пришло время подумать о том, как мы хотим, чтобы он себя вел. По умолчанию очереди в кластере RabbitMQ расположены на одном узле (узел, на котором они были сначала объявлены). Очень важно это понимать.
Ваши очереди будут распределены между вашими узлами кластера? Какой сценарий хотите? Хорошо ли это?
Правильное использование распределенных очередей – это когда у вас действительно высокие скорости ввода-вывода для ваших очередей и вы хотите распределить нагрузку по всем узлам. Имейте в виду, что очередь будет жить в одном единственном узле, и если один узел упадет, все очереди, живущие на этом узле, будут недоступны, пока не вернутся узел.
Если это сценарий, который вам нужен, вам подойдут распределенные очереди по умолчанию.
Я также рекомендую вам взглянуть на HAProxy Load Balancer, или если вы используете AWS, GCP, DO или еще что-то - там есть свои балансировщики.
Также могут быть зеркальные очереди, которые являются своего рода набором реплик. В этой ситуации все узлы будут просто копией друг друга. Все сообщения, опубликованные в очередь, реплицируются на все узлы кластера.
Это очень полезно, когда нужна высокая доступность очередей. Таким образом, если узел падает, у вас все еще есть очереди на других узлах.
Чтобы настроить зеркальные очереди, вам просто нужно установить политику для своих очередей.
docker exec rabbit rabbitmqctl set_policy ha "." '{"ha-mode":"all"}'
В этом примере мы устанавливаем политику с именем ha так, что все очереди . будут доступны на всех узлах {"ha-mode":"all"}.
У вас могут быть различные конфигурации для высокодоступных очередей, проверьте документацию.
Для улучшения реализации кластера можно использовать, например, RAM Nodes, Firewall Nodes, Partition, Synchronization и т. д. Ниже две важные ссылки: