
本文字数:8311;估计阅读时间:21分钟
作者:Jordan Simonovski

编者按: 本文译自 ClickHouse 原博客(链接点文末-查看原文)。 原文围绕「ClickHouse 观测性资源的基础设施即代码实践」展开。将 ClickStack 纳入 Terraform 管理体系,有效解决了多环境配置同步的痛点。这标志着 ClickHouse 在运维自动化与标准化方面迈出了重要一步。
概述
ClickHouse Terraform provider 现已支持管理自托管部署和 ClickHouse Cloud 中的 ClickStack 资源。仪表盘、告警、数据源、保存的搜索、连接和 Webhook 都可以保存在版本控制系统中,并通过常规的 terraform plan 和 terraform apply 工作流进行管理。
为某个服务创建的仪表盘很少只停留在单一环境中。它通常连同过滤条件、保存的搜索和告警一起,在预发和生产环境中被重建。一旦存在这些副本,要保持它们一致,就意味着必须在 UI 中重复修改,并人工检查每个环境。
ClickStack 的配置现在可以采用与其他基础设施相同的工作流。官方 ClickHouse Terraform provider 现已支持自托管部署和 ClickHouse Cloud 的 ClickStack 资源。仪表盘、告警、数据源、保存的搜索、连接和 Webhook 都可以存放在版本控制系统中,通过代码审查,并使用 `terraform plan` 和 `terraform apply` 进行应用。
自 v3.25 版本起,常规 provider 版本以 Beta 版形式提供了对自托管 ClickStack 和 Managed ClickStack 资源的支持。随着我们收集到更多生产环境的反馈,其行为和配置可能会发生变化。
ClickHouse Terraform provider
ClickHouse 维护了两个分工不同的官方 Terraform provider:
• ClickHouse/clickhouse 管理 ClickHouse Cloud 控制平面中的资源,包括服务、私有端点、ClickPipes、组织访问权限和 Managed Postgres。
• ClickHouse/clickhousedbops 连接至 ClickHouse 实例,用于管理数据库级别的用户、角色、授权和数据库。
ClickStack 的支持被归入 ClickHouse/clickhouse 中。在 ClickStack 用户的反馈中,无论是自托管还是 Cloud 部署,对 Terraform 的支持请求都是最常见的。我们最初将此支持作为独立项目开发,但后来意识到,发布一个新的 provider 会导致版本发布、测试、文档以及身份验证代码的重复工作。
因此,ClickStack provider 作为一个专属服务模块被添加至现有的 ClickHouse/clickhouse provider 中,使其资源和数据源与 ClickHouse Cloud 及 Postgres 的实现保持独立。用户只需像以往一样安装单一 provider,并遵循相同的版本更新路线。
这也保持了 ClickHouse Cloud 中认证方式的一致性。ClickStack 资源与该 provider 的其他部分使用相同的组织 ID 和 Cloud API 凭据,并通过 ClickStack 服务 ID 来标识目标部署。自托管的开源 ClickStack 则使用独立的端点和个人 API 访问密钥。后文将展示这两种配置。

基于 ClickStack API 构建
Terraform 资源需要行为可预测的 API 契约。在读取和更新操作中,资源标识符必须保持稳定。创建、更新、删除和导入等行为也必须明确。此外,错误信息还需要具备足够的结构化数据,以便在 plan 阶段就能向用户指出具体出错的字段。
今年早些时候开展的 ClickStack API 相关工作,通过现有的 ClickHouse Cloud 服务路径开放了可观测性资源:
/v1/organizations/{organizationId}/services/{serviceId}/clickstack/...
为了支持基础设施工具,API 定义也需要做出相应的修改。内联 Schema 被替换成了命名类型,数值字段被统一定义为整数,且验证失败时会提供结构化的错误详情。这些改动不仅让生成的客户端能够顺畅使用 OpenAPI 契约,也为 Terraform 提供了充足的信息来清晰地报告配置错误。
管理仪表盘提出了一项额外要求:仪表盘的定义以 JSON 格式提供,并且在应用前必须经过验证。在 terraform plan 阶段,只要验证端点可用,provider 就会将该定义发送给 ClickStack 验证 API。这样一来,无效配置就会在 terraform apply 实际执行变更前被拦截。

注意:如果验证端点不可用(例如使用的是早期版本的 ClickStack),provider 会发出警告,而不是阻塞 terraform plan 的执行。验证工作将推迟到 terraform apply 阶段进行。
有了这些改动,用户即可通过 ClickHouse Terraform provider 来管理开源版和托管版 ClickStack 部署中的 ClickStack 资源。
使用 ClickStack 资源
虽然以下示例使用 Provider 配置 ClickHouse Cloud 上的 Managed ClickStack,但同一个 clickhouse_clickstack_dashboard 资源也适用于开源的自托管 ClickStack。资源定义保持不变,但这两种部署在身份验证和团队作用域(team scoping)上有所不同。
你需要使用 Terraform 1.5 或更高版本、最低 3.25 版本的 ClickHouse Provider,以及一个现有的 Managed ClickStack 服务。下文的仪表板示例还假设你已配置好 OpenTelemetry 日志源和 ClickHouse 连接。
创建 ClickHouse Cloud API 密钥
Provider 会代表你调用 ClickHouse Cloud API。在 ClickHouse Cloud 控制台中,打开 Organization → API keys,选择 New API key,创建一个具有 Service Admin 或 Org Admin 权限的密钥。请妥善保存该密钥 ID 和 Secret。

