Introdução ao acelerador distribuído para armazenamento em nuvem no AKS (versão prévia)

Esse guia de Início Rápido habilita o acelerador distribuído para armazenamento em nuvem (DACS) por meio de sua extensão gerenciada em um cluster existente do Serviço de Kubernetes do Azure (AKS), concede acesso de leitura a um contêiner do Blob do Azure e verifica se leituras repetidas usam o cache. O exemplo da carga de trabalho usa o pacote público dacs-client==0.1.0 .

Important

O acelerador distribuído para armazenamento em nuvem está em prévia. Os recursos de pré-visualização são fornecidos sem um contrato de nível de serviço e não são recomendados para trabalhos em ambientes de produção. Para obter mais informações, consulte Termos de Uso Complementares para Versões Prévias do Microsoft Azure.

Prerequisites

Antes de começar, você precisa de:

  • Uma assinatura do Azure.
  • Um cluster AKS existente que atende aos requisitos de suporte para pré-visualização do DACS.
  • Um pool de nós de cache Linux com discos de dados NVMe locais, como a Standard_L*s_v3 família VM.
  • Uma conta do Armazenamento do Azure e um contêiner Blob contendo dados representativos do modelo.
  • Um shell Bash com CLI do Azure, kubectle Docker ou outra ferramenta de build de imagem de container. Execute os comandos nesse início rápido na mesma sessão de shell para que as variáveis permaneçam disponíveis.
  • Permissão para instalar extensões do AKS, administrar recursos do Kubernetes, atualizar rótulos do pool de nós e atribuir o papel de acesso a dados de armazenamento usado neste quickstart.
  • Uma imagem de carga de trabalho com Python 3.8 ou posterior e glibc 2.35 ou posterior. Este quickstart usa python:3.12-slim-bookworm e o pacote PyPI dacs-client==0.1.0 em nós x64.

O Distributed Accelerator para armazenamento em nuvem não usa o pool de nós de cache como armazenamento persistente. Armazenamento de Blobs do Azure permanece a fonte da verdade.

Requisitos de suporte para pré-visualização do DACS

Requirement Suporte para pré-visualização de DACS
Regiões do Azure Todas as regiões de nuvem pública do Azure.
Versões do AKS Kubernetes 1.35 ou posterior.

Definir variáveis

Substitua os valores provisórios e execute os seguintes comandos:

SUBSCRIPTION_ID=<subscription-id>
RESOURCE_GROUP=<resource-group>
CLUSTER_NAME=<aks-cluster-name>
CACHE_NODE_POOL=<nvme-node-pool>
STORAGE_ACCOUNT=<storage-account-name>
STORAGE_CONTAINER=<blob-container-name>
CACHE_NAMESPACE=dacs-cache-system
CACHE_NAME=cache-sample

az account set --subscription $SUBSCRIPTION_ID
az aks get-credentials \
  --resource-group $RESOURCE_GROUP \
  --name $CLUSTER_NAME

Garantir a extensão do AKS preview

A prévia do DACS requer aks-preview versão 22.0.0b9 ou posterior. Instale ou atualize a extensão e as extensões usadas para gerenciar e inspecionar DACS:

az extension add --name aks-preview --upgrade --yes
az extension show --name aks-preview --query version --output tsv
az extension add --name connectedk8s --upgrade --yes
az extension add --name k8s-extension --upgrade --yes

Você não precisa conectar o cluster AKS ao Azure Arc. Se você já instalou um controlador DACS manualmente, siga Prepare for upgrades antes de mudar para a extensão gerenciada. Não use dois controladores DACS no mesmo cluster.

Verifique o pool de nós de cache

Confirme que o pool de nós selecionado usa Linux e um tamanho de VM com discos de dados NVMe locais:

az aks nodepool show \
  --resource-group $RESOURCE_GROUP \
  --cluster-name $CLUSTER_NAME \
  --name $CACHE_NODE_POOL \
  --query '{osType:osType,vmSize:vmSize,count:count,powerState:powerState.code}' \
  --output table

