
Pe măsură ce acumulezi experiență în IT, începi să observi că sistemele au propriul caracter. Ele pot fi docile, tăcute, capricioase, dure. Pot fi primitoare sau respingătoare. Oricum, trebuie să 'ne înțelegem' cu ele, să navigăm printre 'capcanele ascunse' și să construim lanțuri de interacțiune.
Iată că ne-a revenit onoarea de a construi o platformă de cloud, iar pentru asta a fost nevoie să 'convingem' câteva subsisteme să colaboreze cu noi. Din fericire, avem 'limbajul API', mâini pricepute și mult entuziasm.
În acest articol nu va fi vorba despre tehnici avansate, dar voi descrie problemele cu care ne-am confruntat în construirea cloud-ului. Am decis să povestim călătoria noastră sub forma unei fantezii tehnice ușoare, despre cum am căutat un teren comun cu sistemele și ce a rezultat din asta.
Bun venit sub cat.
Începutul călătoriei
Cu ceva timp în urmă, echipa noastră a primit sarcina de a lansa o platformă de cloud pentru clienții noștri. La dispoziția noastră au fost suportul conducerii, resursele, infrastructura hardware și libertatea de a alege tehnologiile pentru implementarea părții software a serviciului.
De asemenea, au fost și o serie de cerințe:
- serviciul trebuie să aibă un panou de administrare prietenos;
- platforma trebuie să fie integrată în sistemul existent de facturare;
- partea software-hardware: OpenStack + Tungsten Fabric (Open Contrail), pe care inginerii noștri au învățat să le 'prepare' destul de bine.
Despre cum s-a adunat echipa, cum a fost dezvoltată interfața panoului de administrare și ce decizii de design au fost luate, vom povesti altădată, dacă comunitatea Habr va fi interesată.
Instrumentele pe care am decis să le folosim:
- Python + Flask + Swagger + SQLAlchemy — un set destul de standard pentru Python;
- Vue.js pentru frontend;
- comunicarea între componente și servicii a fost realizată prin Celery deasupra AMQP.
Anticipând întrebările legate de alegerea limbajului Python, vreau să explic. Limbajul și-a găsit locul în compania noastră și în jurul său s-a dezvoltat o mică, dar totuși, cultură. De aceea, s-a decis să începem construirea serviciului pe baza lui. Mai ales că viteza de dezvoltare este adesea crucială în astfel de sarcini.
Așadar, să începem cunoașterea noastră.
Bill tăcut — facturare
Ne cunoaștem acest băiat de mult timp. El stătea mereu alături și număra ceva în tăcere. Uneori ne redirecționa cererile utilizatorilor, emitea facturi pentru clienți, gestiona serviciile. Un tip obișnuit, muncitor. Adevărul este că au existat dificultăți. Era tăcut, uneori contemplativ și adesea — cu capul în altă parte.

Billing-ul a fost primul sistem cu care am încercat să ne împrietenim. Și prima dificultate s-a ivit când am început să procesăm serviciile.
De exemplu, când creăm sau ștergem, sarcina ajunge în coada internă a billing-ului. Astfel este implementat sistemul de lucru asincron cu serviciile. Pentru a procesa tipurile noastre de servicii, a trebuit să "adunăm" sarcinile noastre în această coadă. Și aici ne-am confruntat cu problema: lipsa documentației.

Judecând după descrierea API-ului software, această problemă poate fi totuși rezolvată, dar nu aveam timp să ne ocupăm de ingineria inversă, așa că am mutat logica în exterior și am organizat o coadă de sarcini deasupra RabbitMQ. Operațiunea asupra serviciului este inițiată de client din contul personal, este encapsulată într-o "sarcină" Celery pe backend și se execută pe partea de billing și OpenStack. Celery permite gestionarea convenabilă a sarcinilor, organizarea repetărilor și monitorizarea stării. Detalii despre "apioș" pot fi citite, de exemplu, .
De asemenea, billing-ul nu a oprit proiectul care a rămas fără bani. Discutând cu dezvoltatorii, am aflat că la calcularea statisticii (iar noi trebuie să implementăm exact această logică) există o interacțiune complexă a regulilor de stopare. Dar aceste modele nu se potrivesc bine cu realitățile noastre. De asemenea, am implementat prin sarcini pe Celery, preluând pe backend logica de gestionare a serviciilor.
Ambele probleme menționate mai sus au dus la faptul că codul s-a umflat puțin și va trebui să ne ocupăm de refactorizare în viitor pentru a muta logica de lucru cu sarcinile într-un serviciu separat. De asemenea, trebuie să stocăm o parte din informațiile despre utilizatori și serviciile lor în propriile noastre tabele, pentru a susține această logică.
O altă problemă - tăcerea.
La unele cereri către API, Billy răspunde tăcut cu "OK". Așa a fost, de exemplu, când făceam înregistrări ale plăților promise pentru o perioadă de testare (despre care vom vorbi mai târziu). Cererile erau executate corect și nu am observat erori.

A fost necesar să studiem jurnalele, lucrând cu sistemul prin UI. S-a dovedit că billingul face astfel de solicitări, schimbând scope-ul la un utilizator specific, de exemplu, admin, transmitem-l ca parametru su.
În general, în ciuda lacunelor din documentație și a unor mici erori ale API-ului, totul a decurs destul de bine. Jurnalele pot fi citite chiar și în condiții de mare încărcare, dacă înțelegem cum sunt structurate și ce trebuie să căutăm. Structura bazei de date este complicată, dar destul de logică și, în unele aspecte, chiar atractivă.
Așadar, concluzionând, principalele probleme cu care ne-am confruntat în etapa de interacțiune sunt legate de particularitățile implementării sistemului specific:
- funcționalități nedocumentate care ne-au afectat într-un fel sau altul;
- sursă închisă (billingul este scris în C++), ca urmare, imposibilitatea de a rezolva problema 1 în alt mod decât prin „metoda încercărilor și greșelilor”.
Din fericire, produsul are un API destul de amplu și am integrat în contul nostru personal următoarele subsisteme:
- modul de suport tehnic — cererile din contul personal sunt 'proxies' în billing în mod transparent pentru clienții serviciului;
- modul financiar — permite emiterea facturilor către clienții actuali, efectuarea de debite și generarea documentelor de plată;
- modul de gestionare a serviciilor — pentru acesta a fost nevoie să implementăm propriul nostru handler. Extensibilitatea sistemului ne-a fost de ajutor și am 'învățat' Billingul un nou tip de servicii.
A fost necesar să ne ocupăm de el, dar, într-un fel sau altul, cred că ne vom înțelege cu Billing.
Plimbări pe câmpurile de tungsten — Tungsten Fabric
Câmpuri de tungsten, presărate cu o sută de cabluri, care transportă mii de biți de informație. Informația este colectată în 'pachete', apoi procesată, construind trasee complexe, ca prin magie.

Aceasta este zona de responsabilitate a celei de-a doua sisteme cu care a trebuit să ne împrietenim — Tungsten Fabric (TF), fostul OpenContrail. Sarcina sa este de a gestiona echipamentele de rețea, oferind o abstracție software pentru noi, ca utilizatori. TF — SDN, încorporează o logică complexă de lucru cu echipamentele de rețea. Există un articol destul de bun despre tehnologie, de exemplu, .
Sistemul este integrat cu OpenStack (despre care vom discuta mai jos) prin pluginul Neutron.

Interacțiunea serviciilor OpenStack.
Această sistemă ne-a fost prezentată de colegii din departamentul de operare. Folosim API-ul sistemului pentru a gestiona stiva de rețea a serviciilor noastre. Până acum nu ne-a cauzat probleme serioase sau neplăceri (nu mă voi pronunța în numele colegilor din OEP), totuși au fost și unele momente amuzante în interacțiune.
Primul a arătat astfel: comenzile care necesită afișarea unui volum mare de date pe consola instanței la conectarea prin SSH pur și simplu "blochează" conexiunea, în timp ce totul funcționa corect prin VNC.

Pentru cei care nu sunt familiarizați cu problema, aceasta poate părea destul de amuzantă: ls /root funcționează corect, în timp ce, de exemplu, top "se blochează" complet. Din fericire, ne-am mai confruntat cu probleme de genul. S-a rezolvat prin optimizarea MTU-ului pe ruta de la nodurile compute la routere. Ca să zic așa, aceasta nu este o problemă TF.
Următoarea problemă ne-a așteptat după colț. Într-un moment "minunat", magia rutării a dispărut, pur și simplu. TF a încetat să mai gestioneze rutarea pe echipament.

Am lucrat cu OpenStack la nivel de admin și de acolo am trecut la nivelul utilizatorului necesar. SDN pare să "preia" domeniul utilizatorului cu care se efectuează acțiunile. Problema este că același cont de admin este folosit pentru comunicarea dintre TF și OpenStack. La pasul de schimbare la utilizator, "magia" dispărea. S-a decis să se creeze un cont separat pentru lucrarea cu sistemul. Acest lucru a permis să lucrăm fără a rupe funcționalitatea integrării.
Formele de viață din siliciu — OpenStack
Creatura de siliciu cu o formă ciudată trăiește aproape de câmpurile de tungsten. Cel mai mult seamănă cu un copil crescut, care cu un singur gest ne-ar putea zdrobi, dar nu emite agresivitate evidentă. Nu provoacă teamă, dar dimensiunile sale induc neliniște. La fel ca și complexitatea a ceea ce se petrece în jur.

OpenStack este nucleul platformei noastre.
OpenStack are mai multe subsisteme, dintre care cele pe care le folosim cel mai activ sunt Nova, Glance și Cinder. Fiecare dintre ele are propriul API. Nova se ocupă de resursele compute și crearea instanțelor, Cinder gestionează volumele și instantanțele acestora, Glance este un serviciu de imagini, care gestionează șabloanele sistemului de operare și metainformațiile aferente acestora.
Fiecare serviciu este lansat într-un container, iar brokerul de mesaje este "iepurașul alb" — RabbitMQ.
Această sistemă ne-a adus cele mai multe neplăceri neașteptate.
Și prima problemă nu s-a lăsat așteptată, când am încercat să conectăm un volum suplimentar la server. API-ul Cinder a refuzat categoric să îndeplinească această sarcină. Mai precis, dacă avem încredere în OpenStack, conexiunea se stabilește, însă în interiorul serverului virtual dispozitivul de disc lipsește.

Am decis să „o ocolim” și am cerut aceeași acțiune de la API-ul Nova. Rezultatul — dispozitivul se conectează corect și este disponibil în interiorul serverului. Se pare că problema apare atunci când stocarea pe blocuri nu răspunde la Cinder.
O altă dificultate ne aștepta la lucru cu discurile. Volumul de sistem nu putea fi deconectat de la server.
Din nou, OpenStack „promite” că a distrus conexiunea și acum se poate lucra corect cu volumul separat. Dar API-ul refuza categoric să efectueze operațiuni asupra discului.

Aici am decis să nu mai luptăm, ci să schimbăm perspectiva asupra logicii de funcționare a serviciului. Dacă există un instance, trebuie să existe și un volum de sistem. Așadar, utilizatorul nu poate elimina sau deconecta „discul” de sistem fără a șterge „serverul”.
OpenStack este un complex de sisteme destul de complicat cu propria logică de interacțiune și un API complex. Ne ajută documentația destul de detaliată și, desigur, metoda probelor și erorilor (altfel cum?).
Lansare de test
Lansarea de test am efectuat-o în decembrie anul trecut. Scopul principal a fost verificarea în condiții reale a proiectului nostru din punct de vedere tehnic și din perspectiva UX. Am invitat selectiv audiența, iar testarea a fost închisă. Totuși, am lăsat și posibilitatea de a solicita acces la testare pe site-ul nostru.
Testul, bineînțeles, nu a fost lipsit de momente amuzante, căci pe ici aventura noastră abia începe.
În primul rând, am evaluat oarecum incorect interesul pentru proiect, așa că a trebuit să adăugăm rapid noduri compute exact în timpul testului. Un caz obișnuit pentru un cluster, dar și aici au fost anumite nuanțe. În documentația pentru versiunea specifică a TF este indicată o versiune specifică a kernel-ului pe care s-a testat funcționarea cu vRouter. Am decis să lansăm nodurile cu kernel-uri mai recente. Ca rezultat — TF nu a primit rutele de la noduri. A trebuit să revenim de urgență la kernel-uri.

Un alt moment amuzant este legat de funcționalitatea butonului „schimbă parola” din contul personal.
Am decis să folosim JWT pentru a organiza accesul la cabinetul personal, pentru a nu lucra cu sesiuni. Deoarece sistemele sunt diverse și dispersate pe scară largă, gestionăm propriul nostru token, în care „împachetăm” sesiuni de la facturare și token de la OpenStack. La schimbarea parolei, token-ul, bineînțeles, devine „expirat”, deoarece datele utilizatorului nu mai sunt valide și trebuie să fie regenerat.

Am omis acest aspect, iar resursele pentru a completa rapid această parte ne-au lipsit. A trebuit să eliminăm funcționalitatea înainte de lansarea în test.
În prezent, facem logout utilizatorului dacă parola a fost schimbată.
În ciuda acestor nuanțe, testarea a decurs bine. În decurs de câteva săptămâni, am avut aproximativ 300 de persoane care ne-au vizitat. Am reușit să privim produsul prin ochii utilizatorilor, să-l testăm în condiții reale și să colectăm feedback de calitate.
Continuarea urmează
Pentru mulți dintre noi, acesta este primul proiect de o asemenea amploare. Am învățat o serie de lecții valoroase despre cum să lucrăm în echipă, să luăm decizii arhitecturale și de design. Cum să integrăm sisteme complexe cu resurse limitate și să le lansăm în producție.
Desigur, există multe aspecte care necesită lucrări, atât în privința codului, cât și la interfețele de integrare a sistemelor. Proiectul este destul de tânăr, dar suntem plini de ambiție să-l transformăm într-un serviciu fiabil și convenabil.
Sistemele am reușit deja să le convingem. Bill se ocupă cuCalcularea, facturarea și solicitările utilizatorilor în biroul său. „Magia” câmpurilor de tungsten ne asigură o conexiune stabilă. Numai OpenStack mai este uneori mofturos, strigând ceva de genul „'WSREP has not yet prepared node for application use”. Dar acesta este cu totul altă poveste...
Chiar recent am lansat serviciul.
Toate detaliile le puteți afla pe .

Echipa de dezvoltare CLO
Linkuri utile
OpenStack
Tungsten Fabric
Sursa: habr.com