你还需要两个非保密的标识符:
• ClickHouse Cloud 组织的组织 ID。
• 希望由 Terraform 管理的 Managed ClickStack 服务的服务 ID。
请从 Cloud 控制台复制这两个 ID。请确保该服务 ID 对应的是你开启 ClickStack 的服务,而不是同一组织下的其他 ClickHouse 服务。

> Cloud 与自托管凭据 - ClickHouse Cloud 使用组织 ID、Cloud API 密钥 ID、Cloud API Secret 以及 ClickStack 服务 ID。一个 Managed ClickStack 服务对应单个团队,因此不要为 Cloud 资源设置 team 属性。相反,自托管的 ClickStack 会使用 CLICKSTACK_ENDPOINT 和 CLICKSTACK_API_KEY。该密钥必须是在 ClickStack UI 中创建的个人 API 访问密钥。如果使用非默认团队,请将资源的 team 属性设置为团队 ID。切勿在同一个未设置别名(unaliased)的 Provider 块中同时配置 Cloud 和自托管凭据。
导出 Cloud 凭据
Provider 会从环境变量中读取凭据。这可以避免将凭据直接写入 Terraform 文件,也能防止在 `terraform.tfvars` 中意外提交密钥。
export CLICKHOUSE_ORG_ID="<organization-id>"
export CLICKSTACK_SERVICE_ID="<managed-clickstack-service-id>"
export CLICKHOUSE_CLOUD_API_KEY="<api-key-id>"
export CLICKHOUSE_CLOUD_API_SECRET="<api-key-secret>"
> 对于自托管部署,请将上述 Cloud 环境变量替换为:
export CLICKSTACK_ENDPOINT="https://clickstack.example.com"
export CLICKSTACK_API_KEY="<personal-api-access-key>"
在部署流水线中运行 Terraform 时,请使用 CI 系统的密钥存储。变量名可保持不变。
本例将加载仪表板对象,通过 ID 引用 ClickStack 的数据源与连接。你可以使用前文导出的凭据,调用 ClickStack API 获取可用值。
curl --silent \
--user "${CLICKHOUSE_CLOUD_API_KEY}:${CLICKHOUSE_CLOUD_API_SECRET}" \
"https://api.clickhouse.cloud/v1/organizations/${CLICKHOUSE_ORG_ID}/services/${CLICKSTACK_SERVICE_ID}/clickstack/sources" \
| jq -r '["SOURCE_ID","KIND","CONNECTION_ID","NAME"], (.result[] | [.id, .kind, .connection, .name]) | @tsv' \
| column -t -s $'\t'
复制需要供仪表板查询的日志数据源及对应连接的 ID,将其作为输入变量传给 Terraform:
export TF_VAR_logs_source_id="68d20d409bc8769c8984585f"
export TF_VAR_connection_id="68b6b6dd5d2cada7d1c593ac"
配置 provider
为本例创建一个空目录,然后将此 provider 配置添加到 [main.tf](http://main.tf):
terraform {
required_version = ">= 1.5.0"
required_providers {
clickhouse = {
source = "ClickHouse/clickhouse"
version = "~> 3.24.0"
}
}
}
provider "clickhouse" {}
variable "logs_source_id" {
type = string
}
variable "connection_id" {
type = string
}
> 这里的 provider 块为空,因为前文的四个环境变量已提供了相应的 Cloud 配置。仅在自托管部署中指定非默认团队时,才需要在仪表板资源中添加 team = var.team_id。
定义仪表板
将仪表板资源添加到 main.tf。本例创建了一个日志图表,用于统计各项服务随时间推移的事件数量:
variable "logs_source_id" {
description = "ID of the ClickStack logs source used by the dashboard"
type = string
}
resource "clickhouse_clickstack_dashboard" "simple_logs" {
dashboard_json = jsonencode({
name = "simple logs dashboard"
tiles = [
{
name = "Log count over time by service",
id = "9kcn995dbkdxjlw3jj28k"
x = 0
y = 0
w = 24
h = 11
config = {
name = "Logs over time"
sourceId = var.logs_source_id
displayType = "line"
granularity = "auto"
alignDateRangeToGranularity = true
select = [
{
aggFn = "count"
aggCondition = ""
aggConditionLanguage = "lucene"
valueExpression = ""
}
]
where = ""
whereLanguage = "lucene"
groupBy = "ServiceName"
}
}
]
filters = []
containers = []
})
}
output "dashboard_id" {
value = clickhouse_clickstack_dashboard.simple_logs.id
}
dashboard_json 的值对应 ClickStack v2 仪表板 API。将其包裹在 jsonencode 中,可以直接使用 Terraform 变量,无需手动拼接 JSON 字符串。
规划并应用更改
初始化目录,格式化并验证配置,然后检查执行计划:
terraform init
terraform fmt
terraform validate
terraform plan
ClickStack 资源目前处于 Beta 阶段。Terraform 在验证和规划期间会打印 Beta 警告,这是正常现象。请确认执行计划中包含一个待添加的 clickhouse_clickstack_dashboard 资源,然后应用该配置:
dalemcdiarmid@Mac clickstack_terraform % terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# clickhouse_clickstack_dashboard.simple_logs will be created
+ resource "clickhouse_clickstack_dashboard" "simple_logs" {
+ dashboard_json = jsonencode(
{
+ containers = []
+ filters = []
+ name = "simple logs dashboard"
+ tiles = [
+ {
+ config = {
+ alignDateRangeToGranularity = true
+ displayType = "line"
+ granularity = "auto"
+ groupBy = "ServiceName"
+ name = "Logs over time"
+ select = [
+ {
+ aggCondition = ""
+ aggConditionLanguage = "lucene"
+ aggFn = "count"
+ valueExpression = ""
},
]
+ sourceId = "68d20d409bc8769c8984585f"
+ where = ""
+ whereLanguage = "lucene"
}
+ h = 11
+ id = "9kcn995dbkdxjlw3jj28k"
+ name = "Log count over time by service"
+ w = 24
+ x = 0
+ y = 0
},
]
}
)
+ id = (known after apply)
+ normalized_json = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
dashboard_id = "6a7daffaecf5dee21ed130c6"
应用完成后,打开该服务的 ClickStack → Dashboards。新仪表板应该包含这两个图表块,Terraform 会将该仪表板 ID 打印为输出结果。

> 保持单一事实来源。 请选择只在 Terraform 还是只在 ClickStack UI 中管理仪表板。仪表板资源不会将 UI 的修改识别为配置漂移。这些修改会一直保留,直到 dashboard_json 发生变更;届时 Terraform 将替换整个仪表板定义,并会覆盖之前的修改。
修改仪表板名称、标签或图表块配置,然后再次运行 terraform plan,在应用前查看更新。如果是临时测试部署,请在完成后移除该仪表板:
terraform destroy
管理现有仪表板
可以通过 terraform import 将现有仪表板纳入 Terraform 管理。首先添加一个匹配的资源块,然后通过 ID 导入仪表板:
terraform import clickhouse_clickstack_dashboard.collectors <dashboard-id>
对于非默认团队的自托管仪表板,请使用 <team-id>/<dashboard-id> 作为导入 ID。完整的 schema 与导入行为详见 ClickStack dashboard resource 文档。
考虑到过去通常手动创建资源,我们也大幅简化了将现有 ClickHouse 资源导入 Terraform 配置的过程。只需在 ClickStack 中打开想要纳入 Terraform 管理的资源(如下方仪表板所示),点击 Terraform 图标,将生成的导入块复制到 .tf 文件中,并运行 terraform plan -generate-config-out=generated-dashboard.tf 命令即可。该工作流需要 Terraform 1.5 及以上版本。

你还可以批量导出所有现有资源并生成资源配置。

随后,你可以使用导出的文件将整个 ClickStack 部署纳入 Terraform 管理。例如:
cp ~/Downloads/hyperdx-import.tf .
terraform init
terraform plan -generate-config-out=generated-dashboard.tf
总结
现在,ClickStack 资源可以遵循与其余基础设施相同的评审与部署流程。团队能够跨环境复现可观测性配置,在应用更改前进行检查,并通过导入功能将现有资源纳入 Terraform 管理。
将这部分工作合并至 ClickHouse/clickhouse,也意味着为托管版 ClickStack 提供了单一 Provider、单一发布路径以及一致的认证方式。只要配置好对应的端点和个人 API 访问密钥,这些资源也完全适用于开源、自托管的 ClickStack。
该 Provider 的 3.25.0 版本已支持 ClickStack。你可以阅读 Provider 文档 了解详情(https://registry.terraform.io/providers/ClickHouse/clickhouse/latest/docs#clickstack-alpha),在现有仪表板上进行尝试,并通过 Provider 的 GitHub 仓库 反馈任何问题或异常情况(https://github.com/ClickHouse/terraform-provider-clickhouse)。
关于我们
ClickHouse(clickhouse.com) 是面向 AI 时代打造的高性能实时分析数据库,能够以极致性能处理海量数据分析任务。凭借高并发、低延迟和云原生架构,ClickHouse 广泛应用于可观测性、数据仓库、实时分析及 AI 数据基础设施等场景。我们致力于帮助企业在公有云平台上构建安全、弹性且高性价比的实时分析与 AI 数据平台,加速释放数据价值,推动智能化创新与数字化转型。目前,Trip.com、DiDi、Meta、Sony、Netflix、Deutsche Bank、Sierra、Cloudflare 等全球领先企业均在使用 ClickHouse 支撑其关键业务和数据分析平台。