Hola a tots! Com a part del meu treball del curs, estava investigant les possibilitats d'una plataforma de núvol domèstica com
Què vols rebre?
Després d'iniciar una màquina virtual amb un servidor web, podeu anar al seu amfitrió i obtenir una bella interfície d'usuari, especificar bases de dades com a fonts per a més treballs, crear taulers i gràfics.
La versió bàsica té un inconvenient important: no és gens tolerant a errors. És a dir, tot el rendiment de l'aplicació depèn de la viabilitat d'una màquina virtual. Si ella es nega o si 10 persones obren la IU alhora, sorgiran problemes.
Es solucionen simplement: només cal desplegar moltes màquines virtuals idèntiques amb un servidor web i col·locar-les sota un equilibrador L3. Però aquí no tot és tan clar. Grafana emmagatzema la configuració dels usuaris (camins a bases de dades, taulers de control, gràfics, etc.) directament al disc de la seva màquina virtual. Així, si canvieu alguns paràmetres a la interfície d'usuari, aquests canvis només es mostraran a la màquina virtual on ens va enviar l'equilibrador. Això comportarà una configuració inconsistent per a la nostra aplicació, problemes amb el llançament i l'ús.
Aquí una altra base de dades vindrà al rescat, per exemple, MySQL o el seu equivalent. Li diem a la Grafana que hauria d'emmagatzemar la configuració de l'usuari en aquesta base de dades "de recanvi". Després d'això, n'hi haurà prou amb especificar el camí d'accés a aquesta base de dades a cada màquina una vegada i editar la resta de paràmetres d'usuari a qualsevol de les màquines virtuals; creixeran a la resta.
Aquí teniu un diagrama de la infraestructura final de l'aplicació:
Aprèn a aixecar amb les mans
MySQL i ClickHouse
Abans de desplegar aquesta aplicació amb el clic d'un botó, calia aprendre a aixecar cadascun dels seus components amb nanses i integrar-los entre ells.
Yandex.Cloud ens ajudarà aquí, que ofereix equilibradors L3, ClickHouse i MySQL com a serveis gestionats. L'usuari només ha d'especificar els paràmetres i esperar fins que la plataforma ho faci tot en un estat de funcionament.
Em vaig registrar, vaig crear un núvol i un compte de facturació. Després d'això, vaig entrar al núvol i vaig plantejar clústers MySQL i ClickHouse amb una configuració mínima. Espereu fins que estiguin actius.
També heu de recordar crear una base de dades a cada clúster i configurar-hi l'accés mitjançant un inici de sessió i una contrasenya. No entraré en detalls aquí: tot és força evident a la interfície.
El detall no obvi era que aquestes bases de dades tenen molts hosts que proporcionen la seva tolerància a errors. Tanmateix, Grafana requereix exactament un amfitrió per a cada base de dades amb què treballa. Llarga lectura c-<cluster_id>.rw.mdb.yandexcloud.net
Mapes a l'amfitrió principal del clúster actiu actual amb l'ID corresponent. Això és el que li donarem a Grafana.
Servidor web
Ara depèn del servidor web. Aixequem una màquina virtual normal amb Linux i configurem-hi Grafana amb les nostres mans.
Connectem-nos mitjançant ssh i instal·lem els paquets necessaris.
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
Després d'això, iniciarem Grafana amb systemctl i instal·lar el connector per treballar amb ClickHouse (sí, no es subministra al paquet bàsic).
sudo systemctl start grafana-server
sudo systemctl enable grafana-server
sudo grafana-cli plugins install vertamedia-clickhouse-datasource
Tot després d'això amb una simple comanda
sudo service grafana-server start
iniciarem el servidor web. Ara serà possible conduir a l'adreça IP externa de la màquina virtual al navegador, especificar el port 3000 i veure la bella interfície d'usuari grafana.
Però no us precipiteu, abans de configurar Grafana, no us oblideu d'especificar el camí a MySQL perquè hi emmagatzemi la configuració.
Tota la configuració del servidor web de Grafana es troba al fitxer /etc/grafana/grafana.ini
. La línia requerida és així:
;url =
Exposem l'amfitrió al clúster MySQL. El mateix fitxer conté l'inici de sessió i la contrasenya per accedir a Grafana a la imatge de dalt, que són iguals per defecte admin
.
Podeu utilitzar les ordres sed:
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
És hora de reiniciar el servidor web!
sudo service grafana-server restart
Ara, a la interfície d'usuari de Grafana, especificarem ClickHouse com a font de dades.
Vaig aconseguir una configuració de treball amb la configuració següent:
He donat com a URL https://c-<cluster_id>.rw.mdb.yandexcloud.net:8443
Tot! Tenim una màquina virtual que funciona amb un servidor web connectat a CH i MySQL. Ja podeu carregar el conjunt de dades a ClickHouse i crear taulers de control. Tanmateix, encara no hem assolit el nostre objectiu i no hem desplegat una infraestructura completa.
Packer
Yandex.Cloud us permet crear una imatge de disc d'una màquina virtual existent i, a partir d'ella, podeu crear tantes màquines idèntiques com vulgueu. Això és exactament el que farem servir. Per muntar còmodament la imatge, agafeu l'eina
El nostre fitxer json constarà de dos blocs: builders i provisioners. El primer bloc descriu els paràmetres de la pròpia imatge com a entitat, i el segon descriu les instruccions per omplir-la amb el contingut necessari.
constructors
{
"builders": [
{
"type": "yandex",
"endpoint": "{{user `endpoint`}}",
"folder_id": "<folder_id>",
"subnet_id": "{{user `subnet_id`}}",
"zone": "{{user `zone`}}",
"labels": {},
"use_ipv4_nat": true,
"use_internal_ip": false,
"service_account_key_file": "<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"
}
],
...
}
En aquesta plantilla, cal establir l'identificador de la secció al núvol on es vol crear una imatge, així com el camí al fitxer amb les claus del compte de servei prèviament creat en aquesta secció. Podeu obtenir més informació sobre la creació de comptes de servei i claus en forma de fitxer a l'apartat corresponent.
Aquesta configuració diu que la imatge del disc es construirà en funció de la plataforma ubuntu-1804-lts
, situat a la secció d'usuari corresponent de la família d'imatges GRAFANA
sota el nom grafana-{{timestamp}}
.
Proveïdors
Ara per la part més interessant de la configuració. Descriurà la seqüència d'accions que caldrà realitzar en una màquina virtual abans de congelar el seu estat en una imatge de disc.
{
...,
"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"
]
}
]
}
Aquí, totes les accions es divideixen en 3 etapes. En la primera etapa, s'executa un script senzill que crea un directori auxiliar.
prepare-ctg.sh:
#!/bin/bash
sudo mkdir -p /opt/grafana
sudo chown -R ubuntu:ubuntu /opt/grafana
En la següent etapa, col·loquem un script en aquest directori, que s'haurà d'executar immediatament després d'iniciar la màquina virtual. Aquest script posarà les variables d'usuari que es configuraran a la configuració de Grafana i reiniciarà el servidor web.
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
Després d'això, hi ha 3 coses a fer:
1) instal·lar paquets
2) inicieu Grafana a systemctl i instal·leu el connector ClickHouse
3) poseu l'script setup.sh a la cua perquè s'executi immediatament després d'encendre la màquina virtual.
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;
Ara queda executar Packer i obtenir la imatge de sortida col·locada a la partició especificada. Quan creeu una màquina virtual, podeu seleccionar-la com a disc d'arrencada i, després de començar, obtenir un servidor web de Grafana preparat.
Grup d'instàncies i equilibrador
Un cop hi hagi una imatge de disc que us permeti crear molts servidors web de Grafana idèntics, podem crear un grup d'instàncies. A la plataforma Yandex.Cloud, aquest terme fa referència a la unió de màquines virtuals que tenen les mateixes característiques. Quan es crea un grup d'instàncies, es configura el prototip de totes les màquines d'aquest grup i després les característiques del propi grup (per exemple, el nombre mínim i màxim de màquines actives). Si el número actual no compleix aquest criteri, el propi grup d'instàncies eliminarà les màquines innecessàries o en crearà de noves a la imatge i semblança.
Com a part de la nostra tasca, crearem un grup d'instàncies de servidors web que es generaran a partir de la imatge de disc creada anteriorment.
La configuració del grup d'última instància és realment notable. El grup objectiu en integració amb Load Balancer us ajudarà a configurar un equilibrador L3 a la part superior de les màquines virtuals d'aquest grup prement un parell de botons.
Quan vaig configurar l'equilibrador, vaig implementar dos punts importants:
- Vaig fer que l'equilibrador acceptés el trànsit d'usuaris al port 80 i el redirigeixi al port 3000 de les màquines virtuals, just on viu Grafana.
- Configureu les comprovacions de l'estat de la màquina fent-les un ping al port 3000.
mini-total
Finalment, hem pogut desplegar manualment la infraestructura d'aplicacions desitjada i ara tenim un servei Grafana molt resistent. Només cal conèixer l'adreça IP de l'equilibrador com a punt d'entrada a l'aplicació i l'amfitrió del clúster ClickHouse per carregar-hi el conjunt de dades.
Semblaria una victòria? Sí, victòria. Però alguna cosa encara em molesta. Tot el procés anterior requereix moltes accions manuals i no escala gens, vull automatitzar-lo si és possible. Aquest serà el focus de la següent secció.
Integració amb Terraform
Tornarem a utilitzar una eina de HashiCorp anomenada
Tot el treball amb Terraform es redueix a escriure un fitxer de configuració (*.tf
) i la creació d'infraestructures a partir d'ella.
Variables
Al principi del fitxer, traurem les variables que determinen on i com es desplegarà la futura infraestructura.
variable "oauth_token" {
type = string
default = "<oauth-token>"
}
variable "cloud_id" {
type = string
default = "<cloud-id>"
}
variable "folder_id" {
type = string
default = "<folder_id>"
}
variable "service_account_id" {
type = string
default = "<service_account_id>"
}
variable "image_id" {
type = string
default = "<image_id>"
}
variable "username" {
type = string
default = "<username>"
}
variable "password" {
type = string
default = "<password>"
}
variable "dbname" {
type = string
default = "<dbname>"
}
variable "public_key_path" {
type = string
default = "<path to ssh public key>"
}
Tot el procés de desplegament d'una aplicació es reduirà a crear una imatge de disc i configurar aquestes variables. Permeteu-me explicar de què són responsables:
oauth_token — un testimoni per accedir al núvol. Es pot obtenir per
cloud_id - identificador del núvol on desplegarem l'aplicació
folder_id — identificador de la secció on desplegarem l'aplicació
service_account_id — identificador del compte de servei a la secció corresponent del núvol.
image_id - identificador de la imatge de disc obtinguda amb Packer
nom d'usuari и contrasenya - nom d'usuari i contrasenya per accedir a les dues bases de dades i al servidor web de Grafana
dbname - nom de la base de dades dins dels clústers CH i MySQL
ruta_de_clau_publica - la ruta al fitxer amb la vostra clau ssh pública, a través de la qual us podeu connectar sota el nom ubuntu
a màquines virtuals amb servidors web
Configuració del proveïdor
Ara heu de configurar el proveïdor de Terraform, en el nostre cas, Yandex:
provider "yandex" {
token = var.oauth_token
cloud_id = var.cloud_id
folder_id = var.folder_id
zone = "ru-central1-a"
}
Podeu veure que aquí estem utilitzant les variables definides anteriorment.
Xarxa i clústers
Ara creem una xarxa en la qual es comunicaran elements de la nostra infraestructura, tres subxarxes (una a cada regió) i aixecaran els clústers CH i MySQL.
resource "yandex_vpc_network" "grafana_network" {}
resource "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"]
}
resource "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"]
}
resource "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"]
}
resource "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
}
}
resource "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
}
}
Com podeu veure, cadascun dels dos clústers està dissenyat per ser bastant tolerant a errors, posant-se en tres zones de disponibilitat.
Servidors web
Sembla que pots continuar amb el mateix esperit, però em vaig trobar amb dificultats. Abans d'això, primer vaig plantejar el clúster MySQL i només després d'això, coneixent el seu ID, vaig recopilar una imatge de disc amb la configuració desitjada, on vaig especificar l'amfitrió del clúster. Però ara no sabem l'ID del clúster abans del llançament de Terraform, inclòs en el moment de la creació de la imatge. Així que vaig haver de recórrer al següent
Mitjançant el servei de metadades d'Amazon, passarem alguns paràmetres a la màquina virtual, que acceptarà i processarà. Necessitem que la màquina vagi a les metadades de l'amfitrió MySQL del clúster i del nom d'usuari-contrasenya que l'usuari va especificar al fitxer Terraform després d'iniciar-se. Canvieu lleugerament el contingut del fitxer setup.sh
, que s'executa quan la màquina virtual està engegada.
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
Grup d'instancias i equilibrador
Després d'haver reconstruït la nova imatge de disc, finalment podem afegir el nostre fitxer per a Terraform.
Indiquem que volem utilitzar una imatge de disc existent:
data "yandex_compute_image" "grafana_image" {
image_id = var.image_id
}
Ara creem un grup d'instàncies:
resource "yandex_compute_instance_group" "grafana_group" {
name = "grafana-group"
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"
}
}
Val la pena parar atenció a com hem passat a les metadades cluster_uri
, username
и password
. És la seva màquina virtual que l'obtindrà a l'inici i la posarà a la configuració de Grafana.
Es tracta de l'equilibrador.
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
}
}
}
}
Una mica de sucre
Quedava ben poc. Un cop desplegada la infraestructura, haureu d'anar a la interfície d'usuari de Grafana i afegir manualment el clúster CH (l'identificador del qual encara necessiteu) com a font de dades. Però Terraform coneix l'ID del clúster. Deixem que acabi la feina.
Afegim un proveïdor nou, Grafana, i introduïm l'IP de l'equilibrador com a amfitrió. Tots els canvis que Terraform faci a la màquina on determina el seu equilibrador creixeran a MySQL i, per tant, a la resta de màquines.
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"
}
Peninem
Mostra la IP de l'equilibrador i l'amfitrió del clúster ClickHouse
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"
}
Pot córrer
Tot! El nostre fitxer de configuració està llest i podem, mitjançant la configuració de variables, dir a Terraform que augmenti tot el que hem descrit anteriorment. Tot el procés em va durar uns 15 minuts.
Al final, podeu veure un missatge preciós:
Apply complete! Resources: 9 added, 0 changed, 0 destroyed.
Outputs:
clickhouse_cluster_host = https://c-c9q14ipa2ngadqsbp2iq.rw.mdb.yandexcloud.net:8443
grafana_balancer_ip_address = 130.193.50.25
I al núvol, es veuran elements de la infraestructura elevada:
Resumir
Ara, utilitzant l'exemple de Grafana, cadascun de vosaltres pot implementar aplicacions amb una arquitectura de núvol extensa a la plataforma Yandex.Cloud. Les eines útils de HashiCorp, com ara Packer i Terraform, us poden ajudar amb això. Espero que aquest article sigui útil a algú 🙂
PS A continuació us adjuntaré un enllaç al repositori, on podreu trobar receptes ja fetes per a Packer i Terraform, fragments de les quals he citat en aquest article.
Font: www.habr.com