For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://docs.nvidia.com/dynamo/llms.txt. For full content including API reference and SDK examples, see https://docs.nvidia.com/dynamo/llms-full.txt.
Amazon Elastic Kubernetes Service (EKS)
Шаги по созданию кластера EKS
Это руководство демонстрирует платформу Dynamo в Amazon Elastic Kubernetes Service (EKS).
Настройка переменных окружения
Мы будем использовать эти переменные окружения на протяжении всего руководства.
Если вы хотите использовать другой регион, измените переменную AWS_REGION
export AWS_REGION="us-east-1"
export CLUSTER_NAME="ai-dynamo"
export DYNAMO_NAMESPACE="dynamo-system"
export DYNAMO_RELEASE_VERSION="1.0.0"
Установите CLI
Установите AWS CLI (руководство по установке AWS CLI)
sudo apt install unzip
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
Установите Kubernetes CLI (руководство по установке kubectl для EKS)
curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.35.2/2026-02-27/bin/darwin/amd64/kubectl
chmod +x ./kubectl
mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$HOME/bin:$PATH
echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc
Установите Eksctl CLI (руководство по установке eksctl)
ARCH=amd64
PLATFORM=$(uname -s)_$ARCH
curl -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz"
curl -sL "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_checksums.txt" | grep $PLATFORM | sha256sum --check
tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp && rm eksctl_$PLATFORM.tar.gz
sudo mv /tmp/eksctl /usr/local/bin
Установите Helm CLI (настройка Helm для EKS)
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 > get_helm.sh
chmod 700 get_helm.sh
./get_helm.sh
Создайте кластер EKS Auto Mode
Создание кластера EKS Auto Mode с помощью Eksctl и eksctl.yaml.
Это создаст кластер EKS Auto Mode с Amazon EFS CSI Driver, установленным как addon. Позже мы будем использовать Amazon EFS для хранения весов модели и компиляции, которые использует Dynamo.
# Use all availability zones in a region, exclude use1-az3 where EKS control plane is not available
export EKS_CP_AZS=$(aws ec2 describe-availability-zones \
--region ${AWS_REGION} \
--filters "Name=opt-in-status,Values=opt-in-not-required" \
--query "AvailabilityZones[?ZoneId!='use1-az3'].[ZoneName]" \
--output text | sed 's/ /, /g; s/^/ - /')
eksctl create cluster -f <(envsubst < templates/eksctl.yaml)
Примечание: eksctl автоматически настроит kubeconfig context; если этого не произошло, можно выполнить: aws eks update-kubeconfig --region $AWS_REGION --name $CLUSTER_NAME
Создайте GPU NodePool в EKS Auto Mode
Создание GPU NodePool, ориентированного на семейства инстансов g5,g6,g6e,g7e,p5,p5e,p5en.
kubectl apply -f automode-np-gpu.yaml
Создайте StorageClass по умолчанию
Создайте StorageClass по умолчанию, чтобы использовать возможности хранения EKS Auto Mode. Это сделает StorageClass по умолчанию таким, который использует EBS volumes для stateful-нагрузок, необходимых NATS, используемому с Dynamo.
kubectl apply -f - << EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: auto-ebs-sc
annotations:
storageclass.kubernetes.io/is-default-class: "true"
allowedTopologies:
- matchLabelExpressions:
- key: eks.amazonaws.com/compute-type
values:
- auto
provisioner: ebs.csi.eks.amazonaws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
type: gp3
encrypted: "true"
EOF
Создайте общий файловый system Amazon EFS
Следуйте руководству по настройке EFS, чтобы создать файловую систему EFS и сделать ее доступной как общее хранилище для workloads Dynamo.
Установите Dynamo Kubernetes Platform
Установите Dynamo Platform
helm fetch https://helm.ngc.nvidia.com/nvidia/ai-dynamo/charts/dynamo-platform-"$DYNAMO_RELEASE_VERSION".tgz
helm install dynamo-platform dynamo-platform-"$DYNAMO_RELEASE_VERSION".tgz \
--namespace "$DYNAMO_NAMESPACE" \
--create-namespace
Настройте HuggingFace TOKEN
export HF_TOKEN=<HF_TOKEN>
kubectl create secret generic hf-token-secret \
--from-literal=HF_TOKEN=${HF_TOKEN} \
-n ${DYNAMO_NAMESPACE}
Проверьте установку
Проверьте, что pod'ы платформы Dynamo запущены; вы должны увидеть вывод, похожий на приведенный ниже.
kubectl get pods -n ${DYNAMO_NAMESPACE}
NAME READY STATUS RESTARTS AGE
dynamo-platform-dynamo-operator-controller-manager-ff54b5dstgcq 1/1 Running 0 106s
dynamo-platform-nats-0 2/2 Running 0 106s
Проверьте, что CRD Dynamo были установлены
kubectl get crds | grep dynamo
dynamocheckpoints.nvidia.com 2026-03-17T13:18:05Z
dynamocomponentdeployments.nvidia.com 2026-03-17T13:18:06Z
dynamographdeploymentrequests.nvidia.com 2026-03-17T13:18:08Z
dynamographdeployments.nvidia.com 2026-03-17T13:18:09Z
dynamographdeploymentscalingadapters.nvidia.com 2026-03-17T13:18:10Z
dynamomodels.nvidia.com 2026-03-17T13:18:10Z
dynamoworkermetadatas.nvidia.com 2026-03-17T13:18:11Z
Разверните Dynamo DynamoGraphDeployment (DGD)
| Манифест | Описание |
|---|---|
manifests/vllm/disagg.yaml | Раздельный DGD для prefill/decode с использованием NIXL и backend'а LIBFABRIC поверх EFA. Ориентирован на инстансы g7e.12xlarge с поддержкой GPUDirect RDMA для высокопроизводительной передачи KV-cache между worker'ами prefill и decode. |
manifests/vllm/disagg-p5.yaml | Раздельный DGD для prefill/decode с использованием NIXL и backend'а LIBFABRIC поверх EFA. Ориентирован на зарезервированные инстансы p5.48xlarge с 8 устройствами EFA (4 EFA на 1 GPU для p5.48xlarge) и TP-2 для Qwen3-32B. Использует 2 реплики decode и 6 реплик prefill на зарезервированной емкости (karpenter.sh/capacity-type: reserved). |
manifests/vllm/disagg-tcp.yaml | Альтернативный раздельный inference-граф для prefill/decode, использующий TCP вместо EFA. Ориентирован на инстансы g6e.2xlarge и подходит для типов инстансов без поддержки EFA. |
manifests/vllm/agg.yaml | Агрегированный inference-граф (один worker), где один worker vLLM обрабатывает и prefill, и decode. Более простое развертывание без overhead на передачу KV-cache. |
Кэшируйте модели на EFS
Перед развертыванием inference-графа загрузите веса модели в общее файловое system EFS. Каждый рецепт Dynamo включает Job-манифест model-cache/model-download.yaml, который загружает модель из HuggingFace.
Скопируйте манифест загрузки из рецепта в локальный каталог kustomize и примените его:
# Example: cache the Qwen3-32B model which we will be using later
cp ../../../recipes/qwen3-32b/model-cache/model-download.yaml manifests/model-download/model-download.yaml
kubectl kustomize manifests/model-download | kubectl -n ${DYNAMO_NAMESPACE} apply -f -
rm -f manifests/model-download/model-download.yaml
Манифесты рецептов не задают memory resources для контейнера загрузки. Без memory request pod Job может получить OOMKilled во время загрузки - особенно для больших моделей. kustomization.yaml в manifests/model-download/ добавляет memory request, чтобы этого избежать. По умолчанию он добавляет 4Gi.
Для более крупных моделей (например, DeepSeek-R1, Nemotron-3-Super-120B) увеличьте это значение в manifests/model-download/kustomization.yaml перед применением:
patches:
- target:
kind: Job
name: model-download
patch: |
apiVersion: batch/v1
kind: Job
metadata:
name: model-download
spec:
template:
spec:
containers:
- name: model-download
resources:
requests:
memory: "16Gi" # increase for larger models
Затем примените:
kubectl kustomize manifests/model-download | kubectl -n ${DYNAMO_NAMESPACE} apply -f -
Отслеживайте Job загрузки:
kubectl -n ${DYNAMO_NAMESPACE} get jobs model-download
kubectl -n ${DYNAMO_NAMESPACE} logs -f job/model-download
Чтобы повторно запустить загрузку (например, после смены модели или исправления OOM), сначала удалите предыдущий Job:
kubectl -n ${DYNAMO_NAMESPACE} delete job model-download
Затем скопируйте манифест нового рецепта и примените его снова.
Раздельное обслуживание
Этот пример разворачивает раздельный Dynamo Inference Graph для prefill/decode, который использует NIXL с backend'ом LIBFABRIC и Elastic Fabric Adapter (EFA) для высокопроизводительной передачи KV-cache между worker'ами.
Он ориентирован на инстансы g7e.12xlarge, которые поддерживают GPUDirect RDMA, и использует контейнер vLLM Dynamo с поддержкой EFA nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.0.0-efa-amd64, в котором EFA Installer уже предустановлен.
Примечание: полный список типов инстансов с поддержкой EFA см. в документации AWS EC2.
nodeSelector:
node.kubernetes.io/instance-type: g7e.12xlarge
KV-cache transfer between workers uses NIXL with the LIBFABRIC backend. Enable it by passing the following argument to vLLM:
--kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_both","kv_connector_extra_config": {"backends": ["LIBFABRIC"]}}'
Примечание: на типах инстансов без поддержки EFA backend libfabric в NIXL автоматически переходит на TCP. Однако NixlConnector в vLLM по умолчанию использует cuda в качестве buffer device, поэтому для работы раздельного обслуживания без EFA нужно добавить "kv_buffer_device":"cpu" к аргументу kv-transfer-config.
Request an EFA device for each worker pod using the vpc.amazonaws.com/efa extended resource:
resources:
requests:
gpu: "1"
custom:
vpc.amazonaws.com/efa: "1"
limits:
gpu: "1"
custom:
vpc.amazonaws.com/efa: "1"
Примечание: EKS Auto Mode включает device plugin EFA, поэтому extended resource vpc.amazonaws.com/efa доступен.
Все worker'ы (prefill и decode) должны находиться в одной availability zone, поскольку трафик EFA не проходит между AZ. Используйте правило pod affinity, чтобы это обеспечить:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: "topology.kubernetes.io/zone"
labelSelector:
matchLabels:
nvidia.com/dynamo-graph-deployment-name: "vllm-disagg"
kubectl -n ${DYNAMO_NAMESPACE} apply -f manifests/vllm/disagg.yaml
Примечание: manifests/vllm/disagg-tcp.yaml содержит альтернативный пример, который использует TCP вместо EFA и ориентирован на инстансы g6e.2xlarge.
Проверьте, что все pod'ы достигли состояния Running:
kubectl -n ${DYNAMO_NAMESPACE} get pods
NAME READY STATUS RESTARTS AGE
dynamo-platform-dynamo-operator-controller-manager-ff54b5dstgcq 1/1 Running 0 39m
dynamo-platform-nats-0 2/2 Running 0 39m
vllm-disagg-frontend-85f8476887-wwtwk 1/1 Running 0 2m13s
vllm-disagg-vllmdecodeworker-510a1741-7666987b-tp58w 1/1 Running 0 2m13s
vllm-disagg-vllmprefillworker-510a1741-54f76d7954-tjgn8 1/1 Running 0 2m13s
kubectl -n ${DYNAMO_NAMESPACE} port-forward svc/vllm-disagg-frontend 8000:8000
curl localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen3-32B",
"messages": [
{
"role": "user",
"content": "In the heart of Eldoria, an ancient land of boundless magic and mysterious creatures, lies the long-forgotten city of Aeloria. Once a beacon of knowledge and power, Aeloria was buried beneath the shifting sands of time, lost to the world for centuries. You are an intrepid explorer, known for your unparalleled curiosity and courage, who has stumbled upon an ancient map hinting at ests that Aeloria holds a secret so profound that it has the potential to reshape the very fabric of reality. Your journey will take you through treacherous deserts, enchanted forests, and across perilous mountain ranges. Your Task: Character Background: Develop a detailed background for your character. Describe their motivations for seeking out Aeloria, their skills and weaknesses, and any personal connections to the ancient city or its legends. Are they driven by a quest for knowledge, a search for lost familt clue is hidden."
}
],
"stream": false,
"max_tokens": 30
}'
Вы должны увидеть вывод, похожий на приведенный ниже
{"id":"chatcmpl-23a7c94b-99cb-42ca-ae56-2397aa5a560f","choices":[{"index":0,"message":{"content":"<think>\nOkay, so I need to develop a character background for someone who's an intrepid explorer in Eldoria, specifically focusing on their motivations,","role":"assistant","reasoning_content":null},"finish_reason":"length"}],"created":1773336002,"model":"Qwen/Qwen3-0.6B","object":"chat.completion","usage":{"prompt_tokens":196,"completion_tokens":30,"total_tokens":226,"prompt_tokens_details":{"audio_tokens":null,"cached_tokens":192}},"nvext":{"worker_id":{"prefill_worker_id":4265733549773195,"prefill_dp_rank":0,"decode_worker_id":7535192362430132,"decode_dp_rank":0},"timing":{"request_received_ms":1773336002136,"prefill_wait_time_ms":0.852483,"prefill_time_ms":12.90597,"ttft_ms":13.758453000000001,"total_time_ms":110.89621500000001,"kv_hit_rate":0.0}}}
Примечание: первый запрос для каждого worker'а будет сопровождаться повышенной задержкой; это связано с handshake и overhead инициализации backend'а NIXL, и такая операция происходит только при самой первой передаче
Просмотр логов
kubectl logs -n ${DYNAMO_NAMESPACE} -l nvidia.com/dynamo-graph-deployment-name=vllm-disagg --all-containers=true --max-log-requests=20 --prefix=true --timestamps -f
Очистка
kubectl -n ${DYNAMO_NAMESPACE} delete -f manifests/vllm/disagg.yaml
Агрегированное обслуживание
kubectl -n ${DYNAMO_NAMESPACE} apply -f manifests/vllm/agg.yaml
Ваши pod'ы должны иметь вид, похожий на приведенный ниже вывод, и находиться в статусе "Running".
kubectl -n ${DYNAMO_NAMESPACE} get pods
NAME READY STATUS RESTARTS AGE
dynamo-platform-dynamo-operator-controller-manager-ff54b5dstgcq 1/1 Running 0 12m
dynamo-platform-nats-0 2/2 Running 0 12m
vllm-agg-frontend-ff8457bcf-tq9jh 1/1 Running 0 4m46s
vllm-agg-vllmdecodeworker-d0a70291-759df94478-8lc74 1/1 Running 0 4m46s
Просмотр логов
kubectl logs -n ${DYNAMO_NAMESPACE} -l nvidia.com/dynamo-graph-deployment-name=vllm-agg --all-containers=true --max-log-requests=20 --prefix=true --timestamps -f
kubectl -n ${DYNAMO_NAMESPACE} port-forward svc/vllm-agg-frontend 8000:8000
curl localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen3-0.6B",
"messages": [
{
"role": "user",
"content": "In the heart of Eldoria, an ancient land of boundless magic and mysterious creatures, lies the long-forgotten city of Aeloria. Once a beacon of knowledge and power, Aeloria was buried beneath the shifting sands of time, lost to the world for centuries. You are an intrepid explorer, known for your unparalleled curiosity and courage, who has stumbled upon an ancient map hinting at ests that Aeloria holds a secret so profound that it has the potential to reshape the very fabric of reality. Your journey will take you through treacherous deserts, enchanted forests, and across perilous mountain ranges. Your Task: Character Background: Develop a detailed background for your character. Describe their motivations for seeking out Aeloria, their skills and weaknesses, and any personal connections to the ancient city or its legends. Are they driven by a quest for knowledge, a search for lost familt clue is hidden."
}
],
"stream": false,
"max_tokens": 30
}'
Вы должны увидеть вывод, похожий на приведенный ниже
{"id":"chatcmpl-093fac0e-f75e-43b5-90dc-96c8c77a2e7c","choices":[{"index":0,"message":{"content":"<think>\nOkay, I need to develop a character background for the explorer in Eldoria. Let me start by understanding the user's query. They mentioned","role":"assistant","reasoning_content":null},"finish_reason":"length"}],"created":1773443560,"model":"Qwen/Qwen3-0.6B","object":"chat.completion","usage":{"prompt_tokens":196,"completion_tokens":30,"total_tokens":226},"nvext":{"timing":{"request_received_ms":1773443560878,"total_time_ms":99.89782}}}%
Очистка
kubectl -n ${DYNAMO_NAMESPACE} delete -f manifests/vllm/agg.yaml
Использование On-Demand Capacity Reservations (ODCR) и Capacity Blocks (CBs) для ML
GPU instances бывает трудно получить по требованию. AWS предоставляет два механизма резервирования, чтобы гарантировать capacity для ML workloads:
- On-Demand Capacity Reservations (ODCRs) резервируют capacity в конкретной AZ на любой срок. Вы платите за зарезервированную capacity независимо от того, используете вы ее или нет.
- Capacity Blocks for ML резервируют GPU instances на фиксированное окно времени (от часов до дней). Instances размещаются в EC2 UltraClusters для low-latency networking. У Capacity Blocks есть определенное время окончания, и EC2 завершит instances до истечения block.
EKS Auto Mode использует Karpenter под капотом, который моделирует reserved capacity как karpenter.sh/capacity-type: reserved и приоритизирует ее выше on-demand и spot.
По умолчанию EKS Auto Mode может автоматически запускаться в открытые ODCR, но не приоритизирует их. Capacity Blocks никогда не используются автоматически. И ODCR, и Capacity Blocks требуют явной настройки capacityReservationSelectorTerms на NodeClass, чтобы они получили приоритет и были помечены как reserved.
Создайте NodeClass с Capacity Reservation
Создайте NodeClass, который ссылается на вашу ODCR или Capacity Block reservation. Вы можете выбирать по reservation ID или по tags.
Сначала извлеките конфигурацию subnet, security group и role из NodeClass default, который EKS Auto Mode уже создал:
export NC_SUBNETS=$(kubectl get nodeclass default -o json | jq -c '.spec.subnetSelectorTerms')
export NC_SG=$(kubectl get nodeclass default -o json | jq -c '.spec.securityGroupSelectorTerms')
export NC_ROLE=$(kubectl get nodeclass default -o json | jq -r '.spec.role')
Замените <CR ID> на фактический reservation ID из консоли EC2.
export CR_ID=<CR ID>
kubectl apply -f - << EOF
apiVersion: eks.amazonaws.com/v1
kind: NodeClass
metadata:
name: gpu-reserved
spec:
role: ${NC_ROLE}
subnetSelectorTerms: ${NC_SUBNETS}
securityGroupSelectorTerms: ${NC_SG}
capacityReservationSelectorTerms:
# Select by reservation ID (ODCR or Capacity Block)
- id: "${CR_ID}"
# Or select by tags (can be combined)
# - tags:
# team: "dynamo"
EOF
Дождитесь, пока состояние capacityReservation не станет active.
kubectl get nodeclass gpu-reserved -o json | jq '.status.capacityReservations'
[
{
"availabilityZone": "us-east-2c",
"endTime": "2026-03-18T11:30:00Z",
"id": "cr-xxxxxxxxxxxxxx",
"instanceMatchCriteria": "targeted",
"instanceType": "p5.48xlarge",
"ownerID": "xxxxxxxxxxx",
"reservationType": "capacity-block",
"state": "active"
}
]
Создайте NodePool для reserved capacity
Создайте NodePool, который ссылается на NodeClass gpu-reserved и использует тип capacity reserved. При желании можно добавить on-demand и spot как fallback, если reservation исчерпан.
kubectl apply -f - << EOF
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu-reserved
spec:
disruption:
budgets:
- nodes: 10%
consolidateAfter: 300s
consolidationPolicy: WhenEmptyOrUnderutilized
template:
spec:
nodeClassRef:
group: eks.amazonaws.com
kind: NodeClass
name: gpu-reserved
requirements:
- key: karpenter.sh/capacity-type
operator: In
values:
- reserved
# Uncomment to fallback to on-demand or spot when reservation is exhausted
# - on-demand
# - spot
- key: eks.amazonaws.com/instance-family
operator: In
values:
- g6e
- g7e
- p5
- p5e
- p5en
taints:
- effect: NoSchedule
key: nvidia.com/gpu
value: Exists
EOF
Проверьте, что NodePool gpu-reserved готов
kubectl get nodepool gpu-reserved
NAME NODECLASS NODES READY AGE
gpu-reserved gpu-reserved 0 True 8s
When configuring capacityReservationSelectorTerms on any NodeClass in the cluster, EKS Auto Mode will stop automatically using open ODCRs for all NodeClasses. Make sure all NodeClasses that should use ODCRs have explicit selector terms configured.
Направление workloads на reserved nodes
Pod'ы назначаются на reserved nodes через существующие требования и taints NodePool. Если вы хотите гарантировать, что workload запускается только на reserved capacity, добавьте node selector:
nodeSelector:
karpenter.sh/capacity-type: reserved
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
Особенности Capacity Blocks
У Capacity Blocks фиксированное время окончания. EC2 начинает завершать instances за 30 минут до истечения block (за 60 минут для типов UltraServer). Karpenter начинает draining nodes за 10 минут до начала завершения EC2, давая вашим workloads время корректно завершиться.
Планируйте inference workloads с учетом этого и рассмотрите on-demand как fallback capacity type в NodePool, если вам нужна непрерывность за пределами окна Capacity Block.
Очистка
Удалите все DynamoGraphDeployment
kubectl -n ${DYNAMO_NAMESPACE} get dgd
# Если они есть, удалите их
kubectl -n ${DYNAMO_NAMESPACE} delete dgd <name>
Удалите Dynamo platform
helm uninstall -n ${DYNAMO_NAMESPACE} dynamo-platform
Очистите оставшиеся PVC, связанные с NATS
kubectl -n ${DYNAMO_NAMESPACE} get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
dynamo-platform-nats-js-dynamo-platform-nats-0 Bound pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 10Gi RWO auto-ebs-sc <unset> 75m
kubectl -n ${DYNAMO_NAMESPACE} delete pvc dynamo-platform-nats-js-dynamo-platform-nats-0
Удалите GPU nodepool AutoMode
kubectl delete nodepool gpu
Для очистки ресурсов, связанных с EFS, следуйте разделу cleanup в руководстве по настройке EFS
Удалите кластер EKS Auto Mode с помощью Eksctl
eksctl delete cluster -f <(envsubst < templates/eksctl.yaml)