Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Hallo zusammen! Im Rahmen meiner Studienarbeit habe ich die Möglichkeiten einer inländischen Cloud-Plattform untersucht, wie Yandex.Cloud. Die Plattform bietet verschiedene Dienste zur Lösung praktischer Aufgaben an. Manchmal ist es jedoch notwendig, auf Basis dieser Dienste eine eigene Cloud-Anwendung mit einer recht umfangreichen Infrastruktur einzurichten. In diesem Artikel möchte ich meine Erfahrungen bei der Bereitstellung einer solchen Anwendung teilen.

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Was möchte man erreichen?

Grafana — ein leistungsfähiges Tool zur Lösung analytischer Aufgaben oder zur Überwachung bestimmter Systeme. In seiner Grundkonfiguration handelt es sich um eine virtuelle Maschine mit einem Grafana-Webserver sowie einer Datenbank (ClickHouse, InfluxDB usw.) mit einem Datensatz, auf dessen Grundlage die Analytik aufgebaut wird.

Nach dem Start der virtuellen Maschine mit dem Webserver kann man auf dessen Host zugreifen und eine ansprechende Benutzeroberfläche erhalten, Datenbanken als Quellen für die weitere Arbeit angeben, Dashboards und Grafiken erstellen.

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Die Basisversion hat einen wesentlichen Nachteil — sie ist völlig nicht ausfallsicher. Das heißt, die Funktionsfähigkeit der Anwendung hängt von der Lebensfähigkeit einer einzigen virtuellen Maschine ab. Wenn diese ausfällt oder zehn Personen gleichzeitig die Benutzeroberfläche öffnen, treten Probleme auf.

Diese werden einfach gelöst: Man muss lediglich… viele identische virtuelle Maschinen mit einem Webserver bereitstellen und sie hinter einen L3-Load-Balancer stellen. Aber hier ist nicht alles so eindeutig. Grafana speichert die Benutzereinstellungen (Pfade zu Datenbanken, Dashboards, Grafiken usw.) direkt auf der Festplatte ihrer virtuellen Maschine. Wenn man also Änderungen in der Benutzeroberfläche vornimmt, werden diese Änderungen nur auf der virtuellen Maschine sichtbar, auf die der Load-Balancer uns geleitet hat. Dies führt zu inkonsistenten Einstellungen unserer Anwendung, was Probleme bei der Ausführung und Nutzung verursacht.

Hier kommt eine weitere Datenbank ins Spiel, zum Beispiel MySQL oder ein ähnliches System. Wir sagen Grafana, dass sie die Benutzereinstellungen genau in dieser "Backup"-Datenbank speichern soll. Danach muss man nur noch einmal auf jeder Maschine den Pfad zu dieser Datenbank angeben, alle anderen Benutzereinstellungen können auf einer der virtuellen Maschinen bearbeitet werden, sie werden auf die anderen übertragen.

Hier ist das Schema der endgültigen Infrastruktur der Anwendung:

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Lernen wir, es manuell zu starten

MySQL und ClickHouse

Bevor man eine solche Anwendung mit einem Klick bereitstellt, musste man lernen, jeden einzelnen Bestandteil manuell zu aktivieren und diese miteinander zu integrieren.

Hier kommt Yandex.Cloud ins Spiel, das L3-Balancer, ClickHouse und MySQL als Managed-Services anbietet. Der Benutzer muss lediglich die Parameter angeben und warten, bis die Plattform alles betriebsbereit macht.

Ich habe mich registriert, eine Cloud und ein Zahlungskonto erstellt. Danach habe ich mich in die Cloud eingeloggt und MySQL- und ClickHouse-Cluster mit minimalen Einstellungen hochgefahren. Ich habe gewartet, bis sie aktiv wurden.

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Außerdem darf man nicht vergessen, in jedem Cluster eine Datenbank zu erstellen und den Zugang über Benutzername und Passwort zu konfigurieren. Ich möchte hier nicht ins Detail gehen – in der Benutzeroberfläche ist alles ziemlich offensichtlich.

Ein weniger offensichtliches Detail war, dass diese Datenbanken viele Hosts haben, die ihre Ausfallsicherheit gewährleisten. Grafana benötigt jedoch genau einen Host für jede Datenbank, mit der sie arbeitet. Längeres Lesen Dokumentation Die Cloud führte mich zur Lösung. Es stellte sich heraus, dass ein Host des Typs c-<cluster_id>.rw.mdb.yandexcloud.net auf den aktuellen aktiven Master-Host des Clusters mit der entsprechenden ID abgebildet wird. Genau diesen werden wir Grafana bereitstellen.

Webserver

Jetzt sind wir beim Webserver angekommen. Wir werden eine normale virtuelle Maschine mit Linux hochfahren und Grafana zu Fuß darauf einrichten.

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Wir verbinden uns per SSH und installieren die benötigten Pakete.

sudo apt-get install -y apt-transport-https software-properties-common wget
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
sudo add-apt-repository "deb https://packages.grafana.com/enterprise/deb stable main"
sudo apt-get update
sudo apt-get install -y grafana-enterprise 

Nach dieser Installation starten wir Grafana mit systemctl und installieren das Plugin zur Arbeit mit ClickHouse (ja, es wird nicht in der Grundausstattung mitgeliefert).

sudo systemctl start grafana-server
sudo systemctl enable grafana-server
sudo grafana-cli plugins install vertamedia-clickhouse-datasource

Das ist alles, nach diesem einfachen Befehl

sudo service grafana-server start

starten wir den Webserver. Jetzt können wir die externe IP-Adresse der virtuellen Maschine in den Browser eingeben, den Port 3000 angeben und die schöne Grafana-Benutzeroberfläche sehen.
Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Aber wir sollten uns nicht beeilen; bevor wir Grafana konfigurieren, müssen wir nicht vergessen, den Pfad zu MySQL anzugeben, um dort die Einstellungen zu speichern.

Die gesamte Konfiguration des Webservers von Grafana befindet sich in der Datei /etc/grafana/grafana.ini. Die benötigte Zeile sieht so aus aus:

;url =

Wir stellen den Host für den MySQL-Cluster ein. In dieser Datei befinden sich auch der Benutzername und das Passwort für den Zugriff auf Grafana, die standardmäßig beide gleich sind. admin.

Sie können sed-Befehle verwenden:

sudo sed -i "s#.*;url =.*#url = mysql://{MYSQL_USERNAME}:{MYSQL_PASSWORD}@{MYSQL_CLUSTER_URI}#" /etc/grafana/grafana.ini
sudo sed -i "s#.*;admin_user =.*#admin_user = {GRAFANA_USERNAME}#" /etc/grafana/grafana.ini
sudo sed -i "s#.*;admin_password =.*#admin_password = {GRAFANA_PASSWORD}#" /etc/grafana/grafana.ini

Es ist Zeit, den Webserver neu zu starten!

sudo service grafana-server restart

Jetzt geben wir im UI von Grafana ClickHouse als Datenquelle an.

Ich habe eine funktionierende Konfiguration mit den folgenden Einstellungen erreicht:

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Als URL habe ich angegeben https://c-.rw.mdb.yandexcloud.net:8443

Das ist es! Wir haben eine funktionierende virtuelle Maschine mit einem Webserver, die mit CH und MySQL verbunden ist. Jetzt können Sie Datensätze in ClickHouse hochladen und Dashboards erstellen. Wir haben jedoch noch nicht unser Ziel erreicht und noch keine vollwertige Infrastruktur aufgebaut.

Packer

Yandex.Cloud ermöglicht es, ein Disk-Image einer bestehenden virtuellen Maschine zu erstellen, und darauf basierend beliebig viele identische Maschinen. Genau das werden wir tun. Um das Image bequem zu erstellen, verwenden wir das Tool Packer von HashiCorp. Es akzeptiert eine JSON-Datei mit Anweisungen zum Erstellen des Images.

Unsere JSON-Datei wird aus zwei Blöcken bestehen: builders und provisioners. Der erste Block beschreibt die Parameter des Images als Entität, der zweite die Anweisungen zur Befüllung mit dem benötigten Inhalt.

Builders

{
"builders": [
    {
      "type": "yandex",
      "endpoint": "{{user `endpoint`}}",
      "folder_id": "",
      "subnet_id": "{{user `subnet_id`}}",
      "zone": "{{user `zone`}}",
      "labels": {},
      "use_ipv4_nat": true,
      "use_internal_ip": false,
      "service_account_key_file": "",
      "image_name": "grafana-{{timestamp}}",
      "image_family": "grafana",
      "image_labels": {},
      "image_description": "GRAFANA",
      "source_image_family": "ubuntu-1804-lts",
      "disk_size_gb": 3,
      "disk_type": "network-hdd",
      "ssh_username": "ubuntu"
    }
  ],
...
}

In dieser Vorlage müssen Sie die Abschnitts-ID in der Cloud angeben, in der Sie das Image erstellen möchten, sowie den Pfad zur Datei mit den Schlüsseln des zuvor in diesem Abschnitt erstellten Dienstkontos. Weitere Informationen zur Erstellung von Dienstkonten und Schlüsseln in Form einer Datei finden Sie im entsprechenden Abschnitt. Dokumentation.

Diese Konfiguration besagt, dass das Disk-Image auf der Plattform ubuntu-1804-lts, im entsprechenden Abschnitt des Benutzers in der Bildfamilie GRAFANA unter dem Namen grafana-{{timestamp}}.

Provisioners

Jetzt kommt der interessantere Teil der Konfiguration. In diesem wird die Reihenfolge der Aktionen beschrieben, die auf der virtuellen Maschine ausgeführt werden müssen, bevor ihr Zustand in ein Disk-Image eingefroren wird.

{
...,
"provisioners": [
    {
            "type": "shell",
            "pause_before": "5s",
            "scripts": [
                "prepare-ctg.sh"
            ]
        },
    {
            "type": "file",
            "source": "setup.sh",
            "destination": "\/opt\/grafana\/setup.sh"
        },
        {
            "type": "shell",
        "execute_command": "sudo {{ .Vars }} bash '{{ .Path }}'",
            "pause_before": "5s",
            "scripts": [
                "install-packages.sh",
                "grafana-setup.sh",
                "run-setup-at-reboot.sh"
        ]
        }
  ]
}

Hier sind alle Aktionen in 3 Phasen unterteilt. In der ersten Phase wird ein einfaches Skript ausgeführt, das ein Hilfsverzeichnis erstellt.

prepare-ctg.sh:

#!/bin/bash
sudo mkdir -p /opt/grafana
sudo chown -R ubuntu:ubuntu /opt/grafana

In der nächsten Phase legen wir dieses Skript in das Verzeichnis, das unmittelbar nach dem Start der virtuellen Maschine ausgeführt werden muss. Dieses Skript wird die Benutzervariablen, die festgelegt werden müssen, in die Grafana-Konfiguration schreiben und den Webserver neu starten.

setup.sh:

#!/bin/bash
CLUSTER_ID="<cluster_id>"
USERNAME="<username>"
PASSWORD="<password>"
sudo sed -i "s#.*;url =.*#url = mysql://${USERNAME}:${PASSWORD}@c-${CLUSTER_ID}.rw.mdb.yandexcloud.net#" /etc/grafana/grafana.ini
sudo sed -i "s#.*;admin_user =.*#admin_user = ${USERNAME}#" /etc/grafana/grafana.ini
sudo sed -i "s#.*;admin_password =.*#admin_password = ${PASSWORD}#" /etc/grafana/grafana.ini
sudo service grafana-server restart

Nach diesem bleiben noch 3 Dinge zu tun:
1) Pakete installieren
2) Grafana unter systemctl starten und das ClickHouse-Plugin installieren
3) Das Skript setup.sh in die Warteschlange für den sofortigen Start nach dem Hochfahren der virtuellen Maschine legen.

install-packages.sh:

#!/bin/bash
sudo systemd-run --property='After=apt-daily.service apt-daily-upgrade.service' --wait /bin/true
sudo apt-get install -y apt-transport-https
sudo apt-get install -y software-properties-common wget
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
sudo add-apt-repository "deb https://packages.grafana.com/enterprise/deb stable main"
sudo apt-get update
sudo apt-get install -y grafana-enterprise 

grafana-setup.sh:

#!/bin/bash
sudo systemctl start grafana-server
sudo systemctl enable grafana-server
sudo grafana-cli plugins install vertamedia-clickhouse-datasource

run-setup-at-reboot.sh:

#!/bin/bash
chmod +x /opt/grafana/setup.sh
cat > /etc/cron.d/first-boot <<EOF
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
@reboot root /bin/bash /opt/grafana/setup.sh > /var/log/yc-setup.log 2>&1
EOF
chmod +x /etc/cron.d/first-boot;

Jetzt bleibt nur noch, Packer zu starten und das Image zu erstellen, das im angegebenen Verzeichnis gespeichert wird. Bei der Erstellung der virtuellen Maschine kann dieses als Boot-Disk ausgewählt werden und nach dem Start erhält man einen fertigen Grafana-Webserver.

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.
Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Instanzgruppe und Load Balancer

Nachdem das Disk-Image erstellt wurde, mit dem zahlreiche identische Grafana-Webserver erstellt werden können, können wir eine Instanzgruppe erstellen. Auf der Yandex.Cloud-Plattform bezeichnet dieser Begriff eine Gruppe von virtuellen Maschinen mit denselben Spezifikationen. Bei der Erstellung einer Instanzgruppe wird der Prototyp aller Maschinen in dieser Gruppe konfiguriert, gefolgt von den Spezifikationen der Gruppe selbst (z.B. die minimale und maximale Anzahl aktiver Maschinen). Wenn die aktuelle Anzahl nicht den Kriterien entspricht, wird die Instanzgruppe selbst nicht benötigte Maschinen entfernen oder neue nach dem vorhandenen Modell erstellen.

Im Rahmen unserer Aufgabe werden wir eine Instanzgruppe von Webservern erstellen, die aus dem zuvor erstellten Disk-Image generiert werden.

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Die letzte Konfiguration der Instanzgruppe ist wirklich bemerkenswert. Die Zielgruppe in der Integration mit dem Load Balancer ermöglicht es, mit nur wenigen Mausklicks den L3-Balancer über die virtuellen Maschinen dieser Gruppe einzurichten.

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Bei der Konfiguration des Balancers habe ich zwei wichtige Punkte umgesetzt:

  1. Ich habe den Balancer so eingerichtet, dass er den Benutzerdatenverkehr auf Port 80 empfängt und ihn auf Port 3000 der virtuellen Maschinen umleitet, wo Grafana lebt.
  2. Ich habe die Lebensfähigkeit der Maschinen überprüft, indem ich sie auf Port 3000 angepingt habe.

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Mini-Zusammenfassung

Endlich konnten wir die gewünschte Anwendungsinfrastruktur manuell bereitstellen, und jetzt haben wir einen hochverfügbaren Grafana-Service. Es ist nur notwendig, die IP-Adresse des Balancers als Einstiegspunkt zur Anwendung und den Host des ClickHouse-Clusters zu kennen, um den Datensatz hochzuladen.

Könnte man sagen, ein Sieg? Ja, ein Sieg. Aber irgendetwas stört doch. Der gesamte oben beschriebene Prozess erfordert eine große Menge an manuellen Eingriffen und ist überhaupt nicht skalierbar, ich möchte ihn nach Möglichkeit automatisieren. Dieser Thematik wird der nächste Abschnitt gewidmet sein.

Integration mit Terraform

Wir werden erneut das Tool von HashiCorp mit dem Namen Terraformnutzen. Es hilft, mit einem Klick die gesamte Anwendungsinfrastruktur bereitzustellen, basierend auf mehreren vom Benutzer übergebenen Variablen. Lassen Sie uns ein Rezept schreiben, das wiederholt in verschiedenen Abschnitten verschiedener Benutzer ausgeführt werden kann.

Die gesamte Arbeit mit Terraform besteht darin, eine Konfigurationsdatei (*.tf) zu erstellen und die Infrastruktur auf ihrer Grundlage aufzubauen.

Variablen

Zu Beginn der Datei werden wir die Variablen auslagern, von denen abhängt, wo und wie die zukünftige Infrastruktur bereitgestellt wird.

variable "oauth_token" {
    type = string
    default = ""
}
variable "cloud_id" {
    type = string
    default = ""
}
variable "folder_id" {
    type = string
    default = ""
}
variable "service_account_id" {
    type = string
    default = ""
}
variable "image_id" {
    type = string
    default = ""
}
variable "username" {
    type = string
    default = ""
}
variable "password" {
    type = string
    default = ""
}
variable "dbname" {
    type = string
    default = ""
}
variable "public_key_path" {
    type = string
    default = ""
}

Der gesamte Prozess der Anwendungsbereitstellung wird auf das Erstellen eines Disk-Images und das Setzen dieser Variablen reduziert. Ich erkläre, wofür sie verantwortlich sind:

oauth_token — Token für den Zugriff auf die Cloud. Kann erhalten werden über dem Link.
cloud_id — die Identifikationsnummer der Cloud, in der wir die Anwendung bereitstellen werden
folder_id — Abschnitts-ID, in dem wir die Anwendung bereitstellen werden
service_account_id — ID des Dienstkontos im entsprechenden Cloud-Bereich.
image_id — ID des mit Packer erstellten Disk-Images
username und passwort — Benutzername und Passwort für den Zugriff auf beide Datenbanken und den Grafana-Webserver
dbname — Name der Datenbank innerhalb der CH- und MySQL-Cluster
public_key_path — Pfad zur Datei mit Ihrem öffentlichen ssh-Schlüssel, über den Sie sich anmelden können ubuntu zu virtuellen Maschinen mit Webservern

Provider-Einstellungen

Jetzt müssen wir den Terraform-Provider einrichten – in unserem Fall Yandex:

provider "yandex" {
  token     = var.oauth_token
  cloud_id  = var.cloud_id
  folder_id = var.folder_id
  zone      = "ru-central1-a"
}

Es ist zu erkennen, dass wir hier die oben definierten Variablen verwenden.

Netzwerk und Cluster

Jetzt erstellen wir ein Netzwerk, in dem die Komponenten unserer Infrastruktur kommunizieren, drei Subnetze (jeweils eines in jeder Region) und heben die CH- und MySQL-Cluster an.


Ressource "yandex_vpc_network" "grafana_network" {}

Ressource "yandex_vpc_subnet" "subnet_a" {
  zone           = "ru-central1-a"
  network_id     = yandex_vpc_network.grafana_network.id
  v4_cidr_blocks = ["10.1.0.0/24"]
}

Ressource "yandex_vpc_subnet" "subnet_b" {
  zone           = "ru-central1-b"
  network_id     = yandex_vpc_network.grafana_network.id
  v4_cidr_blocks = ["10.2.0.0/24"]
}

Ressource "yandex_vpc_subnet" "subnet_c" {
  zone           = "ru-central1-c"
  network_id     = yandex_vpc_network.grafana_network.id
  v4_cidr_blocks = ["10.3.0.0/24"]
}

Ressource "yandex_mdb_clickhouse_cluster" "ch_cluster" {
  name        = "grafana-clickhouse"
  environment = "PRODUCTION"
  network_id  = yandex_vpc_network.grafana_network.id

  clickhouse {
    resources {
      resource_preset_id = "s2.micro"
      disk_type_id       = "network-ssd"
      disk_size          = 16
    }
  }

  zookeeper {
    resources {
      resource_preset_id = "s2.micro"
      disk_type_id       = "network-ssd"
      disk_size          = 10
    }
  }

  database {
    name = var.dbname
  }

  user {
    name     = var.username
    password = var.password
    permission {
      database_name = var.dbname
    }
  }

  host {
    type      = "CLICKHOUSE"
    zone      = "ru-central1-a"
    subnet_id = yandex_vpc_subnet.subnet_a.id
  }

  host {
    type      = "CLICKHOUSE"
    zone      = "ru-central1-b"
    subnet_id = yandex_vpc_subnet.subnet_b.id
  }

  host {
    type      = "CLICKHOUSE"
    zone      = "ru-central1-c"
    subnet_id = yandex_vpc_subnet.subnet_c.id
  }

  host {
    type      = "ZOOKEEPER"
    zone      = "ru-central1-a"
    subnet_id = yandex_vpc_subnet.subnet_a.id
  }

  host {
    type      = "ZOOKEEPER"
    zone      = "ru-central1-b"
    subnet_id = yandex_vpc_subnet.subnet_b.id
  }

  host {
    type      = "ZOOKEEPER"
    zone      = "ru-central1-c"
    subnet_id = yandex_vpc_subnet.subnet_c.id
  }
}

Ressource "yandex_mdb_mysql_cluster" "mysql_cluster" {
  name        = "grafana_mysql"
  environment = "PRODUCTION"
  network_id  = yandex_vpc_network.grafana_network.id
  version     = "8.0"

  resources {
    resource_preset_id = "s2.micro"
    disk_type_id       = "network-ssd"
    disk_size          = 16
  }

  database {
    name = var.dbname
  }

  user {
    name     = var.username
    password = var.password
    permission {
      database_name = var.dbname
      roles         = ["ALL"]
    }
  }

  host {
    zone      = "ru-central1-a"
    subnet_id = yandex_vpc_subnet.subnet_a.id
  }
  host {
    zone      = "ru-central1-b"
    subnet_id = yandex_vpc_subnet.subnet_b.id
  }
  host {
    zone      = "ru-central1-c"
    subnet_id = yandex_vpc_subnet.subnet_c.id
  }
}

Wie man sehen kann, sind beide Cluster aufgrund der Verteilung auf drei Verfügbarkeitszonen recht ausfallsicher gestaltet.

Web-Server

Es scheint, dass man in diesem Geist weitermachen könnte, aber ich bin auf ein Problem gestoßen. Zuvor habe ich zuerst den MySQL-Cluster gestartet und erst danach, in dem Wissen um seine ID, ein Abbild der Festplatte mit der gewünschten Konfiguration erstellt, wobei ich den Host des Clusters angegeben habe. Aber jetzt wissen wir die ID des Clusters bis zur Ausführung von Terraform nicht, auch nicht zum Zeitpunkt der Erstellung des Abbilds. Daher mussten wir auf den folgenden Trick zurückgreifen..

Mithilfe des Metadaten-Dienstes von Amazon übergeben wir der virtuellen Maschine einige Parameter, die sie annehmen und verarbeiten wird. Wir benötigen, dass die Maschine nach dem Start auf die Metadaten des MySQL-Cluster-Hosts sowie auf den Benutzernamen und das Passwort zugreift, die der Benutzer in der Terraform-Datei angegeben hat. Wir werden den Inhalt der Datei geringfügig ändern. setup.sh, die beim Einschalten der virtuellen Maschine gestartet wird.

setup.sh:

#!/bin/bash
CLUSTER_URI="$(curl -H 'Metadata-Flavor:Google' http://169.254.169.254/computeMetadata/v1/instance/attributes/mysql_cluster_uri)"
USERNAME="$(curl -H 'Metadata-Flavor:Google' http://169.254.169.254/computeMetadata/v1/instance/attributes/username)"
PASSWORD="$(curl -H 'Metadata-Flavor:Google' http://169.254.169.254/computeMetadata/v1/instance/attributes/password)"
sudo sed -i "s#.*;url =.*#url = mysql://${USERNAME}:${PASSWORD}@${CLUSTER_URI}#" /etc/grafana/grafana.ini
sudo sed -i "s#.*;admin_user =.*#admin_user = ${USERNAME}#" /etc/grafana/grafana.ini
sudo sed -i "s#.*;admin_password =.*#admin_password = ${PASSWORD}#" /etc/grafana/grafana.ini
sudo service grafana-server restart

Instance-Gruppe und Load-Balancer

Nachdem wir ein neues Disk-Image neu erstellt haben, können wir endlich unsere Datei für Terraform ergänzen.

Wir geben an, dass wir ein bestehendes Disk-Image verwenden möchten:

data "yandex_compute_image" "grafana_image" {
  image_id = var.image_id
}

Jetzt erstellen wir eine Instanz-Gruppe:

resource "yandex_compute_instance_group" "grafana_group" {
  name               = "grafana-gruppe"
  folder_id          = var.folder_id
  service_account_id = var.service_account_id
  instance_template {
    platform_id = "standard-v1"
    resources {
      memory = 1
      cores  = 1
    }
    boot_disk {
      mode = "READ_WRITE"
      initialize_params {
        image_id = data.yandex_compute_image.grafana_image.id
        size     = 4
      }
    }
    network_interface {
      network_id = yandex_vpc_network.grafana_network.id
      subnet_ids = [yandex_vpc_subnet.subnet_a.id, yandex_vpc_subnet.subnet_b.id, yandex_vpc_subnet.subnet_c.id]
      nat = "true"
    }
    metadata = {
      mysql_cluster_uri = "c-${yandex_mdb_mysql_cluster.mysql_cluster.id}.rw.mdb.yandexcloud.net:3306/${var.dbname}"
      username = var.username
      password = var.password
      ssh-keys = "ubuntu:${file("${var.public_key_path}")}"
    }
    network_settings {
      type = "STANDARD"
    }
  }

  scale_policy {
    fixed_scale {
      size = 6
    }
  }

  allocation_policy {
    zones = ["ru-central1-a", "ru-central1-b", "ru-central1-c"]
  }

  deploy_policy {
    max_unavailable = 2
    max_creating    = 2
    max_expansion   = 2
    max_deleting    = 2
  }

  load_balancer {
    target_group_name = "grafana-target-group"
  }
}

Es ist erwähnenswert, wie wir die Metadaten übergeben haben cluster_uri, username und passwort. Genau diese Informationen wird die virtuelle Maschine beim Start abrufen und in die Grafana-Konfiguration einfügen.

Es hängt nun vom Load-Balancer ab.

resource "yandex_lb_network_load_balancer" "grafana_balancer" {
  name = "grafana-balancer"

  listener {
    name = "grafana-listener"
    port = 80
    target_port = 3000
    external_address_spec {
      ip_version = "ipv4"
    }
  }

  attached_target_group {
    target_group_id = yandex_compute_instance_group.grafana_group.load_balancer.0.target_group_id

    healthcheck {
      name = "healthcheck"
      tcp_options {
        port = 3000
      }
    }
  }
}

Ein wenig Zucker

Es bleibt nur noch eine kleine Aufgabe. Nachdem die Infrastruktur eingerichtet ist, müssen wir in die Grafana-Benutzeroberfläche gehen und manuell den CH-Cluster (dessen ID wir noch ermitteln müssen) als Datenquelle hinzufügen. Terraform weiß jedoch die ID des Clusters. Wir werden ihm auftragen, den Job zu Ende zu bringen.

Wir fügen einen neuen Anbieter hinzu – Grafana, und für den Host geben wir die IP-Adresse des Load Balancers an. Alle Änderungen, die Terraform auf der Maschine vornimmt, die sein Load Balancer bestimmt, werden in MySQL übernommen und somit auch auf alle anderen Maschinen übertragen.

provider "grafana" {
  url  = "http://${[for s in yandex_lb_network_load_balancer.grafana_balancer.listener: s.external_address_spec.0.address].0}"
  auth = "${var.username}:${var.password}"
}

resource "grafana_data_source" "ch_data_source" {
  type          = "vertamedia-clickhouse-datasource"
  name          = "grafana"
  url           = "https://c-${yandex_mdb_clickhouse_cluster.ch_cluster.id}.rw.mdb.yandexcloud.net:8443"
  basic_auth_enabled = "true"
  basic_auth_username = var.username
  basic_auth_password = var.password
  is_default = "true"
  access_mode = "proxy"
}

Wir frisieren.

Wir geben die IP-Adresse des Load Balancers und den Host des ClickHouse Clusters aus.

output "grafana_balancer_ip_address" {
  value = [for s in yandex_lb_network_load_balancer.grafana_balancer.listener: s.external_address_spec.0.address].0
}

output "clickhouse_cluster_host" {
  value = "https://c-${yandex_mdb_clickhouse_cluster.ch_cluster.id}.rw.mdb.yandexcloud.net:8443"
}

Kann gestartet werden.

Fertig! Unsere Konfigurationsdatei ist bereit und wir können, nachdem wir die Variablen eingestellt haben, Terraform anweisen, alles zu starten, was wir oben beschrieben haben. Der gesamte Prozess hat bei mir etwa 15 Minuten gedauert.
Am Ende sieht man eine schöne Nachricht:

Apply complete! Ressourcen: 9 hinzugefügt, 0 geändert, 0 zerstört.
Ausgaben:

clickhouse_cluster_host = https://c-c9q14ipa2ngadqsbp2iq.rw.mdb.yandexcloud.net:8443
grafana_balancer_ip_address = 130.193.50.25

Im Cloud werden die Elemente der hochgefahrenen Infrastruktur sichtbar sein:

Bereitstellung verteilter Dienste in Yandex.Cloud am Beispiel von Grafana.

Lassen Sie uns die Ergebnisse zusammenfassen

Jetzt kann jeder von euch anhand von Grafana lernen, Anwendungen mit einer umfangreichen Cloud-Architektur auf der Plattform Yandex.Cloud zu implementieren. Dabei können euch nützliche Werkzeuge von HashiCorp, wie Packer und Terraform, unterstützen. Ich hoffe, dieser Artikel ist für jemanden von Nutzen 🙂.

P.S. Unten füge ich einen Link zum Repository bei, in dem man fertige Rezepte für Packer und Terraform finden kann, deren Auszüge ich in diesem Artikel verwendet habe.

Repository

Quelle: habr.com

60GB SSD 8Gb DDR4