
W miarę zdobywania doświadczenia w IT zaczynasz zauważać, że systemy mają swój charakter. Mogą być posłuszne, milczące, kapryśne, surowe. Mogą przyciągać do siebie lub odpychać. Tak czy inaczej, musisz z nimi „dogadywać się”, lawirować między „ukrytymi niebezpieczeństwami” i budować łańcuchy ich interakcji.
I nam przypadła zaszczytna rola zbudowania chmurowej platformy, a w tym celu musieliśmy „namówić” kilka podsystemów do współpracy. Na szczęście mamy „język API”, zręczne ręce i mnóstwo entuzjazmu.
W tym artykule nie będzie technicznego hardcore'u, ale opis problemów, z którymi się zmierzyliśmy podczas budowy chmury. Postanowiłem opisać naszą drogę w formie lekkiej technicznej fantazji o tym, jak szukaliśmy wspólnego języka z systemami i co z tego wynikło.
Witaj w środku.
Początek drogi
Jakiś czas temu przed naszym zespołem postawiono zadanie - uruchomienie chmurowej platformy dla naszych klientów. Mieliśmy wsparcie kierownictwa, zasoby, sprzęt i wolność w wyborze technologii do realizacji programowej części usługi.
Były również pewne wymagania:
- serwis potrzebuje wygodnego panelu użytkownika;
- platforma musi być zintegrowana z istniejącym systemem billingowym;
- część programowo-sprzętowa: OpenStack + Tungsten Fabric (Open Contrail), które nasi inżynierowie nauczyli się dość dobrze „przygotowywać”.
O tym, jak zbierał się zespół, opracowywano interfejs panelu użytkownika i podejmowano decyzje projektowe, opowiemy innym razem, jeśli społeczność Habr będzie zainteresowana.
Narzędzia, które postanowiliśmy wykorzystać:
- Python + Flask + Swagger + SQLAlchemy - całkiem standardowy zestaw Python;
- Vue.js dla frontendu;
- interakcję między komponentami i usługami postanowiliśmy realizować za pomocą Celery na AMQP.
Przewidując pytania o wybór Pythona, wyjaśnię. Język zajął swoją niszę w naszej firmie i wokół niego powstała mała, ale jednak kultura. Dlatego zdecydowano się budować usługę właśnie na nim. Zwłaszcza, że szybkość rozwoju w takich zadaniach często ma kluczowe znaczenie.
Zacznijmy więc nasze poznawanie.
Milczący Bill - billing
Z tym facetem znaliśmy się od dawna. Zawsze siedział obok i coś cicho liczył. Czasami przesyłał nam zapytania od użytkowników, wystawiał faktury dla klientów, zarządzał usługami. Zwykły pracowity facet. Były jednak trudności. Był milczący, czasami zamyślony i często — skryty.

Billing to pierwszy system, z którym próbowaliśmy się zaprzyjaźnić. I pierwsza trudność, z jaką się zmierzyliśmy, pojawiła się przy przetwarzaniu usług.
Na przykład przy tworzeniu lub usuwaniu, zadanie trafia do wewnętrznej kolejki billingowej. W ten sposób zrealizowano system asynchronicznej pracy z usługami. Aby przetwarzać nasze typy usług, musieliśmy "układać" nasze zadania w tę kolejkę. I tutaj napotkaliśmy problem: brak dokumentacji.

Sądząc po opisie API, można to zadanie rozwiązać, jednak nie mieliśmy czasu na inżynierię odwrotną, w związku z czym przenieśliśmy logikę na zewnątrz i zorganizowaliśmy kolejkę zadań na RabbitMQ. Operacja nad usługą jest inicjowana przez klienta w panelu użytkownika, opakowywana w "zadanie" Celery na backendzie i wykonywana po stronie billingowej i OpenStacka. Celery umożliwia dość wygodne zarządzanie zadaniami, organizowanie powtórzeń i śledzenie statusu. Więcej o "selerze" można poczytać, na przykład, .
Billing nie zatrzymywał również projektu, w którym skończyły się pieniądze. Rozmawiając z programistami, dowiedzieliśmy się, że przy obliczaniu statystyk (a dokładnie taką logikę musimy wdrożyć) istnieje złożona interakcja reguł zatrzymywania. Ale te modele nie pasują do naszych godzin. Zrealizowaliśmy to również przez zadania na Celery, przenosząc logikę zarządzania usługami na backend.
Obie powyższe problemy doprowadziły do tego, że kod trochę się rozrósł i w przyszłości będziemy musieli zająć się refaktoryzacją, aby przenieść logikę pracy z zadaniami do osobnej usługi. Musimy również przechowywać część informacji o użytkownikach i ich usługach w naszych tabelach, aby podtrzymać tę logikę.
Jeszcze jeden problem — milczenie.
Na część zapytań do API Billy cicho odpowiada "Ok". Tak było na przykład, gdy wykonywaliśmy wpływy obiecanych płatności w trakcie testów (o tym później). Zapytania były poprawnie realizowane i nie widzieliśmy błędów.

