Содержание

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

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

Описание

Архитектура рассчитана на использование одного сервера как основной и второго сервера как запасной с постоянной репликацией. В случае отказа работы основного возможность ручного переключения на запасного с помощью скрипта и изменении 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 для корректной работы сервисов.

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 +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

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

Вам необходимо положить сертификаты по пути /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 запись для Корпоративного сервера, например:

Пример создания DNS записи для корпоративного сервера

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

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

sudo bash ./online_installer.sh

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

Установка сервера, меню Make clean install?

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

Установка сервера, меню Intstall postgresql server on local pc?

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

Установка сервера, меню Intstall Document Server?

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

Ввод secret для защищённого доступа Р7-Диска и Сервера Документов

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

Меню Database password

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

Установка сервера, меню Intstall CDDisk api & web?

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

Меню Choose database type

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

Меню Create database?

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

Ввод ip адрес текущего первого сервера

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

Ввод порта (по умолчанию 5432)

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

Меню Database user for create DB

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

Меню Database for create DB password

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

Меню The salt to be used during the key derivation process

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

Меню Make HTTPS?

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

Меню с вводом домена

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

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

Меню с установкой Р7 Почтовый сервер

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

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

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

Установка сервера, меню Make clean install?

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

Установка сервера, меню Intstall postgresql server on local pc?

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

Установка сервера, меню Intstall Document Server?

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

Ввод secret для защищённого доступа

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

Меню Database password

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

Установка сервера, меню Intstall CDDisk api & web?

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

Меню Choose database type

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

Меню Create database?

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

Меню с вводом ip адреса первого сервера master

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

Ввод порта 5432

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

Меню Database user for create DB

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

Меню Database for create DB password

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

Меню The salt to be used during the key derivation process

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

Меню Make HTTPS?

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

Меню с вводом домена ( в котором созданы записи из пункта подготовки)

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

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

Меню с установкой Р7 Почтовый сервер

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

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.test2.s7-office.site/ Организации — Выберите организацию, в которую добавлены пользователи — Почтовые серверы:

Добавление почтового сервера

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

Данные по почтовому серверу

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

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

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.test2.s7-office.site.

Убедитесь что используется корректная адресация на первый адрес Корпоративного сервера (используйте команду 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.

Была ли полезна статья?
Позвольте нам стать лучше