Para o acelerador distribuído de armazenamento em nuvem, use um pool dedicado de nós de cache ou confirme que outros softwares não reservam nem formatam os mesmos discos NVMe locais.

Rotule o pool de nós de cache no nível do pool de nós para que o rótulo sobreviva à substituição de nós. Se o pool já tiver etiquetas personalizadas, inclua-as na atualização para preservá-las:

az aks nodepool update \
  --resource-group $RESOURCE_GROUP \
  --cluster-name $CLUSTER_NAME \
  --name $CACHE_NODE_POOL \
  --labels dacs.azure.com/processing-unit=cpu

Caution

Ativar o DACS instala um DaemonSet pré-requisito que descobre, formata e monta discos NVMe locais em nós de cache rotulados. Rotule apenas os nós com discos dedicados ao cache.

Habilitar o acelerador distribuído para armazenamento em nuvem

Ative o DACS passando distributedAccelerator sozinho. A maiúscula A é necessária:

az aks update \
  --resource-group $RESOURCE_GROUP \
  --name $CLUSTER_NAME \
  --enable-azure-container-storage distributedAccelerator

O comando instala a distributedaccelerator extensão gerenciada, o controlador DACS e o pré-requisito NVMe DaemonSet em kube-system, e a caches.storage.azure.com definição personalizada de recurso (CRD). Você não instala um gráfico de pré-requisitos separado nem gerencia o release do Helm da extensão por conta própria. Crie um recurso de cache separadamente, como mostrado mais adiante.

Verificar a extensão

az k8s-extension show \
  --cluster-type managedClusters \
  --cluster-name $CLUSTER_NAME \
  --resource-group $RESOURCE_GROUP \
  --name distributedaccelerator \
  --query '{extensionType:extensionType,provisioningState:provisioningState,currentVersion:currentVersion,releaseTrain:releaseTrain}' \
  --output table

Confirme que o tipo de extensão é microsoft.distributedaccelerator e o estado de provisionamento é Succeeded. A versão instalada do servidor é reportada por currentVersion; não infira isso a partir da versão do pacote cliente ou de uma tag de imagem pública.

Grave essa versão para diagnóstico, depois verifique o controlador e o CRD:

DACS_VERSION=$(az k8s-extension show \
  --cluster-type managedClusters \
  --cluster-name $CLUSTER_NAME \
  --resource-group $RESOURCE_GROUP \
  --name distributedaccelerator \
  --query currentVersion --output tsv)

echo "$DACS_VERSION"
kubectl rollout status deployment/dacs-manager --namespace kube-system --timeout=5m
kubectl get crd caches.storage.azure.com

Continue somente depois que a extensão estiver no Succeeded estado e o controlador estiver pronto. Se as verificações de instalação ou prontidão falharem, confira Solucionar problemas do acelerador distribuído para armazenamento em nuvem.

Provisionar o cache

Verifique a preparação local para NVMe

A extensão gerenciada prepara discos NVMe locais por meio de seu pré-requisito DaemonSet. Não implante uma carga de trabalho duplicada de configuração de disco nem instale outro chart de pré-requisitos.

kubectl rollout status daemonset/dacs-prereq \
  --namespace kube-system --timeout=10m

kubectl get daemonset dacs-prereq --namespace kube-system
kubectl get pods --namespace kube-system --selector app.kubernetes.io/name=dacs-prereq --output wide

Confirme que o DaemonSet tem um pod Pronto em cada nó de cache rotulado. O ponto de montagem é /var/lib/ssd/cacheserver e deve corresponder ao spec.storage.hostPath.nodeCacheFolderPath do recurso cache. Se o DaemonSet estiver faltando ou não estiver pronto, pare e verifique a versão da extensão e os eventos do pod de pré-requisito em vez de instalar um chart separado.

