Записки системного администратора

Ещё один блог о системном администрировании, операционных системах, СУБД, сетях, костылях-велосипедах и пр.

Настройка отказоустойчивого кластера виртуализации на базе OpenNebula, Ceph, MariaDB Galera, Open vSwitch, Paсemaker и Nginx

В этой заметке я хотел бы написать, как настроить отказоустойчивый кластер для виртаулизации из нескольких серверов с исользованием Ceph, OpenNebula, MariaDB Galera Cluster, Open vSwitch, Paсemaker и Nginx. Все эти проекты opensource и у них всех есть замечательная документация, и, в принципе, от этой заметки толку мало. Но, если честно, надоело вспоминать всякие нюансы при настройке очередного кластера. А если кто-то случайно набрел на эту статью, пусть узнает, что так тоже можно. В конце заметки обязательно укажу ссылки на офф документацию этих проектов.
Похожая заметка есть на Хабре, и идею, конечно же, я взял оттуда. Но той заметке уже три года, некоторые моменты изменились. И так, поехали.

Установка и настройка всего этого комбайна будет проходить несколько этапов. Вот они:

  • Настройка кластера распределенного хранилища Ceph
  • Настройка galera кластера MariaDB
  • Настройка программного свитча Open vSwitch
  • Настройка OpenNebula
  • Настройка отказоустойчивого кластера
  • Подключение Ceph хранилища к OpenNebula и первоначальная конфигурация
  • Настройка https на веб-интерфейсе управления кластером OpenNebula

В данном туториале будет описана установка на 3 ноды. В действительности нод может быть сколько угодно.

Желательно, чтобы между нодами кластера была 10G сеть. Она необходима для "комфортного" функционирования кластера Ceph. Об этом пишут сами разработчики в документации по проекту. Но можно обойтись и 1G, если это, например, тестовый кластер или кластер в резервной серверной. В этом случае, конечно же, можно сэкономить ввиду меньшей критичности.

В данном случае между серверами используется 1G сеть. На каждой ноде по два сетевых интерфейса - один интерфейс мы "воткнем" в openvswitch, второй интерфейс будет использоваться ceph.

Также каждая нода содержит 3 HDD по 2Tb для основного пула ceph, оперативную память, достаточную для функционирования ceph (1Gb RAM на 1Tb данных), и конечно же ресурсы, необходимые для функционирования самого облака - CPU и RAM, которые будут использоваться для запуска виртуальных машин.

На каждой ноде установлена операционная система CentOS 7 с последними обновлениями.

Также нужно отключить Selinux (да, да, я в курсе https://stopdisablingselinux.com/, но этого требуют сами разработчики):

for node in tank dozer truck; do ssh $node "sed -i s/SELINUX=enforcing/SELINUX=disabled/g /etc/selinux/config && setenforce 0"; done

И установить EPEL репозиторий:

for node in tank dozer truck; do ssh $node yum install -y epel-release; done

Отлючим временно firewall (я использую iptables):

for node in tank dozer truck; do ssh $node.domain.local systemctl stop iptables; done

Ближе к концу статьи я оставлю список правил для iptables.

Ceph очень привиредлив к настрокам времени - на всех нодах время должно быть одинaково. Поэтому установим демон сhrony:

for node in tank dozer truck; do ssh $node "yum install chrony -y && systemctl enable chronyd && systemctl start chronyd"; done

Схема нашего кластера

Ну и табличка с характеристиками каждой ноды:

Hostname                   | tank             | dozer            | truck
------------------------------------------------------------------------------------
Public Network Interface   | em1              | em1              | em1
Private Network Interface  | em2              | em2              | em2
Public IP Address          | 192.168.5.201/24 | 192.168.5.202/24 | 192.168.5.203/24
Private IP Address         | 10.0.1.1/29      | 10.0.1.2/29      | 10.0.1.3/29
HDD                        | sdc              | sdc              | sdc              
HDD                        | sdd              | sdd              | sdd              
HDD                        | sde              | sde              | sde

Настройка Ceph

Ceph Homepage

Здесь опишу настройку ceph для хранения блочных устройств RBD (RADOS Block Device) для наших виртуальных машин. Последний стабильный релиз - Mimic. Но сколько бы я не пытался настроить его работу мне никак не удавалось. С релизом Luminous у меня никаких проблем не возникало. Поэтому опишу установку именно Ceph Luminous.

Установка будет осуществляться с помощью ceph-deploy, а она подразумевает установку с так называемого админского сервера. В качестве админского сервера может выступить любой инстанс с установленным ceph-deploy и ssh-клиентом. В этом примере будем деплоить с одной из нод - tank.

На каждой ноде необходимо иметь пользователя ceph, который может ходить между нодами без пароля и выполнять любые команды через sudo так же без пароля. На каждой ноде выполняем:

sudo useradd ceph
sudo passwd ceph
sudo echo "ceph ALL = (root) NOPASSWD:ALL" > /etc/sudoers.d/ceph
sudo chmod 0440 /etc/sudoers.d/ceph

Сгенерируем ключ и скопируем его на остальные ноды.

sudo -u ceph mkdir /home/ceph/.ssh
sudo -u ceph ssh-keygen -f /home/ceph/.ssh/id_rsa
sudo -u ceph cat /home/ceph/.ssh/id_rsa.pub >> /home/ceph/.ssh/authorized_keys
for node in dozer truck; do scp -r /home/ceph/.ssh/ ceph@$node:/home/ceph/; done

Добавим ceph репозиторий в /etc/yum.repos.d/ceph.repo. Вместо {ceph-stable-release} нужно указать необходимы релиз (например, mimic или luminous)

[ceph-noarch]
name=Ceph noarch packages
baseurl=https://download.ceph.com/rpm-luminous/el7/noarch
enabled=1
gpgcheck=1
type=rpm-md
gpgkey=https://download.ceph.com/keys/release.asc

Устанавливаем ceph-deploy:

sudo yum install -y ceph-deploy

Теперь зайдем под пользователем ceph и создадим папку, в которой будут храниться конфиги и ключи ceph:

sudo su - ceph
mkdir ceph-admin
cd ceph-admin

Создадим кластер:

ceph-deploy new --public-network 192.168.5.0/24 --cluster-network=10.0.1.0/29 tank dozer truck        

Установим ceph на наши ноды:

ceph-deploy install tank dozer truck

Если в процессе возникла ошибка:

Traceback (most recent call last):
  File "/bin/ceph-deploy", line 18, in <module>
    from ceph_deploy.cli import main
  File "/usr/lib/python2.7/site-packages/ceph_deploy/cli.py", line 1, in <module>
    import pkg_resources
ImportError: No module named pkg_resources

то необходимо установить pip:

sudo yum install python2-pip

и повторить процесс заново:

ceph-deploy install tank dozer truck

Создадим мониторы:

ceph-deploy mon create-initial

В документации к OpenNebula говорится, что необходим строго RBD format 2. Поэтому добавим строчку в конфиг ceph.conf в секцию global:

[global]
rbd_default_format = 2

Обновим конфиг на наших нодах:

ceph-deploy admin tank dozer truck

Для релизов Ceph старше Luminous необходимо создать так же демона manager:

ceph-deploy mgr create tank.domain.local dozer.domain.local truck.domain.local

Подготовим наши диски и установим osd демоны. Сейчас это выполняется всего одной командой для каждого osd. Команду ниже нужно выполнить для всех нод и каждого диска, которые будут использоваться в пуле ceph:

ceph-deploy osd create --data /dev/sdc tank.domain.local

Посмотрим, что у нас получилось:

[root@tank ~]$sudo ceph -s

  cluster:
    id:     f5ba7ed1-de2c-4355-a7b6-27e0c22eefca
    health: HEALTH_OK

  services:
    mon: 3 daemons, quorum tank,dozer,truck
    mgr: tank.domain.local(active), standbys: truck.domain.local, dozer.domain.local
    osd: 6 osds: 6 up, 6 in

  data:
    pools:   0 pools, 0 pgs
    objects: 0  objects, 0 B
    usage:   6.0 GiB used, 10.1 TiB / 10.1 TiB avail
    pgs:
[root@tank ~]$sudo ceph osd tree

ID CLASS  WEIGHT  TYPE NAME      STATUS REWEIGHT PRI-AFF 
-1       10.91271 root default                           
-5        3.63757     host dozer                         
 2   hdd  1.81879         osd.2      up  1.00000 1.00000 
 3   hdd  1.81879         osd.3      up  1.00000 1.00000 
-7        3.63757     host truck                          
 4   hdd  1.81879         osd.4      up  1.00000 1.00000 
 5   hdd  1.81879         osd.5      up  1.00000 1.00000 
-3        3.63757     host tank                          
 0   hdd  1.81879         osd.0      up  1.00000 1.00000 
 1   hdd  1.81879         osd.1      up  1.00000 1.00000

Создадим пул для images и system. Создается комaндой:

ceph osd pool create {pool-name} pg_num

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

  • меньше 5 osd - pg_num = 128
  • между 5 и 10 osd - pg_num = 512
  • между 10 и 50 osd - pg_num = 1024

Если количество osd больше, чем 50, то можно воспользоваться калькулятором

Назначаем им size - размер реплики, min_size - минимальный размер реплики в момент записи, то есть сколько нужно сделать реплик в момент записи, чтобы "отпустить" операцию записи, compression_algorithm, compression_mode. Полный список возможных опций можно посмотреть тут:

sudo ceph osd pool create one 512
sudo ceph osd pool set one min_size 2
sudo ceph osd pool set one size 3
sudo ceph osd pool set one compression_algorithm zlib
sudo ceph osd pool set one compression_mode force 

sudo ceph osd pool create one-system 512
sudo ceph osd pool set one min_size 2
sudo ceph osd pool set one size 3
sudo ceph osd pool set one compression_algorithm zlib
sudo ceph osd pool set one compression_mode force

Проверим:

[ceph@tank ceph-admin]$ sudo ceph osd lspools
1 one
2 one-system

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

Настройка MariaDB Galera Cluster

MariaDB Homepage

Теперь настроим отказоустойчивую MySQL базу данных на наших нодах, в которой мы и будем хранить конфигурацию нашего дата центра. MariaDB Galera Cluster — это MariaDB кластер с мастер-мастер репликацией использующий для синхронизации galera-библиотеку. Плюс ко всему он довольно прост в настройке.

На всех нодах добавим репозиторий /etc/yum.repos.d/mariadb.repo:

[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.3/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

Установим сервер:

for node in tank dozer truck; do ssh $node yum install -y MariaDB-server MariaDB-client rsync galera; done

Установим в атозагрузку на каждой ноде:

systemctl enable mariadb

и запустим:

systemctl start mariadb 

Произведем первоначальную настройку:

mysql_secure_installation

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

mysql -u root -p
create user 'replicator'@'%' identified by 'gK7LBHty7Eosid9gE82Obf8O';
grant all privileges on *.* to 'replicator'@'%';
flush privileges;
exit

И остановим mariadb:

systemctl stop mariadb

В my.cnf (или в /etc/my.cnf.d/server.cnf в секцию mysqld) на первой ноде нужно добавить следующее:

collation-server = utf8_general_ci
init-connect = 'SET NAMES utf8'
character-set-server = utf8
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
innodb_locks_unsafe_for_binlog=1
query_cache_size=0
query_cache_type=0
bind-address=0.0.0.0
datadir=/var/lib/mysql
innodb_log_file_size=100M
innodb_file_per_table
innodb_flush_log_at_trx_commit=2
wsrep_on=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address="gcomm://192.168.5.202,192.168.5.203"
wsrep_cluster_name='galera_cluster'
wsrep_node_address='192.168.5.201'
wsrep_node_name='tank.domain.local'
wsrep_sst_method=rsync
wsrep_sst_auth=replicator:gK7LBHty7Eosid9gE82Obf8O

На остальных нодах:

collation-server = utf8_general_ci
init-connect = 'SET NAMES utf8'
character-set-server = utf8
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
innodb_locks_unsafe_for_binlog=1
query_cache_size=0
query_cache_type=0
bind-address=0.0.0.0
datadir=/var/lib/mysql
innodb_log_file_size=100M
innodb_file_per_table
innodb_flush_log_at_trx_commit=2
wsrep_on=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address="gcomm://192.168.5.201,192.168.5.203"
wsrep_cluster_name='galera_cluster'
wsrep_node_address='192.168.5.202'
wsrep_node_name='dozer.domain.local'
wsrep_sst_method=rsync
wsrep_sst_auth=replicator:gK7LBHty7Eosid9gE82Obf8O
collation-server = utf8_general_ci
init-connect = 'SET NAMES utf8'
character-set-server = utf8
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
innodb_locks_unsafe_for_binlog=1
query_cache_size=0
query_cache_type=0
bind-address=0.0.0.0
datadir=/var/lib/mysql
innodb_log_file_size=100M
innodb_file_per_table
innodb_flush_log_at_trx_commit=2
wsrep_on=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address="gcomm://192.168.5.201,192.168.5.202"
wsrep_cluster_name='galera_cluster'
wsrep_node_address='192.168.5.203'
wsrep_node_name='truck.domain.local'
wsrep_sst_method=rsync
wsrep_sst_auth=replicator:gK7LBHty7Eosid9gE82Obf8O

Запускаем кластер. На первой ноде выполняем:

galera_new_cluster

Если все прошло без ошибок, остальные ноды запускаем так:

systemctl start mariadb

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

mysql -u root -p
SHOW STATUS LIKE 'wsrep%';

Должны получить что-то похожее на это:

MariaDB [(none)]> SHOW STATUS LIKE 'wsrep%';
+------------------------------+----------------------------------------------------------+
| Variable_name                | Value                                                    |
+------------------------------+----------------------------------------------------------+
| wsrep_apply_oooe             | 0.000000                                                 |
| wsrep_apply_oool             | 0.000000                                                 |
| wsrep_apply_window           | 0.000000                                                 |
| wsrep_causal_reads           | 0                                                        |
| wsrep_cert_deps_distance     | 0.000000                                                 |
| wsrep_cert_index_size        | 0                                                        |
| wsrep_cert_interval          | 0.000000                                                 |
| wsrep_cluster_conf_id        | 3                                                        |
| wsrep_cluster_size           | 3                                                        |
| wsrep_cluster_state_uuid     | 332eb3dc-d08c-11e8-b23f-3ea9f81c173c                     |
| wsrep_cluster_status         | Primary                                                  |
| wsrep_cluster_weight         | 3                                                        |
| wsrep_commit_oooe            | 0.000000                                                 |
| wsrep_commit_oool            | 0.000000                                                 |
| wsrep_commit_window          | 0.000000                                                 |
| wsrep_connected              | ON                                                       |
| wsrep_desync_count           | 0                                                        |
| wsrep_evs_delayed            |                                                          |
| wsrep_evs_evict_list         |                                                          |
| wsrep_evs_repl_latency       | 0/0/0/0/0                                                |
| wsrep_evs_state              | OPERATIONAL                                              |
| wsrep_flow_control_paused    | 0.000000                                                 |
| wsrep_flow_control_paused_ns | 0                                                        |
| wsrep_flow_control_recv      | 0                                                        |
| wsrep_flow_control_sent      | 0                                                        |
| wsrep_gcomm_uuid             | 45b29422-d08c-11e8-a2ff-96d1e7471207                     |
| wsrep_incoming_addresses     | 192.168.5.201:3306,192.168.5.202:3306,192.168.5.203:3306 |
| wsrep_last_committed         | 0                                                        |
| wsrep_local_bf_aborts        | 0                                                        |
| wsrep_local_cached_downto    | 18446744073709551615                                     |
| wsrep_local_cert_failures    | 0                                                        |
| wsrep_local_commits          | 0                                                        |
| wsrep_local_index            | 1                                                        |
| wsrep_local_recv_queue       | 0                                                        |
| wsrep_local_recv_queue_avg   | 0.000000                                                 |
| wsrep_local_recv_queue_max   | 1                                                        |
| wsrep_local_recv_queue_min   | 0                                                        |
| wsrep_local_replays          | 0                                                        |
| wsrep_local_send_queue       | 0                                                        |
| wsrep_local_send_queue_avg   | 0.000000                                                 |
| wsrep_local_send_queue_max   | 1                                                        |
| wsrep_local_send_queue_min   | 0                                                        |
| wsrep_local_state            | 4                                                        |
| wsrep_local_state_comment    | Synced                                                   |
| wsrep_local_state_uuid       | 332eb3dc-d08c-11e8-b23f-3ea9f81c173c                     |
| wsrep_open_connections       | 0                                                        |
| wsrep_open_transactions      | 0                                                        |
| wsrep_protocol_version       | 9                                                        |
| wsrep_provider_name          | Galera                                                   |
| wsrep_provider_vendor        | Codership Oy <info@codership.com>                        |
| wsrep_provider_version       | 25.3.24(r3825)                                           |
| wsrep_ready                  | ON                                                       |
| wsrep_received               | 4                                                        |
| wsrep_received_bytes         | 531                                                      |
| wsrep_repl_data_bytes        | 0                                                        |
| wsrep_repl_keys              | 0                                                        |
| wsrep_repl_keys_bytes        | 0                                                        |
| wsrep_repl_other_bytes       | 0                                                        |
| wsrep_replicated             | 0                                                        |
| wsrep_replicated_bytes       | 0                                                        |
| wsrep_thread_count           | 2                                                        |
+------------------------------+----------------------------------------------------------+
61 rows in set (0.002 sec)

Настройка Open vSwitch

Open vSwitch Homepage

Так как в стандартных репозиториях нет пакета openvswitch, можно скачать исходники, скопилировать и установить, а можно воспользоваться репозиторием RDO:

for node in tank dozer truck; do ssh $node yum install https://rdoproject.org/repos/rdo-release.rpm; done
for node in tank dozer truck; do ssh $node yum install openvswitch; done

Добавим в автозагрузку и запустим демон:

for node in tank dozer truck; do ssh $node systemctl enable openvswitch; done
for node in tank dozer truck; do ssh $node systemctl start openvswitch; done

Сейчас настроим сетевой бридж, в который будут добавляться порты:

ovs-vsctl add-br ovs-br0
ovs-vsctl add-port ovs-br0 em1

Если настройка производится на удаленном сервере и кроме ssh другого доступа нет, то эти команды лучше выполнить позже, после правки конфигов сетевых интерфейсов.

Поправим конфиги сетевых интерфейсов. Для первой ноды:

/etc/sysconfig/network-scripts/ifcfg-em1
TYPE="OVSPort"
NM_CONTROLLED="no"
IPV4_FAILURE_FATAL="no"
IPV6INIT="no"
NAME="em1"
UUID="f1326702-cdc5-4743-8537-77ab270e47ab"
DEVICE="em1"
DEVICETYPE="OVSIntPort"
ONBOOT="yes"
OVS_BRIDGE="ovs-br0"

/etc/sysconfig/network-scripts/ifcfg-ovs-br0
DEVICE="ovs-br0"
NM_CONTROLLED="no"
ONBOOT="yes"
TYPE="OVSBridge"
BOOTPROTO="static"
IPADDR="192.168.5.201"
NETMASK="255.255.255.0"
GATEWAY="192.168.5.1"
DNS1="1.1.1.1"
DNS2="8.8.8.8"
HOTPLUG="no"

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

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

systemctl restart network

Установка и настройка OpenNebula

OpenNebula Homepage

На всех нодах подключим репозиторий OpenNebula:

# cat << EOT > /etc/yum.repos.d/opennebula.repo
[opennebula]
name=opennebula
baseurl=https://downloads.opennebula.org/repo/5.6/CentOS/7/x86_64
enabled=1
gpgkey=https://downloads.opennebula.org/repo/repo.key
gpgcheck=1
#repo_gpgcheck=1
EOT

Устанавливаем сервер, веб-интерфейс с api и мета-пакет, который создаст в системе пользователя oneadmin и установит на ноду libvirt и kvm:

for node in tank dozer truck; do ssh $node yum install -y opennebula-server opennebula-sunstone opennebula-node-kvm; done

Некоторые компоненты opennebula требуют наличия некоторых ruby библиотек и дополнительных пакетов. Для их установки на каждой ноде нужно запустить интерактивный скрипт:

/usr/share/one/install_gems

Если во время компиляции библиотек возникла ошибка

/usr/bin/ld: cannot find -lmariadb
collect2: ошибка: выполнение ld завершилось с кодом возврата 1
make: *** [mysql2.so] Ошибка 1


Gem files will remain installed in /usr/local/share/gems/gems/mysql2-0.5.1 for inspection.
Results logged to /usr/local/share/gems/gems/mysql2-0.5.1/ext/mysql2/gem_make.out

An error occurred while installing mysql2 (0.5.1), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.1' --source 'https://rubygems.org/'` succeeds before bundling.

То нужно выполнить:

ln -s /usr/lib64/libmysqld.so /usr/lib64/libmariadb.so
ln -s /usr/lib64/libmysqld.a /usr/lib64/libmariadb.a

Проверить все ли хорошо можно командой:

ld -lmariadb --verbose

После этого скрипт нужно запустить заново.

Установщик сам создал пользователя oneadmin в системе, ssh-ключи и правила для sudo. Так же этому пользователю необходимо разрешить заходить на каждую ноду по ssh без пароля. Для этого выполним:

sudo passwd oneadmin
sudo -u oneadmin cat /var/lib/one/.ssh/id_rsa.pub >> /var/lib/one/.ssh/authorized_keys
for node in dozer truck; do scp /var/lib/one/.ssh/* oneadmin@$node:/var/lib/one/.ssh/; done

Настроим базу данных:

mysql -u root -p
create database opennebula;
create user 'oneadmin'@'%' identified by 'JKnknjkncxsgEObf8343fdd5O';
grant all privileges on opennebula.* to 'oneadmin'@'%';
flush privileges;

Теперь сообщим opennebula как подключиться к нашей базе данных. Поправим конфиг /etc/one/oned.conf.
Закомментируем строку:

DB = [ BACKEND = "sqlite" ]

и добавим:

DB = [ BACKEND = "mysql",
        SERVER  = "localhost",
        PORT    = 0,
        USER    = "oneadmin",
        PASSWD  = "JKnknjkncxsgEObf8343fdd5O",
        DB_NAME = "opennebula",
        CONNECTIONS = 50 ]

Это нужно выполнить на каждой ноде.

Так же мы должны скопировать ключ авторизации oneadmin в кластере на остальные ноды, так как все управление кластером OpenNebula осуществляется именно под ним:

for node in dozer truck; do scp /var/lib/one/.one/one_auth oneadmin@$node.domain.local:/var/lib/one/.one/; done

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

systemctl start opennebula opennebula-sunstone

Проверяем:

http://192.168.5.201:9869

Проверим эти логи на наличие ошибок:

/var/log/one/oned.log /var/log/one/sched.log /var/log/one/sunstone.log

Если все ок, то выключаем:

systemctl stop opennebula opennebula-sunstone

Настройка отказоустойчивого кластера

ClusterLabs Homepage

Тут я сделал как в статье на Хабре

Будем использовать pacemaker, corosync and crmsh.

Отключим автозапуск демонов opennebula на всех нодах:

for node in tank dozer truck; do ssh $node.domain.local "systemctl disable opennebula opennebula-sunstone opennebula-novnc"; done

Добавим репозиторий на всех нодах:

cat << EOT > /etc/yum.repos.d/network\:ha-clustering\:Stable.repo
[network_ha-clustering_Stable]
name=Stable High Availability/Clustering packages (CentOS_CentOS-7)
type=rpm-md
baseurl=http://download.opensuse.org/repositories/network:/ha-clustering:/Stable/CentOS_CentOS-7/
gpgcheck=1
gpgkey=http://download.opensuse.org/repositories/network:/ha-clustering:/Stable/CentOS_CentOS-7/repodata/repomd.xml.key
enabled=1
EOT

Установим необходимые пакеты:

for node in tank dozer truck; do ssh $node "yum install corosync pacemaker crmsh resource-agents -y"; done

Пакет resource-agents потребовал cifs-utils, не знаю зачем он ему, но я не стал спорить и установил дополнительно и его.

Отредактируем на всех нодах конфиг /etc/corosync/corosync.conf и приведем его к следующему виду:

totem {
        version: 2
        crypto_cipher: none
        crypto_hash: none
        interface {
                ringnumber: 0
                bindnetaddr: 192.168.5.0
                mcastaddr: 226.94.1.1
                mcastport: 4000
                ttl: 1
        }
}
logging {
        fileline: off
        to_stderr: no
        to_logfile: yes
        logfile: /var/log/cluster/corosync.log
        to_syslog: yes
        debug: off
        timestamp: on
        logger_subsys {
                subsys: QUORUM
                debug: off
        }
}
quorum {
        provider: corosync_votequorum
}
service {
name: pacemaker
ver: 1
}
nodelist {
        node {
                ring0_addr: tank.domain.local
                nodeid: 1
        }
        node {
                ring0_addr: dozer.domain.local
                nodeid: 2
        }
        node {
                ring0_addr: truck.domain.local
                nodeid: 3
        }
}

Сгенерируем ключ и скопируем его на остальные ноды:

cd /etc/corosync
corosync-keygen
for node in dozer truck; do scp /etc/corosync/authkey root@$node:/etc/corosync/; done

Запустим HA-сервисы на всех нодах:

systemctl enable pacemaker corosync
systemctl start pacemaker corosync        

Проверяем статус:

[root@tank corosync]# crm status
Stack: corosync
Current DC: tank.domain.local (version 1.1.18-11.el7_5.3-2b07d5c5a9) - partition with quorum
Last updated: Tue Oct 16 13:50:33 2018
Last change: Tue Oct 16 13:50:26 2018 by hacluster via crmd on tank.domain.local

3 nodes configured
0 resources configured

Online: [ dozer.domain.local truck.domain.local tank.domain.local ]

No resources

Отключим STONITH (механизм добивания неисправной ноды):

crm configure property stonith-enabled=false

Если ноды всего две, то нужно отключить кворум, во избежании splitbrain'a:

crm configure property no-quorum-policy=stop

Теперь создадим ресурсы:

[root@tank corosync]# crm
crm(live)# configure
crm(live)configure# primitive ClusterIP ocf:heartbeat:IPaddr2 params ip="192.168.5.200" cidr_netmask="24" op monitor interval="30s"
crm(live)configure# primitive opennebula_p systemd:opennebula op monitor interval=60s timeout=20s op start interval="0" timeout="120s" op stop  interval="0" timeout="120s"
crm(live)configure# primitive opennebula-sunstone_p systemd:opennebula-sunstone op monitor interval=60s timeout=20s op start interval="0" timeout="120s" op stop  interval="0" timeout="120s"
crm(live)configure# primitive opennebula-novnc_p systemd:opennebula-novnc op monitor interval=60s timeout=20s op start interval="0" timeout="120s" op stop  interval="0" timeout="120s" 
crm(live)configure# group Opennebula_HA ClusterIP opennebula_p opennebula-sunstone_p  opennebula-novnc_p
crm(live)configure# exit
There are changes pending. Do you want to commit them (y/n)? y

Этими действиями мы создали виртуальный IP (192.168.5.200), добавили три наших сервиса в HA-кластер и объединили их в группу Opennebula_HA.

Проверяем:

[root@tank corosync]# crm status
Stack: corosync
Current DC: tank.domain.local (version 1.1.18-11.el7_5.3-2b07d5c5a9) - partition with quorum
Last updated: Tue Oct 16 13:59:05 2018
Last change: Tue Oct 16 13:57:53 2018 by root via cibadmin on tank.domain.local

3 nodes configured
4 resources configured

Online: [ dozer.domain.local truck.domain.local tank.domain.local ]

Full list of resources:

Resource Group: Opennebula_HA
      ClusterIP        (ocf::heartbeat:IPaddr2):        Started tank.domain.local
      opennebula_p        (systemd:opennebula):        Started tank.domain.local
      opennebula-sunstone_p        (systemd:opennebula-sunstone):        Started tank.domain.local
      opennebula-novnc_p        (systemd:opennebula-novnc):        Started tank.domain.local

На этом настройка HA закончена.

Подключение Ceph хранилища к OpenNebula и первоначальная конфигурация

Возвращаемся к нашему ceph хранилищу. Необходимо в ceph создать пользователя для доступа к созданным пулам one и one-system. Этот пользователь так же будет использоваться libvirt'ом для доступа к образам дисков. Создадим пользователя libvirt:

ceph auth get-or-create client.libvirt mon 'profile rbd' osd 'profile rbd pool=one'

Получим ключ и сохраним его:

ceph auth get-key client.libvirt | tee client.libvirt.key
ceph auth get client.libvirt -o /etc/ceph/ceph.client.libvirt.keyring

Файл keyring скопируем в каталог /etc/ceph на оставшихся нодах:

for node in dozer truck; do scp ceph.client.libvirt.keyring root@$node.domain.local:/etc/ceph/; done

Сохраним ключ авторизации для libvirtd:

[vadim@tank ~]$ sudo su - oneadmin

[oneadmin@tank ~]$ UUID=`uuidgen`; echo $UUID
u86d28f9-84af-49c8-87db-b5f379e26364

[oneadmin@tank ~]$ cat > secret.xml <<EOF
<secret ephemeral='no' private='no'>
  <uuid>$UUID</uuid>
  <usage type='ceph'>
          <name>client.libvirt secret</name>
  </usage>
</secret>
EOF

[oneadmin@tank ~]$ for node in tank dozer truck; do virsh --connect=qemu+ssh://oneadmin@$node.domain.local/system secret-define secret.xml; done
[oneadmin@tank ~]$ for node in tank dozer truck; do virsh --connect=qemu+ssh://oneadmin@$node.domain.local/system secret-set-value --secret $UUID --base64 $(cat client.libvirt.key); done

Файл key после этого можно удалить:

rm client.libvirt.key

Теперь подключим пул для images:

[oneadmin@tank ~]$ cat << EOT > rbd-images.conf
NAME = "ceph-images-ds"
DS_MAD = ceph
TM_MAD = ceph
DISK_TYPE = RBD
POOL_NAME = one
BRIDGE_LIST ="192.168.5.201 192.168.5.202 192.168.5.203"
CEPH_HOST ="192.168.5.201:6789 192.168.5.202:6789 192.168.5.203:6789"
CEPH_SECRET ="376d28f9-84af-49c8-87db-b5fe85e26364"
CEPH_USER = libvirt
EOT


[oneadmin@tank ~]$ onedatastore create rbd-images.conf

Пул system:

[oneadmin@tank ~]$ cat << EOT > rbd-system.conf
NAME = "ceph-system-ds"
TM_MAD = ceph
DISK_TYPE = RBD
POOL_NAME = one-system
TYPE = SYSTEM_DS
BRIDGE_LIST ="192.168.5.201 192.168.5.202 192.168.5.203"
CEPH_HOST ="192.168.5.201:6789 192.168.5.202:6789 192.168.5.203:6789"
CEPH_SECRET ="376d28f9-84af-49c8-87db-b5fe85e26364"
CEPH_USER = libvirt
EOT

[oneadmin@tank ~]$ onedatastore create rbd-system.conf

Далее заходим в веб-интерфейс. Он всегда будет доступен по адресу http://192.168.5.200:9869

login: oneadmin
pass: находится в /var/lib/one/.one/one_auth

В веб-интерфейсе создаем кластер, добавляем ноды и виртуальную сеть. Интерфейс очень понятный, поэтому описывать тут эту настройку не буду.

Настройка https на веб-интерфейсе управления кластером

Nginx Homepage

Добавим репозиторий nginx:

cat << EOT > /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/\$basearch/
gpgcheck=0
enabled=1
EOT

Установим nginx:

for node in tank dozer truck; do ssh $node.domain.local yum install -y nginx nginx-module-geoip; done

Добавим его в автозагрузку:

for node in tank dozer truck; do ssh $node.domain.local systemctl enable nginx; done

Удалим дефолтный конфиг:

for node in tank dozer truck; do ssh $node.domain.local rm -f /etc/nginx/conf.d/default.conf; rm -f /etc/nginx/nginx.conf; done

Сертификаты для https можно использовать самоподписанные или от Let's Encrypt - тут уже как душе угодно. Информации о том, как сделать любую из этих вещей, в интернете вагон и две тележки - описывать тут не буду.

На каждой ноде добавляем следующие конфиги:

less /etc/nginx/nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    tcp_nopush      on;
    tcp_nodelay     on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    ssl_session_cache   shared:SSL:100m;
    ssl_session_timeout 1h;

    include /etc/nginx/conf.d/*.conf;
    server_tokens off;
}
less /etc/nginx/conf.d/one.conf
##
## Upstreams
###

upstream one-crm {
        server 192.168.5.200:9869;
}

##
## HTTP Server
###

server {
        listen 869 default_server;
        server_name one-cluster.domain.local;
        return 301 https://one-cluster.domain.local:4869$request_uri;
}

##
## HTTPS Server
###

server {
        listen 4869 ssl;
        server_name one-cluster.domain.local;

        ssl_certificate /etc/ssl/one-cluster.domain.local/one_domain_local.crt; 
        ssl_certificate_key /etc/ssl/one-cluster.domain.local/one_domain_local.key;

        ssl_protocols TLSv1.2;
        ssl_prefer_server_ciphers on;

        ssl_dhparam /etc/ssl/certs/dhparam.pem;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:AES256-GCM-SHA384:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";

        location / {
                proxy_pass http://one-crm;
                proxy_store off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-Host $host;
                proxy_set_header X-Forwarded-Server $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                client_max_body_size 0;
                client_body_buffer_size 128k;
                proxy_connect_timeout 60;
                proxy_send_timeout 60;
                proxy_read_timeout 60;
                proxy_buffer_size 8k;
                proxy_buffers 4 32k;
                proxy_busy_buffers_size 64k;
                proxy_temp_file_write_size 64k;
                location ~ /\.ht {
                        deny all;
                }
                location ~ /\.git {
                        deny all;
                }
        }
}

Проверим, что конфиг без ошибок:

sudo nginx -t

И запустим nginx:

sudo systemctl start nginx

Теперь подключение к основному веб интерфейсу у нас шифруется tls1.2, осталось зашифровать подключение к vnc.

Правим конфиг /etc/one/sunstone-server.conf

:vnc_proxy_port: 29876
:vnc_proxy_support_wss: only
:vnc_proxy_cert: /etc/ssl/one-cluster.domain.local/one_domain_local.crt
:vnc_proxy_key: /etc/ssl/one-cluster.domain.local/one_domain_local.key

И перезапускаем:

sudo systemctl restart opennebula-sunstone

Но несмотря на то, что мы в конфиге описали расположение сертификатов, wss не хочет работать. При попытке запуска vnс подключения оно не будет устанавливаться, в консоли FF увидим сообщение "Firefox can’t establish a connection to the server at wss", а в логе /var/log/one/novnc.log будет сообщение "SSL connection but '/self.pem' not found".

Не знаю, может я плохо читал документацию к opennebula, но в ней я информации об этом не нашел, поэтому выбрал немного костыльный метод (зато работает).
В файле /usr/share/one/websockify/websockify я подправил два параметра, чтобы получилось так:

    parser.add_option("--cert", default="/etc/ssl/one-cluster.domain.local/one_domain_local.crt",
            help="SSL certificate file")
    parser.add_option("--key", default="/etc/ssl/one-cluster.domain.local/one_domain_local.key",
            help="SSL key file (if separate from cert)")

И перезапустил opennebula-novnc:

sudo systemctl restart opennebula-novnc

Пробуем подключиться:

Настройка firewall

Как я писал выше, в работе я использую iptables (firewalld мне неудобен). Ниже представлен список правил для этого firewall, необходимых для функционирования кластера:

## Allow full access from dozer
-A INPUT -s 192.168.5.202 -j ACCEPT
## Allow full access from truck
-A INPUT -s 192.168.5.203 -j ACCEPT
## Allow ceph cluster network
-A INPUT -s 10.0.1.0/28 -j ACCEPT
## Allow access to one web interface
-A INPUT -s ${admin-desktop-ip} -p tcp -m multiport --ports 869,4869,29876 -j ACCEPT

Источники

Комментарии (RSS)

Автор молодец! Спасибо, очень помог

Ответить Отменить ответ

вопрос к автору

[ceph_deploy.mon][ERROR ] Some monitors have still not reached quorum:

всё проходи ок по мануалу, фаерволы выключены, selinux=disabled

сеть 192.168.30.0/24

что могло пойти не так?

Ответить Отменить ответ

А что в логах? Это при инициализации мониторов возникает?

Ответить Отменить ответ

Я переделал всё с нуля и заработало, единственное что - это нужно использовать другого юзера вместо ceph, он зарезервирован самим сервисом. Спасибо за статью, кармы ++.

Ответить Отменить ответ

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

Комментарий ожидает проверки

HTML Preview:

Коротко о себе:

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

Связаться со мной можно, написав письмо на адрес vadim@adminbook.click