大家好!作為課程作業的一部分,我正在研究這樣一個國內雲端平台的功能, 。該平台提供各種服務來解決實際問題。但是,有時需要基於這些服務建立自己的具有相當廣泛的基礎設施的雲端應用程式。在本文中,我想分享部署此類應用程式的經驗。

你想得到什麼?
— 解決任何系統的分析問題或監控問題的有力工具。在其基本配置中,這是一個帶有 Grafana Web 伺服器的虛擬機,以及一個帶有資料集的資料庫(ClickHouse、InfluxDB 等),將根據該資料集建立分析。
啟動具有 Web 伺服器的虛擬機器後,您可以轉到其主機並獲得良好的 UI,指定資料庫作為進一步工作的來源,建立儀表板和圖表。

基本版本有一個明顯的缺點——它根本不能容錯。也就是說,應用程式的整個功能取決於一台虛擬機器的可行性。如果失敗或10個人同時開啟UI,就會出現問題。
這些問題的解決很簡單:你只需要…在 Web 伺服器上部署許多相同的虛擬機,並將它們置於 L3 平衡器之下。但這裡並非所有事情都如此明確。 Grafana 將使用者設定(資料庫、儀表板、圖表等的路徑)直接儲存在其虛擬機器的磁碟上。因此,如果您在 UI 中更改任何設置,這些更改將僅顯示在平衡器發送給我們的虛擬機器上。這將導致我們的應用程式設定不一致,從而出現啟動和使用問題。
這時另一個資料庫將會發揮作用,例如 MySQL 或其等效資料庫。我們告訴 Grafana 它應該將用戶設定儲存在這個「備用」資料庫中。之後,只需在每台機器上指定一次該資料庫的路徑,並在任何虛擬機器上編輯所有其他使用者設定即可;它們會傳播給其他人。
以下是最終應用程式基礎架構的圖表:

讓我們學習用手舉起
MySQL 和 ClickHouse
在透過按下按鈕來部署這樣的應用程式之前,必須學習如何使用手把提起其每個組件並將它們相互整合。
在這裡我們將得到 Yandex.Cloud 的幫助,它提供 L3 平衡器、ClickHouse 和 MySQL 作為託管服務。使用者只需指定參數並等待平台使一切正常運作。
我註冊並創建了一個雲端帳戶和一個支付帳戶。之後,我進入雲端並以最少的設定設定了 MySQL 和 ClickHouse 叢集。等到他們變得活躍起來。


您還需要記住在每個叢集中建立一個資料庫,並使用登入名稱和密碼設定對它的存取。我不會在這裡詳細介紹——介面上的一切都非常明顯。
不太明顯的細節是,這些資料庫有多個主機,這確保了它們的容錯能力。但是,Grafana 要求與其配合使用的每個資料庫都只有一個主機。長讀 雲朵引導我找到了解決方案。事實證明,宿主屬於該物種 c-<cluster_id>.rw.mdb.yandexcloud.net 對應到具有對應 ID 的目前活動群集主主機。這正是我們將給予 Grafana 的。
網絡服務器
現在該搭建Web伺服器了。讓我們來設定一個普通的虛擬機器。 Linux 我們將親手在上面安裝 Grafana。


讓我們透過 ssh 連接並安裝必要的軟體包。
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
之後,我們將在 systemctl 下啟動 Grafana 並安裝一個用於與 ClickHouse 配合使用的插件(是的,它不包含在基本套件中)。
sudo systemctl start grafana-server
sudo systemctl enable grafana-server
sudo grafana-cli plugins install vertamedia-clickhouse-datasource就這樣,經過這個簡單的指令
sudo service grafana-server start我們將啟動一個網頁伺服器。現在您可以在瀏覽器中輸入虛擬機器的外部IP位址,指定連接埠3000並看到漂亮的Grafana UI。

但不要著急,在設定 Grafana 之前,您需要記住指定 MySQL 的路徑以將設定儲存在那裡。
Grafana Web 伺服器的完整設定位於檔案中 /etc/grafana/grafana.ini。您需要的行如下所示:
;url =我們將主機暴露給 MySQL 叢集。同一個檔案包含上圖中存取 Grafana 的登入名稱和密碼,預設情況下它們是相等的。 admin.
您可以使用 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
是時候重新啟動網頁伺服器了!
sudo service grafana-server restart現在在 Grafana UI 中我們將指定 ClickHouse 作為資料來源。
我能夠透過以下設定實現工作配置:

作為我指定的 URL https://c-<cluster_id>.rw.mdb.yandexcloud.net:8443
全部!我們有一個正在運行的虛擬機,其中有一個連接到 CH 和 MySQL 的 Web 伺服器。您已經可以將資料集上傳到 ClickHouse 並建立儀表板。然而,我們尚未實現我們的目標並部署成熟的基礎設施。
帕克
Yandex.Cloud 可讓您建立現有虛擬機器的磁碟映像,並在此基礎上建立任意數量的相同機器。這正是我們要利用的。為了方便地組裝圖像,我們來使用工具 來自 HashiCorp。它將包含組裝圖像說明的 json 檔案作為輸入。
我們的 json 檔案將由兩個區塊組成:builders 和 provisioners。第一個區塊描述影像本身作為實體的參數,第二個區塊描述用必要內容填充的指令。
建設者
{
"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"
}
],
...
}在此範本中,您需要設定您想要在雲端中建立影像的部分的標識符,以及包含先前在此部分中建立的服務帳戶的金鑰的檔案的路徑。您可以在相應部分中了解有關以文件形式建立服務帳戶和金鑰的更多信息 .
此配置表示磁碟映像將基於平台構建 ubuntu-1804-lts,放置在圖像系列中對應的用戶部分 GRAFANA 以...之名 grafana-{{timestamp}}.
供應商
現在來看看配置中更有趣的部分。它將描述在將虛擬機器狀態凍結為磁碟映像之前需要執行的一系列操作。
{
...,
"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"
]
}
]
}這裡所有動作分為3個階段。第一步是執行一個建立輔助目錄的簡單腳本。
準備-ctg.sh:
#!/bin/bash
sudo mkdir -p /opt/grafana
sudo chown -R ubuntu:ubuntu /opt/grafana在下一個階段,我們將在這個目錄中放置一個腳本,該腳本需要在啟動虛擬機器後立即執行。該腳本將把需要寫入Grafana配置的使用者變數放入,並重新啟動Web伺服器。
設定.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此後,還有三件事要做:
1)安裝軟體包
2)在 systemctl 下運行 Grafana 並安裝 ClickHouse 插件
3)開啟虛擬機器後立即將setup.sh腳本放入運行佇列中。
安裝軟體包.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運行設定重啟.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;現在剩下的就是運行 Packer 並將映像放置在指定的部分作為輸出。建立虛擬機器時,您可以選擇它作為啟動磁碟,啟動後,您將獲得現成的 Grafana Web 伺服器。


實例組和平衡器
一旦我們有了可以創建多個相同 Grafana Web 伺服器的磁碟映像,我們就可以建立一個實例組。在 Yandex.Cloud 平台上,該術語指的是具有相同特徵的虛擬機器的組合。建立實例組時,將配置組中所有機器的原型,然後配置組本身的特性(例如,活動機器的最小數量和最大數量)。如果目前數量不符合這些條件,實例組將刪除不必要的機器或建立具有相同影像和相似的新機器。
作為我們任務的一部分,我們將建立一個 Web 伺服器實例群組,該實例組將從先前建立的磁碟映像中產生。


最後一個實例組設定確實值得注意。與負載平衡器整合的目標群組將幫助您透過幾次點擊在該群組的虛擬機器之上配置 L3 平衡器。

在設定平衡器時,我實現了兩個要點:
- 我這樣做是為了讓平衡器在連接埠 80 上接收用戶流量並將其重定向到虛擬機器的連接埠 3000,也就是 Grafana 所在的連接埠。
- 透過在連接埠 3000 上 ping 來設定機器的健康檢查。

