Piszki Lab

Analiza przypadku w języku przodków…

CloudStack – instalacja i konfiguracja, część 3, przygotowanie węzła.

| 0 comments

W poprzednich częściach zapoznaliśmy się z terminologią CloudStack i z konfiguracją sieci na węzłach. W tym poście skupimy się na przygotowaniu węzłów do pełnienia roli serwera wirtualizacji oraz poczynimy pierwsze kroki w konfiguracji środowiska zarządczego. Niestety, w między czasie musiałem oddać fizyczne serwery, dlatego dalszy ciąg będzie opisany na podstawie trzech wirtualnych maszyn uruchomionych pod ESXi. O tym jak przygotować zagnieżdżony serwer KVM w VMware vSphere pisałem tutaj, różnica jest tylko jedna, jako że będziemy stawiać CloudStack z siecią zaawansowaną (VLAN), zagnieżdżony KVM musi być przypięty do port grupy typu Trunk (dla sieci CloudStack). Będzie to długi i nudny wpis, ale bez niego nie da rady iść dalej.

Bazujemy na systemie CentOS 7, najlepiej jest aby wszystkie węzły miały ten sam zestaw pakietów. W poprzednim artykule instalowane były pakiety potrzebne do kompilacji i instalacji OpenvSwitch, teraz doinstalujemy wszystko to, co będzie nam potrzebne. Zaczynamy od stworzenia właściwych plików repo:

/etc/yum.repos.d/CloudStack.repo

[cloudstack-4.10]
name=cloudstack
baseurl=http://cloudstack.apt-get.eu/centos/7/4.10/
enabled=1
gpgcheck=0
gpgkey=http://cloudstack.apt-get.eu/release.asc

/etc/yum.repos.d/MariaDB.repo

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

 /etc/yum.repos.d/Ceph.repo

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

Instalujemy potrzebne pakiety:
yum install nano bash-completion mc net-tools wget curl bind-utils lsof rpcbind nfs-utils scree bmon epel-release ntp keepalived haproxy rsync nmap perl-Dbi nc socat jemalloc xinetd galera mariadb-server mariadb-client kvm libvirt virt-install virt-manager qemu-kvm libvirt-client virt-viewer bridge-utils qemu-img libvirt-python xauth cloudstack-agent cloudstack-management cloudstack-usage

Każdy węzeł będzie pełnił wiele ról, będzie członkiem klastra MariaDB-Galera, członkiem klastra CloudStack, serwerem KVM oraz członkiem klastra Ceph (dlatego możemy zainstalować wszystkie pakiety od razu). Dlaczego Ceph? Dlatego że potrzebujemy współdzielonej, klastrowanej przestrzeni dyskowej, bez niego nie będzie możliwe przenoszenie maszyn pomiędzy hostami (vMotion). Oczywiście wspierane są też dyski lokalne w CloudStack, niestety tutaj jesteśmy zamknięci w jednym hoście. A my chcemy postawić konfigurację zaawansowaną, przypominającą funkcjonalnie VMware vSphere.

Wróćmy do storage, CloudStack potrzebuje wejściowo dwóch przestrzeni, Primary Storage i Secondary Storage. Primary pełni rolę głównej, współdzielonej przestrzeni a Secondary jest udziałem NFS. W obydwu przypadkach wykorzystamy Ceph (można też GlusterFS jeśli mamy mniej niż 3 węzły), CloudStack jako jedyne znane mi rozwiązanie (typu Open Source) wspiera SharedMountPoint, jest to lokalnie zamontowana przestrzeń dyskowa dostępna bezpośrednio na każdym węźle z poziomu systemu plików. Oznacza to, że tak jak w VMware, mamy dostęp fizyczny do pliko dysków maszyn wirtualnych (które leżą sobie we współdzielonym katalogu). Można też Ceph montować jako udział RBD (blokowy) i jest to metoda preferowana dla sieci 10GB, jeśli konfiguracja jaką stawiamy idzie po sieci 1GB to zróbmy to jako CephFS (osiągniemy większą wydajność niż RBD po 1GB). Secondary Storage wystawimy jako udział CephFS po NFS na każdym węźle, dostęp będzie poprzez pływający adres IP hostowany przez KeepaliveD (można też poprzez Ganesha NFS lub montować ze zdalnego serwer NFS, np. z NAS).

Kontynuujemy przygotowanie węzła (na każdym węźle te ustawienia są takie same), zaczniemy od systemu. Do poprawnego działania sieci wewnątrz serwerów KVM należy odpowiednio dostroić parametry jądra systemu, robimy to za pomocą zawartości pliku /etc/sysctl.conf :

net.ipv4.ip_forward = 1
net.ipv4.ip_nonlocal_bind = 1
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0

W przypadku SELinux i FirewallD, proponuję wyłączyć i dostroić do własnych potrzeb po poprawnym uruchomieniu całości. W kolejnym kroku konfigurujemy KVM (zmieniamy podane parametry w podanych plikach konfiguracyjnych). Włączamy nasłuchiwanie na porcie 16509 w ruchu nieszyfrowanym i nie autentykowanym (wymaganie podstawowe CloudStack):

/etc/libvirtd/libvird.conf:

listen_tcp=1
listen_tls=1
tcp_port=”16509”
mdns_adv=0
auth_tcp=”none”

Nasłuchiwanie konsoli VNC:

/etc/libvirtd/qemu.conf:
vnc_listen=0.0.0.0

Nasłuchiwanie libvirtd (-l to odpowiednik –listen).

/etc/sysconfig/libvirtd:
LIBVIRTD_ARGS=-l

Zmiany aktywujemy poprzez restart usługi libvirtd lub hosta. W pliku konfiguracyjnym /etc/cloudstack/agent/agent.properties zmieniamy następujące opcje:

network.bridge.type=openvswitch
libvirt.vif.driver=com.cloud.hypervisor.kvm.resource.OvsVifDriver

Dopisujemy linie:

guest.cpu.model=SandyBridge (lub zgodne z naszą architekturą)
guest.cpu.mode=custom

Standardowe mostki sieciowe (instalowane z KVM) wchodzą w interakcję z OpenvSwitch, należy zablokować moduł jądra odpowiedzialny za ich obsługę.

Tworzymy plik /etc/modprobe.d/blacklist.conf z zawartością „blacklist bridge”.

Przypomnijmy, na tym etapie mamy trzy (wirtualne w moim przypadku) serwery przygotowane do pełnienia wielu ról wraz ze skonfigurowaną siecią. Budujemy środowisko odporne na awarie, HA w CloudStack oprzemy na KeepaliveD i HAProxy. CloudStack nie wspiera MariaDB-Galera wprost, dlatego będzie się z nią łączył poprzez pływający adres IP który będzie także punktem wejścia dla usługi NFS, do połączeń CloudStack Agent oraz do łączenia się z interfejsem WEB CloudStack Managemen Server (oczywiście jeśli stawiacie CloudStack na pojedynczej maszynie to nie potrzebujecie ani klastra Galery ani Ceph i w zasadzie możecie pominąć dalszą część posta). Dla każdego IP tworzymy rekord DNS, w moim przypadku będzie to:

pstack – 172.18.2.144 (IP pływający)
pstack1 – 172.18.28.145 (węzeł 1)
pstack2 – 172.18.28.146 (węzeł 2)
pstack3 – 172.18.28.147 (węzeł 3)

Jako że każdy węzeł jest równy, nie będzie powrotu na stary serwer po jego ponownym uruchomieniu po awarii (usługi przeskoczą i zostaną na nowym serwerze). Konfiguracja KeepaliveD (dla KVM działającego jako wirtualna maszyna należy zastosować opcje unicast):

global_defs {
router_id CS_LAB
}
vrrp_script haproxy {
 script "/usr/bin/killall -0 haproxy"
interval 2
weight 2
}

vrrp_instance VI_1 {
virtual_router_id 59
advert_int 1
priority 101
unicast_src_ip 192.168.70.71 #(adresy przykładowe)
state MASTER
interface ens160
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.18.28.144/24 dev ens160
}
unicast_peer {
192.168.70.72
{
track_script {
haproxy
}
}

Konfiguracja ta obsługuje usługę MariaDB-Galera (za pomocą skryptu clustercheck o czym będzie niżej) oraz dostęp do usługi CloudStack Management Server (po http i https). Czas najwyższy uruchomić sam klaster Galery, jest to bardzo proste. Tworzymy na każdym węźle właściwy plik /etc/my.cnf.d/server.conf (tutaj macie mój):

[server]
[mysqld]
bind-address = 0.0.0.0
binlog_format = ROW
character_set_server = utf8
collation_server = utf8_general_ci
datadir = /var/lib/mysql
default_storage_engine = InnoDB
expire_logs_days = 10
innodb_autoinc_lock_mode = 2
innodb_buffer_pool_size = 1G
innodb_log_file_size = 512M
innodb_doublewrite = 1
innodb_file_per_table = 1
innodb_flush_log_at_trx_commit = 2
innodb_lock_wait_timeout = 600
innodb_stats_on_metadata = 0
key_buffer_size = 256M
lock_wait_timeout = 300
max_allowed_packet = 128M
max_binlog_size = 128M
max_connections = 350
myisam_sort_buffer_size = 64M
net_buffer_length = 8K
query_cache_limit = 64M
query_cache_size = 128M
read_buffer_size = 8M
read_rnd_buffer_size = 8M
skip-external-locking
sort_buffer_size = 16M
table_cache = 4096
table_definition_cache = 65535
table_open_cache = 65535
thread_cache_size = 8
log_error = /var/log/mariadb/mariadb_error.log
#general_log_file = /var/log/mariadb/mariadb.log
#general_log = 1
[galera]
wsrep_on=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address='gcomm://172.18.28.145,172.18.28.146,172.18.28.147’
wsrep_cluster_name='cloudstack_db'
wsrep_node_name='H1'
wsrep_node_address='172.18.28.145'
wsrep_sst_method=rsync
wsrep_sst_auth=sst_user:dbpass
[embedded]
[mariadb]
[mariadb-10.1]
[mysqldump]
max_allowed_packet = 16M
quick
quote-names
[mysql]
[isamchk]
key_buffer = 256M
read_buffer = 16M
sort_buffer_size = 256M
write_buffer = 16M

Na każdym węźle poprawiamy node_name i node_address i uruchamiamy na pierwszym węźle poleceniem galera_new_cluster (wystartowanie nowego klastra jest potrzebne zawsze gdy wyłączone będą wszystkie węzły). Na pozostałych startujemy standardowo systemctl start/enable mariadb i dalej mysql_secure_installation (w tym przykładzie hasło na root db ustawiamy na dbpass).

Teraz skonfigurujemy skrypt clustercheck:

wget https://raw.githubusercontent.com/olafz/percona-clustercheck/master/clustercheck

chmod +x clustercheck
mv clustercheck /usr/bin/

vi /etc/xinetd.d/mysqlchk

# default: on
# description: mysqlchk
service mysqlchk
{
        disable = no
        flags = REUSE
        socket_type = stream
        port = 9200             # This port used by xinetd for clustercheck
        wait = no
        user = nobody
        server = /usr/bin/clustercheck
        log_on_failure += USERID
        log_on_success =
        only_from = 0.0.0.0/0
        per_source = UNLIMITED
}

vi /etc/services

mysqlchk        9200/tcp                # mysqlchk
#wap-wsp         9200/tcp                # WAP connectionless session service
#wap-wsp         9200/udp                # WAP connectionless session service

systemctl start/enable xinetd

mysql -u root -p
GRANT PROCESS ON *.* TO ‘clustercheckuser’@’localhost’ IDENTIFIED BY ‘clustercheckpassword!’ ;
exit;

Testy (jeśli macie błąd, to sprawdźcie w skrypcie clustercheck czy prawidłowo podany jest użytkownik i hasło):

[root@pstack2 ~]# /usr/bin/clustercheck
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: close
Content-Length: 40

Percona XtraDB Cluster Node is synced.

W kolejnym kroku konfigurujemy HAProxy:

global
log         127.0.0.1 local2

    chroot      /var/lib/haproxy
pidfile     /var/run/haproxy.pid
maxconn     4000
user        haproxy
group       haproxy
daemon

    stats socket /var/lib/haproxy/stats

defaults
mode                    http
log                     global
option                  tcplog
option                  dontlognull
option http-server-close
option forwardfor       except 127.0.0.0/8
option                  redispatch
retries                 3
timeout http-request    10s
timeout queue           1m
timeout connect         10s
timeout client          1m
timeout server          1m
timeout http-keep-alive 10s
timeout check           10s
maxconn                 3000

listen mariadb_cluster 0.0.0.0:3030
mode tcp
balance leastconn
option httpchk
server pstack1:3306 172.18.28.145:3306 check port 9200
server pstack2:3306 172.18.28.146:3306 check port 9200
server pstack3:3306 172.18.28.147:3306 check port 9200

listen stats 0.0.0.0:9000
mode http
stats enable
stats uri /stats
stats realm HAProxy\ Statistics
stats auth admin:admin
stats admin if TRUE

frontend ui
bind 172.18.28.144:80
mode http
option forwardfor
option httplog
use_backend uib

#frontend uis   <—to wykorzystamy później
#        bind 172.18.28.144:443 ssl crt /etc/haproxy/cloud.pem
#        mode http
#        option httpclose
#        option forwardfor
#        reqadd X-Forwarded-Proto:\ https
#        use_backend uib

backend uib
balance source
server pstack1:8080 172.18.28.145:8080 maxconn 32 check inter 5000
server pstack2:8080 172.18.28.146:8080 maxconn 32 check inter 5000
server pstack3:8080 172.18.28.147:8080 maxconn 32 check inter 5000

Testy:

mysql -u root -p
GRANT ALL PRIVILEGES ON *.* TO root@’%’ IDENTIFIED BY “dbpass”;

mysql -u root -p -h 172.18.28.X -P 3030 -e “select Host, User, Password from mysql.user”

Dzięki takiej konfiguracji uzyskaliśmy klaster MariaDB-Galera dostępny na porcie 3030 poprzez każdy adres IP (w tym najważniejszy, pływający), każde połączenie jest balansowane przez HAProxy pomiędzy wszystkimi węzłami. Taka konfiguracja zabezpieczy CloudStack Management Server przed awariami węzłów. Dodatkowo mamy podgląd na pracę HAProxy pod adresem http://172.18.28.x:9000/stats. Na tę chwilę zostawimy Galerę i przejdziemy do Ceph. Instalacja i uruchomienie Ceph jest bardzo proste, musimy jedynie spełnić podstawy warunek, minimum trzy serwery i minimum jeden dysk per serwer przeznaczony pod pulę dyskową. Można zmusić Ceph do uruchomienia na jednym i dwóch węzłach ale to już jest dłubanie i pozostawiam to Wam (możecie też zastosować GlusterFS 1:1).

Na wybranym węźle który będzie pełnił rolę Admin Server dla Ceph instalujemy pakiet ceph-deploy (a na każdym ceph-fuse). Dodatkowo dla użytkownika który będzie pełnił rolę Admin Ceph (np. root) generujemy klucz ssh (ssh-keygen z pustym hasłem) i rozsyłamy go poleceniem ssh-copy-id na pozostałe węzły. Rezultat jaki musimy osiągnąć to możliwość zalogowania się po ssh bez hasła na każdy węzeł. Tworzymy też plik (uprawnienia 644):

[root@pstack1 .ssh]# cat config

Host pstack1
Hostname pstack1
User root
Host pstack2
Hostname pstack2
User root
Host pstack3
Hostname pstack3
User root

Następnie wydajemy polecenie (najlepiej w jakimś katalogu a nie w katalogu domowym użytkownika):

ceph-deploy new pstack1 pstack2 pstack3

W ten sposób uzyskamy inicjalną konfigurację Ceph, modyfikujemy plik ceph.conf do postaci jaka nas interesuje (tutaj mój):

[root@pstack1 ceph]# cat ceph.conf

[global]
fsid = b1bf8ac2-d9b6-486c-9ca5-6abd59e6d20e
mon_initial_members = pstack1, pstack2, pstack3
mon_host = 172.16.28.145,172.18.28.146,172.18.28.147
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx
osd_pool_default_size = 2
osd_pool_default_min_size = 2
osd pool default pgp num = 256
osd pool default pg num = 256
osd max object name len = 256
osd max object namespace len = 64
mon_allow_pool_delete = True
public network = 172.18.28.0/24
cluster network = 172.18.37.0/24

[osd]
osd mkfs options xfs = -f -i size=2048
osd mkfs type = xfs
osd journal size = 5120
osd mount options xfs = noatime,largeio,inode64,swalloc

Zmienne public network i cluster network definiują nam sieci którymi Ceph udostępnia i wymienia pomiędzy węzłami dane. Nie są obligatoryjne, jeśli ich nie użyjemy to cała komunikacja pójdzie głównym interfejsem sieciowym maszyny (zalecane jest jednak aby szło to osobnymi interfejsami). Następnie wykonujemy polecenie:

ceph-deploy install pstack1 pstack2 pstack3


(można ją ponawiać np. dla wybranego serwera gdy coś będzie nie tak). Jeśli instalacja wykonała się poprawnie, wykonujemy polecenie:

ceph-deploy mon create-initial


(roześlemy konfigurację do węzłów). Teraz wydajemy polecenie:

ceph-deploy gatherkeys pstack1

ceph-deploy admin pstack1 pstack2 pstack3


(roześlemy klucz administracyjny umożliwiający działanie polecenia ceph, np. ceph –w do monitorowania stanu klastra) i na końcu:

ceph-deploy mgr create pstack1 pstack2 pstack3


Na tym etapie mamy działający klaster Ceph bez podłączonych dysków (OSD). Przygotowanie i aktywowanie dysków jest równie proste, u mnie pod OSD idą dyski sdb, wykonujemy polecenie (dla Ceph Luminous i nowszych z fs bluestore):

ceph-deploy osd prepare –bluestore –block-db /dev/sdb –block-wal /dev/sdb pstack2:sdb

ceph-deploy osd activate pstack2:sdb1

Dla wersji Mimic i nowszych: ceph-deploy osd create --data /dev/sdb pstack2

Testy:

[root@pstack1 ceph]# ceph osd tree
ID CLASS WEIGHT  TYPE NAME        STATUS REWEIGHT PRI-AFF
-1       0.29095 root default
-3       0.09698     host pstack1
0   hdd 0.09698         osd.0        up  1.00000 1.00000
-5       0.09698     host pstack2
1   hdd 0.09698         osd.1        up  1.00000 1.00000
-7       0.09698     host pstack3
2   hdd 0.09698         osd.2        up  1.00000 1.00000
[root@pstack1 ceph]# ceph -s
cluster:
id:     b1bf8ac2-d9b6-486c-9ca5-6abd59e6d20e
health: HEALTH_OK

services:
mon: 3 daemons, quorum pstack1,pstack2,pstack3
mgr: pstack1(active), standbys: pstack3, pstack2
osd: 3 osds: 3 up, 3 in

data:
pools:   0 pools, 0 pgs
objects: 0 objects, 0 bytes
usage:   6149 MB used, 292 GB / 298 GB avail
pgs:

Czyli mamy działający klaster Ceph, trzy węzły, trzy dyski, trzy monitory. To nie koniec, dla CephFS musimy jeszcze uruchomić MetaDadata Server, stworzyć FS i zamontować go lokalnie na każdym serwerze. Jeśli wielkość 128 jest zbyt duża dla Was (komunikat o błędzie) to dopasujcie ją do wielkości dysku zmniejszając odpowiednio podane wartości.

ceph-deploy mds create pstack1 pstack2 pstack3

ceph osd pool create cephfs_data 128

ceph osd pool create cephfs_metadata 128

ceph fs new cephfs cephfs_metadata cephfs_data

Testy:

[root@pstack1 ceph]# ceph mds stat
cephfs-1/1/1 up  {0=pstack3=up:active}, 2 up:standby

Teraz pozostaje zamontować wolumen cephfs lokalnie na każdym węźle, jest wiele metod, najprostsza to /etc/fstab (cp /etc/ceph/ceph.client.admin.keyring /etc/ceph.key chmod 644 /etc/ceph.key w samym pliku należy pozostawić jedynie wartość klucza):

172.18.28.145:6789:/            /data           ceph            name=admin,secretfile=/etc/ceph.key,_netdev,noatime     0 2

Na końcu będziemy potrzebowali udziału NFS, udział ten będzie wykorzystywany przez maszynę systemową CloudStack Secondary Storage VM i służy do przechowywania template maszyn systemowych (routery wirtualne), template maszyn które zrobicie i snapshotów. Można użyć dowolnego serwera NFS (np. NAS), ja uruchomię lokalnie na każdym węźle serwer NFS dla katalogu /data/nfs a montować udział będę poprzez pływający adres IP. Dzięki temu awaria jednego z węzłów nie spowoduje niedostępności serwera NFS (taką samą funkcjonalność daje Ganesha NFS). Uruchamiamy potrzebne usługi:

systemctl enable rpcbind
systemctl enable nfs-server
systemctl enable nfs-lock
systemctl enable nfs-idmap
systemctl start rpcbind
systemctl start nfs-server
systemctl start nfs-lock
systemctl start nfs-idmap

I robimy wpis w pliku /etc/exports:

/data/nfs       172.18.28.0/24(rw,sync,no_root_squash,no_all_squash)

I to w tym poście na tyle. Dużo pracy trzeba wykonać ale jest ona niezbędna aby później na poziomie CloudStack uniknąć problemów. Dobrze przygotowany węzeł to podstawa. W kolejnym poście uruchomimy CloudStack i wykonamy inicjalną konfigurację. Mam nadzieję że jeszcze się nie zniechęciliście, tak na prawdę, przy odrobinie wprawy całość instalacji i konfiguracji sporego środowiska zajmuje dzień maksymalnie dwa. Jak do tego dołożymy Ansible to postawienie CloudStack zajmuje chwilę.

Oceń ten artykuł:
[Głosów:0    Średnia:0/5]

Dodaj komentarz

Required fields are marked *.


.

Podobał się wpis? Wesprzyj Piszki Lab, kliknij w reklamę! :-)

.