Comece com o acelerador distribuído para armazenamento na cloud no AKS (pré-visualização)

Este quickstart permite o acelerador distribuído para armazenamento na nuvem (DACS) através da sua extensão gerida num cluster existente do Azure Kubernetes Service (AKS), concede acesso de leitura a um contentor Azure Blob e verifica se as leituras repetidas utilizam a cache. O exemplo da carga de trabalho usa o pacote público dacs-client==0.1.0 .

Importante

O acelerador distribuído para armazenamento na nuvem está em pré-visualização. As funcionalidades de pré-visualização são fornecidas sem um acordo de nível de serviço, não sendo recomendadas para cargas de trabalho de produção. Para mais informações, consulte Termos Suplementares de Utilização para Microsoft Azure Previews.

Prerequisites

Antes de começar, você precisa:

  • Uma assinatura do Azure.
  • Um cluster AKS existente que cumpre os 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 Armazenamento do Azure e um contentor Blob contendo dados representativos do modelo.
  • Um shell Bash com CLI do Azure, kubectle Docker ou outra ferramenta de construção de imagem de container. Execute os comandos deste 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 AKS, administrar recursos 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 workload com Python 3.8 ou posterior e glibc 2.35 ou posterior. Este quickstart utiliza python:3.12-slim-bookworm e o pacote PyPI dacs-client==0.1.0 em nós x64.

O acelerador distribuído para armazenamento na cloud não usa o pool de nós de cache como armazenamento persistente. Armazenamento de Blobs do Azure continua a ser a fonte da verdade.

Requisitos de suporte para pré-visualização de 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 Kubernetes no AKS 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 de preview do AKS

A pré-visualização do DACS requer aks-preview versão 22.0.0b9 ou posterior. Instale ou atualize a extensão e as extensões usadas para gerir 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

Não precisas de ligar o cluster AKS ao Azure Arc. Se já instalaste manualmente um controlador DACS, segue Preparar para atualizações antes de mudar para a extensão gerida. Não uses dois controladores DACS no mesmo cluster.

Verificar o pool de nós da 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 aceleradores distribuídos para armazenamento na cloud, use um pool dedicado de nós de cache ou confirme que outro software não utiliza nem formata os mesmos discos NVMe locais.

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

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. Etiquete apenas os nós com discos dedicados à cache.

Ativar acelerador distribuído para armazenamento na nuvem

Ativar o DACS passando distributedAccelerator sozinho. É necessária uma maiúscula:

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

O comando instala a distributedaccelerator extensão gerida, o controlador DACS e o pré-requisito NVMe DaemonSet em kube-system, e a caches.storage.azure.com definição personalizada de recursos (CRD). Não instalas um quadro de pré-requisitos separado nem geres tu próprio a versão Helm da extensão. 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 que o estado de provisionamento é Succeeded. A versão instalada do servidor é reportada por currentVersion; não a infira a partir da versão do pacote cliente ou de uma etiqueta de imagem pública.

Grava essa versão para resolução de problemas, depois verifica 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 apenas depois de a extensão estar no Succeeded estado e o controlador estar pronto. Se as verificações de instalação ou prontidão falharem, consulte Resolver problemas do acelerador distribuído para armazenamento na cloud.

Configurar a cache

Verificar a preparação local do NVMe

A extensão gerida prepara discos NVMe locais através do seu pré-requisito DaemonSet. Não implementes uma carga de trabalho duplicada de configuração de disco nem instales 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 em falta ou não estiver pronto, pára e verifica a versão da extensão e os eventos do pod pré-requisito em vez de instalar um chart separado.

Crie um namespace dedicado para a 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 o número de servidores, o tamanho da cache, a CPU e a memória para se adaptarem ao 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 a cache está pronta

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 que cada pod do servidor de cache está a correr num 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

Dar acesso de leitura aos dados do modelo

Este quickstart utiliza a identidade gerida AKS kubelet. Obtenha o respetivo 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)

Atribuir o papel de leitura com menor privilégio no âmbito do contentor:

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"

As atribuições de funções podem demorar vários minutos a propagar-se. Para usar a identidade de kubelet, defina as três variáveis de identidade gerida mostradas na especificação do pod: AZURE_CLIENT_ID, MSI_ENDPOINT e um MSI_SECRET não vazio. Definir apenas AZURE_CLIENT_ID não é suficiente para esta configuração de cliente.

Adicionar o cliente a uma imagem de workload

Crie um ficheiro 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"

Constrói e envia a imagem para um registo de onde o teu cluster AKS possa extrair. Para o Azure Container Registry (ACR), faça login antes de fazer push e certifique-se de que a identidade kubelet tem permissões para obter imagens. Para um registry que utilize permissões RBAC do registry, conceda AcrPull no âmbito do registry. Para um registo habilitado por ABAC, utilize a função de leitor de repositório apropriada. Para detalhes, consulte Authenticate with Azure Container Registry from Azure Kubernetes Service.

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

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

Fazer deploy de um teste só de leitura

Escolha um blob de modelos existente e defina o 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 leituras, e verifica se todas as leituras retornam a mesma soma de verificação SHA-256. A população da cache é assíncrona, por isso uma segunda leitura imediata pode não encontrar a cache. Os intervalos dão tempo para os uploads em segundo plano serem concluídos; use as métricas do cliente e os contadores do servidor para confirmar hits na cache, em vez de assumir que uma leitura específica é um hit. Para comparar contadores de servidor, capture uma linha de base antes de criar o pod seguindo Verifique o caminho do pedido 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"

Verificar o caminho do pedido DACS

Uma leitura bem-sucedida ou uma segunda leitura mais rápida sozinha não provam que o pedido chegou ao DACS, porque o cliente pode recorrer ao Armazenamento de Blobs do Azure. Defina tanto CACHE_DISCOVERY_URL como CACHE_SERVER_PORT. Se algum estiver em falta, o cliente regista Cache not configured. Working in Remote Blob mode only.

Inspecione os pod logs para as métricas de encerramento do cliente cache_client_download_cache_hits e cache_client_download_cache_misses. Uma contagem de acertos na cache diferente de zero indica que foi servido um pedido a partir da cache. Os contadores de cliente podem incluir pedidos internos e não correspondem necessariamente ao número de leituras da aplicação.

Compare também os contadores de pedido do servidor cache antes e depois de executar o teste. Verifique todos os pods de servidor cache porque o pedido pode ser servido 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

Noutro terminal, recupere as métricas e inspecione o contador de pedidos:

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

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

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

Fazer a limpeza do teste

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

Se já não precisares da cache, elimina o recurso de cache enquanto o controlador está a funcionar:

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

Apague o namespace apenas se for dedicado a este quickstart e não contiver recursos que precise de manter:

kubectl delete namespace "$CACHE_NAMESPACE"

Após remover todos os recursos de cache e cargas de trabalho dependentes, desative a extensão gerida:

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

Desativar o DACS remove a sua extensão gerida, controlador e o pré-requisito DaemonSet, mas mantém o CRD da Cache. Não apague os pré-requisitos geridos separadamente, desinstale diretamente a versão Helm da extensão ou apague manualmente o CRD. Remova qualquer atribuição de função ou rótulo de pool de nós adicionado apenas para este quickstart depois de confirmar que nenhuma outra carga de trabalho precisa disso.

Para mais informações, consulte Remover acelerador distribuído para armazenamento na cloud.

Passos seguintes