迷你摘要
最後,我們能夠手動部署所需的應用程式基礎設施,現在我們擁有高度穩定的 Grafana 服務。您只需要知道平衡器 IP 位址作為應用程式的入口點和 ClickHouse 叢集主機以將資料集載入到其中。
這看起來像是一場勝利?是的,勝利。但有些事還是困擾著我。上述整個過程需要大量的手動操作並且根本不可擴展,如果可能的話,我想實現自動化。下一節將專門討論這一點。
Terraform 集成
我們將再次使用 HashiCorp 的一款工具,名為 。它將幫助您根據用戶傳遞的幾個變量,只需單擊按鈕即可部署整個應用程式基礎架構。讓我們編寫一個可以在不同部分針對不同使用者運行多次的配方。
Terraform 的所有工作都歸結為編寫設定檔(*.tf) 以及以此為基礎的基礎設施的創建。
變量
在文件的最開始,我們將放置變量,這些變量取決於未來基礎設施將在何處以及如何部署。
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>"
}部署應用程式的整個過程將簡化為組裝磁碟映像和設定這些變數。讓我解釋一下他們的職責:
oauth_token — 用於存取雲端的令牌。您可以透過以下方式取得 .
雲端ID — 我們將部署應用程式的雲端的標識符
資料夾 ID — 我們將部署應用程式的部分的標識符
服務帳戶 ID — 雲端中對應部分的服務帳戶識別碼。
圖片編號 — 使用 Packer 取得磁碟映像的標識符
用戶名 и 密碼 — 用於存取資料庫和 Grafana Web 伺服器的使用者名稱和密碼
數據庫名 — CH 和 MySQL 叢集中的資料庫名稱
公鑰路徑 — 包含您的公用 ssh 金鑰的檔案的路徑,您可以使用該檔案以名稱連接 ubuntu 帶有 Web 伺服器的虛擬機
設定您的提供者
現在您需要配置 Terraform 提供者 - 在我們的例子中是 Yandex:
provider "yandex" {
token = var.oauth_token
cloud_id = var.cloud_id
folder_id = var.folder_id
zone = "ru-central1-a"
}
您可以看到我們在這裡使用上面定義的變數。
網路和叢集
現在我們將創建一個網絡,我們的基礎設施元素可以在其中進行通信,三個子網(每個區域一個)並建立 CH 和 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
}
}如您所見,透過放置在三個可用區域,兩個集群中的每一個都具有相當的容錯能力。
Web 伺服器
看起來我可以繼續保持同樣的精神,但我遇到了困難。在此之前,我首先設定了一個 MySQL 集群,然後,在知道了它的 ID 之後,我組裝了一個具有所需配置的磁碟映像,並在其中指定了集群的主機。但現在我們在 Terraform 啟動之前(包括在鏡像組裝時)不知道群集 ID。因此,我們不得不採取以下措施 .
使用亞馬遜的元資料服務,我們將向虛擬機器傳遞一些參數,虛擬機器將接受並處理這些參數。我們需要機器啟動後去取得MySQL叢集主機的元資料和使用者在Terraform檔案中指定的使用者名稱密碼。讓我們稍微改變一下文件的內容 setup.sh,它在虛擬機啟動時啟動。
設定.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入口組和平衡器
重建新的磁碟映像後,我們終於可以完成為 Terraform 編寫檔案了。
讓我們指定要使用現有的磁碟映像:
data "yandex_compute_image" "grafana_image" {
image_id = var.image_id
}現在讓我們建立一個實例組:
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"
}
}值得注意的是我們如何轉移到元數據 cluster_uri, username и password。虛擬機器在啟動時將提取這些內容並將其放入 Grafana 配置中。
這取決於平衡器。
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
}
}
}
}少許糖
只剩下一點點了。部署基礎架構後,您必須前往 Grafana UI 並手動新增 CH 叢集(仍需要取得其 ID)作為資料來源。但是 Terraform 知道集群 ID。我們委託他完成這項工作。
讓我們新增一個新的提供者 - Grafana,並將平衡器的 IP 位址作為主機提供給它。 Terraform 在平衡器分配的機器上所做的所有更改都將擴展到 MySQL,從而擴展到所有其他機器。
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"
}讓我們梳理一下
我們將輸出平衡器的 IP 位址和 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"
}您可以啟動它
全部!我們的設定檔已經準備好了,我們可以設定變數來告訴 Terraform 實作我們上面描述的所有內容。整個過程花了我大約15分鐘。
最後你會看到一條美麗的訊息:
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在雲端,凸起的基礎設施元素將清晰可見:

綜合
現在,以Grafana為例,你們每個人都可以在Yandex.Cloud平台上部署具有龐大雲端架構的應用程式。 HashiCorp 提供的 Packer 和 Terraform 等有用工具可以幫助您實現這一點。我希望這篇文章對某些人有用 🙂
附註:下面我將附上一個存儲庫的鏈接,您可以在其中找到 Packer 和 Terraform 的現成配方,我在本文中提供了其中的片段。
來源: www.habr.com
