
Już pisaliśmy o , który umożliwia rozwój aplikacji rozproszonych i ich pakowanie. Zostało tylko nauczyć się wdrażać te aplikacje i nimi zarządzać. Nie martw się, wszystko przewidzieliśmy! Zebraliśmy najlepsze praktyki dotyczące pracy z Tarantool Cartridge i napisaliśmy , która zainstaluje pakiet na serwerach, uruchomi instancje, połączy je w klaster, skonfiguruje autoryzację, zainicjuje vshard, włączy automatyczny failover i zaktualizuje konfigurację klastra.
Ciekawi? Zapraszam do rozwinięcia, wszystko opowiemy i pokażemy.
Zacznijmy od przykładu
Zastanowimy się tylko nad częścią funkcjonalności naszej roli. Pełny opis wszystkich jej możliwości i parametrów wejściowych znajdziesz zawsze w . Ale lepiej raz spróbować niż sto razy zobaczyć, więc zainstalujmy małą aplikację.
Tarantool Cartridge ma do stworzenia niewielkiej aplikacji Cartridge, która przechowuje informacje o klientach banku i ich kontach, a także udostępnia API do zarządzania danymi przez HTTP. W aplikacji opisane są dwie możliwe role: api i magazyn, które mogą być przypisane do instancji.
Sam Cartridge nic nie mówi o tym, jak uruchamiać procesy, udostępnia jedynie możliwość konfiguracji już uruchomionych instancji. Resztę użytkownik musi zrobić sam: rozstawić pliki konfiguracyjne, uruchomić usługi i skonfigurować topologię. Ale tym wszystkim zajmie się za nas Ansible.
Od słów do czynów
Zatem zainstalujemy naszą aplikację na dwóch maszynach wirtualnych i skonfigurujemy prostą topologię:
- Replika zestaw
app-1będzie realizować rolęapi, która obejmuje rolęvshard-router. Będzie tylko jedna instancja. - Replika zestaw
storage-1realizuje rolęmagazyn(a jednocześnievshard-storage), dodamy tutaj dwie instancje z różnych maszyn.

Aby uruchomić przykład potrzebujemy i (wersje 2.8 lub wyższe).
Rola znajduje się w . To takie repozytorium, które pozwala dzielić się swoimi osiągnięciami i korzystać z gotowych ról.
Sklonujmy repozytorium z przykładem:
$ git clone https://github.com/dokshina/deploy-tarantool-cartridge-app.git
$ cd deploy-tarantool-cartridge-app && git checkout 1.0.0Uruchamiamy maszyny wirtualne:
$ vagrant upInstalujemy rolę ansible Tarantool Cartridge:
$ ansible-galaxy install tarantool.cartridge,1.0.1Uruchamiamy zainstalowaną rolę:
$ ansible-playbook -i hosts.yml playbook.ymlCzekamy na zakończenie wykonania playbooka, przechodzimy do i cieszymy się rezultatem:

Można przesyłać dane. Fajnie, prawda?
A teraz rozwiążmy, jak to działa, a przy okazji dodamy jeszcze jeden replikaset do topologii.
Zaczynamy się rozglądać
Zatem, co się wydarzyło?
Utworzyliśmy dwie maszyny wirtualne i uruchomiliśmy playbook ansible, który skonfigurował nasz klaster. Zobaczmy zawartość pliku playbook.yml:
---
- name: Wdrażam moją aplikację Tarantool Cartridge
hosts: all
become: true
become_user: root
tasks:
- name: Importuj rolę Tarantool Cartridge
import_role:
name: tarantool.cartridgeTu nic interesującego się nie dzieje, uruchamiamy rolę ansible, która nazywa się tarantool.cartridge.
Wszystko, co najważniejsze (a mianowicie, konfiguracja klastra) znajduje się w -pliku hosts.yml:
---
all:
vars:
# wspólne zmienne klastra
cartridge_app_name: getting-started-app
cartridge_package_path: .\/getting-started-app-1.0.0-0.rpm # ścieżka do pakietu
cartridge_cluster_cookie: app-default-cookie # cookie klastra
# wspólne opcje ssh
ansible_ssh_private_key_file: ~\/vagrant.d\/insecure_private_key
ansible_ssh_common_args: '-o IdentitiesOnly=yes -o UserKnownHostsFile=\/dev\/null -o StrictHostKeyChecking=no'
# INSTANCJE
hosts:
storage-1:
config:
advertise_uri: '172.19.0.2:3301'
http_port: 8181
app-1:
config:
advertise_uri: '172.19.0.3:3301'
http_port: 8182
storage-1-replica:
config:
advertise_uri: '172.19.0.3:3302'
http_port: 8183
children:
# GRUPUJ INSTANCJE WG MASZYN
host1:
vars:
# opcje połączenia z pierwszą maszyną
ansible_host: 172.19.0.2
ansible_user: vagrant
hosts: # instancje, które będą uruchamiane na pierwszej maszynie
storage-1:
host2:
vars:
# opcje połączenia z drugą maszyną
ansible_host: 172.19.0.3
ansible_user: vagrant
hosts: # instancje, które będą uruchamiane na drugiej maszynie
app-1:
storage-1-replica:
# GRUPUJ INSTANCJE WG REPLIKASETÓW
replicaset_app_1:
vars: # konfiguracja repliki
replicaset_alias: app-1
failover_priority:
- app-1 # lider
roles:
- 'api'
hosts: # instancje repliki
app-1:
replicaset_storage_1:
vars: # konfiguracja repliki
replicaset_alias: storage-1
weight: 3
failover_priority:
- storage-1 # lider
- storage-1-replica
roles:
- 'storage'
hosts: # instancje repliki
storage-1:
storage-1-replica:Wszystko, czego potrzebujemy, to nauczyć się zarządzać instancjami i replikasetami, zmieniając zawartość tego pliku. Dalej dodamy w nim nowe sekcje. Aby się nie pogubić, gdzie je dodawać, możecie zerknąć na ostateczną wersję tego pliku, hosts.updated.yml, który znajduje się w repozytorium z przykładem.
Zarządzanie instancjami
W terminologii Ansible każdy instans to host (nie mylić z fizycznym serwerem), tj. węzeł infrastruktury, którym Ansible będzie zarządzać. Dla każdego hosta możemy określić parametry połączenia (takie jak ansible_host i ansible_user), a także konfigurację instansa. Opis instansów znajduje się w sekcji hosts.
Rozważmy konfigurację instansa storage-1:
all:
vars:
...
# INSTANCJE
hosts:
storage-1:
config:
advertise_uri: '172.19.0.2:3301'
http_port: 8181
...W zmiennej config określiliśmy parametry instansa — advertise URI i HTTP port.
Poniżej znajdują się parametry instansów app-1 i storage-1-replica.
Musimy poinformować Ansible o parametrach połączenia dla każdego instansa. Wydaje się logiczne, aby połączyć instansy w grupy według maszyn wirtualnych. W tym celu instansy zostały zgrupowane w grupy host1 i host2, a w każdej grupie w sekcji vars określone są wartości ansible_host i ansible_user dla jednej wirtualki. A w sekcji hosts — hosts (czyli instansy), które wchodzą w skład tej grupy:
all:
vars:
...
hosts:
...
children:
# GRUPUJ INSTANCJE WEDŁUG MASZYN
host1:
vars:
# opcje połączenia dla pierwszej maszyny
ansible_host: 172.19.0.2
ansible_user: vagrant
hosts: # instancje, które będą uruchomione na pierwszej maszynie
storage-1:
host2:
vars:
# opcje połączenia dla drugiej maszyny
ansible_host: 172.19.0.3
ansible_user: vagrant
hosts: # instancje, które będą uruchomione na drugiej maszynie
app-1:
storage-1-replica:Zaczynamy wprowadzać zmiany hosts.yml. Dodamy jeszcze dwa instansy, storage-2-replica na pierwszej wirtualce i storage-2 na drugiej:
all:
vars:
...
# INSTANCJE
hosts:
...
storage-2: # <==
config:
advertise_uri: '172.19.0.3:3303'
http_port: 8184
storage-2-replica: # <==
config:
advertise_uri: '172.19.0.2:3302'
http_port: 8185
children:
# GRUPUJ INSTANCJE WEDŁUG MASZYN
host1:
vars:
...
hosts: # instancje, które będą uruchomione na pierwszej maszynie
storage-1:
storage-2-replica: # <==
host2:
vars:
...
hosts: # instancje, które będą uruchomione na drugiej maszynie
app-1:
storage-1-replica:
storage-2: # <==
...Uruchamiamy ansible-playbook:
$ ansible-playbook -i hosts.yml
--limit storage-2,storage-2-replica
playbook.ymlZwróć uwagę na opcję --limit. Ponieważ każdy instans klastra jest hostem w terminologii Ansible, możemy jawnie określać, które instansy mają być skonfigurowane podczas wykonywania playbooka.
Ponownie wchodzimy do interfejsu Web UI i obserwujemy nasze nowe instansy:

Nie zatrzymujmy się na osiągniętym celu i nauczmy się zarządzać topologią.
Zarządzanie topologią
Połączmy nasze nowe instansy w replikaset storage-2. Dodamy nową grupę replicaset_storage_2 i opiszemy w jej zmiennych parametry replikasetu analogicznie do replicaset_storage_1. W sekcji hosts Określamy, które instancje będą należeć do tej grupy (to znaczy nasz zestaw replik):
---
all:
vars:
...
hosts:
...
children:
...
# GRUPUJ INSTANCJE W ZESTAWY REPLIK
...
replicaset_storage_2: # <==
vars: # konfiguracja zestawu replik
replicaset_alias: storage-2
weight: 2
failover_priority:
- storage-2
- storage-2-replica
roles:
- 'storage'
hosts: # instancje zestawu replik
storage-2:
storage-2-replica:Ponownie uruchamiamy playbook:
$ ansible-playbook -i hosts.yml
--limit replicaset_storage_2
--tags cartridge-replicasets
playbook.ymlW parametrze --limit tym razem przekazaliśmy nazwę grupy, która odpowiada naszemu zestawowi replik.
Rozważmy opcję tags.
Nasza rola stopniowo wykonuje różne zadania, które są oznaczone następującymi tagami:
cartridge-instances: zarządzanie instancjami (konfiguracja, podłączenie do membership);cartridge-replicasets: zarządzanie topologią (zarządzanie zestawami replik i nieodwracalne usuwanie (expel) instancji z klastra);cartridge-config: zarządzanie pozostałymi parametrami klastra (vshard bootstrapping, tryb automatycznego failover, parametry autoryzacji i konfiguracja aplikacji).
Możemy wyraźnie określić, którą część pracy chcemy wykonać, wtedy rola pominie wykonanie pozostałych zadań. W naszym przypadku chcemy pracować tylko z topologią, dlatego określiliśmy cartridge-replicasets.
Oceńmy wynik naszych wysiłków. Znajdujemy nowy zestaw replik na .

Hurra!
Eksperymentuj z zmianą konfiguracji instancji i zestawów replik oraz zobacz, jak zmienia się topologia klastra. Możesz przetestować różne scenariusze operacyjne, na przykład, lub zwiększenie memtx_memory. Rola spróbuje to zrobić bez restartu instancji, aby zminimalizować możliwy czas przestoju aplikacji.
Nie zapomnij uruchomić vagrant halt, aby zatrzymać wirtualki, gdy skończysz z nimi pracować.
A co pod maską?
Tutaj szczegółowo opowiem, co działo się pod maską roli ansible podczas naszych eksperymentów.
Rozważmy krok po kroku wdrożenie aplikacji Cartridge.
Instalacja pakietu i uruchomienie instancji
Najpierw musisz dostarczyć pakiet na serwer i go zainstalować. Obecnie rola potrafi pracować z pakietami RPM i DEB.
Następnie uruchamiamy instancje. Tutaj wszystko jest bardzo proste: każda instancja to osobny systemd-serwis. Opowiem na przykładzie:
$ systemctl start myapp@storage-1To polecenie uruchomi instancję storage-1 aplikacji myapp. Uruchomiona instancja będzie szukać swojej do /etc/tarantool/conf.d/. Dzienniki instancji można będzie przeglądać za pomocą journald.
Plik jednostki /etc/systemd/system/myapp@.sevice dla usługi systemd będzie dostarczony wraz z pakietem.
Ansible zawiera wbudowane moduły do instalacji pakietów i zarządzania usługami systemd, tutaj nie wymyśliliśmy nic nowego.
Konfiguracja topologii klastra
A tutaj zaczyna się najciekawsza część. Zgadzam się, byłoby dziwnie martwić się o specjalną rolę ansible do instalacji pakietów i uruchamiania systemd-usług.
Klastr można skonfigurować ręcznie:
- Pierwsza opcja: otwieramy interfejs webowy i klikamy przyciski. Do jednorazowego uruchomienia kilku instancji będzie to wystarczające.
- Druga opcja: można skorzystać z API GraphQl. Tutaj można coś zautomatyzować, na przykład napisać skrypt w Pythonie.
- Trzecia opcja (dla odważnych): wchodzimy na serwer, łączymy się z jedną z instancji za pomocą
tarantoolctl connecti wykonujemy wszystkie niezbędne operacje z modułem Luacartridge.
Główne zadanie naszego wynalazku to właśnie ta, najbardziej skomplikowana część pracy.
Ansible pozwala napisać własny moduł i użyć go w roli. Nasza rola korzysta z takich modułów do zarządzania różnymi komponentami klastra.
Jak to działa? Opisujesz pożądany stan klastra w deklaratywnej konfiguracji, a rola podaje każdemu modułowi jego sekcję konfiguracji. Moduł otrzymuje aktualny stan klastra i porównuje go z tym, co otrzymał na wejściu. Następnie przez socket jednej z instancji uruchamiany jest kod, który przekształca klaster w żądany stan.
Podsumowanie
Dzisiaj opowiedzieliśmy i pokazaliśmy, jak wdrożyć aplikację na Tarantool Cartridge i skonfigurować prostą topologię. Do tego użyliśmy Ansible - potężnego narzędzia, które wyróżnia się prostotą w użyciu i pozwala jednocześnie konfigurować wiele węzłów infrastruktury (w naszym przypadku to instancje klastra).
Powyżej przyjrzeliśmy się jednemu z wielu sposobów opisu konfiguracji klastra za pomocą Ansible. Gdy tylko zrozumiesz, że jesteś gotowy iść dalej, zapoznaj się z pisania playbooków. Może być ci wygodniej zarządzać topologią za pomocą group_vars i host_vars.
Wkrótce opowiemy, jak trwale usuwać (expel) instancje z topologii, bootstrapować vshard, zarządzać trybem automatycznego failoveru, konfigurować autoryzację i patchować konfigurację klastra. Na razie możesz samodzielnie studiować i eksperymentować z modyfikowaniem parametrów klastra.
Jeśli coś nie działa, koniecznie nas o problemie. Szybko to wyjaśnimy!
Źródło: habr.com
