OpenUDS HA
HA-кластер с OpenUDS
Компоненты OpenUDS можно настроить в режиме высокой доступности (HA).
Для обеспечения высокой доступности среды VDI, кроме настройки нескольких OpenUDS-Server и OpenUDS-Tunnel, необходимо настроить репликацию базы данных. Также следует настроить балансировщик нагрузки, который будет распределять подключения к компонентам OpenUDS-Server и OpenUDS-Tunnel.
В этом документе приведён пример настройки работы OpenUDS в режиме высокой доступности с программным балансировщиком нагрузки (HAProxy) и базой данных MySQL.
Системные требования
Основные элементы отказоустойчивого решения:
- MySQL сервер — база данных является одним из наиболее существенных компонентов среды VDI с OpenUDS. Поэтому настоятельно рекомендуется иметь резервную копию этого компонента, либо посредством полной резервной копии машины, либо посредством конфигурации активной/пассивной реплики. В данном руководстве описана настройка двух серверов MySQL, главного и подчиненного, в режиме активной/пассивной репликации.
- HAProxy-сервер — сервер, отвечающий за распределение подключений к OpenUDS-Server и OpenUDS-Tunnel. Через него осуществляется доступ пользователей к OpenUDS и выполняются подключения к различным сервисам. На серверах HAProxy также будет настроен IP-адрес, который будет активен только на основном сервере. В случае отказа основного сервера IP-адрес будет автоматически активирован на другом сервере HAProxy.
- OpenUDS Server — наличие нескольких машин OpenUDS-Server обеспечит непрерывный доступ пользователей к OpenUDS, даже при отказе одного из OpenUDS-Server.
- OpenUDS Tunnel — наличие нескольких машин OpenUDS-Tunnel позволит получить доступ к службам (рабочим столам или приложениям) через туннелированные соединения и HTML5, даже при отказе одного из OpenUDS-Tunnel.
Компонент | Количество | ОЗУ | ЦП | Диск |
---|---|---|---|---|
MySQL Server | 2 | 1 ГБ | 2 vCPUs | 10 ГБ |
HAProxy | 2 | 1 ГБ | 2 vCPUs | 10 ГБ |
OpenUDS Server | 2 | 2 ГБ | 2 vCPUs | 8 ГБ |
OpenUDS Tunnel | 2 | 2 ГБ | 2 vCPUs | 10 ГБ |
Конфигурация серверов MySQL
Узел | Имя | IP-адрес |
---|---|---|
Основной (Master) | mysql01 | 192.168.0.128 |
Вторичный (Slave) | mysql02 | 192.168.0.129 |
На обоих серверах установить MySQL (MariaDB):
# apt-get install mariadb
# systemctl enable --now mariadb.service
# mysql_secure_installation
Настройка репликации между серверами
Главный узел (Master)
В файле /etc/my.cnf.d/server.cnf:
- закомментировать параметр skip-networking;
- раскомментировать параметры server-id и log-bin;
- убедиться, что для параметра server-id установлено значение 1;
- раскомментировать параметр bind-address и указать IP-адрес сервера (в этом случае главного):
bind-address 192.168.0.128
Перезагрузить службу MySQL:
# systemctl restart mariadb
Создать нового пользователя, с правами которого будет производиться репликация:
- Войти в консоль MySQL с правами root:
$ mysql -p
- Создать пользователя (в примере пользователь «replica» с паролем «uds»):
MariaDB [(none)]> CREATE USER 'replica'@'%' IDENTIFIED BY 'uds'; Query OK, 0 rows affected (0.009 sec)
- Предоставить права «replication slave» пользователю:
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO 'replica'@'%' IDENTIFIED BY 'uds'; Query OK, 0 rows affected (0.002 sec)
- Выполнить следующую команду, чтобы получить информацию об имени двоичного файла и его позиции:
MariaDB [(none)]> SHOW MASTER STATUS\G *************************** 1. row *************************** File: mysql-bin.000002 Position: 328 Binlog_Do_DB: Binlog_Ignore_DB: 1 row in set (0.001 sec)
В данном примере:
- mysql-bin.000002 — имя файла;
- 328 — позиция.
Эти данные будут необходимы для настройки Slave-сервера.
# mysqlbinlog --no-defaults /var/lib/mysql/db/mysql-bin.000002
Вторичный узел (Slave)
В файле /etc/my.cnf.d/server.cnf:
- закомментировать параметр skip-networking;
- раскомментировать параметры log-bin и server-id;
- в параметре server-id установить значение 2:
server-id = 2
- раскомментировать параметр bind-address и указать IP-адрес сервера (в этом случае вторичного):
bind-address 192.168.0.129
Перезагрузить службу MySQL:
# systemctl restart mariadb
Настроить параметры, которые вторичный сервер (Slave) будет использовать для подключения к основному серверу (Master):
- Войти в консоль MySQL с правами root:
$ mysql -p
- Остановить репликацию:
MariaDB [(none)]> STOP SLAVE; Query OK, 0 rows affected, 1 warning (0.001 sec)
- Настроить репликацию между основным сервером и вторичным сервером:
MariaDB [(none)]>CHANGE MASTER TO MASTER_HOST='192.168.0.128', MASTER_USER='replica', MASTER_PASSWORD='uds', MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=328; Query OK, 0 rows affected (0.020 sec)
- где
- 192.168.0.128 — IP-адрес основного сервера;
- replica — пользователь, с правами которого будет производиться репликация;
- uds — пароль пользователя replica;
- myslq-bin.000002 — имя файла полученного на предыдущем шаге;
- 328 — позиция двоичного файла.
- Запустить репликацию:
MariaDB [(none)]> START SLAVE; Query OK, 0 rows affected (0.001 sec)
- Убедиться, что конфигурация верна:
MariaDB [(none)]> SHOW SLAVE STATUS\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.0.128 Master_User: replica Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000004 Read_Master_Log_Pos: 328 Relay_Log_File: mysqld-relay-bin.000006 Relay_Log_Pos: 555 Relay_Master_Log_File: mysql-bin.000004 Slave_IO_Running: Yes Slave_SQL_Running: Yes …
IP-адрес основного сервера должен быть указан корректно, параметры Slave_IO_Running и Slave_SQL_Running должны быть установлены в значение «Yes».
Проверка репликации
Для проверки репликации можно создать БД на главном сервере и убедиться, что она автоматически реплицируется на вторичном сервере:
- Получить доступ к консоли MySQL главного сервера и создать новую тестовую БД «replicatest»:
MariaDB [(none)]> CREATE DATABASE replicatest; Query OK, 1 row affected (0.001 sec)
- Убедиться, что БД создана:
MariaDB [(none)]> SHOW DATABASES; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | replicatest | +--------------------+ 4 rows in set (0.001 sec)
- Получить доступ к консоли MySQL вторичного сервера и убедиться, что БД, созданная на основном сервере, успешно реплицировалась на этот сервер:
MariaDB [(none)]> SHOW DATABASES; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | replicatest | +--------------------+ 4 rows in set (0.002 sec)
MariaDB [(none)]> DROP DATABASE replicatest;
Теперь можно создать на основном сервере БД:
mysql> CREATE DATABASE dbuds CHARACTER SET utf8 COLLATE utf8_general_ci;
mysql> CREATE USER 'dbuds'@'%' IDENTIFIED BY 'password';
mysql> GRANT ALL PRIVILEGES ON dbuds.* TO 'dbuds'@'%';
mysql> FLUSH PRIVILEGES;
И подключить серверы OpenUDS к БД основного сервера.
Отказ сервера
При недоступности одного из серверов БД необходимо выполнить ряд задач. Задачи, которые следует выполнить, зависят от того к какому серверу (Master или Slave) нет доступа.
Главный узел (Master)
Если недоступен основной сервер БД (Master), то будет потерян доступ к среде VDI. В этом случае необходимо вручную подключить OpenUDS-Server к вторичной БД (Slave), в которой находится вся информация среды VDI до момента падения основной БД. Чтобы настроить новое подключение к БД на OpenUDS-Server следует в конфигурационном файле /var/server/server/settings.py указать параметры новой БД (это необходимо сделать на всех серверах OpenUDS-Server).
После изменения IP-адреса БД необходимо перезапустить сервер (это необходимо сделать на всех серверах OpenUDS-Server).
После перезапуска сервера доступ к среде VDI будет восстановлен.
Затем необходимо настроить новый сервер для репликации БД.
Для этого есть несколько вариантов, в том числе:
- Настроить текущий сервер БД как главный и создать новый сервер-реплику, который нужно настроить и восстановить БД из резервной копии с существующими данными (поскольку реплицируются только новые данные).
- Напрямую сделать резервную копию текущего сервера БД (предварительно остановив все машины OpenUDS-Server). Создать новый сервер БД Master, восстановить туда резервную копию БД и перенастроить репликацию.
# mysqldump -u dbuds -ppassword --databases dbuds > dbuds_dump.sql
При создании резервной копии все машины OpenUDS-Server должны быть выключены. Таким образом, обеспечивается согласованность данных и отсутствие различий в данных между главным и подчиненным серверами перед настройкой реплики.
Вторичный узел (Slave)
Если недоступен вторичный сервер БД (Slave), доступ к среде VDI сохранится, но будет необходимо перенастроить вторичный сервер-реплику. Перед выполнением данной настройки необходимо восстановить резервную копию с текущим состоянием основной БД, так как будут синхронизированы только новые данные реплики (существующие данные не будут реплицированы в базе данных).
Важно, чтобы во время всего этого процесса машины OpenUDS-Server были выключены, чтобы не возникало различий между БД Master и Slave серверов.
Настройка серверов HAProxy
Узел | Имя | IP-адрес |
---|---|---|
Основной (Master) | Haproxy01 | 192.168.0.52 |
Вторичный (Slave) | Haproxy02 | 192.168.0.53 |
192.168.0.49 — виртуальный IP-адрес по которому будут доступны серверы OpenUDS.
В данной конфигурации используется служба Keepalived и виртуальный IP-адрес, общий для главного (Master) и резервного (Slave) узлов. Служба Keepalived связывает виртуальный IP-адрес с главным узлом и отслеживает доступность HAProxy. Если служба обнаруживает, что HAProxy не отвечает, то она связывает виртуальный адрес с вспомогательным узлом, что минимизирует время недоступности сервера. Пользователи при обращении к OpenUDS должны использовать этот виртуальный IP-адрес. Этот же виртуальный IP-адрес следует использовать при регистрации OpenUDS Actor (см. Подготовка шаблона ВМ).
Нижеперечисленные действия необходимо выполнить на обоих узлах, за исключением создания сертификата, который должен быть создан только на одном из серверов. Конфигурация компонента Keepalived для вторичного сервера будет использовать режим SLAVE.
На основном узле сгенерировать сертификат:
# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /root/ssl.key -out /root/ssl.crt
Создать файл .pem, выполнив команду (предварительно может понадобиться создать каталог /etc/openssl/private):
# cat /root/ssl.crt /root/ssl.key > /etc/openssl/private/haproxy.pem
На обоих узлах:
- Установить пакеты haproxy и keepalived:
# apt-get install haproxy keepalived
- Заменить содержимое файла /etc/haproxy/haproxy.cfg следующим:
global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /var/lib/haproxy/admin.sock mode 660 level admin stats timeout 30s maxconn 2048 user _haproxy group _haproxy daemon # Default SSL material locations # ca-base /etc/openssl/certs # crt-base /etc/openssl/private # Default ciphers to use on SSL-enabled listening sockets. # For more information, see ciphers(1SSL). This list is from: # https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ ssl-default-bind-options ssl-min-ver TLSv1.2 prefer-client-ciphers # ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA267:TLS_AES_267_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA267 ssl-default-bind-ciphers ECDH+AESGCM:ECDH+CHACHA20:ECDH+AES267:ECDH+AES128:!aNULL:!SHA1:!AESCCM # ssl-default-server-options ssl-min-ver TLSv1.2 # ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA267:TLS_AES_267_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA267 # ssl-default-server-ciphers ECDH+AESGCM:ECDH+CHACHA20:ECDH+AES267:ECDH+AES128:!aNULL:!SHA1:!AESCCM tune.ssl.default-dh-param 2048 defaults log global mode http option httplog option dontlognull option forwardfor retries 3 option redispatch stats enable stats uri /haproxystats stats realm Strictly\ Private stats auth stats:haproxystats timeout connect 5000 timeout client 50000 timeout server 50000 frontend http-in bind *:80 mode http http-request set-header X-Forwarded-Proto http default_backend openuds-backend frontend https-in bind *:443 ssl crt /etc/openssl/private/haproxy.pem mode http http-request set-header X-Forwarded-Proto https default_backend openuds-backend frontend tunnel-in bind *:1443 mode tcp option tcplog default_backend tunnel-backend-ssl frontend tunnel-in-guacamole # HTML5 bind *:10443 mode tcp option tcplog default_backend tunnel-backend-guacamole backend openuds-backend option http-keep-alive balance roundrobin server udss1 192.168.0.85:80 check inter 2000 rise 2 fall 5 server udss2 192.168.0.86:80 check inter 2000 rise 2 fall 5 backend tunnel-backend-ssl mode tcp option tcplog balance roundrobin server udst1 192.168.0.87:7777 check inter 2000 rise 2 fall 5 server udst2 192.168.0.88:7777 check inter 2000 rise 2 fall 5 backend tunnel-backend-guacamole mode tcp option tcplog balance source server udstg1 192.168.0.87:10443 check inter 2000 rise 2 fall 5 server udstg2 192.168.0.88:10443 check inter 2000 rise 2 fall 5
- Включить в ядре поддержку двух IP-адресов:
echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf # sysctl -p
- Настроить службу Keepalived. Для этого создать файл /etc/keepalived/keepalived.conf. Содержимое файла зависит от узла, который настраивается:
- на главном узле:
global_defs { # Keepalived process identifier lvs_id haproxy_DH } # Script used to check if HAProxy is running vrrp_script check_haproxy { script "killall -0 haproxy" interval 2 weight 2 } # Виртуальный интерфейс # The priority specifies the order in which the assigned interface to take over in a failover vrrp_instance VI_01 { state MASTER interface enp0s3 virtual_router_id 51 priority 101 # Виртуальный IP-адрес virtual_ipaddress { 192.168.0.49 } track_script { check_haproxy } }
- где enp0s3 — интерфейс, для виртуального IP (узнать имя сетевого интерфейса можно, выполнив команду ip a).
- на вторичном узле:
global_defs { # Keepalived process identifier lvs_id haproxy_DH_passive } # Script used to check if HAProxy is running vrrp_script check_haproxy { script "killall -0 haproxy" interval 2 weight 2 } # Виртуальный интерфейс # The priority specifies the order in which the assigned interface to take over in a failover vrrp_instance VI_01 { state SLAVE interface eth0 virtual_router_id 51 priority 100 # Виртуальный IP-адрес virtual_ipaddress { 192.168.0.49 } track_script { check_haproxy } }
- где eth0 — интерфейс, для виртуального IP (узнать имя сетевого интерфейса можно, выполнив команду ip a).
- на главном узле:
- Для запуска сервисов выполнить команды:
# systemctl enable --now haproxy # systemctl enable --now keepalived
- Убедиться, что балансирующий виртуальный IP активен на основном сервере:
$ ip a |grep enp0s3 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 inet 192.168.0.52/24 brd 192.168.0.255 scope global noprefixroute enp0s3 inet 192.168.0.49/32 scope global enp0s3
Настройка OpenUDS
После настройки серверов MySQL и HAProxy можно приступить к установке и настройке компонентов OpenUDS-Server и OpenUDS-Tunnel.
Настройка OpenUDS-Server
Узел | Имя | IP-адрес |
---|---|---|
Основной (Master) | udss01 | 192.168.0.85 |
Вторичный (Slave) | udss02 | 192.168.0.86 |
На обоих узлах OpenUDS-Server:
- Установить OpenUDS Server:
# apt-get install openuds-server-nginx
- Отредактировать /etc/openuds/settings.py, указав корректные данные для подключения к основному MySQL-серверу:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'OPTIONS': { 'isolation_level': 'read committed', }, 'NAME': 'dbuds', # Or path to database file if using sqlite3. 'USER': 'dbuds', # Not used with sqlite3. 'PASSWORD': 'password', # Not used with sqlite3. 'HOST': '192.168.0.128', # Set to empty string for localhost. Not used with sqlite3. 'PORT': '3306', # Set to empty string for default. Not used with sqlite3. } }
- "Заполнить" базу данных первоначальными данными (выполнить только на одном узле!):
# su -s /bin/bash - openuds $ cd /usr/share/openuds $ python3 manage.py migrate $ exit
- Запустить gunicorn:
# systemctl enable --now openuds-web.service
- Запустить nginx:
# ln -s ../sites-available.d/openuds.conf /etc/nginx/sites-enabled.d/openuds.conf # systemctl enable --now nginx.service
- Запустить менеджер задач OpenUDS:
# systemctl enable --now openuds-taskmanager.service
- Подключиться к серверу OpenUDS http://<Виртуальный IP-адрес> (в примере http://192.168.0.49).
Настройка OpenUDS-Tunnel
Узел | Имя | IP-адрес |
---|---|---|
Основной (Master) | udst01 | 192.168.0.87 |
Вторичный (Slave) | udst02 | 192.168.0.88 |
На каждом узле OpenUDS-Tunnel:
- Установить OpenUDS Tunnel:
# apt-get install openuds-tunnel
- Настроить туннель:
- Указать виртуальный IP-адрес в файле /etc/openuds-tunnel/udstunnel.conf:
uds_server = http://192.168.0.49/uds/rest/tunnel/ticket uds_token = 5ba9d52bb381196c2a22e495ff1c9ba4bdc03440b726aa8b
- Запустить и добавить в автозагрузку сервис OpenUDS Tunnel:
# systemctl enable --now openuds-tunnel.service
- Указать виртуальный IP-адрес в файле /etc/openuds-tunnel/udstunnel.conf:
- Настроить HTML5:
- В файле /etc/guacamole/guacamole.properties привести значение параметра uds-base-url к виду:
uds-base-url=http://192.168.0.49/uds/guacamole/auth/5ba9d52bb381196c2a22e495ff1c9ba4bdc03440b726aa8b
- где 192.168.0.49 — виртуальный IP-адрес.
- Настроить tomcat, для этого в файл /etc/tomcat/server.xml добавить новый Connector, в котором указать порт (в примере 10443), сертификат (файл .crt, .pem и т.д.), закрытый ключ (.key, .pem и т.д.):
<Connector port="10443" protocol="org.apache.coyote.http11.Http11AprProtocol" SSLEnabled="true" ciphers="A-CHACHA20-POLY1305,ECDHE-RSA-CHACHA20-POLY1305,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,DHE-RSA-AES128-GCM-SHA256,DHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES256-SHA384,ECDHE-RSA-AES128-SHA,ECDHE-ECDSA-AES256-SHA384,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-RSA-AES128-SHA256,DHE-RSA-AES128-SHA,DHE-RSA-AES256-SHA256,DHE-RSA-AES256-SHA,ECDHE-ECDSA-DES-CBC3-SHA,ECDHE-RSA-DES-CBC3-SHA,EDH-RSA-DES-CBC3-SHA,AES128-GCM-SHA256,AES256-GCM-SHA384,AES128-SHA256,AES256-SHA256,AES128-SHA,AES256-SHA,DES-CBC3-SHA" maxThreads="500" scheme="https" secure="true" SSLCertificateFile="/etc/openuds-tunnel/ssl/certs/openuds-tunnel.pem" SSLCertificateKeyFile="/etc/openuds-tunnel/ssl/private/openuds-tunnel.key" maxKeepAliveRequests="1000" clientAuth="false" sslProtocol="TLSv1+TLSv1.1+TLSv1.2" />
- Запустить сервисы:
# systemctl enable --now guacd tomcat
- В файле /etc/guacamole/guacamole.properties привести значение параметра uds-base-url к виду:
На главном узле (Master) MySQL добавить в БД информацию о каждом OpenUDS Tunnel: INSERT INTO `uds_tunneltoken` VALUES (ID,'автор добавления','IP-адрес туннеля','IP-адрес туннеля','название туннеля','Токен из файла udstunnel.conf','дата добавления'); . Например:
# mysql -u root -p
MariaDB> USE dbuds;
MariaDB> INSERT INTO `uds_tunneltoken` VALUES (ID,'admin','192.168.0.87','192.168.0.87','Tunnel','5ba9d52bb381196c2a22e495ff1c9ba4bdc03440b726aa8b','2022-11-15');
MariaDB> INSERT INTO `uds_tunneltoken` VALUES (ID,'admin','192.168.0.88','192.168.0.88','Tunnel','9ba4bdc03440b726aa8b5ba9d52bb381196c2a22e495ff1c','2022-11-15')
MariaDB> exit;
Оба сервера OpenUDS-Tunnel будут работать в активном режиме. Пользователи, использующие подключение через туннель, будут подключаться к этим серверам случайным образом. При падении одного из серверов, соединения пользователей, которые используют этот сервер, будут прерваны, но при повторном установлении соединения они автоматически получат доступ через другой активный туннельный сервер.
При создании туннельного транспорта (X2Go, RDP) в поле «Туннельный сервер» следует указывать виртуальный IP-адрес и порт, указанный в разделе frontend tunnel-in файла /etc/haproxy/haproxy.cfg (в данном примере: 1443):
При создании транспорта «HTML5 RDP (туннельный)» в поле «Tunnel Server» следует указывать виртуальный IP-адрес и порт, указанный в разделе frontend tunnel-in-guacamole файла /etc/haproxy/haproxy.cfg (в данном примере: 10443):
Пример подключения с использованием HTML5: