Blog
Bereitstellung von Grafana auf Azure App Service mit Terraform (und Active Directory Integration)

Intro
Grafana ist eine kostenlose und quelloffene Plattform, die es Ihnen ermöglicht, Ihre Metriken abzufragen, zu visualisieren, zu melden und zu verstehen.
Wenn Ihr System größer wird und mehr bewegliche Teile hat, wird es wichtig, auf einen Blick erkennen zu können, ob es gesund und betriebsbereit ist.
In Azure können Sie Ihr Grafana auf verschiedene Weise zum Laufen bringen:
Verwenden Sie Azure Managed Grafana
Dies ist ein vollständig verwalteter Service, der eine praktikable Option sein kann, wenn Sie keine Ressourcen für die Wartung Ihrer Überwachungslösung entbehren können. Sie können sicher sein, dass Ihre verwaltete Grafana-Instanz mit den neuesten Patches aktualisiert wird.
Der Nachteil dieses Ansatzes ist der Preis - zum Zeitpunkt der Erstellung dieses Artikels kostet es ~5,7 Euro pro Benutzer und Monat, was nicht allzu teuer ist, wenn Sie nicht viele Personen für den Zugriff auf das Dashboard benötigen. Eine weitere Einschränkung ist, dass Sie aufgrund von Sicherheitsbedenken keine benutzerdefinierten Plugins installieren können.
Grafana auf Azure App Service bereitstellen
Diese Option würde mehr Verantwortung auf die Techniker übertragen, da sie dafür verantwortlich wären, dass die Grafana-Instanz gepatcht ist und alle notwendigen Plugins installiert sind. Das Gute daran ist, dass Sie mehr Kontrolle über die Plattform haben und nicht pro Benutzer zahlen müssen.
Voraussetzungen
Um diese Ressourcen bereitstellen zu können, benötigen Sie:
- Terraform (v1.1.9 zum Zeitpunkt des Schreibens)
- Azure-Konto mit Eigentümerrechten für Ihr Abonnement
- Azure CLI
- sqlite
Provisionierung
Anbieter
Melden wir uns zunächst bei AzureCLI an
az login
Nachdem dies erfolgreich war, können wir Terraform initialisieren. Wir benötigen zwei Anbieter: azurerm und random.
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~>3.0"
}
azuread = {
source = "hashicorp/azuread"
version = "~> 2.15.0"
}
random = {
source = "hashicorp/random"
version = "3.1.0"
}
}
}
provider "azurerm" {
features {}
}
provider "random" {
}
provider "azuread" {
tenant_id = data.azurerm_client_config.current.tenant_id
}
Falls Sie ein Remote-Backend verwenden möchten (was Sie wahrscheinlich tun sollten), vergessen Sie nicht, es im terraform Block zu konfigurieren. Für diesen Beitrag lassen wir ihn weg.
Nachdem Ihre Provider konfiguriert sind, können wir das Arbeitsverzeichnis initialisieren.
terraform init
Bootstrap für die Infrastruktur
In unserem Beispiel werden wir eine PostgreSQL-Datenbank überwachen. Um die Einrichtung zu vereinfachen, werden alle Ressourcen in einer Ressourcengruppe bereitgestellt. Lassen Sie uns die Ressourcengruppe erstellen.
locals {
location = "westeurope"
resource_group_name = "grafana"
}
resource "azurerm_resource_group" "rg" {
name = local.resource_group_name
location = local.location
}
Lassen Sie uns auch den Keyvault erstellen, in dem wir unser Admin-Passwort speichern. Wir könnten auch die Terraform-Ausgabe verwenden, um das Passwort auszulesen. Der Weg über den Keyvault würde es Ihren Kollegen ermöglichen, auf die Anmeldedaten zuzugreifen, ohne mit Terraform arbeiten zu müssen.
locals {
...
kv_name = "grafanakv"
}
data "azurerm_client_config" "current" {}
resource "azurerm_key_vault" "kv" {
name = local.kv_name
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
tenant_id = data.azurerm_client_config.current.tenant_id
soft_delete_retention_days = 7
purge_protection_enabled = false
sku_name = "standard"
access_policy {
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
secret_permissions = [
"Get", "List", "Purge", "Set", "Delete", "Recover"
]
}
}
Wir geben unserem angemeldeten Benutzer auch Zugriff auf die Geheimnisse in diesem Keyvault. Wenn mehr Benutzer/Gruppen ihn benötigen, können Sie jederzeit weitere access_policy Blöcke hinzufügen.
Wenn der Keyvault eingerichtet ist, können wir den Datenbankserver erstellen
locals {
...
postgres_name = "grafana"
database_name = "data"
sql_admin_name = "sqladmin"
}
resource "random_password" "password" {
length = 16
special = true
}
resource "azurerm_key_vault_secret" "password" {
name = "db-password"
value = random_password.password.result
key_vault_id = azurerm_key_vault.kv.id
}
resource "azurerm_postgresql_server" "source" {
name = local.postgres_name
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
public_network_access_enabled = true
administrator_login = local.sql_admin_name
administrator_login_password = azurerm_key_vault_secret.password.value
backup_retention_days = 7
sku_name = "B_Gen5_1"
ssl_enforcement_enabled = false
ssl_minimal_tls_version_enforced = "TLSEnforcementDisabled"
storage_mb = 5120
version = "11"
}
Und die Datenbank selbst
resource "azurerm_postgresql_database" "db" {
name = local.database_name
resource_group_name = azurerm_resource_group.rg.name
charset = "UTF8"
collation = "English_United States.1252"
server_name = azurerm_postgresql_server.source.name
}
Bereitstellung von Grafana
Wenn die Ressourcen vorhanden sind, können wir die Überwachungsinfrastruktur einrichten. Als erstes müssen Sie den Log Analytics Workspace erstellen.
locals {
...
log_analytics_workspace_name = "log-analytics"
}
resource "azurerm_log_analytics_workspace" "logs" {
name = local.log_analytics_workspace_name
location = local.location
resource_group_name = local.resource_group_name
sku = "PerGB2018"
retention_in_days = 30
}
Als Nächstes erstellen wir den Dienstprinzipal, um eine Verbindung zu Azure AD herzustellen, generieren ein Passwort dafür und speichern es in unserem Keyvault
locals {
...
ad_app_display_name = "grafana"
microsoft_graph = {
app_id = "00000003-0000-0000-c000-000000000000" # Microsoft Graph
scopes = [
"37f7f235-527c-4136-accd-4a02d197296e", # openid
"64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0", # email
"14dad69e-099b-42c9-810b-d002981feec1", # profile
]
}
}
resource "azuread_application" "grafana" {
display_name = local.ad_app_display_name
web {
homepage_url = "https://${local.app_service_name}.azurewebsites.net"
redirect_uris = ["https://${local.app_service_name}.azurewebsites.net/login/generic_oauth"]
}
identifier_uris = ["api://${local.ad_app_display_name}"]
owners = [data.azuread_user.owner.id]
required_resource_access {
resource_app_id = local.microsoft_graph.app_id
dynamic "resource_access" {
for_each = local.microsoft_graph.scopes
content {
id = resource_access.value
type = "Scope"
}
}
}
}
resource "azuread_application_password" "grafana" {
application_object_id = azuread_application.grafana.object_id
}
resource "azurerm_key_vault_secret" "password" {
name = "grafana-app-password"
value = azuread_application_password.grafana.value
key_vault_id = data.azurerm_key_vault.kv.id
}
resource "azuread_service_principal" "grafana" {
application_id = azuread_application.grafana.application_id
owners = [data.azuread_user.owner.id]
}
Dieser Dienstleiter muss die Rolle Überwachungsleser in unserer Ressourcengruppe haben:
resource "azurerm_role_assignment" "grafana_monitoring_reader" {
scope = data.azurerm_resource_group.rg.id
role_definition_name = "Monitoring Reader"
principal_id = azuread_service_principal.grafana.id
}
web und required_resource_access werden benötigt, um sich mit Ihrem AzureAD-Benutzer bei Grafana anmelden zu können. Denken Sie daran, dass der Teil owner sehr wichtig ist, da Sie sonst nichts mit dem Service Principal anfangen können und im Grunde ausgesperrt sind.
Eine weitere Voraussetzung ist die Bereitstellung eines Speicherkontos mit einer Freigabe, in der Grafana seine Daten speichern kann.
locals {
...
storage_account_name = "grafanastorage"
grafana_share_name = "grafana-share"
}
resource "azurerm_storage_account" "storage" {
name = local.storage_account_name
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
account_tier = "Standard"
account_replication_type = "LRS"
account_kind = "StorageV2"
is_hns_enabled = true
}
resource "azurerm_storage_share" "grafana" {
name = local.grafana_share_name
storage_account_name = data.azurerm_storage_account.storage.name
quota = 50
}
Es gibt ein Problem mit Grafana, dass es möglicherweise nicht in der Lage ist, die Datenbank zu erstellen und zu initialisieren, und Sie erhalten die Fehlermeldung database is locked. Um dies zu vermeiden, können Sie eine leere Sqlite-Datenbank erstellen:
mkdir assets
sqlite3 assets/grafana.db 'PRAGMA journal_mode=wal;'
und laden Sie sie in die Freigabe hoch:
resource "azurerm_storage_share_file" "grafana_db" {
name = "grafana.db"
storage_share_id = azurerm_storage_share.grafana.id
source = "assets/grafana.db"
}
Wenn alle Voraussetzungen erfüllt sind, können wir unseren App Service, der Grafana hostet, bereitstellen.
locals {
...
app_service_plan_name = "grafana-asp"
app_service_name = "grafana"
}
resource "azurerm_service_plan" "grafana" {
name = local.app_service_plan_name
location = local.location
resource_group_name = local.resource_group_name
os_type = "Linux"
sku_name = "B1"
}
resource "azurerm_linux_web_app" "grafana" {
name = local.app_service_name
location = local.location
resource_group_name = local.resource_group_name
service_plan_id = azurerm_service_plan.grafana.id
site_config {
application_stack {
docker_image = "grafana/grafana"
docker_image_tag = "latest"
}
}
app_settings = {
"GF_SERVER_ROOT_URL" = "https://${local.app_service_name}.azurewebsites.net"
"GF_SECURITY_ADMIN_USER" = data.azuread_user.owner.user_principal_name
"GF_INSTALL_PLUGINS" = "grafana-clock-panel,grafana-simple-json-datasource"
"GF_AUTH_GENERIC_OAUTH_NAME" = "Azure AD"
"GF_AUTH_GENERIC_OAUTH_ENABLED" = "true"
"GF_AUTH_GENERIC_OAUTH_CLIENT_ID" = azuread_application.grafana.application_id
"GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET" = azuread_application_password.grafana.value
"GF_AUTH_GENERIC_OAUTH_SCOPES" = "openid email name"
"GF_AUTH_GENERIC_OAUTH_AUTH_URL" = "https://login.microsoftonline.com/${data.azurerm_client_config.current.tenant_id}/oauth2/authorize"
"GF_AUTH_GENERIC_OAUTH_TOKEN_URL" = "https://login.microsoftonline.com/${data.azurerm_client_config.current.tenant_id}/oauth2/token"
"GF_AUTH_GENERIC_OAUTH_API_URL" = ""
"GF_AUTH_GENERIC_OAUTH_TEAM_IDS" = ""
"GF_AUTH_GENERIC_OAUTH_ALLOWED_ORGANIZATIONS" = ""
}
storage_account {
access_key = data.azurerm_storage_account.datalake.primary_access_key
account_name = data.azurerm_storage_account.datalake.name
name = local.app_service_name
share_name = azurerm_storage_share.grafana.name
type = "AzureFiles"
mount_path = "/var/lib/grafana/"
}
logs {
http_logs {
file_system {
retention_in_mb = 35
retention_in_days = 5
}
}
}
depends_on = [
azurerm_storage_share_file.grafana_db
]
}
Bitte beachten Sie, dass unser aktuell angemeldeter Benutzer eine Admin-Rolle zugewiesen bekommt (siehe GF_SECURITY_ADMIN_USER Umgebungsvariable).
Verbinden von Grafana mit Azure Monitor
Nachdem die Konfiguration angewendet wurde, können Sie sich bei Ihrem App-Dienst anmelden und wenn alles korrekt ist, sehen Sie den Grafana-Willkommensbildschirm:

wo Sie auf "Mit Azure AD anmelden" klicken können.
Falls die Seite nicht geladen wird, können Sie die Protokolle im Log Stream überprüfen:

Nachdem Sie sich angemeldet haben, müssen Sie eine neue Datenquelle vom Typ Azure Monitor hinzufügen. Datenquellen können über die Seite Konfiguration hinzugefügt werden:

Suchen Sie nach Azure Monitor und fügen Sie es hinzu

Füllen Sie den Berechtigungsnachweis aus

Und Sie sollten sehen, dass Grafana eine Verbindung zum Azure Log Analytics Service herstellen konnte

Anzeigen von PostgreSQL-Metriken
Lassen Sie uns sehen, ob wir ein Dashboard mit unserer PostgreSQL-CPU-Auslastungsmetrik erstellen können.
Gehen Sie zu Neues Dashboard hinzufügen:

Und geben Sie alle Details zu Ihrer PostgreSQL-Datenbank an:

Wie Sie sehen, können wir mit Grafana Metriken zur CPU-Auslastung der Datenbank auslesen.
Fazit
Wir haben gezeigt, wie Sie Grafana mit Azure Monitor verwenden können, um Ihre Überwachungsmöglichkeiten zu verbessern. Wenn Sie Ihren Anwendungsdienst mit Azure AD verbinden, können Sie den Zugriff auf Grafana zentral und automatisch verwalten.
Verfasst von
Valerii Matveev
Unsere Ideen
Weitere Blogs
Contact



