在 Azure Kubernetes 服务 (AKS) 上设置 GPU 分析(预览版)

基于 GPU 的工作负载(如 AI 推理服务)可能会占用大量内存,并且难以优化,而无需了解 GPU 活动。 你可能会看到内存不足(OOM)错误、意外延迟峰值或 GPU 内存压力上升,但传统的 Kubernetes 指标不显示代码分配内存的位置。 GPU 分析可帮助你识别负责 GPU 内存使用的函数。

本文介绍如何部署基于 eBPF 的 GPU 可观测性代理、在 Pyroscope 中存储配置文件,以及如何在 Grafana 中可视化 GPU 内存分配。

重要

AKS 预览功能可在自助服务和自愿选择的基础上启用。 预览版按“现状”和“视供应情况”提供,它们不包括在服务级别协议和有限保证范围内。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:

重要

AKS 文档和示例中都提到了开源软件。 您部署的软件被排除在 AKS 服务级别协议、有限保修和 Azure 支持之外。 将开源技术与 AKS 一起使用时,请查阅相应社区和项目维护者提供的支持选项来制定计划。

Microsoft 将负责生成我们在 AKS 上部署的开源包。 该责任包括拥有构建、扫描、签名、验证和快速修复流程的完整所有权,并掌控容器镜像中的二进制文件。 如需了解详细信息,请参阅 AKS 漏洞管理和 AKS 支持范围。

先决条件

  • 至少具有一个启用了 GPU 的节点池的 AKS 群集。
  • Azure CLI 2.72.0 或更高版本。 请运行 az --version 以查看版本。
  • 这是 k8s-extension Azure CLI 扩展。 运行 az extension add --name k8s-extension 以安装它。
  • Helm 3.x 或更高版本。 请运行 helm version 以查看版本。
  • Azure Monitor,除非你使用自己的监控解决方案。
  • Azure 托管 Grafana,除非你使用自己的 Grafana 实例。

步骤 1:通过 Inspektor 小工具扩展启用 GPU 分析

Inspektor Gadget 是一个基于 eBPF 的开源 Kubernetes 可观测性框架。 对于 GPU 性能分析,它无需更改代码、使用边车容器或重启 Pod,即可跟踪 CUDA 内存分配调用。

在 AKS 群集上启用 GPU 性能分析:

注释

此命令假定你在 AKS 群集上启用了Azure Monitor。 如果使用自己的 Prometheus 设置,请删除 --configuration-settings azureMonitor.enabled=true。 有关详细信息,请参阅 GPU 分析常见问题解答。

az k8s-extension create \
  --extension-type microsoft.inspektorgadget \
  --subscription <your-subscription-id> \
  --resource-group <your-resource-group> \
  --cluster-name <your-cluster-name> \
  --cluster-type managedClusters \
  --release-train preview \
  --name inspektor-gadget \
  --configuration-settings gpuObservability.enabled=true \
  --configuration-settings azureMonitor.enabled=true

验证 Inspektor Gadget Pod 是否正在运行:

kubectl get pods -n gadget -l k8s-app=gadget

Tip

GPU 内存分析可在内存分配事件发生时捕获这些事件。 如果你的工作负载在启用性能分析之前分配了 GPU 内存,性能分析器将无法捕获这些事件。 对于诸如 vLLM 这类在启动时预分配 GPU 内存的工作负载,请在部署工作负载之前启用性能分析,或者重启工作负载以捕获初始内存分配路径。

步骤 2:使用 Pyroscope 启用性能剖析可视化

注释

如果群集中有现有的 Grafana 和 Pyroscope 堆栈,请跳过此步骤。

Pyroscope 是一个开源项目,用于可视化和存储性能配置文件,以便进行内存优化和故障排除。

将单个 Pyroscope 实例 部署到群集:

