AKSでのクラウドストレージ用分散アクセラレータ(プレビュー)を始めましょう

このクイックスタートでは、既存のAzure Kubernetes Service (AKS) クラスター上の管理拡張機能を通じて分散アクセラレータ・フォー・クラウド ストレージ (DACS) を有効にし、Azure Blob コンテナへの読み取りアクセスを付与して、繰り返しの読み取りでキャッシュが使用されることを確認します。 ワークロードの例ではパブリック dacs-client==0.1.0 パッケージを使用しています。

Important

クラウドストレージ向けの分散アクセラレータはプレビュー段階です。 プレビュー機能は、サービス レベル アグリーメントなしで提供され、運用環境のワークロードには推奨されません。 詳細については、「 Microsoft Azure プレビューの追加使用条件」を参照してください。

Prerequisites

開始する前に、次のものが必要です。

  • Azure サブスクリプション。
  • 既存の AKS クラスターが DACS プレビューのサポート要件を満たしています。
  • Standard_L*s_v3 VMファミリーのようなローカルNVMeデータディスクを備えたLinuxキャッシュノードプールです。
  • 代表的なモデルデータを含むAzure StorageアカウントとBlobコンテナ。
  • Azure CLI、kubectl、および Docker または他のコンテナー イメージ ビルド ツールを備えた Bash シェル。 このクイックスタートのコマンドを同じシェル セッション内で実行し、変数が利用可能なままにします。
  • AKS 拡張のインストール、Kubernetes リソースの管理、ノードプール ラベルの更新、このクイックスタートで使用されるストレージデータ アクセス ロールの割り当てアクセス許可。
  • Python 3.8以降とglibc 2.35以降のワークロードイメージです。 このクイックスタートでは、x64 ノード上で python:3.12-slim-bookworm と PyPI パッケージ dacs-client==0.1.0 を使用して説明します。

クラウドストレージ用の分散アクセラレータは、キャッシュノードプールを永続保存として使いません。 Azure Blob Storage は信頼できる唯一の情報源です。

DACSプレビューのサポート要件

Requirement DACSプレビューサポート
Azureリージョン すべての Azure パブリック クラウド リージョン。
AKS Kubernetes バージョン 1.35 またはそれ以降。

変数の設定

プレースホルダーの値を置き換え、次のコマンドを実行してください。

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

AKS Preview 拡張機能を確認する

DACS プレビューには aks-preview バージョン 22.0.0b9 以降が必要です。 拡張機能および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

AKSクラスターをAzure Arcに接続する必要はありません。すでに手動でDACSコントローラーをインストールしている場合は、マネージド拡張機能に切り替える前に「アップグレード準備」に従ってください。 同じクラスターで2つのDACSコントローラーを動かさないでください。

キャッシュノードプールの検証

選択したノード プールが Linux を使用し、ローカル NVMe データ ディスクを備えた VM サイズを使用していることを確認してください:

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

クラウド ストレージ用の分散アクセラレーターでは、専用のキャッシュ ノード プールを使うか、他のソフトウェアが同じローカル NVMe ディスクを使用したりフォーマットしたりしていないか確認してください。

ノードプール レベルでキャッシュ ノードプールにラベルを付け、ノード置換後もラベルが残るようにします。 プールにすでにカスタムラベルがある場合は、更新時にラベルを含めて保持してください:

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

Caution

DACSを有効にすると、ラベル付けされたキャッシュノード上のローカルNVMeディスクを検出し、フォーマットしてマウントする前提条件となるDaemonSetがインストールされます。 キャッシュ専用のディスクを持つノードのみにラベルを付けます。

クラウドストレージ用の分散アクセラレータを有効にする

distributedAccelerator を単独で渡すことで、DACSを有効にします。 大文字の A が必要です:

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

このコマンドは、 distributedaccelerator 管理拡張、DACSコントローラおよびNVMeの前提条件DaemonSetを kube-systemにインストールし、 caches.storage.azure.com のカスタムリソース定義(CRD)をインストールします。 別途前提条件チャートをインストールしたり、拡張機能のHelmリリースを自分で管理したりする必要はありません。 後述のようにキャッシュリソースを別途作成します。

拡張機能を確認する

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

拡張タイプが microsoft.distributedaccelerator で、プロビジョニング状態が Succeededであることを確認しましょう。 インストールされたサーバーバージョンは currentVersion によって報告されます。クライアントパッケージのバージョンや公開イメージタグから推測しないでください。

トラブルシューティングのためにそのバージョンを記録し、その後コントローラーと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

拡張が Succeeded 状態になり、コントローラーが準備できてからのみ継続してください。 インストールや準備状況のチェックが失敗した場合は、 クラウドストレージの分散アクセラレータのトラブルシューティングを参照してください。

キャッシュをプロビジョニングする

ローカルNVMe準備の検証

マネージド拡張は、その前提条件のDaemonSetを通じてローカルNVMeディスクを準備します。 重複したディスクセットアップのワークロードを展開したり、別の前提条件チャートをインストールしたりしないでください。

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

DaemonSetのラベル付きキャッシュノードすべてにReadyポッドがあるか確認してください。 マウントポイントは /var/lib/ssd/cacheserver であり、キャッシュリソースの spec.storage.hostPath.nodeCacheFolderPathと一致しなければなりません。 DaemonSet が存在しないか準備完了していない場合は、別のチャートをインストールするのではなく、いったん作業を止めて、拡張機能のバージョンと前提条件となる Pod のイベントを確認してください。

Cache とテストワークロード用の専用名前空間を作成します:

kubectl create namespace "$CACHE_NAMESPACE"

キャッシュリソースを作成する

キャッシュ リソースを作成します。 この例では、ラベル付き NVMe ノードごとに 1 台ずつ、合計 3 台のキャッシュ サーバーを構成し、条件を満たすノードが少なくとも 3 台必要です。 ノード プールに応じて、サーバー数、キャッシュ サイズ、CPU、メモリを調整します。

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

Azure 対応性の状態を確認する

クラスタ内の最初のキャッシュを選択するのではなく、指定した名前のキャッシュ リソースを待機する:

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

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

現在のキャッシュ サーバーの数と想定されるキャッシュ サーバーの数が一致していること、および各キャッシュ サーバー ポッドが NVMe ノード上で実行されていることを確認してください。

ワークロードクライアントが使うディスカバリーホスト名を取得する:

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

echo $CACHE_DISCOVERY_URL

モデルデータへのリードアクセスを許可する

このクイックスタートでは、AKS kubelet のマネージド ID を使用します。 そのオブジェクト ID とストレージ アカウントのリソース ID を取得します:

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)

コンテナ スコープで最小特権の読み取りロールを割り当てます:

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"

役割割り当ては伝播に数分かかることがあります。 kubeletの識別子を使用するには、pod仕様に示されている3つの管理付き識別変数( AZURE_CLIENT_ID、 MSI_ENDPOINT、そして空でない MSI_SECRET)をすべて設定します。 このクライアント構成では、AZURE_CLIENT_ID のみを設定しても不十分です。

クライアントをワークロード イメージに追加

ビルド ディレクトリに Dockerfile という名前のファイルを作成し、以下の内容を記述します。 ディストリビューション名はdacs-clientで、Pythonのインポート名前空間はpy_dacs_clientです。

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

イメージをビルドして、AKSクラスターが引き込めるレジストリにプッシュしてください。 Azure Container Registry (ACR) の場合は、プッシュする前にサインインし、kubelet ID にイメージのプル アクセス権があることを確認してください。 RBACレジストリ権限を使用するレジストリの場合は、レジストリの範囲でAcrPullを付与してください。 ABAC 対応レジストリの場合は、代わりに適切な repository-reader ロールを使用します。 詳細については、Azure Kubernetes Service から Azure Container Registry で認証するを参照してください。

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

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

読み取り専用テストをデプロイする

既存のモデルのブロブを選択し、そのパスを設定します:

MODEL_BLOB=<path-to-model-blob>

テストポッドを作成してください。 ポッドは Blob から最大 4 MiB を 5 回読み出し、読み取り間隔は 1 秒で、すべての読み込みが同じ SHA-256 チェックサムを返すことを検証します。 キャッシュの生成は非同期であるため、直後に再度読み取ると、キャッシュにヒットしないことがあります。 この間隔はバックグラウンドアップロードが完了する時間を確保します。特定の読み取りをヒットとみなすのではなく、クライアントのメトリクスやサーバーカウンターを使ってキャッシュヒットを確認しましょう。 サーバーカウンターを比較するには、ポッドを作成する前に「 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"

DACSリクエストパスの検証

リードが成功したり、2回目のリードが速くなっただけでは、リクエストがDACSに到達した証拠にはなりません。なぜならクライアントはAzure Blob Storageにフォールバックできるからです。 CACHE_DISCOVERY_URLとCACHE_SERVER_PORTの両方をセットしてください。 もしいずれかが欠けている場合、クライアントは Cache not configured. Working in Remote Blob mode only. をログに記録します

ポッドのログで、クライアントのシャットダウン メトリクス cache_client_download_cache_hits と cache_client_download_cache_misses を確認してください。 キャッシュヒット カウントがゼロでない場合は、要求がキャッシュから提供されたことを示します。 クライアントカウンターは内部リクエストを含めることができ、必ずしもアプリケーションの読み込み回数と等しくない場合があります。

また、テスト実行前後のキャッシュサーバーのリクエストカウンターを比較してください。 すべてのキャッシュサーバーポッドをチェックしてください。リクエストは必ずしも最初のポッドではなく、どのサーバーからも提供される可能性があります。 サーバーを 1 台確認するには:

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

別の端末でメトリックを取得し、リクエストカウンターを検査します:

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

単にカウンターシリーズの存在ではなく、request_type="Download" と status="Success" でダウンロード要求の増加を確認してください。カウンター シリーズはゼロ値でも存在し得るためです。 ラベルの値は大文字と小文字を区別します。 必要に応じてポートフォワードを停止し、他のキャッシュサーバーポッドでも同じことを繰り返します。 クライアントのキャッシュヒット指標をサーバーカウンターやAzure Blobのテレメトリと関連付けて、キャッシュヒット、オリジントラフィック、フォールバック動作を区別します。

完全なメトリック参照およびスクレイプ構成については、クラウド ストレージ用の分散アクセラレータのモニタリングを参照してください。

テストをクリーンアップ

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

キャッシュが不要な場合は、コントローラーが動作している間にキャッシュリソースを削除してください:

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

このクイックスタート専用で、必要なリソースがない場合のみ名前空間を削除してください:

kubectl delete namespace "$CACHE_NAMESPACE"

すべてのキャッシュリソースと依存するワークロードを削除した後、管理拡張を無効にします。

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

DACSを無効にすると、マネージド拡張、コントローラ、前提条件のDaemonSetは削除されますが、キャッシュCRDは保持されます。 管理される前提条件を個別に削除したり、拡張機能のHelmリリースを直接アンインストールしたり、CRDを手動で削除したりしないでください。 このクイックスタート専用に追加されたロール割り当てやノードプールラベルは、他のワークロードが必要ないことを確認した後にのみ削除してください。

詳細については、「クラウド ストレージ用の分散アクセラレーターの削除」をご覧ください。

次のステップ