Crie um namespace dedicado para o Cache e a carga de trabalho de teste:

kubectl create namespace "$CACHE_NAMESPACE"

Criar o recurso Cache

Crie o recurso Cache. O exemplo configura três servidores de cache, com um servidor por nó NVMe rotulado, e requer pelo menos três nós elegíveis. Ajuste a contagem de servidores, tamanho do cache, CPU e memória para se encaixar no seu pool de nós.

cat <<EOF | kubectl apply -f -
apiVersion: storage.azure.com/v1
kind: Cache
metadata:
  name: $CACHE_NAME
  namespace: $CACHE_NAMESPACE
spec:
  scaling:
    static:
      numServers: 3
  serverSizeInGB: 1000
  serverThreads: 80
  cpuLimit: 4
  memoryLimitMB: 32000
  port: 9065
  metricsPort: 9096
  nodeSelectorKey: dacs.azure.com/processing-unit
  nodeSelectorValue: cpu
  storage:
    hostPath:
      nodeCacheFolderPath: /var/lib/ssd/cacheserver
EOF

Verificar se o cache está pronto

Espere pelo recurso Cache nomeado em vez de selecionar o primeiro cache no cluster:

kubectl wait \
  --namespace $CACHE_NAMESPACE \
  --for=condition=Ready \
  cache/$CACHE_NAME \
  --timeout=10m

kubectl get cache,pods \
  --namespace $CACHE_NAMESPACE \
  --output wide

Verifique se as contagens atuais e desejadas do servidor de cache correspondem e se cada pod de servidor de cache está rodando em um nó NVMe.

Obtenha o nome de host de descoberta usado pelos clientes de carga de trabalho:

CACHE_DISCOVERY_URL=$(kubectl get cache $CACHE_NAME \
  --namespace $CACHE_NAMESPACE \
  -o jsonpath='{.status.discoveryURL}')

echo $CACHE_DISCOVERY_URL

Conceder acesso de leitura aos dados do modelo

Esse quickstart usa a identidade gerenciada do kubelet do AKS. Obtenha o ID do objeto e o ID do recurso da conta de armazenamento:

KUBELET_OBJECT_ID=$(az aks show \
  --resource-group $RESOURCE_GROUP \
  --name $CLUSTER_NAME \
  --query identityProfile.kubeletidentity.objectId \
  --output tsv)

KUBELET_CLIENT_ID=$(az aks show \
  --resource-group $RESOURCE_GROUP \
  --name $CLUSTER_NAME \
  --query identityProfile.kubeletidentity.clientId \
  --output tsv)

STORAGE_ID=$(az storage account show \
  --resource-group $RESOURCE_GROUP \
  --name $STORAGE_ACCOUNT \
  --query id \
  --output tsv)

Atribua o papel de leitura com menor privilégio no escopo do contêiner:

az role assignment create \
  --assignee-object-id $KUBELET_OBJECT_ID \
  --assignee-principal-type ServicePrincipal \
  --role "Storage Blob Data Reader" \
  --scope "$STORAGE_ID/blobServices/default/containers/$STORAGE_CONTAINER"

Atribuições de funções podem levar vários minutos para serem propagadas. Para usar a identidade de Kubelet, defina todas as três variáveis de identidade gerenciada mostradas na especificação do pod: AZURE_CLIENT_ID, MSI_ENDPOINT, e um não vazio MSI_SECRET. Configurar apenas AZURE_CLIENT_ID não é suficiente para essa configuração de cliente.

Adicionar o cliente a uma imagem de workload

Crie um arquivo nomeado Dockerfile no seu diretório de build com o seguinte conteúdo. O nome da distribuição é dacs-client, e o namespace de importação em Python é py_dacs_client:

FROM python:3.12-slim-bookworm
RUN python3 -m pip install --no-cache-dir "dacs-client==0.1.0"

