Attività iniziali all'acceleratore distribuito per l'archiviazione cloud nel servizio Azure Kubernetes (anteprima)

Questo quickstart consente l'acceleratore distribuito per lo storage cloud (DACS) tramite la sua estensione gestita su un cluster Servizio Azure Kubernetes (AKS) esistente, concede accesso alla lettura a un container Azure Blob e verifica che le letture ripetute utilizzino la cache. L'esempio del workload utilizza il pacchetto pubblico dacs-client==0.1.0.

Important

L'acceleratore distribuito per lo storage cloud è in anteprima. Le funzionalità di anteprima vengono fornite senza un contratto di servizio e non sono consigliate per i carichi di lavoro di produzione. Per ulteriori informazioni, vedere Condizioni supplementari per l'uso delle versioni di anteprima di Microsoft Azure.

Prerequisites

Prima di iniziare, è necessario disporre di quanto segue:

  • Una sottoscrizione di Azure.
  • Un cluster AKS esistente che soddisfa i requisiti di supporto per la preview DACS.
  • Un pool di nodi cache Linux con dischi dati NVMe locali, come la Standard_L*s_v3 famiglia VM.
  • Un account Archiviazione di Azure e un container Blob contenenti dati rappresentativi del modello.
  • Una shell Bash con interfaccia della riga di comando di Azure, kubectle Docker o un altro strumento di build container-image. Esegui i comandi in questo avvio rapido nella stessa sessione di shell in modo che le variabili rimangano disponibili.
  • Permesso di installare estensioni AKS, amministrare le risorse Kubernetes, aggiornare le etichette del pool di nodi e assegnare il ruolo di accesso ai dati di archiviazione utilizzato in questo avvio rapido.
  • Un'immagine del carico di lavoro con Python 3.8 o successivo e glibc 2.35 o successiva. Questo quickstart utilizza python:3.12-slim-bookworm e il pacchetto PyPI dacs-client==0.1.0 su nodi x64.

Distributed accelerator per cloud storage non utilizza il pool di nodi della cache come storage persistente. Archiviazione BLOB di Azure rimane la fonte attendibile.

Requisiti di supporto per l'anteprima DACS

Requirement Supporto per l'anteprima DACS
Regioni di Azure Tutte le aree del cloud pubblico di Azure.
Versioni di Kubernetes AKS 1.35 o successive.

Impostare variabili

Sostituisci i valori segnaposto e poi esegui i seguenti comandi:

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

Verificare che l'estensione di anteprima AKS sia installata

L'anteprima DACS richiede aks-preview versione 22.0.0b9 o successiva. Installa o aggiorna l'estensione e le estensioni utilizzate per gestire e ispezionare i 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

Non è necessario collegare il cluster del servizio Azure Kubernetes ad Azure Arc. Se è già stato installato manualmente un controller DACS, seguire Prepararsi per gli aggiornamenti prima di passare all'estensione gestita. Non usare due controller DACS sullo stesso cluster.

Verifica il pool di nodi della cache

Conferma che il pool di nodi selezionato utilizza Linux e una dimensione di VM con dischi dati NVMe locali:

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

Per un acceleratore distribuito per l'archiviazione cloud, usare un pool dedicato di nodi della cache o confermare che altri software non attestino né formattino gli stessi dischi NVMe locali.

Etichetta il pool di nodi cache a livello di pool di nodi così che l'etichetta sopravviva alla sostituzione del nodo. Se il pool ha già etichette personalizzate, includile nell'aggiornamento per preservarle:

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

Caution

Abilitando DACS si installa un DaemonSet prerequisito che scopre, formatta e monta dischi NVMe locali su nodi di cache etichettati. Etichetta solo i nodi con dischi dedicati alla cache.

Abilita l'acceleratore distribuito per lo storage cloud

Abilita il DACS passando solo distributedAccelerator. La maiuscola A è richiesta:

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

Il comando installa l'estensione distributedaccelerator gestita, il controller DACS e il prerequisito NVMe DaemonSet in kube-system, e la caches.storage.azure.com definizione personalizzata della risorsa (CRD). Non installi un chart separato dei prerequisiti né gestisci tu stesso la release Helm dell'estensione. Crea una risorsa Cache separatamente come mostrato più avanti.

Verificare l'estensione

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

Conferma che il tipo di estensione sia microsoft.distributedaccelerator e che lo stato di provisioning sia Succeeded. La versione server installata è segnalata da currentVersion; non dedurla dalla versione del pacchetto client o da un tag immagine pubblica.

Registra quella versione per la risoluzione dei problemi, poi verifica il controller e il 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

Continua solo dopo che l'estensione è nello stato Succeeded e il controller è pronto. Se i controlli di installazione o preparazione non riescono, vedere Risolvere i problemi dell'acceleratore distribuito per l'archiviazione cloud.

Effettuare il provisioning della cache

Verifica la preparazione locale del NVMe

L'estensione gestita prepara i dischi NVMe locali tramite il suo prerequisito DaemonSet. Non distribuire un workload duplicato di configurazione del disco né installare un altro chart dei prerequisiti.

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

Conferma che il DaemonSet abbia un pod Ready su ogni nodo della cache etichettato. Il punto di montaggio è /var/lib/ssd/cacheserver e deve corrispondere al spec.storage.hostPath.nodeCacheFolderPath della risorsa della cache. Se il DaemonSet manca o non è pronto, fermati e controlla la versione dell'estensione e gli eventi dei pod prerequisito invece di installare un chart separato.

Crea un namespace dedicato per la Cache e il workload di test:

kubectl create namespace "$CACHE_NAMESPACE"

Crea la risorsa Cache

Crea la risorsa Cache. L'esempio configura tre server cache, con un server per ogni nodo NVMe etichettato, e richiede almeno tre nodi idonei. Regola il numero di server, la dimensione della cache, la CPU e la memoria per adattarli al pool di nodi.

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

Verificare l'idoneità della cache

Aspettare la risorsa Cache nominata invece di selezionare la prima cache nel cluster:

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

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

Verifica che i conteggi attuali e desiderati del server cache corrispondano e che ogni pod server cache sia in esecuzione su un nodo NVMe.

Recuperare il nome host di individuazione usato dai client del carico di lavoro:

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

echo $CACHE_DISCOVERY_URL

Concedi accesso in lettura ai dati del modello

Questo quickstart utilizza l'identità gestita AKS kubelet. Ottieni il suo ID oggetto e l'ID della risorsa dell'account di archiviazione:

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)

Assegna il ruolo di lettura con il minor privilegio nell'ambito del container:

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"

Le assegnazioni dei ruoli possono richiedere diversi minuti per essere propagate. Per usare l'identità di Kubelet, impostare tutte e tre le variabili di identità gestita mostrate nella specifica del pod: AZURE_CLIENT_ID, MSI_ENDPOINT, e un non vuoto MSI_SECRET. Impostare solo AZURE_CLIENT_ID non è sufficiente per questa configurazione client.

Aggiungere il client a un'immagine del carico di lavoro

Crea un file chiamato Dockerfile nella tua directory build con il seguente contenuto. Il nome della distribuzione è dacs-client, e lo spazio di importazione Python è py_dacs_client:

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

Compila e spingi l'immagine in un registro da cui il tuo cluster AKS possa prelevare. Per Registro Azure Container (ACR), accedi prima di fare push e assicurati che l'identità kubelet abbia l'autorizzazione per il pull delle immagini. Per un registro che utilizza Autorizzazioni del registro RBAC, concedere AcrPull a livello di registro. Per un registro abilitato ABAC, usa invece il ruolo appropriato di lettore di repository. Per dettagli, vedi Authenticate with Registro Azure Container from servizio Azure Kubernetes.

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

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

Implementa un test di sola lettura

Scegli un blob di modello esistente e imposta il suo percorso:

MODEL_BLOB=<path-to-model-blob>

Crea un pod di test. Il pod legge fino a 4 MiB dal blob cinque volte, con un intervallo di un secondo tra una lettura e l'altra, e verifica che tutte le letture restituiscano lo stesso checksum SHA-256. La popolazione della cache è asincrona, quindi una seconda lettura immediata può non trovare la cache. Gli intervalli danno tempo ai caricamenti in background per completarsi; utilizzare le metriche client e i contatori server per confermare gli hit della cache invece di presumere che una lettura particolare sia un hit. Per confrontare i contatori del server, cattura una linea di base prima di creare il pod seguendo Verificare il percorso della richiesta 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"

Verifica il percorso di richiesta DACS

Una lettura riuscita o una seconda lettura più veloce da sola non sono la prova che la richiesta sia arrivata al DACS perché il client può ripiegare su Archiviazione BLOB di Azure. Imposta sia CACHE_DISCOVERY_URL che CACHE_SERVER_PORT. Se manca uno dei due, il client registra Cache not configured. Working in Remote Blob mode only.

Ispeziona i log dei pod per le metriche di spegnimento del client cache_client_download_cache_hits e cache_client_download_cache_misses. Un conteggio di cache hit non nullo indica che una richiesta è stata servita dalla cache. I contatori client possono includere richieste interne e non necessariamente corrispondono al numero di letture applicative.

Confronta anche i contatori di richiesta del server cache prima e dopo l'esecuzione del test. Controlla ogni pod cache-server perché la richiesta potrebbe essere servita da qualsiasi server, non necessariamente dal primo pod. Per ispezionare un server:

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

In un altro terminale, recupera le metriche e ispeziona il contatore delle richieste:

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

Conferma un aumento delle richieste di download con request_type="Download" e status="Success", non solo la presenza di una serie di contatori, che può esistere a zero. I valori delle etichette sono sensibili a maiuscole e minuscole. Interrompi il port-forwarding e ripeti per altri pod di cache server se necessario. Correla le metriche di cache-hit del client con i server counter e la telemetria Azure Blob per distinguere i hit della cache, il traffico di origine e il comportamento di fallback.

Per il riferimento completo delle metriche e della configurazione di scrape, vedi Monitorare l'acceleratore distribuito per l'archiviazione cloud.

Pulisci il test

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

Se non hai più bisogno della cache, elimina la risorsa Cache mentre il controller è in funzione:

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

Elimina lo spazio dei nomi solo se era dedicato a questo quickstart e non contiene risorse da conservare:

kubectl delete namespace "$CACHE_NAMESPACE"

Dopo aver rimosso tutte le risorse della cache e i carichi di lavoro dipendenti, disabilita l'estensione gestita:

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

Disabilitare DACS rimuove la sua estensione gestita, il controller e il DaemonSet prerequisito ma mantiene il CRD della cache. Non eliminare separatamente i prerequisiti gestiti, disinstalla direttamente la release Helm dell'estensione o elimina manualmente il CRD. Rimuovere qualsiasi assegnazione di ruolo o etichetta del pool di nodi aggiunta esclusivamente per questo avvio rapido solo dopo aver confermato che nessun altro carico di lavoro ne abbia bisogno.

Per maggiori informazioni, vedi Rimuovere acceleratore distribuito per lo storage cloud.

Passaggi successivi