AKS(Azure Kubernetes Service) GPU 프로파일링 설정(미리 보기)

AI 유추 서비스와 같은 GPU 기반 워크로드는 메모리 집약적일 수 있으며 GPU 활동에 대한 가시성 없이는 최적화하기 어려울 수 있습니다. OOM(메모리 부족) 오류, 예기치 않은 대기 시간 급증 또는 GPU 메모리 압력 증가가 표시될 수 있지만 기존 Kubernetes 메트릭은 코드에서 메모리를 할당하는 위치를 표시하지 않습니다. GPU 프로파일링은 GPU 메모리 사용을 담당하는 함수를 식별하는 데 도움이 됩니다.

이 문서에서는 eBPF 기반 GPU 관찰 에이전트를 배포하고, 프로파일을 파이로스코프에 저장하고, Grafana에서 GPU 메모리 할당을 시각화하는 방법을 보여 줍니다.

Important

AKS 미리 보기 기능은 셀프 서비스에서 사용할 수 있습니다(옵트인 방식). 미리 보기는 "있는 그대로" 및 "사용 가능한 상태로" 제공되며 서비스 수준 계약 및 제한적 보증에서 제외됩니다. AKS 미리 보기의 일부는 고객 지원팀에서 최선을 다해 지원합니다. 따라서 이러한 기능은 프로덕션 용도로 사용할 수 없습니다. 자세한 내용은 다음 지원 문서를 참조하세요.

Important

오픈 소스 소프트웨어는 AKS 설명서와 샘플 전반에서 언급되어 있습니다. 배포하는 소프트웨어는 AKS 서비스 수준 계약, 제한된 보증 및 Azure 지원 제외됩니다. AKS와 함께 오픈 소스 기술을 사용하는 경우 각 커뮤니티 및 프로젝트 유지 관리자에서 사용할 수 있는 지원 옵션을 참조하여 계획을 개발합니다.

Microsoft는 AKS에 배포하는 오픈 소스 패키지를 빌드하는 역할을 담당합니다. 해당 책임에는 컨테이너 이미지의 이진 파일에 대한 제어와 함께 빌드, 스캔, 서명, 유효성 검사 및 핫픽스 프로세스의 완전한 소유권이 포함됩니다. 자세한 내용은 AKS의 취약성 관리 및 AKS 지원 범위를 참조하세요.

사전 요구 사항

  • GPU 사용 노드 풀이 하나 이상 있는 AKS 클러스터입니다.
  • Azure CLI 버전 2.72.0 이상. az --version을 실행하여 버전을 확인합니다.
  • Azure CLI 확장입니다 k8s-extension . az extension add --name k8s-extension을(를) 실행하여 이를 설치합니다.
  • Helm 버전 3.x 이상. helm version을 실행하여 버전을 확인합니다.
  • 자체 모니터링 설정을 사용하는 경우가 아니라면 Azure Monitor.
  • 자체 Grafana 인스턴스를 사용하는 경우가 아니라면 Azure Managed Grafana.

1단계: Inspektor 가젯 확장을 통해 GPU 프로파일링 사용

Inspektor 가젯 은 Kubernetes에 대한 오픈 소스 eBPF 기반 관찰 프레임워크입니다. GPU 프로파일링의 경우 코드 변경, 사이드카 또는 Pod 다시 시작 없이 CUDA(Compute Unified Device Architecture) 메모리 할당 호출을 추적합니다.

AKS 클러스터에서 GPU 프로파일링을 사용하도록 설정합니다.

메모

이 명령은 AKS 클러스터에서 Azure Monitor 사용하도록 설정했다고 가정합니다. 자체 Prometheus 설정을 사용하는 경우 --configuration-settings azureMonitor.enabled=true를 제거하세요. 자세한 내용은 GPU 프로파일링 FAQ를 참조하세요.

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 가젯 Pod가 실행 중인지 확인합니다.

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

Tip

GPU 메모리 프로파일링은 발생하는 메모리 할당 이벤트를 캡처합니다. 프로파일링을 사용하도록 설정하기 전에 워크로드가 GPU 메모리를 할당하는 경우 프로파일러가 해당 이벤트를 캡처하지 않습니다. 시작 중에 GPU 메모리를 미리 할당하는 vLLM과 같은 워크로드의 경우 워크로드를 배포하기 전에 프로파일링을 사용하도록 설정하거나 워크로드를 다시 시작하여 초기 메모리 할당 경로를 캡처합니다.

2단계: 파이로스코프를 사용하여 프로필 시각화 사용

메모

클러스터에 기존 Grafana 및 파이로스코프 스택이 있는 경우 이 단계를 건너뜁니다.

파이로스코프 는 메모리 최적화 및 문제 해결을 위해 성능 프로필을 시각화하고 저장하는 오픈 소스 프로젝트입니다.

클러스터에 단일 파이로스코프 인스턴스 를 배포합니다.

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 파드가 실행 중인지 확인하세요.

kubectl get pods -n gadget pyroscope-0

메모

이 명령은 로컬 파일 시스템에 프로필을 저장하므로 Pod를 다시 만들면 프로파일링 데이터가 손실됩니다. Pod 다시 시작에서 프로필을 유지하려면 GPU 프로파일링 FAQ를 참조하세요.

3단계: 파이로스코프를 Azure Managed Grafana 연결

메모

고유한 Grafana 인스턴스를 사용하는 경우 GPU 프로파일링 FAQ를 참조하세요.

Tip

Pyroscope UI에서 직접 워크로드 프로필을 보려면 실행 kubectl port-forward -n gadget pyroscope-0 4040:4040합니다.

Pyroscope를 Azure Private Link를 통해 Azure Managed 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 Managed 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 Managed Grafana 파이로스코프 데이터 원본을 만듭니다.

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 to Grafana에 대한 Connect Azure Monitor 관리 서비스를 기반으로 합니다. 특히 작업 영역이 다른 리소스 그룹 또는 구독에 있는 경우 Grafana의 관리 ID에 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)"

대시보드 URL을 가져옵니다.

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 통합 및 영구 파이로스코프 스토리지는 GPU 프로파일링 FAQ를 참조하세요.

다음 단계