Musiałem przeanalizować logi, pracując z systemem przez UI. Okazało się, że sam billing wykonuje podobne zapytania, zmieniając zakres na konkretnego użytkownika, na przykład admina, przekazując go w parametrze su.
Ogólnie rzecz biorąc, mimo luk w dokumentacji i drobnych niedoskonałości API, wszystko przebiegło dość dobrze. Logi są czytelne nawet przy dużym obciążeniu, jeśli rozumie się, jak są zbudowane i czego szukać. Struktura bazy danych jest złożona, ale całkiem logiczna i w pewnym sensie atrakcyjna.
Podsumowując, główne problemy, które napotkaliśmy na etapie interakcji, dotyczą szczególnych cech realizacji konkretnego systemu:
- niedokumentowane „funkcje”, które w ten czy inny sposób nas dotyczyły;
- zamknięty kod źródłowy (billing napisany w C++), w konsekwencji — niemożność rozwiązania problemu 1 w żaden sposób, poza „metodą prób i błędów”.
Na szczęście produkt ma wystarczająco rozbudowane API i zintegrowaliśmy w naszym panelu następujące podsystemy:
- moduł wsparcia technicznego — zapytania z panelu użytkownika są transparentnie przekazywane do bilingu dla klientów serwisu;
- moduł finansowy — pozwala na wystawianie faktur dla bieżących klientów, dokonywanie obciążeń i generowanie dokumentów płatniczych;
- moduł zarządzania usługami — dla niego musieliśmy zaimplementować własny procesor. Rozszerzalność systemu okazała się dla nas korzystna, a my "nauczyliśmy" Billy'ego nowego typu usług.
Trochę z tym popracowaliśmy, ale sądzę, że z Billym się dogadamy.
Spacerując po polach tungstenowych — Tungsten Fabric
Pola tungstenowe, usiane setkami kabli, przez które przepływają tysiące bitów informacji. Informacje są zbierane w "pakiety", analizowane, tworząc złożone trasy, jakby za pomocą magii.

To jest domena drugiego systemu, z którym musieliśmy się zaprzyjaźnić — Tungsten Fabric (TF), dawny OpenContrail. Jej zadaniem jest zarządzanie sprzętem sieciowym, zapewniając nam, jako użytkownikom, abstrakcję programową. TF — SDN, inkapsuluje w sobie skomplikowaną logikę pracy z urządzeniami sieciowymi. O samej technologii jest dobry artykuł, na przykład, .
System jest zintegrowany z OpenStack (o nim będzie mowa poniżej) przez wtyczkę Neutron’a.

Interakcja usług OpenStack.
Z tą systemą zapoznali nas koledzy z działu eksploatacji. Używamy API systemu do zarządzania sieciowym stosem naszych usług. Na razie nie sprawia nam poważnych problemów ani niedogodności (o kolegach z DE nie będę się wypowiadał), chociaż zdarzyły się też pewne zabawne sytuacje podczas interakcji.
Pierwszy problem wyglądał tak: komendy, które wymagały wyświetlenia dużej ilości danych na konsoli instancji po połączeniu przez SSH po prostu "zawieszały" połączenie, podczas gdy przez VNC wszystko działało poprawnie.

Dla tych, którzy nie znają problemu, wygląda to dość zabawnie: ls /root wykonuje się poprawnie, podczas gdy na przykład top "zawiesza się" całkowicie. Na szczęście już wcześniej napotkaliśmy podobne problemy. Rozwiązano je dostosowując MTU na trasie od węzłów compute do routerów. Swoją drogą, to nie był problem TF.
Kolejny problem czekał za rogiem. W pewnym "pięknym" momencie magia routingu zniknęła, tak po prostu. TF przestał zarządzać routingiem na sprzęcie.

Pracowaliśmy z OpenStack na poziomie admina, a następnie przechodziliśmy na poziom odpowiedniego użytkownika. SDN, wydaje się, "przechwytuje" zakres użytkownika, w którym wykonywane są działania. To, że to samo konto admina używane jest do komunikacji TF i OpenStack, sprawiło, że w momencie przełączania na użytkownika "magia" znikała. Zdecydowaliśmy się utworzyć osobne konto do pracy z systemem. Dzięki temu mogliśmy pracować, nie łamiąc funkcjonalności integracji.
Formy życia silikonowego — OpenStack
Silikonowa istota o dziwacznej formie zamieszkuje pobliskie pola tungstenowe. Najbardziej przypomina dorastającego chłopca, który jednym machnięciem może nas zmiażdżyć, ale nie emanuje oczywistą agresją. Nie budzi strachu, ale jego rozmiary budzą niepokój. Podobnie jak złożoność tego, co dzieje się wokół.