helm install pyroscope -n gadget \
  oci://ghcr.io/grafana/helm-charts/pyroscope \
  --version 1.15.0 \
  --set pyroscope.image.repository=grafana/pyroscope \
  --set-string pyroscope.image.tag=1.15.0 \
  --set pyroscope.replicaCount=1 \
  --set pyroscope.structuredConfig.self_profiling.disable_push=true \
  --set pyroscope.structuredConfig.storage.backend=filesystem \
  --set pyroscope.service.type=LoadBalancer \
  --set pyroscope.service.port=4040 \
  --set-string pyroscope.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-internal"=true \
  --set-string pyroscope.service.annotations."service\.beta\.kubernetes\.io/azure-pls-create"=true \
  --set-string pyroscope.service.annotations."service\.beta\.kubernetes\.io/azure-pls-name"=pyroscope-pls \
  --set-string pyroscope.service.annotations."service\.beta\.kubernetes\.io/azure-pls-proxy-protocol"=false \
  --set-string pyroscope.service.annotations."service\.beta\.kubernetes\.io/azure-pls-visibility"='*' \
  --set alloy.enabled=false \
  --set minio.enabled=false

确认 Pyroscope Pod 是否正在运行:

kubectl get pods -n gadget pyroscope-0

注释

有关高可用性部署,请参阅 Pyroscope 微服务文档。

注释

此命令将配置文件存储在本地文件系统上,因此,如果重新创建 Pod,分析数据将丢失。 若要在 Pod 重启后保留配置文件,请参阅 GPU 分析常见问题解答。

步骤 3:将火镜连接到 Azure 托管 Grafana

注释

如果使用自己的 Grafana 实例,请参阅 GPU 分析常见问题解答。

Tip

若要直接在Pyoscope UI 中查看工作负荷配置文件,请运行 kubectl port-forward -n gadget pyroscope-0 4040:4040。

通过Azure 专用链接将火镜连接到Azure 托管 Grafana。

设置群集和 Grafana 环境变量:

export RESOURCE_GROUP="<your-resource-group>"
export AKS_CLUSTER="<your-aks-cluster-name>"
export LOCATION="<your-aks-cluster-location>"
export GRAFANA_NAME="<your-azure-managed-grafana-name>"
export AKS_NODE_RG=$(az aks show \
  --resource-group "$RESOURCE_GROUP" \
  --name "$AKS_CLUSTER" \
  --query 'nodeResourceGroup' \
  --output tsv)

Tip

如果没有Azure 托管 Grafana实例,请运行 az grafana create --name "$GRAFANA_NAME" --resource-group "$RESOURCE_GROUP" --location "$LOCATION" --output none。

设置专用终结点环境变量:

export PYROSCOPE_PLS="pyroscope-pls"
export PYROSCOPE_MPE="pyroscope-mpe"
export PYROSCOPE_PORT="4040"

创建专用链接:

注释

创建专用链接可能需要几分钟时间。

# Check the Azure Managed Grafana extension version.
ver=$(az extension show --name amg --query version --output tsv)
[[ "${ver%%.*}" -ge 3 ]] && MPE="managed-private-endpoint" || MPE="mpe"

# Wait until the Pyroscope private link service is available.
until az network private-link-service show \
  --name "$PYROSCOPE_PLS" \
  --resource-group "$AKS_NODE_RG" \
  --output none 2>/dev/null; do
  sleep 10
done

PYRO_PLS_ID=$(az network private-link-service show \
  --name "$PYROSCOPE_PLS" \
  --resource-group "$AKS_NODE_RG" \
  --query 'id' \
  --output tsv)

az grafana $MPE create \
  --workspace-name "$GRAFANA_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --name "$PYROSCOPE_MPE" \
  --private-link-resource-id "$PYRO_PLS_ID" \
  --location "$LOCATION" \
  --output none

sleep 30

PYRO_CONN=$(az network private-link-service show \
  --name "$PYROSCOPE_PLS" \
  --resource-group "$AKS_NODE_RG" \
  --query "privateEndpointConnections[?privateLinkServiceConnectionState.status=='Pending' && starts_with(name, 'grafana-${GRAFANA_NAME}')].name | [0]" \
  --output tsv)

az network private-link-service connection update \
  --name "$PYRO_CONN" \
  --service-name "$PYROSCOPE_PLS" \
  --resource-group "$AKS_NODE_RG" \
  --connection-status Approved \
  --output none

az grafana $MPE refresh \
  --workspace-name "$GRAFANA_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --output none

echo "Successfully created private link."

