Accettiamo 10 eventi in Yandex.Cloud. Parte 000

Ciao a tutti, amici!

* Questo articolo è basato sul workshop aperto REBRAIN & Yandex.Cloud, se preferisci guardare il video, puoi trovarlo a questo link - https://youtu.be/cZLezUm0ekE

Recentemente abbiamo avuto l'opportunità di provare Yandex.Cloud dal vivo. Poiché volevamo indagare a lungo e in modo approfondito, abbiamo immediatamente abbandonato l'idea di lanciare un semplice blog Wordpress con base cloud: era troppo noioso. Dopo qualche riflessione, abbiamo deciso di implementare qualcosa di simile a un'architettura di servizi di produzione per ricevere e analizzare eventi in modalità quasi in tempo reale.

Sono assolutamente sicuro che la stragrande maggioranza delle attività online (e non solo) raccolgano in qualche modo una montagna di informazioni sui propri utenti e sulle loro azioni. Come minimo, questo è necessario per prendere determinate decisioni: ad esempio, se gestisci un gioco online, puoi guardare le statistiche a quale livello gli utenti rimangono più spesso bloccati ed eliminano il tuo giocattolo. O perché gli utenti lasciano il tuo sito senza acquistare nulla (ciao Yandex.Metrica).

Quindi, la nostra storia: come abbiamo scritto un'applicazione in Golang, testato Kafka vs RabbitMQ vs yqs, scritto lo streaming di dati in un cluster Clickhouse e visualizzato i dati utilizzando yandex datalens. Naturalmente, tutto ciò è stato condito con delizie infrastrutturali sotto forma di docker, terraform, gitlab ci e, ovviamente, prometheus. Andiamo!

Vorrei prenotare immediatamente che non saremo in grado di configurare tutto in una sola seduta: per questo avremo bisogno di diversi articoli della serie. Un po' di struttura:

Parte 1 (la stai leggendo). Decideremo le specifiche e l'architettura della soluzione e scriveremo anche un'applicazione in golang.
Parte 2. Rilasciamo la nostra applicazione in produzione, la rendiamo scalabile e testiamo il carico.
Parte 3. Proviamo a capire perché dobbiamo archiviare i messaggi in un buffer e non in file, e confrontiamo anche il servizio di coda Kafka, Rabbitmq e Yandex.
Parte 4 Distribuiremo un cluster Clickhouse, scriveremo un servizio di streaming per trasferire i dati dal buffer lì e configureremo la visualizzazione in datalens.
Parte 5 Portiamo l'intera infrastruttura nella forma corretta: configuriamo ci/cd utilizzando gitlab ci, colleghiamo il monitoraggio e il rilevamento dei servizi utilizzando prometheus e consul.

TK

Per prima cosa formuliamo i termini di riferimento: esattamente cosa vogliamo ottenere come risultato.

  1. Vogliamo avere un endpoint come events.kis.im (kis.im è il dominio di prova che utilizzeremo in tutti gli articoli), che dovrebbe ricevere eventi utilizzando HTTPS.
  2. Gli eventi sono un semplice json come: {“event”: “view”, “os”: “linux”, “browser”: “chrome”}. Nella fase finale aggiungeremo altri campi, ma questo non avrà un ruolo importante. Se lo desideri, puoi passare a protobuf.
  3. Il servizio deve essere in grado di elaborare 10 eventi al secondo.
  4. Dovrebbe essere possibile scalare orizzontalmente semplicemente aggiungendo nuove istanze alla nostra soluzione. E sarebbe bello se potessimo spostare la parte anteriore in diverse geolocalizzazioni per ridurre la latenza per le richieste dei clienti.
  5. Tolleranza ai guasti. La soluzione deve essere sufficientemente stabile e in grado di sopravvivere alla caduta di qualsiasi parte (fino ad un certo numero, ovviamente).

Architettura

In generale, per questo tipo di compiti sono state inventate da tempo architetture classiche che consentono una scalabilità efficiente. La figura mostra un esempio della nostra soluzione.

Accettiamo 10 eventi in Yandex.Cloud. Parte 000

Quindi cosa abbiamo:

1. A sinistra ci sono i nostri dispositivi che generano vari eventi, che si tratti di giocatori che completano un livello in un giocattolo su uno smartphone o che creano un ordine in un negozio online tramite un normale browser. Un evento, come specificato nelle specifiche, è un semplice json che viene inviato al nostro endpoint - events.kis.im.

2. I primi due server sono semplici bilanciatori, i loro compiti principali sono:

  • Sii costantemente disponibile. Per fare ciò, puoi utilizzare, ad esempio, keepalived, che scambierà l'IP virtuale tra i nodi in caso di problemi.
  • Terminare TLS. Sì, termineremo TLS su di essi. In primo luogo, affinché la nostra soluzione rispetti le specifiche tecniche e, in secondo luogo, per alleviare l'onere di stabilire una connessione crittografata dai nostri server backend.
  • Bilancia le richieste in entrata sui server backend disponibili. La parola chiave qui è accessibile. Sulla base di ciò, arriviamo alla conclusione che i bilanciatori di carico devono essere in grado di monitorare i nostri server con applicazioni e interrompere il bilanciamento del traffico verso i nodi guasti.

3. Dopo i bilanciatori, abbiamo i server delle applicazioni che eseguono un'applicazione abbastanza semplice. Dovrebbe essere in grado di accettare richieste in arrivo tramite HTTP, convalidare il json inviato e inserire i dati in un buffer.

4. Il diagramma mostra Kafka come buffer, anche se ovviamente a questo livello possono essere utilizzati altri servizi simili. Confronteremo Kafka, coniglimq e yqs nel terzo articolo.

5. Il penultimo punto della nostra architettura è Clickhouse, un database a colonne che consente di archiviare ed elaborare un'enorme quantità di dati. A questo livello, dobbiamo trasferire i dati dal buffer al sistema di archiviazione stesso (maggiori informazioni nell'articolo 4).

Questo design ci consente di ridimensionare ogni livello in modo indipendente in senso orizzontale. I server backend non possono farcela - aggiungiamo un'altra cosa - dopotutto sono applicazioni stateless e quindi questo può essere fatto anche automaticamente. Il buffer in stile Kafka non funziona: aggiungiamo più server e trasferiamo su di essi alcune partizioni del nostro argomento. Clickhouse non può gestirlo: è impossibile :) Infatti, collegheremo anche i server e divideremo i dati.

A proposito, se desideri implementare la parte opzionale delle nostre specifiche tecniche e scalare in diverse geolocalizzazioni, non c'è niente di più semplice:

Accettiamo 10 eventi in Yandex.Cloud. Parte 000

In ogni geolocalizzazione distribuiamo un bilanciatore del carico con applicazione e kafka. In generale sono sufficienti 2 server applicativi, 3 nodi Kafka e un bilanciatore cloud, ad esempio cloudflare, che controllerà la disponibilità dei nodi applicativi e bilancerà le richieste tramite geolocalizzazione in base all'indirizzo IP di origine del client. Pertanto, i dati inviati da un cliente americano arriveranno su server americani. E i dati dall'Africa sono in africano.

Quindi tutto è abbastanza semplice: utilizziamo lo strumento mirror del set Kafka e copiamo tutti i dati da tutte le località nel nostro data center centrale situato in Russia. Internamente, analizziamo i dati e li registriamo in Clickhouse per la successiva visualizzazione.

Quindi, abbiamo risolto l'architettura: iniziamo a scuotere Yandex.Cloud!

Scrivere un'applicazione

Prima del Cloud bisogna avere ancora un po' di pazienza e scrivere un servizio abbastanza semplice per elaborare gli eventi in arrivo. Utilizzeremo golang perché si è dimostrato molto efficace come linguaggio per scrivere applicazioni di rete.

Dopo aver trascorso un'ora (forse un paio d'ore), otteniamo qualcosa del genere: https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/main.go.

Quali sono i punti principali che vorrei sottolineare qui:

1. All'avvio dell'applicazione è possibile specificare due flag. Uno è responsabile della porta su cui ascolteremo le richieste http in arrivo (-addr). Il secondo è per l'indirizzo del server Kafka dove registreremo i nostri eventi (-kafka):

addr     = flag.String("addr", ":8080", "TCP address to listen to")
kafka    = flag.String("kafka", "127.0.0.1:9092", "Kafka endpoints”)

2. L'applicazione utilizza la libreria sarama ([]github.com/Shopify/sarama) per inviare messaggi al cluster Kafka. Impostiamo subito le impostazioni mirate alla massima velocità di elaborazione:

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

3. La nostra applicazione dispone anche di un client Prometheus integrato, che raccoglie varie metriche, come:

  • numero di richieste alla nostra applicazione;
  • numero di errori durante l'esecuzione della richiesta (impossibile leggere la richiesta post, json non funzionante, impossibile scrivere a Kafka);
  • tempo di elaborazione per una richiesta da parte del client, compreso il tempo necessario per scrivere un messaggio a Kafka.

4. Tre endpoint elaborati dalla nostra applicazione:

  • /status - restituisce semplicemente ok per dimostrare che siamo vivi. Sebbene sia possibile aggiungere alcuni controlli, come la disponibilità del cluster Kafka.
  • /metrics: in base a questo URL, il client Prometheus restituirà le metriche raccolte.
  • /post è l'endpoint principale a cui verranno inviate le richieste POST con json all'interno. La nostra applicazione controlla la validità del json e, se tutto è ok, scrive i dati nel cluster Kafka.

Effettuerò una prenotazione sul fatto che il codice non è perfetto: può (e deve!) essere completato. Ad esempio, puoi smettere di usare net/http integrato e passare al più veloce fasthttp. Oppure puoi guadagnare tempo di elaborazione e risorse della CPU spostando il controllo di validità JSON in una fase successiva, quando i dati vengono trasferiti dal buffer al cluster clickhouse.

Oltre all'aspetto dello sviluppo, abbiamo pensato subito alla nostra infrastruttura futura e abbiamo deciso di implementare la nostra applicazione tramite docker. Il Dockerfile finale per la creazione dell'applicazione è https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/Dockerfile. In generale è abbastanza semplice, l'unico punto a cui vorrei prestare attenzione è l'assemblaggio multistadio, che ci permette di ridurre l'immagine finale del nostro contenitore.

Primi passi nel cloud

Prima di tutto registrati su cloud.yandex.ru. Dopo aver compilato tutti i campi necessari, verrà creato un account e verrà assegnata una sovvenzione per una certa somma di denaro, che potrà essere utilizzata per testare i servizi cloud. Se vuoi ripetere tutti i passaggi del nostro articolo, questa sovvenzione dovrebbe essere sufficiente per te.

Dopo la registrazione, verranno creati per te un cloud separato e una directory predefinita, in cui potrai iniziare a creare risorse cloud. In generale, in Yandex.Cloud, la relazione tra le risorse è simile a questa:

Accettiamo 10 eventi in Yandex.Cloud. Parte 000

Puoi creare più cloud per un account. E all'interno del cloud, crea directory diverse per diversi progetti aziendali. Puoi leggere ulteriori informazioni a riguardo nella documentazione: https://cloud.yandex.ru/docs/resource-manager/concepts/resources-hierarchy. A proposito, ne farò spesso riferimento più avanti nel testo. Quando ho configurato l'intera infrastruttura da zero, la documentazione mi ha aiutato più di una volta, quindi ti consiglio di studiarla.

Per gestire il cloud, puoi utilizzare sia l'interfaccia web che l'utilità della console - yc. L'installazione viene eseguita con un comando (per Linux e Mac Os):

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

Se il tuo specialista della sicurezza interna è infuriato per l'esecuzione di script da Internet, in primo luogo, puoi aprire lo script e leggerlo e, in secondo luogo, eseguirlo con il nostro utente, senza diritti di root.

Se desideri installare un client per Windows, puoi utilizzare le istruzioni qui e poi eseguire yc initper personalizzarlo completamente:

vozerov@mba:~ $ yc init
Welcome! This command will take you through the configuration process.
Please go to https://oauth.yandex.ru/authorize?response_type=token&client_id= in order to obtain OAuth token.

Please enter OAuth token:
Please select cloud to use:
 [1] cloud-b1gv67ihgfu3bp (id = b1gv67ihgfu3bpt24o0q)
 [2] fevlake-cloud (id = b1g6bvup3toribomnh30)
Please enter your numeric choice: 2
Your current cloud has been set to 'fevlake-cloud' (id = b1g6bvup3toribomnh30).
Please choose folder to use:
 [1] default (id = b1g5r6h11knotfr8vjp7)
 [2] Create a new folder
Please enter your numeric choice: 1
Your current folder has been set to 'default' (id = b1g5r6h11knotfr8vjp7).
Do you want to configure a default Compute zone? [Y/n]
Which zone do you want to use as a profile default?
 [1] ru-central1-a
 [2] ru-central1-b
 [3] ru-central1-c
 [4] Don't set default zone
Please enter your numeric choice: 1
Your profile default Compute zone has been set to 'ru-central1-a'.
vozerov@mba:~ $

In linea di principio, il processo è semplice: devi prima ottenere un token OAuth per gestire il cloud, selezionare il cloud e la cartella che utilizzerai.

Se disponi di più account o cartelle all'interno dello stesso cloud, puoi creare profili aggiuntivi con impostazioni separate tramite yc config profile create e passare da uno all'altro.

Oltre ai metodi di cui sopra, il team Yandex.Cloud ha scritto un ottimo plugin per Terraform per la gestione delle risorse cloud. Da parte mia, ho preparato un repository git, in cui ho descritto tutte le risorse che verranno create come parte dell'articolo - https://github.com/rebrainme/yandex-cloud-events/. A noi interessa il ramo master, cloniamolo in locale:


vozerov@mba:~ $ git clone https://github.com/rebrainme/yandex-cloud-events/ events
Cloning into 'events'...
remote: Enumerating objects: 100, done.
remote: Counting objects: 100% (100/100), done.
remote: Compressing objects: 100% (68/68), done.
remote: Total 100 (delta 37), reused 89 (delta 26), pack-reused 0
Receiving objects: 100% (100/100), 25.65 KiB | 168.00 KiB/s, done.
Resolving deltas: 100% (37/37), done.
vozerov@mba:~ $ cd events/terraform/

Tutte le variabili principali utilizzate in terraform sono scritte nel file main.tf. Per iniziare, crea un file private.auto.tfvars nella cartella terraform con il seguente contenuto:

# 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 = ""

Tutte le variabili possono essere prese dall'elenco yc config, poiché abbiamo già configurato l'utilità della console. Ti consiglio di aggiungere subito private.auto.tfvars a .gitignore, per non pubblicare accidentalmente dati privati.

In private.auto.tfvars abbiamo anche specificato i dati di Cloudflare - per creare record DNS e delegare il dominio principale events.kis.im ai nostri server. Se non desideri utilizzare cloudflare, rimuovi l'inizializzazione del provider cloudflare in main.tf e il file dns.tf, che è responsabile della creazione dei record DNS necessari.

Nel nostro lavoro combineremo tutti e tre i metodi: l'interfaccia web, l'utilità della console e terraform.

Reti virtuali

Ad essere onesti, potresti saltare questo passaggio, poiché quando crei un nuovo cloud, avrai automaticamente una rete separata e 3 sottoreti create, una per ciascuna zona di disponibilità. Ma vorremmo comunque creare una rete separata per il nostro progetto con un proprio indirizzamento. Lo schema generale di come funziona la rete in Yandex.Cloud è mostrato nella figura seguente (onestamente tratto da https://cloud.yandex.ru/docs/vpc/concepts/)

Accettiamo 10 eventi in Yandex.Cloud. Parte 000

Quindi, crei una rete comune all'interno della quale le risorse possono comunicare tra loro. Per ogni zona di disponibilità viene creata una sottorete con il proprio indirizzamento e collegata alla rete generale. Di conseguenza, tutte le risorse cloud al suo interno possono comunicare, anche se si trovano in zone di disponibilità diverse. Le risorse connesse a diverse reti cloud possono vedersi solo attraverso indirizzi esterni. A proposito, come funziona questa magia all'interno? è stato ben descritto su Habré.

La creazione della rete è descritta nel file network.tf dal repository. Lì creiamo una rete privata comune interna e colleghiamo ad essa tre sottoreti in diverse zone di disponibilità: internal-a (172.16.1.0/24), internal-b (172.16.2.0/24), internal-c (172.16.3.0/24 ).

Inizializza terraform e crea reti:

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

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

... skipped ...

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

yandex_vpc_network.internal: Creating...
yandex_vpc_network.internal: Creation complete after 3s [id=enp2g2rhile7gbqlbrkr]
yandex_vpc_subnet.internal-a: Creating...
yandex_vpc_subnet.internal-b: Creating...
yandex_vpc_subnet.internal-c: Creating...
yandex_vpc_subnet.internal-a: Creation complete after 6s [id=e9b1dad6mgoj2v4funog]
yandex_vpc_subnet.internal-b: Creation complete after 7s [id=e2liv5i4amu52p64ac9p]
yandex_vpc_subnet.internal-c: Still creating... [10s elapsed]
yandex_vpc_subnet.internal-c: Creation complete after 10s [id=b0c2qhsj2vranoc9vhcq]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Grande! Abbiamo creato la nostra rete e ora siamo pronti a creare i nostri servizi interni.

Creare macchine virtuali

Per testare l'applicazione dovremo solo creare due macchine virtuali: la prima ci servirà per creare ed eseguire l'applicazione, la seconda per eseguire Kafka, che utilizzeremo per archiviare i messaggi in arrivo. E creeremo un'altra macchina in cui configureremo Prometheus per monitorare l'applicazione.

Le macchine virtuali verranno configurate utilizzando ansible, quindi prima di avviare terraform assicurati di disporre di una delle ultime versioni di ansible. E installa i ruoli necessari con Ansible Galaxy:

vozerov@mba:~/events/terraform (master) $ cd ../ansible/
vozerov@mba:~/events/ansible (master) $ ansible-galaxy install -r requirements.yml
- cloudalchemy-prometheus (master) is already installed, skipping.
- cloudalchemy-grafana (master) is already installed, skipping.
- sansible.kafka (master) is already installed, skipping.
- sansible.zookeeper (master) is already installed, skipping.
- geerlingguy.docker (master) is already installed, skipping.
vozerov@mba:~/events/ansible (master) $

All'interno della cartella ansible c'è un file di configurazione di esempio .ansible.cfg che utilizzo. Potrebbe tornare utile.

Prima di creare macchine virtuali, assicurati di avere ssh-agent in esecuzione e una chiave ssh aggiunta, altrimenti terraform non sarà in grado di connettersi alle macchine create. Ovviamente mi sono imbattuto in un bug in OS X: https://github.com/ansible/ansible/issues/32499#issuecomment-341578864. Per evitare che ciò accada di nuovo, aggiungi una piccola variabile a env prima di avviare Terraform:

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

Nella cartella con terraform creiamo le risorse necessarie:

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]

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

Se tutto si è concluso con successo (e dovrebbe essere), allora avremo tre macchine virtuali:

  1. build: una macchina per testare e creare un'applicazione. Docker è stato installato automaticamente da Ansible.
  2. monitoraggio - una macchina di monitoraggio - prometheus & grafana installata su di essa. Login/password standard: admin/admin
  3. kafka è una piccola macchina con kafka installato, accessibile sulla porta 9092.

Assicuriamoci che siano tutti a posto:

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 |
+----------------------+------------+---------------+---------+---------------+-------------+

Le risorse sono a posto e da qui possiamo ottenere i loro indirizzi IP. In quanto segue utilizzerò gli indirizzi IP per connettermi tramite ssh e testare l'applicazione. Se hai un account cloudflare connesso a terraform, sentiti libero di utilizzare nomi DNS appena creati.
A proposito, quando si crea una macchina virtuale, vengono forniti un IP interno e un nome DNS interno, in modo da poter accedere ai server all'interno della rete per nome:

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

Questo ci sarà utile per indicare all'applicazione l'endpoint con kafk.

Assemblaggio dell'applicazione

Fantastico, ci sono i server, c'è un'applicazione: non resta che assemblarla e pubblicarla. Per la build utilizzeremo la solita build docker, ma come archiviazione delle immagini utilizzeremo un servizio di Yandex: registro dei contenitori. Ma prima le cose principali.

Copiamo l'applicazione sulla macchina di compilazione, accediamo tramite ssh e assembliamo l'immagine:

vozerov@mba:~/events/terraform (master) $ cd ..
vozerov@mba:~/events (master) $ rsync -av app/ [email protected]:app/

... skipped ...

sent 3849 bytes  received 70 bytes  7838.00 bytes/sec
total size is 3644  speedup is 0.93

vozerov@mba:~/events (master) $ ssh 84.201.132.3 -l ubuntu
ubuntu@build:~$ cd app
ubuntu@build:~/app$ sudo docker build -t app .
Sending build context to Docker daemon  6.144kB
Step 1/9 : FROM golang:latest AS build
... skipped ...

Successfully built 9760afd8ef65
Successfully tagged app:latest

Metà della battaglia è fatta: ora possiamo verificare la funzionalità della nostra applicazione avviandola e inviandola a Kafka:

ubuntu@build:~/app$ sudo docker run --name app -d -p 8080:8080 app /app/app -kafka=kafka.ru-central1.internal:9092</code>

С локальной машинки можно отправить тестовый event и посмотреть на ответ:

<code>vozerov@mba:~/events (master) $ curl -D - -s -X POST -d '{"key1":"data1"}' http://84.201.132.3:8080/post
HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 13 Apr 2020 13:53:54 GMT
Content-Length: 41

{"status":"ok","partition":0,"Offset":0}
vozerov@mba:~/events (master) $

L'applicazione ha risposto con successo alla registrazione e indicando l'id della partizione e l'offset in cui era incluso il messaggio. Tutto ciò che resta da fare è creare un registro in Yandex.Cloud e caricare lì la nostra immagine (come farlo utilizzando tre righe è descritto nel file registro.tf). Crea un archivio:

vozerov@mba:~/events/terraform (master) $ terraform apply -target yandex_container_registry.events

... skipped ...

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

... skipped ...

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Esistono diversi modi per eseguire l'autenticazione nel registro dei contenitori: utilizzando un token oauth, un token iam o una chiave dell'account di servizio. Maggiori dettagli su questi metodi possono essere trovati nella documentazione. https://cloud.yandex.ru/docs/container-registry/operations/authentication. Utilizzeremo la chiave dell'account di servizio, quindi creiamo un account:

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

... skipped ...

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Ora non resta che crearne una chiave:

vozerov@mba:~/events/terraform (master) $ yc iam key create --service-account-name docker -o key.json
id: ajej8a06kdfbehbrh91p
service_account_id: ajep6d38k895srp9osij
created_at: "2020-04-13T14:00:30Z"
key_algorithm: RSA_2048

Riceviamo informazioni sull'ID del nostro archivio, trasferiamo la chiave ed effettuiamo l'accesso:

vozerov@mba:~/events/terraform (master) $ scp key.json [email protected]:
key.json                                                                                                                    100% 2392   215.1KB/s   00:00

vozerov@mba:~/events/terraform (master) $ ssh 84.201.132.3 -l ubuntu

ubuntu@build:~$ cat key.json | sudo docker login --username json_key --password-stdin cr.yandex
WARNING! Your password will be stored unencrypted in /home/ubuntu/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
ubuntu@build:~$

Per caricare l'immagine nel registro, abbiamo bisogno dell'ID del registro del contenitore, lo prendiamo dall'utilità yc:

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

Successivamente, tagghiamo la nostra immagine con un nuovo nome e carichiamo:

ubuntu@build:~$ sudo docker tag app cr.yandex/crpdgj6c9umdhgaqjfmm/events:v1
ubuntu@build:~$ sudo docker push cr.yandex/crpdgj6c9umdhgaqjfmm/events:v1
The push refers to repository [cr.yandex/crpdgj6c9umdhgaqjfmm/events]
8c286e154c6e: Pushed
477c318b05cb: Pushed
beee9f30bc1f: Pushed
v1: digest: sha256:1dd5aaa9dbdde2f60d833be0bed1c352724be3ea3158bcac3cdee41d47c5e380 size: 946

Possiamo verificare che l'immagine sia stata caricata correttamente:

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

A proposito, se installi l'utilità yc su una macchina Linux, puoi utilizzare il comando

yc container registry configure-docker

per configurare la finestra mobile.

conclusione

Abbiamo lavorato molto duramente e il risultato:

  1. Abbiamo ideato l'architettura del nostro servizio futuro.
  2. Abbiamo scritto un'applicazione in Golang che implementa la nostra logica aziendale.
  3. Lo abbiamo raccolto e inserito in un registro contenitori privato.

Nella parte successiva passeremo alle cose interessanti: rilasceremo la nostra applicazione in produzione e infine ne avvieremo il caricamento. Non cambiare!

Questo materiale è nella registrazione video del workshop aperto REBRAIN e Yandex.Cloud: accettiamo 10 richieste al secondo su Yandex Cloud - https://youtu.be/cZLezUm0ekE

Se sei interessato a partecipare a tali eventi online e porre domande in tempo reale, connettiti a canale DevOps di REBRAIN.

Vorremmo ringraziare in modo speciale Yandex.Cloud per l'opportunità di ospitare un evento del genere. Collegati a loro - https://cloud.yandex.ru/prices

Se devi passare al cloud o hai domande sulla tua infrastruttura, sentitevi liberi di lasciare una richiesta.

PS Abbiamo 2 audit gratuiti al mese, forse il tuo progetto sarà uno di questi.

Fonte: habr.com

Aggiungi un commento