Construa e envie a imagem para um registro do qual seu cluster AKS possa puxar. Para Registro de Contêiner do Azure (ACR), faça login antes de fazer push e certifique-se de que a identidade kubelet tenha acesso de pull de imagem. Para um registry que utiliza permissões de registry RBAC, conceda AcrPull no escopo do registry. Para um registro habilitado por ABAC, use a função repository-reader apropriada. Para detalhes, veja Authenticate with Registro de Contêiner do Azure from Serviço de Kubernetes do Azure.

WORKLOAD_IMAGE=<registry-name>.azurecr.io/dacs-test:0.1.0

docker build \
  --tag $WORKLOAD_IMAGE .
docker push $WORKLOAD_IMAGE

Implantar um teste somente leitura

Escolha um blob de modelo existente e defina seu caminho:

MODEL_BLOB=<path-to-model-blob>

Crie um pod de teste. O pod lê até 4 MiB do blob cinco vezes, com um intervalo de um segundo entre as leituras, e verifica se todas as leituras retornam a mesma soma de verificação SHA-256. A população do cache é assíncrona, então uma segunda leitura imediata pode não entrar no cache. Os intervalos dão tempo para os uploads em segundo plano serem concluídos; use as métricas do cliente e contadores de servidor para confirmar acertos de cache, em vez de assumir que uma leitura específica é um acerto. Para comparar contadores de servidor, capture uma linha de base antes de criar o pod seguindo Verifique o caminho da solicitação DACS.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: dacs-test
  namespace: $CACHE_NAMESPACE
spec:
  restartPolicy: Never
  containers:
    - name: test
      image: $WORKLOAD_IMAGE
      env:
        - name: CACHE_DISCOVERY_URL
          value: "$CACHE_DISCOVERY_URL"
        - name: CACHE_SERVER_PORT
          value: "9065"
        - name: DACS_CPU_CORES
          value: "2"
        - name: DACS_MEMORY_MB
          value: "512"
        - name: AZURE_CLIENT_ID
          value: "$KUBELET_CLIENT_ID"
        - name: MSI_ENDPOINT
          value: "http://169.254.169.254/metadata/identity/oauth2/token"
        - name: MSI_SECRET
          value: "required-nonempty-value"
        - name: MODEL_PATH
          value: "az://$STORAGE_ACCOUNT.blob.core.windows.net/$STORAGE_CONTAINER/$MODEL_BLOB"
      command: ["python3", "-c"]
      resources:
        requests:
          cpu: "1"
          memory: 512Mi
        limits:
          cpu: "2"
          memory: 1Gi
      args:
        - |
          import asyncio
          import ctypes
          import hashlib
          import os
          import time

          from py_dacs_client.dacs_client import DACSCacheClient
          from py_dacs_client.dacs_utils import BoundedBufferManager

          async def main():
              path = os.environ["MODEL_PATH"]
              client = DACSCacheClient()
              buffers = BoundedBufferManager(max_memory_limit=64 * 1024 * 1024)
              try:
                  size = min(await client.get_file_size(path), 4 * 1024 * 1024)
                  if size == 0:
                      raise ValueError("Choose a nonempty model blob")
                  first_digest = None
                  for attempt in range(1, 6):
                      start = time.perf_counter()
                      buffer = await buffers.acquire_buffer(size)
                      try:
                          count = await client.read_blob(path, buffer, size, 0)
                          if count != size:
                              raise RuntimeError(f"Expected {size} bytes, received {count}")
                          digest = hashlib.sha256(ctypes.string_at(buffer, count)).hexdigest()
                          if first_digest is not None and digest != first_digest:
                              raise RuntimeError("Repeated reads returned different data")
                          first_digest = digest
                      finally:
                          await buffers.release_buffer(buffer)
                      elapsed = time.perf_counter() - start
                      print(f"read {attempt}: {count} bytes in {elapsed:.3f}s; sha256={digest}")
                      if attempt < 5:
                          await asyncio.sleep(1)
              finally:
                  await client.shutdown()

          asyncio.run(main())
