Łatwe i bezproblemowe wdrażanie aplikacji na Tarantool Cartridge (część 1)

Łatwe i bezproblemowe wdrażanie aplikacji na Tarantool Cartridge (część 1)

Już pisaliśmy o Tarantool Cartridge, 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 rolę ansible, 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 dokumentacji. Ale lepiej raz spróbować niż sto razy zobaczyć, więc zainstalujmy małą aplikację.

Tarantool Cartridge ma tutorial 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-1 będzie realizować rolę api, która obejmuje rolę vshard-router. Będzie tylko jedna instancja.
  • Replika zestaw storage-1 realizuje rolę magazyn (a jednocześnie vshard-storage), dodamy tutaj dwie instancje z różnych maszyn.

Łatwe i bezproblemowe wdrażanie aplikacji na Tarantool Cartridge (część 1)

Aby uruchomić przykład potrzebujemy Vagrant i Ansible (wersje 2.8 lub wyższe).

Rola znajduje się w Ansible Galaxy. 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.0

Uruchamiamy maszyny wirtualne:

$ vagrant up

Instalujemy rolę ansible Tarantool Cartridge:

$ ansible-galaxy install tarantool.cartridge,1.0.1

Uruchamiamy zainstalowaną rolę:

$ ansible-playbook -i hosts.yml playbook.yml

Czekamy na zakończenie wykonania playbooka, przechodzimy do http://localhost:8181/admin/cluster/dashboard i cieszymy się rezultatem:

Łatwe i bezproblemowe wdrażanie aplikacji na Tarantool Cartridge (część 1)

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.cartridge

Tu 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 inventory-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.yml

Zwróć 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 http://localhost:8181/admin/cluster/dashboard i obserwujemy nasze nowe instansy:

Łatwe i bezproblemowe wdrażanie aplikacji na Tarantool Cartridge (część 1)

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.yml

W 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 http://localhost:8181/admin/cluster/dashboard.

Łatwe i bezproblemowe wdrażanie aplikacji na Tarantool Cartridge (część 1)

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, rolling update 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-1

To polecenie uruchomi instancję storage-1 aplikacji myapp. Uruchomiona instancja będzie szukać swojej konfiguracji 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 connect i wykonujemy wszystkie niezbędne operacje z modułem Lua cartridge.

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 best practices 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ć dokumentację i eksperymentować z modyfikowaniem parametrów klastra.

Jeśli coś nie działa, koniecznie poinformuj nas o problemie. Szybko to wyjaśnimy!

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster