Отказоустойчивость:
Подготовка серверов#

Эта статья описывает необходимые действия и подготовку перед настройкой отказоустойчивости для серверной части мессенджера Compass.

Предварительные требования#

Перед настройкой отказоустойчивости убедитесь, что:

  1. У вас есть два сервера:

  2. Оба сервера находятся в одной сети и им доступно минимум 3 адреса:

    • один внутренний IP-адрес для основного сервера;

    • один внутренний IP-адрес для резервного сервера;

    • один внешний и внутренний IP-адрес, используемый как виртуальный IP (VIP).

    Пример схемы размещения серверов и использования VIP:

    • основной сервер: внутренний IP — 192.168.1.4;

    • резервный сервер: внутренний IP — 192.168.1.5;

    • виртуальный IP (VIP) — 192.168.1.6, на который настроен DST-NAT с внешнего адреса 188.124.51.150.

    Примечание

    Виртуальный IP (VIP) — это дополнительный IP-адрес, который используется для балансировки и автоматического переключения трафика между основным и резервным серверами. VIP должен быть выделен в вашей внутренней сети. В процессе настройки Отказоустойчивости VIP будет привязан к вашему домену, используемому для доступа к Compass.

    Предупреждение

    Если у вас ранее уже был установлен сервер, подключать домен к внешнему IP VIP на этом шаге не требуется.

  3. Для сценария отказоустойчивости Compass использует встроенные базы данных в Docker. Подключение к внешним базам данных в этом режиме не поддерживается.

Настройка Docker#

  1. Если ваша версия Compass on-premise ниже 6.1.0, то обновите окружение в соответствии с инструкцией по обновлению.

  2. На основном и резервном серверах проверьте, что версия Docker совпадает:

    sudo docker version --format '{{.Server.Version}}'
    
  3. На основном сервере выполните команду для создания токена присоединения:

    sudo docker swarm join-token manager
    
  4. Добавьте указанный в полученной команде <port> в список разрешённых для фаервола на обоих серверах:

    sudo ufw allow from <IP другой ноды> to any port <port>
    

    Список IP нод можно получить с помощью команды:

    sudo docker node ls -q | xargs sudo docker node inspect --format '{{.Description.Hostname}} {{.Status.Addr}}'
    

    Примечание

    Пример:
    Имеются две ноды node-1 (IP 192.168.0.1) и node-2 (IP 192.168.0.2).
    Таким образом команда добавления в разрешённые фаервола для node-1 выглядит следующим образом:
    sudo ufw allow from 192.168.0.2 to any port 2377

  5. На обоих серверах добавьте следующие порты в список разрешённых фаервола для корректной работы нод:

    sudo ufw allow from <IP другой ноды> to any port 7946
    sudo ufw allow from <IP другой ноды> to any port 4789
    sudo ufw allow from <IP другой ноды> to any port 3306 proto tcp
    
  6. На резервном сервере необходимо покинуть Docker Swarm:

    sudo docker swarm leave --force
    

Настройка репликации баз данных#

  1. На основном сервере откройте конфигурационный файл configs/replication.yaml для редактирования любым текстовым редактором и заполните поля:

    # service_label — лейбл для обозначения сервисов сервера (основной, резервный).
    # Имя должно быть не длиннее 7 символов
    service_label: "primary"
    
    # mysql_server_id — идентификатор mysql сервера.
    # Каждый новый сервер должен иметь отличный идентификатор от предыдущего.
    # Для основного сервера установите значение 1, для резервного — значение 2.
    mysql_server_id: 1
    
    # start_octet — используется для определения сабсети для сервисов. Для каждого нового сервера необходимо инкрементировать на 10.
    # Для основного сервера установите значение 10, для резервного — значение 20.
    start_octet: 10
    
  2. На основном сервере получите текущий список нод:

    sudo docker node ls
    

    В полученном списке скопируйте ID той ноды, рядом с которой стоит отметка * и добавьте лейбл primary для выбранного ID ноды.

    Примечание

    Установите лейбл, который добавляли в конфигурационный файл configs/replication.yaml в поле service_label.

    sudo docker node update --label-add role=primary <node id>
    

    Проверить результат можно командой:

    sudo docker node inspect <node-id> --format '{{ json .Spec.Labels }}'
    
  3. Дальнейшие действия зависят от того, первая ли это установка приложения Compass на серверах или выполняете обновление имеющегося приложения.

    Если это первая установка основного сервера с нуля (ранее сервер не поднимался для установки приложения)

    На резервном сервере подключите сервер как вторую ноду к основному серверу.
    Выполните команду, полученную ранее при выполнении sudo docker swarm join-token manager:

    sudo docker swarm join --token <токен для присоединения ноды> <ip>:<port>
    

    Далее необходимо добавить лейбл reserve для ID резервной ноды.

    На резервном сервере получите список нод:

    sudo docker node ls
    

    Затем выполните команду для резервной ноды с отметкой *:

    sudo docker node update --label-add role=reserve <node id>
    

    На основном сервере выполните установку приложения:

    sudo python3 script/install.py
    

    Дождитесь завершения установки приложения на основном сервере.

    Если ранее приложение уже было установлено

    Выполните обновление основного сервера, чтобы применить изменения конфигурационного файла configs/replication.yaml:

    Примечание

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

    sudo python3 script/update.py
    

    Дождитесь завершения обновления основного сервера.

    Далее подключите резервный сервер как вторую ноду к основному серверу.
    Выполните на резервном сервере команду, полученную ранее при выполнении sudo docker swarm join-token manager:

    sudo docker swarm join --token <токен для присоединения ноды> <ip>:<port>
    

    Далее необходимо добавить лейбл reserve для ID резервной ноды.

    На резервном сервере получите список нод:

    sudo docker node ls
    

    Затем выполните команду для резервной ноды с отметкой *:

    sudo docker node update --label-add role=reserve <node id>
    

    На основном сервере создайте mysql-пользователя для репликации баз данных:

    sudo python3 script/replication/create_mysql_user.py --type monolith
    
    sudo python3 script/replication/create_mysql_user.py --type team
    

    Если у вас больше одной компании - выберете пункт «Все».

    На основном сервере запустите скрипт для старта репликации данных Manticore:

    Примечание

    В параметре master-mysql-server-id укажите значение поля mysql_server_id из конфигурационного файла configs/replication.yaml основного сервера

    sudo python3 script/replication/start_manticore_replication.py --type master --master-mysql-server-id 1 --need-update-company 1
    
  4. Скопируйте данные баз данных основного сервера на резервный.

    Для переноса данных на другой сервер требуется прокинуть ключ без passphrase с основного сервера на резервный.

    На основном сервере сгенерируйте ключ доступа, оставив passphrase пустым:

    ssh-keygen -t rsa -b 4096
    

    Затем на основном сервере выполните команду, чтобы скопировать созданный ключ на другой сервер, где:

    • remote_server_user — логин для подключения к резервному серверу;

    • remote_server_ip — IP-адрес резервного сервера.

    ssh-copy-id <remote_server_user>@<remote_server_ip>
    
  5. Для сохранения и отправки данных приложения на основном сервере необходимо выполнить скрипт script/backup_all_data.py из директории установщика.

    В скрипт передается параметр -dst, в котором:

    • remote_server_user — логин для подключения к резервному серверу;

    • remote_server_ip — IP-адрес резервного сервера;

    • remote_backup_folder — абсолютный путь до папки на резервном сервере, в которую необходимо сохранить копию данных (например, /home/compass_backup).

    Предупреждение

    Убедитесь, что директория remote_backup_folder имеет права для сохранения файлов от лица remote_server_user.

    sudo python3 script/backup_all_data.py \
       -dst remote_server_user@remote_server_ip:remote_backup_folder
    

    После выполнения скрипта резервная копия данных будет сохранена по пути remote_backup_folder на резервном сервере.

  6. На резервном сервере добавьте пользователя www-data, если тот отсутствует:

    sudo useradd -u 33 -g www-data -M -s /usr/sbin/nologin www-data
    
  7. На резервном сервере скопируйте данные приложения в новую директорию:

    sudo cp -a <remote_backup_folder>/compass /home/
    

    И поменяйте права для директорий:

    sudo chown -R root.root /home/compass; \
    sudo chown -R www-data.www-data /home/compass/company_configs; \
    sudo chown -R www-data.www-data /home/compass/default_file; \
    sudo chown -R www-data.www-data /home/compass/files; \
    sudo chown -R www-data.www-data /home/compass/tmp_files
    
  8. Скопируйте инсталлятор по новому пути (например, /home/on-premise/onpremise-installer) и перейдите в новую директорию с ним:

    mkdir -p <путь к новому инсталлятору>
    
    sudo cp -a /home/compass/installer/* <путь к новому инсталлятору>
    
    cd <путь к новому инсталлятору>
    
  9. Подготовьте скопированные конфигурационные файлы для дальнейшей работы:

    На резервном сервере в configs/global.yaml замените внутренний IP основного сервера на внутренний IP резервного:

    sudo sed -i 's/<внутренний ip основного сервера>/<внутренний ip резервного>/' configs/global.yaml
    
    # пример команды
    sudo sed -i 's/192.168.1.4/192.168.1.5/' configs/global.yaml
    

    Удалите файл с лейблом, скопированный с основного сервера:

    sudo rm -f .service_label
    

    В configs/global.yaml на резервном сервере замените порты, которые уже используются на основном сервере:

    sudo sed -i -e 's/domino.go_database_controller_port: 31101/domino.go_database_controller_port: 31111/' \
      -e 's/domino.service.manticore.external_port: 31102/domino.service.manticore.external_port: 31112/' \
      -e 's/jitsi.service.jicofo.port: 35001/jitsi.service.jicofo.port: 35011/' \
      -e 's/jitsi.service.prosody.serve_port: 35002/jitsi.service.prosody.serve_port: 35012/' \
      -e 's/jitsi.service.prosody.v0.serve_port: 35003/jitsi.service.prosody.v0.serve_port: 35013/' \
      -e 's/jitsi.service.prosody.v1.serve_port: 35004/jitsi.service.prosody.v1.serve_port: 35014/' \
      -e 's/jitsi.service.prosody.v2.serve_port: 35005/jitsi.service.prosody.v2.serve_port: 35015/' \
      -e 's/jitsi_web.service.jitsi_web.external_port: 31901/jitsi_web.service.jitsi_web.external_port: 31911/' \
      -e 's/monolith_nginx_port: 32100/monolith_nginx_port: 32110/' \
      -e 's/jitsi.service.web.https_port: 35000/jitsi.service.web.https_port: 35010/' \
    "configs/global.yaml"
    

    Добавьте порты 31111 и 31112 в разрешённые для фаервола:

    sudo ufw allow 31111
    sudo ufw allow 31112
    
  10. На резервном сервере откройте конфигурационный файл configs/replication.yaml для редактирования любым текстовым редактором и заполните поля:

    Примечание

    Установите лейблы, которые ранее добавляли в шаге установки лейблов для нод: «primary» (на основном сервере) и «reserve» (на резервном).

    # далее необходимо заполнить:
    # service_label — лейбл для обозначения сервисов сервера (основной, резервный).
    # Установите лейблы, которые ранее добавляли в шаге установки лейблов для нод: primary (на основном сервере) и reserve (на резервном).
    service_label: "reserve"
    
    # mysql_server_id — идентификатор mysql сервера.
    # Каждый новый сервер должен иметь отличный идентификатор от предыдущего.
    # Для основного сервера установите значение 1, для резервного — значение 2.
    mysql_server_id: 2
    
    # start_octet — используется для определения сабсети для сервисов. Для каждого нового сервера необходимо инкрементировать на 10.
    # Для основного сервера установите значение 10, для резервного — значение 20.
    start_octet: 20
    
  11. Замените значения в файле src/values.compass.yaml:

    Примечание

    В команду ниже подставьте те значение, которые указали в конфигурационном файле

    sudo sed -i -e 's/service_label: primary/service_label: reserve/' \
       -e 's/master_service_label: reserve/master_service_label: primary/' \
       -e 's/mysql_server_id: 1/mysql_server_id: 2/' \
       -e 's/start_octet: 10/start_octet: 20/' \
       -e 's/subnet: 172.39.11.0\/24/subnet: 172.39.20.0\/24/' \
    "src/values.compass.yaml"
    
  12. На резервном сервере запустите скрипт для восстановления данных.

    При запуске скрипта вам будет предложено:

    • Выбрать нужный бэкап из списка доступных копий.

    • Подтвердить удаление текущих данных и завершение работы приложения. Если на резервном сервере не было установлено приложение Compass, то ничего удалено не будет.

    sudo python3 script/restore_db.py --force-update-company-db 0
    

    Дождитесь завершение выполнение скрипта. После этого проверьте состояние развертывания с помощью команды:

    sudo docker service ls | grep reserve | grep -vE "default-file|jitsi-custom"
    
  13. Запустите скрипт для обновления портов в сервисе go_database на резервном сервере:

    sudo python3 script/replication/update_database_port.py
    
  14. На резервном сервере инвалидируйте порты, на которых были созданы компании:

    При запуске скрипта вам будет предложено:

    • Выбрать идентификатор сервера с базой данных. Если используется односерверная установка, выберите d1.

    • Выбрать порты, которые необходимо инвалидировать (выберите все по очереди).

    sudo docker exec -it $(sudo docker ps | grep php_monolith | awk '{print $1}') bash -c \
       "php src/Compass/Pivot/sh/php/domino/invalid_port_repairer.php"
    

    Примечание

    Если скрипт показывает, что порты с нужным статусом отсутствуют — пропустите этот пункт.

  15. Восстановите компании на резервном сервере:

    sudo python3 script/replication/repair_all_teams.py
    
  16. Запустите на резервном сервере скрипты для создания mysql-пользователя для репликации баз данных:

    Предупреждение

    Скрипты репликации баз данных НЕ работают с пользовательскими базами данных.

    sudo python3 script/replication/create_mysql_user.py --type monolith
    
    sudo python3 script/replication/create_mysql_user.py --type team
    

    Если у вас больше одной компании - выберете пункт «Все».

  17. Перед началом запуска репликации на резервном сервере выполните сброс репликации:

    sudo python3 script/replication/reset_slave_replication.py --type monolith
    
    sudo python3 script/replication/reset_slave_replication.py --type team
    

    Если у вас больше одной компании - выберете пункт «Все».

  18. Далее на резервном сервере запустите скрипты для старта репликации:

    sudo python3 script/replication/start_slave_replication.py --type monolith
    
    sudo python3 script/replication/start_slave_replication.py --type team
    

    Если у вас больше одной компании - выберете пункт «Все».

    Дождитесь завершения репликации.

    Если в выводе скрипта получаете «No» для одной из позиций (IO, SQL, или другое),
    значит репликация не может завершиться успешно. В этом случае рекомендуется использовать скрипты из раздела управление процессом отказоустойчивости.

  19. Затем на резервном сервере запустите скрипт для старта репликации данных Manticore:

    Примечание

    В параметре master-mysql-server-id укажите значение поля mysql_server_id из конфигурационного файла configs/replication.yaml основного сервера.

    sudo python3 script/replication/start_manticore_replication.py \
       --type reserve --master-mysql-server-id 1
    
  20. Для проверки состояния репликации на резервном сервере запустите команды:

    sudo python3 script/replication/show_slave_replication_status.py --type monolith
    
    sudo python3 script/replication/show_slave_replication_status.py --type team
    

    Внимание

    Перед выполнением переключения необходимо убедиться, что репликация завершила синхронизацию данных.
    Критерием готовности является значение поля Seconds_Behind_Master равное нулю, что указывает на отсутствие отставания реплики от мастера.

  21. На резервном сервере добавьте удалённый репозиторий к новому инсталлятору:

    git init
    git remote add origin https://github.com/getCompass/onpremise-installer.git
    git fetch
    git reset --hard origin/master
    git branch --set-upstream-to=origin/master master