EOF

kubectl wait \
  --namespace "$CACHE_NAMESPACE" \
  --for=jsonpath='{.status.phase}'=Succeeded \
  pod/dacs-test \
  --timeout=5m

kubectl logs dacs-test --namespace "$CACHE_NAMESPACE"

Verifique o caminho de requisição do DACS

Uma leitura bem-sucedida ou uma segunda leitura mais rápida sozinha não provam que a solicitação chegou ao DACS, porque o cliente pode recorrer ao Armazenamento de Blobs do Azure. Defina tanto CACHE_DISCOVERY_URL quanto CACHE_SERVER_PORT. Se qualquer um dos dois estiver faltando, o cliente registra Cache not configured. Working in Remote Blob mode only.

Inspecione os logs dos pods para as métricas de desligamento do cliente cache_client_download_cache_hits e cache_client_download_cache_misses. Uma contagem de acertos no cache diferente de zero indica que uma solicitação foi atendida do cache. Contadores de cliente podem incluir requisições internas e não necessariamente equivalem ao número de leituras de aplicação.

Também compare os contadores de solicitação do servidor de cache antes e depois de rodar o teste. Verifique cada pod de servidor de cache porque a solicitação pode ser atendida por qualquer servidor, não necessariamente pelo primeiro pod. Para inspecionar um servidor:

CACHE_POD=$(kubectl get pods \
  --namespace $CACHE_NAMESPACE \
  --selector app=cacheserver \
  -o jsonpath='{.items[0].metadata.name}')

kubectl port-forward \
  --namespace $CACHE_NAMESPACE \
  pod/$CACHE_POD 9096:9096

Em outro terminal, recupere as métricas e inspecione o contador de solicitações:

curl --fail --silent --show-error http://localhost:9096/metrics > dacs-metrics.txt
grep '^cache_server_request_counter' dacs-metrics.txt

Confirme um aumento nas solicitações de download com request_type="Download" e status="Success", não apenas a presença de uma série de contadores, que pode existir em zero. Os valores de rótulo diferenciam maiúsculas de minúsculas. Pare o encaminhamento de portas e repita para outros pods de servidor de cache conforme necessário. Correlacione métricas de acerto de cache do cliente com contadores de servidor e telemetria do Azure Blob para distinguir acertos de cache, tráfego de origem e comportamento de fallback.

Para a referência completa de métricas e configuração de scrape, veja Monitorar o acelerador distribuído para armazenamento em nuvem.

Limpe o teste

kubectl delete pod dacs-test --namespace "$CACHE_NAMESPACE"

Se você não precisar mais do cache, exclua o recurso de cache enquanto o controlador estiver rodando:

kubectl delete cache "$CACHE_NAME" --namespace "$CACHE_NAMESPACE" --wait=true
kubectl get cache -A

Exclua o namespace apenas se ele foi dedicado a esse quickstart e não contiver recursos que você precise manter:

kubectl delete namespace "$CACHE_NAMESPACE"

Após remover todos os recursos do Cache e cargas de trabalho dependentes, desative a extensão gerenciada:

az aks update \
  --resource-group $RESOURCE_GROUP \
  --name $CLUSTER_NAME \
  --disable-azure-container-storage distributedAccelerator

Desabilitar o DACS remove sua extensão gerenciada, controlador e o pré-requisito DaemonSet, mas mantém o CRD de Cache. Não apague os pré-requisitos gerenciados separadamente, desinstale diretamente o release do Helm da extensão ou exclua o CRD manualmente. Remova qualquer atribuição de função ou rótulo de pool de nós adicionado exclusivamente para este quickstart somente após confirmar que nenhuma outra carga de trabalho precisa dele.

Para obter mais informações Remover o acelerador distribuído para armazenamento em nuvem.

Próximas Etapas