Продукты Р7
Корпоративный сервер 2024
Корпоративный сервер 2024
Сервер документов
Сервер документов
Редакторы
Редакторы
Корпоративный сервер 2019
Корпоративный сервер 2019
Графика
Графика
Команда
Команда
Мобильные редакторы
Мобильные редакторы
Облачный офис
Облачный офис
Почта
Почта
Органайзер
Органайзер
Дополнительно
Часто задаваемые вопросы
Разработчикам
Интеграции
Новые возможности

Установка двухузловой архитектуры master-slave на РедОС

Обновлено: 24.12.25

Актуальная схема

Описание

Архитектура рассчитана на использование одного сервера как основной и второго сервера как запасной с постоянной репликацией. В случае отказа работы основного возможность ручного переключения на запасного с помощью скрипта и изменении ip адреса указывающего на основную ноду.

В архитектуре используются следующие компоненты и входят в состав стандартной установки Корпоративного сервера 2024:

  • PostgreSQL 12.22
  • RabbitMQ-Server 3.13.7
  • Redis Server 7.2.7
  • GlusterFS 11.1

Проверка осуществлялась на версии 2.0.2024.14752 Корпоративного сервера и сервера документов 2025.2.1.801.

Условия эксплуатации

1. При использовании одной доменной А записи с несколькими IP-адресами (с возможностью включения и выключения IP) или изменение доменной записи для Корпоративного сервера вида *.domain.ru, например:

*.test2.s7-office.site.

И отдельными записями для двух почтовых серверов (*опционально).

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

Команды связанные с почтовым сервером отмечены в статье.

3. При ошибках работы приложений на сервере master потребуется переключение сервера slave в режим master с помощью скрипта.

Технические требования

  • 2 Виртуальные машины;
  • Для хранения данных GlusterFS;
  • ТХ Машин, для тестирования, возможно использовать:
    от 4 CPU;
    от 8Гб RAM;
    от 50Гб свободного пространства на диске;
  • Более конкретные данные рассчитываются по обращению в ТП;
  • Отключение или перевод SELinux в режим permissive для корректной работы сервисов.
Важно

В состав дистрибутива Корпоративный сервер 2024 не включён модуль Р7 Графика. Для установки модуля Р7 Графика необходимо воспользоваться инструкциями, опубликованными в разделе: Р7 Графика > Установка ↗.

1. Установка и настройка сервиса хранения GlusterFS

Описание

Файловое хранилище:

  • Для почтового сервера будет использоваться каталог /mail
  • Корпоративный Сервер /var/r7-office/filestorage /var/r7-office/searchindex
  • Сервер документов /var/www/r7-office/Data /var/lib/r7-office/documentserver/App_Data/cache

Нет необходимости синхронизировать временных каталогов:

filestorage_temp
filestorage_temp_proc

База данных (БД):

Используется PostgreSQL версии 12 в режиме master-slave.

1.1. Установка и настройка glusterfs

Добавьте запись в /etc/hosts:

192.168.27.186 gluster1
192.168.26.253 gluster2
Важно

Рекомендуется использовать запись 127.0.0.1 localhost как стандартную и без использования имени сервера, так как в дальнейшем будут добавлены другие записи для работы почтового сервера.

Укажите соответствующее имя (поправить на свой домен и IP-адрес сервера), вместо mx1 можно использовать любое необходимое имя (например, mail):

Обратите внимание

Создание томов выполняется на сервере №1.

hostnamectl set-hostname mx1.your-domain.ru
Уточнение

Hostname сервера не совпадает с его доменом.

Например, server.example.com — полное имя домена, а server — его hostname.

Данная запись необходима для почтового сервера.

Без использования почтового сервера возможно задать любое имя сервера

Укажите соответствующее имя на сервере №2 для почтового сервера (поправить на свой домен):

Обратите внимание

Создание томов выполняется на сервере №2.

hostnamectl set-hostname mx2.your-domain.ru
Важно

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

Уточнение

Без использования почтового сервера возможно задать любое имя сервера.

1.2. На всех нодах установить, запустить и добавить в автозагрузку

dnf install -y glusterfs-server
systemctl start glusterd.service
systemctl enable glusterd.service

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

gluster peer probe gluster2

Фактически эта команда сообщает gluster1 доверять gluster2 и регистрирует его как часть пула хранения данных.

Если зондирование пройдет успешно, вы получите следующий вывод:

peer probe: success

Вы можете проверить связь узлов в любое время путем запуска команды:

gluster peer status

Если вы запустите эту команду из gluster2, вы увидите следующий вывод:

Number of Peers: 1

Hostname: gluster1

Uuid: 7ecfa2d1-3394-4f15-a1f5-bba484f2bbef

State: Peer in Cluster (Connected)
Важно

Рекомендуется на время установки/настройки отключить firewalld.

На этом этапе два ваших сервера взаимодействуют и готовы к созданию томов хранения друг с другом.

Обратите внимание

Создание томов выполняется на сервере №1.

Для создания тома вы будете использовать команду gluster volume create с таким общим синтаксисом:

sudo gluster volume create mail_volume replica 2 gluster{1,2}:/mail_volume force
sudo gluster volume create cddisk-filestorage replica 2 gluster{1,2}:/cddisk-filestorage force
sudo gluster volume create cddisk-searchindex replica 2 gluster{1,2}:/cddisk-searchindex force
sudo gluster volume create ds-data replica 2 gluster{1,2}:/ds-data force
sudo gluster volume create ds-cache replica 2 gluster{1,2}:/ds-cache force

Если том был создан успешно, вы увидите следующий вывод:

volume create: mail_volume: success: please start the volume to access data

На этом этапе ваш том создан, но еще не активирован.

Вы можете запустить том и сделать его доступным для использования путем выполнения следующей команды с любого сервера Gluster (для почтового сервера):

sudo gluster volume start mail_volume
sudo gluster volume start cddisk-filestorage
sudo gluster volume start cddisk-searchindex
sudo gluster volume start ds-data
sudo gluster volume start ds-cache

Вы получите следующий вывод, если том запущен корректно:

volume start: mail_volume: success

volume start: cddisk-filestorage: success

volume start: cddisk-searchindex: success

volume start: ds-data: success

volume start: ds-cache: success

Затем проверьте, находится ли том в сети. Запустите следующую команду с любого из ваших узлов:

sudo gluster volume status

В результате вы увидите вывод, аналогичный данному:

Status of volume: mail

Gluster process TCP Port RDMA Port Online Pid

------------------------------------------------------------------------------

Brick gluster1:/mail 49152 0 Y 4495

Brick gluster2:/mail 49152 0 Y 20192

Self-heal Daemon on localhost N/A N/A Y 4518

Self-heal Daemon on gluster2 N/A N/A Y 20215

Task Status of Volume mail_volume

------------------------------------------------------------------------------

There are no active volume tasks

Создайте каталог и смонтируйте:

Обратите внимание

Следующие инструкции выполняются на всех серверах (для почтового сервера).

mkdir /mail
mkdir -p /var/r7-office/filestorage
mkdir -p /var/r7-office/searchindex
mkdir -p /var/www/r7-office/Data
mkdir -p /var/lib/r7-office/documentserver/App_Data/cache


mount.glusterfs localhost:/mail_volume /mail
mount.glusterfs localhost:/cddisk-filestorage /var/r7-office/filestorage
mount.glusterfs localhost:/cddisk-searchindex /var/r7-office/searchindex
mount.glusterfs localhost:/ds-data /var/www/r7-office/Data
mount.glusterfs localhost:/ds-cache /var/lib/r7-office/documentserver/App_Data/cache

Добавьте в автозагрузку (для почтового сервера):

{
echo 'localhost:/mail_volume /mail glusterfs defaults,_netdev,backupvolfile-server=localhost 0 0'
echo 'localhost:/cddisk-filestorage /var/r7-office/filestorage glusterfs defaults,_netdev,backupvolfile-server=localhost 0 0'
echo 'localhost:/cddisk-searchindex /var/r7-office/searchindex glusterfs defaults,_netdev,backupvolfile-server=localhost 0 0'
echo 'localhost:/ds-data /var/www/r7-office/Data glusterfs defaults,_netdev,backupvolfile-server=localhost 0 0'
echo 'localhost:/ds-cache /var/lib/r7-office/documentserver/App_Data/cache glusterfs defaults,_netdev,backupvolfile-server=localhost 0 0'
} | sudo tee -a /etc/fstab

Добавьте задание для перезапуска GlusterFS, в случае перезагрузки или выключения питания:

Обратите внимание

Следующие инструкции выполняются на всех серверах.

Важно

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

echo "@reboot sleep 30 && systemctl restart glusterd.service" | crontab -

Проверка монтирования:

df -h
mount -a

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

При настройке разрешенных портов рекомендуется проверить все задействованные порты на двух серверах:

ss -tulnp | grep gluster

2. Подготовка к установке почтового сервера (*опционально)

2.1. Записи в DNS и необходимые конфигурации

Для почтового сервера необходимо сделать A и MX записи в виде:

# MX-записи

mx1 — 192.168.27.186
mx2 — 192.168.26.253

# А-записи

smtp — 192.168.27.186, 192.168.26.253
imap — 192.168.27.186, 192.168.26.253

Примеры А-записей:

А также TXT-запись v=spf1 +mx ~all.

TXT-запись v=spf1 +a +mx -all — говорит о том, что отправлять письма от имени домена your-domain.ru могут сервера, указанные в A и MX-записях этого домена, а письма, отправленные от других серверов должны быть удалены (Fail).

Важно

Важно понимать: SPF-запись не наследуется на поддомены.

2.2. Скопируйте репозиторий для возможности быстрого доступа к копированию и просмотру конфигурационных файлов

Обратите внимание

Следующие инструкции выполняются на всех серверах.

Скачайте архив:

wget https://download.r7-office.ru/mailserver/mailserver-rpm-config.tar.gz

И распакуйте его, чтобы каталог config и остальные файлы была после данной директории /mnt/mailserver/, чтобы было быстрее выполнять команды.

Например так:

tar -xzf mailserver-rpm-config.tar.gz -C /mnt
mv /mnt/mailserver-redos73-config /mnt/mailserver

Так как, далее примеры команд указаны с данным путём.

2.3 Установка для почтового сервера dovecot, postfix

dnf install postgresql-server postfix postfix-pgsql dovecot dovecot-pgsql dovecot-pigeonhole ca-certificates acl rsyslog

3. Установка и настройка БД

Установите следующие пакеты на оба сервера:

dnf install postgresql-server-12 postgresql-12

3.1. БД

Обратите внимание

Следующие инструкции выполняются на всех серверах.

Создайте первичный кластер базы данных:

sudo postgresql-setup --initdb
sudo systemctl enable --now postgresql

Отредактируйте /var/lib/pgsql/data/postgresql.conf:

listen_addresses = 'localhost,ip_srv1,ip_srv2'        # Слушать на адресах
port = 5432                                           # Задать порт БД
wal_level = replica                                   # Включить репликацию
archive_mode = on                                     # Включить архивирование WAL
archive_command = 'cp %p /var/lib/pgsql/archive/%f'   # Команда для архивирования WAL
max_wal_senders = 5                                   # Максимальное количество одновременных подключений репликации
wal_keep_segments = 50                                # Количество WAL-сегментов для хранения
hot_standby = on                                      # Разрешить подключения в режиме hot standby

Где, ip_srv1, ip_srv2 — адреса внутренней сети первого и второго почтового сервера.

Обратите внимание

Следующие инструкции выполняются на всех серверах.

В файле postgresql.conf разрешите логическую репликацию, добавляем строку для прослушивания локального интерфейса:

/var/lib/pgsql/data/pg_hba.conf

Привести к виду:

# Разрешить локальные подключения для всех пользователей
# "local" is for Unix domain socket connections only
local   all             all                              trust
# IPv4 local connections:
host    all             all             127.0.0.1/32     trust
host    all             all             ip_srv1/32       trust
host    all             all             ip_srv2/32       trust

Вместо ip_srv1/32 и ip_srv2/32 укажите IP-адрес двух серверов. Режим trust необходим для установки Корпоративного сервера.

Для возможности репликации БД добавьте строки в конце:

# Разрешить репликацию с обоих серверов для пользователя replication_user
host    replication     replication_user        ip_srv1/32    md5
host    replication     replication_user        ip_srv2/32    md5

Где, ip_another_srv/32 — адрес первого или второго почтового сервера, в зависимости от сервера где производится настройка.

Выполните перезапуск сервиса БД:

sudo systemctl restart postgresql
Обратите внимание

Следующие инструкции выполняются на сервере №1.

После базовой настройки базы данных, создаем необходимую структуру в БД, создаем пользователей и настраиваем репликацию:

sudo -u postgres psql

В консоли psql выполните следующие команды, подтверждая каждую нажатием Enter:

Важно

Вместо паролей password и replication_password, cddisk и ds задайте свои пароли.

В поле insert into вместо YOUR_DOMAIN укажите реальный адрес вашего домена.

Важно

Не рекомендуется использовать другие имена для баз данных cddisk и ds.

CREATE USER cddisk WITH password 'cddisk';
CREATE USER ds WITH password 'ds';
CREATE DATABASE cddisk OWNER cddisk;
CREATE DATABASE ds OWNER ds;
GRANT ALL privileges ON DATABASE cddisk TO cddisk;
GRANT ALL privileges ON DATABASE ds TO ds;
CREATE USER replication_user WITH REPLICATION LOGIN PASSWORD 'replication_password';
GRANT CONNECT ON DATABASE cddisk TO replication_user;
GRANT CONNECT ON DATABASE ds TO replication_user;


\c cddisk
GRANT USAGE ON SCHEMA public TO replication_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO replication_user;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO replication_user;


\c ds
GRANT USAGE ON SCHEMA public TO replication_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO replication_user;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO replication_user;

# Для выхода из БД:
\q

Для почтового сервера:

CREATE DATABASE postfix ENCODING 'UTF-8';
CREATE USER postfix WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE postfix TO postfix;
GRANT CONNECT ON DATABASE postfix TO replication_user;


\c postfix;


CREATE TABLE virtual_domains (
    id serial PRIMARY KEY,
    name varchar(50) NOT NULL
);


CREATE TABLE virtual_users (
    id serial PRIMARY KEY,
    domain_id int NOT NULL,
    password varchar(106) NOT NULL,
    email varchar(120) NOT NULL,
    quota bigint DEFAULT NULL,
    UNIQUE (email),
    FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
);


CREATE TABLE virtual_aliases (
    id serial PRIMARY KEY,
    domain_id int NOT NULL,
    source varchar(100) NOT NULL,
    destination varchar(100) NOT NULL,
    FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
);


GRANT ALL PRIVILEGES ON TABLE virtual_domains TO postfix;
GRANT ALL PRIVILEGES ON TABLE virtual_users TO postfix;
GRANT ALL PRIVILEGES ON TABLE virtual_aliases TO postfix;
GRANT ALL PRIVILEGES ON SEQUENCE virtual_domains_id_seq TO postfix;
GRANT ALL PRIVILEGES ON SEQUENCE virtual_users_id_seq TO postfix;
GRANT ALL PRIVILEGES ON SEQUENCE virtual_aliases_id_seq TO postfix;
GRANT USAGE ON SCHEMA public TO replication_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO replication_user;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO replication_user;


INSERT INTO virtual_domains (name) VALUES ('YOUR_DOMAIN');

# Для выхода из БД:
\q
Обратите внимание

Следующие инструкции выполняются на сервере №1.

Создайте директорию для архива:

sudo mkdir /var/lib/pgsql/archive
sudo chown -R postgres: /var/lib/pgsql/archive
sudo chmod -R 750 /var/lib/pgsql/archive
Обратите внимание

Следующие инструкции выполняются на сервере №1.

Перезагрузите службу PostgreSQL для применения изменений:

systemctl restart postgresql

3.2. Настройка репликации БД

Обратите внимание

Следующие инструкции выполняются на сервере №2.

Удалите существующую директорию данных:

rm -rf /var/lib/pgsql/data

Создайте базовую резервную копию с мастера:

su — postgres -c "pg_basebackup --host=ip_srv1 --username=replication_user --pgdata=/var/lib/pgsql/data --wal-method=stream --write-recovery-conf"

Где, ip_srv1 — адрес внутренней сети первого сервера, с master БД.

Перезапустите сервис и проверьте его статус:

systemctl restart postgresql.service
systemctl status postgresql.service

4. Настройка почтового сервера (*опционально)

4.1. Конфигурация Postfix.

Обратите внимание

Следующие инструкции выполняются на всех серверах.

Для настройки Postfix, внесите изменения (сменив домен на свой), скопируйте файл /etc/postfix/main.cf:

Уточнение

Все конфигурационные файлы задействованные при установки находятся в mailserver / config gitlab.

yes | cp /mnt/mailserver/config/main_pgsql.cf /etc/postfix/main.cf

Необходимо поправить параметры в файле /etc/postfix/main.cf, в строках:

myhostname = mx1.domain.ru
mydomain = domain.ru

Где:

  • mx1.domain.ru — А запись почтового сервера в DNS;
  • domain.ru — ваш домен.

Скопируйте файл конфигурации /etc/postfix/master.cf:

yes | cp /mnt/mailserver/config/master.cf /etc/postfix

Скопируйте и отредактируйте конфигурационные файлы, при помощи которых Postfix сможет обращаться к базе данных PostgreSQL:

Важно

Если пользователь с правами в БД был добавлен иной, не postfix, учитывайте это и измените пароль после копирования этих файлов, необходимо отредактировать параметр password, который в п.2.12 указали отличный от password.

mkdir -p /etc/postfix/pgsql
cp -a /mnt/mailserver/config/pgsql/. /etc/postfix/pgsql/
find /etc/postfix/pgsql -type d -exec chmod 750 {} \;
find /etc/postfix/pgsql -type f -exec chmod 640 {} \;


sudo vi /etc/postfix/pgsql/virtual_alias_maps.cf
sudo vi /etc/postfix/pgsql/virtual_mailbox_domains.cf
sudo vi /etc/postfix/pgsql/virtual_mailbox_maps.cf

Необходимо положить или сгенерировать сертификаты домена.

Обратите внимание

Для установки потребуется wildcard сертификат, содержащий полную цепочку (fullchain)

Например:

—-BEGIN CERTIFICATE——
(Your Primary SSL certificate: your_domain_name.crt)
——END CERTIFICATE——
——BEGIN CERTIFICATE——
(Your Intermediate certificate: DigiCertCA.crt)
——END CERTIFICATE——
——BEGIN CERTIFICATE——
(Your Root certificate: TrustedRoot.crt)
——END CERTIFICATE——

Где:

Основной Certificate — your_domain_name.crt
Промежуточный Certificate — DigiCertCA.crt
Корневой Certificate — TrustedRoot.crt

Вам необходимо положить сертификаты по пути /etc/ssl/.

Где:

  • mail_cert.pem — ключ с полной цепочкой сертификатов;
  • mail_key.pem — закрытый ключ.

Скопируйте файл tls_policy_maps, с помощью которого можно вручную задавать версию tls протокола для общения серверов, либо полностью отключать его. Это иногда бывает нужно, если подключаешься к очень старому серверу, который не поддерживает современные протоколы. Приходится использовать нешифрованное подключение:

cp /mnt/mailserver/config/tls_policy_maps /etc/postfix/
postmap /etc/postfix/tls_policy_maps

Настройте работу SMTP-сервера для работы и поменяйте права на файлы. Создайте папку etc для Postfix и скопируйте файлы:

mkdir /var/spool/postfix/etc
cp /etc/host.conf /var/spool/postfix/etc/
cp /etc/resolv.conf /var/spool/postfix/etc/
cp /etc/services /var/spool/postfix/etc/

Измените права в файлах /etc/resolv.conf и /var/pool/postfix/etc/ на 1777:

chmod 1777 /etc/resolv.conf
chmod 1777 -R /var/spool/postfix/etc
systemctl restart postfix.service

4.2. Интеграция служб Dovecot

Обратите внимание

Следующие инструкции выполняются на всех серверах.

Создайте специализированную группу и пользователя для работы с Dovecot с указанными в конфиге uid 1100:

Важно

Если у вас уже занят этот uid, то везде замените его на другой или удалите пользователя с uid 1100, если он вам не нужен.

groupadd -g 1100 vmail
sudo useradd -d /mail -g 1100 -u 1100 vmail
usermod -a -G dovecot vmail
chown vmail:vmail /mail

Скопируйте и отредактируйте конфигурационный файл /etc/dovecot/dovecot.conf, в который впишете настройки сервиса (меняем домен в строке auth_default_realm = ):

Важно

Обратите внимание, что сертификат из переменных ssl_key и ssl_cert будет использоваться тот же самый, который был сгенерирован для Postfix.

yes | cp /mnt/mailserver/config/dovecot_pgsql.conf /etc/dovecot/dovecot.conf
sudo vi /etc/dovecot/dovecot.conf

Замените параметр в строке:

auth_default_realm = domain.ru

Скопируйте и отредактируйте конфигурацию для подключения к базе данных PostgreSQL:

cp /mnt/mailserver/config/dovecot-pgsql.conf /etc/dovecot/ && chmod 640 /etc/dovecot/dovecot-pgsql.conf
sudo vi /etc/dovecot/dovecot-pgsql.conf

Замените параметр в строке:

password=<пароль из п.3.1>

Так же потребуется скопировать и отредактировать параметр:

cp /mnt/mailserver/config/dovecot-dict-sql.conf.ext /etc/dovecot/ && chmod 640 /etc/dovecot/dovecot-dict-sql.conf.ext
sudo vi /etc/dovecot/dovecot-dict-sql.conf.ext

Замените параметр в строке:

password=<пароль из п.3.1>

Создайте директорию и файлы для логов:

mkdir /var/log/dovecot
touch /var/log/dovecot/{main.log,info.log,debug.log,lda-errors.log,lda-deliver.log,lmtp.log}
chown -R vmail:dovecot /var/log/dovecot

Создайте служебную папку для плагина acl:

mkdir /mail/shared-folders
chown -R vmail:vmail /mail

На этом основная настройка почтового сервера на базе Postfix и Dovecot завершена.

Можно запускать службы и проверять работу системы:

sudo postfix check
systemctl reload postfix
systemctl start dovecot
systemctl enable postfix
systemctl enable dovecot

4.3. Создание почтовых ящиков

Обратите внимание

Следующие инструкции выполняются на сервере с master БД.

Создайте файл паролей для PostgreSQL и поменяйте права на него:

awk -F '[= ]+' 'BEGIN {OFS=":"} /^connect/ {print "127.0.0.1", "5432", $5, $7, $9}' /etc/dovecot/dovecot-pgsql.conf >> ~/.pgpass 
chmod 600 .pgpass

Скачайте каталог скриптов:

wget https://download.r7-office.ru/mailserver/operations_mailserver_db-pgsql.tar.gz

Распакуйте архив, например так:

tar -xzf operations_mailserver_db-pgsql.tar.gz

Команда указанная ниже, как пример, создания пользователя:

bash operations_mailserver_db-pgsql-mailserver/mailserver/create_user.sh user@your-domain.ru password

Запустите скрипт на создание почтового ящика:

bash /script/mailserver/create_user.sh user@your-domain.ru password

Где, вместо user@your-domain.ru указываете необходимое наименование для почтового ящика, а также вместо password указываете пароль для него.

Разрешается использовать только те спецсимволы при установке пароля, что указаны ниже:

~ @ # % ^ * _ + = - ? : { } [ ] \ /

5. Установка Корпоративного сервера

Уточнение

Выполнение установки производится по инструкции: Установка Корпоративного сервера 2024 на РЕД ОС ↗.

Обратите внимание

Следующие инструкции выполняются на сервере №1.

5.1. Предварительная подготовка

Скачайте дистрибутив и рекомендуем, для корректной установки, архив разместите в директории, отличной от /root, например в /mnt или /tmp.

Перейдите в каталог:

cd /mnt

Распакуйте архив:

unzip RedOS_*.zip

Для корректной работы Корпоративного сервера обязательно требуется настройка HTTPS. Перед установкой скопируйте crt и key файлы в папку sslcert.

Предоставьте права на скрипт установки:

chmod +x online_installer.sh

Создайте DNS запись для Корпоративного сервера, например:

5.2 Запуск установки первого сервера

Выполните команду:

sudo bash ./online_installer.sh

Выберите «Нет»:

Выберите «Нет»:

Выберите «Да»:

Задайте secret. Необходимо ввести секрет (Набор цифр, букв и спецсимволов. Длина от 8 символов) для защищённого доступа Р7 Диска и Сервера Документов:

Укажите пароль к БД ds, ранее созданного в пункте 3.1 (из примера: ds):

Выберите «Да»:

Выберите «postgresql»:

Выберите «Нет»:

Укажите БД master и IP-адрес текущего первого сервера:

Укажите по умолчанию порт 5432:

Укажите БД cddisk из пункта 3.1 (из примера: cddisk):

Укажите пароль к БД cddisk из пункта 3.1 (из примера: cddisk):

Измените на актуальный, если есть Р7 Офис Корпоративный сервер 2019 и нажмите «ОК»:

Выберите «Да»:

Необходимо указать домен, в котором у вас созданы записи из пункта подготовки:

Далее укажите необходимые префиксы для всех модулей.

Выберите «Нет»:

Перезапустите сервер.

5.3. Установка второго сервера

Обратите внимание

Следующие инструкции выполняются на сервере №2.

Скачайте дистрибутив и рекомендуем, для корректной установки, архив разместите в директории, отличной от /root, например в /mnt или /tmp:

Перейдите в каталог :

cd /mnt

Распакуйте архив:

unzip RedOS_*.zip
Важно

Для корректной работы Корпоративного сервера обязательно требуется настройка HTTPS. Перед установкой скопируйте crt и key файлы в папку sslcert.

Предоставьте права на скрипт установки:

chmod +x online_installer.sh

5.4. Запуск установки

Выполните команду:

sudo bash ./online_installer.sh

Выберите «Нет»:

Выберите «Нет»:

Выберите «Да»:

Укажите такой же secret как для первого сервера:

Укажите пароль к БД ds из пункта 2.2.1 (из примера: ds):

Выберите «Да»:

Выберите «postgresql»:

Выберите «Нет»:

Укажите IP-адрес первого сервера master:

Укажите порт 5432:

Укажите БД cddisk из пункта 3.1 (из примера: cddisk):

Укажите пароль к БД cddisk из пункта 3.1 (из примера: cddisk):

Измените на актуальный, если есть Р7 Офис Корпоративный сервер 2019 и нажмите «ОК»:

Выберите «Да»:

Необходимо указать домен, в котором у вас созданы записи из пункта подготовки:

Далее укажите необходимые префиксы для всех модулей.

Выберите «Нет»:

Перезапустите сервер.

6. Выполните дополнительную настройку Nginx и Сервер документов

Выведите значение параметра secure_link_secret на первом сервере:

grep -rn "set \$secure_link_secret" /etc/r7-office/documentserver/nginx/ds.conf

Пример вывода:

13: set $secure_link_secret kCj7RMAAYCNtOh6KiGin;

Для второго сервера:

sudo sed -i "s/set \$secure_link_secret [^;]*/set \$secure_link_secret НОВОЕ_ЗНАЧЕНИЕ/" $(grep -rl "set \$secure_link_secret" /etc/r7-office/documentserver/)
sudo sed -i "s/set \$secretString [^;]*/set \$secretString НОВОЕ_ЗНАЧЕНИЕ/" $(grep -rl "set \$secretString" /etc/r7-office/documentserver/)
Важно

Где замените НОВОЕ_ЗНАЧЕНИЕ на необходимый параметр c вывода предыдущей команды.

Пример: kCj7RMAAYCNtOh6KiGin.

Выполните команды по перезапуску Nginx и Сервера документов:

systemctl restart nginx ds-converter.service ds-docservice.service ds-metrics.service

7. Настройка подключения почтового сервера (*опционально)

Перейдите в https://admin.{ВАШ_ДОМЕН} Организации — Выберите организацию, в которую добавлены пользователи — Почтовые серверы:

Укажите ранее добавленные данные по почтовому серверу:

В таком случае управлять почтовыми ящиками можно через консоль сервера.

Обратите внимание

Интеграция с почтовым сервером не поддерживается из-за наличия конфликтов двух одинаковых записей доменов.

8. Управление переключением БД при неработоспособности первого сервера

8.1. Создайте скрипт управления

Укажите необходимые константы в начале скрипта. Потребуется указать необходимые параметры, что является master (первый сервер) и slave (второй сервер).

Параметры указанные ранее в пункте 3.1:

Константы для подключения к БД:

  • MASTER_IP="192.168.27.186" — укажите адрес master БД;
  • SLAVE_IP="192.168.26.253" — укажите адрес replica БД;
  • REPLICATION_USER="replication_user" — укажите пользователя для репликации;
  • REPLICATION_PASS="replication_password" — пароль от пользователя для репликации;
  • LOG_FILE="/var/log/switch_postgres.log" — расположение файла логирования скрипта.

Константы для cddisk (appsettings.json):

  • CDDISK_DB_NAME="cddisk" — не рекомендуется изменять;
  • CDDISK_DB_USER="cddisk" — укажите пользователя КС;
  • CDDISK_DB_PASS="cddisk" — укажите пароль для пользователя КС;
  • CDDISK_DB_PORT="5432" — укажите порт БД.

Константы для documentserver (local.json):

  • DS_DB_NAME="ds" — не рекомендуется изменять;
  • DS_DB_USER="ds" — укажите пользователя ДС;
  • DS_DB_PASS="ds" — укажите пароль для пользователя ДС;
  • DS_DB_PORT="5432" — укажите порт БД.
#!/bin/bash


# === Константы для подключения к БД ===
MASTER_IP="192.168.27.186"
SLAVE_IP="192.168.26.253"
REPLICATION_USER="replication_user"
REPLICATION_PASS="replication_password"
LOG_FILE="/var/log/switch_postgres.log"


# === Константы для cddisk (appsettings.json) ===
CDDISK_DB_NAME="cddisk"
CDDISK_DB_USER="cddisk"
CDDISK_DB_PASS="cddisk"
CDDISK_DB_PORT="5432"


# === Константы для documentserver (local.json) ===
DS_DB_NAME="ds"
DS_DB_USER="ds"
DS_DB_PASS="ds"
DS_DB_PORT="5432"


function log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') — $1" | tee -a "$LOG_FILE"
}


function check_superuser() {
    if [[ $EUID -ne 0 ]]; then
        log "Ошибка: Скрипт должен запускаться от root."
        exit 1
    fi
}


function get_local_ip() {
    hostname -I | awk '{print $1}'
}


function is_master() {
    [[ "$(get_postgres_role)" == "master" ]]
}


function is_slave() {
    [[ "$(get_postgres_role)" == "slave" ]]
}


function backup_file_if_needed() {
    local file="$1"
    local bak_file="${file}.bak"


    if [[ ! -f "$bak_file" ]]; then
        cp "$file" "$bak_file"
        log "Создана резервная копия: $bak_file"
    fi
}


function restore_from_backup() {
    local file="$1"
    local bak_file="${file}.bak"


    if [[ -f "$bak_file" ]]; then
        log "Восстановление файла $file из резервной копии..."
        cp "$bak_file" "$file"
    else
        log "⚠️ Резервная копия для $file не найдена. Пропущено."
    fi
}


function restore_all_configs() {
    log "Начало восстановления конфигураций из резервных копий..."


    local files=(
        "/opt/r7-office/Api/appsettings.json"
        "/opt/r7-office/Sso.Api/appsettings.json"
        "/opt/r7-office/Processing/appsettings.json"
        "/etc/r7-office/documentserver/local.json"
    )


    for file in "${files[@]}"; do
        restore_from_backup "$file"
    done


    log "✅ Восстановление завершено."
}