在Azure 托管 Grafana中创建Pyoscope数据源:

ver=$(az extension show --name amg --query version --output tsv)
[[ "${ver%%.*}" -ge 3 ]] && MPE="managed-private-endpoint" || MPE="mpe"

PYRO_IP=$(az grafana $MPE show \
  --workspace-name "$GRAFANA_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --name "$PYROSCOPE_MPE" \
  --query 'privateLinkServicePrivateIP' \
  --output tsv)

export PYROSCOPE_URL="http://${PYRO_IP}:${PYROSCOPE_PORT}"

az grafana data-source create \
  --name "$GRAFANA_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --definition "{
    \"name\": \"local-pyroscope\",
    \"uid\": \"local-pyroscope\",
    \"type\": \"grafana-pyroscope-datasource\",
    \"access\": \"proxy\",
    \"url\": \"${PYROSCOPE_URL}\",
    \"jsonData\": { \"keepCookies\": [\"pyroscope_git_session\"] }
  }" \
  --output none

echo "Successfully created the local-pyroscope data source."

验证数据源是否具有有效的 URL:

az grafana data-source show \
  --name "$GRAFANA_NAME" \
  --data-source local-pyroscope

步骤 4:将 Grafana 连接到 Prometheus Azure Monitor托管服务

注释

这些步骤基于 将 Prometheus 的 Azure Monitor 托管服务连接到 Grafana。 请确保 Grafana 的托管标识在 Azure Monitor 工作区上具有 监视数据读取者 角色,尤其是在该工作区位于其他资源组或其他订阅下时。

设置Azure Monitor工作区环境变量:

export AMP_NAME="<your-azure-monitor-workspace-name>"
export AMP_RESOURCE_GROUP="<your-azure-monitor-workspace-resource-group>"

Tip

运行az resource list --resource-type Microsoft.Monitor/accounts --resource-group "$AMP_RESOURCE_GROUP" --output table以列出资源组中的Azure Monitor工作区。 若要搜索订阅,请省略 --resource-group。

创建 Prometheus 数据源:

AMP_ENDPOINT=$(az resource show \
  --resource-type Microsoft.Monitor/accounts \
  --name "$AMP_NAME" \
  --resource-group "$AMP_RESOURCE_GROUP" \
  --query properties.metrics.prometheusQueryEndpoint \
  --output tsv)

az grafana data-source create \
  --name "$GRAFANA_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --definition "{
    \"name\": \"$AMP_NAME\",
    \"type\": \"prometheus\",
    \"access\": \"proxy\",
    \"url\": \"$AMP_ENDPOINT\",
    \"jsonData\": {
      \"httpMethod\": \"POST\",
      \"azureCredentials\": { \"authType\": \"msi\" }
    }
  }"

验证数据源:

az grafana data-source show \
  --name "$GRAFANA_NAME" \
  --data-source "$AMP_NAME"

步骤 5:在 Grafana 中设置仪表板

导入 GPU 可观测性仪表板:

az grafana dashboard create \
  --name "$GRAFANA_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --definition "$(curl -sSL https://raw.githubusercontent.com/inspektor-gadget/grafana-dashboards/refs/heads/main/dashboards/gpu-observability/AdvancedGPUObservability.json)"

获取仪表板网址:

GRAFANA_URL=$(az grafana show \
  --name "$GRAFANA_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --query properties.endpoint \
  --output tsv)

echo "${GRAFANA_URL}/d/AdvancedGPUObservability"

若要解读性能分析数据,请参阅 分析 GPU 性能分析火焰图。

清理资源

删除群集内 GPU 可观测性堆栈:

helm uninstall pyroscope -n gadget
az k8s-extension delete \
  --name inspektor-gadget \
  --cluster-name <your-cluster-name> \
  --resource-group <your-resource-group> \
  --cluster-type managedClusters \
  --yes
kubectl delete namespace gadget

解读火焰图

若要解释分析结果并识别 GPU 内存热点,请参阅 分析 GPU 分析火焰图。

FAQ

有关自定义 Prometheus 和 Grafana 集成以及 Pyroscope 持久化存储,请参阅 GPU 性能分析常见问题解答。

后续步骤