Acceptăm 10.000 de evenimente în Yandex.Cloud. Partea 1

Bună tuturor, prieteni!

* Acest articol a fost scris pe baza practicumului deschis REBRAIN & Yandex.Cloud; dacă preferați să vizionați un videoclip, îl puteți găsi la acest link — https://youtu.be/cZLezUm0ekE

Recent, am avut ocazia să experimentăm live Yandex.Cloud. Deoarece am vrut să ne aprofundăm, am abandonat rapid ideea de a lansa un simplu blog wordpress cu o bază de date în cloud – era prea plicitisitor. După câteva reflecții scurte, am decis să implementăm ceva asemănător cu o arhitectură de producție a unui serviciu pentru primirea și analiza evenimentelor în timp aproape real.

Sunt absolut convins că cea mai mare parte a afacerilor online (și nu numai) colectează în moduri variate o cantitate uriașă de informații despre utilizatorii lor și acțiunile acestora. Cel puțin, acest lucru este necesar pentru a lua anumite decizii – de exemplu, dacă gestionați un joc online, puteți verifica statisticile pentru a vedea la ce nivel utilizatorii rămân blocați cel mai des și își dezinstalează jocul. Sau de ce utilizatorii părăsesc site-ul dvs. fără să cumpere nimic (salut, Yandex.Metrica).

Așadar, povestea noastră: cum am scris o aplicație în golang, am testat kafka vs rabbitmq vs yqs, am implementat streaming de date în clusterul Clickhouse și am vizualizat datele folosind yandex datalens. Evident, toate acestea au fost condimentate cu rafinamente infrastrucurale sub formă de docker, terraform, gitlab ci și, desigur, prometeus. Să începem!

De la bun început, vreau să subliniez că nu vom putea configura totul dintr-o singură șezătoare – pentru asta ne vor trebui mai multe articole într-o serie. Puțin despre structură:

Partea 1 (o citiți acum). Ne vom defini cerințele și arhitectura soluției și vom scrie aplicația în golang.
Partea 2. Vom lansa aplicația noastră în producție, o vom face scalabilă și vom testa încărcătura.
Partea 3. Vom încerca să înțelegem de ce trebuie să păstrăm mesajele în buffer, nu în fișiere, și ne vom compara între noi kafka, rabbitmq și yandex queue service.
Partea 4. Vom desfășura clusterul Clickhouse, vom scrie streaming pentru a transfera datele din buffer acolo și vom configura vizualizarea în datalens.
Partea 5. Vom aduce întreaga infrastructură în ordinea dorită – vom configura ci/cd folosind gitlab ci, vom conecta monitorizarea și descoperirea serviciului cu ajutorul prometheus și consul.

Caiet de sarcini

Mai întâi, să formulăm cerințele tehnice – ce anume dorim să obținem la final.

  1. Vrem să avem un endpoint de tip events.kis.im (kis.im — domeniul de test pe care îl vom folosi pe parcursul tuturor articolelor), care să primească evenimente prin HTTPS.
  2. Evenimentele sunt un simplu JSON de tipul: {"event": "view", "os": "linux", "browser": "chrome"}. În etapa finală, vom adăuga câteva câmpuri în plus, dar acest lucru nu va avea un impact semnificativ. Dacă există dorința, se poate schimba la protobuf.
  3. Serviciul trebuie să fie capabil să proceseze 10.000 de evenimente pe secundă.
  4. Trebuie să existe posibilitatea de a scala orizontal — prin simpla adăugare de noi instanțe în soluția noastră. Ar fi bine dacă am putea muta partea frontală în diverse locații geografice pentru a reduce latența la cererile clienților.
  5. Reziliență. Soluția trebuie să fie suficient de stabilă și să poată supraviețui căderii oricăror părți (până la un anumit număr, desigur).

Arhitectură

În general, pentru astfel de sarcini au fost create de mult timp arhitecturi clasice, care permit scalarea eficientă. În imagine este prezentat un exemplu al soluției noastre.

Acceptăm 10.000 de evenimente în Yandex.Cloud. Partea 1

Așadar, ce avem:

1. În stânga sunt reprezentate dispozitivele noastre care generează diverse evenimente, fie că este vorba de trecerea nivelurilor jucătorilor într-un joc pe smartphone sau de crearea unei comenzi în magazinul online printr-un browser obișnuit. Evenimentul, așa cum este specificat în caietul de sarcini, este un simple JSON, care este trimis către endpoint-ul nostru — events.kis.im.

2. Primele două servere sunt simple balansatoare de încărcare, principalele lor sarcini fiind:

  • Să fie disponibile în permanență. Pentru aceasta, putem folosi, de exemplu, keepalived, care va comuta IP-ul virtual între noduri în caz de probleme.
  • Să termine TLS. Da, vom termina TLS exact pe ele. În primul rând, pentru a ne conforma caietului de sarcini, iar în al doilea rând, pentru a reduce sarcina de stabilire a unei conexiuni criptate de pe serverele noastre backend.
  • Să echilibreze cererile de intrare pe serverele backend disponibile. Cuvântul cheie aici este — disponibile. Pe baza acestei premise, ajungem la concluzia că balansatoarele de încărcare trebuie să fie capabile să monitorizeze serverele noastre cu aplicații și să înceteze să echilibreze traficul pe nodurile căzute.

3. După balansatoare, avem servere de aplicație, pe care este rulată o aplicație destul de simplă. Aceasta trebuie să fie capabilă să primească cereri de intrare prin HTTP, să valideze JSON-ul trimis și să stocheze datele în bufer.

4. Ca buffer pe diagramă este reprezentată kafka, deși, desigur, la acest nivel se pot folosi și alte servicii asemănătoare. Vom compara Kafka, rabbitmq și yqs în al treilea articol.

5. Penultima etapă a arhitecturii noastre este Clickhouse - o bază de date coloană care permite stocarea și prelucrarea unor cantități uriașe de date. La acest nivel, trebuie să transferăm datele din buffer în, de fapt, sistemul de stocare (despre asta - în articolul 4).

Această schemă ne permite să scalăm orizontal fiecare strat în mod independent. Dacă serverele backend nu fac față - vom adăuga altele - deoarece acestea sunt aplicații stateless, iar prin urmare, acest lucru poate fi realizat chiar și în mod automat. Dacă bufferul sub formă de kafkă nu face față - vom adăuga mai multe servere și vom muta pe ele o parte din partițiile topicului nostru. Dacă Clickhouse nu face față - acest lucru este imposibil 🙂 De fapt, vom adăuga și aici servere și vom sharda datele.

Apropo, dacă doriți să implementați partea opțională a TCN-ului nostru și să faceți scalare în diferite geolocatii, atunci nu este nimic mai simplu:

Acceptăm 10.000 de evenimente în Yandex.Cloud. Partea 1

În fiecare geolocație desfășurăm un load balancer cu aplicația și kafka. În general, sunt suficiente 2 servere application, 3 noduri kafka și un load balancer în cloud, de exemplu, cloudflare, care va verifica disponibilitatea nodurilor aplicației și va echilibra cererile pe geolocații în funcție de adresa IP de origine a clientului. Astfel, datele trimise de un client american vor ajunge pe serverele americane. Iar datele din Africa - pe cele africane.

Apoi, totul devine foarte simplu - folosim mirror tool din setul kafkă și copiem toate datele din toate locațiile în centrul nostru de date central, situat în Rusia. Acolo descompunem datele și le scriem în Clickhouse pentru vizualizare ulterioară.

Așadar, ne-am clarificat cu arhitectura - să începem să „tremurăm” Yandex.Cloud!

Scriem o aplicație

Până la Cloud mai trebuie să așteptăm puțin și să scriem un serviciu destul de simplu pentru procesarea evenimentelor de intrare. Vom folosi golang, deoarece s-a dovedit foarte eficient ca limbaj pentru scrierea aplicațiilor de rețea.

Dedicând o oră (poate, chiar și două ore), obținem cam așa ceva: https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/main.go.

Care sunt principalele puncte pe care ai dori să le remarc?

1. La pornire aplicației, putem specifica două flaguri. Unul este responsabil pentru portul pe care vom asculta cererile http (-addr). Al doilea - pentru adresa serverului kafka, unde ne vom salva evenimentele (-kafka):

addr     = flag.String("addr", ":8080", "Adresă TCP pentru a asculta")
kafka    = flag.String("kafka", "127.0.0.1:9092", "EndPoint-uri Kafka")

2. Aplicația folosește biblioteca sarama ([] github.com/Shopify/sarama) pentru a trimite mesaje în clusterul kafka. Am setat imediat configurațiile, orientate spre maximizarea vitezei de procesare:

config := sarama.NewConfig()
config.Producer.RequiredAcks = sarama.WaitForLocal
config.Producer.Compression = sarama.CompressionSnappy
config.Producer.Return.Successes = true

3. De asemenea, aplicația noastră include un client prometheus, care colectează diverse metrici, cum ar fi:

  • numărul de cereri către aplicația noastră;
  • numărul de erori la executarea cererii (imposibil de citit cererea post, json corupt, imposibil de scris în kafka);
  • timpul de procesare al unei cereri de la client, inclusiv timpul de scriere a mesajului în kafka.

4. Trei endpoint-uri pe care aplicația noastră le procesează:

  • /status — просто возвращаем ok, чтобы показать, что мы живы. Хотя можно и добавить некоторые проверки, типа доступности кафка кластера.
  • /metrics — по этому url prometheus client будет возвращать собранные им метрики.
  • /post — основной endpoint, куда будут приходить POST запросы с json внутри. Наше приложение проверяет json на валидность и если все ок — записывает данные в кафка-кластер.

Menționez că codul nu este ideal - poate fi (și trebuie!) îmbunătățit. De exemplu, se poate renunța la utilizarea net/http integrat și se poate trece la fasthttp, care este mai rapid. Sau se poate câștiga timp de procesare și resurse CPU, mutând verificarea validității json într-o etapă ulterioară - când datele sunt transferate din buffer în clusterul clickhouse.

În plus față de aspectul dezvoltării, ne-am gândit imediat la infrastructura noastră viitoare și am decis să desfășurăm aplicația noastră prin docker. Dockerfile-ul final pentru construcția aplicației este https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/Dockerfile. În general, este destul de simplu, singurul aspect la care vrem să atragem atenția este construcția multistage, care permite reducerea dimensiunii finale a imaginii containerului nostru.

Primii pași în cloud

În primul rând, ne înregistrăm pe cloud.yandex.ru. După completarea tuturor câmpurilor necesare, ne va fi creat un cont și ne va fi oferit un grant pentru o anumită sumă de bani, care poate fi utilizată pentru a testa serviciile din cloud. Dacă doriți să repetați pașii din articolul nostru, acest grant ar trebui să fie suficient.

După înregistrare, un cloud separat va fi creat pentru dvs. și un catalog default, în care puteți începe să creați resurse cloud. În general, interconectarea resurselor în Yandex.Cloud arată astfel:

Acceptăm 10.000 de evenimente în Yandex.Cloud. Partea 1

Pe un singur cont, poți crea mai multe clouduri. Iar în interiorul cloudului, poți crea diferite directoare pentru diferitele proiecte ale companiei. Mai multe detalii poți găsi în documentație — https://cloud.yandex.ru/docs/resource-manager/concepts/resources-hierarchy. Apropo, mai jos în text voi face adesea referire la aceasta. Când am configurat întreaga infrastructură de la zero — documentația m-a ajutat nu o dată, așa că îți recomand să o studiezi.

Pentru a gestiona cloudul, poți folosi atât interfața web, cât și utilitarul din linia de comandă — yc. Instalarea se face cu o singură comandă (pentru Linux și Mac OS):

curl https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash

Dacă în legătură cu rularea scripturilor de pe internet, s-a activat un securist intern în tine — ei bine, pe de o parte, poți deschide scriptul și să-l citești, iar pe de altă parte, noi îl rulăm sub utilizatorul nostru — fără privilegii de root.

Dacă vrei să instalezi clientul pentru Windows, poți folosi instrucțiunile aici și apoi să execuți yc init, pentru a-l configura complet:

vozerov@mba:~ $ yc init
Bun venit! Această comandă te va ghida prin procesul de configurare.
Te rog să mergi la https://oauth.yandex.ru/authorize?response_type=token&client_id= pentru a obține tokenul OAuth.

Te rog să introduci tokenul OAuth:
Te rog să selectezi cloudul pe care vrei să-l folosești:
 [1] cloud-b1gv67ihgfu3bp (id = b1gv67ihgfu3bpt24o0q)
 [2] fevlake-cloud (id = b1g6bvup3toribomnh30)
Te rog să introduci alegerea ta numerică: 2
Cloudul tău curent a fost setat pe 'fevlake-cloud' (id = b1g6bvup3toribomnh30).
Te rog să alegi folderul pe care vrei să-l folosești:
 [1] default (id = b1g5r6h11knotfr8vjp7)
 [2] Crează un folder nou
Te rog să introduci alegerea ta numerică: 1
Folderul tău curent a fost setat pe 'default' (id = b1g5r6h11knotfr8vjp7).
Vrei să configurezi o zonă Compute implicită? [Y/n]
Ce zonă vrei să folosești ca zonă implicită de profil?
 [1] ru-central1-a
 [2] ru-central1-b
 [3] ru-central1-c
 [4] Nu seta zonă implicită
Te rog să introduci alegerea ta numerică: 1
Zona ta implicită de Compute a fost setată pe 'ru-central1-a'.
vozerov@mba:~ $

În principiu, procesul nu este complicat — mai întâi trebuie să obții un token oauth pentru a gestiona cloudul, să alegi cloudul și folderul pe care îl vei folosi.

Dacă ai mai multe conturi sau foldere în interiorul unui singur cloud, poți crea profiluri suplimentare cu setări distincte folosind yc config profile create și să te schimbi între ele.

Pe lângă metodele menționate anterior, echipa Yandex.Cloud a creat un plugin foarte bun pentru terraform pentru gestionarea resurselor cloud. Din partea mea, am pregătit un repository git, unde am descris toate resursele care vor fi create în cadrul articolului — https://github.com/rebrainme/yandex-cloud-events/. Ne interesează ramura master, haideți să o clonăm local:


vozerov@mba:~ $ git clone https://github.com/rebrainme/yandex-cloud-events/ events
Clonare în 'events'...
remote: Enumerarea obiectelor: 100, finalizat.
remote: Contarea obiectelor: 100% (100/100), finalizat.
remote: Compresie obiecte: 100% (68/68), finalizat.
remote: Total 100 (delta 37), reutilizat 89 (delta 26), pachet-reutilizat 0
Primire obiecte: 100% (100/100), 25.65 KiB | 168.00 KiB/s, finalizat.
Rezolvarea deltei: 100% (37/37), finalizat.
vozerov@mba:~ $ cd events/terraform/

Toate variabilele principale utilizate în terraform sunt specificate în fișierul main.tf. Pentru a începe lucrul, creăm în folderul terraform fișierul private.auto.tfvars cu următorul conținut:

# Yandex Cloud Oauth token
yc_token = ""
# Yandex Cloud ID
yc_cloud_id = ""
# Yandex Cloud folder ID
yc_folder_id = ""
# Default Yandex Cloud Region
yc_region = "ru-central1-a"
# Cloudflare email
cf_email = ""
# Cloudflare token
cf_token = ""
# Cloudflare zone id
cf_zone_id = ""

Toate variabilele pot fi obținute din yc config list, deoarece utilitarul de consolă este deja configurat. Vă sfătuiesc să adăugați imediat private.auto.tfvars în .gitignore, pentru a nu publica accidental datele private.

În private.auto.tfvars am specificat de asemenea datele de la Cloudflare — pentru crearea înregistrărilor DNS și pentru a face proxy pentru domeniul principal events.kis.im pe serverele noastre. Dacă nu doriți să folosiți Cloudflare, eliminați inițializarea provider-ului cloudflare în main.tf și fișierul dns.tf, care se ocupă cu crearea înregistrărilor DNS necesare.

În activitatea noastră vom combina toate cele trei metode — interfața web, utilitarul de consolă și terraform.

Rețele virtuale

Sincer, acest pas ar fi putut fi omis, deoarece la crearea unui nou cloud se va crea automat o rețea separată și 3 subrețele — câte una pentru fiecare zonă de disponibilitate. Totuși, ne-ar plăcea să creăm pentru proiectul nostru o rețea separată cu propria sa adresare. Schema generală de funcționare a rețelei în Yandex.Cloud este prezentată în imaginea de mai jos (luată cinstit de pe https://cloud.yandex.ru/docs/vpc/concepts/)

Acceptăm 10.000 de evenimente în Yandex.Cloud. Partea 1

Așadar, creați o rețea comună, în cadrul căreia resursele vor putea comunica între ele. Pentru fiecare zonă de disponibilitate se creează o subrețea cu propria sa adresare care se conectează la rețeaua comună. În final, toate resursele cloud din ea pot comunica, chiar și fiind în zone de disponibilitate diferite. Resursele conectate la diferite rețele cloud pot să se vadă una pe alta doar prin adrese externe. Apropo, cum funcționează această magie în interior, a fost bine descris pe Habr.

Crearea rețelei este descrisă în fișierul network.tf din repository. Acolo creăm o rețea privată comună internă și conectăm la ea trei subrețele în diferite zone de disponibilitate — internal-a (172.16.1.0/24), internal-b (172.16.2.0/24), internal-c (172.16.3.0/24).

Inițializăm terraform și creăm rețele:

vozerov@mba:~\/events\/terraform (master) $ terraform init
... trecut...

vozerov@mba:~\/events\/terraform (master) $ terraform apply -target yandex_vpc_subnet.internal-a -target yandex_vpc_subnet.internal-b -target yandex_vpc_subnet.internal-c

... trecut...

Plan: 4 de adăugat, 0 de modificat, 0 de distrus.

Vrei să efectuezi aceste acțiuni?
  Terraform va efectua acțiunile descrise mai sus.
  Numai 'da' va fi acceptat pentru aprobat.

  Introdu o valoare: da

yandex_vpc_network.internal: Creare...
yandex_vpc_network.internal: Creare completă după 3s [id=enp2g2rhile7gbqlbrkr]
yandex_vpc_subnet.internal-a: Creare...
yandex_vpc_subnet.internal-b: Creare...
yandex_vpc_subnet.internal-c: Creare...
yandex_vpc_subnet.internal-a: Creare completă după 6s [id=e9b1dad6mgoj2v4funog]
yandex_vpc_subnet.internal-b: Creare completă după 7s [id=e2liv5i4amu52p64ac9p]
yandex_vpc_subnet.internal-c: Încă se creează... [10s scurs]
yandex_vpc_subnet.internal-c: Creare completă după 10s [id=b0c2qhsj2vranoc9vhcq]

Aplicare completă! Resurse: 4 adăugate, 0 modificate, 0 distruse.

Excelent! Am creat rețeaua noastră și acum suntem pregătiți să creăm serviciile noastre interne.

Crearea mașinilor virtuale

Pentru testarea aplicației, va fi suficient să creăm două mașini virtuale — prima va fi necesară pentru compilarea și rularea aplicației, iar a doua — pentru a rula Kafka, pe care o vom folosi pentru stocarea mesajelor de intrare. Și vom crea încă o mașină, unde vom configura Prometheus pentru monitorizarea aplicației.

Virtualele vor fi configurate cu ajutorul Ansible, așa că înainte de a rula Terraform, asigură-te că ai instalată o versiune recentă de Ansible. Și instalează rolurile necesare cu Ansible Galaxy:

vozerov@mba:~\/events\/terraform (master) $ cd ..\/ansible\/
vozerov@mba:~\/events\/ansible (master) $ ansible-galaxy install -r requirements.yml
- cloudalchemy-prometheus (master) este deja instalat, sărind.
- cloudalchemy-grafana (master) este deja instalat, sărind.
- sansible.kafka (master) este deja instalat, sărind.
- sansible.zookeeper (master) este deja instalat, sărind.
- geerlingguy.docker (master) este deja instalat, sărind.
vozerov@mba:~\/events\/ansible (master) $

În interiorul folderului Ansible se află un exemplu de fișier de configurare .ansible.cfg, pe care îl folosesc eu. Poate fi util.

Înainte de a crea mașinile virtuale, asigură-te că ssh-agent-ul tău este activat și că ai adăugat cheia ssh, altfel Terraform nu va putea să se conecteze la mașinile create. Eu, desigur, am dat peste o eroare în os x: https://github.com/ansible/ansible/issues/32499#issuecomment-341578864. Pentru a nu întâlni aceeași problemă, înainte de a rula Terraform, adaugă o mică variabilă în env:

vozerov@mba:~\/events\/terraform (master) $ export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES

În folderul cu Terraform, creăm resursele necesare:

vozerov@mba:~\/events\/terraform (master) $ terraform apply -target yandex_compute_instance.build -target yandex_compute_instance.monitoring -target yandex_compute_instance.kafka
yandex_vpc_network.internal: Refreshing state... [id=enp2g2rhile7gbqlbrkr]
data.yandex_compute_image.ubuntu_image: Refreshing state...
yandex_vpc_subnet.internal-a: Refreshing state... [id=e9b1dad6mgoj2v4funog]

A execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

... skipped ...

Plan: 3 to add, 0 to change, 0 to destroy.

... skipped ...

Dacă totul a decurs bine (și așa ar trebui să fie), atunci vom avea trei mașini virtuale:

  1. build — mașina pentru testarea și compilarea aplicației. Docker a fost instalat automat de ansible.
  2. monitoring — mașina pentru monitorizare — pe ea sunt instalate prometheus & grafana. Login / parolă standard: admin / admin
  3. kafka — o mașină mică cu kafka instalat, accesibilă pe portul 9092.

Să ne asigurăm că toate sunt la locul lor:

vozerov@mba:~\/events (master) $ yc compute instance list
+----------------------+------------+---------------+---------+---------------+-------------+
|          ID          |    NAME    |    ZONE ID    | STATUS  |  EXTERNAL IP  | INTERNAL IP |
+----------------------+------------+---------------+---------+---------------+-------------+
| fhm081u8bkbqf1pa5kgj | monitoring | ru-central1-a | RUNNING | 84.201.159.71 | 172.16.1.35 |
| fhmf37k03oobgu9jmd7p | kafka      | ru-central1-a | RUNNING | 84.201.173.41 | 172.16.1.31 |
| fhmt9pl1i8sf7ga6flgp | build      | ru-central1-a | RUNNING | 84.201.132.3  | 172.16.1.26 |
+----------------------+------------+---------------+---------+---------------+-------------+

Resursele sunt la locul lor și de aici putem extrage adresele lor IP. În cele ce urmează, voi folosi adresele IP pentru conectarea prin SSH și testarea aplicației. Dacă aveți un cont pe cloudflare, conectat la terraform, folosiți fără ezitare numele DNS proaspăt create.
Apropo, când se creează o mașină virtuală, se emite un IP intern și un nume DNS intern, astfel încât să te poți adresa serverelor din rețea după nume:

ubuntu@build:~$ ping kafka.ru-central1.internal
PING kafka.ru-central1.internal (172.16.1.31) 56(84) bytes of data.
64 bytes from kafka.ru-central1.internal (172.16.1.31): icmp_seq=1 ttl=63 time=1.23 ms
64 bytes from kafka.ru-central1.internal (172.16.1.31): icmp_seq=2 ttl=63 time=0.625 ms
^C
--- kafka.ru-central1.internal ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min\/avg\/max\/mdev = 0.625\/0.931\/1.238\/0.308 ms

Acest lucru ne va fi util pentru a specifica aplicației endpoint-ul cu kafka.

Construim aplicația

Excelent, serverele sunt pregătite, aplicația este disponibilă — rămâne doar să o construim și să o publicăm. Pentru construire, vom folosi un docker build obișnuit, dar pentru stocarea imaginilor vom folosi serviciul oferit de yandex — container registry. Dar despre toate pe rând.

Copiem aplicația pe mașina build, ne conectăm prin SSH și construim imaginea:

vozerov@mba:~\/events\/terraform (master) $ cd ..
vozerov@mba:~\/events (master) $ rsync -av app\/ ubuntu@84.201.132.3:app\/\n\n... skipped ...\n\nsent 3849 bytes  received 70 bytes  7838.00 bytes\/sec\ntotal size is 3644  speedup is 0.93\n\nvozerov@mba:~\/events (master) $ ssh 84.201.132.3 -l ubuntu\nuptao@build:~$ cd app\nuptao@build:~\/app$ sudo docker build -t app .\nSending build context to Docker daemon  6.144kB\nStep 1\/9 : FROM golang:latest AS build\n... skipped ...\n\nSuccessfully built 9760afd8ef65\nSuccessfully tagged app:latest

Am făcut jumătate din treabă - acum putem verifica funcționarea aplicației noastre, rulând-o și direcționând-o către kafka:

ubuntu@build:~\/app$ sudo docker run --name app -d -p 8080:8080 app \/app\/app -kafka=kafka.ru-central1.internal:9092\n\nDe pe mașina locală putem trimite un eveniment de test și observa răspunsul:\n\nvozerov@mba:~\/events (master) $ curl -D - -s -X POST -d '{"key1":"data1"}' http:\/\/84.201.132.3:8080\/post\nHTTP\/1.1 200 OK\nContent-Type: application\/json\nDate: Mon, 13 Apr 2020 13:53:54 GMT\nContent-Length: 41\n\n{"status":"ok","partition":0,"Offset":0}\nvozerov@mba:~\/events (master) $

Aplicația a răspuns cu succesul înregistrării și indicarea ID-ului partiției și offset-ului în care a ajuns mesajul. Rămâne un singur lucru de făcut - să creăm un registry în Yandex.Cloud și să urcăm acolo imaginea noastră (cum se face acest lucru în trei linii, este descris în fișierul registry.tf). Creăm un depozit:

vozerov@mba:~\/events\/terraform (master) $ terraform apply -target yandex_container_registry.events\n\n... skipped ...\n\nPlan: 1 to add, 0 to change, 0 to destroy.\n\n... skipped ...\n\nApply complete! Resources: 1 added, 0 changed, 0 destroyed.

Pentru autentificarea în container registry există mai multe metode - cu ajutorul token-ului oauth, token-ului iam sau cheii contului de serviciu. Mai multe detalii despre aceste metode sunt în documentație. https://cloud.yandex.ru/docs/container-registry/operations/authentication. Vom folosi cheia contului de serviciu, așa că vom crea un cont:

vozerov@mba:~\/events\/terraform (master) $ terraform apply -target yandex_iam_service_account.docker -target yandex_resourcemanager_folder_iam_binding.puller -target yandex_resourcemanager_folder_iam_binding.pusher\n\n... skipped ...\n\nApply complete! Resources: 3 added, 0 changed, 0 destroyed.

Acum rămâne să facem o cheie pentru el:

vozerov@mba:~\/events\/terraform (master) $ yc iam key create --service-account-name docker -o key.json\nid: ajej8a06kdfbehbrh91p\nservice_account_id: ajep6d38k895srp9osij\ncreated_at: "2020-04-13T14:00:30Z"\nkey_algorithm: RSA_2048

Obținem informații despre ID-ul depozitului nostru, transferăm cheia și ne autorizăm:

vozerov@mba:~\/events\/terraform (master) $ scp key.json ubuntu@84.201.132.3:\nkey.json                                                                                                                    100% 2392   215.1KB\/s   00:00\n\nvozerov@mba:~\/events\/terraform (master) $ ssh 84.201.132.3 -l ubuntu\n\nubuntu@build:~$ cat key.json | sudo docker login --username json_key --password-stdin cr.yandex\nWARNING! Your password will be stored unencrypted in \/home\/ubuntu\/.docker\/config.json.\nConfigure a credential helper to remove this warning. See\nhttps:\/\/docs.docker.com\/engine\/reference\/commandline\/login\/#credentials-store\n\nLogin Succeeded\nubunt@build:~$

Pentru a încărca imaginea în registru, vom avea nevoie de ID-ul container registry, pe care îl obținem din utilitarul yc:

vozerov@mba:~ $ yc container registry get events
id: crpdgj6c9umdhgaqjfmm
folder_id:
name: events
status: ACTIVE
created_at: "2020-04-13T13:56:41.914Z"

După aceasta, etichetăm imaginea noastră cu un nume nou și o încărcăm:

ubuntu@build:~$ sudo docker tag app cr.yandex/crpdgj6c9umdhgaqjfmm/events:v1
ubuntu@build:~$ sudo docker push cr.yandex/crpdgj6c9umdhgaqjfmm/events:v1
Încărcarea se referă la repository [cr.yandex/crpdgj6c9umdhgaqjfmm/events]
8c286e154c6e: Încărcat
477c318b05cb: Încărcat
beee9f30bc1f: Încărcat
v1: digest: sha256:1dd5aaa9dbdde2f60d833be0bed1c352724be3ea3158bcac3cdee41d47c5e380 size: 946

Putem verifica că imaginea a fost încărcată cu succes:

vozerov@mba:~/events/terraform (master) $ yc container repository list
+----------------------+-----------------------------+
|          ID          |            NAME             |
+----------------------+-----------------------------+
| crpe8mqtrgmuq07accvn | crpdgj6c9umdhgaqjfmm/events |
+----------------------+-----------------------------+

Apropo, dacă instalați utilitarul yc pe o mașină cu linux, puteți folosi comanda

yc container registry configure-docker

pentru a configura docker-ul.

Concluzie

Am realizat o muncă mare și grea și, ca rezultat:

  1. Am conceput arhitectura serviciului nostru viitor.
  2. Am scris o aplicație în golang, care implementează logica noastră de afaceri.
  3. Am compilat-o și am încărcat-o în registry-ul privat de containere.

În următoarea parte ne vom concentra pe ceva interesant — vom publica aplicația noastră în producție și în cele din urmă vom aplica o sarcină asupra ei. Nu vă deconectați!

Acest material este disponibil într-o înregistrare video a practicumului deschis REBRAIN & Yandex.Cloud: Acceptăm 10.000 de cereri pe secundă pe Yandex Cloud — https://youtu.be/cZLezUm0ekE

Dacă sunteți interesați să participați la astfel de evenimente online și să puneți întrebări în timp real, conectați-vă la canalul DevOps by REBRAIN.

Oferim mulțumiri speciale Yandex.Cloud pentru oportunitatea de a organiza un astfel de eveniment. Linkul către ei — https://cloud.yandex.ru/prices

Dacă aveți nevoie de migrare în cloud sau aveți întrebări despre infrastructura dumneavoastră, nu ezitați să lăsați o cerere.

P.S. Avem 2 audituri gratuite pe lună, poate proiectul dumneavoastră va fi printre ele.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster