大家好! 作為課程作業的一部分,我研究了這樣一個國內雲端平台的功能:
你想收到什麼?
啟動具有 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 的叢集目前活動的 Master 主機。 這就是我們將提供給 Grafana 的內容。
網絡服務器
現在由網頁伺服器決定。 讓我們使用 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
全部! 我們有一台正在運行的虛擬機,其 Web 伺服器連接到 CH 和 MySQL。 您已經可以將資料集上傳到 ClickHouse 並建立儀表板。 然而,我們還沒有實現我們的目標,也沒有部署成熟的基礎設施。
帕克
Yandex.Cloud 可讓您建立現有虛擬機器的磁碟映像,並在此基礎上建立任意數量的彼此相同的電腦。 這正是我們將要使用的。 為了方便地組裝圖像,請使用工具
我們的 json 檔案將包含兩個區塊:建構器和配置器。 第一個區塊描述了作為實體的影像本身的參數,第二個區塊描述了用於填充必要內容的指令。
建設者
{
"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
之後還有 3 件事要做:
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
運行-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;
現在剩下的就是運行 Packer 並獲取放置在指定部分的輸出影像。 建立虛擬機器時,您可以選擇它作為啟動磁碟,啟動後您將收到現成的 Grafana Web 伺服器。
實例組和平衡器
一旦我們有了一個允許我們創建許多相同的 Grafana Web 伺服器的磁碟映像,我們就可以建立一個實例組。 在 Yandex.Cloud 平台上,該術語指具有相同特徵的虛擬機器的聯合。 建立實例組時,會配置該組中所有機器的原型,然後配置該組本身的特徵(例如,最小和最大活躍機器數)。 如果目前數量不符合這些條件,則實例組本身將刪除不必要的機器或在自己的映像中建立新機器。
作為我們任務的一部分,我們將建立一個 Web 伺服器實例群組,該實例組將從先前建立的磁碟映像產生。
真正值得注意的是最後一個實例組設定。 與負載平衡器整合的目標群組將幫助您透過點擊幾個按鈕在此群組的虛擬機器之上配置 L3 平衡器。
在設定平衡器時,我實現了兩個要點:
- 我讓平衡器接受連接埠 80 上的使用者流量,並將其重新導向到虛擬機器的連接埠 3000,這正是 Grafana 所在的位置。
- 我透過 ping 連接埠 3000 來檢查機器的可行性。
迷你摘要
最後,我們能夠手動部署所需的應用程式基礎設施,現在我們擁有了高度彈性的 Grafana 服務。 您只需要知道平衡器的 IP 位址作為應用程式的入口點和 ClickHouse 叢集的主機,即可將資料集載入其中。
看起來像是一場勝利? 是的,勝利。 但有些事情仍然讓我困惑。 上面的整個過程需要很多手動步驟,而且根本不可擴展;如果可能的話,我希望將其自動化。 這就是下一節將專門討論的內容。
地形集成
我們將再次使用 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
}
}
正如您所看到的,兩個集群都位於三個可用區,因此具有很強的容錯能力。
網路伺服器
看起來我們可以以同樣的精神繼續下去,但我遇到了困難。 在此之前,我首先建立了一個 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)可以幫助您解決此問題。 我希望有人覺得這篇文章有用:)
PS 下面我將附上一個存儲庫的鏈接,您可以在其中找到 Packer 和 Terraform 的現成配方,我在本文中提供了其中的片段。
來源: www.habr.com