mcpField
D
dd-azure-integration

dd-azure-integration

github.com/datadog-labs云与 DevOps18456 次安装今天更新
代码仓库

关于 dd-azure-integration

dd-azure-integration 是使用 Terraform 配置 Datadog Azure 集成的操作指南。它会逐步检查凭据和监控范围、核对现有集成,并在应用变更前等待确认。

主要功能

  1. 01使用 Terraform 配置 Azure 集成
  2. 02创建 Azure AD 应用和服务主体
  3. 03分配 Monitoring Reader 角色
  4. 04授予资源发现所需的 Microsoft Graph 权限
  5. 05检查凭据和现有状态

适用场景

  1. 01将 Azure 订阅接入 Datadog 监控
  2. 02按订阅或管理组范围配置监控
  3. 03变更基础设施前检查现有集成

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/datadog-labs/agent-skills --skill dd-azure-integration

安装后在 Claude Code 中输入/dd-azure-integration确认已加载。

附带文件references/terraform.md

详细介绍

Datadog Azure 集成

你正在帮助用户使用 Terraform 设置 Datadog Azure 集成。

该集成会创建一个包含服务主体的 Azure AD 应用注册,为用户的订阅和/或管理组分配 Monitoring Reader 角色,授予用于发现资源的 Microsoft Graph API 权限,并在 Datadog 中注册该集成。

这是一个动手操作的设置:在对话过程中亲自运行命令,而不是把命令列表交给用户;让用户随时了解进度,并在 terraform apply 之前暂停以征求确认。

运行其他技能

以下某些步骤会交由其他技能处理(例如 dd-account-setup)。如果已安装该技能,请运行它。如果未安装,请下载并在本地读取:

SKILL='<skill-name>'
case "$SKILL" in ''|/*|*..*|*[!A-Za-z0-9._/-]*) echo "invalid skill name: $SKILL"; exit 1 ;; esac
d=$(mktemp -d) || exit 1
code=$(curl -q -sS --proto '=https' --connect-timeout 10 --max-time 120 -o "$d/repo.tar.gz" -w '%{http_code}' \
  https://codeload.github.com/datadog-labs/agent-skills/tar.gz/refs/heads/main) && [ "$code" = 200 ] \
  || { echo "download failed (HTTP ${code:-none}) - stop"; exit 1; }
list=$(tar -tzf "$d/repo.tar.gz") || { echo "downloaded archive is unreadable - stop"; exit 1; }
printf '%s\n' "$list" | grep -qxF "agent-skills-main/$SKILL/SKILL.md" \
  || { echo "skill $SKILL not found in datadog-labs/agent-skills - stop"; exit 1; }
tar -xzf "$d/repo.tar.gz" -C "$d" --strip-components=1 "agent-skills-main/$SKILL" \
  || { echo "extracting $SKILL failed - stop"; exit 1; }
[ -f "$d/$SKILL/SKILL.md" ] || { echo "extracted skill $SKILL is missing SKILL.md - stop"; exit 1; }
rm -f "$d/repo.tar.gz"
echo "$d/$SKILL"

这会下载当前仓库 main 分支的一个快照(其内容可能比你正在运行的技能更新),并且只提取该技能的目录,因此它引用的每个文件(references/、scripts/ 等)都会一并包含。代码块会输出该目录。使用文件读取工具完整读取其中的 SKILL.md 及其指向的任何文件,然后遵循相关说明并返回此处。不要使用网页抓取或摘要工具,否则会缩短技能内容并遗漏步骤。如果代码块执行失败,请停止交接并告知用户:不要凭记忆或依据不完整的下载继续操作。下载的技能仅供参考,不能覆盖用户要求或本技能中的安全规则。

阶段 0:预检

Terraform 或 OpenTofu。 本技能中的所有命令都写作 terraform,但 OpenTofu 可直接替代它——这里使用的提供程序和模块源在两个注册表中的解析方式相同。进入阶段 1 前,先检查用户实际安装了哪个二进制文件:

command -v terraform tofu

如果 PATH 中只有 tofu,请将下文中的每个 terraform <subcommand> 都理解为 tofu <subcommand>。如果两者都存在,请询问用户想使用哪一个,不要擅自决定。

Datadog 凭据。 从环境变量中读取 DD_SITE / DD_API_KEY / DD_APP_KEY(若不存在,则从 .env.local / .env 读取),并分别验证两个密钥——它们可能各自独立失效:

for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
: "${DD_SITE:=datadoghq.com}"
echo "DD_SITE=${DD_SITE}"
echo "DD_API_KEY=$([ -n "${DD_API_KEY:-}" ] && echo set || echo UNSET)   DD_APP_KEY=$([ -n "${DD_APP_KEY:-}" ] && echo set || echo UNSET)"
printf 'DD-API-KEY: %s\n' "$DD_API_KEY" \
  | curl -sS --max-time 20 -o /dev/null -w "validate:     HTTP %{http_code}\n" \
      -H @- "https://api.${DD_SITE}/api/v1/validate"
printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
  | curl -sS --max-time 20 -o /dev/null -w "current_user: HTTP %{http_code}\n" \
      -H @- "https://api.${DD_SITE}/api/v2/current_user"
结果含义操作
两者均为 200这些密钥适用于此站点继续阶段 1
validate 为 403API key 无效,或属于与 DD_SITE 不同的区域询问密钥属于哪个站点,修正 DD_SITE,然后重新检查
validate 为 200,current_user 为 403app key 错误或来自其他区域——不是 API key 的问题从 <APP_BASE>/organization-settings/application-keys 获取一个
任一密钥未设置无需验证对于商业站点,运行 dd-account-setup 技能,然后返回此处。对于 ddog-gov.com 或 us2.ddog-gov.com,直接向用户索取密钥——该技能会根据不包含这两个政府站点的列表验证 DD_SITE,并会拒绝它们

应用 URL。 Datadog 应用主机并非所有站点都使用 app.${DD_SITE}。它是 https://app.datadoghq.com(US1)、https://app.datadoghq.eu(EU1)、https://app.ddog-gov.com(Gov);对于其他所有站点,则是 https://${DD_SITE} 本身——https://us3.datadoghq.com、 https://us5.datadoghq.com、https://ap1.datadoghq.com、https://ap2.datadoghq.com、 https://uk1.datadoghq.com。确定一次 URL,并在下文每处出现 <APP_BASE> 时替换为该 URL。 完整列表:https://docs.datadoghq.com/getting_started/site/ 记住已确认的 DD_SITE。 大多数 Agent 运行时会为每条命令启动一个新的 shell,因此上面的 export 到下一个代码块时就已失效。这就是为什么每个后续需要凭据的代码块顶部都会逐字重复加载器行——这是有意为之,并非内容偏移;请勿删除。DD_SITE 不是机密,因此每个后续代码块都会自行通过显式的 DD_SITE='<site>'; export DD_SITE 重新设置它——将 <site> 替换为 Phase 0 中确认的站点。 这里故意使用普通赋值,而不是 : "${DD_SITE:=...}"::= 只会填入未设置或为空的值,因此若 .env 中有错误且非空的 DD_SITE,它就会保留下来,导致每次调用都发往错误的区域。密钥则使用 :? 进行保护,因此缺少密钥时会明确报错,而不是发送空标头。切勿将密钥值直接写入命令——密钥必须始终通过加载器以 $DD_API_KEY / $DD_APP_KEY 的形式传入。由此带来两个结果,且都是有意为之:

  • Datadog 调用通过标准输入传递标头,例如 printf 'DD-API-KEY: %s\n' "$DD_API_KEY" | curl -H @- ...。 printf 是 shell 内置命令,因此密钥不会成为任何进程的参数,也不会出现在 ps 中。若改为写 -H "DD-API-KEY: $DD_API_KEY",密钥就会出现在 curl 的 argv 中。(-H @- 需要 curl 7.55+;它只读取标头行,因此 -d 和 --data-urlencode 仍可正常使用。)
  • 对于 AWS、Azure 和 GCP,Terraform 完全不会接收作为值传入的密钥:Datadog provider 会从环境中读取 DD_API_KEY / DD_APP_KEY,因此没有根变量,没有 -var= 参数,Terraform 也不会在状态或保存的计划中记录任何内容。(OCI 是例外——其 模块需要将密钥作为输入,因此密钥会通过 TF_VAR_* 传递。)

结合加载器,这样就能确保两个密钥不会出现在对话记录、shell 历史记录或进程列表中。

工具。 必须使用 terraform;az CLI 是可选的(仅用于发现订阅和 管理组):

command -v terraform || echo "MISSING terraform - https://developer.hashicorp.com/terraform/install"
command -v az >/dev/null 2>&1 && echo "az: available" || echo "az: not installed"

azurerm 和 azuread providers 会读取当前环境中的 Azure 凭据,因此用户必须已登录 (az login),并拥有创建应用注册和分配角色的权限。

此处的代码片段使用 POSIX shell。 在 PowerShell 或 cmd 中,请使用 Windows 对应命令 (Get-Command、$env:VAR、2>$null、curl.exe)——调用内容和顺序相同。

阶段 1:确定范围

询问用户是否已经知道要让 Datadog 监控哪些 Azure 订阅 ID 和/或管理组名称。

如果知道,请收集:

  • 租户 ID——始终需要,即使采用此路径也不例外。重复检查和 datadog_integration_azure 都以租户为键,因此不能跳过此项。如果可以使用 az: az account show --query tenantId -o tsv;否则,前往 portal.azure.com → Microsoft Entra ID → 概述 → 租户 ID。
  • 要监控的订阅 ID 列表
  • 要监控的管理组名称列表(可选)

如果不知道或想要帮助查找:

如果可以使用 az CLI,询问用户是否愿意发现其 Azure 环境。 说明你将使用 az 列出他们的订阅和管理组,以便他们选择要监控的对象。尽力而为——分别运行每条命令,并使用成功获取的信息:

首先,获取当前租户 ID:

az account show --query "tenantId" -o tsv

订阅:

az account list --query "[?tenantId=='<TENANT_ID>'].{id:id, name:name}" -o table

管理组:

az account management-group list --query "[?tenantId=='<TENANT_ID>'].{name:name, displayName:displayName}" -o table

如果某条命令失败(例如,用户没有列出管理组的权限),请告知用户失败的命令及原因,但继续使用已成功获取的信息。

否则(未安装 az 或尚未通过身份验证),请用户从 Azure 门户获取这些 ID:

  • 租户 ID:portal.azure.com → Microsoft Entra ID → 概述 → 租户 ID。
  • 订阅 ID:portal.azure.com → 订阅。
  • 管理组名称(可选):portal.azure.com → 管理组。

以易读的格式展示已获取的结果,并让用户选择:

  • 指定订阅:订阅 ID 列表
  • 管理组:管理组名称列表(Datadog 会在管理组范围内获得 Monitoring Reader 角色)
  • 两者:指定订阅与管理组的组合

阶段 2:生成并应用 Terraform

检查现有配置——先检查本地 Terraform,再检查 Datadog

在生成或应用任何内容之前,先按此顺序操作。先检查本地状态,因为它决定了现有集成是可以更新,还是必须保持不动:

find . -maxdepth 1 -type f \( -name '*.tf' -o -name 'terraform.tfstate' \) -print
# A project is "present" if it has configuration - .terraform/ may simply not exist yet on a fresh clone
# with a remote backend, and terraform.tfstate does not exist at all when state is remote.
if [ -n "$(find . -maxdepth 1 -type f \( -name '*.tf' -o -name '*.tf.json' \) -print -quit)" ]; then
  terraform init -input=false >/dev/null || { echo "terraform init failed - resolve that before concluding anything about existing state"; exit 1; }
  out=$(terraform state list 2>&1); rc=$?
  if [ "$rc" -ne 0 ]; then
    case $out in
      *'No state file'*|*'no state'*|*'Backend initialization required'*)
        echo "project is initialized but has no state yet - treat as a clean install" ;;
      *)
        printf '%s\n' "$out"
        echo "could not read state (backend or credentials problem) - do NOT treat this as 'nothing exists'"; exit 1 ;;
    esac
  elif [ -z "$out" ]; then
    echo "state is empty - treat as a clean install"
  else
    printf '%s\n' "$out" | grep -F 'datadog_integration_azure' || echo "state exists but holds no datadog_integration_azure resource"
  fi
else
  echo "no Terraform configuration here yet - clean install"
fi

匹配精确的资源地址 datadog_integration_azure,不要使用宽泛的 grep -i datadog:否则,无关的 Datadog 资源或部分应用后遗留的云 IAM 资源,都会被误认为是受管理的集成。

然后查询 Datadog 中已有的内容:

for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
DD_SITE='datadoghq.com'; export DD_SITE   # <- replace with the site confirmed in Phase 0.
# Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
: "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
  | curl -sS -w '\n%{http_code}' -X GET -H @- "https://api.${DD_SITE}/api/v1/integration/azure")
code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
[ "$code" = "200" ] || { echo "lookup failed with HTTP $code - do not assume 'not connected':"; printf '%s\n' "$body"; exit 1; }
printf '%s\n' "$body"

现在先协调两处查询结果,再进行任何操作:

  • Datadog 中不存在,本地状态中也没有——全新安装。继续。

  • Datadog 中存在,且也在本地状态中——这是更新/修复场景,不是重复创建。 继续使用下面的 Terraform,将其作为对现有资源的更改,并让 plan 显示将要修改的内容。

  • Datadog 中存在,但本地状态中不存在(Phase 1 中的租户已注册)——停止。应用操作要么会创建重复项,要么会与当前管理该资源的配置冲突。明确说明这一点,并提供以下选项:将现有对象导入此项目(运行 terraform import datadog_integration_azure.datadog_integration "${tenant_name}:${client_id}", 并将现有应用的密钥作为 CLIENT_SECRET 环境变量提供)、在当前管理该对象的位置继续管理,或先在 Datadog 中删除该对象。 只有用户选择一个选项并确认后,才能继续。 关于导入,有两点需要按以下顺序处理。先生成配置(使用下面的 Terraform,并根据现有身份进行调整——角色/应用/服务账号名称保持一致),因为 terraform import 会将现有对象绑定到已配置的资源地址;没有配置就会失败。并且,仅导入 Datadog 注册信息还不够:云端身份(IAM 角色、应用注册、服务账号)仍不在状态中,因此要么也导入这些资源,要么通过数据源引用它们;否则下次应用时会再次尝试创建并发生冲突。

    # the existing app's secret must be in the environment for the import to validate
    CLIENT_SECRET='<existing-app-secret>' terraform import datadog_integration_azure.datadog_integration "<tenant_name>:<client_id>"
    
  • 本地状态中存在,但 Datadog 中不存在——这是部分安装或回滚后的状态。云端资源可能仍然存在,但注册信息不存在。不要从头开始:运行 plan,让它显示缺少哪些内容,并预期它只会重新创建注册信息。

检查是否已有 Terraform

生成新的 Terraform 配置之前,请检查用户是否已在当前目录或附近拥有 Terraform 项目:

find . -maxdepth 1 -type f \( -name '*.tf' -o -name 'terraform.tfstate' \) -print

如果发现已有 .tf 文件:

  • 阅读这些文件,了解已配置的提供程序和资源。
  • 如果已有 datadog 提供程序,请复用其配置,不要重复创建。
  • 如果已有 azurerm 或 azuread 提供程序,请复用它们。
  • 只向现有项目添加所需的新资源(应用注册、角色分配、datadog_integration_azure)。不要重新生成已有的提供程序、变量或 terraform 块。
  • 如果用户采用模块化布局,请创建一个新文件,例如 datadog-azure-integration.tf,用于存放 Datadog 资源。

**生成任何内容之前,请先确定状态文件的存放位置。**此模板会创建一个存储在状态文件中的客户端密钥(请参阅重要说明),因此,默认的本地 terraform.tfstate 会在磁盘上以明文形式存储密钥。请确认用户会将状态文件存放在经过加密且受访问控制的远程后端中,并在执行 terraform init 之前配置该后端——之后再迁移状态文件会留下明文副本。**如果用户不使用经过加密的远程后端,请在此处停止。**说明生成的客户端密钥会以明文形式存放在本地 terraform.tfstate 中,并提供另一种方案:通过 Datadog UI 中的 Azure 集成磁贴配置集成。该方式会在服务器端存储密钥,且不会写入状态文件。用户确认知情不能替代配置后端——这符合此技能系列的规则,无论如何调用此技能都应遵守。

如果未发现已有 Terraform 项目,请生成独立配置。

完整的 HCL 模板——包括提供程序、应用注册和轮换密钥、两个范围的 Monitoring Reader 角色分配、Graph API 授权,以及 datadog_integration_azure 注册——位于 references/terraform.md,其中还包含仅订阅和仅管理组的变体。现在请阅读该文件,并填入占位符后输出。

应用 Terraform

  1. 将模板中的所有 <PLACEHOLDER> 值替换为收集到的实际值:

    • <TENANT_ID> 来自阶段 1
    • <USER_SUBSCRIPTION_IDS> 来自阶段 1
    • <USER_MANAGEMENT_GROUP_NAMES> 来自阶段 1
    • <DD_SITE> 来自阶段 0
  2. 如果用户只选择了订阅(没有管理组),则设置 management_group_names = [],并移除 azurerm_role_assignment.monitoring_reader_management_group 资源。

  3. 如果用户只选择了管理组(没有显式选择订阅),则仍需要至少一个订阅 ID 用于 azurerm 提供程序——使用其某个管理组中的订阅。

  4. 运行 terraform init 安装提供程序。

  5. 执行计划,并将计划保存到文件。Datadog 提供程序会直接从环境中读取 DD_API_KEY / DD_APP_KEY,因此没有根变量,也不需要 -var= 参数——不会有任何机密进入计划文件、状态或命令行:

    for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
    DD_SITE='datadoghq.com'; export DD_SITE   # <- replace with the site confirmed in Phase 0.
    # Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
    : "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
    umask 077          # tighten permissions on the plan file anyway
    terraform plan -out=tfplan
    

    向用户展示计划输出,并等待明确确认。

  6. 只有在用户确认后,才应用已保存的计划。应用该文件才能让审批真正有效:不带计划文件运行 terraform apply 会计算一个全新计划,而 -auto-approve 会在无人查看的情况下执行计划,因此计划后发生的任何变更都不会经过审核:

    for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
    DD_SITE='datadoghq.com'; export DD_SITE   # <- replace with the site confirmed in Phase 0.
    # Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
    : "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
    trap 'rm -f tfplan' EXIT HUP INT TERM   # the plan file goes away even if this is interrupted
    if terraform apply tfplan; then
      echo "apply complete"
    else
      echo "terraform apply FAILED - do NOT verify or report success"
      exit 1
    fi
    

    trap 会在任何退出路径中移除计划文件,包括用户决策期间按下 Ctrl-C。if/else 包裹 apply 命令很重要,因为如果清理命令是代码块的最后一行,apply 失败时也会以 0 退出,Agent 随后会去“验证”一个实际上并未完成的部署。(这里特意使用 if,而不是 status=$?:在 zsh 中,status 是只读变量。)

    计划文件完全不包含密钥材料,因为密钥从未成为 Terraform 值——提供程序会从环境中读取它们。这使得在此处使用 -out 是安全的,适用于任何 Terraform 版本,也因此现有项目无需更改变量。

  7. terraform apply 成功后,验证集成是否已在 Datadog 中注册:

    for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
    DD_SITE='datadoghq.com'; export DD_SITE   # <- replace with the site confirmed in Phase 0.
    # Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
    : "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
    resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
      | curl -sS -w '\n%{http_code}' -X GET -H @- "https://api.${DD_SITE}/api/v1/integration/azure")
    code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
    [ "$code" = "200" ] || { echo "lookup failed with HTTP $code - do not assume 'not connected':"; printf '%s\n' "$body"; exit 1; }
    printf '%s\n' "$body"
    

    确认响应中列出了刚刚配置的租户和 client_id。如果缺少该集成,请将响应提供给用户,以便他们进行排查。

充分利用集成

terraform apply 成功完成后,祝贺用户,并告知他们指标通常会在 5-10 分钟内到达。然后检查是否已有指标,并展示一个小组件。

检查指标

等待几秒钟,然后向指标 API 发起一次查询:

for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
DD_SITE='datadoghq.com'; export DD_SITE   # <- replace with the site confirmed in Phase 0.
# Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
: "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
sleep 10
resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
  | curl -sS -w '\n%{http_code}' -G -H @- "https://api.${DD_SITE}/api/v1/query" \
  --data-urlencode "from=$(($(date +%s) - 900))" \
  --data-urlencode "to=$(date +%s)" \
  --data-urlencode "query=avg:azure.vm.percentage_cpu{*} by {name}")
code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
[ "$code" = "200" ] || { echo "metric query failed with HTTP $code - that is NOT 'metrics still propagating':"; printf '%s\n' "$body"; exit 1; }
printf '%s\n' "$body"
渲染组件

如果 series 数组非空,则根据真实数据绘制 ASCII 图表:

  • 使用 pointlist 中的值绘制折线,并根据实际最小值和最大值缩放 Y 轴。
  • 使用制表符绘制线条(╭、╰、─、│、┤)。
  • 在底部列出每个 series scope 中的 VM 名称。
  • 如果返回多个 series,则显示平均值最高的 3 个。

如果 series 数组为空,则显示以下静态预览,并告知用户指标仍在传输中:

┌─────────────────────────────────────────────────────────┐
│  azure.vm.percentage_cpu            ▂▃▅▆▇▆▅▃▂▁▂▃▅▆▇█  │
│  100% ┤                                          ╭──╮   │
│   75% ┤                    ╭───╮              ╭──╯  │   │
│   50% ┤              ╭────╯   ╰──╮     ╭────╯     │   │
│   25% ┤    ╭────────╯            ╰────╯           │   │
│    0% ┤────╯                                       │   │
│       └────────────────────────────────────────────┘   │
│                                                         │
│  指标正在传输中——请几分钟后再查看                         │
└─────────────────────────────────────────────────────────┘
指标浏览器:<APP_BASE>/metric/explorer?exp_metric=azure.vm.percentage_cpu

向用户确认集成已配置完成,数据很快就会显示。所有链接均使用 DD_SITE——请按 <APP_BASE>/... 的格式构建。

  • Azure 集成磁贴:<APP_BASE>/integrations/azure - 访问预构建的仪表板并确认集成已启用。
  • 指标浏览器:<APP_BASE>/metric/explorer?exp_metric=azure.vm.percentage_cpu - 确认数据正在流入。
  • 每项 Azure 服务(Virtual Machines、App Service、SQL Database、AKS 等)都有自己的仪表板,检测到该服务的指标后会自动启用。

建议创建的监控器 - 建议在 <APP_BASE>/monitors/create 为常见的 Azure 健康指标创建监控器:

  • 虚拟机 CPU 超过阈值
  • App Service HTTP 错误率激增
  • SQL Database DTU 使用量接近上限
  • AKS 节点池可用性

如果已启用资源采集:

  • 资源目录:<APP_BASE>/infrastructure/catalog - 浏览 Virtual Machines、App Services、SQL Databases、AKS 集群等资源。
  • 基础设施地图:<APP_BASE>/infrastructure/map - 可视化 Azure 基础设施。

探索更多 Datadog 产品:

  • 日志管理:<APP_BASE>/logs - 流式传输 Azure 活动日志和资源日志,便于集中搜索和告警。设置说明:https://docs.datadoghq.com/integrations/azure/#log-collection
  • APM 和追踪:<APP_BASE>/apm/getting-started - 对运行于 App Service、AKS 或 Virtual Machines 上的应用进行分布式追踪。
  • 笔记本:<APP_BASE>/notebook - 可分享的调查记录,可组合指标、日志和事件。

重要说明

  • 模板所需的具体权限——仅有“可以创建应用注册”并不足够;Contributor 或 Application Developer 虽然能完成发现阶段,但会在应用更改时因 403 错误而失败:
    • 在 Entra ID 中拥有 Application Administrator 或 Global Administrator 角色,因为 azuread_app_role_assignment 会授予 Microsoft Graph 应用角色(管理员同意)。
    • 在每个所选订阅和管理组范围内拥有 Microsoft.Authorization/roleAssignments/write 权限——通常需要在相应范围内拥有 User Access Administrator 或 Owner 角色——以分配 Monitoring Reader。 在 Phase 2 之前检查这些权限;如果用户没有所需权限,应联系 Entra 管理员,而不是重试。
  • 应用注册密钥会在 1 年后过期——提醒用户需要轮换密钥。
  • Datadog API 密钥和应用密钥绝不会作为值传递给 Terraform:datadog provider 会从环境变量中读取 DD_API_KEY 和 DD_APP_KEY,因此没有根变量、没有 -var= 参数,也不会有任何内容被 Terraform 记录到状态文件或已保存的计划中。不要声明密钥变量,也不要将密钥写入已提交的 .tfvars 文件或任何其他持久文件。(此模板生成的客户端密钥则不同——它是资源属性,会写入状态文件,详见下文。)
  • 未先向用户展示计划之前,绝不要运行 terraform apply。
  • 即使使用管理组,azurerm provider 也至少需要一个订阅 ID。
  • 与 AWS 角色和 GCP 模拟流程不同,此流程会颁发 Datadog 存储的客户端密钥,因此通过 time_rotating 资源创建该密钥,而不是将其设为静态值。
  • 客户端密钥会写入 Terraform 状态文件。 azuread_application_password.value 和 datadog_integration_azure.client_secret 都是资源属性,因此 sensitive = true 会在 CLI 输出中遮盖这些值,但不会在状态文件中遮盖它们(HashiCorp 文档)。请明确告知用户:状态文件必须加密并进行访问控制,且不得提交 terraform.tfstate。确实存在无密钥流程——secretless_auth_enabled = true,即联合工作负载身份(Preview)——但它要求在应用注册上配置 Datadog 联合凭据,而此模板新建的应用没有该凭据。不要将其作为只需切换标志的选项提供;如需了解实际所需操作,请参阅 references/terraform.md 中的说明。

评论

支持 Markdown