function extract_cddisk_db_credentials() {
    local file="/opt/r7-office/Api/appsettings.json"


    if [[ ! -f "$file" ]]; then
        log "Файл $file не найден."
        return 1
    fi


    # Извлекаем строку подключения
    local line
    line=$(grep -A2 '"R7StorageServerUserActions"' "$file" | tr -d '
')
    if [[ -z "$line" ]]; then
        log "Строка R7StorageServerUserActions не найдена в $file"
        return 1
    fi


    local conn_str
    conn_str=$(echo "$line" | sed -E 's/.*"R7StorageServerUserActions"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')


    if [[ -z "$conn_str" ]]; then
        log "Не удалось извлечь строку подключения из $file"
        return 1
    fi


    DB_NAME=$(echo "$conn_str" | grep -oP 'Database=\K[^;]+')
    DB_USER=$(echo "$conn_str" | grep -oP 'Username=\K[^;]+')
    DB_PASS=$(echo "$conn_str" | grep -oP 'Password=\K[^;]+')
    DB_HOST=$(echo "$conn_str" | grep -oP 'Host=\K[^;]+')
    DB_PORT=$(echo "$conn_str" | grep -oP 'Port=\K[^;]*')


    DB_PORT="${DB_PORT:-5432}"


    if [[ -z "$DB_NAME" || -z "$DB_HOST" ]]; then
        log "В строке подключения отсутствуют необходимые параметры (Database и Host)."
        return 1
    fi


    export DB_NAME DB_USER DB_PASS DB_HOST DB_PORT
}


function extract_documentserver_db_credentials() {
    local config="/etc/r7-office/documentserver/local.json"


    if [[ ! -f "$config" ]]; then
        log "⚠️ Файл $config не найден."
        return 1
    fi


    DS_DB_HOST=$(grep '"dbHost"' "$config" | awk -F '"' '{print $4}')
    DS_DB_NAME=$(grep '"dbName"' "$config" | awk -F '"' '{print $4}')
    DS_DB_USER=$(grep '"dbUser"' "$config" | awk -F '"' '{print $4}')
    DS_DB_PASS=$(grep '"dbPass"' "$config" | awk -F '"' '{print $4}')
    DS_DB_PORT=$(grep '"dbPort"' "$config" | awk -F '"' '{print $4}')


    DS_DB_PORT="${DS_DB_PORT:-5432}"


    if [[ -z "$DS_DB_HOST" || -z "$DS_DB_USER" || -z "$DS_DB_PASS" ]]; then
        log "⚠️ В файле local.json отсутствуют данные для подключения к БД."
        return 1
    fi


    export DS_DB_HOST DS_DB_NAME DS_DB_USER DS_DB_PASS DS_DB_PORT
}


function check_db_connection_after_change() {
    local new_master="$1"
    log "Проверка подключения к БД с новыми параметрами..."


    # === cddisk: используем константы с обновлённым Host ===
    local db_name="$CDDISK_DB_NAME"
    local db_user="$CDDISK_DB_USER"
    local db_pass="$CDDISK_DB_PASS"
    local db_host="$new_master"
    local db_port="${CDDISK_DB_PORT:-5432}"


    log "Попытка подключения (cddisk): Host=$db_host, User=$db_user, Database=$db_name, Port=$db_port"
    echo "$db_pass" | PGPASSWORD="$db_pass" psql -h "$db_host" -U "$db_user" -p "$db_port" -d "$db_name" -c "\q" > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        log "✅ Успешное подключение к cddisk"
    else
        log "❌ Не удалось подключиться к cddisk"
        return 1
    fi


    # === documentserver: используем DS_* константы с обновлённым Host ===
    local ds_name="$DS_DB_NAME"
    local ds_user="$DS_DB_USER"
    local ds_pass="$DS_DB_PASS"
    local ds_host="$new_master"
    local ds_port="${DS_DB_PORT:-5432}"


    log "Попытка подключения (documentserver): Host=$ds_host, User=$ds_user, Database=$ds_name, Port=$ds_port"
    echo "$ds_pass" | PGPASSWORD="$ds_pass" psql -h "$ds_host" -U "$ds_user" -p "$ds_port" -d "$ds_name" -c "\q" > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        log "✅ Успешное подключение к documentserver"
    else
        log "❌ Не удалось подключиться к documentserver"
        return 1
    fi


    return 0
}


function check_db_connection() {
    log "Проверка подключения к БД с текущими параметрами..."


    # === cddisk ===
    if extract_cddisk_db_credentials; then
        local db_host="$DB_HOST"
        local db_name="$DB_NAME"
        local db_user="$DB_USER"
        local db_pass="$DB_PASS"
        local db_port="${DB_PORT:-5432}"


        log "Попытка подключения (cddisk): Host=$db_host, User=$db_user, Database=$db_name, Port=$db_port"


        echo "$db_pass" | PGPASSWORD="$db_pass" psql -h "$db_host" -U "$db_user" -p "$db_port" -d "$db_name" -c "SELECT version();" > /dev/null 2>&1


        if [ $? -eq 0 ]; then
            log "Успешное подключение к БД от пользователя $db_user"
        else
            log "Не удалось подключиться к БД от пользователя $db_user. Проверьте настройки доступа или пароль."
        fi
    else
        log "⚠️ Пропущена проверка cddisk: не удалось получить данные из appsettings.json"
    fi


    # === documentserver ===
    if extract_documentserver_db_credentials; then
        local ds_host="$DS_DB_HOST"
        local ds_name="$DS_DB_NAME"
        local ds_user="$DS_DB_USER"
        local ds_pass="$DS_DB_PASS"
        local ds_port="$DS_DB_PORT"


        log "Попытка подключения (documentserver): Host=$ds_host, User=$ds_user, Database=$ds_name, Port=$ds_port"


        echo "$ds_pass" | PGPASSWORD="$ds_pass" psql -h "$ds_host" -U "$ds_user" -p "$ds_port" -d "$ds_name" -c "SELECT version();" > /dev/null 2>&1


        if [ $? -eq 0 ]; then
            log "Успешное подключение к БД от пользователя $ds_user"
        else
            log "Не удалось подключиться к БД от пользователя $ds_user. Проверьте настройки доступа или пароль."
        fi
    else
        log "⚠️ Пропущена проверка documentserver: не удалось получить данные из local.json"
    fi


    return 0
}


function update_cddisk_configs() {
    local new_master="$1"
    log "Обновление appsettings.json для cddisk на новый мастер: $new_master..."


    # Формируем новые строки подключения с новым IP
    local conn_user_actions="Database=$CDDISK_DB_NAME;Username=$CDDISK_DB_USER;Password=$CDDISK_DB_PASS;Host=$new_master;Port=$CDDISK_DB_PORT;"
    local conn_server="Database=$CDDISK_DB_NAME;Username=$CDDISK_DB_USER;Password=$CDDISK_DB_PASS;Host=$new_master;Port=$CDDISK_DB_PORT;"


    local files=(
        "/opt/r7-office/Api/appsettings.json"
        "/opt/r7-office/Sso.Api/appsettings.json"
        "/opt/r7-office/Processing/appsettings.json"
    )


    for file in "${files[@]}"; do
        if [[ ! -f "$file" ]]; then
            log "⚠️ Файл $file не найден, пропущено."
            continue
        fi


        backup_file_if_needed "$file"


        # === R7StorageServerUserActions ===
        local old_line=$(grep -A2 '"R7StorageServerUserActions"' "$file" | tr -d '
')
        if [[ -n "$old_line" ]]; then
            log "Старая строка (R7StorageServerUserActions): $old_line"
            sed -i "s|\"R7StorageServerUserActions\": *\"[^\"]*\"|\"R7StorageServerUserActions\": \"$conn_user_actions\"|" "$file"
            if [[ $? -eq 0 ]]; then
                log "✅ R7StorageServerUserActions в $file обновлён"
            else
                log "❌ Ошибка при обновлении R7StorageServerUserActions в $file"
            fi
        else
            log "⚠️ R7StorageServerUserActions не найден в $file"
        fi


        # === R7StorageServer ===
        local old_line=$(grep -A2 '"R7StorageServer"' "$file" | tr -d '
')
        if [[ -n "$old_line" ]]; then
            log "Старая строка (R7StorageServer): $old_line"
            sed -i "s|\"R7StorageServer\": *\"[^\"]*\"|\"R7StorageServer\": \"$conn_server\"|" "$file"
            if [[ $? -eq 0 ]]; then
                log "✅ R7StorageServer в $file обновлён"
            else
                log "❌ Ошибка при обновлении R7StorageServer в $file"
            fi
        else
            log "⚠️ R7StorageServer не найден в $file"
        fi
    done
}


function update_documentserver_config() {
    local new_master="$1"
    local config="/etc/r7-office/documentserver/local.json"
    if [[ ! -f "$config" ]]; then
        log "⚠️ Файл $config не найден, пропущено."
        return 1
    fi
    backup_file_if_needed "$config"


    current_host=$(grep '"dbHost"' "$config" | awk -F '"' '{print $4}')
    if [[ "$current_host" == "$new_master" ]]; then
        log "IP-адрес в $config уже актуален ($new_master). Изменение не требуется."
        return 0
    fi


    log "Старый dbHost: $current_host"
    sed -i "s/\"dbHost[^\"]*\": *\"[^\"]*\"/\"dbHost\": \"$new_master\"/" "$config"
    if [[ $? -eq 0 ]]; then
        log "dbHost в $config успешно обновлён на $new_master"
    else
        log "❌ Ошибка обновления $config"
    fi
}


function restart_supervisor_services() {
    log "Перезапуск supervisor-сервисов..."
    supervisorctl restart all
}


function restart_documentserver_services() {
    log "Перезапуск ds-сервисов..."


    local prepare_script="/usr/bin/documentserver-prepare4shutdown.sh"


    if [[ -f "$prepare_script" ]]; then
        log "Выполняется подготовительный скрипт: $prepare_script..."
        "$prepare_script"
        if [[ $? -eq 0 ]]; then
            log "Подготовительный скрипт выполнен успешно."
        else
            log "⚠️ Подготовительный скрипт завершился с ошибкой. Продолжить перезапуск? (y/n)"
            read -p "Продолжить? " confirm
            [[ "$confirm" != "y" && "$confirm" != "Y" ]] && log "Перезапуск отменён пользователем." && return 1
        fi
    else
        log "⚠️ Подготовительный скрипт $prepare_script не найден. Пропущено."
    fi


    local services=(
        "ds-converter.service"
        "ds-docservice.service"
        "ds-metrics.service"
    )


    for service in "${services[@]}"; do
        if systemctl is-active --quiet "$service"; then
            log "Перезапуск $service..."
            systemctl daemon-reload > /dev/null 2>&1
            systemctl restart "$service"
            log "$service перезапущен."
        else
            if systemctl list-units --type=service | grep -q "$service"; then
                log "⚠️ Сервис $service найден, но не активен. Пропущено."
            else
                log "⚠️ Сервис $service не найден. Проверьте установку документ-сервера."
            fi
        fi
    done


    log "✅ Все актуальные ds-сервисы перезапущены."
}


function promote_slave_to_master() {
    log "Продвижение slave в master..."


    local pg_data="/var/lib/pgsql/data"
    if [[ ! -f "$pg_data/standby.signal" && ! -f "$pg_data/recovery.signal" ]]; then
        log "⚠️ Сервер не находится в режиме standby. Пропущено продвижение в master."
        return 0
    fi


    sudo -u postgres pg_ctl promote -D "$pg_data"
    if [ $? -eq 0 ]; then
        log "✅ Slave успешно переведён в режим master."
    else
        log "⚠️ Не удалось продвинуть в master (возможно, уже является master)."
    fi
}


function switch_to_slave_as_master() {
    log "Начало процесса переключения slave -> master..."
    log "Используем MASTER_IP = $MASTER_IP из констант."


    # Проверяем доступность БД с новым IP
    check_db_connection_after_change "$MASTER_IP"


    # Продвигаем в master (работает только если standby.signal существует)
    promote_slave_to_master


    # Обновляем конфиги приложений
    update_cddisk_configs "$MASTER_IP"
    update_documentserver_config "$MASTER_IP"


    # Перезапуск сервисов
    restart_supervisor_services
    restart_documentserver_services


    log "✅ Сервер переведён в режим master."
}


function switch_to_master_as_slave() {
    log "Начало процесса переключения master -> slave..."
    log "Используем MASTER_IP = $MASTER_IP для создания реплики."
    read -p "Вы уверены, что хотите сделать этот сервер slave? Это очистит данные. (y/n): " confirm
    [[ "$confirm" != "y" ]] && log "Операция отменена пользователем." && exit 1


    # Убираем запрос пароля — используем REPLICATION_PASS из констант
    if [[ -z "$REPLICATION_PASS" ]]; then
        log "❌ Пароль не может быть пустым."
        exit 1
    fi


    log "Остановка PostgreSQL..."
    systemctl stop postgresql


    log "Очистка каталога данных PostgreSQL..."
    rm -rf /var/lib/pgsql/data/*
    mkdir -p /var/lib/pgsql/data


    log "Создание новой реплики с мастера: $MASTER_IP..."


    # Передаем пароль через PGPASSWORD вместо stdin
    sudo -u postgres env PGPASSWORD="$REPLICATION_PASS" pg_basebackup \
        -h "$MASTER_IP" \
        -D /var/lib/pgsql/data \
        -U "$REPLICATION_USER" \
        -P -R


    if [ $? -ne 0 ]; then
        log "❌ Ошибка при создании реплики. Проверьте доступность мастера и учётные данные."
        exit 1
    fi


    log "Запуск PostgreSQL..."
    systemctl start postgresql


    # === Меняем IP на MASTER_IP ===
    check_db_connection_after_change "$MASTER_IP"
    update_cddisk_configs "$MASTER_IP"
    update_documentserver_config "$MASTER_IP"


    restart_supervisor_services
    restart_documentserver_services


    log "✅ Сервер успешно переведён в режим slave."
}


function show_current_configurations() {
    echo -e "
=== Текущие конфигурации с подключением к БД ==="
    echo "Файлы appsettings.json (только актуальные):"


                                                                                                                                                         
    local files=(
        "/opt/r7-office/Api/appsettings.json"
        "/opt/r7-office/Sso.Api/appsettings.json"
        "/opt/r7-office/Processing/appsettings.json"
    )


    for file in "${files[@]}"; do
        if [[ ! -f "$file" ]]; then
            echo "  $file — не найден"
            continue
        fi


        echo "  === $file ==="


        local user_actions=$(grep -A2 '"R7StorageServerUserActions"' "$file" | tr -d '
' | sed 's/[",]//g; s/:[ ]*/:/g')
        if [[ -n "$user_actions" ]]; then
            echo "  R7StorageServerUserActions: ${user_actions#*R7StorageServerUserActions: }"
        else
            echo "  R7StorageServerUserActions: не найден"
        fi


        local storage_server=$(grep -A2 '"R7StorageServer"' "$file" | tr -d '
' | sed 's/[",]//g; s/:[ ]*/:/g')
        if [[ -n "$storage_server" ]]; then
            echo "  R7StorageServer: ${storage_server#*R7StorageServer: }"
        else
            echo "  R7StorageServer: не найден"
        fi


        echo ""
    done


    local doc_config="/etc/r7-office/documentserver/local.json"
    echo "Файл local.json (documentserver):"
    if [[ -f "$doc_config" ]]; then
        grep -E '"(dbHost|dbName|dbUser|dbPass|dbPort)"' "$doc_config" | sed 's/^/  /'
    else
        echo "  Файл не найден"
    fi
}


function get_postgres_data_dir() {
    local dir="/var/lib/pgsql/data"


    if [[ -d "$dir" ]]; then
        echo "$dir"
        return 0
    else
        log "❌ Каталог данных PostgreSQL не найден."
        return 1
    fi
}


function get_postgres_role() {
    local pg_data="/var/lib/pgsql/data"


    # Попробуем через SQL, если PostgreSQL запущен
    if systemctl is-active --quiet postgresql > /dev/null 2>&1; then
        local role_sql=$(sudo -u postgres psql -tAc "SELECT pg_is_in_recovery();")
        if [[ $? -eq 0 ]]; then
            if [[ "$(echo "$role_sql" | tr '[:upper:]' '[:lower:]')" == "f" ]]; then
                echo "master"
                return 0
            else
                echo "slave"
                return 0
            fi
        else
            log "⚠️ Не удалось выполнить запрос к PostgreSQL."
        fi
    fi


    # Если БД не запущена — проверяем сигналы
    if [[ -f "$pg_data/standby.signal" ]]; then
        echo "slave"
        return 0
    elif [[ -f "$pg_data/postmaster.pid" ]]; then
        echo "master"
        return 0
    else
        log "❌ Не удалось определить роль PostgreSQL."
        echo "unknown"
        return 1
    fi
}


function is_master() {
    [[ "$(get_postgres_role)" == "master" ]]
}


function is_slave() {
    [[ "$(get_postgres_role)" == "slave" ]]
}


function show_status_replication() {
    local local_ip=$(get_local_ip)
    echo -e "
=== Текущий статус сервера ==="
    echo "IP сервера: $local_ip"
    echo "MASTER_IP (константа): $MASTER_IP"
    echo "SLAVE_IP (константа): $SLAVE_IP"
    local role=$(get_postgres_role)
    echo "Роль: ${role^}"
    if [[ "$role" == "master" ]]; then
        echo "Проверка состояния репликации:"
        env PGHOME=/tmp sudo -u postgres PGOPTIONS="-c search_path=pg_catalog" psql -c "SELECT * FROM pg_stat_replication;"
    elif [[ "$role" == "slave" ]]; then
        echo "Проверка состояния восстановления:"
        env PGHOME=/tmp sudo -u postgres PGOPTIONS="-c search_path=pg_catalog" psql -c "SELECT * FROM pg_stat_wal_receiver;"
    else
        echo "Роль: Не определена"
    fi
    echo -e "==============================
"
}


function main_menu() {
    clear
    echo "=== Добро пожаловать в систему управления PostgreSQL ==="
    echo "Лог-файл: $LOG_FILE"
    echo ""
    while true; do
        echo "=== Меню управления PostgreSQL ==="
        echo "1. Установка параметров master"
        echo "2. Установка параметров slave"
        echo "3. Показать текущие конфиги"
        echo "4. Проверка подключения с новыми параметрами"
        echo "5. Восстановить конфигурации из .bak"
        echo "6. Перезапустить сервисы приложений"
        echo "7. Показать текущий статус сервера"
        echo "8. Выход"
        read -p "Выберите действие (1-8): " choice
        case $choice in
            1)
                switch_to_slave_as_master
                show_status_replication
                read -p "Нажмите Enter для продолжения..."
                ;;
            2)
                switch_to_master_as_slave
                show_status_replication
                read -p "Нажмите Enter для продолжения..."
                ;;
            3)
                show_current_configurations
                read -p "Нажмите Enter для продолжения..."
                ;;
            4)
                check_db_connection_after_change "$MASTER_IP"
                read -p "Нажмите Enter для продолжения..."
                ;;
            5)
                restore_all_configs
                read -p "Нажмите Enter для продолжения..."
                ;;
            6)
                log "Перезапуск всех сервисов..."
                supervisorctl restart all
                restart_documentserver_services
                read -p "Нажмите Enter для продолжения..."
                ;;
            7)
                show_status_replication
                read -p "Нажмите Enter для продолжения..."
                ;;
            8)
                log "Выход..."
                exit 0
                ;;
            *)
                echo "Неверный выбор."
                sleep 2
                ;;
        esac
        clear
    done
}


# === MAIN ===
check_superuser
main_menu

Описание пунктов:

  1. Установка параметров master — устанавливает параметры master для сервера используемого основным (меняет конфигурации приложений на использование БД master) и создает в том же каталоге резервную копию изменяемых файлов;
  2. Установка параметров slave — устанавливает параметры slave для сервера используемым запасным (меняет конфигурации приложений на использование БД master и включение репликации на этом сервере) и создает в том же каталоге резервную копию изменяемых файлов;
  3. Показать текущие конфиги — показывает текущие параметры приложений;
  4. Проверка подключения с новыми параметрами — проверяет доступ для приложений с заданными константами по подключению к master;
  5. Восстановить конфигурации из .bak — при ранее измененных конфигураций приложений может восстановить резервные копии файлов из формата .bak;
  6. Перезапустить сервисы приложений — перезапускает сервисы приложений;
  7. Показать текущий статус сервера — указывает состояние БД на текущем сервере.

8.2. Проверка работы серверов

Для проверки потребуется переключать в DNS А-запись ведущая на первый сервер.

Перейдите по адресу https://admin.{ВАШ_ДОМЕН}.

Убедитесь что используется корректная адресация на первый адрес Корпоративного сервера (используйте команду ping) и используйте предустановленный логин\пароль superadmin.

Создайте пользователя и проверьте редактирование файлов — корректное сохранение файлов и повторное открытие файлов.

Далее переключите А-запись на второй сервер и так же проверьте его работу.

В DNS используйте установленную текущую ноду как master. Запустите скрипт управления БД и проверьте текущие статусы серверов.

Обратите внимание

Настоятельно рекомендуется отработать поэтапное переключение из slave в master на втором сервере в случае появления ошибок на первом сервере.

9. Резервное копирование и восстановление

Для проведения резервирования и восстановления необходимо использовать скрипты из статьи: Резервное копирование/восстановление Корпоративный сервер 2024 ↗.

Перед использованием скрипта создания бекапа добавьте каталог mail, приведите к виду строку:

Важно

При использовании почтового сервера.

# Создание архива с бэкапом
tar cf "$backup_dir/cddisk-${backup_date}.tar.bz2" --selinux --use-compress-prog="lbzip2 -k -n$num_cores" /opt/r7-office $supervisor_dir /etc/r7-office /var/r7-office /var/www/r7-office "$backup_dir/cddisk_db.tar.gz /mail"

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

systemctl stop glusterfs

После завершения восстановления включить:

systemctl start glusterfs

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