Wir akzeptieren 10 Ereignisse in Yandex.Cloud. Teil 000

Hallo zusammen, Freunde!

* Dieser Artikel basiert auf dem offenen Workshop von REBRAIN & Yandex.Cloud. Wenn Sie sich das Video lieber ansehen möchten, können Sie es unter diesem Link finden – https://youtu.be/cZLezUm0ekE

Wir hatten kürzlich die Gelegenheit, Yandex.Cloud live auszuprobieren. Da wir lange und gründlich experimentieren wollten, haben wir die Idee, einen einfachen WordPress-Blog mit Cloud-Basis zu starten, sofort aufgegeben – es war zu langweilig. Nach einigem Überlegen entschieden wir uns, etwas zu implementieren, das einer Produktionsdienstarchitektur ähnelt, um Ereignisse nahezu in Echtzeit zu empfangen und zu analysieren.

Ich bin absolut sicher, dass die überwiegende Mehrheit der Online-Unternehmen (und nicht nur) auf irgendeine Weise eine Menge Informationen über ihre Benutzer und deren Aktionen sammeln. Zumindest ist dies notwendig, um bestimmte Entscheidungen zu treffen. Wenn Sie beispielsweise ein Online-Spiel verwalten, können Sie sich die Statistiken ansehen, auf welcher Ebene Benutzer am häufigsten stecken bleiben, und Ihr Spielzeug löschen. Oder warum Benutzer Ihre Website verlassen, ohne etwas zu kaufen (Hallo, Yandex.Metrica).

Also unsere Geschichte: Wie wir eine Anwendung in Golang geschrieben, Kafka vs. RabbitMQ vs. YQS getestet, Daten-Streaming in einem Clickhouse-Cluster geschrieben und die Daten mithilfe von Yandex Datalens visualisiert haben. Natürlich wurde das alles mit Infrastrukturfreuden in Form von Docker, Terraform, Gitlab Ci und natürlich Prometheus gewürzt. Lass uns gehen!

Ich möchte sofort reservieren, dass wir nicht alles in einer Sitzung konfigurieren können – dafür benötigen wir mehrere Artikel der Serie. Ein wenig zur Struktur:

Teil 1 (Sie lesen es gerade). Wir legen die Spezifikationen und die Architektur der Lösung fest und schreiben auch eine Anwendung in Golang.
Teil 2. Wir geben unsere Anwendung in die Produktion frei, machen sie skalierbar und testen die Auslastung.
Teil 3. Versuchen wir herauszufinden, warum wir Nachrichten in einem Puffer und nicht in Dateien speichern müssen, und vergleichen wir auch die Warteschlangendienste Kafka, RabbitMQ und Yandex.
Teil 4 Wir werden einen Clickhouse-Cluster bereitstellen, einen Streaming-Dienst schreiben, um Daten aus dem Puffer dorthin zu übertragen, und die Visualisierung in Datalens einrichten.
Teil 5 Bringen wir die gesamte Infrastruktur in den richtigen Zustand – richten Sie ci/cd mit gitlab ci ein, verbinden Sie Monitoring und Service Discovery mit prometheus und consul.

TK

Lassen Sie uns zunächst die Leistungsbeschreibung formulieren – was genau wir als Ergebnis erreichen wollen.

  1. Wir möchten einen Endpunkt wie events.kis.im haben (kis.im ist die Testdomäne, die wir in allen Artikeln verwenden werden), der Ereignisse über HTTPS empfangen soll.
  2. Ereignisse sind ein einfacher JSON wie: {“event“: „view“, „os“: „linux“, „browser“: „chrome“}. Im letzten Schritt werden wir noch ein paar Felder hinzufügen, aber das wird keine große Rolle spielen. Wenn Sie möchten, können Sie zu Protobuf wechseln.
  3. Der Dienst muss in der Lage sein, 10 Ereignisse pro Sekunde zu verarbeiten.
  4. Eine horizontale Skalierung sollte durch einfaches Hinzufügen neuer Instanzen zu unserer Lösung möglich sein. Und es wäre schön, wenn wir den vorderen Teil an andere geografische Standorte verschieben könnten, um die Latenz für Kundenanfragen zu reduzieren.
  5. Fehlertoleranz. Die Lösung muss stabil genug sein und den Sturz beliebiger Teile (natürlich bis zu einer bestimmten Anzahl) überstehen.

Architektur

Im Allgemeinen wurden für diese Art von Aufgaben seit langem klassische Architekturen erfunden, die eine effiziente Skalierung ermöglichen. Die Abbildung zeigt ein Beispiel unserer Lösung.

Wir akzeptieren 10 Ereignisse in Yandex.Cloud. Teil 000

Was wir also haben:

1. Auf der linken Seite befinden sich unsere Geräte, die verschiedene Ereignisse generieren, sei es, dass Spieler ein Level in einem Spielzeug auf einem Smartphone abschließen oder über einen normalen Browser eine Bestellung in einem Online-Shop aufgeben. Ein Ereignis, wie in der Spezifikation angegeben, ist ein einfaches JSON, das an unseren Endpunkt gesendet wird – events.kis.im.

2. Die ersten beiden Server sind einfache Balancer, ihre Hauptaufgaben sind:

  • Seien Sie ständig verfügbar. Dazu können Sie beispielsweise keepalived verwenden, das bei Problemen die virtuelle IP zwischen Knoten wechselt.
  • TLS beenden. Ja, wir werden TLS für sie beenden. Erstens, damit unsere Lösung den technischen Spezifikationen entspricht, und zweitens, um den Aufwand für den Aufbau einer verschlüsselten Verbindung von unseren Backend-Servern zu entlasten.
  • Verteilen Sie eingehende Anfragen auf verfügbare Backend-Server. Das Schlüsselwort hier ist zugänglich. Auf dieser Grundlage kommen wir zu dem Schluss, dass Load Balancer in der Lage sein müssen, unsere Server mit Anwendungen zu überwachen und den Datenverkehr nicht mehr auf ausgefallene Knoten auszugleichen.

3. Nach den Balancern haben wir Anwendungsserver, auf denen eine ziemlich einfache Anwendung ausgeführt wird. Es sollte in der Lage sein, eingehende Anfragen über HTTP anzunehmen, den gesendeten JSON zu validieren und die Daten in einen Puffer zu legen.

4. Das Diagramm zeigt Kafka als Puffer, obwohl auf dieser Ebene natürlich auch andere ähnliche Dienste verwendet werden können. Im dritten Artikel werden wir Kafka, RabbitMQ und YQS vergleichen.

5. Der vorletzte Punkt unserer Architektur ist Clickhouse – eine spaltenbasierte Datenbank, die es Ihnen ermöglicht, große Datenmengen zu speichern und zu verarbeiten. Auf dieser Ebene müssen wir Daten vom Puffer zum Speichersystem selbst übertragen (mehr dazu in Artikel 4).

Dieses Design ermöglicht es uns, jede Ebene unabhängig horizontal zu skalieren. Backend-Server kommen damit nicht zurecht – fügen wir noch etwas hinzu – schließlich handelt es sich um zustandslose Anwendungen, und daher kann dies sogar automatisch erfolgen. Der Puffer im Kafka-Stil funktioniert nicht – fügen wir weitere Server hinzu und übertragen einige der Partitionen unseres Themas auf diese. Clickhouse kann damit nicht umgehen – es ist unmöglich :) Tatsächlich werden wir auch die Server verbinden und die Daten teilen.

Übrigens, wenn Sie den optionalen Teil unserer technischen Spezifikationen umsetzen und an verschiedenen Standorten skalieren möchten, dann gibt es nichts einfacheres:

Wir akzeptieren 10 Ereignisse in Yandex.Cloud. Teil 000

An jedem Standort stellen wir einen Load Balancer mit Anwendung und Kafka bereit. Im Allgemeinen reichen 2 Anwendungsserver, 3 Kafka-Knoten und ein Cloud-Balancer, zum Beispiel Cloudflare, aus, der die Verfügbarkeit von Anwendungsknoten überprüft und Anfragen per Geolokalisierung basierend auf der Quell-IP-Adresse des Clients ausgleicht. Somit landen die von einem amerikanischen Client gesendeten Daten auf amerikanischen Servern. Und Daten aus Afrika sind in afrikanischer Sprache.

Dann ist alles ganz einfach: Wir nutzen das Spiegeltool aus dem Kafka-Set und kopieren alle Daten von allen Standorten in unser zentrales Rechenzentrum in Russland. Intern analysieren wir die Daten und zeichnen sie zur anschließenden Visualisierung in Clickhouse auf.

Also haben wir die Architektur geklärt – fangen wir an, Yandex.Cloud zu erschüttern!

Eine Bewerbung schreiben

Vor der Cloud muss man sich noch ein wenig gedulden und einen recht einfachen Dienst zur Verarbeitung eingehender Ereignisse schreiben. Wir werden Golang verwenden, da es sich als Sprache zum Schreiben von Netzwerkanwendungen sehr gut bewährt hat.

Nachdem wir eine Stunde (vielleicht ein paar Stunden) verbracht haben, erhalten wir etwa Folgendes: https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/main.go.

Was sind die wichtigsten Punkte, die ich hier anmerken möchte:

1. Beim Starten der Anwendung können Sie zwei Flags angeben. Einer ist für den Port verantwortlich, an dem wir eingehende http-Anfragen abhören (-addr). Der zweite ist für die Kafka-Serveradresse, unter der wir unsere Ereignisse aufzeichnen (-kafka):

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

2. Die Anwendung verwendet die Sarama-Bibliothek ([] github.com/Shopify/sarama), um Nachrichten an den Kafka-Cluster zu senden. Wir stellen sofort die auf maximale Verarbeitungsgeschwindigkeit ausgerichteten Einstellungen ein:

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

3. Unsere Anwendung verfügt außerdem über einen integrierten Prometheus-Client, der verschiedene Metriken sammelt, wie zum Beispiel:

  • Anzahl der Anfragen zu unserer Bewerbung;
  • Anzahl der Fehler bei der Ausführung der Anfrage (Post-Anfrage kann nicht gelesen werden, JSON ist kaputt, Kafka kann nicht geschrieben werden);
  • Bearbeitungszeit für eine Anfrage des Kunden, einschließlich der Zeit zum Schreiben einer Nachricht an Kafka.

4. Drei Endpunkte, die unsere Anwendung verarbeitet:

  • /status – geben Sie einfach ok zurück, um zu zeigen, dass wir am Leben sind. Sie können jedoch einige Prüfungen hinzufügen, beispielsweise die Verfügbarkeit des Kafka-Clusters.
  • /metrics – Gemäß dieser URL gibt der Prometheus-Client die von ihm gesammelten Metriken zurück.
  • /post ist der Hauptendpunkt, an den POST-Anfragen mit JSON gesendet werden. Unsere Anwendung prüft den JSON auf Gültigkeit und wenn alles in Ordnung ist, schreibt sie die Daten in den Kafka-Cluster.

Ich mache einen Vorbehalt, dass der Code nicht perfekt ist – er kann (und sollte!) vervollständigt werden. Sie können beispielsweise die Verwendung des integrierten net/http beenden und zum schnelleren fasthttp wechseln. Oder Sie können Verarbeitungszeit und CPU-Ressourcen gewinnen, indem Sie die JSON-Gültigkeitsprüfung auf eine spätere Stufe verschieben – wenn die Daten vom Puffer zum Clickhouse-Cluster übertragen werden.

Zusätzlich zur Entwicklungsseite des Problems haben wir sofort über unsere zukünftige Infrastruktur nachgedacht und beschlossen, unsere Anwendung über Docker bereitzustellen. Die endgültige Docker-Datei zum Erstellen der Anwendung ist https://github.com/RebrainMe/yandex-cloud-events/blob/master/app/Dockerfile. Im Allgemeinen ist es ganz einfach, der einzige Punkt, auf den ich achten möchte, ist die mehrstufige Montage, die es uns ermöglicht, das endgültige Bild unseres Containers zu reduzieren.

Erste Schritte in der Cloud

Registrieren Sie sich zunächst unter cloud.yandex.ru. Nachdem wir alle erforderlichen Felder ausgefüllt haben, wird uns ein Konto erstellt und ein Zuschuss über einen bestimmten Geldbetrag gewährt, der zum Testen von Cloud-Diensten verwendet werden kann. Wenn Sie alle Schritte aus unserem Artikel wiederholen möchten, sollte dieser Zuschuss für Sie ausreichen.

Nach der Registrierung wird für Sie eine separate Cloud und ein Standardverzeichnis erstellt, in dem Sie mit der Erstellung von Cloud-Ressourcen beginnen können. Im Allgemeinen sieht die Beziehung der Ressourcen in Yandex.Cloud so aus:

Wir akzeptieren 10 Ereignisse in Yandex.Cloud. Teil 000

Sie können mehrere Clouds für ein Konto erstellen. Und erstellen Sie innerhalb der Cloud unterschiedliche Verzeichnisse für unterschiedliche Unternehmensprojekte. Mehr dazu können Sie in der Dokumentation nachlesen - https://cloud.yandex.ru/docs/resource-manager/concepts/resources-hierarchy. Ich werde übrigens weiter unten im Text oft darauf verweisen. Als ich die gesamte Infrastruktur von Grund auf neu eingerichtet habe, hat mir die Dokumentation mehr als einmal geholfen, daher empfehle ich Ihnen, sie zu studieren.

Um die Cloud zu verwalten, können Sie sowohl die Weboberfläche als auch das Konsolendienstprogramm yc verwenden. Die Installation erfolgt mit einem Befehl (für Linux und Mac OS):

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

Wenn Ihr interner Sicherheitsspezialist darüber schimpft, Skripte aus dem Internet auszuführen, dann können Sie erstens das Skript öffnen und lesen, und zweitens führen wir es unter unserem Benutzer aus – ohne Root-Rechte.

Wenn Sie einen Client für Windows installieren möchten, können Sie die Anleitung verwenden hier und dann ausführen yc initum es vollständig anzupassen:

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:~ $

Im Prinzip ist der Vorgang einfach: Zuerst müssen Sie ein OAuth-Token zur Verwaltung der Cloud erhalten, die Cloud und den Ordner auswählen, den Sie verwenden möchten.

Wenn Sie mehrere Konten oder Ordner innerhalb derselben Cloud haben, können Sie über yc config profile create zusätzliche Profile mit separaten Einstellungen erstellen und zwischen diesen wechseln.

Zusätzlich zu den oben genannten Methoden hat das Yandex.Cloud-Team ein sehr gutes geschrieben Plugin für Terraform zur Verwaltung von Cloud-Ressourcen. Ich für meinen Teil habe ein Git-Repository vorbereitet, in dem ich alle Ressourcen beschrieben habe, die im Rahmen des Artikels erstellt werden - https://github.com/rebrainme/yandex-cloud-events/. Uns interessiert der Master-Zweig, klonen wir ihn lokal:


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/

Alle Hauptvariablen, die in Terraform verwendet werden, werden in die Datei main.tf geschrieben. Erstellen Sie zunächst eine private.auto.tfvars-Datei im Terraform-Ordner mit folgendem Inhalt:

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

Alle Variablen können der yc-config-Liste entnommen werden, da wir das Konsolen-Utility bereits konfiguriert haben. Ich rate Ihnen, private.auto.tfvars sofort zu .gitignore hinzuzufügen, um nicht versehentlich private Daten zu veröffentlichen.

In private.auto.tfvars haben wir auch Daten von Cloudflare angegeben – um DNS-Einträge zu erstellen und die Hauptdomäne events.kis.im an unsere Server weiterzuleiten. Wenn Sie Cloudflare nicht verwenden möchten, entfernen Sie die Initialisierung des Cloudflare-Anbieters in main.tf und der Datei dns.tf, die für die Erstellung der erforderlichen DNS-Einträge verantwortlich ist.

In unserer Arbeit werden wir alle drei Methoden kombinieren – das Webinterface, das Konsolen-Dienstprogramm und Terraform.

Virtuelle Netzwerke

Um ehrlich zu sein, können Sie diesen Schritt überspringen, da beim Erstellen einer neuen Cloud automatisch ein separates Netzwerk und drei Subnetze erstellt werden – eines für jede Verfügbarkeitszone. Wir möchten für unser Projekt aber trotzdem ein eigenes Netzwerk mit eigener Adressierung erstellen. Das allgemeine Diagramm, wie das Netzwerk in Yandex.Cloud funktioniert, ist in der Abbildung unten dargestellt (ehrlich genommen aus https://cloud.yandex.ru/docs/vpc/concepts/)

Wir akzeptieren 10 Ereignisse in Yandex.Cloud. Teil 000

Sie schaffen also ein gemeinsames Netzwerk, in dem Ressourcen miteinander kommunizieren können. Für jede Verfügbarkeitszone wird ein Subnetz mit eigener Adressierung erstellt und an das allgemeine Netzwerk angeschlossen. Dadurch können alle darin enthaltenen Cloud-Ressourcen kommunizieren, auch wenn sie sich in unterschiedlichen Verfügbarkeitszonen befinden. Ressourcen, die mit verschiedenen Cloud-Netzwerken verbunden sind, können sich gegenseitig nur über externe Adressen sehen. Übrigens, wie funktioniert diese Magie im Inneren? wurde auf Habré gut beschrieben.

Die Netzwerkerstellung wird in der Datei network.tf aus dem Repository beschrieben. Dort erstellen wir ein gemeinsames privates Netzwerk intern und verbinden drei Subnetze damit in verschiedenen Verfügbarkeitszonen – intern-a (172.16.1.0/24), intern-b (172.16.2.0/24), intern-c (172.16.3.0/24). ).

Terraform initialisieren und Netzwerke erstellen:

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.

Großartig! Wir haben unser Netzwerk aufgebaut und sind nun bereit, unsere internen Dienste zu erstellen.

Erstellen Sie virtuelle Maschinen

Um die Anwendung zu testen, müssen wir nur zwei virtuelle Maschinen erstellen – die erste benötigen wir zum Erstellen und Ausführen der Anwendung, die zweite zum Ausführen von Kafka, das wir zum Speichern eingehender Nachrichten verwenden. Und wir erstellen eine weitere Maschine, auf der wir Prometheus für die Überwachung der Anwendung konfigurieren.

Die virtuellen Maschinen werden mit Ansible konfiguriert. Stellen Sie daher vor dem Start von Terraform sicher, dass Sie über eine der neuesten Ansible-Versionen verfügen. Und installieren Sie die erforderlichen Rollen mit 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) $

Im Ansible-Ordner befindet sich eine Beispielkonfigurationsdatei .ansible.cfg, die ich verwende. Es könnte nützlich sein.

Stellen Sie vor dem Erstellen virtueller Maschinen sicher, dass der SSH-Agent ausgeführt und ein SSH-Schlüssel hinzugefügt wurde. Andernfalls kann Terraform keine Verbindung zu den erstellten Maschinen herstellen. Ich bin natürlich auf einen Fehler in OS X gestoßen: https://github.com/ansible/ansible/issues/32499#issuecomment-341578864. Um zu verhindern, dass dies erneut passiert, fügen Sie vor dem Start von Terraform eine kleine Variable zu env hinzu:

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

Im Ordner mit Terraform erstellen wir die notwendigen Ressourcen:

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

Wenn alles erfolgreich endete (und das sollte so sein), dann haben wir drei virtuelle Maschinen:

  1. build – eine Maschine zum Testen und Erstellen einer Anwendung. Docker wurde von Ansible automatisch installiert.
  2. Überwachung – eine Überwachungsmaschine – darauf installiert Prometheus & Grafana. Login/Passwort-Standard: admin/admin
  3. Kafka ist eine kleine Maschine, auf der Kafka installiert ist und die über Port 9092 zugänglich ist.

Stellen wir sicher, dass alle vorhanden sind:

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

Die Ressourcen sind vorhanden und von hier aus können wir ihre IP-Adressen abrufen. Im Folgenden werde ich IP-Adressen verwenden, um eine Verbindung über SSH herzustellen und die Anwendung zu testen. Wenn Sie über ein mit Terraform verbundenes Cloudflare-Konto verfügen, können Sie gerne frisch erstellte DNS-Namen verwenden.
Beim Erstellen einer virtuellen Maschine werden übrigens eine interne IP und ein interner DNS-Name vergeben, sodass Sie über den Namen auf Server innerhalb des Netzwerks zugreifen können:

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

Dies wird für uns nützlich sein, um der Anwendung den Endpunkt mit Kafk anzuzeigen.

Zusammenstellen der Anwendung

Großartig, es gibt Server, es gibt eine Anwendung – es bleibt nur noch, sie zusammenzustellen und zu veröffentlichen. Für den Build verwenden wir den üblichen Docker-Build, als Image-Speicher verwenden wir jedoch einen Dienst von Yandex – Container Registry. Aber das Wichtigste zuerst.

Wir kopieren die Anwendung auf die Build-Maschine, melden uns per SSH an und stellen das Image zusammen:

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

Die halbe Miete ist geschafft – jetzt können wir die Funktionalität unserer Anwendung überprüfen, indem wir sie starten und an kafka senden:

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) $

Die Anwendung antwortete mit einer erfolgreichen Aufzeichnung und gab die ID der Partition und den Offset an, in dem die Nachricht enthalten war. Jetzt müssen Sie nur noch eine Registrierung in Yandex.Cloud erstellen und unser Bild dort hochladen (wie das mit drei Zeilen geht, ist in der Datei „registry.tf“ beschrieben). Erstellen Sie einen Speicher:

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.

Es gibt mehrere Möglichkeiten, sich in der Container-Registrierung zu authentifizieren – mithilfe eines OAuth-Tokens, eines IAM-Tokens oder eines Dienstkontoschlüssels. Weitere Details zu diesen Methoden finden Sie in der Dokumentation. https://cloud.yandex.ru/docs/container-registry/operations/authentication. Wir werden den Dienstkontoschlüssel verwenden, also erstellen wir ein Konto:

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.

Jetzt müssen Sie nur noch einen Schlüssel dafür anfertigen:

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

Wir erhalten Informationen über die ID unseres Speichers, übertragen den Schlüssel und melden uns an:

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:~$

Um das Bild in die Registrierung hochzuladen, benötigen wir die Container-Registrierungs-ID. Diese entnehmen wir dem Dienstprogramm yc:

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

Danach markieren wir unser Bild mit einem neuen Namen und laden Folgendes hoch:

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

Wir können überprüfen, ob das Bild erfolgreich geladen wurde:

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

Wenn Sie das Dienstprogramm yc auf einem Linux-Rechner installieren, können Sie übrigens den Befehl verwenden

yc container registry configure-docker

um Docker zu konfigurieren.

Abschluss

Wir haben viel harte Arbeit geleistet und als Ergebnis:

  1. Wir haben die Architektur unseres zukünftigen Dienstes entwickelt.
  2. Wir haben eine Anwendung in Golang geschrieben, die unsere Geschäftslogik implementiert.
  3. Wir haben es gesammelt und in ein privates Containerregister gegossen.

Im nächsten Teil kommen wir zu den interessanten Dingen – wir geben unsere Anwendung in die Produktion frei und starten schließlich den Ladevorgang. Nicht wechseln!

Dieses Material ist in der Videoaufzeichnung des offenen Workshops REBRAIN & Yandex.Cloud enthalten: Wir akzeptieren 10 Anfragen pro Sekunde auf Yandex Cloud – https://youtu.be/cZLezUm0ekE

Wenn Sie daran interessiert sind, solche Veranstaltungen online zu besuchen und in Echtzeit Fragen zu stellen, kontaktieren Sie uns Kanal DevOps von REBRAIN.

Wir möchten uns ganz besonders bei Yandex.Cloud für die Möglichkeit bedanken, eine solche Veranstaltung auszurichten. Link zu ihnen - https://cloud.yandex.ru/prices

Wenn Sie in die Cloud wechseln müssen oder Fragen zu Ihrer Infrastruktur haben, Hinterlassen Sie gerne eine Anfrage.

PS: Wir bieten 2 kostenlose Audits pro Monat an, vielleicht gehört auch Ihr Projekt dazu.

Source: habr.com

Kommentar hinzufügen