OpenStack jest rdzeniem naszej platformy.
OpenStack ma kilka podsystemów, z których najbardziej aktywnie wykorzystujemy na razie Nova, Glance i Cinder. Każdy z nich ma swoje API. Nova odpowiada za zasoby obliczeniowe i tworzenie instancji, Cinder — zarządza wolumenami i ich snapshotami, Glance — to usługa obrazów, która zarządza szablonami systemów operacyjnych i metainformacjami o nich.
Każda usługa uruchamiana jest w kontenerze, a brokerem wiadomości jest "biały królik" — RabbitMQ.
Ten system sprawił nam najwięcej nieoczekiwanych kłopotów.
I pierwszy problem nie kazał na siebie długo czekać, gdy próbowaliśmy podłączyć dodatkowy wolumin do serwera. Cinder API kategorycznie odmówił wykonania tego zadania. Dokładniej mówiąc, jeśli wierzyć samemu OpenStack, połączenie jest nawiązywane, jednak wewnątrz wirtualnego serwera urządzenie dyskowe jest niedostępne.

Postanowiliśmy „obejść to” i poprosiliśmy o tę samą czynność do Nova API. Wynik — urządzenie jest poprawnie podłączone i dostępne wewnątrz serwera. Wygląda na to, że problem pojawia się, gdy block-storage nie odpowiada Cinderowi.
Kolejna trudność czekała na nas przy pracy z dyskami. Systemowy wolumin nie mógł zostać odłączony od serwera.
Znowu, sam OpenStack „przysięga”, że połączenie zostało zniszczone i teraz można poprawnie pracować z woluminem osobno. Ale API kategorycznie odmówiło przeprowadzenia operacji na dysku.

Tutaj postanowiliśmy szczególnie nie walczyć, a zmienić podejście do logiki działania usługi. Skoro istnieje instancja, musi istnieć także systemowy wolumin. Dlatego użytkownik tymczasowo nie może usunąć lub odłączyć systemowego „dysku”, nie usuwając „serwera”.
OpenStack to dość skomplikowany zestaw systemów z własną logiką interakcji i zawiłym API. Pomaga nam dosyć szczegółowa dokumentacja i, oczywiście, metoda prób i błędów (gdzieżby bez niej).
Testowe uruchomienie
Testowe uruchomienie przeprowadziliśmy w grudniu ubiegłego roku. Głównym zadaniem było sprawdzenie w trybie produkcyjnym naszego projektu z punktu widzenia technicznego oraz UX. Publiczność była zapraszana selektywnie, a testowanie miało charakter zamknięty. Niemniej jednak pozostawiliśmy także możliwość zgłoszenia dostępu do testów na naszej stronie.
Sam test, oczywiście, nie obył się bez komicznych momentów, ponieważ na tym nasze przygody dopiero się zaczynają.
Po pierwsze, nieco niepoprawnie oceniliśmy zainteresowanie projektem i musieliśmy szybko dodać węzły compute w trakcie testu. Zwykły przypadek dla klastra, jednak były tu także niuanse. W dokumentacji dla konkretnej wersji TF podana jest konkretna wersja jądra, na którym testowano działanie z vRouter. Postanowiliśmy uruchamiać węzły z nowszymi jądrami. W rezultacie TF nie otrzymał tras z węzłów. Musieliśmy nagle cofnąć jądra.

Inny komiczny moment dotyczy funkcji przycisku „zmień hasło” w osobistym panelu.
Postanowiliśmy użyć JWT do organizacji dostępu do panelu użytkownika, aby uniknąć pracy z sesjami. Ponieważ systemy są różnorodne i szeroko rozproszone, zarządzamy naszym tokenem, w który "opakowujemy" sesje z systemu billingowego oraz token z OpenStacka. Przy zmianie hasła, token oczywiście "wygasa", ponieważ dane użytkownika stają się nieważne i trzeba go odnowić.

Zlekceważyliśmy ten aspekt, a zasobów, by szybko dodać tę część, po prostu zabrakło. Musieliśmy usunąć funkcjonalność tuż przed uruchomieniem testów.
Obecnie wykonujemy logout użytkownika, jeśli hasło zostało zmienione.
Mimo tych niuansów, testowanie przebiegło dobrze. W ciągu kilku tygodni odwiedziło nas około 300 osób. Mieliśmy okazję zobaczyć produkt oczami użytkowników, przetestować go w realnych warunkach i zebrać wartościowe opinie.
Ciąg dalszy nastąpi
Dla wielu z nas to pierwszy projekt takiej skali. Wyciągnęliśmy szereg cennych lekcji o tym, jak pracować w zespole, podejmować decyzje architektoniczne i projektowe. Jak integrować złożone systemy przy ograniczonych zasobach i wprowadzać je na rynek.
Oczywiście, jest nad czym pracować zarówno w zakresie kodu, jak i na styku integracji systemów. Projekt jest dość młody, ale jesteśmy pełni ambicji, aby przekształcić go w niezawodną i wygodną usługę.
Systemy już udało nam się przekonać. Bill z posłuszeństwem zajmuje się obliczeniami, wystawianiem rachunków i zapytaniami użytkowników w swoim skromnym biurze. "Czarodziejstwo" tungstenowych pól zapewnia nam stabilne połączenie. Tylko OpenStack czasami sprawia problemy, wykrzykując coś w stylu "'WSREP has not yet prepared node for application use". Ale to już zupełnie inna historia...
Niedawno uruchomiliśmy usługę.
Wszystkie szczegóły możesz poznać na naszej .

Zespół programistyczny CLO
Przydatne linki
OpenStack
Tungsten Fabric
Źródło: habr.com
